aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorazidar2015-05-18 20:33:23 -0700
committerazidar2015-05-18 20:33:23 -0700
commit14bb9cda8352388bcd33ba9ca2700805dc51639f (patch)
treea9bf8f46948aedadae0fe8e6c423ec48b643786e
parent3336e6beb23e1ba883097eac0c0000269bf8ebfa (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--.gitignore2
-rw-r--r--TODO12
-rw-r--r--src/main/stanza/compilers.stanza27
-rw-r--r--src/main/stanza/firrtl-test-main.stanza2
-rw-r--r--src/main/stanza/passes.stanza35
-rw-r--r--src/main/stanza/verilog.stanza197
-rw-r--r--test/passes/resolve-genders/accessor.fir2
-rw-r--r--test/passes/to-verilog/gcd.fir45
8 files changed, 299 insertions, 23 deletions
diff --git a/.gitignore b/.gitignore
index a6993b83..780102cd 100644
--- a/.gitignore
+++ b/.gitignore
@@ -8,9 +8,11 @@
*/*/*.swp
*/*/*/*.swp
*/*/*.flo
+*/*/*.v
*/*/*.out
*/*/Output
*/*/*/*.flo
+*/*/*/*.v
*/*/*/*.out
*/*/*/Output
src/lib/stanzam
diff --git a/TODO b/TODO
index ac17f5f9..9a03aa85 100644
--- a/TODO
+++ b/TODO
@@ -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!
+