package synthesijer.hdl.vhdl;
import java.io.PrintWriter;
import synthesijer.Constant;
import synthesijer.SynthesijerUtils;
import synthesijer.hdl.HDLExpr;
import synthesijer.hdl.HDLInstance;
import synthesijer.hdl.HDLInstanceRef;
import synthesijer.hdl.HDLInstance.ParamPair;
import synthesijer.hdl.HDLLiteral;
import synthesijer.hdl.HDLModule;
import synthesijer.hdl.HDLParameter;
import synthesijer.hdl.HDLPort;
import synthesijer.hdl.HDLPrimitiveType;
import synthesijer.hdl.HDLSequencer;
import synthesijer.hdl.HDLSignal;
import synthesijer.hdl.HDLTreeVisitor;
import synthesijer.hdl.HDLUserDefinedType;
import synthesijer.hdl.HDLUtils;
import synthesijer.hdl.expr.HDLPreDefinedConstant;
import synthesijer.hdl.expr.HDLValue;
import synthesijer.hdl.sequencer.SequencerState;
import synthesijer.hdl.sequencer.StateTransitCondition;
public class GenerateVHDLVisitor implements HDLTreeVisitor{
private final PrintWriter dest;
private final int offset;
public GenerateVHDLVisitor(PrintWriter dest, int offset){
this.dest = dest;
this.offset = offset;
}
@Override
public void visitHDLExpr(HDLExpr o) {
String str = String.format("%s <= %s;", o.getResultExpr().getVHDL(), adjustTypeFor((HDLSignal)o.getResultExpr(), o));
HDLUtils.println(dest, offset, str);
}
private void genGenericMap(HDLInstance o){
HDLUtils.println(dest, offset, String.format("generic map("));
String sep = "";
for(ParamPair pair: o.getParameterPairs()){
if(pair.getValue() != null){
HDLUtils.print(dest, 0, sep);
HDLUtils.print(dest, offset+2, String.format("%s => %s", pair.param.getName(), pair.getValue().getVHDL()));
}else{
HDLUtils.print(dest, 0, sep);
HDLUtils.print(dest, offset+2, String.format("%s => %s", pair.param.getName(), pair.param.getValue().getVHDL()));
}
sep = "," + Constant.BR;
}
HDLUtils.println(dest, 0, "");
HDLUtils.println(dest, offset, ")");
}
private void genPortMap(HDLInstance o){
HDLUtils.println(dest, offset, String.format("port map("));
String sep = "";
for(HDLInstance.PortPair pair: o.getPairs()){
HDLUtils.print(dest, 0, sep);
if(o.getSubModule().getSysClkPairItem() != null && pair.port.getName().equals(o.getSubModule().getSysClkPairItem().getName())){
// target port to connect is system clock, the port should be connected system clock in this module directly.
if(o.getModule().getSysClkPairItem() == null){
SynthesijerUtils.warn(o.getModule().getName() + " does not have system clock, but sub-module requires system clock");
SynthesijerUtils.warn("system clock of sub-module is remained as open, so the sub-module will not work well.");
}else{
HDLUtils.print(dest, offset+2, String.format("%s => %s", pair.port.getName(), o.getModule().getSysClkPairItem().getName()));
}
}else if(o.getSubModule().getSysResetPairItem() != null && pair.port.getName().equals(o.getSubModule().getSysResetPairItem().getName())){
// target port to connect is system reset, the port should be connected system reset in this module directly.
if(o.getModule().getSysResetPairItem() == null){
SynthesijerUtils.warn(o.getModule().getName() + " does not have system reset, but sub-module requires system reset");
SynthesijerUtils.warn("system reset of sub-module is remained as open, so the sub-module will not work well.");
}else{
HDLUtils.print(dest, offset+2, String.format("%s => %s", pair.port.getName(), o.getModule().getSysResetPairItem().getName()));
}
}else{
HDLUtils.print(dest, offset+2, String.format("%s => %s", pair.port.getName(), pair.item.getName()));
}
sep = "," + Constant.BR;
}
HDLUtils.println(dest, 0, "");
HDLUtils.println(dest, offset, ");");
}
@Override
public void visitHDLInstance(HDLInstance o) {
HDLUtils.println(dest, offset, String.format("inst_%s : %s", o.getName(), o.getSubModule().getName()));
if(o.getSubModule().getParameters().length > 0){
genGenericMap(o);
}
genPortMap(o);
HDLUtils.nl(dest);
}
@Override
public void visitHDLLitral(HDLLiteral o) {
// TODO Auto-generated method stub
}
@Override
public void visitHDLModule(HDLModule o) {
// library import
HDLUtils.println(dest, offset, String.format("library IEEE;"));
HDLUtils.println(dest, offset, String.format("use IEEE.std_logic_1164.all;"));
HDLUtils.println(dest, offset, String.format("use IEEE.numeric_std.all;"));
HDLUtils.nl(dest);
HDLModule.LibrariesInfo[] libraries = o.getLibraries();
for(HDLModule.LibrariesInfo lib: libraries){
HDLUtils.println(dest, offset, String.format("library " + lib.libName + ";"));
for(String s: lib.useName){
HDLUtils.println(dest, offset, String.format("use " + s + ";"));
}
HDLUtils.nl(dest);
}
// entity
o.accept(new GenerateVHDLDefVisitor(dest, offset));
// architecture body
HDLUtils.println(dest, offset, String.format("begin"));
HDLUtils.nl(dest);
for(HDLPort p: o.getPorts()){ p.accept(new GenerateVHDLVisitor(dest, offset+2)); }
HDLUtils.nl(dest);
HDLUtils.println(dest, offset+2, "-- expressions");
for(HDLExpr expr : o.getExprs()){ expr.accept(new GenerateVHDLVisitor(dest, offset+2)); }
HDLUtils.nl(dest);
HDLUtils.println(dest, offset+2, "-- sequencers");
for(HDLSequencer m: o.getSequencers()){ m.accept(new GenerateVHDLVisitor(dest, offset+2)); }
HDLUtils.nl(dest);
for(HDLSignal s: o.getSignals()){ s.accept(new GenerateVHDLVisitor(dest, offset+2)); }
HDLUtils.nl(dest);
for(HDLInstance i: o.getModuleInstances()){ i.accept(new GenerateVHDLVisitor(dest, offset+2)); }
HDLUtils.nl(dest);
HDLUtils.println(dest, offset, String.format("end RTL;"));
}
@Override
public void visitHDLPort(HDLPort o) {
if(o.isSet(HDLPort.OPTION.NO_SIG) || o.isSet(HDLPort.OPTION.EXPORT_PATH)) return; // nothing to do
if(o.getDir() == HDLPort.DIR.INOUT){
return;
}else if(o.isOutput()){
HDLUtils.println(dest, offset, String.format("%s <= %s;", o.getName(), o.getSignal().getName()));
}else{
HDLUtils.println(dest, offset, String.format("%s <= %s;", o.getSignal().getName(), o.getName()));
}
o.getSignal().accept(this);
}
@Override
public void visitHDLParameter(HDLParameter o) {
// nothing to do
}
private void genSyncSequencerHeader(HDLSequencer o, int offset){
HDLUtils.println(dest, offset, String.format("process (%s)", o.getModule().getSysClkName()));
}
private void genAsyncSequencerHeader(HDLSequencer o, int offset){
HDLUtils.println(dest, offset, String.format("process"));
}
private void genSyncSequencerSwitch(HDLSequencer o, int offset){
if(o.getStates().size() > 0){
HDLUtils.println(dest, offset, String.format("case (%s) is", o.getStateKey().getName()));
for(SequencerState s: o.getStates()){
HDLUtils.println(dest, offset+2, String.format("when %s => ", s.getStateId().getVHDL()));
if(s.hasExitCondition()){
HDLUtils.println(dest, offset+4, String.format("if %s then", s.getExitConditionAsVHDL()));
HDLUtils.println(dest, offset+6, String.format("%s <= (others => '0');", o.getDelayCounter().getName()));
genStateTransition(dest, offset+6, s);
HDLUtils.println(dest, offset+4, String.format("else"));
HDLUtils.println(dest, offset+6, String.format("%s <= %s + 1;", o.getDelayCounter().getName(), o.getDelayCounter().getName()));
HDLUtils.println(dest, offset+4, String.format("end if;"));
}else{
genStateTransition(dest, offset+4, s);
}
}
HDLUtils.println(dest, offset+2, String.format("when others => null;"));
HDLUtils.println(dest, offset, String.format("end case;"));
}
for(HDLSequencer.Pair p: o.getSeqExprList()){
HDLUtils.println(dest, offset, String.format("%s <= %s;", p.dest.getVHDL(), p.expr.getResultExpr().getVHDL()));
}
for(HDLSequencer.Triple t: o.getSeqCondExprList()){
HDLUtils.println(dest, offset, String.format("if (%s) = '1' then", t.cond.getVHDL()));
HDLUtils.println(dest, offset + 2, String.format("%s <= %s;", t.dest.getVHDL(), t.expr.getResultExpr().getVHDL()));
HDLUtils.println(dest, offset, String.format("end if;"));
}
}
private void genSyncSequencerBody(HDLSequencer o, int offset){
HDLUtils.println(dest, offset, String.format("if %s'event and %s = '1' then", o.getModule().getSysClkName(), o.getModule().getSysClkName()));
// reset
if(o.getModule().isNegativeReset()){
HDLUtils.println(dest, offset+2, String.format("if %s = '0' then", o.getModule().getSysResetName()));
}else{
HDLUtils.println(dest, offset+2, String.format("if %s = '1' then", o.getModule().getSysResetName()));
}
HDLUtils.println(dest, offset+4, String.format("%s <= %s;", o.getStateKey().getName(), o.getIdleState().getStateId().getVHDL()));
HDLUtils.println(dest, offset+4, String.format("%s <= %s;", o.getDelayCounter().getName(), o.getDelayCounter().getDefaultValue().getVHDL()));
HDLUtils.println(dest, offset+2, String.format("else"));
genSyncSequencerSwitch(o, offset+4);
if(o.getModule().isSynchronous()){
HDLUtils.println(dest, offset+2, String.format("end if;"));
HDLUtils.println(dest, offset, String.format("end if;"));
}
}
private void genAsyncSequencerBody(HDLSequencer o, int offset){
if(o.getStates().size() > 0){
for(SequencerState s: o.getStates()){
HDLUtils.println(dest, offset, String.format("-- state %s = %s", o.getStateKey().getName(), s.getStateId().getVHDL()));
genStateTransition(dest, offset, s);
if(o.hasTransitionTime()) HDLUtils.println(dest, offset, String.format("wait for %d ns;", o.getTransitionTime()));
}
}
}
@Override
public void visitHDLSequencer(HDLSequencer o) {
if(o.getModule().isSynchronous()){
genSyncSequencerHeader(o, offset);
}else{
genAsyncSequencerHeader(o, offset);
}
HDLUtils.println(dest, offset, String.format("begin"));
if(o.getModule().isSynchronous()){
genSyncSequencerBody(o, offset+2);
}else{
genAsyncSequencerBody(o, offset+2);
}
HDLUtils.println(dest, offset, String.format("end process;"));
HDLUtils.nl(dest);
}
public void genStateTransition(PrintWriter dest, int offset, SequencerState s){
if(s.getTransitions().size() > 0){
String sep = "if";
int cnt = 0;
for(StateTransitCondition c: s.getTransitions()){
String str = String.format("%s <= %s;",
s.getKey().getName(),
c.getDestState().getStateId().getVHDL());
if(c.hasCondition()){
HDLUtils.println(dest, offset, String.format("%s %s then", sep, c.getCondExprAsVHDL()));
HDLUtils.println(dest, offset+2, str);
sep = "elsif";
cnt++;
}else{
if(cnt == 0){
HDLUtils.println(dest, offset, str);
}else{
HDLUtils.println(dest, offset, "else");
HDLUtils.println(dest, offset+2, str);
}
}
}
if(cnt > 0){
HDLUtils.println(dest, offset, String.format("end if;"));
}
}else{
HDLUtils.println(dest, offset, "null;");
}
}
private void genSyncProcess(HDLSignal o, int offset){
HDLUtils.println(dest, offset, String.format("if %s'event and %s = '1' then", o.getModule().getSysClkName(), o.getModule().getSysClkName()));
if(o.getModule().isNegativeReset()){
HDLUtils.println(dest, offset+2, String.format("if %s = '0' then", o.getModule().getSysResetName()));
}else{
HDLUtils.println(dest, offset+2, String.format("if %s = '1' then", o.getModule().getSysResetName()));
}
if(o.getResetValue() != null){
HDLUtils.println(dest, offset+4, String.format("%s <= %s;", o.getName(), adjustTypeFor(o, o.getResetValue())));
}
HDLUtils.println(dest, offset+2, String.format("else"));
if(o.getConditions().length > 0){
String sep = "if";
for(HDLSignal.AssignmentCondition c: o.getConditions()){
HDLUtils.println(dest, offset+4, String.format("%s %s then", sep, c.getCondExprAsVHDL()));
if(c.getValue() != null){
HDLUtils.println(dest, offset+6, String.format("%s <= %s;", o.getName(), adjustTypeFor(o, c.getValue())));
}else{
SynthesijerUtils.warn("Assignment value is not found for " + o.getName());
}
sep = "elsif";
}
if(o.hasDefaultValue()){
HDLUtils.println(dest, offset+4, String.format("else"));
HDLUtils.println(dest, offset+6, String.format("%s <= %s;", o.getName(), adjustTypeFor(o, o.getDefaultValue())));
}
HDLUtils.println(dest, offset+4, String.format("end if;"));
}else{
if(o.hasDefaultValue()){
HDLUtils.println(dest, offset+4, String.format("%s <= %s;", o.getName(), adjustTypeFor(o, o.getDefaultValue())));
}else{
HDLUtils.println(dest, offset+4, String.format("null;"));
}
}
HDLUtils.println(dest, offset+2, String.format("end if;"));
HDLUtils.println(dest, offset, String.format("end if;"));
}
private void genAsyncProcess(HDLSignal o, int offset){
/*
if(o.getConditions().length == 1){
HDLUtils.println(dest, offset, String.format("%s <= %s;", o.getName(), adjustTypeFor(o, o.getConditions()[0].getValue())));
}else if(o.getConditions().length > 1){
*/
if(o.getConditions().length > 0){
String sep = "if";
for(HDLSignal.AssignmentCondition c: o.getConditions()){
HDLUtils.println(dest, offset, String.format("%s %s then", sep, c.getCondExprAsVHDL()));
HDLUtils.println(dest, offset+2, String.format("%s <= %s;", o.getName(), adjustTypeFor(o, c.getValue())));
sep = "elsif";
}
HDLUtils.println(dest, offset, String.format("end if;"));
}else{
HDLUtils.println(dest, offset, String.format("null;"));
}
}
private void genSyncProcessHeader(HDLSignal o){
HDLUtils.println(dest, offset, String.format("process(%s)", o.getModule().getSysClkName()));
}
private void genAsyncProcessHeader(HDLSignal o){
String s = "";
String sep = "";
for(HDLSignal src: o.getDriveSignals()){
s += sep + src.getName();
sep = ", ";
}
HDLUtils.println(dest, offset, String.format("process(%s)", s));
}
private void genSignalRegisterProcess(HDLSignal o){
if(o.getModule().isSynchronous()){
genSyncProcessHeader(o);
}else{
genAsyncProcessHeader(o);
}
HDLUtils.println(dest, offset, "begin");
if(o.getModule().isSynchronous()){
genSyncProcess(o, offset+2);
}else{
genAsyncProcess(o, offset+2);
}
HDLUtils.println(dest, offset, "end process;");
HDLUtils.nl(dest);
}
private String adjustTypeFor(HDLSignal dest, HDLExpr expr){
if(expr instanceof HDLValue && !expr.getType().isDigit()) return expr.getVHDL();
if(expr instanceof HDLPreDefinedConstant) return expr.getVHDL();
if(dest.getType().getKind() == expr.getType().getKind()){
return expr.getVHDL();
}else{
String src = expr.getVHDL();
if(expr instanceof HDLValue &&
expr.getType().isDigit() &&
dest.getType() instanceof HDLPrimitiveType &&
(dest.getType().isVector() || dest.getType().isSigned())){
src = String.format("to_signed(%s, %d)", src, ((HDLPrimitiveType)dest.getType()).getWidth());
}
if(dest.getType().isBit()){
return String.format("std_logic(%s)", src);
}else if(dest.getType().isVector()){
if(dest.getType().getWidth() != expr.getType().getWidth()){
SynthesijerUtils.warn(String.format("Destination(%s) is %dbit, but source(%s) is %dbit. It is forced for destination.",
dest.getVHDL(), dest.getType().getWidth(), src, expr.getType().getWidth()));
if(dest.getType().getWidth() < expr.getType().getWidth()){
src = String.format("%s(%d-1 downto %d)", src, dest.getType().getWidth(), 0);
}else if(dest.getType().getWidth() > expr.getType().getWidth()){
String s = "";
for(int i = 0; i < dest.getType().getWidth()-expr.getType().getWidth(); i++){
s += src + "(" + (expr.getType().getWidth()-1) + ")" + " & ";
}
src = s + src;
}
}
return String.format("std_logic_vector(%s)", src);
}else if(dest.getType().isSigned()){
if(dest.getType().getWidth() != expr.getType().getWidth()){
SynthesijerUtils.warn(String.format("Destination(%s) is %dbit, but source(%s) is %dbit. It is forced for destination.",
dest.getVHDL(), dest.getType().getWidth(), src, expr.getType().getWidth()));
if(dest.getType().getWidth() < expr.getType().getWidth()){
src = String.format("%s(%d-1 downto %d)", src, dest.getType().getWidth(), 0);
}else if(dest.getType().getWidth() > expr.getType().getWidth()){
String s = "";
for(int i = 0; i < dest.getType().getWidth()-expr.getType().getWidth(); i++){
s += src + "(" + (expr.getType().getWidth()-1) + ")" + " & ";
}
src = s + src;
}
}
return String.format("signed(%s)", src);
}else{
SynthesijerUtils.error("cannot assign:" + dest + " <- " + expr);
throw new RuntimeException("cannot assign:" + dest + " <- " + expr);
}
}
}
@Override
public void visitHDLSignal(HDLSignal o) {
if(o.isRegister() && o.isAssignSignalEvent()){
HDLUtils.println(dest, offset, String.format("process(%s)", o.getAssignSignalEventSignal().getName()));
HDLUtils.println(dest, offset, "begin");
HDLUtils.println(dest, offset+2, String.format("if %s'event and %s = '1' then", o.getAssignSignalEventSignal().getName(), o.getAssignSignalEventSignal().getName()));
HDLUtils.println(dest, offset+4, String.format("%s <= %s;", o.getName(), adjustTypeFor(o, o.getAssignSignalEventExpr().getResultExpr())));
HDLUtils.println(dest, offset+2, "end if;");
HDLUtils.println(dest, offset, "end process;");
HDLUtils.nl(dest);
}else if(o.isRegister() && o.isAssignPortEvent()){
HDLUtils.println(dest, offset, String.format("process(%s)", o.getAssignPortEventPort().getName()));
HDLUtils.println(dest, offset, "begin");
HDLUtils.println(dest, offset+2, String.format("if %s'event and %s = '1' then", o.getAssignPortEventPort().getName(), o.getAssignPortEventPort().getName()));
HDLUtils.println(dest, offset+4, String.format("%s <= %s;", o.getName(), adjustTypeFor(o, o.getAssignPortEventExpr().getResultExpr())));
HDLUtils.println(dest, offset+2, "end if;");
HDLUtils.println(dest, offset, "end process;");
HDLUtils.nl(dest);
}else if(o.isRegister() && !o.isAssignAlways()){
if(o.isIgnore()) return;
if(o.getConditions().length == 0 && o.hasDefaultValue() == false) return;
// if(o.getConditions().length == 0) return;
genSignalRegisterProcess(o);
}else if(o.isAssignAlways()){
HDLUtils.println(dest, offset, String.format("%s <= %s;", o.getName(), adjustTypeFor(o, o.getAssignAlwaysExpr().getResultExpr())));
HDLUtils.nl(dest);
}
}
@Override
public void visitHDLType(HDLPrimitiveType o) {
// TODO Auto-generated method stub
}
@Override
public void visitHDLUserDefinedType(HDLUserDefinedType o) {
// TODO Auto-generated method stub
}
@Override
public void visitHDLInstanceRef(HDLInstanceRef o){
}
}