X-Git-Url: http://git.megacz.com/?a=blobdiff_plain;f=src%2Fedu%2Fberkeley%2Ffleet%2Ffpga%2Fverilog%2FVerilog.java;h=44d02e594c6524f0ce1e930e9f95a8c4be9c06bb;hb=8ef6f34f6a3eea2a8c2a60139e90fb07e3cf96de;hp=9ad420d0a0cfd82a51add82572d0bbfc3e92d244;hpb=30f7bb5b3132e52cf3a272cd14d9d3a1dd0f6c2a;p=fleet.git diff --git a/src/edu/berkeley/fleet/fpga/verilog/Verilog.java b/src/edu/berkeley/fleet/fpga/verilog/Verilog.java index 9ad420d..44d02e5 100644 --- a/src/edu/berkeley/fleet/fpga/verilog/Verilog.java +++ b/src/edu/berkeley/fleet/fpga/verilog/Verilog.java @@ -8,137 +8,331 @@ import java.util.*; import java.io.*; import static edu.berkeley.fleet.two.FleetTwoFleet.*; +/* + +- ideally: want to merge Fpga.dump() with this... but have to resolve + the handling of flushing first. + +- eliminate uses of SimpleXXX + - force width parameter in remaining uses + - re-enable width checking (add zero-extend and sign-extend) + +- ideally: make getVerilog() package-private somehow + +- change Event constructors from Object[] to Event[]/Action[] +- change portorder to LinkedHashMap + +=> mangle the names given for strings +=> ensure uniquification of percolated ports + +=> later: scan chain +*/ + +/** + * Among the benefits are: + * - automatic scan-chain insertion + * - better error-checking (for example, width mismatches) than Verilog provides + * - pin percolation + * + * One of the most annoying things about Verilog is that you cannot + * "double-slice" a value; in other words, foo[10:2] is valid + * Verilog, but foo[10:2][4:3] is not; the programmer must write + * foo[4+2:3+2]. This lack of compositionality is the reason for + * most of the complexity in the Value class. + */ public class Verilog { + public static final int FORWARD_LATENCY = 6; // must be >=1 + public static final int REVERSE_LATENCY = 4; // must be >=3 + + public static interface Value { + public String getVerilog(); + public Value getBits(int high, int low); + public Value getBits(Mask mask); + public Trigger testMask(Mask mask); + public Value invertBits(); + public int getWidth(); + } + public static class SimpleValue implements Value { public final String s; - public SimpleValue(String s) { this.s = s; } - public SimpleValue(String s, int high, int low) { this.s = s+"["+high+":"+low+"]"; } - public Value getBits(int high, int low) { return new SimpleValue(s, high, low); } + private final String s0; + private final int high; + private final int low; + private final int width; + public SimpleValue(String s) { this(s, -1); } + public SimpleValue(String s, int width) { + this.s = s; + this.s0 = s; + this.high = -1; + this.low = -1; + this.width = width; + } + public SimpleValue(String s, int high, int low) { + this.s = s+"["+high+":"+low+"]"; + this.s0 = s; + this.high = high; + this.low = low; + this.width = 1+high-low; + } public Value getBits(Mask mask) { return getBits(mask.valmaskmax, mask.valmaskmin); } - public Assignable getAssignableBits(int high, int low) { return new SimpleValue(s, high, low); } - public String getVerilogName() { return s; } - public String toString() { return s; } - public Value invertBits() { return new SimpleValue("~("+getVerilogName()+")"); } + public Trigger testMask(Mask mask) { return new SimpleTrigger(mask.verilog(getVerilog())); } + public Value getBits(int high, int low) { + if (this.high==-1 && this.low==-1) return new SimpleValue(s, high, low); + if (high+this.low > this.high) throw new RuntimeException("out of range"); + return new SimpleValue(s0, high+this.low, low+this.low); + } + public String getVerilog() { return s; } + public Value invertBits() { return new SimpleValue("~("+getVerilog()+")",width); } + public int getWidth() { + if (width==-1) throw new RuntimeException("not implemented"); + return width; + } + } + + public static class MuxValue implements Value { + private final Trigger sel; + private final Value if0; + private final Value if1; + public MuxValue(Trigger sel, Value if1, Value if0) { + this.sel = sel; + this.if0 = if0; + this.if1 = if1; + if (if0.getWidth() != if1.getWidth()) + throw new RuntimeException("width mismatch; "+if0+"="+if0.getWidth()+", "+if1+"="+if1.getWidth()); + } + public int getWidth() { return if0.getWidth(); } + public String getVerilog() { return "("+sel.getVerilogTrigger()+" ? "+if1.getVerilog()+" : "+if0.getVerilog()+")"; } + public Value getBits(int high, int low) { return new MuxValue(sel, if1.getBits(high,low), if0.getBits(high,low)); } + public Value getBits(Mask mask) { return new MuxValue(sel, if1.getBits(mask), if0.getBits(mask)); } + public Value invertBits() { return new MuxValue(sel, if1.invertBits(), if0.invertBits()); } + public Trigger testMask(Mask mask) { return new SimpleTrigger(mask.verilog(getVerilog())); } + } + + public static class ConstantValue implements Value { + private final BitVector bits; + public ConstantValue(BitVector bits) { this.bits = bits; } + public Value getBits(int high, int low) { return new ConstantValue(bits.get(high, low)); } + public Value getBits(Mask mask) { throw new RuntimeException("FIXME"); } + public Value invertBits() { + BitVector ret = new BitVector(bits.length()); + for(int i=0; i=0; i--) + sb.append(bits.get(i) ? '1' : '0'); + return sb.toString(); + } + public Trigger testMask(Mask mask) { return new SimpleTrigger(mask.verilog(getVerilog())); } + public int getWidth() { return bits.length(); } } public static class CatValue implements Value { private final Value[] values; public CatValue(Value[] values) { this.values = values; } public Value getBits(Mask mask) { return getBits(mask.valmaskmax, mask.valmaskmin); } - public Value getBits(int high, int low) { - throw new RuntimeException(); - } - public Assignable getAssignableBits(int high, int low) { - throw new RuntimeException(); + public Value getBits(int high, int low) { throw new RuntimeException(); } + public int getWidth() { + int ret = 0; + for (Value val : values) ret += val.getWidth(); + return ret; } - public String toString() { return getVerilogName(); } - public String getVerilogName() { + public String getVerilog() { StringBuffer sb = new StringBuffer(); sb.append("{ "); boolean first = true; for(int i=0; i="+v2.getVerilog()+")"; + case LT: return "("+v1.getVerilog()+"<" +v2.getVerilog()+")"; + case GT: return "("+v1.getVerilog()+">" +v2.getVerilog()+")"; + } + throw new RuntimeException("impossible"); + } + public Value getBits(int high, int low) { throw new RuntimeException("you probably didn't mean to do this"); } + public Value getBits(Mask mask) { throw new RuntimeException("you probably didn't mean to do this"); } + public Trigger testMask(Mask mask) { throw new RuntimeException("you probably didn't mean to do this"); } + public Trigger invert() { return invertMe(); } + public Value invertBits() { return invertMe(); } + private TestValue invertMe() { + switch(tt) { + case NE: return new TestValue(v1, TestType.EQ, v2); + case EQ: return new TestValue(v1, TestType.NE, v2); + case LE: return new TestValue(v1, TestType.GT, v2); + case GE: return new TestValue(v1, TestType.LT, v2); + case LT: return new TestValue(v1, TestType.GE, v2); + case GT: return new TestValue(v1, TestType.LE, v2); + } + throw new RuntimeException("impossible"); + } + public int getWidth() { return 1; } } + // Triggers ////////////////////////////////////////////////////////////////////////////// + public static interface Trigger { public String getVerilogTrigger(); public Trigger invert(); } - public static class InvertedTrigger implements Trigger { - private final Trigger original; - public InvertedTrigger(Trigger original) { this.original = original; } - public String getVerilogTrigger() { return "!("+original.getVerilogTrigger()+")"; } - public Trigger invert() { return original; } + public static class SimpleTrigger implements Trigger { + private final String s; + public SimpleTrigger(String s) { this.s = s; } + public String getVerilogTrigger() { return s; } + public Trigger invert() { return new SimpleTrigger("!("+s+")"); } } - public static interface Assignable { - public String getVerilogName(); - public Assignable getAssignableBits(int high, int low); + public static class AndTrigger implements Trigger { + private final Trigger t1, t2; + public AndTrigger(Trigger t1, Trigger t2) { this.t1 = t1; this.t2 = t2; } + public String getVerilogTrigger() { return "("+t1.getVerilogTrigger()+" && "+t2.getVerilogTrigger()+")"; } + public Trigger invert() { return new InvertedTrigger(this); } } - public static interface Value extends Assignable { - public String getVerilogName(); - public Value getBits(int high, int low); - public Value getBits(Mask mask); - public Value invertBits(); + public static class OrTrigger implements Trigger { + private final Trigger t1, t2; + public OrTrigger(Trigger t1, Trigger t2) { this.t1 = t1; this.t2 = t2; } + public String getVerilogTrigger() { return "("+t1.getVerilogTrigger()+" || "+t2.getVerilogTrigger()+")"; } + public Trigger invert() { return new InvertedTrigger(this); } } - public static class ConditionalAction implements Action { - public String condition; - public Action action; - public ConditionalAction(String condition, Action action) { - this.condition = condition; - this.action = action; - } - public String toString() { return getVerilogAction(); } - public String getVerilogAction() { return "if ("+condition+") begin "+action.getVerilogAction()+" end"; } + public static class InvertedTrigger implements Trigger { + private final Trigger original; + public InvertedTrigger(Trigger original) { this.original = original; } + public String getVerilogTrigger() { return "!("+original.getVerilogTrigger()+")"; } + public Trigger invert() { return original; } } public static class ConditionalTrigger implements Trigger { - public String condition; + public Trigger condition; public Trigger trigger; - public ConditionalTrigger(String condition, Trigger trigger) { + public ConditionalTrigger(Trigger condition, Trigger trigger) { this.condition = condition; this.trigger = trigger; - if (trigger instanceof Module.Port) - ((Module.Port)trigger).hasLatch = true; } public String getVerilogTrigger() { - return "&& (("+condition+") ? (1 " + trigger.getVerilogTrigger() + ") : 1)"; + return "(("+condition.getVerilogTrigger()+") ? (" + trigger.getVerilogTrigger() + ") : 1)"; } public Trigger invert() { return new InvertedTrigger(this); } } - public static class SimpleAssignable implements Assignable { - public final String s; - public SimpleAssignable(String s) { this.s = s; } - public String getVerilogName() { return s; } - public Assignable getAssignableBits(int high, int low) { return new SimpleValue(s, high, low); } - public Value invertBits() { return new SimpleValue("~("+getVerilogName()+")"); } + // Actions ////////////////////////////////////////////////////////////////////////////// + + public static interface Action { + public String getVerilogAction(); + } + + public static class ConditionalAction implements Action { + public Trigger condition; + public Action action; + public ConditionalAction(Trigger condition, Action action) { + this.condition = condition; + this.action = action; + } + public String getVerilogAction() { return "if ("+condition.getVerilogTrigger()+") begin "+action.getVerilogAction()+" end"; } } public static class AssignAction implements Action { - public String left; - public String right; + public Assignable left; + public Value right; public AssignAction(Assignable left, Value right) { - this.left = left.getVerilogName(); - this.right = right.getVerilogName().toString(); - } - public AssignAction(Assignable left, String right) { - this.left = left.getVerilogName(); + this.left = left; this.right = right; } - public String getVerilogAction() { return left + "<=" + right + ";"; } - public String toString() { return getVerilogAction(); } + public String getVerilogAction() { return left.getVerilog() + "<=" + right.getVerilog() + ";"; } + } + + // Assignables ////////////////////////////////////////////////////////////////////////////// + + public static interface Assignable { + public String getVerilog(); } - - public static class SimpleAction implements Action { - public final String verilog; - public SimpleAction(String verilog) { this.verilog = verilog; } - public String getVerilogAction() { return verilog; } - public String toString() { return verilog; } + + public static class SimpleAssignable implements Assignable { + public final String s; + public SimpleAssignable(String s) { this.s = s; } + public String getVerilog() { return s; } } + // Module Internals ////////////////////////////////////////////////////////////////////////////// + public static class Module { + // order matters here + public LinkedHashMap instantiatedModules = new LinkedHashMap(); + public void dump(String prefix) throws IOException { PrintWriter pw = new PrintWriter(new OutputStreamWriter(new FileOutputStream(prefix+"/"+name+".v"))); dump(pw, true); pw.flush(); - for(InstantiatedModule m : instantiatedModules) + for(InstantiatedModule m : instantiatedModules.values()) m.module.dump(prefix); } public int id = 0; @@ -146,7 +340,8 @@ public class Verilog { public String getName() { return name; } public Port getPort(String name) { return ports.get(name); } - public HashSet instantiatedModules = new HashSet(); + // order matters here + public LinkedList percolatedPorts = new LinkedList(); public final ArrayList events = new ArrayList(); // FIXME: always-alphabetical convention? @@ -154,53 +349,24 @@ public class Verilog { public final ArrayList portorder = new ArrayList(); public final HashMap statewires = new HashMap(); public final HashMap latches = new HashMap(); + public final HashMap wires = new HashMap(); - public StringBuffer crap = new StringBuffer(); - public StringBuffer precrap = new StringBuffer(); - //public void addCrap(String s) { crap.append(s); crap.append('\n'); } - public void addPreCrap(String s) { precrap.append(s); precrap.append('\n'); } - public void addPreCrap0(String s) { precrap.append(s); } - - public Module(String name) { - this.name = name; - } + public Module(String name) { this.name = name; } - public SourcePort createInputPort(String name, int width) { - if (ports.get(name)!=null) throw new RuntimeException(); - return new SourcePort(name, width, true); - } - public SourcePort getInputPort(String name) { - SourcePort ret = (SourcePort)ports.get(name); - if (ret==null) throw new RuntimeException(); - return ret; - } - public SinkPort createOutputPort(String name, int width, String resetBehavior) { - if (ports.get(name)!=null) throw new RuntimeException(); - return new SinkPort(name, width, true, resetBehavior); - } - public SinkPort createWirePort(String name, int width) { - if (ports.get(name)!=null) throw new RuntimeException(); - return new SinkPort(name, width, false, ""); - } - public SourcePort createWireSourcePort(String name, int width) { - if (ports.get(name)!=null) throw new RuntimeException(); - return new SourcePort(name, width, false); - } - public SinkPort getOutputPort(String name) { - SinkPort ret = (SinkPort)ports.get(name); - if (ret==null) throw new RuntimeException(); - return ret; - } + public SourcePort createInputPort(String name, int width) { return new SourcePort(name, width, true); } + public SinkPort createOutputPort(String name, int width) { return new SinkPort(name, width, true); } + + // Latches and Wires ////////////////////////////////////////////////////////////////////////////// public class StateWire { public final String name; public final boolean initiallyFull; public String getName() { return name; } - public Action isFull() { return new SimpleAction(name+"==1"); } - public Action isEmpty() { return new SimpleAction(name+"==0"); } - public Action doFill() { return new SimpleAction(name+"<=1;"); } - public Action doDrain() { return new SimpleAction(name+"<=0;"); } - public String doReset() { return name+"<="+(initiallyFull?"1":"0")+";"; } + public Trigger isFull() { return new SimpleTrigger("("+name+"==1)"); } + public Trigger isEmpty() { return new SimpleTrigger("("+name+"==0)"); } + public Action doFill() { return new AssignAction(new SimpleAssignable(name), new ConstantValue(new BitVector(1).set(1))); } + public Action doDrain() { return new AssignAction(new SimpleAssignable(name), new ConstantValue(new BitVector(1).set(0))); } + public String getResetCode() { return name+"<="+(initiallyFull?"1":"0")+";"; } public StateWire(String name) { this(name, false); } public StateWire(String name, boolean initiallyFull) { this.name = name; @@ -224,383 +390,346 @@ public class Verilog { this.initial = initial; latches.put(name, this); } - public String getVerilogName() { return name; } - public Value getBits(int high, int low) { return new SimpleValue(getVerilogName(), high, low); } + public int getWidth() { return width; } + public String getVerilog() { return name; } + public Value getBits(int high, int low) { return new SimpleValue(getVerilog(), high, low); } public Value getBits(Mask mask) { return getBits(mask.valmaskmax, mask.valmaskmin); } - public Value invertBits() { return new SimpleValue("~("+getVerilogName()+")"); } - public Assignable getAssignableBits(int high, int low) { return new SimpleValue(getVerilogName(), high, low); } - public String doReset() { return name+"<="+initial+";"; } + public Value invertBits() { return new SimpleValue("~("+getVerilog()+")",getWidth()); } + public String getResetCode() { return name+"<="+initial+";"; } public void dump(PrintWriter pw) { pw.println(" reg ["+(width-1)+":0] "+name+";"); pw.println(" initial "+name+"="+initial+";"); } - public void connect(SinkPort driven) { - driven.latchDriver = this; - } + public Trigger testMask(Mask mask) { return new SimpleTrigger(mask.verilog(getVerilog())); } } - public abstract class Port implements Action, Assignable, Trigger { - public abstract String doReset(); + public class WireValue implements Value { public final String name; - public String getName() { return name; } public final int width; + public final Value assign; + public WireValue(String name, int width, Value assign) { + this.width = width; + this.name = name; + this.assign = assign; + wires.put(name, this); + } public int getWidth() { return width; } - public boolean hasLatch = false; - public boolean external; + public String getVerilog() { return name; } + public Value getBits(int high, int low) { return new SimpleValue(getVerilog(), high, low); } + public Value getBits(Mask mask) { return getBits(mask.valmaskmax, mask.valmaskmin); } + public Value invertBits() { return new SimpleValue("~("+getVerilog()+")",getWidth()); } + public Trigger testMask(Mask mask) { return new SimpleTrigger(mask.verilog(getVerilog())); } + public void dump(PrintWriter pw) { pw.println(" wire ["+(width-1)+":0] "+name+";"); } + public String getAssignments() { return " assign "+name+" = "+assign.getVerilog()+";"; } + } + + // Ports ////////////////////////////////////////////////////////////////////////////// + + public abstract class Port implements Action, Trigger { + final String name; + final int width; + final boolean external; public Port(String name, int width, boolean external) { this.width = width; this.name = name; this.external = external; + if (ports.get(name)!=null) + throw new RuntimeException("port "+name+" already exists"); ports.put(name, this); if (external) portorder.add(name); } - public String getVerilogName() { return name; } + public String getName() { return name; } + public int getWidth() { return width; } + public String getVerilog() { return name; } String getAck() { return name+"_a"; } String getReq() { return name+"_r"; } - public String isFull() { return "("+name+"_r"+" && !"+name+"_a)"; } + public String isFull() { return "("+getReq()+" && !"+getAck()+")"; } + public abstract String getResetCode(); public abstract String getInterface(); public abstract String getSimpleInterface(); public abstract String getDeclaration(); public abstract String getAssignments(); - public abstract void connect(SinkPort driven); + public abstract String getCleanup(); public Trigger invert() { return new InvertedTrigger(this); } - } - - public static class InstantiatedModule { - public final Module module; - public final Module thisModule; - public final int id; - public final HashMap ports = new HashMap(); - public String getName() { return module.getName()+"_"+id; } - public InstantiatedModule(Module thisModule, Module module) { - this.thisModule = thisModule; - this.module = module; - this.id = thisModule.id++; - thisModule.instantiatedModules.add(this); - } - public void dump(PrintWriter pw) { - pw.println(" " + module.getName() + " " + getName() + "(clk, rst "); - for(String s : module.portorder) - pw.println(", " + getPort(s).getSimpleInterface()); - if (module.name.equals("dram")) { - pw.println(" , dram_addr"); - pw.println(" , dram_addr_r"); - pw.println(" , dram_addr_a"); - pw.println(" , dram_isread"); - pw.println(" , dram_write_data"); - pw.println(" , dram_write_data_push"); - pw.println(" , dram_write_data_full"); - pw.println(" , dram_read_data"); - pw.println(" , dram_read_data_pop"); - pw.println(" , dram_read_data_empty"); - pw.println(" , dram_read_data_latency"); - } - if (module.name.equals("ddr2")) { - pw.println(" , ddr2_addr"); - pw.println(" , ddr2_addr_r"); - pw.println(" , ddr2_addr_a"); - pw.println(" , ddr2_isread"); - pw.println(" , ddr2_write_data"); - pw.println(" , ddr2_write_data_push"); - pw.println(" , ddr2_write_data_full"); - pw.println(" , ddr2_read_data"); - pw.println(" , ddr2_read_data_pop"); - pw.println(" , ddr2_read_data_empty"); - pw.println(" , ddr2_read_data_latency"); - } - if (module.name.equals("video")) { - pw.println(" , vga_clk"); - pw.println(" , vga_psave"); - pw.println(" , vga_hsync"); - pw.println(" , vga_vsync"); - pw.println(" , vga_sync"); - pw.println(" , vga_blank"); - pw.println(" , vga_r"); - pw.println(" , vga_g"); - pw.println(" , vga_b"); - pw.println(" , vga_clkout"); - } - pw.println(" );"); - } - public Port getPort(String name) { - return (module.ports.get(name) instanceof SinkPort) ? getOutputPort(name) : getInputPort(name); - } - public SinkPort getInputPort(String name) { - int width = module.getPort(name).getWidth(); - SinkPort port = (SinkPort)ports.get(name); - if (port == null) { - port = thisModule.new SinkPort(getName()+"_"+name, width, false, ""); - ports.put(name, port); - } - return port; - } - public SourcePort getOutputPort(String name) { - int width = module.getPort(name).getWidth(); - SourcePort port = (SourcePort)ports.get(name); - if (port == null) { - port = thisModule.new SourcePort(getName()+"_"+name, width, false); - ports.put(name, port); - } - return port; - } + public Trigger testMask(Mask mask) { return new SimpleTrigger(mask.verilog(getVerilog())); } } public class SourcePort extends Port implements Value { - public SourcePort(String name, int width, boolean external) { - super(name, width, external); } - public Value getBits(int high, int low) { return new SimpleValue(getVerilogName(), high, low); } + private SinkPort driven = null; + public SourcePort(String name, int width, boolean external) { super(name, width, external); } + public Value getBits(int high, int low) { return new SimpleValue(getVerilog(), high, low); } public Value getBits(Mask mask) { return getBits(mask.valmaskmax, mask.valmaskmin); } - public Value invertBits() { return new SimpleValue("~("+getVerilogName()+")"); } - public Assignable getAssignableBits(int high, int low) { return new SimpleValue(getVerilogName(), high, low); } - public String getVerilogTrigger() { return " && " + getReq() + " && !"+getAck(); } + public Value invertBits() { return new SimpleValue("~("+getVerilog()+")",getWidth()); } + public String getVerilogTrigger() { return getReq() + " && !"+getAck(); } public String getVerilogAction() { return getAck() + " <= 1;"; } public String getInterface() { return getReq()+", "+getAck()+"_, "+name+""; } public String getSimpleInterface() { return getReq()+", "+getAck()+", "+name+""; } - public String testBit(int index, boolean value) { - return "("+name+"["+index+"]=="+(value?1:0)+")"; - } + public String testBit(int index, boolean value) { return "("+name+"["+index+"]=="+(value?1:0)+")"; } public String getDeclaration() { StringBuffer sb = new StringBuffer(); if (external) { - sb.append("input " + name +"_r;\n"); - sb.append("output " + name +"_a_;\n"); - if (width>0) - sb.append("input ["+(width-1)+":0]" + name +";\n"); - else - sb.append("input [0:0]" + name +";\n"); // waste a bit, I guess + sb.append("input " + name +"_r;\n"); + sb.append("output " + name +"_a_;\n"); + sb.append("input ["+Math.max(0,width-1)+":0]" + name +";\n"); } else { - sb.append("wire " + name +"_r;\n"); - if (width>0) - sb.append("wire ["+(width-1)+":0]" + name +";\n"); + sb.append("wire " + name +"_r;\n"); + sb.append("wire ["+Math.max(0,width-1)+":0]" + name +";\n"); } - if (!hasLatch) { + if (driven!=null) { sb.append("wire " + name +"_a;\n"); } else { - sb.append("reg " + name +"_a;\n"); - sb.append("initial " + name +"_a = 0;\n"); + sb.append("reg " + name +"_a;\n"); + sb.append("initial " + name +"_a = 0;\n"); } return sb.toString(); } - public String doReset() { return hasLatch ? name+"_a<=1;" : ""; } + public String getCleanup() { return driven==null ? "if (!"+getReq()+" && "+getAck()+") "+getAck()+"<=0;" : ""; } + public String getResetCode() { return driven==null ? name+"_a<=1;" : ""; } public String getAssignments() { StringBuffer sb = new StringBuffer(); - if (external) - sb.append("assign " + name +"_a_ = " + name + "_a;\n"); + if (external) { + int a = REVERSE_LATENCY - 3; + if (a<0 || a>16) { + throw new RuntimeException("cannot offer latency of " + REVERSE_LATENCY +"-3"); + } else if (a==0) { + sb.append("assign " + name +"_a_ = " + name + "_a;\n"); + } else { + a = a-1; // CLK-to-Q gives us one cycle of latency anyways + sb.append("SRL16E srl16_"+name+"_a\n"); + sb.append(" (.Q ("+name+"_a_),\n"); + sb.append(" .A0 ("+((a & (1<<0)) == 0 ? 0 : 1)+"),\n"); + sb.append(" .A1 ("+((a & (1<<1)) == 0 ? 0 : 1)+"),\n"); + sb.append(" .A2 ("+((a & (1<<2)) == 0 ? 0 : 1)+"),\n"); + sb.append(" .A3 ("+((a & (1<<3)) == 0 ? 0 : 1)+"),\n"); + sb.append(" .CE (1),\n"); + sb.append(" .CLK (clk),\n"); + sb.append(" .D ("+name+"_a));\n"); + } + } return sb.toString(); } public void connect(SinkPort driven) { - driven.driver = this; + if (driven.controlDriver!=null) throw new RuntimeException("driven net already has a driver"); + if (driven.latchDriver!=null) throw new RuntimeException("driven net already has a driver"); + if (this.driven!=null) throw new RuntimeException("driver already has a driven net"); + this.driven = driven; + driven.controlDriver = this; + driven.latchDriver = this; + // FIXME + // if (getWidth() != driven.getWidth()) + // throw new RuntimeException("width mismatch: " + getWidth() + " " + driven.getWidth()); } } - public class SinkPort extends Port { - public SourcePort driver = null; - public boolean forceNoLatch = false; - public SinkPort driven = null; - public Value latchDriver = null; - public boolean noDriveLatches = false; - public final String resetBehavior; - public Assignable getAssignableBits(int high, int low) { return new SimpleValue(getVerilogName(), high, low); } + + public class SinkPort extends Port implements Assignable { + SourcePort controlDriver = null; + Value latchDriver = null; + public SinkPort(String name, int width, boolean external) { super(name, width, external); } public String getVerilogAction() { return getReq() + " <= 1;"; } - public String getVerilogTrigger() { return " && !" + getReq() + " && !"+getAck(); } - public SinkPort(String name, int width, boolean external, String resetBehavior) { - super(name, width, external); this.resetBehavior=resetBehavior; } - public String getResetBehavior() { return resetBehavior; } + public String getVerilogTrigger() { return "!" + getReq() + " && !"+getAck(); } public String getInterface() { return name+"_r_, "+name+"_a, "+name+"_"; } public String getSimpleInterface() { return name+"_r, "+name+"_a, "+name; } + public String getCleanup() { return controlDriver==null ? "if ("+getReq()+" && "+getAck()+") begin "+getReq()+"<=0; end" : ""; } + public Assignable getBits(Mask mask) { return new SimpleAssignable(name+"["+mask.valmaskmax+":"+mask.valmaskmin+"]"); } + public String getResetCode() { return controlDriver!=null ? "" : name+"_r<=0;"; } + public void connectControl(SourcePort controlDriver) { + if (this.controlDriver != null) throw new RuntimeException("attempt to connect control twice"); + this.controlDriver = controlDriver; + } + public void connectValue(Value val) { + //if (latchDriver!=null) throw new RuntimeException("attempt to re-assign via connectValue()"); + this.latchDriver = val; + // FIXME + //if (getWidth() != val.getWidth()) + //throw new RuntimeException("width mismatch: " + getWidth() + " " + val.getWidth()); + } public String getDeclaration() { StringBuffer sb = new StringBuffer(); if (external) { - sb.append("output " + name +"_r_;\n"); - sb.append("input " + name +"_a;\n"); - if (width>0) - sb.append("output ["+(width-1)+":0]" + name +"_;\n"); - else - sb.append("output [0:0]" + name +"_;\n"); // waste a bit, I guess + sb.append("output " + name +"_r_;\n"); + sb.append("input " + name +"_a;\n"); + sb.append("output ["+Math.max(0,width-1)+":0]" + name +"_;\n"); } else { sb.append("wire " + name +"_a;\n"); } - - if (forceNoLatch || latchDriver!=null) { - sb.append("reg " + name +"_r;\n"); - sb.append("initial " + name +"_r = 0;\n"); - if (width>0) - sb.append("wire ["+(width-1)+":0]" + name +";\n"); - } else if (!hasLatch) { + if (controlDriver!=null) { sb.append("wire " + name +"_r;\n"); - if (width>0) - sb.append("wire ["+(width-1)+":0]" + name +";\n"); + sb.append("wire ["+Math.max(0,width-1)+":0]" + name +";\n"); } else { sb.append("reg " + name +"_r;\n"); sb.append("initial " + name +"_r = 0;\n"); - if (width>0) { - sb.append("reg ["+(width-1)+":0]" + name +";\n"); - if (!"/*NORESET*/".equals(resetBehavior)) - sb.append("initial " + name +" = 0;\n"); - } + if (latchDriver!=null) sb.append("wire ["+Math.max(0,width-1)+":0]" + name +";\n"); + else sb.append("reg ["+Math.max(0,width-1)+":0]" + name +";\n"); } return sb.toString(); } - public String doReset() { - return (forceNoLatch||latchDriver!=null||width==0) - ? name+"_r<=0;" - : hasLatch - ? (name+"_r<=0; "+("/*NORESET*/".equals(resetBehavior) ? "" : (name+"<=0;"))) - : ""; - } public String getAssignments() { StringBuffer sb = new StringBuffer(); if (external) { - sb.append("assign " + name +"_r_ = " + name + "_r;\n"); - if (width>0) - sb.append("assign " + name +"_ = " + name + ";\n"); - } - if (driven != null) { - sb.append("assign " + driven.name +"_r = " + name + "_r;\n"); - sb.append("assign " + name +"_a = " + driven.name + "_a;\n"); - if (width>0) - sb.append("assign " + driven.name +" = " + name + ";\n"); - } - if (driver != null) { - sb.append("assign " + name +"_r = " + driver.name + "_r;\n"); - sb.append("assign " + driver.name +"_a = " + name + "_a;\n"); - if (width>0 && !noDriveLatches) - sb.append("assign " + name +" = " + driver.name + ";\n"); + int a = FORWARD_LATENCY - 1; + if (a<0 || a>16) { + throw new RuntimeException("cannot offer latency of " + FORWARD_LATENCY +"-1"); + } else if (a==0) { + sb.append("assign " + name +"_r_ = " + name + "_r;\n"); + } else { + a = a-1; // CLK-to-Q gives us one cycle of latency anyways + sb.append("SRL16E srl16_"+name+"_r\n"); + sb.append(" (.Q ("+name+"_r_),\n"); + sb.append(" .A0 ("+((a & (1<<0)) == 0 ? 0 : 1)+"),\n"); + sb.append(" .A1 ("+((a & (1<<1)) == 0 ? 0 : 1)+"),\n"); + sb.append(" .A2 ("+((a & (1<<2)) == 0 ? 0 : 1)+"),\n"); + sb.append(" .A3 ("+((a & (1<<3)) == 0 ? 0 : 1)+"),\n"); + sb.append(" .CE (1),\n"); + sb.append(" .CLK (clk),\n"); + sb.append(" .D ("+name+"_r));\n"); + } + sb.append("assign " + name +"_ = " + name + ";\n"); } - if (latchDriver != null) { - if (width>0) - sb.append("assign " + name +" = " + latchDriver.getVerilogName() + ";\n"); + if (controlDriver != null) { + sb.append("assign " + name +"_r = " + controlDriver.name + "_r;\n"); + sb.append("assign " + controlDriver.name +"_a = " + name + "_a;\n"); + if (latchDriver==null) + sb.append("assign " + name +" = " + controlDriver.name + ";\n"); } + if (latchDriver != null) + sb.append("assign " + name +" = " + latchDriver.getVerilog() + ";\n"); return sb.toString(); } - public void connect(SinkPort driven) { - this.driven = driven; - throw new RuntimeException(); - } } - public void dump(PrintWriter pw, boolean fix) { - pw.println("module "+name+"(clk, rst "); - for(String name : portorder) { - Port p = ports.get(name); - pw.println(" , " + p.getInterface()); + // InstantiatedModule ////////////////////////////////////////////////////////////////////////////// + + public static class InstantiatedModule { + public final Module module; + public final Module thisModule; + public final int id; + public final HashMap ports = new HashMap(); + private final String name; + public String getName() { return name; } + public InstantiatedModule(Module thisModule, Module module) { + this.thisModule = thisModule; + this.module = module; + // CRUDE + int id = 0; + while(thisModule.instantiatedModules.get(module.getName()+"_"+id)!=null) id++; + this.id = id; + this.name = module.getName()+"_"+id; + thisModule.instantiatedModules.put(this.name, this); + for(String s : module.portorder) + getPort(s); } - if (this.name.equals("root")) { - pw.println(" , dram_addr"); - pw.println(" , dram_addr_r"); - pw.println(" , dram_addr_a"); - pw.println(" , dram_isread"); - pw.println(" , dram_write_data"); - pw.println(" , dram_write_data_push"); - pw.println(" , dram_write_data_full"); - pw.println(" , dram_read_data"); - pw.println(" , dram_read_data_pop"); - pw.println(" , dram_read_data_empty"); - pw.println(" , dram_read_data_latency"); - pw.println(" , vga_clk"); - pw.println(" , vga_psave"); - pw.println(" , vga_hsync"); - pw.println(" , vga_vsync"); - pw.println(" , vga_sync"); - pw.println(" , vga_blank"); - pw.println(" , vga_r"); - pw.println(" , vga_g"); - pw.println(" , vga_b"); - pw.println(" , vga_clkout"); - pw.println(" , ddr2_addr"); - pw.println(" , ddr2_addr_r"); - pw.println(" , ddr2_addr_a"); - pw.println(" , ddr2_isread"); - pw.println(" , ddr2_write_data"); - pw.println(" , ddr2_write_data_push"); - pw.println(" , ddr2_write_data_full"); - pw.println(" , ddr2_read_data"); - pw.println(" , ddr2_read_data_pop"); - pw.println(" , ddr2_read_data_empty"); - pw.println(" , ddr2_read_data_latency"); + public void dump(PrintWriter pw) { + pw.println(" " + module.getName() + " " + getName() + "(clk, rst "); + for(String s : module.portorder) + pw.println(", " + getPort(s).getSimpleInterface()); + for(PercolatedPort pp : module.percolatedPorts) + pw.println(" , "+pp.name); + pw.println(" );"); } - pw.println(" );"); - pw.println(); - pw.println(" input clk;"); - pw.println(" input rst;"); - if (this.name.equals("root")) { - pw.println("output [31:0] dram_addr;"); - pw.println("output dram_addr_r;"); - pw.println("input dram_addr_a;"); - pw.println("output dram_isread;"); - pw.println("output [63:0] dram_write_data;"); - pw.println("output dram_write_data_push;"); - pw.println("input dram_write_data_full;"); - pw.println("input [63:0] dram_read_data;"); - pw.println("output dram_read_data_pop;"); - pw.println("input dram_read_data_empty;"); - pw.println("input [1:0] dram_read_data_latency;"); - pw.println("output [31:0] ddr2_addr;"); - pw.println("output ddr2_addr_r;"); - pw.println("input ddr2_addr_a;"); - pw.println("output ddr2_isread;"); - pw.println("output [63:0] ddr2_write_data;"); - pw.println("output ddr2_write_data_push;"); - pw.println("input ddr2_write_data_full;"); - pw.println("input [63:0] ddr2_read_data;"); - pw.println("output ddr2_read_data_pop;"); - pw.println("input ddr2_read_data_empty;"); - pw.println("input [1:0] ddr2_read_data_latency;"); - pw.println("input vga_clk;"); - pw.println("output vga_psave;"); - pw.println("output vga_hsync;"); - pw.println("output vga_vsync;"); - pw.println("output vga_sync;"); - pw.println("output vga_blank;"); - pw.println("output [7:0] vga_r;"); - pw.println("output [7:0] vga_g;"); - pw.println("output [7:0] vga_b;"); - pw.println("output vga_clkout;"); + public Port getPort(String name) { + return (module.ports.get(name) instanceof SinkPort) ? getOutputPort(name) : getInputPort(name); } - for(String name : ports.keySet()) { - Port p = ports.get(name); - pw.println(" " + p.getDeclaration()); + public SinkPort getInputPort(String name) { + int width = module.getPort(name).getWidth(); + SinkPort port = (SinkPort)ports.get(name); + if (port == null) { + port = thisModule.new SinkPort(getName()+"_"+name, width, false); + ports.put(name, port); + } + return port; } - for(StateWire sw : statewires.values()) - sw.dump(pw); - for(Latch l : latches.values()) - l.dump(pw); - for(String name : ports.keySet()) { - Port p = ports.get(name); - pw.println(" " + p.getAssignments()); + public SourcePort getOutputPort(String name) { + int width = module.getPort(name).getWidth(); + SourcePort port = (SourcePort)ports.get(name); + if (port == null) { + port = thisModule.new SourcePort(getName()+"_"+name, width, false); + ports.put(name, port); + } + return port; } - for(InstantiatedModule m : instantiatedModules) { - m.dump(pw); + } + + public void dump(PrintWriter pw, boolean fix) { + if (!fix) throw new RuntimeException(); + boolean isRoot = name.equals("main"); + pw.print("module "+name); + pw.println(isRoot ? "(rst_pin " : "(clk, rst "); + for(String name : portorder) pw.println(" , " + ports.get(name).getInterface()); + for (InstantiatedModule im : this.instantiatedModules.values()) + for(PercolatedPort pp : im.module.percolatedPorts) + if (!isRoot || (!pp.name.startsWith("root_in_") && !pp.name.startsWith("rst_"))) + pw.println(" , "+pp.name); + pw.println(" );"); + pw.println(); + + if (isRoot) { + pw.println(" input rst_pin;"); + pw.println(" wire clk;"); + pw.println(" wire clk_fb;"); + pw.println(" wire clk_unbuffered;"); + + /* + pw.println(" DCM"); + pw.println(" #("); + pw.println(" .CLKFX_MULTIPLY(4),"); + pw.println(" .CLKFX_DIVIDE(8),"); + pw.println(" .CLKIN_PERIOD(\"10 ns\")"); + pw.println(" ) mydcm("); + pw.println(" .CLKIN (clk_pin),"); + pw.println(" .CLKFB(clk_fb),"); + pw.println(" .CLKFX (clk_unbuffered),"); + pw.println(" .CLK0 (clk_fb)"); + pw.println(" );"); + */ + pw.println(" wire rst;"); + } else { + pw.println(" input clk;"); + pw.println(" input rst;"); } - pw.println(precrap); - pw.println("always @(posedge clk) begin"); - pw.println(" if (!rst) begin"); - for(Latch l : latches.values()) - pw.println(l.doReset()); - for(StateWire sw : statewires.values()) - pw.println(sw.doReset()); - for(Port p : ports.values()) - pw.println(p.doReset()); - pw.println(" end else begin"); - for(Port p : ports.values()) { - if (p instanceof SourcePort) { - SourcePort ip = (SourcePort)p; - if (ip.hasLatch) - pw.println("if (!"+ip.getReq()+" && "+ip.getAck()+") "+ip.getAck()+"<=0;"); - } else { - SinkPort op = (SinkPort)p; - if (op.hasLatch) - pw.println("if ("+op.getReq()+" && "+op.getAck()+") begin "+ - op.getReq()+"<=0; "+ - op.getResetBehavior()+" end"); + + for (InstantiatedModule im : this.instantiatedModules.values()) + for(PercolatedPort pp : im.module.percolatedPorts) { + if (isRoot && (pp.name.startsWith("root_in_") || pp.name.startsWith("rst_"))) + pw.print("wire"); + else switch(pp.type) { + case UP: pw.print("output"); break; + case DOWN: pw.print("input"); break; + case INOUT: pw.print("inout"); break; + } + pw.print(" "); + if (pp.width > 1) + pw.print("["+(pp.width-1)+":0]"); + pw.print(" "); + pw.print(pp.name); + pw.println(";"); } + + if (isRoot) { + pw.println(" assign rst = rst_out;"); + pw.println(" assign rst_in = !rst_pin;"); + pw.println(" BUFG GBUF_FOR_MUX_CLOCK (.I(clk_unbuffered), .O(clk));"); + pw.println(" assign clk_unbuffered = clk_out;"); } + + for(String name : ports.keySet()) pw.println(" " + ports.get(name).getDeclaration()); + for(StateWire sw : statewires.values()) sw.dump(pw); + for(Latch l : latches.values()) l.dump(pw); + for(WireValue wv : wires.values()) wv.dump(pw); + for(String name : ports.keySet()) pw.println(" " + ports.get(name).getAssignments()); + for(WireValue wv : wires.values()) pw.println(" " + wv.getAssignments()); + for(InstantiatedModule m : instantiatedModules.values()) m.dump(pw); + pw.println("always @(posedge clk) begin"); + pw.println(" if (rst) begin"); + for(Latch l : latches.values()) pw.println(l.getResetCode()); + for(StateWire sw : statewires.values()) pw.println(sw.getResetCode()); + for(Port p : ports.values()) pw.println(p.getResetCode()); + pw.println(" end else begin"); + for(Port p : ports.values()) pw.println(p.getCleanup()); for(Event a : events) a.dump(pw, fix); pw.println(" begin end"); pw.println(" end"); pw.println(" end"); - - pw.println(crap); pw.println("endmodule"); } @@ -612,14 +741,12 @@ public class Verilog { Module.this.events.add(this); this.triggers = triggers; this.actions = actions; - for(int i=0; i