diff options
| author | azidar | 2015-05-15 16:34:34 -0700 |
|---|---|---|
| committer | azidar | 2015-05-15 16:34:34 -0700 |
| commit | 2702e571040e7a07317b79f9c5cfdbd61b9ab2bf (patch) | |
| tree | 0e5973d175be18851865b712e16871764157889f /src | |
| parent | 521a4277bfc1d764dc9ee771c604200525e871cb (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.stanza | 49 | ||||
| -rw-r--r-- | src/main/stanza/errors.stanza | 22 | ||||
| -rw-r--r-- | src/main/stanza/firrtl-test-main.stanza | 35 | ||||
| -rw-r--r-- | src/main/stanza/flo.stanza | 221 | ||||
| -rw-r--r-- | src/main/stanza/ir-utils.stanza | 34 | ||||
| -rw-r--r-- | src/main/stanza/passes.stanza | 359 |
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!") |
