diff options
| author | azidar | 2015-05-18 20:33:23 -0700 |
|---|---|---|
| committer | azidar | 2015-05-18 20:33:23 -0700 |
| commit | 14bb9cda8352388bcd33ba9ca2700805dc51639f (patch) | |
| tree | a9bf8f46948aedadae0fe8e6c423ec48b643786e | |
| parent | 3336e6beb23e1ba883097eac0c0000269bf8ebfa (diff) | |
First pass at a Verilog Backend. Not tested, but compiles and generates reasonable verilog. Requires inlining, future versions will instantiate modules
| -rw-r--r-- | .gitignore | 2 | ||||
| -rw-r--r-- | TODO | 12 | ||||
| -rw-r--r-- | src/main/stanza/compilers.stanza | 27 | ||||
| -rw-r--r-- | src/main/stanza/firrtl-test-main.stanza | 2 | ||||
| -rw-r--r-- | src/main/stanza/passes.stanza | 35 | ||||
| -rw-r--r-- | src/main/stanza/verilog.stanza | 197 | ||||
| -rw-r--r-- | test/passes/resolve-genders/accessor.fir | 2 | ||||
| -rw-r--r-- | test/passes/to-verilog/gcd.fir | 45 |
8 files changed, 299 insertions, 23 deletions
@@ -8,9 +8,11 @@ */*/*.swp */*/*/*.swp */*/*.flo +*/*/*.v */*/*.out */*/Output */*/*/*.flo +*/*/*/*.v */*/*/*.out */*/*/Output src/lib/stanzam @@ -22,12 +22,12 @@ BlackBoxes Scaling ======== Verilog Backend Notes ======== -1) Emit module. No Parameters. Include clk and reset signals -2) Emit all declarations (wires,regs) -3) Initialize all regs with random values under synthesis -4) Emit all connections as assign statements -5) Emit assertions under always @ posedge clk, under synthesisp -6) Emit all register updates: +* 1) Emit module. No Parameters. Include clk and reset signals +o 2) Emit all declarations (wires,regs) +o 3) Initialize all regs with random values under synthesis +o 4) Emit all connections as assign statements +o 5) Emit assertions under always @ posedge clk, under synthesis +o 6) Emit all register updates: if(io_update_valid) begin R4 <= io_update_bits_target; end diff --git a/src/main/stanza/compilers.stanza b/src/main/stanza/compilers.stanza index 33b64b8b..e912d3a0 100644 --- a/src/main/stanza/compilers.stanza +++ b/src/main/stanza/compilers.stanza @@ -4,12 +4,12 @@ defpackage firrtl/compiler : import firrtl/passes import firrtl/errors import firrtl/flo + import firrtl/verilog import firrtl/ir2 import firrtl/ir-utils public defstruct StandardFlo <: Compiler : file: String with: (as-method => true) - public defmethod passes (c:StandardFlo) -> List<Pass> : to-list $ [ CheckHighForm() @@ -33,6 +33,31 @@ public defmethod passes (c:StandardFlo) -> List<Pass> : Flo(file(c)) ] +public defstruct StandardVerilog <: Compiler : + file: String with: (as-method => true) +public defmethod passes (c:StandardVerilog) -> List<Pass> : + to-list $ [ + CheckHighForm() + TempElimination() + ToWorkingIR() + MakeExplicitReset() + ResolveKinds() + CheckKinds() + InferTypes() + CheckTypes() + ResolveGenders() + CheckGenders() + ExpandAccessors() + LowerToGround() + ExpandIndexedConnects() + ExpandWhens() + InferWidths() + Inline() + SplitExp() + ToRealIR() + Verilog(file(c)) + ] + ;============= DRIVER ====================================== public defn run-passes (c:Circuit,comp:Compiler) : run-passes(c,passes(comp)) diff --git a/src/main/stanza/firrtl-test-main.stanza b/src/main/stanza/firrtl-test-main.stanza index 1b15c6b1..5a7e593d 100644 --- a/src/main/stanza/firrtl-test-main.stanza +++ b/src/main/stanza/firrtl-test-main.stanza @@ -11,6 +11,7 @@ #include("errors.stanza") #include("compilers.stanza") #include("flo.stanza") +#include("verilog.stanza") defpackage firrtl-main : import core @@ -70,6 +71,7 @@ defn main () : else : switch {_ == compiler} : "flo" : run-passes(c,StandardFlo(output as String)) + "verilog" : run-passes(c,StandardVerilog(output as String)) else : error("Invalid compiler flag") main() diff --git a/src/main/stanza/passes.stanza b/src/main/stanza/passes.stanza index 236addce..72cbe756 100644 --- a/src/main/stanza/passes.stanza +++ b/src/main/stanza/passes.stanza @@ -744,7 +744,7 @@ defn index-of-elem (t:BundleType, s:Symbol) -> Int : defn generate-entry (n:Symbol,t:Type) -> List<NTF> : - defn uniquify (n*:Symbol) -> Symbol : symbol-join([n "$" n*]) + defn uniquify (n*:Symbol) -> Symbol : symbol-join([n "_" n*]) match(t) : (t:BundleType) : for f in fields(t) map-append : @@ -933,9 +933,9 @@ defn expand-connect-indexed-stmt (s: Stmt) -> Stmt : DoPrim(EQUAL-OP,list(e1,e2),List(),UIntType(UnknownWidth())) defn get-name (e:Expression) -> Symbol : match(e) : - (e:WRef) : symbol-join([name(e) `#]) - (e:WSubfield) : symbol-join([get-name(exp(e)) `. name(e) `#]) - (e:WIndex) : symbol-join([get-name(exp(e)) `. to-symbol(value(e)) `#]) + (e:WRef) : symbol-join([name(e) `__]) + (e:WSubfield) : symbol-join([get-name(exp(e)) `. name(e) `__]) + (e:WIndex) : symbol-join([get-name(exp(e)) `. to-symbol(value(e)) `__]) (e) : `T match(s) : (s:ConnectToIndexed) : Begin $ @@ -1192,24 +1192,29 @@ defn expand-whens (s:Stmt, table:HashTable<Symbol,SymbolicValue>,decs:Vector<Stm else : Connect(info(s),ref,to-exp(table[name(s)]) as Expression) }() (s:DefRegister) : - add(decs,DefWire(info(s),name(s),type(s))) + ;add(decs,DefWire(info(s),name(s),type(s))) + ;add{cons,_} $ { + ; val ref = WRef(name(s),type(s),RegKind(),FEMALE) + ; val e = to-exp(table[name(s)]) + ; match(e) : + ; (e:False) : EmptyStmt() + ; (e:Expression) : Connect(info(s),ref,Register(type(s),e, to-exp(optimize $ get-write-enable(table[name(s)])) as Expression)) + ;}() + val e = to-exp(table[name(s)]) add{cons,_} $ { - val ref = WRef(name(s),type(s),RegKind(),FEMALE) - val e = to-exp(table[name(s)]) match(e) : (e:False) : EmptyStmt() - (e:Expression) : Connect(info(s),ref,Register(type(s),e, to-exp(optimize $ get-write-enable(table[name(s)])) as Expression)) + (e:Expression) : DefNode(info(s),name(s),Register(type(s),e,to-exp(optimize $ get-write-enable(table[name(s)])) as Expression)) }() (s:WDefAccessor) : val t = type(type(source(s)) as VectorType) val n = name(s) - add(decs,DefWire(info(s),n,t)) add{cons,_} $ { switch {_ == gender(s)} : MALE : - val ref = WRef(n,t,ReadAccessorKind(),FEMALE) - Begin $ list $ Connect(info(s),ref,ReadPort(source(s),index(s),t,get-read-enable(n,table))) + Begin $ list $ DefNode(info(s),n,ReadPort(source(s),index(s),t,get-read-enable(n,table))) FEMALE : + add(decs,DefWire(info(s),n,t)) val ref = WRef(n,t,WriteAccessorKind(),FEMALE) val e = to-exp(table[n]) val s* = match(e) : @@ -1777,17 +1782,17 @@ defn inline-instances (c:Circuit) : (e:WSubfield) : match(kind(exp(e) as WRef)) : (k:InstanceKind) : - WRef(symbol-join([name(exp(e) as WRef) "$" name(e)]),type(e),k,gender(e)) + WRef(symbol-join([name(exp(e) as WRef) "_" name(e)]),type(e),k,gender(e)) (k:MemKind) : e (e) : e - defn rename (ref:Symbol,n:Symbol) -> Symbol : symbol-join([n "$" ref]) + defn rename (ref:Symbol,n:Symbol) -> Symbol : symbol-join([n "_" ref]) defn rename-e (e:Expression,n:Symbol) -> Expression : match(map(rename-e{_,n},e)) : (e:WRef) : WRef(rename(name(e),n),type(e),kind(e),gender(e)) (e:WSubfield) : match(kind(exp(e) as WRef)) : (k:InstanceKind) : - WRef(symbol-join([name(exp(e) as WRef) "$" name(e)]),type(e),k,gender(e)) + WRef(symbol-join([name(exp(e) as WRef) "_" name(e)]),type(e),k,gender(e)) (k:MemKind) : e (e) : e defn rename-s (s:Stmt,n:Symbol) -> Stmt : @@ -1829,7 +1834,7 @@ defn split-exp (c:Circuit) : (e:Subfield|DoPrim|ReadPort|Register|WritePort) : val n* = if n typeof False : firrtl-gensym(`T) - else : firrtl-gensym(symbol-join([n as Symbol `#])) + else : firrtl-gensym(symbol-join([n as Symbol `__])) add(v,DefNode(info,n*,e)) WRef(n*,type(e),NodeKind(),UNKNOWN-GENDER) (e) : e diff --git a/src/main/stanza/verilog.stanza b/src/main/stanza/verilog.stanza new file mode 100644 index 00000000..20433f0f --- /dev/null +++ b/src/main/stanza/verilog.stanza @@ -0,0 +1,197 @@ +defpackage firrtl/verilog : + import core + import verse + import firrtl/ir-utils + import firrtl/ir2 + +public defstruct Verilog <: Pass : + file : String +public defmethod pass (b:Verilog) -> (Circuit -> Circuit) : emit-verilog{file(b),_} +public defmethod name (b:Verilog) -> String : "To Verilog" +public defmethod short-name (b:Verilog) -> String : "To Verilog" + +;============ Utilz ============= +defn width! (w:Width) -> Int : + match(w) : + (w:IntWidth) : width(w) + (w) : error("Non-supported width type.") + +defn width! (t:Type) -> Int : + match(t) : + (t:UIntType) : width!(width(t)) + (t:SIntType) : width!(width(t)) + (t) : error("Non-supported type.") + +defn emit (w:Width) -> String : + match(w) : + (w:IntWidth) : string-join $ ["[" width(w) ":0]"] ;TODO check if need to special case 0 or 1 width wires + (w) : error("Non-supported width type.") + +defn get-width (t:Type) -> String : + match(t) : + (t:UIntType) : emit(width(t)) + (t:SIntType) : emit(width(t)) + (t) : error("Non-supported type.") + + +;============ Verilog Backend ============= + +defn emit (e:Expression) -> String : + match(e) : + (e:Ref) : to-string $ name(e) + (e:UIntValue) : string-join $ [width!(type(e)) "'d" value(e)] + (e:SIntValue) : string-join $ [width!(type(e)) "'sd" value(e)] + (e:Subfield) : error("Non-supported expression") + (e:Index) : error("Non-supported expression") + (e:Register) : error("Non-supported expression") + (e:ReadPort) : error("Non-supported expression") + (e:WritePort) : error("Non-supported expression") + (e:DoPrim) : string-join $ switch {_ == op(e)} : + ADD-OP : [emit(args(e)[0]) " + " emit(args(e)[1])] + SUB-OP : [emit(args(e)[0]) " - " emit(args(e)[1])] + MUL-OP : [emit(args(e)[0]) " * " emit(args(e)[1])] + DIV-OP : [emit(args(e)[0]) " / " emit(args(e)[1])] + MOD-OP : [emit(args(e)[0]) " % " emit(args(e)[1])] + QUO-OP : [emit(args(e)[0]) " / " emit(args(e)[1])] + REM-OP : [emit(args(e)[0]) " % " emit(args(e)[1])] + ADD-WRAP-OP : [emit(args(e)[0]) " + " emit(args(e)[1])] + SUB-WRAP-OP : [emit(args(e)[0]) " - " emit(args(e)[1])] + LESS-OP : [emit(args(e)[0]) " < " emit(args(e)[1])] + LESS-EQ-OP : [emit(args(e)[0]) " <= " emit(args(e)[1])] + GREATER-OP : [emit(args(e)[0]) " > " emit(args(e)[1])] + GREATER-EQ-OP : [emit(args(e)[0]) " >= " emit(args(e)[1])] + NEQUAL-OP : [emit(args(e)[0]) " != " emit(args(e)[1])] + EQUAL-OP : [emit(args(e)[0]) " == " emit(args(e)[1])] + MUX-OP : [emit(args(e)[0]) " ? " emit(args(e)[1]) " : " emit(args(e)[2])] + PAD-OP : + val x = args(e)[0] + val w = width!(type(x)) + val diff = consts(e)[0] - w + ["{" diff "{" x "[" w - 1 "]}," emit(x)] + AS-UINT-OP : + ["$unsigned(" emit(args(e)[0]) " "] + AS-SINT-OP : + ["$signed(" emit(args(e)[0]) " "] + DYN-SHIFT-LEFT-OP : [emit(args(e)[0]) " << " emit(args(e)[1])] + DYN-SHIFT-RIGHT-OP : [emit(args(e)[0]) " >> " emit(args(e)[1])] + SHIFT-LEFT-OP : [emit(args(e)[0]) " << " emit(args(e)[1])] + SHIFT-RIGHT-OP : [emit(args(e)[0]) " >> " emit(args(e)[1])] + NEG-OP : ["-{" emit(args(e)[0]) "}"] + CONVERT-OP : + match(type(args(e)[0])) : + (t:UIntType) : ["{1'b0," emit(args(e)[0]) "}"] + (t:SIntType) : [emit(args(e)[0])] + BIT-NOT-OP : ["!" emit(args(e)[0])] + BIT-AND-OP : [emit(args(e)[0]) " & " emit(args(e)[1])] + BIT-OR-OP : [emit(args(e)[0]) " | " emit(args(e)[1])] + BIT-XOR-OP : [emit(args(e)[0]) " ^ " emit(args(e)[1])] + CONCAT-OP : ["{" emit(args(e)[0]) "," emit(args(e)[1]) "}"] + BIT-SELECT-OP : [emit(args(e)[0]) "[" consts(e)[0] "]"] + BITS-SELECT-OP : [emit(args(e)[0]) "[" consts(e)[1] ":" consts(e)[0] "]"] + BIT-AND-REDUCE-OP : + var v = emit(args(e)[0]) + for x in tail(args(e)) do : + v = concat(v, [" & " emit(x)]) + v + BIT-OR-REDUCE-OP : + var v = emit(args(e)[0]) + for x in tail(args(e)) do : + v = concat(v, [" | " emit(x)]) + v + BIT-XOR-REDUCE-OP : + var v = emit(args(e)[0]) + for x in tail(args(e)) do : + v = concat(v, [" ^ " emit(x)]) + v + +defn emit-module (m:Module) : + val wires = Vector<Streamable>() + val regs = Vector<Streamable>() + val inits = Vector<Streamable>() + val assigns = Vector<Streamable>() + val updates = Vector<Streamable>() + + defn emit-s (s:Stmt) : + match(s) : + (s:DefWire) : add(wires,["wire " get-width(type(s)) " " name(s) ";"]) + (s:DefInstance) : false ; TODO fix this + (s:DefMemory) : + val vtype = type(s) as VectorType + val innerwidth = + add(regs,["reg " get-width(type(vtype)) " " name(s) " [0:" size(vtype) "];"]) + add(inits,["for (initvar = 0; initvar < " size(vtype) "; initvar = initvar+1)"]) + add(inits,[name(s) " = {" width!(type(vtype)) "{$random}};"]) + (s:DefNode) : + if value(s) typeof Register : + val reg = value(s) as Register + add(regs,["reg " get-width(type(reg)) " " name(s) ";"]) + add(inits,[name(s) " = {" width!(type(reg)) "{$random}};"]) + add(updates,["if(" emit(enable(reg)) ") begin"]) + add(updates,[" " name(s) " <= " emit(value(reg)) ";"]) + add(updates,["end"]) + else if value(s) typeof ReadPort : + val rp = value(s) as ReadPort + add(assigns,["assign " name(s) " = " emit(mem(rp)) "[" emit(index(rp)) "];"]) + else : + add(wires,["wire " get-width(type(value(s))) " " name(s) ";"]) + add(assigns,["assign " name(s) " = " emit(value(s)) ";"]) + (s:Begin) : do(emit-s, body(s)) + (s:Connect) : + if loc(s) typeof WritePort : + val wp = loc(s) as WritePort + add(updates,["if(" emit(enable(wp)) ") begin"]) + add(updates,[" " emit(mem(wp)) "[" emit(index(wp)) "] <= " emit(exp(s)) ";"]) + add(updates,["end"]) + else : + add(assigns,["assign " emit(loc(s)) " = " emit(exp(s)) ";"]) + (s) : s + + emit-s(body(m)) + + ;==== Actually printing module ===== + val port-indent = " " + print-all(["module " name(m) "(input clk, input reset,\n"]) + for (p in ports(m),i in 1 to false) do : + if name(p) !=`reset : + var end = ",\n" + if length(ports(m)) - 1 == i : + end = "\n);\n" + switch {_ == direction(p)} : + INPUT : print-all([port-indent "input " get-width(type(p)) " " name(p) end]) + OUTPUT : print-all([port-indent "output " get-width(type(p)) " " name(p) end]) + + for w in wires do : + print(" ") + println-all(w) + for r in regs do : + print(" ") + println-all(r) + + println("`ifndef SYNTHESIS") + println(" integer initvar;") + println(" initial begin") + println(" #0.002;") + for i in inits do : + print-all(" ") + println-all(i) + println(" end") + println("`endif") + + for a in assigns do : + print(" ") + println-all(a) + + println(" always @(posedge clk) begin") + for u in updates do : + print(" ") + println-all(u) + println(" end") + + println("endmodule") + + +public defn emit-verilog (file:String, c:Circuit) : + with-output-file{file, _} $ fn () : + for m in modules(c) do : + emit-module(m) + c diff --git a/test/passes/resolve-genders/accessor.fir b/test/passes/resolve-genders/accessor.fir index 31314148..41aea1f4 100644 --- a/test/passes/resolve-genders/accessor.fir +++ b/test/passes/resolve-genders/accessor.fir @@ -3,7 +3,7 @@ ;CHECK: Resolve Genders circuit top : module top : - wire m : UInt<32>[5][5][5] + wire m : UInt<32>[2][2][2] wire i : UInt accessor a = m[i] ;CHECK: accessor a = m@<g:m>[i@<g:m>]@<g:m> accessor b = a[i] ;CHECK: accessor b = a@<g:m>[i@<g:m>]@<g:m> diff --git a/test/passes/to-verilog/gcd.fir b/test/passes/to-verilog/gcd.fir new file mode 100644 index 00000000..170e7866 --- /dev/null +++ b/test/passes/to-verilog/gcd.fir @@ -0,0 +1,45 @@ +; RUN: firrtl -i %s -o %s.v -X verilog -p c | tee %s.out | FileCheck %s + +;CHECK: Verilog +circuit top : + module subtracter : + input x : UInt + input y : UInt + output q : UInt + q := sub-wrap(x, y) + module gcd : + input a : UInt<16> + input b : UInt<16> + input e : UInt<1> + output z : UInt<16> + output v : UInt<1> + reg x : UInt + reg y : UInt + on-reset x := UInt(0) + on-reset y := UInt(42) + when gt(x, y) : + inst s of subtracter + s.x := x + s.y := y + x := s.q + else : + inst s2 of subtracter + s2.x := x + s2.y := y + y := s2.q + when e : + x := a + y := b + v := eq(v, UInt(0)) + z := x + module top : + input a : UInt<16> + input b : UInt<16> + output z : UInt + inst i of gcd + i.a := a + i.b := b + i.e := UInt(1) + z := i.z +;CHECK: Done! + |
