aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorazidar2015-05-15 16:34:34 -0700
committerazidar2015-05-15 16:34:34 -0700
commit2702e571040e7a07317b79f9c5cfdbd61b9ab2bf (patch)
tree0e5973d175be18851865b712e16871764157889f /src
parent521a4277bfc1d764dc9ee771c604200525e871cb (diff)
Updated firrtl for its passes to be a bit more modular, and to enable plugging in other backends. Also updated a lot of tests, but not all of them because its annoying.
Diffstat (limited to 'src')
-rw-r--r--src/main/stanza/compilers.stanza49
-rw-r--r--src/main/stanza/errors.stanza22
-rw-r--r--src/main/stanza/firrtl-test-main.stanza35
-rw-r--r--src/main/stanza/flo.stanza221
-rw-r--r--src/main/stanza/ir-utils.stanza34
-rw-r--r--src/main/stanza/passes.stanza359
6 files changed, 428 insertions, 292 deletions
diff --git a/src/main/stanza/compilers.stanza b/src/main/stanza/compilers.stanza
new file mode 100644
index 00000000..33b64b8b
--- /dev/null
+++ b/src/main/stanza/compilers.stanza
@@ -0,0 +1,49 @@
+defpackage firrtl/compiler :
+ import core
+ import verse
+ import firrtl/passes
+ import firrtl/errors
+ import firrtl/flo
+ 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()
+ TempElimination()
+ ToWorkingIR()
+ MakeExplicitReset()
+ ResolveKinds()
+ CheckKinds()
+ InferTypes()
+ CheckTypes()
+ ResolveGenders()
+ CheckGenders()
+ ExpandAccessors()
+ LowerToGround()
+ ExpandIndexedConnects()
+ ExpandWhens()
+ InferWidths()
+ Inline()
+ SplitExp()
+ ToRealIR()
+ Flo(file(c))
+ ]
+
+;============= DRIVER ======================================
+public defn run-passes (c:Circuit,comp:Compiler) :
+ run-passes(c,passes(comp))
+public defn run-passes (c:Circuit,ls:List<Pass>) :
+ var c*:Circuit = c
+ println("Compiling!")
+ if PRINT-CIRCUITS : println("Original Circuit")
+ if PRINT-CIRCUITS : print(c)
+ for p in ls do :
+ if PRINT-CIRCUITS : println(name(p))
+ c* = pass(p)(c*)
+ if PRINT-CIRCUITS : print(c*)
+ if PRINT-CIRCUITS : println-all(["Finished " name(p) "\n"])
+ println("Done!")
diff --git a/src/main/stanza/errors.stanza b/src/main/stanza/errors.stanza
index 30414afd..06c09522 100644
--- a/src/main/stanza/errors.stanza
+++ b/src/main/stanza/errors.stanza
@@ -15,12 +15,6 @@ defpackage firrtl/errors :
; * Only modules in circuit (no statements or expressions) <- parser
; * Module must be a reference in inst declaration
-;AFTER GENDER INFERENCE
-; o Nodes always male
-; o Accessors only have one gender, unless rdwr
-; o output/input only one gender
-; o correctly check for the base bundle
-
;AFTER WIDTH INFERENCE
; o No names
; o No Unknowns
@@ -50,6 +44,10 @@ defpackage firrtl/errors :
; * all references are declared
; * UInt only has positive ints
+public defstruct CheckHighForm <: Pass
+public defmethod pass (b:CheckHighForm) -> (Circuit -> Circuit) : check-high-form
+public defmethod name (b:CheckHighForm) -> String : "High Form Check"
+
;----------------- Errors ------------------------
defn NotUnique (info:FileInfo, name:Symbol) :
PassException $ string-join $
@@ -226,6 +224,10 @@ public defn check-high-form (c:Circuit) -> Circuit :
; o onreset can only handle a register
; o Cannot use a mem in anything except an accessor, Readport, or Writeport
+public defstruct CheckKinds <: Pass
+public defmethod pass (b:CheckKinds) -> (Circuit -> Circuit) : check-kinds
+public defmethod name (b:CheckKinds) -> String : "Check Kinds"
+
;----------------- Errors ---------------------
defn NotMem (info:FileInfo, name:Symbol) :
PassException $ string-join $
@@ -311,6 +313,10 @@ public defn check-kinds (c:Circuit) -> Circuit :
; o := has same types
; o 2nd arg in dshr/l must be UInt, in general do primops
+public defstruct CheckTypes <: Pass
+public defmethod pass (b:CheckTypes) -> (Circuit -> Circuit) : check-types
+public defmethod name (b:CheckTypes) -> String : "Check Types"
+
;----------------- Errors ---------------------
defn SubfieldNotInBundle (info:FileInfo, name:Symbol) :
PassException $ string-join $
@@ -421,6 +427,10 @@ public defn check-types (c:Circuit) -> Circuit :
; o output/input only one gender
; o correctly check for the base bundle
+public defstruct CheckGenders <: Pass
+public defmethod pass (b:CheckGenders) -> (Circuit -> Circuit) : check-genders
+public defmethod name (b:CheckGenders) -> String : "Check Genders"
+
;----------------- Errors ---------------------
defn WrongGender (info:FileInfo,expr:Symbol,wrong:Symbol,right:Symbol) :
PassException $ string-join $
diff --git a/src/main/stanza/firrtl-test-main.stanza b/src/main/stanza/firrtl-test-main.stanza
index 0f977ebe..7f578772 100644
--- a/src/main/stanza/firrtl-test-main.stanza
+++ b/src/main/stanza/firrtl-test-main.stanza
@@ -9,6 +9,8 @@
#include("passes.stanza")
#include("primop.stanza")
#include("errors.stanza")
+#include("compilers.stanza")
+#include("flo.stanza")
defpackage firrtl-main :
import core
@@ -18,6 +20,7 @@ defpackage firrtl-main :
import stz/lexer
import stz/parser
import firrtl/ir-utils
+ import firrtl/compiler
defn set-printvars! (p:List<Char>) :
if contains(p,'t') : PRINT-TYPES = true
@@ -29,24 +32,44 @@ defn set-printvars! (p:List<Char>) :
if contains(p,'d') : PRINT-DEBUG = true
if contains(p,'i') : PRINT-INFO = true
-;firrtl -i gcd.fir -o gcd.flo -x qabcefghipjklmno -p c
+defn get-passes (pass-names:List<String>) -> List<Pass> :
+ for n in pass-names map :
+ val p = for p in standard-passes find : n == short-name(p)
+ if p == false :
+ error(to-string $ ["Unrecognized pass flag: " n])
+ p as Pass
+
defn main () :
val args = commandline-arguments()
var input = false
var output = false
- var passes = "qabcefghipjklmno"
+ var compiler = false
+ val pass-names = Vector<String>()
var printvars = ""
for (s in args, i in 0 to false) do :
if s == "-i" : input = args[i + 1]
if s == "-o" : output = args[i + 1]
- if s == "-x" : passes = args[i + 1]
+ if s == "-x" : add(pass-names,args[i + 1])
+ if s == "-X" : compiler = args[i + 1]
if s == "-p" : printvars = args[i + 1]
- if input == false : error("No input file provided. Use -i flag")
- if output == false : error("No output file provided. Use -o flag")
+
+ if input == false :
+ error("No input file provided. Use -i flag.")
+ if output == false :
+ error("No output file provided. Use -o flag.")
+ if compiler == false and length(pass-names) == 0 :
+ error("Must specify a compiler. Use -X flag.")
+
val lexed = lex-file(input as String)
val c = parse-firrtl(lexed)
set-printvars!(to-list(printvars))
- run-passes(c,to-list(passes),output as String)
+
+ if compiler == false :
+ run-passes(c,get-passes(to-list(pass-names)))
+ else :
+ switch {_ == compiler} :
+ "flo" : run-passes(c,StandardFlo(output as String))
+ else : error("Invalid compiler flag")
main()
diff --git a/src/main/stanza/flo.stanza b/src/main/stanza/flo.stanza
new file mode 100644
index 00000000..d98ed0ce
--- /dev/null
+++ b/src/main/stanza/flo.stanza
@@ -0,0 +1,221 @@
+defpackage firrtl/flo :
+ import core
+ import verse
+ import firrtl/ir-utils
+ import firrtl/ir2
+
+public defstruct Flo <: Pass :
+ file : String
+public defmethod pass (b:Flo) -> (Circuit -> Circuit) : emit-flo{file(b),_}
+public defmethod name (b:Flo) -> String : "To Flo"
+
+;============= FLO PRINTER ======================================
+; Emit
+
+defn flo-op-name (op:PrimOp) -> String :
+ switch {op == _ } :
+ ;NEG-OP : "neg"
+ ;NEG-OP : "neg"
+ ;NEG-OP : "neg"
+ ;NEG-OP : "neg"
+ ADD-UU-OP : "add"
+ ADD-US-OP : "add"
+ ADD-SU-OP : "add"
+ ADD-SS-OP : "add"
+ ADD-WRAP-UU-OP : "add"
+ ADD-WRAP-US-OP : "add"
+ ADD-WRAP-SU-OP : "add"
+ ADD-WRAP-SS-OP : "add"
+ SUB-UU-OP : "sub"
+ SUB-US-OP : "sub"
+ SUB-SU-OP : "sub"
+ SUB-SS-OP : "sub"
+ SUB-WRAP-UU-OP : "sub"
+ SUB-WRAP-US-OP : "sub"
+ SUB-WRAP-SU-OP : "sub"
+ SUB-WRAP-SS-OP : "sub"
+ MUL-UU-OP : "mul" ;; todo: signed version
+ MUL-US-OP : "mul" ;; todo: signed version
+ MUL-SU-OP : "mul" ;; todo: signed version
+ MUL-SS-OP : "mul" ;; todo: signed version
+ DIV-UU-OP : "div" ;; todo: signed version
+ DIV-US-OP : "div" ;; todo: signed version
+ DIV-SU-OP : "div" ;; todo: signed version
+ DIV-SS-OP : "div" ;; todo: signed version
+ MOD-UU-OP : "mod" ;; todo: signed version
+ MOD-US-OP : "mod" ;; todo: signed version
+ MOD-SU-OP : "mod" ;; todo: signed version
+ MOD-SS-OP : "mod" ;; todo: signed version
+ LESS-UU-OP : "lt" ;; todo: signed version
+ LESS-US-OP : "lt" ;; todo: signed version
+ LESS-SU-OP : "lt" ;; todo: signed version
+ LESS-SS-OP : "lt" ;; todo: signed version
+ LESS-EQ-UU-OP : "lte" ;; todo: swap args
+ LESS-EQ-US-OP : "lte" ;; todo: swap args
+ LESS-EQ-SU-OP : "lte" ;; todo: swap args
+ LESS-EQ-SS-OP : "lte" ;; todo: swap args
+ GREATER-UU-OP : "lt" ;; todo: swap args
+ GREATER-US-OP : "lt" ;; todo: swap args
+ GREATER-SU-OP : "lt" ;; todo: swap args
+ GREATER-SS-OP : "lt" ;; todo: swap args
+ GREATER-EQ-UU-OP : "lte" ;; todo: signed version
+ GREATER-EQ-US-OP : "lte" ;; todo: signed version
+ GREATER-EQ-SU-OP : "lte" ;; todo: signed version
+ GREATER-EQ-SS-OP : "lte" ;; todo: signed version
+ NEQUAL-UU-OP : "neq"
+ NEQUAL-SS-OP : "neq"
+ EQUAL-UU-OP : "eq"
+ EQUAL-SS-OP : "eq"
+ MUX-UU-OP : "mux"
+ MUX-SS-OP : "mux"
+ PAD-U-OP : "rsh" ;; todo: signed version
+ PAD-S-OP : "rsh" ;; todo: signed version
+ NEG-U-OP : "neg"
+ NEG-S-OP : "neg"
+ ;AS-UINT-U-OP :
+ ;AS-UINT-S-OP :
+ ;AS-SINT-U-OP :
+ ;AS-SINT-S-OP :
+ SHIFT-LEFT-U-OP : "lsh"
+ SHIFT-LEFT-S-OP : "lsh"
+ SHIFT-RIGHT-U-OP : "rsh"
+ SHIFT-RIGHT-S-OP : "arsh"
+ DYN-SHIFT-LEFT-U-OP : "lsh"
+ DYN-SHIFT-LEFT-S-OP : "lsh"
+ DYN-SHIFT-RIGHT-U-OP : "rsh"
+ DYN-SHIFT-RIGHT-S-OP : "arsh"
+ ;CONVERT-U-OP :
+ ;CONVERT-S-OP :
+ BIT-AND-OP : "and"
+ BIT-NOT-OP : "not"
+ BIT-OR-OP : "or"
+ BIT-XOR-OP : "xor"
+ CONCAT-OP : "cat"
+ BIT-SELECT-OP : "rsh"
+ BITS-SELECT-OP : "rsh"
+ else : error $ string-join $ ["Unable to print Primop: " op]
+
+defn sane-width (wd:Width) -> Int :
+ match(wd) :
+ (w:IntWidth) : max(1, width(w))
+ (w) : error(string-join(["Unknown width: " w]))
+
+defn prim-width (type:Type) -> Int :
+ match(type) :
+ (t:UIntType) : sane-width(width(t))
+ (t:SIntType) : sane-width(width(t))
+ (t) : error("Bad prim width type")
+
+defn sizeof (in: Int) -> Int :
+ max(1, ceil-log2(in + 1))
+
+defn emit-all (es:Streamable, top:Symbol) :
+ for e in es do :
+ match(e) :
+ (ex:Expression) : emit!(ex,top)
+ (ex:String) : print(ex)
+ (ex:Symbol) : print(ex)
+ ;; (ex:Int) : print-all([ex "'" sizeof(ex)])
+ (ex:Int) : print(ex)
+ (ex) : print(ex)
+
+defn emit! (e:Expression,top:Symbol) :
+ defn greater-op? (op: PrimOp) -> True|False :
+ contains?([GREATER-OP, GREATER-UU-OP, GREATER-US-OP, GREATER-SU-OP, GREATER-SS-OP], op)
+ defn greater-eq-op? (op: PrimOp) -> True|False :
+ contains?([GREATER-EQ-OP, GREATER-EQ-UU-OP, GREATER-EQ-US-OP, GREATER-EQ-SU-OP, GREATER-EQ-SS-OP], op)
+ defn less-eq-op? (op: PrimOp) -> True|False :
+ contains?([LESS-EQ-OP, LESS-EQ-UU-OP, LESS-EQ-US-OP, LESS-EQ-SS-OP, LESS-EQ-SS-OP], op)
+ defn less-op? (op: PrimOp) -> True|False :
+ contains?([LESS-OP, LESS-UU-OP, LESS-US-OP, LESS-SS-OP, LESS-SS-OP], op)
+ defn cmp-op? (op: PrimOp) -> True|False :
+ greater-op?(op) or greater-eq-op?(op) or less-op?(op) or less-eq-op?(op) or
+ contains?([EQUAL-OP, EQUAL-UU-OP, EQUAL-SS-OP, NEQUAL-OP, NEQUAL-UU-OP, NEQUAL-SS-OP], op)
+ match(e) :
+ (e:Ref) : emit-all([top "::" name(e)], top)
+ (e:UIntValue) : emit-all([value(e) "'" sane-width(width(e))], top)
+ (e:SIntValue) : emit-all([value(e) "'" sane-width(width(e))], top)
+ (e:Subfield) : emit-all([exp(e) "/" name(e)], top)
+ (e:Index) : emit-all([exp(e) "/" value(e)], top)
+ (e:Pad) :
+ emit-all(["rsh'" prim-width(type(e)) " " value(e) " 0"], top)
+ (e:Register) :
+ emit-all(["reg'" prim-width(type(e)) " " enable(e) " " value(e)], top)
+ (e:ReadPort) :
+ emit-all(["rd'" prim-width(type(e)) " " "1" " " mem(e) " " index(e)], top) ;; enable(e)
+ (e:DoPrim) :
+ if cmp-op?(op(e)) :
+ emit-all([flo-op-name(op(e)) "'" prim-width(type(args(e)[0]))], top)
+ if greater-op?(op(e)) or greater-eq-op?(op(e)) :
+ emit-all([" " args(e)[1] " " args(e)[0]], top)
+ else :
+ emit-all([" " args(e)[0] " " args(e)[1]], top)
+ else if op(e) == BIT-SELECT-OP :
+ emit-all([flo-op-name(op(e)) "'1 " args(e)[0] " " consts(e)[0]], top)
+ else if op(e) == BITS-SELECT-OP :
+ val w = consts(e)[0] - consts(e)[1] + 1
+ emit-all([flo-op-name(op(e)) "'" w " " args(e)[0] " " consts(e)[1]], top)
+ ;; else if op(e) == CONCAT-OP :
+ ;; val w = consts(e)[0] - consts(e)[1] + 1
+ ;; emit-all([flo-op-name(op(e)) "'" w " " args(e)[0] " " consts(e)[1]], top)
+ else :
+ emit-all([flo-op-name(op(e)) "'" prim-width(type(e))], top)
+ if (op(e) == PAD-U-OP) or (op(e) == PAD-S-OP) :
+ emit-all([" " args(e)[0] " " consts(e)[0]], top)
+ else :
+ for arg in args(e) do :
+ print(" ")
+ emit!(arg, top)
+ for const in consts(e) do :
+ print-all([" " const "'" sizeof(const)])
+ (e) : error("SHOULDN'T EMIT THIS") ;; print-all(["EMIT(" e ")"])
+ ;(e) : emit-all(["mov'" prim-width(type(e)) " " e], top) ;TODO, not sure which one is right
+
+defn maybe-mov (e:Expression) -> String :
+ val need-mov? = match(e) :
+ (e:Ref) : true
+ (e:UIntValue) : true
+ (e:SIntValue) : true
+ (e:Subfield) : true
+ (e:Index) : true
+ (e) : false
+ if need-mov?: "mov " else: ""
+
+defn emit-s (s:Stmt, v:List<Symbol>, top:Symbol) :
+ match(s) :
+ (s:DefWire) : ""
+ (s:DefInstance) : error("Shouldn't be here")
+ (s:DefMemory) :
+ val vtype = type(s) as VectorType
+ emit-all([top "::" name(s) " = mem'" prim-width(type(vtype)) " " size(vtype) "\n"], top)
+ (s:DefNode) :
+ if value(s) typeof WritePort :
+ val e = value(s) as WritePort
+ val n = firrtl-gensym(`F)
+ emit-all([top "::" n " = wr'" prim-width(type(e)) " " enable(e) " " mem(e) " " index(e) " " top "::" name(s) "\n"], top)
+ else :
+ emit-all([top "::" name(s) " = " maybe-mov(value(s)) value(s) "\n"], top)
+ (s:Begin) : do(emit-s{_, v, top}, body(s))
+ (s:Connect) :
+ val n = name(loc(s) as Ref)
+ if contains?(v,n) :
+ emit-all([top "::" n " = out'" prim-width(type(loc(s))) " " exp(s) "\n"], top)
+ else :
+ emit-all([top "::" n " = " maybe-mov(exp(s)) exp(s) "\n"], top)
+ (s) : s
+
+defn emit-module (m:Module) :
+ val v = Vector<Symbol>()
+ for port in ports(m) do :
+ if name(port) ==`reset :
+ emit-all([name(m) "::" name(port) " = rst'1\n"], name(m))
+ else : switch {_ == direction(port)} :
+ INPUT : print-all([name(m) "::" name(port) " = " "in'" prim-width(type(port)) "\n"])
+ OUTPUT : add(v,name(port))
+ emit-s(body(m), to-list(v), name(m))
+
+public defn emit-flo (file:String, c:Circuit) :
+ with-output-file{file, _} $ fn () :
+ emit-module(modules(c)[0])
+ false
+ c
diff --git a/src/main/stanza/ir-utils.stanza b/src/main/stanza/ir-utils.stanza
index 190ad09a..2f049203 100644
--- a/src/main/stanza/ir-utils.stanza
+++ b/src/main/stanza/ir-utils.stanza
@@ -7,6 +7,40 @@ defpackage firrtl/ir-utils :
public defmulti print-debug (o:OutputStream, e:Expression|Stmt|Type|Port|Field|Module|Circuit) -> False
+;============== GENSYM STUFF ======================
+
+val sym-hash = HashTable<Symbol,Int>(symbol-hash)
+public defn firrtl-gensym (s:Symbol) -> Symbol :
+ val cur = get?(sym-hash,s,0)
+ val nxt = cur + 1
+ sym-hash[s] = nxt
+ symbol-join([s cur])
+
+public defn firrtl-gensym () -> Symbol :
+ firrtl-gensym(`gen)
+
+;============== Exceptions =====================
+
+public definterface PassException <: Exception
+public defn PassException (s:String) :
+ new PassException :
+ defmethod print (o:OutputStream, this) :
+ print(o, s)
+
+public defn PassExceptions (xs:Streamable<PassException>) :
+ PassException(string-join(xs, "\n"))
+
+;============== Pass/Compiler Structs ============
+
+public definterface Compiler
+public defmulti passes (c:Compiler) -> List<Pass>
+public defmulti file (c:Compiler) -> String
+
+public definterface Pass
+public defmulti pass (p:Pass) -> (Circuit -> Circuit)
+public defmulti name (p:Pass) -> String
+public defmulti short-name (p:Pass) -> String
+
;============== PRINTERS ===================================
defmethod print (o:OutputStream, d:Flip) :
diff --git a/src/main/stanza/passes.stanza b/src/main/stanza/passes.stanza
index 835a032e..0e20cd4c 100644
--- a/src/main/stanza/passes.stanza
+++ b/src/main/stanza/passes.stanza
@@ -7,16 +7,26 @@ defpackage firrtl/passes :
import firrtl-main
import firrtl/errors
-;============== Exceptions =====================
-public definterface PassException <: Exception
-public defn PassException (s:String) :
- new PassException :
- defmethod print (o:OutputStream, this) :
- print(o, s)
-
-public defn PassExceptions (xs:Streamable<PassException>) :
- PassException(string-join(xs, "\n"))
-
+;============== Pass List ================
+public val standard-passes = to-list $ [
+ CheckHighForm()
+ TempElimination()
+ ToWorkingIR()
+ MakeExplicitReset()
+ ResolveKinds()
+ CheckKinds()
+ InferTypes()
+ CheckTypes()
+ ResolveGenders()
+ CheckGenders()
+ ExpandAccessors()
+ LowerToGround()
+ ExpandIndexedConnects()
+ ExpandWhens()
+ InferWidths()
+ Inline()
+ SplitExp()
+ ToRealIR() ]
;=============== WORKING IR ================================
public definterface Kind
public defstruct WireKind <: Kind
@@ -149,18 +159,6 @@ defmethod info (stmt:EmptyStmt) -> FileInfo : FileInfo()
defmethod type (exp:UIntValue) -> Type : UIntType(width(exp))
defmethod type (exp:SIntValue) -> Type : SIntType(width(exp))
-;============== GENSYM STUFF ======================
-
-val sym-hash = HashTable<Symbol,Int>(symbol-hash)
-defn firrtl-gensym (s:Symbol) -> Symbol :
- val cur = get?(sym-hash,s,0)
- val nxt = cur + 1
- sym-hash[s] = nxt
- symbol-join([s cur])
-
-defn firrtl-gensym () -> Symbol :
- firrtl-gensym(`gen)
-
;============== DEBUG STUFF =============================
public var PRINT-TYPES : True|False = false
public var PRINT-KINDS : True|False = false
@@ -279,6 +277,10 @@ defmethod map (f: Type -> Type, e: WIndex) :
;================= Temporary Variable Elimination ========================
; Returns a new Circuit where temporary variables are removed and returns
; the resulting nested expression
+public defstruct TempElimination <: Pass
+public defmethod pass (b:TempElimination) -> (Circuit -> Circuit) : temp-elimination
+public defmethod name (b:TempElimination) -> String : "Temp Elimination"
+public defmethod short-name (b:TempElimination) -> String : "temp-elim"
defn temp-elimination (c:Circuit) :
val h = HashTable<Symbol,Expression>(symbol-hash)
@@ -308,6 +310,10 @@ defn temp-elimination (c:Circuit) :
; Returns a new Circuit with Refs, Subfields, Indexes and DefAccessors
; replaced with IR-internal nodes that contain additional
; information (kind, gender)
+public defstruct ToWorkingIR <: Pass
+public defmethod pass (b:ToWorkingIR) -> (Circuit -> Circuit) : to-working-ir
+public defmethod name (b:ToWorkingIR) -> String : "Working IR"
+public defmethod short-name (b:ToWorkingIR) -> String : "to-working-ir"
defn to-working-ir (c:Circuit) :
defn to-exp (e:Expression) :
@@ -334,6 +340,10 @@ defn to-working-ir (c:Circuit) :
; If reset is not explicitly passed to instantiations, then this
; pass autmatically connects the parent module's reset to the
; instantiation's reset
+public defstruct MakeExplicitReset <: Pass
+public defmethod pass (b:MakeExplicitReset) -> (Circuit -> Circuit) : make-explicit-reset
+public defmethod name (b:MakeExplicitReset) -> String : "Make Explicit Reset"
+public defmethod short-name (b:MakeExplicitReset) -> String : "make-explicit-reset"
defn make-explicit-reset (c:Circuit) :
defn find-explicit (c:Circuit) -> List<Symbol> :
@@ -374,6 +384,10 @@ defn make-explicit-reset (c:Circuit) :
; objects referenced. This information is stored in the kind
; field in WRef. This pass walks the graph and returns a new
; Circuit where all WRef kinds are resolved
+public defstruct ResolveKinds <: Pass
+public defmethod pass (b:ResolveKinds) -> (Circuit -> Circuit) : resolve-kinds
+public defmethod name (b:ResolveKinds) -> String : "Resolve Kinds"
+public defmethod short-name (b:ResolveKinds) -> String : "resolve-kinds"
defn resolve-kinds (c:Circuit) :
defn resolve (body:Stmt, kinds:HashTable<Symbol,Kind>) :
@@ -428,6 +442,10 @@ defn resolve-kinds (c:Circuit) :
; resolving the subexpressions in its elements.
; Type errors are not checked in this pass, as this is
; postponed for a later/earlier pass.
+public defstruct InferTypes <: Pass
+public defmethod pass (b:InferTypes) -> (Circuit -> Circuit) : infer-types
+public defmethod name (b:InferTypes) -> String : "Infer Types"
+public defmethod short-name (b:InferTypes) -> String : "infer-types"
defn type (m:Module) -> Type :
BundleType(for p in ports(m) map : to-field(p))
@@ -517,6 +535,10 @@ defn infer-types (c:Circuit) -> Circuit :
; elements are single-gender (e.g. accessors, ports).
; Because accessor gender is not known during declaration,
; this pass requires iterating until a fixed point is reached.
+public defstruct ResolveGenders <: Pass
+public defmethod pass (b:ResolveGenders) -> (Circuit -> Circuit) : resolve-genders
+public defmethod name (b:ResolveGenders) -> String : "Resolve Genders"
+public defmethod short-name (b:ResolveGenders) -> String : "resolve-genders"
; Notes
; Is there a case where an incorrect gender would cause a weird result in resolving an accessor gender, such that a following gender check is wrong/right which it shouldn't be?
@@ -637,6 +659,10 @@ defn resolve-genders (c:Circuit) :
; of the accessor, it is transformed into ConnectToIndexed (male) or
; ConnectFromIndexed (female)
; Eg:
+public defstruct ExpandAccessors <: Pass
+public defmethod pass (b:ExpandAccessors) -> (Circuit -> Circuit) : expand-accessors
+public defmethod name (b:ExpandAccessors) -> String : "Expand Accessors"
+public defmethod short-name (b:ExpandAccessors) -> String : "expand-accessors"
defn expand-vector (e:Expression) -> List<Expression> :
val t = type(e) as VectorType
@@ -679,6 +705,10 @@ defn expand-accessors (c:Circuit) :
; This pass involves filling a table mapping the name of elevated types
; to the lowered ground expression names and genders. This allows
; references to be resolved.
+public defstruct LowerToGround <: Pass
+public defmethod pass (b:LowerToGround) -> (Circuit -> Circuit) : lower-to-ground
+public defmethod name (b:LowerToGround) -> String : "Lower To Ground"
+public defmethod short-name (b:LowerToGround) -> String : "lower-to-ground"
defstruct EF :
exp : Expression
@@ -894,6 +924,10 @@ defn lower-to-ground (c:Circuit) -> Circuit :
; This pass converts ConnectToIndexed and ConnectFromIndexed
; into a series of when statements. TODO what about initial
; values?
+public defstruct ExpandIndexedConnects <: Pass
+public defmethod pass (b:ExpandIndexedConnects) -> (Circuit -> Circuit) : expand-connect-indexed
+public defmethod name (b:ExpandIndexedConnects) -> String : "Expand Indexed Connects"
+public defmethod short-name (b:ExpandIndexedConnects) -> String : "expand-indexed-connects"
defn expand-connect-indexed-stmt (s: Stmt) -> Stmt :
defn equality (e1:Expression,e2:Expression) -> Expression :
@@ -910,15 +944,15 @@ defn expand-connect-indexed-stmt (s: Stmt) -> Stmt :
else :
val ref = WRef(firrtl-gensym(get-name(exp(s))),type(index(s)),NodeKind(),UNKNOWN-GENDER)
append(
- list(Connect(info(s),head(locs(s)),exp(s)),DefNode(info(s),name(ref),index(s)))
+ list(DefNode(info(s),name(ref),index(s)))
to-list $
- for (i in 1 to false, l in tail(locs(s))) stream : Conditionally(
+ for (i in 0 to false, l in locs(s)) stream : Conditionally(
info(s),
equality(ref,UIntValue(i,UnknownWidth())),
Connect(info(s),l,exp(s)),
EmptyStmt()
)
- )
+ )
(s:ConnectFromIndexed) : Begin $
if length(exps(s)) == 0 : list(EmptyStmt())
else :
@@ -963,6 +997,10 @@ defn expand-connect-indexed (c: Circuit) -> Circuit :
; The ReadPort enable is calcuated by scanning all entries in
; the table for when this is referenced (a read). All conditions
; are accumulated and OR'ed together.
+public defstruct ExpandWhens <: Pass
+public defmethod pass (b:ExpandWhens) -> (Circuit -> Circuit) : expand-whens
+public defmethod name (b:ExpandWhens) -> String : "Expand Whens"
+public defmethod short-name (b:ExpandWhens) -> String : "expand-whens"
; ======== Expression Computation Library ===========
@@ -1132,7 +1170,6 @@ defn reduce-or (l:List<Expression>) -> Expression :
; kinds: Used to know the kind of reference, so we know whether we should error if it isn't initialized. We also know how we should declare the refernce.
; enables:Calculated off of assigns.
-
defn expand-whens (ports:List<Port>, table:HashTable<Symbol,SymbolicValue>,cons:Vector<Stmt>) -> False :
for p in ports do :
if direction(p) == OUTPUT :
@@ -1350,6 +1387,10 @@ defn expand-whens (c:Circuit) -> Circuit :
; Finally, you replace all width variables with the solved
; widths.
; Low FIRRTL Pass.
+public defstruct InferWidths <: Pass
+public defmethod pass (b:InferWidths) -> (Circuit -> Circuit) : infer-widths
+public defmethod name (b:InferWidths) -> String : "Infer Widths"
+public defmethod short-name (b:InferWidths) -> String : "infer-widths"
public defstruct VarWidth <: Width :
name: Symbol
@@ -1716,6 +1757,10 @@ defn infer-widths (c:Circuit) -> Circuit :
;================= Inline Instances ========================
; Inlines instances. Assumes module with same name as the
; Circuit is the top level module
+public defstruct Inline <: Pass
+public defmethod pass (b:Inline) -> (Circuit -> Circuit) : inline-instances
+public defmethod name (b:Inline) -> String : "Inline Instances"
+public defmethod short-name (b:Inline) -> String : "inline-instances"
defn inline-instances (c:Circuit) :
val h = HashTable<Symbol,Module>(symbol-hash)
@@ -1769,6 +1814,10 @@ defn inline-instances (c:Circuit) :
;================= Split Expressions ========================
; Intended to only work on low firrtl
+public defstruct SplitExp <: Pass
+public defmethod pass (b:SplitExp) -> (Circuit -> Circuit) : split-exp
+public defmethod name (b:SplitExp) -> String : "Split Expressions"
+public defmethod short-name (b:SplitExp) -> String : "split-expressions"
defn split-exp (c:Circuit) :
defn split-exp-s (s:Stmt,v:Vector<Stmt>) -> False :
@@ -1790,7 +1839,6 @@ defn split-exp (c:Circuit) :
val n* =
if n typeof False : firrtl-gensym(`T)
else : firrtl-gensym(symbol-join([n as Symbol `#]))
- ;to-symbol $ string-join $ [n as Symbol firrtl-gensym(`#)]
add(v,DefNode(info,n*,e))
WRef(n*,type(e),NodeKind(),UNKNOWN-GENDER)
(e) : e
@@ -1803,6 +1851,10 @@ defn split-exp (c:Circuit) :
;================= Bring to Real IR ========================
; Returns a new Circuit with only real IR nodes.
+public defstruct ToRealIR <: Pass
+public defmethod pass (b:ToRealIR) -> (Circuit -> Circuit) : to-real-ir
+public defmethod name (b:ToRealIR) -> String : "Real IR"
+public defmethod short-name (b:ToRealIR) -> String : "real-ir"
defn to-real-ir (c:Circuit) :
defn to-exp (e:Expression) :
@@ -1823,257 +1875,4 @@ defn to-real-ir (c:Circuit) :
for m in modules(c) map :
Module(info(m),name(m), ports(m), to-stmt(body(m)))
-;============= FLO PRINTER ======================================
-; Emit
-
-defn flo-op-name (op:PrimOp) -> String :
- switch {op == _ } :
- ;NEG-OP : "neg"
- ;NEG-OP : "neg"
- ;NEG-OP : "neg"
- ;NEG-OP : "neg"
- ADD-UU-OP : "add"
- ADD-US-OP : "add"
- ADD-SU-OP : "add"
- ADD-SS-OP : "add"
- ADD-WRAP-UU-OP : "add"
- ADD-WRAP-US-OP : "add"
- ADD-WRAP-SU-OP : "add"
- ADD-WRAP-SS-OP : "add"
- SUB-UU-OP : "sub"
- SUB-US-OP : "sub"
- SUB-SU-OP : "sub"
- SUB-SS-OP : "sub"
- SUB-WRAP-UU-OP : "sub"
- SUB-WRAP-US-OP : "sub"
- SUB-WRAP-SU-OP : "sub"
- SUB-WRAP-SS-OP : "sub"
- MUL-UU-OP : "mul" ;; todo: signed version
- MUL-US-OP : "mul" ;; todo: signed version
- MUL-SU-OP : "mul" ;; todo: signed version
- MUL-SS-OP : "mul" ;; todo: signed version
- DIV-UU-OP : "div" ;; todo: signed version
- DIV-US-OP : "div" ;; todo: signed version
- DIV-SU-OP : "div" ;; todo: signed version
- DIV-SS-OP : "div" ;; todo: signed version
- MOD-UU-OP : "mod" ;; todo: signed version
- MOD-US-OP : "mod" ;; todo: signed version
- MOD-SU-OP : "mod" ;; todo: signed version
- MOD-SS-OP : "mod" ;; todo: signed version
- LESS-UU-OP : "lt" ;; todo: signed version
- LESS-US-OP : "lt" ;; todo: signed version
- LESS-SU-OP : "lt" ;; todo: signed version
- LESS-SS-OP : "lt" ;; todo: signed version
- LESS-EQ-UU-OP : "lte" ;; todo: swap args
- LESS-EQ-US-OP : "lte" ;; todo: swap args
- LESS-EQ-SU-OP : "lte" ;; todo: swap args
- LESS-EQ-SS-OP : "lte" ;; todo: swap args
- GREATER-UU-OP : "lt" ;; todo: swap args
- GREATER-US-OP : "lt" ;; todo: swap args
- GREATER-SU-OP : "lt" ;; todo: swap args
- GREATER-SS-OP : "lt" ;; todo: swap args
- GREATER-EQ-UU-OP : "lte" ;; todo: signed version
- GREATER-EQ-US-OP : "lte" ;; todo: signed version
- GREATER-EQ-SU-OP : "lte" ;; todo: signed version
- GREATER-EQ-SS-OP : "lte" ;; todo: signed version
- NEQUAL-UU-OP : "neq"
- NEQUAL-SS-OP : "neq"
- EQUAL-UU-OP : "eq"
- EQUAL-SS-OP : "eq"
- MUX-UU-OP : "mux"
- MUX-SS-OP : "mux"
- PAD-U-OP : "rsh" ;; todo: signed version
- PAD-S-OP : "rsh" ;; todo: signed version
- NEG-U-OP : "neg"
- NEG-S-OP : "neg"
- ;AS-UINT-U-OP :
- ;AS-UINT-S-OP :
- ;AS-SINT-U-OP :
- ;AS-SINT-S-OP :
- SHIFT-LEFT-U-OP : "lsh"
- SHIFT-LEFT-S-OP : "lsh"
- SHIFT-RIGHT-U-OP : "rsh"
- SHIFT-RIGHT-S-OP : "arsh"
- DYN-SHIFT-LEFT-U-OP : "lsh"
- DYN-SHIFT-LEFT-S-OP : "lsh"
- DYN-SHIFT-RIGHT-U-OP : "rsh"
- DYN-SHIFT-RIGHT-S-OP : "arsh"
- ;CONVERT-U-OP :
- ;CONVERT-S-OP :
- BIT-AND-OP : "and"
- BIT-NOT-OP : "not"
- BIT-OR-OP : "or"
- BIT-XOR-OP : "xor"
- CONCAT-OP : "cat"
- BIT-SELECT-OP : "rsh"
- BITS-SELECT-OP : "rsh"
- else : error $ string-join $ ["Unable to print Primop: " op]
-
-defn sane-width (wd:Width) -> Int :
- match(wd) :
- (w:IntWidth) : max(1, width(w))
- (w) : error(string-join(["Unknown width: " w]))
-
-defn prim-width (type:Type) -> Int :
- match(type) :
- (t:UIntType) : sane-width(width(t))
- (t:SIntType) : sane-width(width(t))
- (t) : error("Bad prim width type")
-
-defn sizeof (in: Int) -> Int :
- max(1, ceil-log2(in + 1))
-
-defn emit-all (es:Streamable, top:Symbol) :
- for e in es do :
- match(e) :
- (ex:Expression) : emit!(ex,top)
- (ex:String) : print(ex)
- (ex:Symbol) : print(ex)
- ;; (ex:Int) : print-all([ex "'" sizeof(ex)])
- (ex:Int) : print(ex)
- (ex) : print(ex)
-
-defn emit! (e:Expression,top:Symbol) :
- defn greater-op? (op: PrimOp) -> True|False :
- contains?([GREATER-OP, GREATER-UU-OP, GREATER-US-OP, GREATER-SU-OP, GREATER-SS-OP], op)
- defn greater-eq-op? (op: PrimOp) -> True|False :
- contains?([GREATER-EQ-OP, GREATER-EQ-UU-OP, GREATER-EQ-US-OP, GREATER-EQ-SU-OP, GREATER-EQ-SS-OP], op)
- defn less-eq-op? (op: PrimOp) -> True|False :
- contains?([LESS-EQ-OP, LESS-EQ-UU-OP, LESS-EQ-US-OP, LESS-EQ-SS-OP, LESS-EQ-SS-OP], op)
- defn less-op? (op: PrimOp) -> True|False :
- contains?([LESS-OP, LESS-UU-OP, LESS-US-OP, LESS-SS-OP, LESS-SS-OP], op)
- defn cmp-op? (op: PrimOp) -> True|False :
- greater-op?(op) or greater-eq-op?(op) or less-op?(op) or less-eq-op?(op) or
- contains?([EQUAL-OP, EQUAL-UU-OP, EQUAL-SS-OP, NEQUAL-OP, NEQUAL-UU-OP, NEQUAL-SS-OP], op)
- match(e) :
- (e:Ref) : emit-all([top "::" name(e)], top)
- (e:UIntValue) : emit-all([value(e) "'" sane-width(width(e))], top)
- (e:SIntValue) : emit-all([value(e) "'" sane-width(width(e))], top)
- (e:Subfield) : emit-all([exp(e) "/" name(e)], top)
- (e:Index) : emit-all([exp(e) "/" value(e)], top)
- (e:Pad) :
- emit-all(["rsh'" prim-width(type(e)) " " value(e) " 0"], top)
- (e:Register) :
- emit-all(["reg'" prim-width(type(e)) " " enable(e) " " value(e)], top)
- (e:ReadPort) :
- emit-all(["rd'" prim-width(type(e)) " " "1" " " mem(e) " " index(e)], top) ;; enable(e)
- (e:DoPrim) :
- if cmp-op?(op(e)) :
- emit-all([flo-op-name(op(e)) "'" prim-width(type(args(e)[0]))], top)
- if greater-op?(op(e)) or greater-eq-op?(op(e)) :
- emit-all([" " args(e)[1] " " args(e)[0]], top)
- else :
- emit-all([" " args(e)[0] " " args(e)[1]], top)
- else if op(e) == BIT-SELECT-OP :
- emit-all([flo-op-name(op(e)) "'1 " args(e)[0] " " consts(e)[0]], top)
- else if op(e) == BITS-SELECT-OP :
- val w = consts(e)[0] - consts(e)[1] + 1
- emit-all([flo-op-name(op(e)) "'" w " " args(e)[0] " " consts(e)[1]], top)
- ;; else if op(e) == CONCAT-OP :
- ;; val w = consts(e)[0] - consts(e)[1] + 1
- ;; emit-all([flo-op-name(op(e)) "'" w " " args(e)[0] " " consts(e)[1]], top)
- else :
- emit-all([flo-op-name(op(e)) "'" prim-width(type(e))], top)
- if (op(e) == PAD-U-OP) or (op(e) == PAD-S-OP) :
- emit-all([" " args(e)[0] " " consts(e)[0]], top)
- else :
- for arg in args(e) do :
- print(" ")
- emit!(arg, top)
- for const in consts(e) do :
- print-all([" " const "'" sizeof(const)])
- (e) : error("SHOULDN'T EMIT THIS") ;; print-all(["EMIT(" e ")"])
- ;(e) : emit-all(["mov'" prim-width(type(e)) " " e], top) ;TODO, not sure which one is right
-
-defn maybe-mov (e:Expression) -> String :
- val need-mov? = match(e) :
- (e:Ref) : true
- (e:UIntValue) : true
- (e:SIntValue) : true
- (e:Subfield) : true
- (e:Index) : true
- (e) : false
- if need-mov?: "mov " else: ""
-
-defn emit-s (s:Stmt, v:List<Symbol>, top:Symbol) :
- match(s) :
- (s:DefWire) : ""
- (s:DefInstance) : error("Shouldn't be here")
- (s:DefMemory) :
- val vtype = type(s) as VectorType
- emit-all([top "::" name(s) " = mem'" prim-width(type(vtype)) " " size(vtype) "\n"], top)
- (s:DefNode) :
- if value(s) typeof WritePort :
- val e = value(s) as WritePort
- val n = firrtl-gensym(`F)
- emit-all([top "::" n " = wr'" prim-width(type(e)) " " enable(e) " " mem(e) " " index(e) " " top "::" name(s) "\n"], top)
- else :
- emit-all([top "::" name(s) " = " maybe-mov(value(s)) value(s) "\n"], top)
- (s:Begin) : do(emit-s{_, v, top}, body(s))
- (s:Connect) :
- val n = name(loc(s) as Ref)
- if contains?(v,n) :
- emit-all([top "::" n " = out'" prim-width(type(loc(s))) " " exp(s) "\n"], top)
- else :
- emit-all([top "::" n " = " maybe-mov(exp(s)) exp(s) "\n"], top)
- (s) : s
-
-defn emit-module (m:Module) :
- val v = Vector<Symbol>()
- for port in ports(m) do :
- if name(port) ==`reset :
- emit-all([name(m) "::" name(port) " = rst'1\n"], name(m))
- else : switch {_ == direction(port)} :
- INPUT : print-all([name(m) "::" name(port) " = " "in'" prim-width(type(port)) "\n"])
- OUTPUT : add(v,name(port))
- emit-s(body(m), to-list(v), name(m))
-
-public defn emit-flo (file:String, c:Circuit) :
- with-output-file{file, _} $ fn () :
- emit-module(modules(c)[0])
- false
- c
-
-;============= DRIVER ======================================
-public defn run-passes (c: Circuit, p: List<Char>,file:String) :
- var c*:Circuit = c
- println("Compiling!")
- if PRINT-CIRCUITS : println("Original Circuit")
- if PRINT-CIRCUITS : print(c)
- defn do-stage (name:String, f: Circuit -> Circuit) :
- if PRINT-CIRCUITS : println(name)
- c* = f(c*)
- if PRINT-CIRCUITS : print(c*)
- if PRINT-CIRCUITS : println-all(["Finished " name "\n"])
-
- if contains(p,'X') or contains(p,'A') : do-stage("High Form Check", check-high-form)
- if contains(p,'X') or contains(p,'a') : do-stage("Temp Elimination", temp-elimination)
- if contains(p,'X') or contains(p,'b') : do-stage("Working IR", to-working-ir)
-
- if contains(p,'X') or contains(p,'c') : do-stage("Make Explicit Reset", make-explicit-reset)
-
- if contains(p,'X') or contains(p,'d') : do-stage("Resolve Kinds", resolve-kinds)
- if contains(p,'X') or contains(p,'D') : do-stage("Check Kinds", check-kinds)
-
- if contains(p,'X') or contains(p,'e') : do-stage("Infer Types", infer-types)
- if contains(p,'X') or contains(p,'E') : do-stage("Check Types", check-types)
-
- if contains(p,'X') or contains(p,'f') : do-stage("Resolve Genders", resolve-genders)
- if contains(p,'X') or contains(p,'F') : do-stage("Check Genders", check-genders)
-
- if contains(p,'X') or contains(p,'g') : do-stage("Expand Accessors", expand-accessors) ;mem kind
- if contains(p,'X') or contains(p,'h') : do-stage("Lower To Ground", lower-to-ground) ;inst kind
- if contains(p,'X') or contains(p,'i') : do-stage("Expand Indexed Connects", expand-connect-indexed)
-
-; make sure no bundle types
- if contains(p,'X') or contains(p,'k') : do-stage("Expand Whens", expand-whens) ; requires types, lowering
-
- if contains(p,'X') or contains(p,'l') : do-stage("Infer Widths", infer-widths) ; requires lowering, expand whens
-
- if contains(p,'X') or contains(p,'m') : do-stage("Inline Instances", inline-instances) ;inst kind
-
- if contains(p,'X') or contains(p,'n') : do-stage("Split Expressions", split-exp)
- if contains(p,'X') or contains(p,'o') : do-stage("Real IR", to-real-ir)
- if contains(p,'X') or contains(p,'F') : do-stage("To Flo", emit-flo{file,_})
- println("Done!")