package edu.berkeley.fleet.fpga.verilog;
import edu.berkeley.fleet.api.*;
import edu.berkeley.fleet.two.*;
+import edu.berkeley.fleet.util.*;
import edu.berkeley.fleet.*;
import java.lang.reflect.*;
-import edu.berkeley.sbp.chr.*;
-import edu.berkeley.sbp.misc.*;
-import edu.berkeley.sbp.meta.*;
-import edu.berkeley.sbp.util.*;
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); }
- public Assignable getAssignableBits(int high, int low) { return new SimpleValue(s, high, low); }
- public String getVerilogName() { return s; }
- public String toString() { return s; }
+ 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 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<bits.length(); i++) ret.set(i, !bits.get(i));
+ return new ConstantValue(ret);
+ }
+ public String getVerilog() {
+ StringBuffer sb = new StringBuffer();
+ sb.append(bits.length());
+ sb.append("'b");
+ for(int i=bits.length()-1; 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(int high, int low) {
- throw new RuntimeException();
- }
- public Assignable getAssignableBits(int high, int low) {
- throw new RuntimeException();
+ public Value getBits(Mask mask) { return getBits(mask.valmaskmax, mask.valmaskmin); }
+ 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<values.length; i++) {
if (values[i]==null) continue;
if (!first) sb.append(", ");
- sb.append(values[i].getVerilogName());
+ sb.append(values[i].getVerilog());
first = false;
}
sb.append(" }");
return sb.toString();
}
+ public Value invertBits() {
+ Value[] newvals = new Value[values.length];
+ for(int i=0; i<values.length; i++)
+ newvals[i] = values[i].invertBits();
+ return new CatValue(newvals);
+ }
+ public Trigger testMask(Mask mask) { return new SimpleTrigger(mask.verilog(getVerilog())); }
}
- public static interface Action {
- public String getVerilogAction();
+ public static class LogicValue implements Value {
+ public static enum LogicType { OR, AND };
+ private final Value v1;
+ private final Value v2;
+ private final LogicType tt;
+ public LogicValue(Value v1, LogicType tt, Value v2) {
+ this.v1 = v1;
+ this.v2 = v2;
+ this.tt = tt;
+ // FIXME: check width match
+ }
+ public String getVerilog() {
+ switch(tt) {
+ case OR: return "("+v1.getVerilog()+"||"+v2.getVerilog()+")";
+ case AND: return "("+v1.getVerilog()+"&&"+v2.getVerilog()+")";
+ }
+ throw new RuntimeException("impossible");
+ }
+ public Value getBits(int high, int low) { return new LogicValue(v1.getBits(high,low),tt,v2.getBits(high,low)); }
+ public Value getBits(Mask mask) { return new LogicValue(v1.getBits(mask),tt,v2.getBits(mask)); }
+ public Trigger testMask(Mask mask) { throw new RuntimeException("FIXME"); }
+ public Value invertBits() {
+ switch(tt) {
+ case OR: return new LogicValue(v1.invertBits(), LogicType.AND, v2.invertBits());
+ case AND: return new LogicValue(v1.invertBits(), LogicType.OR, v2.invertBits());
+ }
+ throw new RuntimeException("impossible");
+ }
+ public int getWidth() { return v1.getWidth(); }
+ }
+
+ public static class TestValue implements Value, Trigger {
+ public static enum TestType { NE, EQ, LT, GT, LE, GE };
+ private final Value v1;
+ private final Value v2;
+ private final TestType tt;
+ public TestValue(Value v1, TestType tt, Value v2) {
+ this.v1 = v1;
+ this.v2 = v2;
+ this.tt = tt;
+ // FIXME: check width match
+ }
+ public String getVerilogTrigger() { return getVerilog(); }
+ public String getVerilog() {
+ switch(tt) {
+ case NE: return "("+v1.getVerilog()+"!="+v2.getVerilog()+")";
+ case EQ: return "("+v1.getVerilog()+"=="+v2.getVerilog()+")";
+ case LE: return "("+v1.getVerilog()+"<="+v2.getVerilog()+")";
+ case GE: return "("+v1.getVerilog()+">="+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 interface Assignable {
- public String getVerilogName();
- public Assignable getAssignableBits(int high, int low);
+ 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 Value extends Assignable {
- public String getVerilogName();
- public Value getBits(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 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 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 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); }
+ // 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() + ";"; }
}
-
- 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; }
+
+ // Assignables //////////////////////////////////////////////////////////////////////////////
+
+ public static interface Assignable {
+ public String getVerilog();
}
+ 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 {
public void dump(String prefix) throws IOException {
- PrintWriter pw = new PrintWriter(new OutputStreamWriter(new FileOutputStream(prefix+"/bitfields.v")));
- pw.println("`define DATAWIDTH "+WIDTH_WORD);
- pw.println("`define CODEBAG_SIZE_BITS "+CBD_SIZE.valmaskwidth);
- pw.println("`define INSTRUCTION_WIDTH "+WIDTH_WORD);
- pw.println("`define packet_token(p) "+PACKET_TOKEN.verilogVal("p"));
- pw.println("`define packet_data(p) "+PACKET_DATA.verilogVal("p"));
- pw.println("`define packet_dest(p) "+PACKET_DEST.verilogVal("p"));
- pw.println("`define instruction_dest(p) "+DISPATCH_PATH.verilogVal("p"));
- pw.flush();
- pw.close();
- pw = new PrintWriter(new OutputStreamWriter(new FileOutputStream(prefix+"/"+name+".v")));
+ 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;
public String getName() { return name; }
public Port getPort(String name) { return ports.get(name); }
- public HashSet<InstantiatedModule> instantiatedModules = new HashSet<InstantiatedModule>();
+ // order matters here
+ public LinkedHashMap<String,InstantiatedModule> instantiatedModules = new LinkedHashMap<String,InstantiatedModule>();
+
+ // order matters here
+ public LinkedList<PercolatedPort> percolatedPorts = new LinkedList<PercolatedPort>();
public final ArrayList<Event> events = new ArrayList<Event>();
// FIXME: always-alphabetical convention?
public final ArrayList<String> portorder = new ArrayList<String>();
public final HashMap<String,StateWire> statewires = new HashMap<String,StateWire>();
public final HashMap<String,Latch> latches = new HashMap<String,Latch>();
+ public final HashMap<String,WireValue> wires = new HashMap<String,WireValue>();
- 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;
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 Assignable getAssignableBits(int high, int low) { return new SimpleValue(getVerilogName(), high, low); }
- public String doReset() { return name+"<="+initial+";"; }
+ 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("~("+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 getAck() { return name+"_a"; }
- public String getReq() { return name+"_r"; }
+ 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 "("+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 static class InstantiatedModule {
- public final Module module;
- public final Module thisModule;
- public final int id;
- public final HashMap<String,Port> ports = new HashMap<String,Port>();
- 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 abstract String getCleanup();
+ public Trigger invert() { return new InvertedTrigger(this); }
+ 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); }
- public Assignable getAssignableBits(int high, int low) { return new SimpleValue(getVerilogName(), high, low); }
- public String getVerilogTrigger() { return " && " + getReq() + " && !"+getAck(); }
+ 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("~("+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 Latch latchDriver = null;
- 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)
- ? 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)
- 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.name + ";\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("`include \"bitfields.v\"");
- 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<String,Port> ports = new HashMap<String,Port>();
+ 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;
+ }
+ }
+
+ public void dump(PrintWriter pw, boolean fix) {
+ if (!fix) throw new RuntimeException();
+ boolean isRoot = name.equals("main");
+ pw.print("module "+name);
+ pw.println(isRoot ? "(clk_pin, 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 clk_pin;");
+ pw.println(" input rst_pin;");
+ pw.println(" wire clk;");
+ pw.println(" wire clk_fb;");
+ pw.println(" wire clk_unbuffered;");
+ pw.println(" assign clk_unbuffered = clk_pin;");
+ //pw.println(" assign clk = clk_pin;");
+
+ pw.println(" BUFG GBUF_FOR_MUX_CLOCK (.I(clk_unbuffered), .O(clk));");
+ /*
+ 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;");
}
- for(InstantiatedModule m : instantiatedModules) {
- m.dump(pw);
+
+ 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(precrap);
+
+ 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.doReset());
- for(StateWire sw : statewires.values())
- pw.println(sw.doReset());
- for(Port p : ports.values())
- pw.println(p.doReset());
+ 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()) {
- 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(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");
}
Module.this.events.add(this);
this.triggers = triggers;
this.actions = actions;
- for(int i=0; i<triggers.length; i++)
- if (triggers[i] instanceof Port)
- ((Port)triggers[i]).hasLatch = true;
}
public void dump(PrintWriter pw, boolean fix) {
+ if (!fix) throw new RuntimeException();
pw.print("if (1");
for(Object o : triggers) {
- if (o instanceof Trigger) pw.print(((Trigger)o).getVerilogTrigger());
+ if (o instanceof Trigger) pw.print(" && " + ((Trigger)o).getVerilogTrigger());
else pw.print(" && " + o);
}
pw.println(") begin ");