diff options
| author | azidar | 2015-11-06 18:55:39 -0800 |
|---|---|---|
| committer | azidar | 2016-01-16 14:28:16 -0800 |
| commit | 9113d54b61b681215a3cc9fcf44e64167fad0568 (patch) | |
| tree | 3cf0e1d3e48397a71c398fad38bef8af0c827e09 /src | |
| parent | ffa090c10d6210395e3f304e56008e2183a85698 (diff) | |
WIP. Compiles, need to test
Diffstat (limited to 'src')
| -rw-r--r-- | src/main/stanza/bigint2.stanza | 25 | ||||
| -rw-r--r-- | src/main/stanza/errorstemp.stanza | 994 | ||||
| -rw-r--r-- | src/main/stanza/firrtl-test-main.stanza | 39 | ||||
| -rw-r--r-- | src/main/stanza/ir-parser.stanza | 2 | ||||
| -rw-r--r-- | src/main/stanza/ir-utils.stanza | 46 | ||||
| -rw-r--r-- | src/main/stanza/passes.stanza | 372 | ||||
| -rw-r--r-- | src/main/stanza/passes.stanza2 | 2662 | ||||
| -rw-r--r-- | src/main/stanza/passes.stanza3 | 2687 |
8 files changed, 6624 insertions, 203 deletions
diff --git a/src/main/stanza/bigint2.stanza b/src/main/stanza/bigint2.stanza index bc2e9f36..91cd4558 100644 --- a/src/main/stanza/bigint2.stanza +++ b/src/main/stanza/bigint2.stanza @@ -1,7 +1,6 @@ defpackage bigint2 : import core import verse - import firrtl/ir-utils ;============ Big Int Library ============= @@ -9,6 +8,30 @@ defpackage bigint2 : ; index 0. ;------------ Helper Functions ------------ +public defn pow (x:Int,y:Int) -> Int : + var x* = 1 + var y* = y + while y* != 0 : + x* = times(x*,x) + y* = minus(y*,1) + x* + +public defn pow (x:Long,y:Long) -> Long : + var x* = to-long(1) + var y* = y + while y* != to-long(0) : + x* = times(x*,x) + y* = minus(y*,to-long(1)) + x* +public defn to-int (x:Long) -> Int : + if x > to-long(2147483647) or x < to-long(-2147483648) : error("Long too big to convert to Int") + else : to-int(to-string(x)) + +public defn req-num-bits (i: Int) -> Int : + val i* = + if i < 0 : ((-1 * i) - 1) + else : i + ceil-log2(i* + 1) + 1 val word-size = 32 val all-digits = "0123456789abcdef" diff --git a/src/main/stanza/errorstemp.stanza b/src/main/stanza/errorstemp.stanza new file mode 100644 index 00000000..9c5043f2 --- /dev/null +++ b/src/main/stanza/errorstemp.stanza @@ -0,0 +1,994 @@ +defpackage firrtl/errors : + import core + import verse + import firrtl/ir2 + import firrtl/ir-utils + import firrtl/primops + import firrtl/passes + import firrtl-main + import bigint2 + +; TODO +; make sure it compiles, write tests, look over code to make sure its right +;========== ALL CHECKS ================= +;PARSER CHECK +; * No nested modules <- parser +; * Only modules in circuit (no statements or expressions) <- parser +; * Module must be a reference in inst declaration + +;AFTER ?????? +; o No combinational loops + +;================= High Form Check ========================== +; * Subexps of Subfield and Index can only be subfields, index, or refs +; * Can only connect to a Ref or Subfield or Index or WritePort +; * A module has the same name as main of circuit +; * mems cannot be a bundle with flips +; * instance module must have the same name as a defined module +; * Unique names per module +; * No name can be a prefix of any other name. +; * all references are declared +; * UInt only has positive ints +; * Vector types has positive size +; * Width sizes are positive +; * Primops have the correct number of arguments + +public defstruct CheckHighForm <: Pass +public defmethod pass (b:CheckHighForm) -> (Circuit -> Circuit) : check-high-form +public defmethod name (b:CheckHighForm) -> String : "High Form Check" +public defmethod short-name (b:CheckHighForm) -> String : "high-form-check" + +var sinfo! = FileInfo() + +;----------------- Errors ------------------------ +defn NotUnique (name:Symbol) : + PassException $ string-join $ + [sinfo! ": [module " mname "] Reference " name " does not have a unique name."] + +defn IsPrefix (prefix:Symbol) : + PassException $ string-join $ + [sinfo! ": [module " mname "] Symbol " prefix " is a prefix."] + +defn InvalidLOC () : + PassException $ string-join $ + [sinfo! ": [module " mname "] Invalid connect to an expression that is not a reference or a WritePort."] + +defn NegUInt () : + PassException $ string-join $ + [sinfo! ": [module " mname "] UIntValue cannot be negative."] + +defn UndeclaredReference (name:Symbol) : + PassException $ string-join $ + [sinfo! ": [module " mname "] Reference " name " is not declared."] + +defn PoisonWithFlip (name:Symbol) : + PassException $ string-join $ + [sinfo! ": [module " mname "] Poison " name " cannot be a bundle type with flips."] + +defn MemWithFlip (name:Symbol) : + PassException $ string-join $ + [sinfo! ": [module " mname "] Memory " name " cannot be a bundle type with flips."] + +defn InvalidAccess () : + PassException $ string-join $ + [sinfo! ": [module " mname "] Invalid access to non-reference."] + +defn NoTopModule (name:Symbol) : + PassException $ string-join $ + [sinfo! ": A single module must be named " name "."] + +defn ModuleNotDefined (name:Symbol) : + PassException $ string-join $ + [sinfo! ": Module " name " is not defined."] + +defn IncorrectNumArgs (op:Symbol, n:Int) : + PassException $ string-join $ + [sinfo! ": [module " mname "] Primop " op " requires " n " expression arguments."] + +defn IncorrectNumConsts (op:Symbol, n:Int) : + PassException $ string-join $ + [sinfo! ": [module " mname "] Primop " op " requires " n " integer arguments."] + +defn NegWidth () : + PassException $ string-join $ + [sinfo! ": [module " mname "] Width cannot be negative or zero."] + +defn NegVecSize () : + PassException $ string-join $ + [sinfo! ": [module " mname "] Vector type size cannot be negative."] + +defn NegMemSize () : + PassException $ string-join $ + [sinfo! ": [module " mname "] Memory size cannot be negative or zero."] + +defn IllegalUnknownWidth () : + PassException $ string-join $ + [sinfo! ": [module " mname "] Widths must be defined for memories and poison nodes."] + +defn BadPrintf (x:Char) : + PassException $ string-join $ + [sinfo! ": [module " mname "] Bad printf format: \"%" x "\""];" + +defn BadPrintfTrailing () : + PassException $ string-join $ + [sinfo! ": [module " mname "] Bad printf format: trailing \"%\""];" + +defn BadPrintfIncorrectNum () : + PassException $ string-join $ + [sinfo! ": [module " mname "] Bad printf format: incorrect number of arguments"];" + + +;---------------- Helper Functions -------------- +defn has-flip? (t:Type) -> True|False : + var has? = false + defn find-flip (t:Type) -> Type : + match(t) : + (t:BundleType) : + for f in fields(t) do : + if flip(f) == REVERSE : has? = true + t + (t) : t + find-flip(t) + map(find-flip,t) + has? + +defn contains?<?T> (c:?T,cs:Streamable<?T>) -> True|False : + label<True|False> myret : + for x in cs do : + if x == c : myret(true) + false + +;defstruct Trie : +; char : Char +; children : HashTable<Char,Trie> +; +;defn char-hash (c:Char) -> Int : symbol-hash(to-symbol(c)) +;defn new-trie (c:Char) -> Trie : Trie(c,HashTable<Char,Trie>(char-hash)) +;defn tail (s:String) -> String : substring(s,1,length(s)) +; +;defn insert-top (trie:Trie,symbol:Symbol) -> True|False : true +; insert(trie,string-join([" " symbol])) +; +;defn insert (trie:Trie,string:String) -> True|False : +; if length(string) == 0 : char(trie) +; +; val child = get?(children(trie),string[0],false) +; if length(string) == 1 : +; match(child) : +; (c:Trie) : false +; (c:False) : +; children(trie)[string[0]] = new-trie(string[0]) +; true +; else : +; match(child) : +; (c:Trie) : insert(c,tail(string)) +; (c:False) : +; val t = new-trie(string[0]) +; insert(t,tail(string)) +; children(trie)[string[0]] = t +; +;defn has? (trie:Trie, string:String) -> True|False : +; if length(string) == 0 : true +; if length(string) >= 1 : +; if key?(children(trie),string[0]) : +; has?(tail(string), children(trie)[string[0]]) +; else : false +; +;defn any-prefixes? (trie:Trie,delim:String) -> String|False : +; if has?(trie,delim) : +; val c = get-children-after(trie:Trie,delim:String) +; if length(keys(c)) > 1 : +; +; +; if length(partial-delim) == 0 : to-string(char(trie)) +; if length(partial-delim) == 1 : +; if key?(children(trie),partial-delim[0]) : any-prefixes?(...WAS HERE +; if char(trie) == partial-delim[0] : +; if length(keys(children(trie))) >= 2 : to-string(char(trie)) +; else : false +; else : +; label<String|False> myret : +; for x in children(trie) do : +; match(any-prefixes?(value(x),full-delim,full-delim)) : +; (s:False) : false +; (s:String) : myret(string-join([char(trie) s])) +; false +; else : +; label<String|False> myret : +; for x in children(trie) do : +; if char(trie) == partial-delim[0] : +; match(any-prefixes?(value(x),tail(partial-delim),full-delim)) : +; (s:False) : false +; (s:String) : myret(string-join([char(trie) s])) +; match(any-prefixes?(value(x),partial-delim,full-delim)) : +; (s:False) : false +; (s:String) : myret(string-join([char(trie) s])) +; match(any-prefixes?(value(x),full-delim,full-delim)) : +; (s:False) : false +; (s:String) : myret(string-join([char(trie) s])) +; false + + +;--------------- Check High Form Pass ------------------- +public defn check-high-form (c:Circuit) -> Circuit : + val errors = Vector<PassException>() + defn check-high-form-primop (e:DoPrim) -> False : + defn correct-num (ne:Int|False,nc:Int) -> False : + if not (ne typeof False) : + if length(args(e)) != ne as Int : add(errors,IncorrectNumArgs(to-symbol(op(e)),ne as Int)) + if length(consts(e)) != nc : add(errors,IncorrectNumConsts(to-symbol $ op(e),nc)) + + switch {op(e) == _} : + ADD-OP : correct-num(2,0) + SUB-OP : correct-num(2,0) + MUL-OP : correct-num(2,0) + DIV-OP : correct-num(2,0) + MOD-OP : correct-num(2,0) + QUO-OP : correct-num(2,0) + REM-OP : correct-num(2,0) + ADD-WRAP-OP : correct-num(2,0) + SUB-WRAP-OP : correct-num(2,0) + LESS-OP : correct-num(2,0) + LESS-EQ-OP : correct-num(2,0) + GREATER-OP : correct-num(2,0) + GREATER-EQ-OP : correct-num(2,0) + EQUAL-OP : correct-num(2,0) + NEQUAL-OP : correct-num(2,0) + EQUIV-OP : correct-num(2,0) + NEQUIV-OP : correct-num(2,0) + MUX-OP : correct-num(3,0) + PAD-OP : correct-num(1,1) + AS-UINT-OP : correct-num(1,0) + AS-SINT-OP : correct-num(1,0) + DYN-SHIFT-LEFT-OP : correct-num(2,0) + DYN-SHIFT-RIGHT-OP : correct-num(2,0) + SHIFT-LEFT-OP : correct-num(1,1) + SHIFT-RIGHT-OP : correct-num(1,1) + CONVERT-OP : correct-num(1,0) + NEG-OP : correct-num(1,0) + BIT-NOT-OP : correct-num(1,0) + BIT-AND-OP : correct-num(2,0) + BIT-OR-OP : correct-num(2,0) + BIT-XOR-OP : correct-num(2,0) + BIT-AND-REDUCE-OP : correct-num(false,0) + BIT-OR-REDUCE-OP : correct-num(false,0) + BIT-XOR-REDUCE-OP : correct-num(false,0) + CONCAT-OP : correct-num(2,0) + BIT-SELECT-OP : correct-num(1,1) + BITS-SELECT-OP : correct-num(1,2) + + defn check-fstring (s:String,i:Int) -> False : + val valid-formats = "bedxs" + var percent = false + var ret = true + var npercents = 0 + for x in s do : + if (not contains?(valid-formats,x)) and percent : + add(errors,BadPrintf(x)) + if x == '%' : npercents = npercents + 1 + percent = x == '%' + if percent : add(errors,BadPrintfTrailing()) + if npercents != i : add(errors,BadPrintfIncorrectNum()) + defn check-valid-loc (e:Expression) -> False : + match(e) : + (e:UIntValue|SIntValue|DoPrim) : + add(errors,InvalidLOC()) + (e) : false + defn check-high-form-w (w:Width) -> Width : + match(w) : + (w:IntWidth) : + if width(w) <= to-long(0) : add(errors,NegWidth()) + w + (w) : w + defn check-high-form-t (t:Type) -> Type : + match(map(check-high-form-t,t)) : + (t:VectorType) : + if size(t) < 0 : add(errors,NegVecSize()) + (t) : false + map(check-high-form-w,t) + + defn check-high-form-m (m:Module) -> Module : + val names = HashTable<Symbol,True>(symbol-hash) + val mnames = HashTable<Symbol,True>(symbol-hash) + defn check-high-form-e (e:Expression) -> Expression : + defn valid-subexp (e:Expression) -> Expression : + match(e) : + (e:Ref|SubField|SubIndex|SubAccess) : false + (e) : add(errors,InvalidAccess()) + e + match(map(check-high-form-e,e)) : + (e:Ref) : + if not key?(names,name(e)) : + add(errors,UndeclaredReference(name(e))) + (e:DoPrim) : check-high-form-primop(e) + (e:UIntValue) : false + (e:SubAccess) : + valid-subexp(exp(e)) + e + (e) : map(valid-subexp,e) + map(check-high-form-w,e) + map(check-high-form-t,e) + e + defn check-high-form-s (s:Stmt) -> Stmt : + defn check-name (name:Symbol) -> Symbol : + if key?(names,name) : add(errors,NotUnique(name)) + else : names[name] = true + name + sinfo! = info(s) + map(check-name,s) + map(check-high-form-t,s) + map(check-high-form-e,s) + match(s) : + (s:DefWire|DefRegister|DefNode|Conditionally|Stop|Begin) : false + (s:DefPoison) : + if has-flip?(type(s)) : add(errors, PoisonWithFlip(name(s))) + check-high-form-t(type(s)) + (s:DefMemory) : + if has-flip?(data-type(s)) : add(errors, MemWithFlip(name(s))) + if depth(s) <= 0 : add(errors,NegMemSize()) + (s:DefInstance) : + if not contains?(module(s),map(name,modules(c))) : + add(errors, ModuleNotDefined(module(s))) + (s:Connect) : check-valid-loc(loc(s)) + (s:Print) : check-fstring(string(s),length(args(s))) + (s:BulkConnect) : check-valid-loc(loc(s)) + (s) : false + + map(check-high-form-s,s) + + mname = name(m) + for m in modules(c) do : + mnames[name(m)] = true + for p in ports(m) do : + names[name(p)] = true + map(check-high-form-t,type(p)) + map(check-high-form-w,type(p)) + + match(m) : + (m:ExModule) : false + (m:InModule) : check-high-form-s(body(m)) + m + + var number-top-m = 0 + for m in modules(c) do : + if name(m) == main(c) : number-top-m = number-top-m + 1 + check-high-form-m(m) + sinfo! = info!(c) + if number-top-m != 1 : add(errors,NoTopModule(main(c))) + throw(PassExceptions(errors)) when not empty?(errors) + c + +;==================== CHECK TYPES ===================== +; o Subfields are only on bundles, before type inference <- need to not error, just do unknown-type +; o Indexes are only on vectors +; o pred in conditionally must be of type UInt +; o enable/index in read/writeports must be UInt +; o node's value cannot be a bundle with a flip in it +; o := has same types +; o 2nd arg in dshr/l must be UInt, in general do primops +; o clock must be ClockType +; o reset must be UInt<1> + +public defstruct CheckTypes <: Pass +public defmethod pass (b:CheckTypes) -> (Circuit -> Circuit) : check-types +public defmethod name (b:CheckTypes) -> String : "Check Types" +public defmethod short-name (b:CheckTypes) -> String : "check-types" + +;----------------- Errors --------------------- +defn SubfieldNotInBundle (info:FileInfo, name:Symbol) : + PassException $ string-join $ + [info ": [module " mname "] Subfield " name " is not in bundle."] + +defn SubfieldOnNonBundle (info:FileInfo, name:Symbol) : + PassException $ string-join $ + [info ": [module " mname "] Subfield " name " is accessed on a non-bundle."] + +defn IndexTooLarge (info:FileInfo, value:Int) : + PassException $ string-join $ + [info ": [module " mname "] Index with value " value " is too large."] + +defn IndexOnNonVector (info:FileInfo) : + PassException $ string-join $ + [info ": [module " mname "] Index illegal on non-vector type."] + +defn IndexNotUInt (info:FileInfo) : + PassException $ string-join $ + [info ": [module " mname "] Index is not of UIntType."] + +defn EnableNotUInt (info:FileInfo) : + PassException $ string-join $ + [info ": [module " mname "] Enable is not of UIntType."] + +defn InvalidConnect (info:FileInfo) : + PassException $ string-join $ + [info ": [module " mname "] Type mismatch."] + +defn PrintfArgNotGround (info:FileInfo) : + PassException $ string-join $ + [info ": [module " mname "] Printf arguments must be either UIntType or SIntType."] + +defn ReqClk (info:FileInfo) : + PassException $ string-join $ + [info ": [module " mname "] Requires a clock typed signal."] + +defn EnNotUInt (info:FileInfo) : + PassException $ string-join $ + [info ": [module " mname "] Enable must be a UIntType typed signal."] + +defn PredNotUInt (info:FileInfo) : + PassException $ string-join $ + [info ": [module " mname "] Predicate not a UIntType."] + +defn OpNotGround (info:FileInfo, op:Symbol) : + PassException $ string-join $ + [info ": [module " mname "] Primop " op " cannot operate on non-ground types."] + +defn OpNotUInt (info:FileInfo, op:Symbol,e:Symbol) : + PassException $ string-join $ + [info ": [module " mname "] Primop " op " requires argument " e " to be a UInt type."] + +defn OpNotAllUInt (info:FileInfo, op:Symbol) : + PassException $ string-join $ + [info ": [module " mname "] Primop " op " requires all arguments to be UInt type."] + +defn OpNotAllSameType (info:FileInfo, op:Symbol) : + PassException $ string-join $ + [info ": [module " mname "] Primop " op " requires all operands to have the same type."] + +defn NodeIllegalFlips (info:FileInfo) : + PassException $ string-join $ + [info ": [module " mname "] Node cannot be a bundle type with flips."] + +defn OnResetIllegalFlips (info:FileInfo) : + PassException $ string-join $ + [info ": [module " mname "] The register in onreset cannot be a bundle type with flips."] + +;---------------- Helper Functions -------------- +defmethod equal? (t1:Type,t2:Type) -> True|False : + match(t1,t2) : + (t1:ClockType,t2:ClockType) : true + (t1:UIntType,t2:UIntType) : true + (t1:SIntType,t2:SIntType) : true + (t1:BundleType,t2:BundleType) : + var same? = true + for (f1 in fields(t1),f2 in fields(t2)) do : + if flip(f1) != flip(f2) : same? = false + if name(f1) != name(f2) : same? = false + if type(f1) != type(f2) : same? = false + same? + (t1:VectorType,t2:VectorType) : + if type(t1) == type(t2) and size(t1) == size(t2) : true + else : false + (t1,t2) : false + +defn ut () -> UIntType : UIntType(UnknownWidth()) +defn st () -> SIntType : SIntType(UnknownWidth()) + +defn check-types-primop (e:DoPrim, errors:Vector<PassException>,info:FileInfo) -> False : + defn all-same-type (ls:List<Expression>) -> False : + var error? = false + for x in ls do : + if type(head(ls)) != type(x) : + error? = true + if error? : add(errors,OpNotAllSameType(info,to-symbol $ op(e))) + defn all-ground (ls:List<Expression>) -> False : + var error? = false + for x in ls do : + if not (type(x) typeof UIntType or type(x) typeof SIntType) : + error? = true + if error? : add(errors,OpNotGround(info,to-symbol $ op(e))) + defn all-uint (ls:List<Expression>) -> False : + var error? = false + for x in ls do : + if not (type(x) typeof UIntType) : + error? = true + if error? : add(errors,OpNotAllUInt(info,to-symbol $ op(e))) + defn is-uint (x:Expression) -> False : + var error? = false + if not (type(x) typeof UIntType) : + error? = true + if error? : add(errors,OpNotUInt(info,to-symbol $ op(e),to-symbol(x))) + + all-ground(args(e)) + + switch {op(e) == _} : + ADD-OP : false + SUB-OP : false + MUL-OP : false + DIV-OP : false + MOD-OP : false + QUO-OP : false + REM-OP : false + ADD-WRAP-OP : false + SUB-WRAP-OP : false + LESS-OP : false + LESS-EQ-OP : false + GREATER-OP : false + GREATER-EQ-OP : false + EQUAL-OP : false + NEQUAL-OP : false + EQUIV-OP : all-same-type(args(e)) + NEQUIV-OP : all-same-type(args(e)) + MUX-OP : + all-same-type(tail(args(e))) + is-uint(head(args(e))) + PAD-OP : false + AS-UINT-OP : false + AS-SINT-OP : false + DYN-SHIFT-LEFT-OP : is-uint(args(e)[1]) + DYN-SHIFT-RIGHT-OP : is-uint(args(e)[1]) + SHIFT-LEFT-OP : false + SHIFT-RIGHT-OP : false + CONVERT-OP : false + NEG-OP : false + BIT-NOT-OP : all-same-type(args(e)) + BIT-AND-OP : all-same-type(args(e)) + BIT-OR-OP : all-same-type(args(e)) + BIT-XOR-OP : all-same-type(args(e)) + BIT-SELECT-OP : false + BITS-SELECT-OP : false + BIT-AND-REDUCE-OP : all-uint(args(e)) + BIT-OR-REDUCE-OP : all-uint(args(e)) + BIT-XOR-REDUCE-OP : all-uint(args(e)) + CONCAT-OP : all-uint(args(e)) + +;----------------- Check Types Pass --------------------- +public defn check-types (c:Circuit) -> Circuit : + val errors = Vector<PassException>() + defn check-types-e (info:FileInfo,e:Expression) -> Expression : + match(map(check-types-e{info,_},e)) : + (e:WRef) : e + (e:WSubField) : + match(type(exp(e))) : + (t:BundleType) : + val ft = for p in fields(t) find : name(p) == name(e) + if ft == false : add(errors,SubfieldNotInBundle(info,name(e))) + (t) : add(errors,SubfieldOnNonBundle(info,name(e))) + (e:WSubIndex) : + match(type(exp(e))) : + (t:VectorType) : + if value(e) >= size(t) : add(errors,IndexTooLarge(info,value(e))) + (t) : add(errors,IndexOnNonVector(info)) + (e:WSubAccess) : + match(type(exp(e))) : + (t:VectorType) : false + (t) : add(errors,IndexOnNonVector(info)) + (e:DoPrim) : check-types-primop(e,errors,info) + (e:UIntValue|SIntValue) : false + e + + defn bulk-equals? (t1:Type,t2:Type) -> True|False : + match(t1,t2) : + (t1:BundleType,t2:BundleType) : + var same? = true + for (f1 in fields(t1),f2 in fields(t2)) do : + if name(f1) == name(f2) : + if flip(f1) != flip(f2) : same? = false + if not bulk-equals?(type(f1),type(f2)) : same? = false + same? + (t1:ClockType,t2:ClockType) : true + (t1:UIntType,t2:UIntType) : true + (t1:SIntType,t2:SIntType) : true + (t1:VectorType,t2:VectorType) : + if bulk-equals?(type(t1),type(t2)) : true + else : false + (t1,t2) : false + + defn check-types-s (s:Stmt) -> Stmt : + map{check-types-s,_} $ { + match(map(check-types-e{info(s),_},s)) : + (s:Connect) : + if type(loc(s)) != type(exp(s)) : add(errors,InvalidConnect(info(s))) + (s:BulkConnect) : + if not bulk-equals?(type(loc(s)),type(exp(s))) : + add(errors,InvalidConnect(info(s))) + (s:Stop) : + if type(clk(s)) != ClockType() : add(errors,ReqClk(info(s))) + if type(en(s)) != ut() : add(errors,EnNotUInt(info(s))) + (s:Print) : + for x in args(s) do : + if type(x) != ut() and type(x) != st(): + add(errors,PrintfArgNotGround(info(s))) + if type(clk(s)) != ClockType() : add(errors,ReqClk(info(s))) + if type(en(s)) != ut() : add(errors,EnNotUInt(info(s))) + (s:Conditionally) : + if type(pred(s)) != ut() : add(errors,PredNotUInt(info(s))) + (s:DefNode) : + if has-flip?(type(value(s))) : add(errors,NodeIllegalFlips(info(s))) + (s) : false + s }() + + for m in modules(c) do : + mname = name(m) + match(m) : + (m:ExModule) : false + (m:InModule) : check-types-s(body(m)) + throw(PassExceptions(errors)) when not empty?(errors) + c + +;================= GENDER CHECK ========================== +; 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 + +public defstruct CheckGenders <: Pass +public defmethod pass (b:CheckGenders) -> (Circuit -> Circuit) : check-genders +public defmethod name (b:CheckGenders) -> String : "Check Genders" +public defmethod short-name (b:CheckGenders) -> String : "check-genders" + +;----------------- Errors --------------------- +defn WrongGender (info:FileInfo,expr:Symbol,wrong:Symbol,right:Symbol) : + PassException $ string-join $ + [info ": [module " mname "] Expression " expr " is used as a " wrong " but can only be used as a " right "."] + +;---------------- Helper Functions -------------- +defn dir-to-gender (d:Direction) -> Gender : + switch {_ == d} : + INPUT : MALE + OUTPUT : FEMALE ;BI-GENDER + +defn as-srcsnk (g:Gender) -> Symbol : + switch {_ == g} : + MALE : `source + FEMALE : `sink + UNKNOWN-GENDER : `unknown + BI-GENDER : `sourceOrSink + +;----------------- Check Genders Pass --------------------- + +public defn check-genders (c:Circuit) -> Circuit : + val errors = Vector<PassException>() + defn get-kind (e:Expression) -> Kind : + match(e) : + (e:WRef) : kind(e) + (e:WSubField) : get-kind(exp(e)) + (e:WSubIndex) : get-kind(exp(e)) + (e:WSubAccess) : get-kind(exp(e)) + (e) : NodeKind() + + defn check-gender (info:FileInfo,genders:HashTable<Symbol,Gender>,e:Expression,desired:Gender) -> False : + val gender = get-gender(e,genders) + val kind* = get-kind(e) + val flip? = + match(type(e)) : + (t:BundleType) : + for f in fields(t) any? : flip(f) == REVERSE + (t) : false + + ;println(e) + ;println(gender) + ;println(desired) + ;println(kind*) + ;println(desired == gender) + ;if gender != desired and gender != BI-GENDER: + switch fn ([x,y]) : gender == x and desired == y : + [MALE, FEMALE] : + add(errors,WrongGender(info,to-symbol(e),as-srcsnk(desired),as-srcsnk(gender))) + [FEMALE, MALE] : + if (kind* == PortKind() or kind* == InstanceKind()) and flip? == false : + ; OK! + false + else : + ; Not Ok! + add(errors,WrongGender(info,to-symbol(e),as-srcsnk(desired),as-srcsnk(gender))) + else : false + + defn get-gender (e:Expression,genders:HashTable<Symbol,Gender>) -> Gender : + match(e) : + (e:WRef) : genders[name(e)] + (e:WSubField) : + val f = {_ as Field} $ for f in fields(type(exp(e)) as BundleType) find : name(f) == name(e) + get-gender(exp(e),genders) * flip(f) + (e:WSubIndex) : get-gender(exp(e),genders) + (e:WSubAccess) : get-gender(exp(e),genders) + (e:DoPrim) : MALE + (e:UIntValue) : MALE + (e:SIntValue) : MALE + + defn check-genders-e (info:FileInfo,e:Expression,genders:HashTable<Symbol,Gender>) -> False : + do(check-genders-e{info,_,genders},e) + match(e) : + (e:WRef) : false + (e:WSubField) : false + (e:WSubIndex) : false + (e:WSubAccess) : false + (e:DoPrim) : + for e in args(e) do : + check-gender(info,genders,e,MALE) + (e:UIntValue) : false + (e:SIntValue) : false + + defn check-genders-s (s:Stmt,genders:HashTable<Symbol,Gender>) -> False : + do(check-genders-e{info(s),_:Expression,genders},s) + do(check-genders-s{_:Stmt,genders},s) + match(s) : + (s:DefWire) : genders[name(s)] = BI-GENDER + (s:DefPoison) : genders[name(s)] = MALE + (s:DefRegister) : genders[name(s)] = BI-GENDER + (s:DefNode) : + check-gender(info(s),genders,value(s),MALE) + genders[name(s)] = MALE + (s:DefMemory) : genders[name(s)] = FEMALE + (s:WDefInstance) : genders[name(s)] = MALE + (s:Connect) : + check-gender(info(s),genders,loc(s),FEMALE) + check-gender(info(s),genders,exp(s),MALE) + (s:Print) : + for x in args(s) do : + check-gender(info(s),genders,x,MALE) + check-gender(info(s),genders,en(s),MALE) + check-gender(info(s),genders,clk(s),MALE) + (s:BulkConnect) : + check-gender(info(s),genders,loc(s),FEMALE) + check-gender(info(s),genders,exp(s),MALE) + (s:Conditionally) : + check-gender(info(s),genders,pred(s),MALE) + (s:Empty) : false + (s:Stop) : + check-gender(info(s),genders,en(s),MALE) + check-gender(info(s),genders,clk(s),MALE) + (s:Begin) : false + + + for m in modules(c) do : + mname = name(m) + val genders = HashTable<Symbol,Gender>(symbol-hash) + for p in ports(m) do : + genders[name(p)] = dir-to-gender(direction(p)) + match(m) : + (m:ExModule) : false + (m:InModule) : check-genders-s(body(m),genders) + throw(PassExceptions(errors)) when not empty?(errors) + c + +;================= Width Check ========================== +;AFTER WIDTH INFERENCE +; * No names +; * No Unknowns +; * All widths are positive +; * widths are large enough to contain value + + +public defstruct CheckWidths <: Pass +public defmethod pass (b:CheckWidths) -> (Circuit -> Circuit) : check-width +public defmethod name (b:CheckWidths) -> String : "Width Check" +public defmethod short-name (b:CheckWidths) -> String : "width-check" + +;----------------- Errors ------------------------ + +defn UninferredWidth (info:FileInfo) : + PassException $ string-join $ + [info ": [module " mname "] Uninferred width."] + +defn WidthTooSmall (info:FileInfo,v:String) : + PassException $ string-join $ + [info ": [module " mname "] Width too small for constant " v "."] + +;---------------- Helper Functions -------------- + +;--------------- Check Width Pass ------------------- +public defn check-width (c:Circuit) -> Circuit : + val errors = Vector<PassException>() + + defn check-width-m (m:Module) -> False : + defn check-width-w (info:FileInfo,w:Width) -> Width : + match(w) : + (w:IntWidth) : + if width(w) <= to-long(0) : add(errors,NegWidth()) + (w) : + add(errors,UninferredWidth(info)) + w + + defn check-width-e (info:FileInfo,e:Expression) -> Expression : + match(map(check-width-e{info,_},e)) : + (e:UIntValue) : + match(width(e)) : + (w:IntWidth) : + if max(to-long(1),to-long(req-num-bits(value(e)) - 1)) > width(w) : + add(errors,WidthTooSmall(info,to-string(value(e)))) + (w) : add(errors,UninferredWidth(info)) + check-width-w(info,width(e)) + (e:SIntValue) : + match(width(e)) : + (w:IntWidth) : + if to-long(req-num-bits(value(e))) > width(w) : + add(errors,WidthTooSmall(info,to-string(value(e)))) + (w) : add(errors,UninferredWidth(info)) + check-width-w(info,width(e)) + (e:DoPrim) : false + (e) : false + + ;mapr(check-width-w{info,_},type(map(check-width-e{info,_},e))) + e + + defn check-width-s (s:Stmt) -> Stmt : + sinfo! = info(s) + map(check-width-e{info(s),_},map(check-width-s,s)) + map(mapr{check-width-w{info(s),_},_:Type},s) + + for p in ports(m) do : + mapr(check-width-w{info(p),_},type(p)) + + match(m) : + (m:ExModule) : false + (m:InModule) : check-width-s(body(m)) + false + + for m in modules(c) do : + mname = name(m) + check-width-m(m) + throw(PassExceptions(errors)) when not empty?(errors) + c + + +;================ Initialization Check ================== +; Error on all componenents that are not connected to. + +public defstruct CheckInitialization <: Pass +public defmethod pass (b:CheckInitialization) -> (Circuit -> Circuit) : check-init +public defmethod name (b:CheckInitialization) -> String : "Check Initialization" +public defmethod short-name (b:CheckInitialization) -> String : "check-init" + +;----------------- Errors ------------------------ + +defn RefNotInitialized (info:FileInfo, name:Symbol) : + PassException $ string-join $ + [info ": [module " mname "] Reference " name " is not fully initialized."] + +;------------ Helper Functions ------------- + +;------------ Pass ------------------ + +public defn check-init (c:Circuit) : + val errors = Vector<PassException>() + + defn check-init-m (m:InModule) : + defn get-name (e:Expression) -> Symbol : + match(e) : + (e:WRef) : name(e) + (e:WSubField) : symbol-join([get-name(exp(e)) `. name(e)]) + (e) : error("Shouldn't be here") + defn has-void? (e:Expression) -> True|False : + var void? = false + defn has-void (e:Expression) -> Expression : + match(e) : + (e:WVoid) : + void? = true + e + (e) : map(has-void,e) + has-void(e) + void? + defn check-init-s (s:Stmt) -> Stmt : + match(s) : + (s:Connect) : + if has-void?(exp(s)) : add(errors,RefNotInitialized(info(s),get-name(loc(s)))) + s + (s) : map(check-init-s,s) + + check-init-s(body(m)) + + for m in modules(c) do : + mname = name(m) + match(m) : + (m:InModule) : check-init-m(m) + (m) : false + + throw(PassExceptions(errors)) when not empty?(errors) + c + +;;================= Low Form Check ========================== +;;AFTER LOWERING +;; o All things connect to once +;; o no reg +;; o no accessors +;; o only vecs are for memories +;; o no bundles (future, will have them for mems) +;; o only predicated conditional connects +; +;public defstruct CheckLowForm <: Pass +;public defmethod pass (b:CheckLowForm) -> (Circuit -> Circuit) : check-low-form +;public defmethod name (b:CheckLowForm) -> String : "Low Form Check" +;public defmethod short-name (b:CheckLowForm) -> String : "low-form-check" +; +;;----------------- Errors ------------------------ +;defn InvalidVec (info:FileInfo,name:Symbol) : +; PassException $ string-join $ +; [info ": [module " mname "] Expression " name " has an illegal vector type."] +; +;defn InvalidBundle (info:FileInfo,name:Symbol) : +; PassException $ string-join $ +; [info ": [module " mname "] Expression " name " has an illegal bundle type."] +; +;defn NoWhen (info:FileInfo) : +; PassException $ string-join $ +; [info ": [module " mname "] Illegal when statement. No when statements with multiple statements are allowed in low firrtl."] +; +;defn SingleAssignment (info:FileInfo,name:Symbol) : +; PassException $ string-join $ +; [info ": [module " mname "] Illegal assignment to " name ". Wires can only be assigned to once."] +; +;defn NoOnReset (info:FileInfo) : +; PassException $ string-join $ +; [info ": [module " mname "] Invalid use of on-reset. No on-resets are allowed in low firrtl."] +; +;defn NoBulkConnect (info:FileInfo) : +; PassException $ string-join $ +; [info ": [module " mname "] Invalid use of <>. No <>'s are allowed in low firrtl."] +; +;;---------------- Helper Functions -------------- +; +;;--------------- Check Low Form Pass ------------------- +;public defn check-low-form (c:Circuit) -> Circuit : +; val errors = Vector<PassException>() +; +; defn check-low-form-t (info:FileInfo,t:Type,name:Symbol) -> False : +; match(t) : +; (t:VectorType) : add(errors,InvalidVec(info,name)) +; (t:BundleType) : add(errors,InvalidBundle(info,name)) +; (t) : false +; +; defn check-low-form-m (m:Module) -> False : +; for p in ports(m) do : +; check-low-form-t(info(p),type(p),name(p)) +; +; val assigned? = HashTable<Symbol,True>(symbol-hash) +; val insts = Vector<Symbol>() +; val mems = Vector<Symbol>() +; defn check-correct-exp (info:FileInfo,e:Expression) -> False : +; do(check-correct-exp{info,_:Expression},e) +; match(e) : +; (e:Ref) : +; if contains?(insts,name(e)) : +; for f in fields(type(e) as BundleType) do : +; check-low-form-t(info,type(f),name(e)) +; if contains?(mems,name(e)) : +; check-low-form-t(info,type(type(e) as VectorType),name(e)) +; (e) : false ;check-low-form-t(info,type(e),to-symbol $ to-string(e)) +; defn check-low-form-s (s:Stmt) -> False : +; match(s) : +; (s:DefWire) : +; check-low-form-t(info(s),type(s),name(s)) +; (s:DefPoison) : +; check-low-form-t(info(s),type(s),name(s)) +; (s:DefMemory) : +; check-low-form-t(info(s),type(s),name(s)) +; add(mems,name(s)) +; (s:DefInstance) : +; for f in fields(type(module(s)) as BundleType) do : +; check-low-form-t(info(s),type(f),name(s)) +; add(insts,name(s)) +; (s:DefNode) : +; check-correct-exp(info(s),value(s)) +; (s:Print) : +; for x in args(s) do : +; check-correct-exp(info(s),x) +; (s:DefRegister) : false +; (s:DefAccessor) : false +; (s:Conditionally) : +; if (not alt(s) typeof Empty) or (conseq(s) typeof Begin) : add(errors,NoWhen(info(s))) +; (s:OnReset) : add(errors,NoOnReset(info(s))) +; (s:BulkConnect) : add(errors,NoBulkConnect(info(s))) +; (s:Connect) : +; check-correct-exp(info(s),exp(s)) +; match(loc(s)) : +; (e:Ref|Subfield) : +; val n* = to-symbol $ to-string $ e +; if key?(assigned?,n*) : add(errors,SingleAssignment(info(s),n*)) +; else : assigned?[to-symbol $ to-string $ e] = true +; (e) : check-correct-exp(info(s),e) +; (s:Empty) : false +; (s:Stop) : false +; (s:Begin) : do(check-low-form-s,s) +; +; match(m) : +; (m:ExModule) : false +; (m:InModule) : check-low-form-s(body(m)) +; false +; +; for m in modules(c) do : +; mname = name(m) +; check-low-form-m(m) +; throw(PassExceptions(errors)) when not empty?(errors) +; c +; diff --git a/src/main/stanza/firrtl-test-main.stanza b/src/main/stanza/firrtl-test-main.stanza index 9c68bc92..b3da3c0b 100644 --- a/src/main/stanza/firrtl-test-main.stanza +++ b/src/main/stanza/firrtl-test-main.stanza @@ -14,7 +14,7 @@ #include("compilers.stanza") ;#include("flo.stanza") ;#include("verilog.stanza") -#include("symbolic-value.stanza") +;#include("symbolic-value.stanza") ;Custom Packages ;#include("custom-passes.stanza") @@ -34,24 +34,24 @@ defpackage firrtl-main : ;import firrtl/custom-passes ;import firrtl/custom-compiler -defn set-printvars! (p:List<Char>) : - if contains(p,'t') : PRINT-TYPES = true - if contains(p,'k') : PRINT-KINDS = true - if contains(p,'w') : PRINT-WIDTHS = true - if contains(p,'T') : PRINT-TWIDTHS = true - if contains(p,'g') : PRINT-GENDERS = true - if contains(p,'c') : PRINT-CIRCUITS = true - if contains(p,'d') : PRINT-DEBUG = true - if contains(p,'i') : PRINT-INFO = true - -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 set-printvars! (p:List<Char>) : +; if contains(p,'t') : PRINT-TYPES = true +; if contains(p,'k') : PRINT-KINDS = true +; if contains(p,'w') : PRINT-WIDTHS = true +; if contains(p,'T') : PRINT-TWIDTHS = true +; if contains(p,'g') : PRINT-GENDERS = true +; if contains(p,'c') : PRINT-CIRCUITS = true +; if contains(p,'d') : PRINT-DEBUG = true +; if contains(p,'i') : PRINT-INFO = true +; +;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 @@ -148,4 +148,3 @@ defn main () : CURRENT-OUTPUT-STREAM = prev-out main() - diff --git a/src/main/stanza/ir-parser.stanza b/src/main/stanza/ir-parser.stanza index 8f4c41dd..fe8af96f 100644 --- a/src/main/stanza/ir-parser.stanza +++ b/src/main/stanza/ir-parser.stanza @@ -276,7 +276,7 @@ defsyntax firrtl : stmt = (inst ?name:#id! #of! ?m:#id!) : DefInstance(first-info(form),name,m) stmt = (node ?name:#id! #=! ?e:#exp!) : DefNode(first-info(form),name,e) stmt = (poison ?name:#id! #:! ?t:#type!) : DefPoison(first-info(form),name, t) - stmt = (stop(?ret:#int,)) : Stop(first-info(form),ret,clk) + stmt = (stop(?clk:#exp,?ret:#int)) : Stop(first-info(form),ret,clk) stmt = (printf(?clk:#exp ?str:#string ?es:#exp ...)) : Print(first-info(form),str,es,clk) stmt = (?s:#stmt/when) : s diff --git a/src/main/stanza/ir-utils.stanza b/src/main/stanza/ir-utils.stanza index 442e5713..ba0e2423 100644 --- a/src/main/stanza/ir-utils.stanza +++ b/src/main/stanza/ir-utils.stanza @@ -7,6 +7,11 @@ defpackage firrtl/ir-utils : ;============== DEBUG STUFF ============================= public defmulti print-debug (o:OutputStream, e:Expression|Stmt|Type|Port|Field|Module|Circuit) -> False +public defmethod print-debug (o:OutputStream, e:Expression|Stmt|Type|Port|Field|Module|Circuit) -> False : false +public defmulti turn-off-debug (x:False) -> False +public defmethod turn-off-debug (x:False) : false +public defmulti turn-on-debug (x:False) +public defmethod turn-on-debug (x:False) : false ;============== GENSYM STUFF ====================== @@ -75,7 +80,7 @@ public defn get-sym-hash (m:InModule,keywords:Streamable<Symbol>) -> HashTable<S to-stmt(body(m)) map(to-port,ports(m)) sym-hash - + ; ======== Expression Computation Library =========== public defn BoolType () : UIntType(IntWidth(1)) @@ -107,7 +112,7 @@ public defn MUX (p:Expression,e1:Expression,e2:Expression) -> Expression : DoPrim(MUX-OP,list(p,e1,e2),list(),type(e1)) public defn CAT (e1:Expression,e2:Expression) -> Expression : - DoPrim(CAT-OP,list(e1,e2),list(),type(e1)) + DoPrim(CONCAT-OP,list(e1,e2),list(),type(e1)) public defn NOT (e1:Expression) -> Expression : if e1 == one : zero @@ -123,9 +128,9 @@ public defn children (e:Expression) -> List<Expression> : to-list(es) public defn exp-hash (e:Expression) -> Int : - turn-off-debug() + turn-off-debug(false) val i = symbol-hash(to-symbol(to-string(e))) - turn-on-debug() + turn-on-debug(false) i ;============== Exceptions ===================== @@ -143,12 +148,17 @@ public defn PassExceptions (xs:Streamable<PassException>) : public definterface Compiler public defmulti passes (c:Compiler) -> List<Pass> public defmulti backend (c:Compiler) -> List<Pass> +defmethod passes (c:Compiler) : List<Pass>() public defmulti with-output (c:Compiler) -> ((() -> False) -> False) +defmethod with-output (c:Compiler) : 1 as ? public definterface Pass public defmulti pass (p:Pass) -> (Circuit -> Circuit) +public defmethod pass (p:Pass) : fn (c:Circuit) : c public defmulti name (p:Pass) -> String +public defmethod name (p:Pass) -> String : "--" public defmulti short-name (p:Pass) -> String +public defmethod short-name (p:Pass) -> String : "--" public defmethod print (o:OutputStream, p:Pass) : print(o,name(p)) @@ -177,15 +187,6 @@ public defn max (x:Long,y:Long) -> Long : if x < y : y else : x -public defn to-int (x:Long) -> Int : - if x > to-long(2147483647) or x < to-long(-2147483648) : error("Long too big to convert to Int") - else : to-int(to-string(x)) - -public defn req-num-bits (i: Int) -> Int : - val i* = - if i < 0 : ((-1 * i) - 1) - else : i - ceil-log2(i* + 1) + 1 defn escape (s:String) -> String : val s* = Vector<String>() @@ -397,7 +398,7 @@ public defn map<?T> (f: Type -> Type, t:?T&Type) -> T : type as T&Type public defmulti map<?T> (f: Expression -> Expression, e:?T&Expression) -> T -defmethod map (f: Expression -> Expression, e:Expression) -> Expression : +defmethod map (f: Expression -> Expression, e:Expression) -> Expression : match(e) : (e:SubField) : SubField(f(exp(e)), name(e), type(e)) (e:SubIndex) : SubIndex(f(exp(e)), value(e), type(e)) @@ -406,7 +407,7 @@ defmethod map (f: Expression -> Expression, e:Expression) -> Expression : (e) : e public defmulti map<?T> (f: Symbol -> Symbol, c:?T&Stmt) -> T -defmethod map (f: Symbol -> Symbol, c:Stmt) -> Stmt : +defmethod map (f: Symbol -> Symbol, c:Stmt) -> Stmt : match(c) : (c:DefWire) : DefWire(info(c),f(name(c)),type(c)) (c:DefPoison) : DefPoison(info(c),f(name(c)),type(c)) @@ -580,21 +581,6 @@ public defn merge!<?K,?V> (a:HashTable<?K,?V>, b:HashTable<K,V>) : for e in b do : a[key(e)] = value(e) -public defn pow (x:Int,y:Int) -> Int : - var x* = 1 - var y* = y - while y* != 0 : - x* = times(x*,x) - y* = minus(y*,1) - x* - -public defn pow (x:Long,y:Long) -> Long : - var x* = to-long(1) - var y* = y - while y* != to-long(0) : - x* = times(x*,x) - y* = minus(y*,to-long(1)) - x* ;=================== VERILOG KEYWORDS ======================= diff --git a/src/main/stanza/passes.stanza b/src/main/stanza/passes.stanza index dcd4c319..897bb94d 100644 --- a/src/main/stanza/passes.stanza +++ b/src/main/stanza/passes.stanza @@ -6,7 +6,6 @@ defpackage firrtl/passes : import firrtl/primops import firrtl-main ;import firrtl/errors - import firrtl/symbolic-value import bigint2 ;============== Pass List ================ @@ -14,20 +13,20 @@ public val standard-passes = to-list $ [ ;CheckHighForm() ;TempElimination() ToWorkingIR() - ;ResolveKinds() + ResolveKinds() ;CheckKinds() - ;InferTypes() + InferTypes() ;CheckTypes() - ;ResolveGenders() + ResolveGenders() ;CheckGenders() ;ExpandAccessors() ;LowerToGround() - ;;ExpandIndexedConnects() + ;ExpandIndexedConnects() ;InlineIndexed() - ;ExpandWhens() - ;InferWidths() + ExpandWhens() + InferWidths() ;Inline() - ;SplitExp() + SplitExp() ;CheckLowForm() ;ToRealIR() ;Pad() @@ -40,7 +39,8 @@ public defstruct RegKind <: Kind public defstruct InstanceKind <: Kind public defstruct PortKind <: Kind public defstruct NodeKind <: Kind -public defstruct MemKind <: Kind +public defstruct MemKind <: Kind : + ports : List<Symbol> public defstruct ExpKind <: Kind public definterface Gender @@ -204,7 +204,7 @@ var old-PRINT-GENDERS : True|False = false var old-PRINT-CIRCUITS : True|False = false var old-PRINT-DEBUG : True|False = false var old-PRINT-INFO : True|False = false -public defn turn-off-debug () : +defmethod turn-off-debug (x:False) : old-PRINT-TYPES = PRINT-TYPES old-PRINT-KINDS = PRINT-KINDS old-PRINT-WIDTHS = PRINT-WIDTHS @@ -213,7 +213,7 @@ public defn turn-off-debug () : old-PRINT-CIRCUITS = PRINT-CIRCUITS old-PRINT-DEBUG = PRINT-DEBUG old-PRINT-INFO = PRINT-INFO -public defn turn-on-debug () : +defmethod turn-on-debug (x:False) : PRINT-TYPES = old-PRINT-TYPES PRINT-KINDS = old-PRINT-KINDS PRINT-WIDTHS = old-PRINT-WIDTHS @@ -366,7 +366,7 @@ defn remove-unknowns-w (w:Width) -> Width : match(w) : (w:UnknownWidth) : VarWidth(firrtl-gensym(`w,width-name-hash)) (w) : w -defn remove-unknowns (t:Type) -> Type : mapr(remove-unknowns-w,t) +defn remove-unknowns (t:Type) -> Type : t;mapr(remove-unknowns-w,t) TODO FIX!!! defmethod equal? (w1:Width,w2:Width) -> True|False : match(w1,w2) : @@ -460,9 +460,9 @@ defn to-dir (g:Gender) -> Direction : MALE : INPUT FEMALE : OUTPUT defn to-gender (d:Direction) -> Gender : - switch {_ == g} : + switch {_ == d} : INPUT: MALE - OUPUT: FEMALE + OUTPUT: FEMALE ;================= Remove Special Characters ======================== ; Returns a new Circuit where all names have all special characters @@ -646,7 +646,7 @@ defn resolve-kinds (c:Circuit) : (s:DefNode) : kinds[name(s)] = NodeKind() (s:DefRegister) : kinds[name(s)] = RegKind() (s:WDefInstance) : kinds[name(s)] = InstanceKind() - (s:DefMemory) : kinds[name(s)] = MemKind() + (s:DefMemory) : kinds[name(s)] = MemKind(append-all([readers(s) writers(s) readwriters(s)])) (s) : false map(find-stmt,s) @@ -919,7 +919,7 @@ defn get-valid-points (t1:Type,t2:Type,flip1:Flip,flip2:Flip) -> List<[Int,Int]> add(points,[x[0] + i, x[1] + i]) to-list(points) defn create-exps (n:Symbol, t:Type) -> List<Expression> : - create-exps(WRef(n,t,ExpKind(),UNKNOWN-GENDER) + create-exps(WRef(n,t,ExpKind(),UNKNOWN-GENDER)) defn create-exps (e:WRef|WSubField|WSubIndex) -> List<Expression> : match(type(e)) : (t:UIntType|SIntType|ClockType) : list(e) @@ -995,7 +995,7 @@ defn expand-connects (c:Circuit) -> Circuit : (m:InModule) : expand-connects(m) -;;================ REPLACE INDEXERS ========================= +;;;================ REPLACE INDEXERS ========================= ; This pass inlines all accessors to non-memory vector typed ; components. @@ -1951,22 +1951,22 @@ defn split-exp (m:InModule) -> InModule : val sh = get-sym-hash(m,keys(v-keywords)) defn split-exp-s (s:Stmt) -> Stmt : val base = match(s) : - (s:Connect) : get-name(loc(s)) + (s:Connect) : lowered-name(loc(s)) (s:DefNode) : name(s) (s:DefRegister) : name(s) (s) : `F defn split (e:Expression) -> Expression : val n = firrtl-gensym(base,sh) add(v,DefNode(info(s),n,e)) - WRef(n,e,kind(e),type(e)) + WRef(n,type(e),kind(e),gender(e)) defn split-exp-e (e:Expression,i:Int) -> Expression : match(map(split-exp-e{_,i + 1},e)) : (e:DoPrim) : - if i > 0 : split(e,base) + if i > 0 : split(e) else : e (e) : e - map{split-exp{_,i},_} $ map(split-exp-s,s) - split-exp-s(body(m),v,sh) + map{split-exp-e{_,0},_} $ map(split-exp-s,s) + split-exp-s(body(m)) InModule(info(m),name(m),ports(m),Begin(to-list(v))) defn split-exp (c:Circuit) -> Circuit : @@ -2289,7 +2289,7 @@ public defn const-prop (c:Circuit) -> Circuit : ; DoPrim(BITS-SELECT-OP,list(root-ref(e)),list(base,off),UIntType(IntWidth(off))) ; ;;------------- Pass ------------------ -; + ;defn condense-mems (m:InModule) -> InModule : ; val mem-assigns = HashTable<Expression,Expression>(exp-hash) ; defn collect-mems (s:Stmt) -> Stmt : @@ -2344,14 +2344,49 @@ public defmethod name (b:LowerTypes) -> String : "Lower Types" public defmethod short-name (b:LowerTypes) -> String : "lower-types" ;------------- Utils --------------- +defn is-ground? (t:Type) -> True|False : + match(t) : + (t:UIntType|SIntType) : true + (t) : false +defn mport? (ex:Expression) -> True|False : + match(kind(ex)) : + (k:MemKind) : match(ex) : + (ex:WRef|WSubIndex) : false + (ex:WSubField) : + var yes? = switch { _ == name(ex) } : + `wdata : true + `rdata : true + `data : true + `wmask : true + else : false + yes? and match(exp(ex)) : + (e:WSubField) : + contains?(ports(kind(e) as MemKind),name(e)) and (exp(e) typeof WRef) + (e) : false + (ex) : false + (k) : false +defn substitute (e:Expression, s:Symbol) -> Expression : + match(e) : + (e:WRef) : WRef(merge(name(e),s,`_),UnknownType(),kind(e),gender(e)) + (e) : map(substitute{_,s},e) +defn collect (e:Expression, s:Symbol) -> Expression : + match(e) : + (e:WSubField) : + if mport?(exp(e)) : substitute(e,s) + else : collect(e,merge(name(e),s,`_)) + (e:WSubIndex) : collect(e,merge(to-symbol(value(e)),s,`_)) + (e) : e +defn lower-mem (e:Expression) -> Expression : + match(e) : + (e:WSubField) : collect(exp(e),name(e)) + (e:WSubIndex) : collect(exp(e),to-symbol(value(e))) + (e) : e defn merge (a:Symbol,b:Symbol,x:Symbol) -> Symbol : symbol-join([a x b]) defn lowered-name (e:Expression) -> Symbol : match(e) : (e:WRef) : name(e) - (e:WSubField) : - if kind(e) typeof MemKind|InstanceKind and exp(e) typeof WRef : name(e) - else : merge(lowered-name(exp(e)),name(e),`_) + (e:WSubField) : merge(lowered-name(exp(e)),name(e),`_) (e:WSubIndex) : merge(lowered-name(exp(e)),to-symbol(value(e)),`_) defn root-ref (e:Expression) -> Expression : match(e) : @@ -2365,9 +2400,11 @@ defn lower-types (s:Stmt) -> Stmt : match(e) : (e:WRef|UIntValue|SIntValue) : e (e:WSubField) : - val root = root-ref(e) - match(kind(e)) - (k:InstanceKind|MemKind) : WSubField(root,lowered-name(e),type(e),gender(e)) + match(kind(e)) : + (k:InstanceKind) : + val temp = lowered-name(WRef(name(e),UnknownType(),InstanceKind(),MALE)) + WSubField(root-ref(e),temp,type(e),gender(e)) + (k:MemKind) : lower-mem(e) (k) : WRef(lowered-name(e),type(e),kind(e),gender(e)) (e:WSubIndex) : WRef(lowered-name(e),type(e),kind(e),gender(e)) (e:DoPrim) : map(lower-types-e,e) @@ -2378,24 +2415,22 @@ defn lower-types (s:Stmt) -> Stmt : val es = create-exps(name(s),type(s)) Begin $ for e in es map : defn replace-type (t:Type) -> Type : type(e) - defn replace-name (n:Symbol) -> Symbol : name(e) + defn replace-name (n:Symbol) -> Symbol : lowered-name(e) map{replace-name,_} $ map(replace-type,s) (s:WDefInstance) : val fields* = for f in fields(type(s) as BundleType) map-append : - val es = create-exps(WRef(name(f),type(f),ExpKind(),flip(p) * MALE)) - BundleType $ for e in es map : + val es = create-exps(WRef(name(f),type(f),ExpKind(),flip(f) * MALE)) + for e in es map : switch { _ == gender(e) } : - MALE : Field(name(e),DEFAULT,type(f)) - FEMALE : Field(name(e),REVERSE,type(f)) + MALE : Field(lowered-name(e),DEFAULT,type(f)) + FEMALE : Field(lowered-name(e),REVERSE,type(f)) WDefInstance(info(s),name(s),module(s),BundleType(fields*)) (s:DefMemory) : - if is - for f in fields(type(s) as BundleType) map-append : - val es = create-exps(WRef(name(f),type(f),ExpKind(),flip(p) * MALE)) - BundleType $ for e in es map : - switch { _ == gender(e) } : - MALE : Field(name(e),DEFAULT,type(f)) - FEMALE : Field(name(e),REVERSE,type(f)) + if is-ground?(data-type(s)) : s + else : + val es = create-exps(name(s),data-type(s)) + Begin $ for e in es map : + DefMemory(info(s),merge(name(s),lowered-name(e),`_),type(e),depth(s),write-latency(s),read-latency(s),readers(s),writers(s),readwriters(s)) (s) : map(lower-types,s) defn lower-types (c:Circuit) -> Circuit : @@ -2423,74 +2458,92 @@ defstruct VIndent defstruct VRandom val tab = VIndent() val ran = VRandom() -defn get-width (t:Type) -> Long : +defn escape (s:String) -> String : + val s* = Vector<String>() + add(s*,"\"");" + var percent = false + for c in s do : + if c == '\n' : + add(s*,"\\n") + else : + if c == 'x' and percent : + add(s*,"h") + else : add(s*,to-string(c)) + percent = c == '%' + add(s*,"\"");" + string-join(s*) +defn remove-root (ex:Expression) -> Expression : + match(exp(ex as WSubField)) : + (e:WSubField) : remove-root(e) + (e:WRef) : WRef(name(ex as WSubField),type(ex),InstanceKind(),UNKNOWN-GENDER) +defn !empty? (s:Vector) -> True|False : + if length(s) == 0 : false + else : true +defn long! (t:Type) -> Long : match(t) : - (t:UIntType|SIntType) : width(t) + (t:UIntType|SIntType) : width(width(t) as IntWidth) (t:BundleType) : - var w = 0 - for f in fields do : - w = w + get-width(type(f)) + var w = to-long(0) + for f in fields(t) do : + w = w + long!(type(f)) w - (t:VectorType) : size(t) * get-width(type(t)) -defn get-name (e:Expression) -> Symbol : - match(e) : - (e:WRef) : name(e) - (e:WSubField) : to-symbol $ string-join([get-name(exp(e)) `_ name(f)]) - (e:WSubAccess) : print(e) - (e:WSubIndex) : print(e) + (t:VectorType) : to-long(size(t)) * long!(type(t)) -defn rand-string (t:Type) -> String : - val w* = ((get-width(t) + to-long(31)) / to-long(32)) +defn rand-string (t:Type) -> Streamable : + val w* = ((long!(t) + to-long(31)) / to-long(32)) ["{" w* "{" ran "}};"] -defn emit (s:Streamable, top:Int) : - for x in s do : - match(x) : - (e:Expression) : - turn-off-debug() - match(e) : - (e:DoPrim) : op-print(e) - (e:WRef) : print(e) - (e:WSubField) : print-all([exp(e) `_ name(f)]) - (e:WSubAccess) : print(e) - (e:WSubIndex) : print(e) - (e:UIntValue|SIntValue) : v-print(e) - turn-on-debug() - (t:Type) : - match(t) : - (t:UIntType) - (s:Symbol) : print(s) - (i:Int) : print(i) - (s:String) : print(s) - (t:VIndent) : print(" ") - (r:VRandom) : print("$random") - (s:Streamable) : emit(s, top + 1) - if top == 0 : print("\n") - - +defn emit (x:?) : emit(x,0) +defn emit (x:?, top:Int) : + match(x) : + (e:Expression) : + turn-off-debug(false) + match(e) : + (e:DoPrim) : op-print(e) + (e:WRef) : print(e) + ;(e:WSubField) : print-all([exp(e) `_ name(f)]) + (e:WSubAccess) : print(e) + (e:WSubIndex) : print(e) + (e:UIntValue|SIntValue) : v-print(e) + turn-on-debug(false) + (t:Type) : + match(t) : + (t:UIntType|SIntType) : + val w = long!(t) - to-long(1) + if w >= to-long(0) : print-all(["[" w ":0]"]) + else : "" + (s:Symbol) : print(s) + (i:Int) : print(i) + (s:String) : print(s) + (t:VIndent) : print(" ") + (r:VRandom) : print("$random") + (s:Streamable) : + for x in s do : + emit(x, top + 1) + if top == 0 : print("\n") ;------------- PASS ----------------- defn v-print (e:UIntValue|SIntValue) : val str = to-string(value(e)) val out = substring(str,1,length(str) - 1) print $ string-join $ match(e) : - (e:UIntValue) : [width!(type(e)) "'" out] - (e:SIntValue) : [width!(type(e)) "'s" out] -defn op-print (dprim:DoPrim) : - defn cast-if (e:Expression) -> String : + (e:UIntValue) : [long!(type(e)) "'" out] + (e:SIntValue) : [long!(type(e)) "'s" out] +defn op-print (doprim:DoPrim) : + defn cast-if (e:Expression) -> ? : val signed? = for x in args(doprim) any? : type(x) typeof SIntType if not signed? : e else : match(type(e)) : (t:SIntType) : ["$signed(" e ")"] (t:UIntType) : ["$signed({1'b0," e "})"] - defn cast (e:Expression) -> String + defn cast (e:Expression) -> ? : match(type(doprim)) : (t:UIntType) : e (t:SIntType) : ["$signed(" e ")"] defn a0 () -> Expression : args(doprim)[0] defn a1 () -> Expression : args(doprim)[1] defn a2 () -> Expression : args(doprim)[2] - defn c0 () -> Expression : consts(doprim)[0] - defn c1 () -> Expression : consts(doprim)[1] + defn c0 () -> Int : consts(doprim)[0] + defn c1 () -> Int : consts(doprim)[1] print $ string-join $ switch {_ == op(doprim)} : ADD-OP : [cast-if(a0()) " + " cast-if(a1())] @@ -2512,12 +2565,12 @@ defn op-print (dprim:DoPrim) : EQUAL-OP : [cast-if(a0()) " == " cast-if(a1())] MUX-OP : [a0() " ? " cast(a1()) " : " cast(a2())] PAD-OP : - val w = width!(type(a0())) + val w = long!(type(a0())) val diff = (to-long(c0()) - w) if w == to-long(0) : [ a0() ] else : match(type(doprim)) : (t:SIntType) : ["{{" diff "{" a0() "[" w - to-long(1) "]}}, " a0() " }"] - (t) : ["{{" diff "'d0 }, " x " }"] + (t) : ["{{" diff "'d0 }, " a0() " }"] AS-UINT-OP : ["$unsigned(" emit(a0()) ")"] AS-SINT-OP : ["$signed(" emit(a0()) ")"] DYN-SHIFT-LEFT-OP : [cast(a0()) " << " emit(a1())] @@ -2526,7 +2579,7 @@ defn op-print (dprim:DoPrim) : (t:SIntType) : [cast(a0()) " >>> " a1()] (t) : [cast(a0()) " >> " a1()] SHIFT-LEFT-OP : [cast(a0()) " << " c0()] - SHIFT-RIGHT-OP : [cast(a0()) "[" width!(type(a0())) - to-long(1) ":" c0() "]"] + SHIFT-RIGHT-OP : [cast(a0()) "[" long!(type(a0())) - to-long(1) ":" c0() "]"] NEG-OP : ["-{" cast(a0()) "}"] CONVERT-OP : match(type(a0())) : @@ -2540,38 +2593,43 @@ defn op-print (dprim:DoPrim) : BIT-SELECT-OP : [cast(a0()) "[" c0() "]"] BITS-SELECT-OP : [cast(a0()) "[" c0() ":" c1() "]"] BIT-AND-REDUCE-OP : - join{_," & "} $ - for b in 0 to width!(type(doprim)) map : - [cast(a0() ) "[" b "]"] + val v = Vector<Streamable>() + for b in 0 to to-int(long!(type(doprim))) do : + add(v,[cast(a0()) "[" b "]"]) + join(v," & ") BIT-OR-REDUCE-OP : - join{_," | "} $ - for b in 0 to width!(type(doprim)) map : - [cast(a0() ) "[" b "]"] + val v = Vector<Streamable>() + for b in 0 to to-int(long!(type(doprim))) do : + add(v,[cast(a0() ) "[" b "]"]) + join(v," | ") BIT-XOR-REDUCE-OP : - join{_," ^ "} $ - for b in 0 to width!(type(doprim)) map : - [cast(a0() ) "[" b "]"] + val v = Vector<Streamable>() + for b in 0 to to-int(long!(type(doprim))) do : + add(v,[cast(a0() ) "[" b "]"]) + join(v," ^ ") defn emit-verilog (m:InModule) -> Module : val netlist = HashTable<Expression,Expression>(exp-hash) val simlist = Vector<Stmt>() + val namehash = get-sym-hash(m,keys(v-keywords)) defn build-netlist (s:Stmt) -> Stmt : match(s) : (s:Connect) : netlist[loc(s)] = exp(s) (s:Conditionally) : add(simlist,s) (s:DefNode) : - val e = WRef(name(s),type(e),NodeKind(),MALE) - netlist[e] = exp(s) + val e = WRef(name(s),get-type(s),NodeKind(),MALE) + netlist[e] = value(s) (s) : map(build-netlist,s) + s val declares = Vector<Streamable>() val at-clock = HashTable<Expression,Vector<Streamable>>(exp-hash) - val initals = Vector<Streamable>() + val initials = Vector<Streamable>() val simulates = Vector<Streamable>() defn declare (b:Symbol,n:Symbol,t:Type) : add(declares,[b t n ";"]) - defn assign (e:Expression) : - add(declares,["assign " e " = " netlist[e]]) + defn assign (e:Expression,value:Expression) : + add(declares,["assign " e " = " value]) defn update-reset (e:Expression,clk:Expression,reset?:Expression,init:Expression) : add(at-clock[clk],["if(" reset? ") begin"]) add(at-clock[clk],[tab e " <= " init]) @@ -2583,52 +2641,64 @@ defn emit-verilog (m:InModule) -> Module : add(at-clock[clk],[tab e " <= " netlist[e]]) add(at-clock[clk],["end"]) defn initialize (e:Expression) : - add(initals,[e " = " rand-string(type(e))]) + add(initials,[e " = " rand-string(type(e))]) defn initialize-mem (e:Expression,i:Int) : - add(initals,["for (initvar = 0; initvar < " i "; initvar = initvar+1)"]) + add(initials,["for (initvar = 0; initvar < " i "; initvar = initvar+1)"]) val index = WRef(`initvar,UnknownType(),ExpKind(),UNKNOWN-GENDER) - add(initals,[tab WSubAccess(e,index,UnknownType(),FEMALE), " = " rand-string(type(e))]) + add(initials,[tab WSubAccess(e,index,UnknownType(),FEMALE), " = " rand-string(type(e))]) defn instantiate (n:Symbol,m:Symbol,es:List<Expression>) : add(declares,[m " " n " ("]) for (e in es,i in 1 to false) do : - val s = [tab "." remove-base(e) "(" netlist[e] ")"] - if i == size(es) : add(declares,[s ","]) + val s = [tab "." remove-root(e) "(" netlist[e] ")"] + if i == length(es) : add(declares,[s ","]) else : add(declares,s) add(declares,[");"]) defn simulate (clk:Expression,en:Expression,s:Streamable) : - add(at-clock(clk),["`ifndef SYNTHESIS"]) - add(at-clock(clk),[tab "if(" en ") begin"]) - add(at-clock(clk),[tab tab s]) - add(at-clock(clk),[tab "end"]) - add(at-clock(clk),["`endif"]) + add(at-clock[clk],["`ifndef SYNTHESIS"]) + add(at-clock[clk],[tab "if(" en ") begin"]) + add(at-clock[clk],[tab tab s]) + add(at-clock[clk],[tab "end"]) + add(at-clock[clk],["`endif"]) defn stop (ret:Int) -> Streamable : ["$fdisplay(32/'h80000002," ret ");$finish;"] defn printf (str:String,args:List<Expression>) -> Streamable : val str* = join(List(escape(str),args),",") ["$fdisplay(32/'h80000002," str* ");"] + defn delay (e:Expression, n:Int) -> Expression : + var e* = e + for i in 0 to n do : + val name = firrtl-gensym(lowered-name(e),namehash) + declare(`reg,name,type(e)) + val e** = WRef(name,type(e),ExpKind(),UNKNOWN-GENDER) + assign(e**,e*) + e* = e** + e* + defn build-streams (s:Stmt) -> Stmt : match(s) : (s:DefWire) : val es = create-exps(WRef(name(s),type(s),WireKind(),BI-GENDER)) for e in es do : - declare(`wire,get-name(e),type(e)) - assign(e) + declare(`wire,lowered-name(e),type(e)) + assign(e,netlist[e]) (s:DefRegister) : val es = create-exps(WRef(name(s),type(s),RegKind(),BI-GENDER)) for e in es do : - declare(`reg,get-name(e),type(e)) - update-reset(e,clk(s),reset(s),init(s)) + declare(`reg,lowered-name(e),type(e)) + update-reset(e,clock(s),reset(s),init(s)) initialize(e) (s:DefPoison) : val es = create-exps(WRef(name(s),type(s),PoisonKind(),MALE)) for e in es do : - declare(`wire,get-name(e),type(e)) + declare(`wire,lowered-name(e),type(e)) initialize(e) (s:DefNode) : - declare(`wire,name(s),type(exp(s))) - netlist[name(s)] = exp(s) - assign(WRef(name(s),type(exp(s)),NodeKind(),MALE)) + declare(`wire,name(s),type(value(s))) + assign(WRef(name(s),type(value(s)),NodeKind(),MALE),value(s)) (s:Conditionally) : + match(conseq(s)) : + (c:Stop) : simulate(clk(c),pred(s),stop(ret(c))) + (c:Print) : simulate(clk(c),pred(s),printf(string(c),args(c))) (s:Stop) : simulate(clk(s),one,stop(ret(s))) (s:Print) : simulate(clk(s),one,printf(string(s),args(s))) (s:WDefInstance) : @@ -2636,47 +2706,46 @@ defn emit-verilog (m:InModule) -> Module : instantiate(name(s),module(s),es) (s:DefMemory) : ;TODO expand bundle in declaration, lots of thinking todo declare(`reg,name(s),VectorType(data-type(s),depth(s))) - val mem = WRef(name(s),type(s),MemKind(),BI-GENDER) + val mem = WRef(name(s),get-type(s),MemKind(append-all([readers(s) writers(s) readwriters(s)])),BI-GENDER) initialize-mem(mem,depth(s)) for r in readers(s) do : val port = HashTable<Symbol,Expression>(symbol-hash) - for f in fields(type(s) as BundleType) do : + for f in fields(get-type(s) as BundleType) do : port[name(f)] = WSubField(mem,name(f),type(f),UNKNOWN-GENDER) - val addr* = delay(port[`addr],read-latency) - val en* = delay(port[`en],read-latency) - val es = create-exps(port[`rdata]) - for e in es do : - netlist[e] = WSubAccess(mem,addr*,type(port[`rdata]),FEMALE) - update(e,port[`clk],en*) + val addr* = delay(port[`addr],read-latency(s)) + val en* = delay(port[`en],read-latency(s)) + val e = port[`rdata] + netlist[e] = WSubAccess(mem,addr*,type(port[`rdata]),FEMALE) + update(e,port[`clk],en*) for w in writers(s) do : val port = HashTable<Symbol,Expression>(symbol-hash) - for f in fields(type(s) as BundleType) do : - port[name(f)] = WSubField(mem,name(f),type(f),UNKNOWN) - val addr* = delay(port[`addr],write-latency - 1) - val en* = delay(port[`en],write-latency - 1) - val wmask* = delay(port[`wmask],write-latency - 1) - val es = create-exps(WSubAccess(port[`wdata],addr*,type(port[`wdata]),FEMALE)) - for (e in es,m in create-exps(wmask*)) do : - update(e,port[`clk],AND(en*,m)) + for f in fields(get-type(s) as BundleType) do : + port[name(f)] = WSubField(mem,name(f),type(f),UNKNOWN-GENDER) + val addr* = delay(port[`addr],write-latency(s) - 1) + val en* = delay(port[`en],write-latency(s) - 1) + val wmask* = delay(port[`wmask],write-latency(s) - 1) + val e = WSubAccess(port[`wdata],addr*,type(port[`wdata]),FEMALE) + update(e,port[`clk],AND(en*,wmask*)) for rw in readwriters(s) do : val port = HashTable<Symbol,Expression>(symbol-hash) - for f in fields(type(s) as BundleType) do : + for f in fields(get-type(s) as BundleType) do : port[name(f)] = WSubField(mem,name(f),type(f),UNKNOWN-GENDER) - val raddr* = delay(port[`raddr],read-latency) - val ren* = delay(port[`ren],read-latency) - val res = create-exps(port[`rdata]) - for e in res do : - netlist[e] = WSubAccess(mem,raddr*,type(port[`rdata]),FEMALE) - update(e,port[`clk],ren*) - val waddr* = delay(port[`waddr],write-latency - 1) - val wen* = delay(port[`wen],write-latency - 1) - val wmask* = delay(port[`wmask],write-latency - 1) - val wes = create-exps(WSubAccess(port[`wdata],waddr*,type(port[`wdata]),FEMALE)) - for (e in wes,m in create-exps(wmask*)) do : update(e,port[`clk],AND(wen*,m)) + val raddr* = delay(port[`raddr],read-latency(s)) + val ren* = delay(port[`ren],read-latency(s)) + val re = port[`rdata] + netlist[re] = WSubAccess(mem,raddr*,type(port[`rdata]),FEMALE) + update(re,port[`clk],ren*) + + val waddr* = delay(port[`waddr],write-latency(s) - 1) + val wen* = delay(port[`wen],write-latency(s) - 1) + val wmask* = delay(port[`wmask],write-latency(s) - 1) + val we = WSubAccess(port[`wdata],waddr*,type(port[`wdata]),FEMALE) + update(we,port[`clk],AND(wen*,wmask*)) (s:Begin) : map(build-streams,s) + s defn emit-streams () : if !empty?(declares) : @@ -2688,7 +2757,7 @@ defn emit-verilog (m:InModule) -> Module : emit([" integer initvar;"]) emit([" initial begin"]) emit([" #0.002;"]) - for x in initals do : + for x in initials do : emit([tab x]) emit([" end"]) emit(["`endif"]) @@ -2703,6 +2772,7 @@ defn emit-verilog (m:InModule) -> Module : build-netlist(body(m)) build-streams(body(m)) emit-streams() + m defn emit-verilog (with-output:(() -> False) -> False, c:Circuit) : with-output $ fn () : diff --git a/src/main/stanza/passes.stanza2 b/src/main/stanza/passes.stanza2 new file mode 100644 index 00000000..787b8429 --- /dev/null +++ b/src/main/stanza/passes.stanza2 @@ -0,0 +1,2662 @@ +defpackage firrtl/passes : + import core + import verse + import firrtl/ir2 + import firrtl/ir-utils + import firrtl/primops + import firrtl-main + import firrtl/errors + import bigint2 + +;============== Pass List ================ +public val standard-passes = to-list $ [ + CheckHighForm() + ;TempElimination() + ToWorkingIR() + Resolve() + ResolveKinds() + ;CheckKinds() + InferTypes() + ;CheckTypes() + ResolveGenders() + ;CheckGenders() + ;ExpandAccessors() + ;LowerToGround() + ;ExpandIndexedConnects() + ;InlineIndexed() + ExpandWhens() + InferWidths() + ;Inline() + SplitExp() + ;CheckLowForm() + ;ToRealIR() + ;Pad() + ] +;=============== WORKING IR ================================ +public definterface Kind +public defstruct WireKind <: Kind +public defstruct PoisonKind <: Kind +public defstruct RegKind <: Kind +public defstruct InstanceKind <: Kind +public defstruct PortKind <: Kind +public defstruct NodeKind <: Kind +public defstruct MemKind <: Kind : + ports : List<Symbol> +public defstruct ExpKind <: Kind + +public definterface Gender +public val MALE = new Gender +public val FEMALE = new Gender +public val UNKNOWN-GENDER = new Gender +public val BI-GENDER = new Gender + +public defstruct WRef <: Expression : + name: Symbol + type: Type with: (as-method => true) + kind: Kind with: (as-method => true) + gender: Gender with: (as-method => true) +public defstruct WSubField <: Expression : + exp: Expression + name: Symbol + type: Type with: (as-method => true) + gender: Gender with: (as-method => true) +public defstruct WSubIndex <: Expression : + exp: Expression + value: Int + type: Type with: (as-method => true) + gender: Gender with: (as-method => true) +public defstruct WSubAccess <: Expression : + exp: Expression + index: Expression + type: Type with: (as-method => true) + gender: Gender with: (as-method => true) +defstruct WIndexer <: Expression : + exps: List<Expression> + index: Expression + type: Type with: (as-method => true) + gender : Gender with: (as-method => true) +public defstruct WVoid <: Expression +public defstruct WDefInstance <: Stmt : + info: FileInfo with: (as-method => true) + name: Symbol + module: Symbol + type: Type + +defmulti gender (e:Expression) -> Gender +defmethod gender (e:Expression) : + MALE + +defn get-gender (s:Stmt|Port) -> Gender : + match(s) : + (s:DefWire|DefRegister) : BI-GENDER + (s:WDefInstance|DefNode|DefInstance|DefPoison) : MALE + (s:Begin|Connect|BulkConnect|Stop|Print|Empty) : UNKNOWN-GENDER + (s:DefMemory) : FEMALE + (p:Port) : + switch { _ == direction(p) } : + INPUT : MALE + OUTPUT : FEMALE + +public defmulti kind (e:Expression) -> Kind +defmethod kind (e:Expression) : + match(e) : + (e:WRef) : kind(e) + (e:WSubField) : kind(exp(e)) + (e:WSubIndex) : kind(exp(e)) + (e:WIndexer) : + val k = kind(exps(e)[0]) + for x in exps(e) do : + if k != kind(x) : error("All kinds of exps of WIndexer must be the same") + k + (e) : ExpKind() + +defmethod info (stmt:Begin) -> FileInfo : FileInfo() +defmethod info (stmt:Empty) -> FileInfo : FileInfo() + +defmethod type (exp:UIntValue) -> Type : UIntType(width(exp)) +defmethod type (exp:SIntValue) -> Type : SIntType(width(exp)) + +defn get-type (s:Stmt) -> Type : + match(s) : + (s:DefWire|DefPoison|DefRegister|WDefInstance) : type(s) + (s:DefNode) : type(value(s)) + (s:DefMemory) : + val depth = depth(s) + ; Fields + val addr = Field(`addr,DEFAULT,UIntType(IntWidth(ceil-log2(depth)))) + val en = Field(`en,DEFAULT,BoolType()) + val clk = Field(`clk,DEFAULT,ClockType()) + val def-data = Field(`data,DEFAULT,data-type(s)) + val rev-data = Field(`data,REVERSE,data-type(s)) + val rdata = Field(`rdata,REVERSE,data-type(s)) + val wdata = Field(`wdata,DEFAULT,data-type(s)) + val mask = create-mask(`mask,data-type(s)) + val wmask = create-mask(`wmask,data-type(s)) + val ren = Field(`ren,DEFAULT,UIntType(IntWidth(1))) + val wen = Field(`wen,DEFAULT,UIntType(IntWidth(1))) + val raddr = Field(`raddr,DEFAULT,UIntType(IntWidth(ceil-log2(depth)))) + val waddr = Field(`waddr,DEFAULT,UIntType(IntWidth(ceil-log2(depth)))) + + val read-type = BundleType(to-list([rev-data,addr,en,clk])) + val write-type = BundleType(to-list([def-data,mask,addr,en,clk])) + val readwrite-type = BundleType(to-list([wdata,wmask,waddr,wen,rdata,raddr,ren,clk])) + + val mem-fields = Vector<Field>() + for x in readers(s) do : + add(mem-fields,Field(x,DEFAULT,read-type)) + for x in writers(s) do : + add(mem-fields,Field(x,DEFAULT,write-type)) + for x in readwriters(s) do : + add(mem-fields,Field(x,DEFAULT,readwrite-type)) + BundleType(to-list(mem-fields)) + (s:DefInstance) : UnknownType() + (s:Begin|Connect|BulkConnect|Stop|Print|Empty) : UnknownType() + +defmethod equal? (e1:Expression,e2:Expression) -> True|False : + match(e1,e2) : + (e1:UIntValue,e2:UIntValue) : + if value(e1) == value(e2) : width(e1) == width(e2) + else : false + (e1:SIntValue,e2:SIntValue) : + if value(e1) == value(e2) : width(e1) == width(e2) + else : false + (e1:WRef,e2:WRef) : name(e1) == name(e2) + (e1:WSubField,e2:WSubField) : + (name(e1) == name(e2)) and (exp(e1) == exp(e2)) + (e1:WSubIndex,e2:WSubIndex) : + (value(e1) == value(e2)) and (exp(e1) == exp(e2)) + (e1:WSubAccess,e2:WSubAccess) : + (index(e1) == index(e2)) and (exp(e1) == exp(e2)) + (e1:WVoid,e2:WVoid) : true + (e1:WIndexer,e2:WIndexer) : + var bool = (length(exps(e1)) == length(exps(e2))) + for (e1* in exps(e1),e2* in exps(e2)) do : + bool = bool and (e1* == e2*) + bool and (index(e1) == index(e2)) + (e1:DoPrim,e2:DoPrim) : + var are-equal? = op(e1) == op(e2) + for (x in args(e1),y in args(e2)) do : + if not x == y : + are-equal? = false + for (x in consts(e1),y in consts(e2)) do : + if not x == y : + are-equal? = false + are-equal? + (e1,e2) : false + +; ================= PRINTERS =================== +defmethod print (o:OutputStream, g:Gender) : + print{o, _} $ + switch {g == _} : + MALE : "m" + FEMALE: "f" + BI-GENDER : "b" + UNKNOWN-GENDER: "u" + +;============== DEBUG STUFF ============================= +public var PRINT-TYPES : True|False = false +public var PRINT-KINDS : True|False = false +public var PRINT-WIDTHS : True|False = false +public var PRINT-TWIDTHS : True|False = false +public var PRINT-GENDERS : True|False = false +public var PRINT-CIRCUITS : True|False = false +public var PRINT-DEBUG : True|False = false +public var PRINT-INFO : True|False = false + +;========= TO TURN OFF =========== + +var old-PRINT-TYPES : True|False = false +var old-PRINT-KINDS : True|False = false +var old-PRINT-WIDTHS : True|False = false +var old-PRINT-TWIDTHS : True|False = false +var old-PRINT-GENDERS : True|False = false +var old-PRINT-CIRCUITS : True|False = false +var old-PRINT-DEBUG : True|False = false +var old-PRINT-INFO : True|False = false +defmethod turn-off-debug (x:False) : + old-PRINT-TYPES = PRINT-TYPES + old-PRINT-KINDS = PRINT-KINDS + old-PRINT-WIDTHS = PRINT-WIDTHS + old-PRINT-TWIDTHS = PRINT-TWIDTHS + old-PRINT-GENDERS = PRINT-GENDERS + old-PRINT-CIRCUITS = PRINT-CIRCUITS + old-PRINT-DEBUG = PRINT-DEBUG + old-PRINT-INFO = PRINT-INFO + PRINT-TYPES = false + PRINT-KINDS = false + PRINT-WIDTHS = false + PRINT-TWIDTHS = false + PRINT-GENDERS = false + PRINT-CIRCUITS = false + PRINT-DEBUG = false + PRINT-INFO = false + +defmethod turn-on-debug (x:False) : + PRINT-TYPES = old-PRINT-TYPES + PRINT-KINDS = old-PRINT-KINDS + PRINT-WIDTHS = old-PRINT-WIDTHS + PRINT-TWIDTHS = old-PRINT-TWIDTHS + PRINT-GENDERS = old-PRINT-GENDERS + PRINT-CIRCUITS = old-PRINT-CIRCUITS + PRINT-DEBUG = old-PRINT-DEBUG + PRINT-INFO = old-PRINT-INFO + +;=== ThePrinters === + +public defn println-all-debug (l:?) -> False : + if PRINT-DEBUG : println-all(l) + else : false + +public defn println-debug (s:?) -> False : + if PRINT-DEBUG : println(s) + else : false + +defmethod print (o:OutputStream, k:Kind) : + print{o, _} $ + match(k) : + (k:WireKind) : "wire" + (k:PoisonKind) : "poison" + (k:RegKind) : "reg" + (k:PortKind) : "port" + (k:MemKind) : "mem" + (k:NodeKind) : "node" + (k:InstanceKind) : "inst" + (k:ExpKind) : "exp" + +defn hasGender (e:?) : + e typeof Expression + +defn hasWidth (e:?) : + e typeof UIntType|SIntType|UIntValue|SIntValue + +defn hasType (e:?) : + e typeof Expression|DefWire|DefRegister|DefPoison + |VectorType|Port|UIntValue|SIntValue + +defn hasKind (e:?) : + e typeof Expression + +defn hasInfo (e:?) : + e typeof Stmt|Port|Circuit|Module + +defn any-debug? (e:?) : + (hasGender(e) and PRINT-GENDERS) or + (hasType(e) and PRINT-TYPES) or + (hasWidth(e) and PRINT-WIDTHS) or + (hasKind(e) and PRINT-KINDS) or + (hasInfo(e) and PRINT-INFO) + +defmethod print-debug (o:OutputStream, e:Expression|Stmt|Type|Port|Field|Module|Circuit) : + defn wipe-width (t:Type) -> Type : + match(t) : + (t:UIntType) : UIntType(UnknownWidth()) + (t:SIntType) : SIntType(UnknownWidth()) + (t) : map(wipe-width,t) + + if any-debug?(e) : print(o,"@") + if PRINT-KINDS and hasKind(e) : print-all(o,["<k:" kind(e as ?) ">"]) + if PRINT-TYPES and hasType(e) : print-all(o,["<t:" wipe-width(type(e as ?)) ">"]) + if PRINT-TWIDTHS and hasType(e): print-all(o,["<t:" type(e as ?) ">"]) + if PRINT-WIDTHS and hasWidth(e): print-all(o,["<w:" width(e as ?) ">"]) + if PRINT-GENDERS and hasGender(e): print-all(o,["<g:" gender(e as ?) ">"]) + if PRINT-INFO and hasInfo(e): print-all(o,["<i:" info(e as ?) ">"]) + +defmethod print (o:OutputStream, e:WRef) : + print(o,name(e)) + print-debug(o,e as ?) +defmethod print (o:OutputStream, e:WSubField) : + print-all(o,[exp(e) "." name(e)]) + print-debug(o,e as ?) +defmethod print (o:OutputStream, e:WSubIndex) : + print-all(o,[exp(e) "[" value(e) "]"]) + print-debug(o,e as ?) +defmethod print (o:OutputStream, e:WSubAccess) : + print-all(o,[exp(e) "[" index(e) "]"]) + print-debug(o,e as ?) +defmethod print (o:OutputStream, e:WVoid) : + print(o,"VOID") + print-debug(o,e as ?) +defmethod print (o:OutputStream, c:WIndexer) : + print-all(o, [exps(c) "[" index(c) "]"]) + print-debug(o,c as ?) +defmethod print (o:OutputStream, c:WDefInstance) : + print-all(o, ["inst " name(c) " of " module(c) " : " type(c)]) + print-debug(o,c as ?) + + +defmethod map (f: Expression -> Expression, e: WSubField) : + WSubField(f(exp(e)), name(e), type(e), gender(e)) +defmethod map (f: Expression -> Expression, e: WSubIndex) : + WSubIndex(f(exp(e)), value(e), type(e), gender(e)) +defmethod map (f: Expression -> Expression, e: WSubAccess) : + WSubAccess(f(exp(e)), f(index(e)), type(e), gender(e)) + +defmethod map (f: Type -> Type, e: WRef) : + WRef(name(e), f(type(e)), kind(e), gender(e)) +defmethod map (f: Type -> Type, e: WSubField) : + WSubField(exp(e), name(e), f(type(e)), gender(e)) +defmethod map (f: Type -> Type, e: WSubIndex) : + WSubIndex(exp(e), value(e), f(type(e)), gender(e)) +defmethod map (f: Type -> Type, e: WSubAccess) : + WSubAccess(exp(e), index(e), f(type(e)), gender(e)) + +defmethod map (f: Type -> Type, s: WDefInstance) : + WDefInstance(info(s),name(s),module(s),f(type(s))) + +;================ WIDTH LIBRARY ==================== + +public val ONE = IntWidth(1) +public defstruct VarWidth <: Width : + name: Symbol +public defstruct PlusWidth <: Width : + arg1 : Width + arg2 : Width +public defstruct MinusWidth <: Width : + arg1 : Width + arg2 : Width +public defstruct MaxWidth <: Width : + args : List<Width> +public defstruct ExpWidth <: Width : + arg1 : Width +val width-name-hash = HashTable<Symbol,Int>(symbol-hash) + +public defmulti map<?T> (f: Width -> Width, w:?T&Width) -> T +defmethod map (f: Width -> Width, w:Width) -> Width : + match(w) : + (w:MaxWidth) : MaxWidth(map(f,args(w))) + (w:PlusWidth) : PlusWidth(f(arg1(w)),f(arg2(w))) + (w:MinusWidth) : MinusWidth(f(arg1(w)),f(arg2(w))) + (w:ExpWidth) : ExpWidth(f(arg1(w))) + (w) : w + +public defmethod print (o:OutputStream, w:VarWidth) : + print(o,name(w)) +public defmethod print (o:OutputStream, w:MaxWidth) : + print-all(o,["max" args(w)]) +public defmethod print (o:OutputStream, w:PlusWidth) : + print-all(o,[ "(" arg1(w) " + " arg2(w) ")"]) +public defmethod print (o:OutputStream, w:MinusWidth) : + print-all(o,[ "(" arg1(w) " - " arg2(w) ")"]) +public defmethod print (o:OutputStream, w:ExpWidth) : + print-all(o,[ "exp(" arg1(w) ")"]) + +defn remove-unknowns-w (w:Width) -> Width : + match(w) : + (w:UnknownWidth) : VarWidth(firrtl-gensym(`w,width-name-hash)) + (w) : w +defn remove-unknowns (t:Type) -> Type : mapr(remove-unknowns-w,t) + +defmethod equal? (w1:Width,w2:Width) -> True|False : + match(w1,w2) : + (w1:VarWidth,w2:VarWidth) : name(w1) == name(w2) + (w1:MaxWidth,w2:MaxWidth) : + label<True|False> ret : + if not length(args(w1)) == length(args(w2)) : ret(false) + else : + for w in args(w1) do : + if not contains?(args(w2),w) : ret(false) + ret(true) + (w1:IntWidth,w2:IntWidth) : width(w1) == width(w2) + (w1:PlusWidth,w2:PlusWidth) : + (arg1(w1) == arg1(w2) and arg2(w1) == arg2(w2)) or (arg1(w1) == arg2(w2) and arg2(w1) == arg1(w2)) + (w1:MinusWidth,w2:MinusWidth) : + (arg1(w1) == arg1(w2) and arg2(w1) == arg2(w2)) or (arg1(w1) == arg2(w2) and arg2(w1) == arg1(w2)) + (w1:ExpWidth,w2:ExpWidth) : arg1(w1) == arg1(w2) + (w1:UnknownWidth,w2:UnknownWidth) : true + (w1,w2) : false +;================ WORKING IR UTILS ========================= +;defn plus (g1:Gender,g2:Gender) -> Gender : +; switch fn ([x,y]) : g1 == x and g2 == y : +; [FEMALE,MALE] : UNKNOWN-GENDER +; [MALE,FEMALE] : UNKNOWN-GENDER +; [MALE,MALE] : MALE +; [FEMALE,FEMALE] : FEMALE +; [BI-GENDER,MALE] : MALE +; [BI-GENDER,FEMALE] : FEMALE +; [MALE,BI-GENDER] : MALE +; [FEMALE,BI-GENDER] : FEMALE + +; These functions do not error, but return Unknown Type +defn module-type (m:Module) -> Type : + BundleType(for p in ports(m) map : to-field(p)) +defn field-type (v:Type,s:Symbol) -> Type : + match(v) : + (v:BundleType) : + val ft = for p in fields(v) find : name(p) == s + if ft != false : type(ft as Field) + else : UnknownType() + (v) : UnknownType() +defn sub-type (v:Type) -> Type : + match(v) : + (v:VectorType) : type(v) + (v) : UnknownType() +defn field-flip (v:Type,s:Symbol) -> Flip : + match(v) : + (v:BundleType) : + val ft = for p in fields(v) find : name(p) == s + if ft != false : flip(ft as Field) + else : DEFAULT ;This will get caught later + (v) : DEFAULT + +defn swap (g:Gender) -> Gender : + switch {_ == g} : + UNKNOWN-GENDER : UNKNOWN-GENDER + MALE : FEMALE + FEMALE : MALE + BI-GENDER : BI-GENDER +defn swap (f:Flip) -> Flip : + switch {_ == f} : + DEFAULT : REVERSE + REVERSE : DEFAULT +defn swap (d:Direction) -> Direction : + switch {_ == d} : + OUTPUT : INPUT + INPUT : OUTPUT + +public defn times (flip:Flip,d:Direction) -> Direction : + flip * d +public defn times (d:Direction,flip:Flip) -> Direction : + switch {_ == flip} : + DEFAULT : d + REVERSE : swap(d) +public defn times (g:Gender,flip:Flip) -> Gender : flip * g +public defn times (flip:Flip,g:Gender) -> Gender : + switch {_ == flip} : + DEFAULT : g + REVERSE : swap(g) +public defn times (f1:Flip,f2:Flip) -> Flip : + switch {_ == f2} : + DEFAULT : f1 + REVERSE : swap(f1) + +defn to-field (p:Port) -> Field : + if direction(p) == OUTPUT : Field(name(p),DEFAULT,type(p)) + else if direction(p) == INPUT : Field(name(p),REVERSE,type(p)) + else : error("Shouldn't be here") +defn to-dir (g:Gender) -> Direction : + switch {_ == g} : + MALE : INPUT + FEMALE : OUTPUT +defn to-gender (d:Direction) -> Gender : + switch {_ == d} : + INPUT: MALE + OUTPUT: FEMALE + +;================= Remove Special Characters ======================== +; Returns a new Circuit where all names have all special characters +; removed, except _. +; +;public defstruct RemoveSpecialChars <: Pass +;public defmethod pass (b:RemoveSpecialChars) -> (Circuit -> Circuit) : remove-special-chars +;public defmethod name (b:RemoveSpecialChars) -> String : "Remove Special Characters" +;public defmethod short-name (b:RemoveSpecialChars) -> String : "rem-spec-chars" +; +;;------------ Helper Functions ------------- +; +;defn get-new-string (n:Char) -> String : +; switch {n == _} : +; '_' : "__" +; '~' : "$A" +; '!' : "$B" +; '@' : "$C" +; '#' : "$D" +; '$' : "$E" +; '%' : "$F" +; '^' : "$G" +; '*' : "$H" +; '-' : "$I" +; '+' : "$J" +; '=' : "$K" +; '?' : "$L" +; '/' : "$M" +; else : to-string(n) +; +;;------------ Pass ------------------ +; +;defn remove-special-chars (c:Circuit) : +; defn rename (n:Symbol) -> Symbol : +; val v = Vector<String>() +; for c in to-string(n) do : +; add(v,get-new-string(c)) +; val n* = symbol-join(v) +; if key?(v-keywords,n*) : +; symbol-join([n* `_]) +; else : +; n* +; defn rename-t (t:Type) -> Type : +; match(t) : +; (t:BundleType) : BundleType $ +; for f in fields(t) map : +; Field(rename(name(f)),flip(f),rename-t(type(f))) +; (t:VectorType) : VectorType(rename-t(type(t)),size(t)) +; (t) : t +; defn rename-e (e:Expression) -> Expression : +; match(e) : +; (e:Ref) : Ref(rename(name(e)),rename-t(type(e))) +; (e:Subfield) : Subfield(rename-e(exp(e)),rename(name(e)),rename-t(type(e))) +; (e:Index) : Index(rename-e(exp(e)),value(e),rename-t(type(e))) +; (e:DoPrim) : DoPrim{op(e),_,consts(e),rename-t(type(e))} $ for x in args(e) map : rename-e(x) +; (e:UIntValue) : e +; (e:SIntValue) : e +; defn rename-s (s:Stmt) -> Stmt : +; match(s) : +; (s:DefWire) : DefWire(info(s),rename(name(s)),rename-t(type(s))) +; (s:DefPoison) : DefPoison(info(s),rename(name(s)),rename-t(type(s))) +; (s:DefRegister) : DefRegister(info(s),rename(name(s)),rename-t(type(s)),rename-e(clock(s)),rename-e(reset(s))) +; (s:WDefInstance) : WDefInstance(info(s),rename(name(s)),rename-e(module(s))) +; (s:DefMemory) : DefMemory(info(s),rename(name(s)),rename-t(type(s)),seq?(s),rename-e(clock(s)),size(s)) +; (s:DefNode) : DefNode(info(s),rename(name(s)),rename-e(value(s))) +; (s:DefAccessor) : DefAccessor(info(s),rename(name(s)),rename-e(source(s)),rename-e(index(s)),acc-dir(s)) +; (s:Conditionally) : Conditionally(info(s),rename-e(pred(s)),rename-s(conseq(s)),rename-s(alt(s))) +; (s:Begin) : Begin $ for b in body(s) map : rename-s(b) +; (s:OnReset) : OnReset(info(s),rename-e(loc(s)),rename-e(exp(s))) +; (s:BulkConnect) : BulkConnect(info(s),rename-e(loc(s)),rename-e(exp(s))) +; (s:Connect) : Connect(info(s),rename-e(loc(s)),rename-e(exp(s))) +; (s:EmptyStmt) : s +; (s:StopStmt) : s +; (s:PrintfStmt) : PrintfStmt(info(s),string(s),map(rename-e,args(s))) +; +; Circuit(info(c),modules*, rename(main(c))) where : +; val modules* = +; for m in modules(c) map : +; match(m) : +; (m:InModule) : +; val ports* = for p in ports(m) map : +; Port(info(p),rename(name(p)),direction(p),rename-t(type(p))) +; InModule(info(m),rename(name(m)), ports*, rename-s(body(m))) +; (m:ExModule) : m + + +;================= 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) : +; defn is-temp? (n:Symbol) -> True|False : +; to-string(n)[0] == 'T' +; defn temp-elim (m:InModule) : +; val h = HashTable<Symbol,Expression>(symbol-hash) +; defn temp-elim-e (e:Expression) : +; match(map(temp-elim-e,e)) : +; (e:Ref) : +; if key?(h,name(e)) : h[name(e)] +; else : e +; (e) : e +; defn temp-elim-s (s:Stmt) : +; match(map(temp-elim-e,s)) : +; (s:DefNode) : +; if is-temp?(name(s)) : +; h[name(s)] = value(s) +; EmptyStmt() +; else : s +; (s) : map(temp-elim-s,s) +; InModule(info(m),name(m), ports(m), temp-elim-s(body(m))) +; +; Circuit(info(c),modules*, main(c)) where : +; val modules* = +; for m in modules(c) map : +; match(m) : +; (m:InModule) : temp-elim(m) +; (m:ExModule) : m + +;================= Bring to Working IR ======================== +; 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) -> Expression : + match(map(to-exp,e)) : + (e:Ref) : WRef(name(e), type(e), NodeKind(), UNKNOWN-GENDER) + (e:SubField) : WSubField(exp(e), name(e), type(e), UNKNOWN-GENDER) + (e:SubIndex) : WSubIndex(exp(e), value(e), type(e), UNKNOWN-GENDER) + (e:SubAccess) : WSubAccess(exp(e), index(e), type(e), UNKNOWN-GENDER) + (e) : e + defn to-stmt (s:Stmt) -> Stmt : + match(map(to-exp,s)) : + (s:DefInstance) : WDefInstance(info(s),name(s),module(s),UnknownType()) + (s) : map(to-stmt,s) + + Circuit(info(c),modules*, main(c)) where : + val modules* = + for m in modules(c) map : + match(m) : + (m:InModule) : InModule(info(m),name(m), ports(m), to-stmt(body(m))) + (m:ExModule) : m + +;=============== Resolve Kinds ============================= +; It is useful for the compiler to know information about +; 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>) : + defn resolve-stmt (s:Stmt) -> Stmt : + map{resolve-expr,_} $ + map(resolve-stmt,s) + + defn resolve-expr (e:Expression) -> Expression : + match(e) : + (e:WRef) : WRef(name(e),type(e),kinds[name(e)],gender(e)) + (e) : map(resolve-expr,e) + + resolve-stmt(body) + + defn find (m:Module, kinds:HashTable<Symbol,Kind>) : + defn find-stmt (s:Stmt) -> Stmt : + match(s) : + (s:DefWire) : kinds[name(s)] = WireKind() + (s:DefPoison) : kinds[name(s)] = PoisonKind() + (s:DefNode) : kinds[name(s)] = NodeKind() + (s:DefRegister) : kinds[name(s)] = RegKind() + (s:WDefInstance) : kinds[name(s)] = InstanceKind() + (s:DefMemory) : kinds[name(s)] = MemKind(append-all([readers(s) writers(s) readwriters(s)])) + (s) : false + map(find-stmt,s) + + for p in ports(m) do : + kinds[name(p)] = PortKind() + match(m) : + (m:InModule) : find-stmt(body(m)) + (m:ExModule) : false + + defn resolve-kinds (m:Module, c:Circuit) -> Module : + val kinds = HashTable<Symbol,Kind>(symbol-hash) + find(m,kinds) + match(m) : + (m:InModule) : + val body! = resolve(body(m),kinds) + InModule(info(m),name(m),ports(m),body!) + (m:ExModule) : ExModule(info(m),name(m),ports(m)) + + Circuit(info(c),modules*, main(c)) where : + val modules* = + for m in modules(c) map : + resolve-kinds(m,c) + +;============== INFER TYPES ================================ + +; ------------------ Utils ------------------------- + +defn set-type (s:Stmt,t:Type) -> Stmt : + match(s) : + (s:DefWire) : DefWire(info(s),name(s),t) + (s:DefRegister) : DefRegister(info(s),name(s),t,clock(s),reset(s),init(s)) + (s:DefMemory) : DefMemory(info(s),name(s),t,depth(s),write-latency(s),read-latency(s),readers(s),writers(s),readwriters(s)) + (s:DefNode) : s + (s:DefPoison) : DefPoison(info(s),name(s),t) + + +; ------------------ 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 infer-types (c:Circuit) -> Circuit : + val module-types = HashTable<Symbol,Type>(symbol-hash) + defn infer-types (m:Module) -> Module : + val types = HashTable<Symbol,Type>(symbol-hash) + defn infer-types-e (e:Expression) -> Expression : + match(map(infer-types-e,e)) : + (e:WRef) : WRef(name(e), types[name(e)],kind(e),gender(e)) + (e:WSubField) : WSubField(exp(e),name(e),field-type(type(exp(e)),name(e)),gender(e)) + (e:WSubIndex) : WSubIndex(exp(e),value(e),sub-type(type(exp(e))),gender(e)) + (e:WSubAccess) : WSubAccess(exp(e),index(e),sub-type(type(exp(e))),gender(e)) + (e:DoPrim) : set-primop-type(e) + (e:UIntValue|SIntValue) : e + defn infer-types-s (s:Stmt) -> Stmt : + match(s) : + (s:DefRegister) : + val t = remove-unknowns(get-type(s)) + types[name(s)] = t + map(infer-types-e,set-type(s,t)) + (s:DefWire|DefPoison|DefNode) : + val s* = map(infer-types-e,s) + val t = remove-unknowns(get-type(s*)) + types[name(s*)] = t + set-type(s*,t) + (s:DefMemory) : + val t = remove-unknowns(get-type(s)) + types[name(s)] = t + val dt = remove-unknowns(data-type(s)) + set-type(s,dt) + (s:WDefInstance) : + types[name(s)] = module-types[module(s)] + WDefInstance(info(s),name(s),module(s),module-types[module(s)]) + (s) : map{infer-types-e,_} $ map(infer-types-s,s) + for p in ports(m) do : + types[name(p)] = type(p) + match(m) : + (m:InModule) : + InModule(info(m),name(m),ports(m),infer-types-s(body(m))) + (m:ExModule) : m + + ; MAIN + val modules* = + for m in modules(c) map : + val ports* = + for p in ports(m) map : + Port(info(p),name(p),direction(p),remove-unknowns(type(p))) + match(m) : + (m:InModule) : InModule(info(m),name(m),ports*,body(m)) + (m:ExModule) : ExModule(info(m),name(m),ports*) + + for m in modules* do : + module-types[name(m)] = module-type(m) + Circuit{info(c), _, main(c) } $ + for m in modules* map : + infer-types(m) + +;============= RESOLVE GENDER ============================ +; To ensure a proper circuit, we must ensure that assignments +; only work on expressions that can be assigned to. Similarly, +; we must ensure that only expressions that can be read from +; are used to assign from. This invariant requires each +; expression's gender to be inferred. +; Various elements can be bi-gender (e.g. wires) and can +; thus be treated as either female or male. Conversely, some +; elements are single-gender (e.g. accessors, ports). +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" + +defn resolve-genders (c:Circuit) : + defn resolve-e (e:Expression,g:Gender) -> Expression : + match(e) : + (e:WRef) : WRef(name(e),type(e),kind(e),g) + (e:WSubField) : + val exp* = + switch { _ == field-flip(type(exp(e)),name(e)) } : + DEFAULT : resolve-e(exp(e),g) + REVERSE : resolve-e(exp(e),swap(g)) + WSubField(exp*,name(e),type(e),g) + (e:WSubIndex) : + val exp* = resolve-e(exp(e),g) + WSubIndex(exp*,value(e),type(e),g) + (e:WSubAccess) : + val exp* = resolve-e(exp(e),g) + val index* = resolve-e(index(e),MALE) + WSubAccess(exp*,index*,type(e),g) + (e:WIndexer) : + val exps* = map(resolve-e{_,g},exps(e)) + val index* = resolve-e(index(e),MALE) + WIndexer(exps*,index*,type(e),g) + (e) : map(resolve-e{_,g},e) + + defn resolve-s (s:Stmt) -> Stmt : + match(s) : + (s:Connect) : + val loc* = resolve-e(loc(s),FEMALE) + val exp* = resolve-e(exp(s),MALE) + Connect(info(s),loc*,exp*) + (s:BulkConnect) : + val loc* = resolve-e(loc(s),FEMALE) + val exp* = resolve-e(exp(s),MALE) + BulkConnect(info(s),loc*,exp*) + (s) : + map{resolve-s,_} $ map(resolve-e{_,MALE},s) + Circuit(info(c),modules*, main(c)) where : + val modules* = + for m in modules(c) map : + match(m) : + (m:InModule) : + val body* = resolve-s(body(m)) + InModule(info(m),name(m),ports(m),body*) + (m:ExModule) : m + +;;============== EXPAND ACCESSORS ================================ +; This pass expands non-memory accessors into DecFromIndexer or +; ConnectFromIndexed. All elements of the vector are +; explicitly written out, then indexed. Depending on the gender +; of the accessor, it is transformed into DecFromIndexer (male) or +; DecToIndexer (female) + +;public defstruct ExpandAccesses <: Pass +;public defmethod pass (b:ExpandAccesses) -> (Circuit -> Circuit) : expand-accesses +;public defmethod name (b:ExpandAccesses) -> String : "Expand Accesses" +;public defmethod short-name (b:ExpandAccesses) -> String : "expand-accesses" +; + +defn expand-vector (e:Expression,g:Gender) -> List<Expression> : + val t = type(e) as VectorType + for i in 0 to size(t) map-append : + list(WSubIndex(e,i,type(t),g)) ;always be WRef|WSubField|WSubIndex + + + +;================ EXPAND CONNECTS ================== +public defstruct ExpandConnects <: Pass +public defmethod pass (b:ExpandConnects) -> (Circuit -> Circuit) : expand-connects +public defmethod name (b:ExpandConnects) -> String : "Expand Connects" +public defmethod short-name (b:ExpandConnects) -> String : "expand-connects" + +;---------------- UTILS ------------------ +defn get-size (e:Expression) -> Int : get-size(type(e)) +defn get-size (t:Type) -> Int : + match(t) : + (t:BundleType) : + var sum = 0 + for f in fields(t) do : + sum = sum + get-size(type(f)) + sum + (t:VectorType) : size(t) * get-size(type(t)) + (t) : 1 +defn get-flip (t:Type, i:Int, f:Flip) -> Flip : + if i >= get-size(t) : error("Shouldn't be here") + match(t) : + (t:UIntType|SIntType|ClockType) : f + (t:BundleType) : label<Flip> ret : + var n = i + for x in fields(t) do : + if n < get-size(type(x)) : + ret(get-flip(type(x),n,flip(x) * f)) + else : + n = n - get-size(type(x)) + error("Shouldn't be here") + (t:VectorType) : label<Flip> ret : + var n = i + for j in 0 to size(t) do : + if n < get-size(type(t)) : + ret(get-flip(type(t),n,f)) + else : + n = n - get-size(type(t)) + error("Shouldn't be here") +defn get-point (e:Expression) -> Int : + match(e) : + (e:WRef) : 0 + (e:WSubField) : + var i = 0 + for f in fields(type(exp(e)) as BundleType) find : + val b = name(f) == name(e) + if not b : i = i + get-size(type(f)) + b + i + (e:WSubIndex) : + value(e) * get-size(e) + (e:WSubAccess) : + get-point(exp(e)) +defn get-valid-points (t1:Type,t2:Type,flip1:Flip,flip2:Flip) -> List<[Int,Int]> : + ;println-all(["Inside with t1:" t1 ",t2:" t2 ",f1:" flip1 ",f2:" flip2]) + match(t1,t2) : + (t1:UIntType,t2:UIntType) : + if flip1 == flip2 : list([0, 0]) + else: list() + (t1:SIntType,t2:SIntType) : + if flip1 == flip2 : list([0, 0]) + else: list() + (t1:BundleType,t2:BundleType) : + val points = Vector<[Int,Int]>() + var ilen = 0 + var jlen = 0 + for i in 0 to length(fields(t1)) do : + for j in 0 to length(fields(t2)) do : + ;println(i) + ;println(j) + ;println(ilen) + ;println(jlen) + val f1 = fields(t1)[i] + val f2 = fields(t2)[j] + if name(f1) == name(f2) : + val ls = get-valid-points(type(f1),type(f2),flip1 * flip(f1), + flip2 * flip(f2)) + for x in ls do : + add(points,[x[0] + ilen, x[1] + jlen]) + println(points) + jlen = jlen + get-size(type(fields(t2)[j])) + ilen = ilen + get-size(type(fields(t1)[i])) + jlen = 0 + to-list(points) + (t1:VectorType,t2:VectorType) : + val points = Vector<[Int,Int]>() + var ilen = 0 + var jlen = 0 + for i in 0 to min(size(t1),size(t2)) do : + val ls = get-valid-points(type(t1),type(t2),flip1,flip2) + for x in ls do : + add(points,[x[0] + ilen, x[1] + jlen]) + ilen = ilen + get-size(type(t1)) + jlen = jlen + get-size(type(t2)) + to-list(points) + + +defn create-exps (n:Symbol, t:Type) -> List<Expression> : + create-exps(WRef(n,t,ExpKind(),UNKNOWN-GENDER)) +defn create-exps (e:Expression) -> List<Expression> : + match(type(e)) : + (t:UIntType|SIntType|ClockType) : list(e) + (t:BundleType) : + for f in fields(t) map-append : + create-exps(WSubField(e,name(f),type(f),gender(e) * flip(f))) + (t:VectorType) : + for i in 0 to size(t) map-append : + create-exps(WSubIndex(e,i,type(t),gender(e))) + +val hashed-create-exps = HashTable<Expression,List<Expression>>(exp-hash) +defn fast-create-exps (n:Symbol, t:Type) -> List<Expression> : + fast-create-exps(WRef(n,t,ExpKind(),UNKNOWN-GENDER)) +defn fast-create-exps (e:Expression) -> List<Expression> : + if key?(hashed-create-exps,e) : hashed-create-exps[e] + else : + val es = Vector<Expression>() + defn create-exps (e:Expression) -> False : + match(type(e)) : + (t:UIntType|SIntType|ClockType) : add(es,e) + (t:BundleType) : + for f in fields(t) do : + create-exps(WSubField(e,name(f),type(f),gender(e) * flip(f))) + (t:VectorType) : + for i in 0 to size(t) do : + create-exps(WSubIndex(e,i,type(t),gender(e))) + create-exps(e) + val x = to-list(es) + hashed-create-exps[e] = x + x + +;---------------- Pass --------------------- + +defn expand-connects (c:Circuit) -> Circuit : + defn expand-connects (m:InModule) -> InModule : + defn expand-s (s:Stmt) -> Stmt : + match(s) : + (s:Connect) : + val n = get-size(loc(s)) + val connects = Vector<Stmt>() + val locs = fast-create-exps(loc(s)) + val exps = fast-create-exps(exp(s)) + for i in 0 to n do : + val loc* = locs[i] + val exp* = exps[i] + add{connects,_} $ + switch { _ == get-flip(type(loc(s)),i,DEFAULT) } : + DEFAULT : Connect(info(s),loc*,exp*) + REVERSE : Connect(info(s),exp*,loc*) + Begin(to-list(connects)) + (s:BulkConnect) : + val ls = get-valid-points(type(loc(s)),type(exp(s)),DEFAULT,DEFAULT) + val connects = Vector<Stmt>() + val locs = fast-create-exps(loc(s)) + val exps = fast-create-exps(exp(s)) + for x in ls do : + val loc* = locs[x[0]] + val exp* = exps[x[1]] + add{connects,_} $ + switch { _ == get-flip(type(loc(s)),x[0],DEFAULT) } : + DEFAULT : Connect(info(s),loc*,exp*) + REVERSE : Connect(info(s),exp*,loc*) + Begin(to-list(connects)) + (s) : map(expand-s,s) + + InModule(info(m),name(m),ports(m),expand-s(body(m))) + + Circuit(info(c),modules*, main(c)) where : + val modules* = + for m in modules(c) map : + match(m) : + (m:ExModule) : m + (m:InModule) : expand-connects(m) + + +;;;================ REPLACE INDEXERS ========================= +; This pass inlines all accessors to non-memory vector typed +; components. + +public defstruct RemoveAccesses <: Pass +public defmethod pass (b:RemoveAccesses) -> (Circuit -> Circuit) : remove-access +public defmethod name (b:RemoveAccesses) -> String : "Remove Accesses" +public defmethod short-name (b:RemoveAccesses) -> String : "remove-access" + +defstruct Location : + base : Expression + guard : Expression +defmethod print (o:OutputStream,x:Location) : + print-all(o,["[" base(x) " , " guard(x) "]"]) + + +val hashed-locations = HashTable<Expression,List<Location>>(exp-hash) +defn get-locations (e:Expression) -> List<Location> : + if key?(hashed-locations,e) : hashed-locations[e] + else : + val x = match(e) : + (e:WRef) : map(Location{_,one},fast-create-exps(e)) + (e:WSubIndex|WSubField) : + val ls = get-locations(exp(e)) + val start = get-point(e) + val end = start + get-size(e) + val stride = get-size(exp(e)) + val ls* = Vector<Location>() + var c = 0 + for i in 0 to length(ls) do : + if (i % stride >= start and i % stride < end) : + add(ls*,ls[i]) + to-list(ls*) + (e:WSubAccess) : + val ls = get-locations(exp(e)) + val stride = get-size(e) + val wrap = size(type(exp(e)) as VectorType) + val ls* = Vector<Location>() + var c = 0 + for i in 0 to length(ls) do : + if c % wrap == 0 : c = 0 + val base* = base(ls[i]) + val guard* = AND(guard(ls[i]),EQV(uint(c),index(e))) + add(ls*,Location(base*,guard*)) + if (i + 1) % stride == 0 : c = c + 1 + to-list(ls*) + hashed-locations[e] = x + x + +defn remove-access (c:Circuit) : + defn remove-m (m:InModule) -> InModule : + val sh = get-sym-hash(m,keys(v-keywords)) + defn remove-s (s:Stmt) -> Stmt : + val stmts = Vector<Stmt>() + defn create-temp (e:Expression) -> Expression : + val n = firrtl-gensym(`GEN,sh) + add(stmts,DefWire(info(s),n,type(e))) + WRef(n,type(e),kind(e),gender(e)) + defn remove-e (e:Expression) -> Expression : ;NOT RECURSIVE (except primops) INTENTIONALLY! + match(e) : + (e:DoPrim) : map(remove-e,e) + (e:UIntValue|SIntValue) : e + (e) : + val rs = get-locations(e) + val foo = for x in rs find : + (guard(x)) != one + if foo == false : e + else : + val temp = create-temp(e) + for (x in rs, i in 0 to false) do : + if i == 0 : + add(stmts,Connect(info(s),temp,base(x))) + else : + add(stmts,Conditionally(info(s),guard(x),Connect(info(s),temp,base(x)),Empty())) + temp + val s* = match(s) : + (s:Connect) : + val ls = get-locations(loc(s)) + val loc* = + if length(ls) == 1 and guard(head(ls)) == one : loc(s) + else : + val temp = create-temp(loc(s)) + for x in ls do : + add(stmts,Conditionally(info(s),guard(x),Connect(info(s),base(x),temp),Empty())) + temp + Connect(info(s),loc*,remove-e(exp(s))) + (s) : map{remove-s,_} $ map(remove-e,s) + add(stmts,s*) + if length(stmts) != 1 : Begin(to-list(stmts)) + else : stmts[0] + + InModule(info(m),name(m),ports(m),remove-s(body(m))) + + Circuit(info(c),modules*, main(c)) where : + val modules* = + for m in modules(c) map : + match(m) : + (m:ExModule) : m + (m:InModule) : remove-m(m) + +;;================ EXPAND WHENS ============================= +; This pass does three things: remove last connect semantics, +; remove conditional blocks, and eliminate concept of scoping. + +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" + +; ========== Expand When Utilz ========== + +defn get-entries (hash:HashTable<Expression,Expression>,exps:Streamable<Expression>) -> HashTable<Expression,Expression> : + val hash* = HashTable<Expression,Expression>(exp-hash) + for e in exps do : + val value = get?(hash,e,false) + match(value) : + (value:Expression) : hash*[e] = value + (value:False) : false + hash* +defn get-female-refs (n:Symbol,t:Type,g:Gender) -> List<Expression> : + val exps = fast-create-exps(WRef(n,t,ExpKind(),g)) + val exps* = Vector<Expression>() + for i in 0 to length(exps) do : + switch { _ == get-gender(t,i,g)} : + BI-GENDER : add(exps*,exps[i]) + FEMALE : add(exps*,exps[i]) + else : false + to-list(exps*) +defn get-gender (t:Type, i:Int, g:Gender) -> Gender : + val f = get-flip(t,i,DEFAULT) + g * f +defn print-hash (h:HashTable<Expression,Expression>) : + for x in h do : + println(x) + +; ------------ Pass ------------------- +defn expand-whens (c:Circuit) -> Circuit : + defn void-all (m:InModule) -> InModule : + defn void-all-s (s:Stmt) -> Stmt : + match(s) : + (s:DefWire|DefRegister|WDefInstance|DefMemory) : + val voids = Vector<Stmt>() + for e in get-female-refs(name(s),get-type(s),get-gender(s)) do : + add(voids,Connect(info(s),e,WVoid())) + Begin(List(s,to-list(voids))) + (s) : map(void-all-s,s) + val voids = Vector<Stmt>() + for p in ports(m) do : + for e in get-female-refs(name(p),type(p),get-gender(p)) do : + add(voids,Connect(info(p),e,WVoid())) + val body* = void-all-s(body(m)) + InModule(info(m),name(m),ports(m),Begin(list(Begin(to-list(voids)),body*))) + + defn expand-whens (m:InModule) -> [HashTable<Expression,Expression> Vector<Stmt>] : + val simlist = Vector<Stmt>() + defn expand-whens (s:Stmt,netlist:HashTable<Expression,Expression>,p:Expression) -> Stmt : + match(s) : + (s:Connect) : netlist[loc(s)] = exp(s) + (s:Conditionally) : + val exps = Vector<Expression>() + defn prefetch (s:Stmt) -> Stmt: + match(s) : + (s:Connect) : + add(exps,loc(s)) + s + (s) : map(prefetch,s) + prefetch(conseq(s)) + val c-netlist = get-entries(netlist,exps) + expand-whens(conseq(s),c-netlist,AND(p,pred(s))) + expand-whens(alt(s),netlist,AND(p,NOT(pred(s)))) + for lvalue in keys(c-netlist) do : + val value = get?(netlist,lvalue,false) + match(value) : + (value:Expression) : + netlist[lvalue] = MUX(pred(s),c-netlist[lvalue],value) + (value:False) : + netlist[lvalue] = c-netlist[lvalue] + (s:Print) : + if p == one : add(simlist,s) + else : add(simlist,Print(info(s),string(s),args(s),clk(s),AND(p,en(s)))) + (s:Stop) : + if p == one : add(simlist,s) + else : add(simlist,Stop(info(s),ret(s),clk(s),AND(p,en(s)))) + (s) : map(expand-whens{_,netlist,p},s) + s + val netlist = HashTable<Expression,Expression>(exp-hash) + expand-whens(body(m),netlist,one) + + ;println("Netlist:") + ;println(netlist) + ;println("Simlist:") + ;println(simlist) + [ netlist simlist ] + + defn create-module (netlist:HashTable<Expression,Expression>,simlist:Vector<Stmt>,m:InModule) -> InModule : + val stmts = Vector<Stmt>() + val connections = Vector<Stmt>() + defn replace-void (e:Expression,rvalue:Expression) -> Expression : + match(rvalue) : + (rv:WVoid) : e + (rv) : map(replace-void{e,_},rv) + defn create (s:Stmt) -> Stmt : + match(s) : + (s:DefWire|DefRegister|WDefInstance|DefMemory) : + add(stmts,s) + for e in get-female-refs(name(s),get-type(s),get-gender(s)) do : + val rvalue = + if s typeof DefRegister : replace-void(e,netlist[e]) + else : netlist[e] + add(connections,Connect(info(s),e,rvalue)) + (s:DefPoison|DefNode) : + add(stmts,s) + (s) : map(create,s) + s + create(body(m)) + for p in ports(m) do : + for e in get-female-refs(name(p),type(p),get-gender(p)) do : + add(connections,Connect(info(p),e,netlist[e])) + for x in simlist do : + add(stmts,x) + InModule(info(m),name(m),ports(m),Begin(list(Begin(to-list(stmts)),Begin(to-list(connections))))) + + val voided-modules = + for m in modules(c) map : + match(m) : + (m:ExModule) : m + (m:InModule) : + val m* = void-all(m as InModule) + m* + val modules* = + for m in voided-modules map : + match(m) : + (m:ExModule) : m + (m:InModule) : + val [netlist simlist] = expand-whens(m) + create-module(netlist,simlist,m) + Circuit(info(c),modules*,main(c)) + +;;================ Module Duplication ================== +; Duplicates modules so that no module is instantiated +; more than once. + +;public defstruct ModuleDuplication <: Pass +;public defmethod pass (b:ModuleDuplication) -> (Circuit -> Circuit) : module-duplication +;public defmethod name (b:ModuleDuplication) -> String : "Module Duplication" +;public defmethod short-name (b:ModuleDuplication) -> String : "mod-dup" +; +;;------------ Helper Functions ------------- +; +;;------------ Pass ------------------ +; +;public defn module-duplication (c:Circuit) : +; val modules* = Vector<Module>() +; val m-names = HashTable<Symbol,Int>(symbol-hash) +; defn rename (n:Symbol) -> Symbol : +; val int = get?(m-names,n,0) +; m-names[n] = int + 1 +; val n* = symbol-join([n module-expand-delin int]) +; val m = for x in modules(c) find : name(x) == n +; match(m) : +; (m:InModule) : add(modules*,InModule(info(m),n*, ports(m), rename-s(body(m)))) +; (m:ExModule) : add(modules*,ExModule(info(m),n*, ports(m))) +; (m:False) : error("Shouldn't be here") +; n* +; +; defn rename-e (e:Expression) -> Expression : +; match(e) : +; (e:Ref) : Ref(rename(name(e)),type(e)) +; (e) : error("Shouldn't be here") +; defn rename-s (s:Stmt) -> Stmt : +; match(s) : +; (s:WDefInstance) : WDefInstance(info(s),name(s),rename-e(module(s))) +; (s) : map(rename-s,s) +; +; val top = for m in modules(c) find : name(m) == main(c) +; match(top) : +; (m:InModule) : add(modules*,InModule(info(m),name(m), ports(m), rename-s(body(m)))) +; (m:ExModule) : m +; (m:False) : error("Shouldn't be here") +; +; Circuit(info(c),to-list(modules*), main(c)) +; +; +;;;================ Deadcode Elimination =================== +;; Walks the circuit, starting from the outputs from the top +;; level module. All components that are not reached are +;; deleted +; +;public defstruct DeadcodeElimination <: Pass +;public defmethod pass (b:DeadcodeElimination) -> (Circuit -> Circuit) : deadcode-elimination +;public defmethod name (b:DeadcodeElimination) -> String : "Deadcode Elimination" +;public defmethod short-name (b:DeadcodeElimination) -> String : "deadcode-elim" +; +;;------------ Helper Functions ------------- +; +;;------------ Pass ------------------ +; +;public defn deadcode-elimination (c:Circuit) : c +; +;;;================ INFER WIDTHS ============================= +;; First, you replace all unknown widths with a unique width +;; variable. +;; Then, you collect all width constraints. +;; Then, you solve width constraints. +;; 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 definterface Constraint +public defstruct WGeq <: Constraint : + loc : Width + exp : Width +public defmethod print (o:OutputStream, c:WGeq) : + print-all(o,[ loc(c) " >= " exp(c)]) +defn apply (a:Int|False,b:Int|False, f: (Int,Int) -> Int) -> Int|False : + if a typeof Int and b typeof Int : f(a as Int, b as Int) + else : false + +defn solve-constraints (l:List<WGeq>) -> HashTable<Symbol,Width> : + defn contains? (n:Symbol,h:HashTable<Symbol,?>) -> True|False : key?(h,n) + defn make-unique (ls:List<WGeq>) -> HashTable<Symbol,Width> : + val h = HashTable<Symbol,Width>(symbol-hash) + for g in ls do : + match(loc(g)) : + (w:VarWidth) : + val n = name(w) + if contains?(n,h) : h[n] = MaxWidth(list(exp(g),h[n])) + else : h[n] = exp(g) + (w) : w + h + defn simplify (w:Width) -> Width : + match(map(simplify,w)) : + (w:MaxWidth) : + val v = Vector<Width>() + for w* in args(w) do : + match(w*) : + (w*:MaxWidth) : + for x in args(w*) do : add(v,x) + (w*) : add(v,w*) + MaxWidth(unique(v)) + (w:PlusWidth) : + match(arg1(w),arg2(w)) : + (w1:IntWidth,w2:IntWidth) : IntWidth(plus(width(w1),width(w2))) + (w1,w2) : w + (w:MinusWidth) : + match(arg1(w),arg2(w)) : + (w1:IntWidth,w2:IntWidth) : IntWidth(minus(width(w1),width(w2))) + (w1,w2) : w + (w:ExpWidth) : + match(arg1(w)) : + (w1:IntWidth) : IntWidth(pow(to-long(2),width(w1)) - to-long(1)) + (w1) : w + (w) : w + defn substitute (w:Width,h:HashTable<Symbol,Width>) -> Width : + ;println-all-debug(["Substituting for [" w "]"]) + val w* = simplify(w) + ;println-all-debug(["After Simplify: [" w* "]"]) + match(map(substitute{_,h},simplify(w))) : + (w:VarWidth) : + ;println-debug("matched varwidth!") + if contains?(name(w),h) : + ;println-debug("Contained!") + ;println-all-debug(["Width: " w]) + ;println-all-debug(["Accessed: " h[name(w)]]) + val t = simplify(substitute(h[name(w)],h)) + ;val t = h[name(w)] + ;println-all-debug(["Width after sub: " t]) + h[name(w)] = t + t + else : w + (w): + ;println-all-debug(["not varwidth!" w]) + w + defn b-sub (w:Width,h:HashTable<Symbol,Width>) -> Width: + match(map(b-sub{_,h},w)) : + (w:VarWidth) : + if key?(h,name(w)) : h[name(w)] + else : w + (w) : w + defn remove-cycle (n:Symbol,w:Width) -> Width : + ;println-all-debug(["Removing cycle for " n " inside " w]) + val w* = match(map(remove-cycle{n,_},w)) : + (w:MaxWidth) : MaxWidth(to-list(filter({_ != VarWidth(n)},args(w)))) + (w:MinusWidth) : + if arg1(w) == VarWidth(n) : arg1(w) + else : w + (w) : w + ;println-all-debug(["After removing cycle for " n ", returning " w*]) + w* + defn self-rec? (n:Symbol,w:Width) -> True|False : + var has? = false + defn look (w:Width) -> Width : + match(map(look,w)) : + (w:VarWidth) : if name(w) == n : has? = true + (w) : w + w + look(w) + has? + + ; Forward solve + ; Returns a solved list where each constraint undergoes: + ; 1) Continuous Solving (using triangular solving) + ; 2) Remove Cycles + ; 3) Move to solved if not self-recursive + val u = make-unique(l) + println-debug("======== UNIQUE CONSTRAINTS ========") + for x in u do : println-debug(x) + println-debug("====================================") + + val f = HashTable<Symbol,Width>(symbol-hash) + val o = Vector<Symbol>() + for x in u do : + println-debug("==== SOLUTIONS TABLE ====") + for x in f do : println-debug(x) + println-debug("=========================") + + val [n e] = [key(x) value(x)] + + val e-sub = substitute(e,f) + println-debug(["Solving " n " => " e]) + println-debug(["After Substitute: " n " => " e-sub]) + println-debug("==== SOLUTIONS TABLE (Post Substitute) ====") + for x in f do : println-debug(x) + println-debug("=========================") + val e* = remove-cycle{n,_} $ e-sub + ;println-debug(["After Remove Cycle: " n " => " e*]) + if not self-rec?(n,e*) : + ;println-all-debug(["Not rec!: " n " => " e*]) + ;println-all-debug(["Adding [" n "=>" e* "] to Solutions Table"]) + add(o,n) + f[n] = e* + + println-debug("Forward Solved Constraints") + for x in f do : println-debug(x) + + ; Backwards Solve + val b = HashTable<Symbol,Width>(symbol-hash) + for i in (length(o) - 1) through 0 by -1 do : + val n = o[i] + println-all-debug(["SOLVE BACK: [" n " => " f[n] "]"]) + println-debug("==== SOLUTIONS TABLE ====") + for x in b do : println-debug(x) + println-debug("=========================") + val e* = simplify(b-sub(f[n],b)) + println-all-debug(["BACK RETURN: [" n " => " e* "]"]) + b[n] = e* + println-debug("==== SOLUTIONS TABLE (Post backsolve) ====") + for x in b do : println-debug(x) + println-debug("=========================") + b + +public defn width! (t:Type) -> Width : + match(t) : + (t:UIntType) : width(t) + (t:SIntType) : width(t) + (t:ClockType) : IntWidth(1) + (t) : error("No width!") +public defn width! (e:Expression) -> Width : width!(type(e)) + +defn reduce-var-widths (c:Circuit,h:HashTable<Symbol,Width>) -> Circuit : + defn evaluate (w:Width) -> Width : + defn apply (a:Long|False,f:(Long) -> Long) -> Long|False : + if a typeof Long : f(a as Long) + else : false + defn apply (a:Long|False,b:Long|False, f: (Long,Long) -> Long) -> Long|False : + if a typeof Long and b typeof Long : f(a as Long, b as Long) + else : false + defn apply-l (l:List<Long|False>,f:(Long,Long) -> Long) -> Long|False : + if length(l) == 0 : to-long(0) + else : apply(head(l),apply-l(tail(l),f),f) + defn max (a:Long,b:Long) -> Long : + if a >= b : a + else : b + defn solve (w:Width) -> False|Long : + match(w) : + (w:VarWidth) : + val w* = get?(h,name(w),false) + match(w*) : + (w:VarWidth) : false + (w:False) : false + (w) : solve(w as Width) + (w:MaxWidth) : apply-l(map(solve,args(w)),max) + (w:PlusWidth) : apply(solve(arg1(w)),solve(arg2(w)),{plus(_,_)}) + (w:MinusWidth) : apply(solve(arg1(w)),solve(arg2(w)),{minus(_,_)}) + (w:ExpWidth) : apply(to-long(2),solve(arg1(w)),{minus(pow(_,_),to-long(1))}) + (w:IntWidth) : width(w) + (w) : + println(w) + error("Shouldn't be here") + + val s = solve(w) + match(s) : + (s:Long) : IntWidth(s) + (s) : w + + defn reduce-var-widths-w (w:Width) -> Width : + println-all-debug(["REPLACE: " w]) + val w* = evaluate(w) + println-all-debug(["WITH: " w*]) + w* + + val modules* = for m in modules(c) map : + val ports* = for p in ports(m) map : + Port(info(p),name(p),direction(p),mapr(reduce-var-widths-w,type(p))) + + match(m) : + (m:ExModule) : ExModule(info(m),name(m),ports*) + (m:InModule) : InModule(info(m),name(m),ports*,mapr(reduce-var-widths-w,body(m))) + + Circuit(info(c),modules*,main(c)) + +defn infer-widths (c:Circuit) -> Circuit : + val v = Vector<WGeq>() + defn constrain (w1:Width,w2:Width) -> False : constrain(w1,w2,DEFAULT) + defn constrain (w1:Width,w2:Width,f:Flip) -> False : + switch { _ == f } : + DEFAULT : add(v,WGeq(w1,w2)) + REVERSE : add(v,WGeq(w2,w1)) + defn get-constraints (t1:Type,t2:Type,f:Flip) -> False : + match(t1,t2) : + (t1:UIntType,t2:UIntType) : constrain(width(t1),width(t2)) + (t1:SIntType,t2:SIntType) : constrain(width(t1),width(t2)) + (t1:BundleType,t2:BundleType) : + for (f1 in fields(t1),f2 in fields(t2)) do : + get-constraints(type(f1),type(f2),flip(f1) * f) + (t1:VectorType,t2:VectorType) : + get-constraints(type(t1),type(t2),f) + defn get-constraints-e (e:Expression) -> Expression : + match(map(get-constraints-e,e)) : + (e:DoPrim) : + if op(e) == MUX-OP : + constrain(width!(args(e)[0]),ONE) + constrain(ONE,width!(args(e)[0])) + e + (e) : e + defn get-constraints (s:Stmt) -> Stmt : + match(map(get-constraints-e,s)) : + (s:Connect) : + ;constrain(width!(loc(s)),width!(exp(s))) + ;s + val n = get-size(loc(s)) + val ce-loc = fast-create-exps(loc(s)) + val ce-exp = fast-create-exps(exp(s)) + for i in 0 to n do : + val loc* = ce-loc[i] + val exp* = ce-exp[i] + switch { _ == get-flip(type(loc(s)),i,DEFAULT) } : + DEFAULT : constrain(width!(loc*),width!(exp*)) + REVERSE : constrain(width!(exp*),width!(loc*)) + s + (s:BulkConnect) : + val ls = get-valid-points(type(loc(s)),type(exp(s)),DEFAULT,DEFAULT) + for x in ls do : + println(x) + println(fast-create-exps(loc(s))) + println(fast-create-exps(exp(s))) + val loc* = fast-create-exps(loc(s))[x[0]] + val exp* = fast-create-exps(exp(s))[x[1]] + switch { _ == get-flip(type(loc(s)),x[0],DEFAULT) } : + DEFAULT : constrain(width!(loc*),width!(exp*)) + REVERSE : constrain(width!(exp*),width!(loc*)) + s + (s:DefRegister) : + constrain(width!(reset(s)),ONE) + constrain(ONE,width!(reset(s))) + get-constraints(type(s),type(init(s)),DEFAULT) + s + (s:Conditionally) : + add(v,WGeq(width!(pred(s)),ONE)) + add(v,WGeq(ONE,width!(pred(s)))) + map(get-constraints,s) + (s) : map(get-constraints,s) + + for m in modules(c) do : + match(m) : + (m:InModule) : get-constraints(body(m)) + (m) : false + println-debug("======== ALL CONSTRAINTS ========") + for x in v do : println-debug(x) + println-debug("=================================") + val h = solve-constraints(to-list(v)) + println-debug("======== SOLVED CONSTRAINTS ========") + for x in h do : println-debug(x) + println-debug("====================================") + reduce-var-widths(Circuit(info(c),modules(c),main(c)),h) + +; ================ All Resolving Passes ================ +public defstruct Resolve <: Pass +public defmethod pass (b:Resolve) -> (Circuit -> Circuit) : resolve +public defmethod name (b:Resolve) -> String : "Resolve" +public defmethod short-name (b:Resolve) -> String : "resolve" + +defn resolve (c:Circuit) -> Circuit : + infer-widths $ + resolve-genders $ + infer-types $ + resolve-kinds $ c + +;;================= 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,InModule>(symbol-hash) +; val h-s = HashTable<Symbol,Stmt>(symbol-hash) +; defn inline-inst (s:Stmt) -> Stmt : +; match(map(inline-inst,s)) : +; (s:WDefInstance) : +; val n = name(module(s) as WRef) +; val m = h[n] +; val body* = +; if key?(h-s,n) : h-s[n] +; else : +; val v = Vector<Stmt>() +; for p in ports(m) do : +; add(v,DefWire(info(s),name(p),type(p))) +; add(v,inline-inst(body(m))) +; Begin(to-list(v)) +; h-s[n] = body* +; rename-s(body*,name(s)) +; (s) : map(inline-inst-e,s) +; defn inline-inst-e (e:Expression) -> Expression : +; match(map(inline-inst-e,e)) : +; (e:WSubField) : +; match(kind(exp(e) as WRef)) : +; (k:InstanceKind) : +; WRef(symbol-join([name(exp(e) as WRef) inline-delin name(e)]),type(e),k,gender(e)) +; (k:MemKind) : e +; (e) : e +; defn rename (ref:Symbol,n:Symbol) -> Symbol : symbol-join([n inline-delin 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) inline-delin name(e)]),type(e),k,gender(e)) +; (k:MemKind) : e +; (e) : e +; defn rename-s (s:Stmt,n:Symbol) -> Stmt : +; map{rename-e{_,n},_} $ match(map(rename-s{_,n},s)) : +; (s:DefWire) : DefWire(info(s),rename(name(s),n),type(s)) +; (s:DefPoison) : DefPoison(info(s),rename(name(s),n),type(s)) +; (s:DefRegister) : DefRegister(info(s),rename(name(s),n),type(s),clock(s),reset(s)) +; (s:WDefInstance) : error("Shouldn't be here") +; (s:DefMemory) : DefMemory(info(s),rename(name(s),n),type(s),seq?(s),clock(s),size(s)) +; (s:DefNode) : DefNode(info(s),rename(name(s),n),value(s)) +; (s) : s +; for m in modules(c) do : +; match(m) : +; (m:ExModule) : error("Cannot inline with external modules") +; (m:InModule) : h[name(m)] = m +; val top = (for m in modules(c) find : name(m) == main(c)) as InModule +; Circuit(info(c),list(InModule(info(top),name(top),ports(top),inline-inst(body(top)))),main(c)) + +;;================= 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 (m:InModule) -> InModule : + val v = Vector<Stmt>() + val sh = get-sym-hash(m,keys(v-keywords)) + defn split-exp-s (s:Stmt) -> Stmt : + val base = match(s) : + (s:Connect) : lowered-name(loc(s)) + (s:DefNode) : name(s) + (s:DefRegister) : name(s) + (s) : `F + defn split (e:Expression) -> Expression : + val n = firrtl-gensym(`GEN,sh) + add(v,DefNode(info(s),n,e)) + WRef(n,type(e),kind(e),gender(e)) + defn split-exp-e (e:Expression,i:Int) -> Expression : + match(map(split-exp-e{_,i + 1},e)) : + (e:DoPrim) : + if i > 0 : split(e) + else : e + (e) : e + match(map(split-exp-e{_,0},s)) : + (s:Begin) : map(split-exp-s,s) + (s) : + add(v,s) + s + split-exp-s(body(m)) + InModule(info(m),name(m),ports(m),Begin(to-list(v))) + +defn split-exp (c:Circuit) -> Circuit : + val modules* = for m in modules(c) map : + match(m) : + (m:InModule) : split-exp(m) + (m:ExModule) : m + Circuit(info(c),modules*,main(c)) + + +;;================= Special Rename ======================== +;; Returns a new Circuit with only real IR nodes. +;public defstruct SpecialRename <: Pass : +; original-sym : Symbol +; new-sym : Symbol +;public defmethod pass (b:SpecialRename) -> (Circuit -> Circuit) : special-rename{original-sym(b),new-sym(b),_:Circuit} +;public defmethod name (b:SpecialRename) -> String : "Special Rename" +;public defmethod short-name (b:SpecialRename) -> String : "special-rename" +; +;public defn special-rename (original-sym:Symbol,new-sym:Symbol,c:Circuit) : +; defn rename (s:Symbol) -> Symbol : +; val y = Vector<String>() +; val os = to-string $ original-sym +; val ns = to-string $ new-sym +; defn rename (st:String) -> False : +; if st == os : +; add(y,ns) +; else if length(st) <= length(os) : +; add(y,st) +; else : +; if substring(st,0,length(os)) == os : +; add(y,ns) +; ;println(st) +; ;println(substring(st,length(os),length(st))) +; rename(substring(st,length(os),length(st))) +; else : +; add(y,substring(st,0,1)) +; rename(substring(st,1,length(st))) +; rename(to-string(s)) +; to-symbol $ string-join $ to-list(y) +; defn to-type (t:Type) -> Type : +; match(map(to-type,t)) : +; (t:BundleType) : BundleType $ +; for f in fields(t) map : Field(rename(name(f)),flip(f),type(f)) +; (t) : t +; defn to-exp (e:Expression) -> Expression : +; map{to-type,_} $ match(map(to-exp,e)) : +; (e:Ref) : Ref(rename(name(e)), type(e)) +; (e:Subfield) : Subfield(exp(e),rename(name(e)),type(e)) +; (e) : e +; defn to-stmt (s:Stmt) -> Stmt : +; map{to-type,_} $ match(map(to-exp,s)) : +; (s:DefWire) : DefWire(info(s),rename(name(s)),type(s)) +; (s:DefPoison) : DefPoison(info(s),rename(name(s)),type(s)) +; (s:DefRegister) : DefRegister(info(s),rename(name(s)),type(s),clock(s),reset(s)) +; (s:WDefInstance) : WDefInstance(info(s),rename(name(s)),module(s)) +; (s:DefMemory) : DefMemory(info(s),rename(name(s)),type(s),seq?(s),clock(s),size(s)) +; (s:DefNode) : DefNode(info(s),rename(name(s)),value(s)) +; (s:DefAccessor) : DefAccessor(info(s),rename(name(s)),source(s),index(s),acc-dir(s)) +; (s) : map(to-stmt,s) +; +; defn to-port (p:Port) -> Port : Port(info(p),rename(name(p)),direction(p),type(p)) +; +; Circuit(info(c),modules*, main(c)) where : +; val modules* = +; for m in modules(c) map : +; match(m) : +; (m:InModule) : InModule(info(m),name(m), map(to-port,ports(m)), to-stmt(body(m))) +; (m:ExModule) : m +; +; +;;========== Pad Widths ================== +; +;public defstruct Pad <: Pass +;public defmethod pass (b:Pad) -> (Circuit -> Circuit) : pad-widths +;public defmethod name (b:Pad) -> String : "Pad Widths" +; +;;------------ Helper Functions -------------- +;defn int-width! (t:Type) -> Long : +; match(width!(t)) : +; (w:IntWidth) : width(w) +; (w) : error("Non-int width") +; +;defn set-width (desired:Long,t:Type) -> Type : +; match(t) : +; (t:UIntType) : UIntType(IntWidth(desired)) +; (t:SIntType) : SIntType(IntWidth(desired)) +; (t) : error("Non-ground type") +; +;defn lmax (l1:Long, l2:Long) -> Long : +; if l1 > l2 : l1 +; else : l2 +; +;;------------- Pad Widths ------------------- +; +;defn pad-widths-e (desired:Long,e:Expression) -> Expression : +; defn trim (desired:Long, e:Expression) : +; ;; println-all(["TRIM " desired " e " e]) +; DoPrim(BITS-SELECT-OP,list(e),list(to-int(to-string(desired)) - 1, 0),set-width(desired,type(e))) +; defn pad (desired:Long, e:Expression) : +; ;; println-all(["PAD " desired " e " e]) +; DoPrim(PAD-OP,list(e),list(to-int $ to-string(desired)),set-width(desired,type(e))) +; defn trim-pad (desired:Long, e:Expression) : +; val i = int-width!(type(e)) +; if i > desired : trim(desired, e) +; else if i == desired : e +; else : pad(desired, e) +; defn self-pad-widths-e (e:Expression) -> Expression : +; pad-widths-e(int-width!(type(e)), e) +; ;; println-all(["PAD-E " desired " " e]) +; match(e) : +; (e:DoPrim) : +; val new-desired = reduce(lmax, to-long(0), map(int-width!{type(_)}, args(e))) +; ;; println-all([" NEW DESIRED " new-desired]) +; val e* = +; if contains?([CONCAT-OP, DYN-SHIFT-RIGHT-OP, DYN-SHIFT-LEFT-OP], op(e)) : +; DoPrim(op(e), map(self-pad-widths-e, args(e)), consts(e), type(e)) +; else if contains?([MUX-OP], op(e)) : +; DoPrim(op(e), list(pad-widths-e(to-long(1), args(e)[0]), pad-widths-e(new-desired, args(e)[1]), pad-widths-e(new-desired, args(e)[2])), consts(e), type(e)) +; else : +; map(pad-widths-e{new-desired,_},e) +; trim-pad(desired, e*) +; (e:Ref|Subfield|Index) : +; trim-pad(desired, e) +; (e:UIntValue) : +; val i = int-width!(type(e)) +; if i > desired : trim(desired, e) +; else : UIntValue(value(e),IntWidth(desired)) +; (e:SIntValue) : +; val i = int-width!(type(e)) +; if i > desired : trim(desired, e) +; else : SIntValue(value(e),IntWidth(desired)) +; (e) : error(to-string $ e) +; +;defn pad-widths-s (s:Stmt) -> Stmt : +; ;; println-all(["PAD-S " s]) +; match(map(pad-widths-s,s)) : +; (s:Connect) : +; val i = int-width!(type(loc(s))) +; val loc* = pad-widths-e(i,loc(s)) +; val exp* = pad-widths-e(i,exp(s)) +; Connect(info(s),loc*,exp*) +; (s:PrintfStmt) : +; val args* = for x in args(s) map : +; val i = int-width!(type(x)) +; pad-widths-e(i,x) +; PrintfStmt(info(s),string(s),args*) +; (s:DefNode) : +; val i = int-width!(type(value(s))) +; val exp* = pad-widths-e(i,value(s)) +; DefNode(info(s),name(s),exp*) +; (s:Conditionally) : +; val i = int-width!(type(pred(s))) +; val pred* = pad-widths-e(i,pred(s)) +; Conditionally(info(s),pred*,conseq(s),alt(s)) +; (s) : s +; +;public defn pad-widths (c:Circuit) -> Circuit : +; Circuit{info(c),_,main(c)} $ +; for m in modules(c) map : +; match(m) : +; (m:ExModule) : m +; (m:InModule) : InModule(info(m),name(m),ports(m),pad-widths-s(body(m))) +; +; + +;============== Common Subexpression Elimination =========== +;NOT DONE + +;public defstruct CSE <: Pass +;public defmethod pass (b:CSE) -> (Circuit -> Circuit) : const-prop +;public defmethod name (b:CSE) -> String : "Common Subexpression Elimination" +;public defmethod short-name (b:ConstProp) -> String : "cse" +; +;defn cse-m (m:InModule) -> InModule : +; val cse-hash = HashTable<Expression,Int>(exp-hash) +; val placed? = HashTable<Expression,True|False>(exp-hash) +; +; defn cse-s (s:Stmt) -> Stmt : +; val stmts = Vector<Stmt>() +; defn cse-e (e:Expression) -> Expression +; match(s) : +; +; defn build-e (e:Expression) -> Expression : +; match(e) : +; (e:DoPrim) : +; if key?(cse-hash,e) : +; cse-hash[e] = cse-hash[e] + 1 +; else : +; cse-hash[e] = 1 +; placed?[e] = false +; (e) : e +; defn build-s (s:Stmt) -> Stmt : map{build-s,_} $ map(build-e,s) +; +; build-s(body(m)) +; InModule(info(m),name(m),ports(m),cse-s(body(m))) +; +;public defn cse (c:Circuit) -> Circuit : +; Circuit{info(c),_,main(c)} $ +; for m in modules(c) map : +; match(m) : +; (m:ExModule) : m +; (m:InModule) : cse-m(m) + + + +;;============= Constant Propagation ================ +; +public defstruct ConstProp <: Pass +public defmethod pass (b:ConstProp) -> (Circuit -> Circuit) : const-prop +public defmethod name (b:ConstProp) -> String : "Constant Propagation" +public defmethod short-name (b:ConstProp) -> String : "const-prop" + +defn const-prop-e (e:Expression) -> Expression : + match(map(const-prop-e,e)) : + (e:DoPrim) : + switch {op(e) == _} : + DYN-SHIFT-RIGHT-OP : + match(args(e)[1]) : + (x:UIntValue|SIntValue) : + DoPrim(SHIFT-RIGHT-OP,list(args(e)[0]),list(to-int(value(x))),UnknownType()) + (x) : e + DYN-SHIFT-LEFT-OP : + match(args(e)[1]) : + (x:UIntValue|SIntValue) : + DoPrim(SHIFT-LEFT-OP,list(args(e)[0]),list(to-int(value(x))),UnknownType()) + (x) : e + SHIFT-RIGHT-OP : + match(args(e)[0]) : + (x:UIntValue) : + val b = rsh(value(x),consts(e)[0]) + UIntValue(b,width(type(e) as UIntType)) + (x:SIntValue) : + val b = rsh(value(x),consts(e)[0]) + SIntValue(b,width(type(e) as SIntType)) + (x) : e + BITS-SELECT-OP : + match(args(e)[0]) : + (x:UIntValue) : + val b = bits(value(x),consts(e)[0] + 1,consts(e)[1]) + UIntValue(b,width(type(e) as UIntType)) + (x) : e + BIT-SELECT-OP : + match(args(e)[0]) : + (x:UIntValue) : + val i = bit(value(x),consts(e)[0]) + UIntValue(i,width(type(e) as UIntType)) + (x) : e + else : e + (e) : e + +defn const-prop-s (s:Stmt) -> Stmt : + map{const-prop-e,_} $ map(const-prop-s,s) + +public defn const-prop (c:Circuit) -> Circuit : + Circuit{info(c),_,main(c)} $ + for m in modules(c) map : + match(m) : + (m:ExModule) : m + (m:InModule) : InModule(info(m),name(m),ports(m),const-prop-s(body(m))) + +;============= Condense Mems ================ +; +;public defstruct CondenseMems <: Pass +;public defmethod pass (b:CondenseMems) -> (Circuit -> Circuit) : condense-mems +;public defmethod name (b:CondenseMems) -> String : "Condense Mems" +;public defmethod short-name (b:CondenseMems) -> String : "condense-mems" +; +;;------------- Utils --------------- +; +;defn concat (es:List<Expression>) -> Expression : +; if length(es) == 1 : head(es) +; else : CAT(head(es),cat(tail(es))) +;defn cast (t:Type,e:Expression) -> Expression : +; match(t) : +; (t:UIntType) : e +; (t:SIntType) : DoPrim(AS-SINT-OP,list(e),list(),SIntType(get-width(t))) +;defn get-width-index (e:Expression) -> Long : +; match(e) : +; (e:WRef) : 0 +; (e:WSubField) : +; var w = get-width-index(exp(e)) +; var found? = false +; for f in fields(type(exp(e)) as BundleType) do : +; if name(f) == name(e) : +; found? = true +; if found? == false : +; w = w + get-width(type(f)) +; w +; (e:WSubIndex) : +; get-width-index(exp(e)) + get-width(type(e)) * value(e) +;defn root-ref (e:Expression) -> Expression : +; match(e) : +; (e:WRef) : e +; (e:WSubField|WSubIndex) : root-ref(e) +;defn flatten (e:Expression) -> Expression : +; match(e) : +; (e:WRef) : e +; (e:WSubField|WSubIndex) : +; val base = get-width-index(e) +; val off = get-width(type(e)) +; DoPrim(BITS-SELECT-OP,list(root-ref(e)),list(base,off),UIntType(IntWidth(off))) +; +;;------------- Pass ------------------ + +;defn condense-mems (m:InModule) -> InModule : +; val mem-assigns = HashTable<Expression,Expression>(exp-hash) +; defn collect-mems (s:Stmt) -> Stmt : +; match(s) : +; (s:Connect) : +; defn condense-mems-e (e:Expression) -> Expression : +; val e* = match(e) : +; (e:WRef|WSubField|WSubIndex) : +; if (kind(e) typeof MemKind) : cast(type(e),flatten(e)) +; else : e +; (e:UIntValue|SIntValue) : e +; (e:DoPrim) : map(condense-mems-e,e) +; defn condense-mems (s:Stmt) -> Stmt : +; match(s) : +; (s:DefMemory) : +; val stmts = Vector<Stmt>() +; val s* = map(flatten,s) +; add(stmts,s*) +; val mem = WRef(name(s),type(s),MemKind(),UNKNOWN-GENDER) +; for f in fields(type(s) as BundleType) do : +; val data-name = +; if contains?(writers(s),name(f)) : `data +; else if contains(readwriters(s),name(f)) : `wdata +; else : false +; match(data-name) : +; (f:False) : false +; (n:Symbol) : +; val port = WSubField(mem,name(f),type(f),UNKNOWN-GENDER) +; val es = create-exps(WSubField(port,n,field-type(type(port),n),UNKNOWN-GENDER)) +; val e* = concat $ for e in es map : +; map(condense-mems-e,mem-assigns[e]) +; add(stmts,Connect(info(s),WSubField(port,n,data-type(s*),UNKNOWN-GENDER),e*)) +; Begin(to-list(stmts)) +; (s:Connect) : +; if kind(loc(s)) typeof MemKind : EmptyStmt() +; else : map(condense-mems-e, s) +; (s) : map{condense-mems,_} $ map(condense-mems-e, s) +; InModule(info(m),name(m),ports(m),condense-mems(body(m))) +; +;defn condense-mems (c:Circuit) -> Circuit : +; Circuit{info(c),_,main(c)} $ +; for m in modules(c) map : +; match(m) : +; (m:ExModule) : m +; (m:InModule) : condense-mems(m) + +;============= Lower Types ================ +; +public defstruct LowerTypes <: Pass +public defmethod pass (b:LowerTypes) -> (Circuit -> Circuit) : lower-types +public defmethod name (b:LowerTypes) -> String : "Lower Types" +public defmethod short-name (b:LowerTypes) -> String : "lower-types" + +;------------- Utils --------------- +defn is-ground? (t:Type) -> True|False : + match(t) : + (t:UIntType|SIntType) : true + (t) : false +defn data? (ex:Expression) -> True|False : + match(kind(ex)) : + (k:MemKind) : match(ex) : + (ex:WRef|WSubIndex) : false + (ex:WSubField) : + var yes? = switch { _ == name(ex) } : + `wdata : true + `rdata : true + `data : true + `mask : true + else : false + yes? and match(exp(ex)) : + (e:WSubField) : + contains?(ports(kind(e) as MemKind),name(e)) and (exp(e) typeof WRef) + (e) : false + (ex) : false + (k) : false + +defn expand-name (e:Expression) -> List<Symbol> : + val names = Vector<Symbol>() + defn expand-name-e (e:Expression) -> Expression : + match(map(expand-name-e,e)) : + (e:WRef) : add(names,name(e)) + (e:WSubField) : add(names,name(e)) + (e:WSubIndex) : add(names,to-symbol(value(e))) + e + expand-name-e(e) + to-list(names) + + +defn lower-other-mem (e:Expression, dt:Type) -> List<Expression> : + val names = expand-name(e) + if length(names) < 3 : error("Shouldn't be here") + for x in fast-create-exps(names[0],dt) map : + var base = lowered-name(x) + for (x in names,i in 0 to false) do : + if i >= 3 : base = symbol-join([base `_ x]) + val m = WRef(base, UnknownType(), kind(e), UNKNOWN-GENDER) + val p = WSubField(m,to-symbol(names[1]),UnknownType(),UNKNOWN-GENDER) + WSubField(p,to-symbol(names[2]),UnknownType(),UNKNOWN-GENDER) + +defn lower-data-mem (e:Expression) -> Expression : + val names = expand-name(e) + if length(names) < 3 : error("Shouldn't be here") + else : + var base = names[0] + for (x in names,i in 0 to false) do : + if i >= 3 : base = symbol-join([base `_ x]) + val m = WRef(base, UnknownType(), kind(e), UNKNOWN-GENDER) + val p = WSubField(m,to-symbol(names[1]),UnknownType(),UNKNOWN-GENDER) + WSubField(p,to-symbol(names[2]),UnknownType(),UNKNOWN-GENDER) + +defn merge (a:Symbol,b:Symbol,x:Symbol) -> Symbol : symbol-join([a x b]) +defn lowered-name (e:Expression) -> Symbol : + match(e) : + (e:WRef) : name(e) + (e:WSubField) : merge(lowered-name(exp(e)),name(e),`_) + (e:WSubIndex) : merge(lowered-name(exp(e)),to-symbol(value(e)),`_) +defn root-ref (e:Expression) -> WRef : + match(e) : + (e:WRef) : e + (e:WSubField|WSubIndex|WSubAccess) : root-ref(exp(e)) + (e:WIndexer) : root-ref(exps(e)[0]) + +;------------- Pass ------------------ + +defn lower-types (m:Module) -> Module : + val mdt = HashTable<Symbol,Type>(symbol-hash) + defn lower-types (s:Stmt) -> Stmt : + defn lower-mem (e:Expression) -> List<Expression> : + val names = expand-name(e) + if contains?([`data `mask `rdata `wdata `wmask],names[2]) : + list(lower-data-mem(e)) + else : + lower-other-mem(e,mdt[name(root-ref(e))]) + defn lower-types-e (e:Expression) -> Expression : + match(e) : + (e:WRef|UIntValue|SIntValue) : e + (e:WSubField) : + match(kind(e)) : + (k:InstanceKind) : + val names = expand-name(e) + var n = names[1] + for (x in names,i in 0 to false) do : + if i > 1 : n = symbol-join([n `_ x]) + WSubField(root-ref(e),n,type(e),gender(e)) + (k:MemKind) : + if not gender(e) == FEMALE : + lower-mem(e)[0] + else : e + (k) : WRef(lowered-name(e),type(e),kind(e),gender(e)) + (e:WSubIndex) : WRef(lowered-name(e),type(e),kind(e),gender(e)) + (e:DoPrim) : map(lower-types-e,e) + match(map(lower-types-e,s)) : + (s:DefWire|DefPoison) : + if is-ground?(type(s)) : s + else : + val es = fast-create-exps(name(s),type(s)) + Begin $ for (e in es, i in 0 to false) map : + defn replace-type (t:Type) -> Type : type(e) + defn replace-name (n:Symbol) -> Symbol : lowered-name(e) + map{replace-name,_} $ map(replace-type,s) + (s:DefRegister) : + if is-ground?(type(s)) : s + else : + val es = fast-create-exps(name(s),type(s)) + Begin $ for (e in es, i in 0 to false) map : + val init = lower-types-e(fast-create-exps(init(s))[i]) + DefRegister(info(s),lowered-name(e),type(e),clock(s),reset(s),init) + (s:WDefInstance) : + val fields* = for f in fields(type(s) as BundleType) map-append : + val es = fast-create-exps(WRef(name(f),type(f),ExpKind(),flip(f) * MALE)) + for e in es map : + switch { _ == gender(e) } : + MALE : Field(lowered-name(e),DEFAULT,type(f)) + FEMALE : Field(lowered-name(e),REVERSE,type(f)) + WDefInstance(info(s),name(s),module(s),BundleType(fields*)) + (s:DefMemory) : + mdt[name(s)] = data-type(s) + if is-ground?(data-type(s)) : s + else : + val es = fast-create-exps(name(s),data-type(s)) + Begin $ for e in es map : + DefMemory(info(s),lowered-name(e),type(e),depth(s),write-latency(s),read-latency(s),readers(s),writers(s),readwriters(s)) + (s:Connect) : + if kind(loc(s)) typeof MemKind : + val es = lower-mem(loc(s)) + Begin $ for e in es map : + Connect(info(s),e,exp(s)) + else : s + (s) : map(lower-types,s) + + val ports* = + for p in ports(m) map-append : + val es = fast-create-exps(WRef(name(p),type(p),PortKind(),to-gender(direction(p)))) + for e in es map : + Port(info(p),lowered-name(e),to-dir(gender(e)),type(e)) + match(m) : + (m:ExModule) : ExModule(info(m),name(m),ports*) + (m:InModule) : InModule(info(m),name(m),ports*,lower-types(body(m))) + +defn lower-types (c:Circuit) -> Circuit : + Circuit{info(c),_,main(c)} $ + for m in modules(c) map : lower-types(m) + +;============ VERILOG ============== + +public defstruct Verilog <: Pass : + with-output: (() -> False) -> False +public defmethod pass (b:Verilog) -> (Circuit -> Circuit) : emit-verilog{with-output(b),_} +public defmethod name (b:Verilog) -> String : "To Verilog" +public defmethod short-name (b:Verilog) -> String : "To Verilog" + +;============ Utilz ============= +defstruct VIndent +defstruct VRandom +val tab = VIndent() +val ran = VRandom() +defn wref (n:Symbol,t:Type) : WRef(n,t,ExpKind(),UNKNOWN-GENDER) +defn escape (s:String) -> String : + val s* = Vector<String>() + add(s*,"\"");" + var percent = false + for c in s do : + if c == '\n' : + add(s*,"\\n") + else : + if c == 'x' and percent : + add(s*,"h") + else : add(s*,to-string(c)) + percent = c == '%' + add(s*,"\"");" + string-join(s*) +defn remove-root (ex:Expression) -> Expression : + match(exp(ex as WSubField)) : + (e:WSubField) : remove-root(e) + (e:WRef) : WRef(name(ex as WSubField),type(ex),InstanceKind(),UNKNOWN-GENDER) +defn !empty? (s:Vector) -> True|False : + if length(s) == 0 : false + else : true +defn long! (t:Type) -> Long : + match(t) : + (t:UIntType|SIntType) : width(width(t) as IntWidth) + (t:BundleType) : + var w = to-long(0) + for f in fields(t) do : + w = w + long!(type(f)) + w + (t:VectorType) : to-long(size(t)) * long!(type(t)) + +defn rand-string (t:Type) -> Streamable : + val w* = ((long!(t) + to-long(31)) / to-long(32)) + ["{" w* "{" ran "}};"] +defn emit (x:?) : emit(x,0) +defn emit (x:?, top:Int) : + match(x) : + (e:Expression) : + turn-off-debug(false) + match(e) : + (e:DoPrim) : emit(op-stream(e), top + 1) + (e:WRef) : print(e) + (e:WSubField) : print(lowered-name(e)) + (e:WSubAccess) : print-all([lowered-name(exp(e)) "[" lowered-name(index(e)) "]"]) + (e:WSubIndex) : print(e) + (e:UIntValue|SIntValue) : v-print(e) + turn-on-debug(false) + (t:Type) : + match(t) : + (t:UIntType|SIntType) : + val w = long!(t) - to-long(1) + if w > to-long(0) : print-all(["[" w ":0]"]) + else : print("");" + (t:ClockType) : print("");" + (t:VectorType) : + emit(type(t), top + 1) + print-all(["[" size(t) - 1 ":0]"]) + (t) : println(t) + + (p:Direction) : + switch {_ == p} : + INPUT : print("input") + OUTPUT : print("output") + (s:Symbol) : print(s) + (i:Int) : print(i) + (i:Long) : print(i) + (s:String) : print(s) + (t:VIndent) : print(" ") + (r:VRandom) : print("$random") + (s:Streamable) : + for x in s do : + emit(x, top + 1) + if top == 0 : print("\n") + +;------------- PASS ----------------- +defn v-print (e:UIntValue|SIntValue) : + val str = to-string(value(e)) + val out = substring(str,1,length(str) - 1) + print $ string-join $ match(e) : + (e:UIntValue) : [long!(type(e)) "'" out] + (e:SIntValue) : [long!(type(e)) "'s" out] +defn op-stream (doprim:DoPrim) -> Streamable : + defn cast-if (e:Expression) -> ? : + val signed? = for x in args(doprim) any? : type(x) typeof SIntType + if not signed? : e + else : match(type(e)) : + (t:SIntType) : ["$signed(" e ")"] + (t:UIntType) : ["$signed({1'b0," e "})"] + defn cast (e:Expression) -> ? : + match(type(doprim)) : + (t:UIntType) : e + (t:SIntType) : ["$signed(" e ")"] + defn a0 () -> Expression : args(doprim)[0] + defn a1 () -> Expression : args(doprim)[1] + defn a2 () -> Expression : args(doprim)[2] + defn c0 () -> Int : consts(doprim)[0] + defn c1 () -> Int : consts(doprim)[1] + + switch {_ == op(doprim)} : + ADD-OP : [cast-if(a0()) " + " cast-if(a1())] + SUB-OP : [cast-if(a0()) " - " cast-if(a1())] + MUL-OP : [cast-if(a0()) " * " cast-if(a1()) ] + DIV-OP : [cast-if(a0()) " / " cast-if(a1()) ] + MOD-OP : [cast-if(a0()) " % " cast-if(a1()) ] + QUO-OP : [cast-if(a0()) " / " cast-if(a1()) ] + REM-OP : [cast-if(a0()) " % " cast-if(a1()) ] + ADD-WRAP-OP : [cast-if(a0()), " + " cast-if(a1())] + SUB-WRAP-OP : [cast-if(a0()), " - " cast-if(a1())] + LESS-OP : [cast-if(a0()) " < " cast-if(a1())] + LESS-EQ-OP : [cast-if(a0()) " <= " cast-if(a1())] + GREATER-OP : [cast-if(a0()) " > " cast-if(a1())] + GREATER-EQ-OP : [cast-if(a0()) " >= " cast-if(a1())] + NEQUIV-OP : [cast-if(a0()) " != " cast-if(a1())] + EQUIV-OP : [cast-if(a0()) " == " cast-if(a1())] + NEQUAL-OP : [cast-if(a0()) " != " cast-if(a1())] + EQUAL-OP : [cast-if(a0()) " == " cast-if(a1())] + MUX-OP : [a0() " ? " cast(a1()) " : " cast(a2())] + PAD-OP : + val w = long!(type(a0())) + val diff = (to-long(c0()) - w) + if w == to-long(0) : [ a0() ] + else : match(type(doprim)) : + (t:SIntType) : ["{{" diff "{" a0() "[" w - to-long(1) "]}}, " a0() " }"] + (t) : ["{{" diff "'d0 }, " a0() " }"] + AS-UINT-OP : ["$unsigned(" a0() ")"] + AS-SINT-OP : ["$signed(" a0() ")"] + DYN-SHIFT-LEFT-OP : [cast(a0()) " << " a1()] + DYN-SHIFT-RIGHT-OP : + match(type(doprim)) : + (t:SIntType) : [cast(a0()) " >>> " a1()] + (t) : [cast(a0()) " >> " a1()] + SHIFT-LEFT-OP : [cast(a0()) " << " c0()] + SHIFT-RIGHT-OP : [cast(a0()) "[" long!(type(a0())) - to-long(1) ":" c0() "]"] + NEG-OP : ["-{" cast(a0()) "}"] + CONVERT-OP : + match(type(a0())) : + (t:UIntType) : ["{1'b0," cast(a0()) "}"] + (t:SIntType) : [cast(a0())] + BIT-NOT-OP : ["~ " cast(a0())] + BIT-AND-OP : [cast(a0()) " & " cast(a1())] + BIT-OR-OP : [cast(a0()) " | " cast(a1())] + BIT-XOR-OP : [cast(a0()) " ^ " cast(a1())] + CONCAT-OP : ["{" cast(a0()) "," cast(a1()) "}"] + BIT-SELECT-OP : [cast(a0()) "[" c0() "]"] + BITS-SELECT-OP : [cast(a0()) "[" c0() ":" c1() "]"] + BIT-AND-REDUCE-OP : + val v = Vector<Streamable>() + for b in 0 to to-int(long!(type(doprim))) do : + add(v,[cast(a0()) "[" b "]"]) + join(v," & ") + BIT-OR-REDUCE-OP : + val v = Vector<Streamable>() + for b in 0 to to-int(long!(type(doprim))) do : + add(v,[cast(a0() ) "[" b "]"]) + join(v," | ") + BIT-XOR-REDUCE-OP : + val v = Vector<Streamable>() + for b in 0 to to-int(long!(type(doprim))) do : + add(v,[cast(a0() ) "[" b "]"]) + join(v," ^ ") + +defn emit-verilog (m:InModule) -> Module : + val netlist = HashTable<Expression,Expression>(exp-hash) + val simlist = Vector<Stmt>() + val namehash = get-sym-hash(m,keys(v-keywords)) + defn build-netlist (s:Stmt) -> Stmt : + match(s) : + (s:Connect) : netlist[loc(s)] = exp(s) + (s:Conditionally) : add(simlist,s) + (s:DefNode) : + val e = WRef(name(s),get-type(s),NodeKind(),MALE) + netlist[e] = value(s) + (s) : map(build-netlist,s) + s + + val portdefs = Vector<Streamable>() + val declares = Vector<Streamable>() + val assigns = Vector<Streamable>() + val at-clock = HashTable<Expression,Vector<Streamable>>(exp-hash) + val initials = Vector<Streamable>() + val simulates = Vector<Streamable>() + defn declare (b:Symbol,n:Symbol,t:Type) : + match(t) : + (t:VectorType) : add(declares,[b " " type(t) " " n " [0:" size(t) - 1 "];"]) + (t) : add(declares,[b " " t " " n ";"]) + defn assign (e:Expression,value:Expression) : + add(assigns,["assign " e " = " value]) + defn update-and-reset (e:Expression,clk:Expression,reset?:Expression,init:Expression) : + if not key?(at-clock,clk) : + at-clock[clk] = Vector<Streamable>() + add(at-clock[clk],["if(" reset? ") begin"]) + add(at-clock[clk],[tab e " <= " init]) + add(at-clock[clk],["end else"]) + add(at-clock[clk],[tab e " <= " netlist[e]]) + add(at-clock[clk],["end"]) + defn update (e:Expression,value:Expression,clk:Expression,en:Expression) : + if not key?(at-clock,clk) : + at-clock[clk] = Vector<Streamable>() + if en == one : + add(at-clock[clk],[e " <= " value]) + else : + add(at-clock[clk],["if(" en ") begin"]) + add(at-clock[clk],[tab e " <= " value]) + add(at-clock[clk],["end"]) + defn initialize (e:Expression) : + add(initials,[e " = " rand-string(type(e))]) + defn initialize-mem (n:Symbol,i:Int,t:Type) : + add(initials,["for (initvar = 0; initvar < " i "; initvar = initvar+1)"]) + val index = WRef(`initvar,UnknownType(),ExpKind(),UNKNOWN-GENDER) + add(initials,[tab WSubAccess(wref(n,t),index,UnknownType(),FEMALE), " = " rand-string(t)]) + defn instantiate (n:Symbol,m:Symbol,es:List<Expression>) : + add(declares,[m " " n " ("]) + for (e in es,i in 1 to false) do : + val s = [tab "." remove-root(e) "(" lowered-name(e) ")"] + if i == length(es) : add(declares,[s ","]) + else : add(declares,s) + add(declares,[");"]) + for e in es do : + declare(`wire,lowered-name(e),type(e)) + val e* = WRef(lowered-name(e),type(e),kind(e),gender(e)) + if (gender(e) == FEMALE) : assign(e*,netlist[e]) + defn simulate (clk:Expression,en:Expression,s:Streamable) : + if not key?(at-clock,clk) : + at-clock[clk] = Vector<Streamable>() + add(at-clock[clk],["`ifndef SYNTHESIS"]) + add(at-clock[clk],[tab "if(" en ") begin"]) + add(at-clock[clk],[tab tab s]) + add(at-clock[clk],[tab "end"]) + add(at-clock[clk],["`endif"]) + defn stop (ret:Int) -> Streamable : + ["$fdisplay(32/'h80000002," ret ");$finish;"] + defn printf (str:String,args:List<Expression>) -> Streamable : + val str* = join(List(escape(str),args),",") + ["$fdisplay(32/'h80000002," str* ");"] + defn delay (e:Expression, n:Int, clk:Expression) -> Expression : + var e* = e + for i in 0 to n do : + val name = firrtl-gensym(`GEN,namehash) + declare(`reg,name,type(e)) + val e** = WRef(name,type(e),ExpKind(),UNKNOWN-GENDER) + update(e**,e*,clk,one) + e* = e** + e* + defn build-ports () : + for (p in ports(m),i in 0 to false) do : + var end = ",\n" + if length(ports(m)) - 1 == i : + end = "\n);\n" + switch {_ == direction(p)} : + INPUT : + add(portdefs,[direction(p) " " type(p) " " name(p) ]) + OUTPUT : + add(portdefs,[direction(p) " " type(p) " " name(p) ]) + val e* = WRef(name(p),type(p),PortKind(),FEMALE) + assign(e*,netlist[e*]) + if length(ports(m)) == 0 : print(");\n") + defn build-streams (s:Stmt) -> Stmt : + match(s) : + (s:Connect) : s + (s:DefWire) : + declare(`wire,name(s),type(s)) + val e = wref(name(s),type(s)) + assign(e,netlist[e]) + (s:DefRegister) : + declare(`reg,name(s),type(s)) + val e = wref(name(s),type(s)) + update-and-reset(e,clock(s),reset(s),init(s)) + initialize(e) + (s:DefPoison) : + declare(`reg,name(s),type(s)) + val e = wref(name(s),type(s)) + initialize(e) + (s:DefNode) : + declare(`wire,name(s),type(value(s))) + assign(WRef(name(s),type(value(s)),NodeKind(),MALE),value(s)) + (s:Stop) : simulate(clk(s),en(s),stop(ret(s))) + (s:Print) : simulate(clk(s),en(s),printf(string(s),args(s))) + (s:WDefInstance) : + val es = fast-create-exps(WRef(name(s),type(s),InstanceKind(),MALE)) + instantiate(name(s),module(s),es) + (s:DefMemory) : + val mem = WRef(name(s),get-type(s),MemKind(append-all([readers(s) writers(s) readwriters(s)])),UNKNOWN-GENDER) + defn mem-exp (p:Symbol,f:Symbol) : + val t1 = field-type(type(mem),p) + val t2 = field-type(t1,f) + WSubField{_,f,t2,UNKNOWN-GENDER} $ + WSubField{_,p,t1,UNKNOWN-GENDER} $ + mem + + declare(`reg,name(s),VectorType(data-type(s),depth(s))) + initialize-mem(name(s),depth(s),data-type(s)) + for r in readers(s) do : + val data = mem-exp(r,`data) + val addr = mem-exp(r,`addr) + val en = mem-exp(r,`en) + val clk = mem-exp(r,`clk) + + declare(`wire,lowered-name(data),type(data)) + declare(`wire,lowered-name(addr),type(addr)) + declare(`wire,lowered-name(en),type(en)) + declare(`wire,lowered-name(clk),type(clk)) + + ; Read port + assign(addr,netlist[addr]) ;Connects value to m.r.addr + assign(en,netlist[en]) ;Connects value to m.r.en + assign(clk,netlist[clk]) ;Connects value to m.r.clk + val addr* = delay(addr,read-latency(s),clk) + val en* = delay(en,read-latency(s),clk) + val mem-port = WSubAccess(mem,addr*,UnknownType(),UNKNOWN-GENDER) + update(data,mem-port,clk,en*) ; m.r.data <= m[addr*] + + for w in writers(s) do : + val data = mem-exp(w,`data) + val addr = mem-exp(w,`addr) + val mask = mem-exp(w,`mask) + val en = mem-exp(w,`en) + val clk = mem-exp(w,`clk) + + declare(`wire,lowered-name(data),type(data)) + declare(`wire,lowered-name(addr),type(addr)) + declare(`wire,lowered-name(mask),type(mask)) + declare(`wire,lowered-name(en),type(en)) + declare(`wire,lowered-name(clk),type(clk)) + + ; Write port + assign(data,netlist[data]) + assign(addr,netlist[addr]) + assign(mask,netlist[mask]) + assign(en,netlist[en]) + assign(clk,netlist[clk]) + + val data* = delay(data,write-latency(s) - 1,clk) + val addr* = delay(addr,write-latency(s) - 1,clk) + val mask* = delay(mask,write-latency(s) - 1,clk) + val en* = delay(en,write-latency(s) - 1,clk) + val mem-port = WSubAccess(mem,addr*,UnknownType(),UNKNOWN-GENDER) + update(mem-port,data*,clk,AND(en*,mask*)) + + for rw in readwriters(s) do : + val rdata = mem-exp(rw,`rdata) + val raddr = mem-exp(rw,`raddr) + val ren = mem-exp(rw,`ren) + val wdata = mem-exp(rw,`wdata) + val waddr = mem-exp(rw,`waddr) + val wmask = mem-exp(rw,`wmask) + val wen = mem-exp(rw,`wen) + val clk = mem-exp(rw,`clk) + + declare(`wire,lowered-name(rdata),type(rdata)) + declare(`wire,lowered-name(raddr),type(raddr)) + declare(`wire,lowered-name(ren),type(ren)) + declare(`wire,lowered-name(wdata),type(wdata)) + declare(`wire,lowered-name(waddr),type(waddr)) + declare(`wire,lowered-name(wmask),type(wmask)) + declare(`wire,lowered-name(wen),type(wen)) + declare(`wire,lowered-name(clk),type(clk)) + + ; Both + assign(clk,netlist[clk]) + + ; Read + assign(raddr,netlist[raddr]) + assign(ren,netlist[ren]) + val raddr* = delay(raddr,read-latency(s),clk) + val ren* = delay(ren,read-latency(s),clk) + val rmem-port = WSubAccess(mem,raddr*,UnknownType(),UNKNOWN-GENDER) + update(rdata,rmem-port,clk,ren*) + + ; Write + assign(wdata,netlist[wdata]) + assign(waddr,netlist[waddr]) + assign(wmask,netlist[wmask]) + assign(wen,netlist[wen]) + + val wdata* = delay(wdata,write-latency(s) - 1,clk) + val waddr* = delay(waddr,write-latency(s) - 1,clk) + val wmask* = delay(wmask,write-latency(s) - 1,clk) + val wen* = delay(wen,write-latency(s) - 1,clk) + val wmem-port = WSubAccess(mem,waddr*,UnknownType(),UNKNOWN-GENDER) + update(wmem-port,wdata*,clk,AND(wen*,wmask*)) + (s:Begin) : map(build-streams,s) + s + + defn emit-streams () : + emit(["module " name(m) "("]) + if !empty?(portdefs) : + for (x in portdefs, i in 0 to false) do : + if i != length(portdefs) : emit([tab x ","]) + else : emit([tab x]) + emit([");"]) + + if !empty?(declares) : + for x in declares do : emit([tab x]) + + if !empty?(assigns) : + for x in assigns do : emit([tab x]) + + if !empty?(initials) : + emit(["`ifndef SYNTHESIS"]) + emit([" integer initvar;"]) + emit([" initial begin"]) + emit([" #0.002;"]) + for x in initials do : + emit([tab x]) + emit([" end"]) + emit(["`endif"]) + + for clk-stream in at-clock do : + if !empty?(value(clk-stream)) : + emit([tab "always @(posedge " key(clk-stream) ") begin"]) + for x in value(clk-stream) do : + emit([tab tab x]) + emit([tab "end"]) + + emit(["endmodule"]) + + build-netlist(body(m)) + build-ports() + build-streams(body(m)) + emit-streams() + m + +defn emit-verilog (with-output:(() -> False) -> False, c:Circuit) : + with-output $ fn () : + for m in modules(c) do : + match(m) : + (m:InModule) : emit-verilog(m) + (m:ExModule) : false + c + + diff --git a/src/main/stanza/passes.stanza3 b/src/main/stanza/passes.stanza3 new file mode 100644 index 00000000..0dc664e7 --- /dev/null +++ b/src/main/stanza/passes.stanza3 @@ -0,0 +1,2687 @@ +defpackage firrtl/passes : + import core + import verse + import firrtl/ir2 + import firrtl/ir-utils + import firrtl/primops + import firrtl-main + import firrtl/errors + import bigint2 + +;============== Pass List ================ +public val standard-passes = to-list $ [ + CheckHighForm() + ;TempElimination() + ToWorkingIR() + Resolve() + ResolveKinds() + ;CheckKinds() + InferTypes() + ;CheckTypes() + ResolveGenders() + ;CheckGenders() + ;ExpandAccessors() + ;LowerToGround() + ;ExpandIndexedConnects() + ;InlineIndexed() + ExpandWhens() + InferWidths() + ;Inline() + SplitExp() + ;CheckLowForm() + ;ToRealIR() + ;Pad() + ] +;=============== WORKING IR ================================ +public definterface Kind +public defstruct WireKind <: Kind +public defstruct PoisonKind <: Kind +public defstruct RegKind <: Kind +public defstruct InstanceKind <: Kind +public defstruct PortKind <: Kind +public defstruct NodeKind <: Kind +public defstruct MemKind <: Kind : + ports : List<Symbol> +public defstruct ExpKind <: Kind + +public definterface Gender +public val MALE = new Gender +public val FEMALE = new Gender +public val UNKNOWN-GENDER = new Gender +public val BI-GENDER = new Gender + +public defstruct WRef <: Expression : + name: Symbol + type: Type with: (as-method => true) + kind: Kind with: (as-method => true) + gender: Gender with: (as-method => true) +public defstruct WSubField <: Expression : + exp: Expression + name: Symbol + type: Type with: (as-method => true) + gender: Gender with: (as-method => true) +public defstruct WSubIndex <: Expression : + exp: Expression + value: Int + type: Type with: (as-method => true) + gender: Gender with: (as-method => true) +public defstruct WSubAccess <: Expression : + exp: Expression + index: Expression + type: Type with: (as-method => true) + gender: Gender with: (as-method => true) +defstruct WIndexer <: Expression : + exps: List<Expression> + index: Expression + type: Type with: (as-method => true) + gender : Gender with: (as-method => true) +public defstruct WVoid <: Expression +public defstruct WDefInstance <: Stmt : + info: FileInfo with: (as-method => true) + name: Symbol + module: Symbol + type: Type + +defmulti gender (e:Expression) -> Gender +defmethod gender (e:Expression) : + MALE + +defn get-gender (s:Stmt|Port) -> Gender : + match(s) : + (s:DefWire|DefRegister) : BI-GENDER + (s:WDefInstance|DefNode|DefInstance|DefPoison) : MALE + (s:Begin|Connect|BulkConnect|Stop|Print|Empty) : UNKNOWN-GENDER + (s:DefMemory) : FEMALE + (p:Port) : + switch { _ == direction(p) } : + INPUT : MALE + OUTPUT : FEMALE + +public defmulti kind (e:Expression) -> Kind +defmethod kind (e:Expression) : + match(e) : + (e:WRef) : kind(e) + (e:WSubField) : kind(exp(e)) + (e:WSubIndex) : kind(exp(e)) + (e:WIndexer) : + val k = kind(exps(e)[0]) + for x in exps(e) do : + if k != kind(x) : error("All kinds of exps of WIndexer must be the same") + k + (e) : ExpKind() + +defmethod info (stmt:Begin) -> FileInfo : FileInfo() +defmethod info (stmt:Empty) -> FileInfo : FileInfo() + +defmethod type (exp:UIntValue) -> Type : UIntType(width(exp)) +defmethod type (exp:SIntValue) -> Type : SIntType(width(exp)) + +defn get-type (s:Stmt) -> Type : + match(s) : + (s:DefWire|DefPoison|DefRegister|WDefInstance) : type(s) + (s:DefNode) : type(value(s)) + (s:DefMemory) : + val depth = depth(s) + ; Fields + val addr = Field(`addr,DEFAULT,UIntType(IntWidth(ceil-log2(depth)))) + val en = Field(`en,DEFAULT,BoolType()) + val clk = Field(`clk,DEFAULT,ClockType()) + val def-data = Field(`data,DEFAULT,data-type(s)) + val rev-data = Field(`data,REVERSE,data-type(s)) + val rdata = Field(`rdata,REVERSE,data-type(s)) + val wdata = Field(`wdata,DEFAULT,data-type(s)) + val mask = create-mask(`mask,data-type(s)) + val wmask = create-mask(`wmask,data-type(s)) + val ren = Field(`ren,DEFAULT,UIntType(IntWidth(1))) + val wen = Field(`wen,DEFAULT,UIntType(IntWidth(1))) + val raddr = Field(`raddr,DEFAULT,UIntType(IntWidth(ceil-log2(depth)))) + val waddr = Field(`waddr,DEFAULT,UIntType(IntWidth(ceil-log2(depth)))) + + val read-type = BundleType(to-list([rev-data,addr,en,clk])) + val write-type = BundleType(to-list([def-data,mask,addr,en,clk])) + val readwrite-type = BundleType(to-list([wdata,wmask,waddr,wen,rdata,raddr,ren,clk])) + + val mem-fields = Vector<Field>() + for x in readers(s) do : + add(mem-fields,Field(x,DEFAULT,read-type)) + for x in writers(s) do : + add(mem-fields,Field(x,DEFAULT,write-type)) + for x in readwriters(s) do : + add(mem-fields,Field(x,DEFAULT,readwrite-type)) + BundleType(to-list(mem-fields)) + (s:DefInstance) : UnknownType() + (s:Begin|Connect|BulkConnect|Stop|Print|Empty) : UnknownType() + +defmethod equal? (e1:Expression,e2:Expression) -> True|False : + match(e1,e2) : + (e1:UIntValue,e2:UIntValue) : + if value(e1) == value(e2) : width(e1) == width(e2) + else : false + (e1:SIntValue,e2:SIntValue) : + if value(e1) == value(e2) : width(e1) == width(e2) + else : false + (e1:WRef,e2:WRef) : name(e1) == name(e2) + (e1:WSubField,e2:WSubField) : + (name(e1) == name(e2)) and (exp(e1) == exp(e2)) + (e1:WSubIndex,e2:WSubIndex) : + (value(e1) == value(e2)) and (exp(e1) == exp(e2)) + (e1:WSubAccess,e2:WSubAccess) : + (index(e1) == index(e2)) and (exp(e1) == exp(e2)) + (e1:WVoid,e2:WVoid) : true + (e1:WIndexer,e2:WIndexer) : + var bool = (length(exps(e1)) == length(exps(e2))) + for (e1* in exps(e1),e2* in exps(e2)) do : + bool = bool and (e1* == e2*) + bool and (index(e1) == index(e2)) + (e1:DoPrim,e2:DoPrim) : + var are-equal? = op(e1) == op(e2) + for (x in args(e1),y in args(e2)) do : + if not x == y : + are-equal? = false + for (x in consts(e1),y in consts(e2)) do : + if not x == y : + are-equal? = false + are-equal? + (e1,e2) : false + +; ================= PRINTERS =================== +defmethod print (o:OutputStream, g:Gender) : + print{o, _} $ + switch {g == _} : + MALE : "m" + FEMALE: "f" + BI-GENDER : "b" + UNKNOWN-GENDER: "u" + +;============== DEBUG STUFF ============================= +public var PRINT-TYPES : True|False = false +public var PRINT-KINDS : True|False = false +public var PRINT-WIDTHS : True|False = false +public var PRINT-TWIDTHS : True|False = false +public var PRINT-GENDERS : True|False = false +public var PRINT-CIRCUITS : True|False = false +public var PRINT-DEBUG : True|False = false +public var PRINT-INFO : True|False = false + +;========= TO TURN OFF =========== + +var old-PRINT-TYPES : True|False = false +var old-PRINT-KINDS : True|False = false +var old-PRINT-WIDTHS : True|False = false +var old-PRINT-TWIDTHS : True|False = false +var old-PRINT-GENDERS : True|False = false +var old-PRINT-CIRCUITS : True|False = false +var old-PRINT-DEBUG : True|False = false +var old-PRINT-INFO : True|False = false +defmethod turn-off-debug (x:False) : + old-PRINT-TYPES = PRINT-TYPES + old-PRINT-KINDS = PRINT-KINDS + old-PRINT-WIDTHS = PRINT-WIDTHS + old-PRINT-TWIDTHS = PRINT-TWIDTHS + old-PRINT-GENDERS = PRINT-GENDERS + old-PRINT-CIRCUITS = PRINT-CIRCUITS + old-PRINT-DEBUG = PRINT-DEBUG + old-PRINT-INFO = PRINT-INFO + PRINT-TYPES = false + PRINT-KINDS = false + PRINT-WIDTHS = false + PRINT-TWIDTHS = false + PRINT-GENDERS = false + PRINT-CIRCUITS = false + PRINT-DEBUG = false + PRINT-INFO = false + +defmethod turn-on-debug (x:False) : + PRINT-TYPES = old-PRINT-TYPES + PRINT-KINDS = old-PRINT-KINDS + PRINT-WIDTHS = old-PRINT-WIDTHS + PRINT-TWIDTHS = old-PRINT-TWIDTHS + PRINT-GENDERS = old-PRINT-GENDERS + PRINT-CIRCUITS = old-PRINT-CIRCUITS + PRINT-DEBUG = old-PRINT-DEBUG + PRINT-INFO = old-PRINT-INFO + +;=== ThePrinters === + +public defn println-all-debug (l:?) -> False : + if PRINT-DEBUG : println-all(l) + else : false + +public defn println-debug (s:?) -> False : + if PRINT-DEBUG : println(s) + else : false + +defmethod print (o:OutputStream, k:Kind) : + print{o, _} $ + match(k) : + (k:WireKind) : "wire" + (k:PoisonKind) : "poison" + (k:RegKind) : "reg" + (k:PortKind) : "port" + (k:MemKind) : "mem" + (k:NodeKind) : "node" + (k:InstanceKind) : "inst" + (k:ExpKind) : "exp" + +defn hasGender (e:?) : + e typeof Expression + +defn hasWidth (e:?) : + e typeof UIntType|SIntType|UIntValue|SIntValue + +defn hasType (e:?) : + e typeof Expression|DefWire|DefRegister|DefPoison + |VectorType|Port|UIntValue|SIntValue + +defn hasKind (e:?) : + e typeof Expression + +defn hasInfo (e:?) : + e typeof Stmt|Port|Circuit|Module + +defn any-debug? (e:?) : + (hasGender(e) and PRINT-GENDERS) or + (hasType(e) and PRINT-TYPES) or + (hasWidth(e) and PRINT-WIDTHS) or + (hasKind(e) and PRINT-KINDS) or + (hasInfo(e) and PRINT-INFO) + +defmethod print-debug (o:OutputStream, e:Expression|Stmt|Type|Port|Field|Module|Circuit) : + defn wipe-width (t:Type) -> Type : + match(t) : + (t:UIntType) : UIntType(UnknownWidth()) + (t:SIntType) : SIntType(UnknownWidth()) + (t) : map(wipe-width,t) + + if any-debug?(e) : print(o,"@") + if PRINT-KINDS and hasKind(e) : print-all(o,["<k:" kind(e as ?) ">"]) + if PRINT-TYPES and hasType(e) : print-all(o,["<t:" wipe-width(type(e as ?)) ">"]) + if PRINT-TWIDTHS and hasType(e): print-all(o,["<t:" type(e as ?) ">"]) + if PRINT-WIDTHS and hasWidth(e): print-all(o,["<w:" width(e as ?) ">"]) + if PRINT-GENDERS and hasGender(e): print-all(o,["<g:" gender(e as ?) ">"]) + if PRINT-INFO and hasInfo(e): print-all(o,["<i:" info(e as ?) ">"]) + +defmethod print (o:OutputStream, e:WRef) : + print(o,name(e)) + print-debug(o,e as ?) +defmethod print (o:OutputStream, e:WSubField) : + print-all(o,[exp(e) "." name(e)]) + print-debug(o,e as ?) +defmethod print (o:OutputStream, e:WSubIndex) : + print-all(o,[exp(e) "[" value(e) "]"]) + print-debug(o,e as ?) +defmethod print (o:OutputStream, e:WSubAccess) : + print-all(o,[exp(e) "[" index(e) "]"]) + print-debug(o,e as ?) +defmethod print (o:OutputStream, e:WVoid) : + print(o,"VOID") + print-debug(o,e as ?) +defmethod print (o:OutputStream, c:WIndexer) : + print-all(o, [exps(c) "[" index(c) "]"]) + print-debug(o,c as ?) +defmethod print (o:OutputStream, c:WDefInstance) : + print-all(o, ["inst " name(c) " of " module(c) " : " type(c)]) + print-debug(o,c as ?) + + +defmethod map (f: Expression -> Expression, e: WSubField) : + WSubField(f(exp(e)), name(e), type(e), gender(e)) +defmethod map (f: Expression -> Expression, e: WSubIndex) : + WSubIndex(f(exp(e)), value(e), type(e), gender(e)) +defmethod map (f: Expression -> Expression, e: WSubAccess) : + WSubAccess(f(exp(e)), f(index(e)), type(e), gender(e)) + +defmethod map (f: Type -> Type, e: WRef) : + WRef(name(e), f(type(e)), kind(e), gender(e)) +defmethod map (f: Type -> Type, e: WSubField) : + WSubField(exp(e), name(e), f(type(e)), gender(e)) +defmethod map (f: Type -> Type, e: WSubIndex) : + WSubIndex(exp(e), value(e), f(type(e)), gender(e)) +defmethod map (f: Type -> Type, e: WSubAccess) : + WSubAccess(exp(e), index(e), f(type(e)), gender(e)) + +defmethod map (f: Type -> Type, s: WDefInstance) : + WDefInstance(info(s),name(s),module(s),f(type(s))) + +;================ WIDTH LIBRARY ==================== + +public val ONE = IntWidth(1) +public defstruct VarWidth <: Width : + name: Symbol +public defstruct PlusWidth <: Width : + arg1 : Width + arg2 : Width +public defstruct MinusWidth <: Width : + arg1 : Width + arg2 : Width +public defstruct MaxWidth <: Width : + args : List<Width> +public defstruct ExpWidth <: Width : + arg1 : Width +val width-name-hash = HashTable<Symbol,Int>(symbol-hash) + +public defmulti map<?T> (f: Width -> Width, w:?T&Width) -> T +defmethod map (f: Width -> Width, w:Width) -> Width : + match(w) : + (w:MaxWidth) : MaxWidth(map(f,args(w))) + (w:PlusWidth) : PlusWidth(f(arg1(w)),f(arg2(w))) + (w:MinusWidth) : MinusWidth(f(arg1(w)),f(arg2(w))) + (w:ExpWidth) : ExpWidth(f(arg1(w))) + (w) : w + +public defmethod print (o:OutputStream, w:VarWidth) : + print(o,name(w)) +public defmethod print (o:OutputStream, w:MaxWidth) : + print-all(o,["max" args(w)]) +public defmethod print (o:OutputStream, w:PlusWidth) : + print-all(o,[ "(" arg1(w) " + " arg2(w) ")"]) +public defmethod print (o:OutputStream, w:MinusWidth) : + print-all(o,[ "(" arg1(w) " - " arg2(w) ")"]) +public defmethod print (o:OutputStream, w:ExpWidth) : + print-all(o,[ "exp(" arg1(w) ")"]) + +defn remove-unknowns-w (w:Width) -> Width : + match(w) : + (w:UnknownWidth) : VarWidth(firrtl-gensym(`w,width-name-hash)) + (w) : w +defn remove-unknowns (t:Type) -> Type : mapr(remove-unknowns-w,t) + +defmethod equal? (w1:Width,w2:Width) -> True|False : + match(w1,w2) : + (w1:VarWidth,w2:VarWidth) : name(w1) == name(w2) + (w1:MaxWidth,w2:MaxWidth) : + label<True|False> ret : + if not length(args(w1)) == length(args(w2)) : ret(false) + else : + for w in args(w1) do : + if not contains?(args(w2),w) : ret(false) + ret(true) + (w1:IntWidth,w2:IntWidth) : width(w1) == width(w2) + (w1:PlusWidth,w2:PlusWidth) : + (arg1(w1) == arg1(w2) and arg2(w1) == arg2(w2)) or (arg1(w1) == arg2(w2) and arg2(w1) == arg1(w2)) + (w1:MinusWidth,w2:MinusWidth) : + (arg1(w1) == arg1(w2) and arg2(w1) == arg2(w2)) or (arg1(w1) == arg2(w2) and arg2(w1) == arg1(w2)) + (w1:ExpWidth,w2:ExpWidth) : arg1(w1) == arg1(w2) + (w1:UnknownWidth,w2:UnknownWidth) : true + (w1,w2) : false +;================ WORKING IR UTILS ========================= +;defn plus (g1:Gender,g2:Gender) -> Gender : +; switch fn ([x,y]) : g1 == x and g2 == y : +; [FEMALE,MALE] : UNKNOWN-GENDER +; [MALE,FEMALE] : UNKNOWN-GENDER +; [MALE,MALE] : MALE +; [FEMALE,FEMALE] : FEMALE +; [BI-GENDER,MALE] : MALE +; [BI-GENDER,FEMALE] : FEMALE +; [MALE,BI-GENDER] : MALE +; [FEMALE,BI-GENDER] : FEMALE + +; These functions do not error, but return Unknown Type +defn module-type (m:Module) -> Type : + BundleType(for p in ports(m) map : to-field(p)) +defn field-type (v:Type,s:Symbol) -> Type : + match(v) : + (v:BundleType) : + val ft = for p in fields(v) find : name(p) == s + if ft != false : type(ft as Field) + else : UnknownType() + (v) : UnknownType() +defn sub-type (v:Type) -> Type : + match(v) : + (v:VectorType) : type(v) + (v) : UnknownType() +defn field-flip (v:Type,s:Symbol) -> Flip : + match(v) : + (v:BundleType) : + val ft = for p in fields(v) find : name(p) == s + if ft != false : flip(ft as Field) + else : DEFAULT ;This will get caught later + (v) : DEFAULT + +defn swap (g:Gender) -> Gender : + switch {_ == g} : + UNKNOWN-GENDER : UNKNOWN-GENDER + MALE : FEMALE + FEMALE : MALE + BI-GENDER : BI-GENDER +defn swap (f:Flip) -> Flip : + switch {_ == f} : + DEFAULT : REVERSE + REVERSE : DEFAULT +defn swap (d:Direction) -> Direction : + switch {_ == d} : + OUTPUT : INPUT + INPUT : OUTPUT + +public defn times (flip:Flip,d:Direction) -> Direction : + flip * d +public defn times (d:Direction,flip:Flip) -> Direction : + switch {_ == flip} : + DEFAULT : d + REVERSE : swap(d) +public defn times (g:Gender,flip:Flip) -> Gender : flip * g +public defn times (flip:Flip,g:Gender) -> Gender : + switch {_ == flip} : + DEFAULT : g + REVERSE : swap(g) +public defn times (f1:Flip,f2:Flip) -> Flip : + switch {_ == f2} : + DEFAULT : f1 + REVERSE : swap(f1) + +defn to-field (p:Port) -> Field : + if direction(p) == OUTPUT : Field(name(p),DEFAULT,type(p)) + else if direction(p) == INPUT : Field(name(p),REVERSE,type(p)) + else : error("Shouldn't be here") +defn to-dir (g:Gender) -> Direction : + switch {_ == g} : + MALE : INPUT + FEMALE : OUTPUT +defn to-gender (d:Direction) -> Gender : + switch {_ == d} : + INPUT: MALE + OUTPUT: FEMALE + +;================= Remove Special Characters ======================== +; Returns a new Circuit where all names have all special characters +; removed, except _. +; +;public defstruct RemoveSpecialChars <: Pass +;public defmethod pass (b:RemoveSpecialChars) -> (Circuit -> Circuit) : remove-special-chars +;public defmethod name (b:RemoveSpecialChars) -> String : "Remove Special Characters" +;public defmethod short-name (b:RemoveSpecialChars) -> String : "rem-spec-chars" +; +;;------------ Helper Functions ------------- +; +;defn get-new-string (n:Char) -> String : +; switch {n == _} : +; '_' : "__" +; '~' : "$A" +; '!' : "$B" +; '@' : "$C" +; '#' : "$D" +; '$' : "$E" +; '%' : "$F" +; '^' : "$G" +; '*' : "$H" +; '-' : "$I" +; '+' : "$J" +; '=' : "$K" +; '?' : "$L" +; '/' : "$M" +; else : to-string(n) +; +;;------------ Pass ------------------ +; +;defn remove-special-chars (c:Circuit) : +; defn rename (n:Symbol) -> Symbol : +; val v = Vector<String>() +; for c in to-string(n) do : +; add(v,get-new-string(c)) +; val n* = symbol-join(v) +; if key?(v-keywords,n*) : +; symbol-join([n* `_]) +; else : +; n* +; defn rename-t (t:Type) -> Type : +; match(t) : +; (t:BundleType) : BundleType $ +; for f in fields(t) map : +; Field(rename(name(f)),flip(f),rename-t(type(f))) +; (t:VectorType) : VectorType(rename-t(type(t)),size(t)) +; (t) : t +; defn rename-e (e:Expression) -> Expression : +; match(e) : +; (e:Ref) : Ref(rename(name(e)),rename-t(type(e))) +; (e:Subfield) : Subfield(rename-e(exp(e)),rename(name(e)),rename-t(type(e))) +; (e:Index) : Index(rename-e(exp(e)),value(e),rename-t(type(e))) +; (e:DoPrim) : DoPrim{op(e),_,consts(e),rename-t(type(e))} $ for x in args(e) map : rename-e(x) +; (e:UIntValue) : e +; (e:SIntValue) : e +; defn rename-s (s:Stmt) -> Stmt : +; match(s) : +; (s:DefWire) : DefWire(info(s),rename(name(s)),rename-t(type(s))) +; (s:DefPoison) : DefPoison(info(s),rename(name(s)),rename-t(type(s))) +; (s:DefRegister) : DefRegister(info(s),rename(name(s)),rename-t(type(s)),rename-e(clock(s)),rename-e(reset(s))) +; (s:WDefInstance) : WDefInstance(info(s),rename(name(s)),rename-e(module(s))) +; (s:DefMemory) : DefMemory(info(s),rename(name(s)),rename-t(type(s)),seq?(s),rename-e(clock(s)),size(s)) +; (s:DefNode) : DefNode(info(s),rename(name(s)),rename-e(value(s))) +; (s:DefAccessor) : DefAccessor(info(s),rename(name(s)),rename-e(source(s)),rename-e(index(s)),acc-dir(s)) +; (s:Conditionally) : Conditionally(info(s),rename-e(pred(s)),rename-s(conseq(s)),rename-s(alt(s))) +; (s:Begin) : Begin $ for b in body(s) map : rename-s(b) +; (s:OnReset) : OnReset(info(s),rename-e(loc(s)),rename-e(exp(s))) +; (s:BulkConnect) : BulkConnect(info(s),rename-e(loc(s)),rename-e(exp(s))) +; (s:Connect) : Connect(info(s),rename-e(loc(s)),rename-e(exp(s))) +; (s:EmptyStmt) : s +; (s:StopStmt) : s +; (s:PrintfStmt) : PrintfStmt(info(s),string(s),map(rename-e,args(s))) +; +; Circuit(info(c),modules*, rename(main(c))) where : +; val modules* = +; for m in modules(c) map : +; match(m) : +; (m:InModule) : +; val ports* = for p in ports(m) map : +; Port(info(p),rename(name(p)),direction(p),rename-t(type(p))) +; InModule(info(m),rename(name(m)), ports*, rename-s(body(m))) +; (m:ExModule) : m + + +;================= 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) : +; defn is-temp? (n:Symbol) -> True|False : +; to-string(n)[0] == 'T' +; defn temp-elim (m:InModule) : +; val h = HashTable<Symbol,Expression>(symbol-hash) +; defn temp-elim-e (e:Expression) : +; match(map(temp-elim-e,e)) : +; (e:Ref) : +; if key?(h,name(e)) : h[name(e)] +; else : e +; (e) : e +; defn temp-elim-s (s:Stmt) : +; match(map(temp-elim-e,s)) : +; (s:DefNode) : +; if is-temp?(name(s)) : +; h[name(s)] = value(s) +; EmptyStmt() +; else : s +; (s) : map(temp-elim-s,s) +; InModule(info(m),name(m), ports(m), temp-elim-s(body(m))) +; +; Circuit(info(c),modules*, main(c)) where : +; val modules* = +; for m in modules(c) map : +; match(m) : +; (m:InModule) : temp-elim(m) +; (m:ExModule) : m + +;================= Bring to Working IR ======================== +; 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) -> Expression : + match(map(to-exp,e)) : + (e:Ref) : WRef(name(e), type(e), NodeKind(), UNKNOWN-GENDER) + (e:SubField) : WSubField(exp(e), name(e), type(e), UNKNOWN-GENDER) + (e:SubIndex) : WSubIndex(exp(e), value(e), type(e), UNKNOWN-GENDER) + (e:SubAccess) : WSubAccess(exp(e), index(e), type(e), UNKNOWN-GENDER) + (e) : e + defn to-stmt (s:Stmt) -> Stmt : + match(map(to-exp,s)) : + (s:DefInstance) : WDefInstance(info(s),name(s),module(s),UnknownType()) + (s) : map(to-stmt,s) + + Circuit(info(c),modules*, main(c)) where : + val modules* = + for m in modules(c) map : + match(m) : + (m:InModule) : InModule(info(m),name(m), ports(m), to-stmt(body(m))) + (m:ExModule) : m + +;=============== Resolve Kinds ============================= +; It is useful for the compiler to know information about +; 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>) : + defn resolve-stmt (s:Stmt) -> Stmt : + map{resolve-expr,_} $ + map(resolve-stmt,s) + + defn resolve-expr (e:Expression) -> Expression : + match(e) : + (e:WRef) : WRef(name(e),type(e),kinds[name(e)],gender(e)) + (e) : map(resolve-expr,e) + + resolve-stmt(body) + + defn find (m:Module, kinds:HashTable<Symbol,Kind>) : + defn find-stmt (s:Stmt) -> Stmt : + match(s) : + (s:DefWire) : kinds[name(s)] = WireKind() + (s:DefPoison) : kinds[name(s)] = PoisonKind() + (s:DefNode) : kinds[name(s)] = NodeKind() + (s:DefRegister) : kinds[name(s)] = RegKind() + (s:WDefInstance) : kinds[name(s)] = InstanceKind() + (s:DefMemory) : kinds[name(s)] = MemKind(append-all([readers(s) writers(s) readwriters(s)])) + (s) : false + map(find-stmt,s) + + for p in ports(m) do : + kinds[name(p)] = PortKind() + match(m) : + (m:InModule) : find-stmt(body(m)) + (m:ExModule) : false + + defn resolve-kinds (m:Module, c:Circuit) -> Module : + val kinds = HashTable<Symbol,Kind>(symbol-hash) + find(m,kinds) + match(m) : + (m:InModule) : + val body! = resolve(body(m),kinds) + InModule(info(m),name(m),ports(m),body!) + (m:ExModule) : ExModule(info(m),name(m),ports(m)) + + Circuit(info(c),modules*, main(c)) where : + val modules* = + for m in modules(c) map : + resolve-kinds(m,c) + +;============== INFER TYPES ================================ + +; ------------------ Utils ------------------------- + +defn set-type (s:Stmt,t:Type) -> Stmt : + match(s) : + (s:DefWire) : DefWire(info(s),name(s),t) + (s:DefRegister) : DefRegister(info(s),name(s),t,clock(s),reset(s),init(s)) + (s:DefMemory) : DefMemory(info(s),name(s),t,depth(s),write-latency(s),read-latency(s),readers(s),writers(s),readwriters(s)) + (s:DefNode) : s + (s:DefPoison) : DefPoison(info(s),name(s),t) + + +; ------------------ 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 infer-types (c:Circuit) -> Circuit : + val module-types = HashTable<Symbol,Type>(symbol-hash) + defn infer-types (m:Module) -> Module : + val types = HashTable<Symbol,Type>(symbol-hash) + defn infer-types-e (e:Expression) -> Expression : + match(map(infer-types-e,e)) : + (e:WRef) : WRef(name(e), types[name(e)],kind(e),gender(e)) + (e:WSubField) : WSubField(exp(e),name(e),field-type(type(exp(e)),name(e)),gender(e)) + (e:WSubIndex) : WSubIndex(exp(e),value(e),sub-type(type(exp(e))),gender(e)) + (e:WSubAccess) : WSubAccess(exp(e),index(e),sub-type(type(exp(e))),gender(e)) + (e:DoPrim) : set-primop-type(e) + (e:UIntValue|SIntValue) : e + defn infer-types-s (s:Stmt) -> Stmt : + match(s) : + (s:DefRegister) : + val t = remove-unknowns(get-type(s)) + types[name(s)] = t + map(infer-types-e,set-type(s,t)) + (s:DefWire|DefPoison|DefNode) : + val s* = map(infer-types-e,s) + val t = remove-unknowns(get-type(s*)) + types[name(s*)] = t + set-type(s*,t) + (s:DefMemory) : + val t = remove-unknowns(get-type(s)) + types[name(s)] = t + val dt = remove-unknowns(data-type(s)) + set-type(s,dt) + (s:WDefInstance) : + types[name(s)] = module-types[module(s)] + WDefInstance(info(s),name(s),module(s),module-types[module(s)]) + (s) : map{infer-types-e,_} $ map(infer-types-s,s) + for p in ports(m) do : + types[name(p)] = type(p) + match(m) : + (m:InModule) : + InModule(info(m),name(m),ports(m),infer-types-s(body(m))) + (m:ExModule) : m + + ; MAIN + val modules* = + for m in modules(c) map : + val ports* = + for p in ports(m) map : + Port(info(p),name(p),direction(p),remove-unknowns(type(p))) + match(m) : + (m:InModule) : InModule(info(m),name(m),ports*,body(m)) + (m:ExModule) : ExModule(info(m),name(m),ports*) + + for m in modules* do : + module-types[name(m)] = module-type(m) + Circuit{info(c), _, main(c) } $ + for m in modules* map : + infer-types(m) + +;============= RESOLVE GENDER ============================ +; To ensure a proper circuit, we must ensure that assignments +; only work on expressions that can be assigned to. Similarly, +; we must ensure that only expressions that can be read from +; are used to assign from. This invariant requires each +; expression's gender to be inferred. +; Various elements can be bi-gender (e.g. wires) and can +; thus be treated as either female or male. Conversely, some +; elements are single-gender (e.g. accessors, ports). +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" + +defn resolve-genders (c:Circuit) : + defn resolve-e (e:Expression,g:Gender) -> Expression : + match(e) : + (e:WRef) : WRef(name(e),type(e),kind(e),g) + (e:WSubField) : + val exp* = + switch { _ == field-flip(type(exp(e)),name(e)) } : + DEFAULT : resolve-e(exp(e),g) + REVERSE : resolve-e(exp(e),swap(g)) + WSubField(exp*,name(e),type(e),g) + (e:WSubIndex) : + val exp* = resolve-e(exp(e),g) + WSubIndex(exp*,value(e),type(e),g) + (e:WSubAccess) : + val exp* = resolve-e(exp(e),g) + val index* = resolve-e(index(e),MALE) + WSubAccess(exp*,index*,type(e),g) + (e:WIndexer) : + val exps* = map(resolve-e{_,g},exps(e)) + val index* = resolve-e(index(e),MALE) + WIndexer(exps*,index*,type(e),g) + (e) : map(resolve-e{_,g},e) + + defn resolve-s (s:Stmt) -> Stmt : + match(s) : + (s:Connect) : + val loc* = resolve-e(loc(s),FEMALE) + val exp* = resolve-e(exp(s),MALE) + Connect(info(s),loc*,exp*) + (s:BulkConnect) : + val loc* = resolve-e(loc(s),FEMALE) + val exp* = resolve-e(exp(s),MALE) + BulkConnect(info(s),loc*,exp*) + (s) : + map{resolve-s,_} $ map(resolve-e{_,MALE},s) + Circuit(info(c),modules*, main(c)) where : + val modules* = + for m in modules(c) map : + match(m) : + (m:InModule) : + val body* = resolve-s(body(m)) + InModule(info(m),name(m),ports(m),body*) + (m:ExModule) : m + +;;============== EXPAND ACCESSORS ================================ +; This pass expands non-memory accessors into DecFromIndexer or +; ConnectFromIndexed. All elements of the vector are +; explicitly written out, then indexed. Depending on the gender +; of the accessor, it is transformed into DecFromIndexer (male) or +; DecToIndexer (female) + +;public defstruct ExpandAccesses <: Pass +;public defmethod pass (b:ExpandAccesses) -> (Circuit -> Circuit) : expand-accesses +;public defmethod name (b:ExpandAccesses) -> String : "Expand Accesses" +;public defmethod short-name (b:ExpandAccesses) -> String : "expand-accesses" +; + +defn expand-vector (e:Expression,g:Gender) -> List<Expression> : + val t = type(e) as VectorType + for i in 0 to size(t) map-append : + list(WSubIndex(e,i,type(t),g)) ;always be WRef|WSubField|WSubIndex + + + +;================ EXPAND CONNECTS ================== +public defstruct ExpandConnects <: Pass +public defmethod pass (b:ExpandConnects) -> (Circuit -> Circuit) : expand-connects +public defmethod name (b:ExpandConnects) -> String : "Expand Connects" +public defmethod short-name (b:ExpandConnects) -> String : "expand-connects" + +;---------------- UTILS ------------------ +val hashed-get-flip = HashTable<TIF,Flip>(tif-hash) +val hashed-create-exps = HashTable<Expression,List<Expression>>(exp-hash) +val hashed-locations = HashTable<Expression,List<Location>>(exp-hash) +;defn clear-hashes () : +; hashed-get-flip = HashTable<TIF,Flip>(tif-hash) +; hashed-create-exps = HashTable<Expression,List<Expression>>(exp-hash) +; hashed-locations = HashTable<Expression,List<Location>>(exp-hash) + +defn get-size (e:Expression) -> Int : get-size(type(e)) +defn get-size (t:Type) -> Int : + match(t) : + (t:BundleType) : + var sum = 0 + for f in fields(t) do : + sum = sum + get-size(type(f)) + sum + (t:VectorType) : size(t) * get-size(type(t)) + (t) : 1 +defstruct TIF : + type : Type + int : Int + flip : Flip +defn tif-hash (tif:TIF) -> Int : + turn-off-debug(false) + val i = symbol-hash(to-symbol(string-join(map(to-string,list(type(tif) int(tif) flip(tif)))))) + turn-on-debug(false) + i + +defn get-flip (t:Type, i:Int, f:Flip) -> Flip : + if key?(hashed-get-flip,TIF(t,i,f)) : hashed-get-flip[TIF(t,i,f)] + else : + if i >= get-size(t) : error("Shouldn't be here") + val x = match(t) : + (t:UIntType|SIntType|ClockType) : f + (t:BundleType) : label<Flip> ret : + var n = i + for x in fields(t) do : + if n < get-size(type(x)) : + ret(get-flip(type(x),n,flip(x) * f)) + else : + n = n - get-size(type(x)) + error("Shouldn't be here") + (t:VectorType) : label<Flip> ret : + var n = i + for j in 0 to size(t) do : + if n < get-size(type(t)) : + ret(get-flip(type(t),n,f)) + else : + n = n - get-size(type(t)) + error("Shouldn't be here") + hashed-get-flip[TIF(t,i,f)] = x + x + +defn get-point (e:Expression) -> Int : + match(e) : + (e:WRef) : 0 + (e:WSubField) : + var i = 0 + for f in fields(type(exp(e)) as BundleType) find : + val b = name(f) == name(e) + if not b : i = i + get-size(type(f)) + b + i + (e:WSubIndex) : + value(e) * get-size(e) + (e:WSubAccess) : + get-point(exp(e)) +defn get-valid-points (t1:Type,t2:Type,flip1:Flip,flip2:Flip) -> List<[Int,Int]> : + ;println-all(["Inside with t1:" t1 ",t2:" t2 ",f1:" flip1 ",f2:" flip2]) + match(t1,t2) : + (t1:UIntType,t2:UIntType) : + if flip1 == flip2 : list([0, 0]) + else: list() + (t1:SIntType,t2:SIntType) : + if flip1 == flip2 : list([0, 0]) + else: list() + (t1:BundleType,t2:BundleType) : + val points = Vector<[Int,Int]>() + var ilen = 0 + var jlen = 0 + for i in 0 to length(fields(t1)) do : + for j in 0 to length(fields(t2)) do : + ;println(i) + ;println(j) + ;println(ilen) + ;println(jlen) + val f1 = fields(t1)[i] + val f2 = fields(t2)[j] + if name(f1) == name(f2) : + val ls = get-valid-points(type(f1),type(f2),flip1 * flip(f1), + flip2 * flip(f2)) + for x in ls do : + add(points,[x[0] + ilen, x[1] + jlen]) + println(points) + jlen = jlen + get-size(type(fields(t2)[j])) + ilen = ilen + get-size(type(fields(t1)[i])) + jlen = 0 + to-list(points) + (t1:VectorType,t2:VectorType) : + val points = Vector<[Int,Int]>() + var ilen = 0 + var jlen = 0 + for i in 0 to min(size(t1),size(t2)) do : + val ls = get-valid-points(type(t1),type(t2),flip1,flip2) + for x in ls do : + add(points,[x[0] + ilen, x[1] + jlen]) + ilen = ilen + get-size(type(t1)) + jlen = jlen + get-size(type(t2)) + to-list(points) + + +defn create-exps (n:Symbol, t:Type) -> List<Expression> : + create-exps(WRef(n,t,ExpKind(),UNKNOWN-GENDER)) +defn create-exps (e:Expression) -> List<Expression> : + match(type(e)) : + (t:UIntType|SIntType|ClockType) : list(e) + (t:BundleType) : + for f in fields(t) map-append : + create-exps(WSubField(e,name(f),type(f),gender(e) * flip(f))) + (t:VectorType) : + for i in 0 to size(t) map-append : + create-exps(WSubIndex(e,i,type(t),gender(e))) + +defn fast-create-exps (n:Symbol, t:Type) -> List<Expression> : + fast-create-exps(WRef(n,t,ExpKind(),UNKNOWN-GENDER)) +defn fast-create-exps (e:Expression) -> List<Expression> : + if key?(hashed-create-exps,e) : hashed-create-exps[e] + else : + val es = Vector<Expression>() + defn create-exps (e:Expression) -> False : + match(type(e)) : + (t:UIntType|SIntType|ClockType) : add(es,e) + (t:BundleType) : + for f in fields(t) do : + create-exps(WSubField(e,name(f),type(f),gender(e) * flip(f))) + (t:VectorType) : + for i in 0 to size(t) do : + create-exps(WSubIndex(e,i,type(t),gender(e))) + create-exps(e) + val x = to-list(es) + hashed-create-exps[e] = x + x + +;---------------- Pass --------------------- + +defn expand-connects (c:Circuit) -> Circuit : + defn expand-connects (m:InModule) -> InModule : + ;clear-hashes() + defn expand-s (s:Stmt) -> Stmt : + match(s) : + (s:Connect) : + val n = get-size(loc(s)) + val connects = Vector<Stmt>() + val locs = fast-create-exps(loc(s)) + val exps = fast-create-exps(exp(s)) + for i in 0 to n do : + val loc* = locs[i] + val exp* = exps[i] + add{connects,_} $ + switch { _ == get-flip(type(loc(s)),i,DEFAULT) } : + DEFAULT : Connect(info(s),loc*,exp*) + REVERSE : Connect(info(s),exp*,loc*) + Begin(to-list(connects)) + (s:BulkConnect) : + val ls = get-valid-points(type(loc(s)),type(exp(s)),DEFAULT,DEFAULT) + val connects = Vector<Stmt>() + val locs = fast-create-exps(loc(s)) + val exps = fast-create-exps(exp(s)) + for x in ls do : + val loc* = locs[x[0]] + val exp* = exps[x[1]] + add{connects,_} $ + switch { _ == get-flip(type(loc(s)),x[0],DEFAULT) } : + DEFAULT : Connect(info(s),loc*,exp*) + REVERSE : Connect(info(s),exp*,loc*) + Begin(to-list(connects)) + (s) : map(expand-s,s) + + + InModule(info(m),name(m),ports(m),expand-s(body(m))) + + Circuit(info(c),modules*, main(c)) where : + val modules* = + for m in modules(c) map : + match(m) : + (m:ExModule) : m + (m:InModule) : expand-connects(m) + + +;;;================ REPLACE INDEXERS ========================= +; This pass inlines all accessors to non-memory vector typed +; components. + +public defstruct RemoveAccesses <: Pass +public defmethod pass (b:RemoveAccesses) -> (Circuit -> Circuit) : remove-access +public defmethod name (b:RemoveAccesses) -> String : "Remove Accesses" +public defmethod short-name (b:RemoveAccesses) -> String : "remove-access" + +defstruct Location : + base : Expression + guard : Expression +defmethod print (o:OutputStream,x:Location) : + print-all(o,["[" base(x) " , " guard(x) "]"]) + +defn get-locations (e:Expression) -> List<Location> : + if key?(hashed-locations,e) : hashed-locations[e] + else : + val x = match(e) : + (e:WRef) : map(Location{_,one},fast-create-exps(e)) + (e:WSubIndex|WSubField) : + val ls = get-locations(exp(e)) + val start = get-point(e) + val end = start + get-size(e) + val stride = get-size(exp(e)) + val ls* = Vector<Location>() + var c = 0 + for i in 0 to length(ls) do : + if (i % stride >= start and i % stride < end) : + add(ls*,ls[i]) + to-list(ls*) + (e:WSubAccess) : + val ls = get-locations(exp(e)) + val stride = get-size(e) + val wrap = size(type(exp(e)) as VectorType) + val ls* = Vector<Location>() + var c = 0 + for i in 0 to length(ls) do : + if c % wrap == 0 : c = 0 + val base* = base(ls[i]) + val guard* = AND(guard(ls[i]),EQV(uint(c),index(e))) + add(ls*,Location(base*,guard*)) + if (i + 1) % stride == 0 : c = c + 1 + to-list(ls*) + hashed-locations[e] = x + x + +defn remove-access (c:Circuit) : + defn remove-m (m:InModule) -> InModule : + val sh = get-sym-hash(m,keys(v-keywords)) + ;clear-hashes() + defn remove-s (s:Stmt) -> Stmt : + val stmts = Vector<Stmt>() + defn create-temp (e:Expression) -> Expression : + val n = firrtl-gensym(`GEN,sh) + add(stmts,DefWire(info(s),n,type(e))) + WRef(n,type(e),kind(e),gender(e)) + defn remove-e (e:Expression) -> Expression : ;NOT RECURSIVE (except primops) INTENTIONALLY! + match(e) : + (e:DoPrim) : map(remove-e,e) + (e:UIntValue|SIntValue) : e + (e) : + val rs = get-locations(e) + val foo = for x in rs find : + (guard(x)) != one + if foo == false : e + else : + val temp = create-temp(e) + for (x in rs, i in 0 to false) do : + if i == 0 : + add(stmts,Connect(info(s),temp,base(x))) + else : + add(stmts,Conditionally(info(s),guard(x),Connect(info(s),temp,base(x)),Empty())) + temp + val s* = match(s) : + (s:Connect) : + val ls = get-locations(loc(s)) + val loc* = + if length(ls) == 1 and guard(head(ls)) == one : loc(s) + else : + val temp = create-temp(loc(s)) + for x in ls do : + add(stmts,Conditionally(info(s),guard(x),Connect(info(s),base(x),temp),Empty())) + temp + Connect(info(s),loc*,remove-e(exp(s))) + (s) : map{remove-s,_} $ map(remove-e,s) + add(stmts,s*) + if length(stmts) != 1 : Begin(to-list(stmts)) + else : stmts[0] + + InModule(info(m),name(m),ports(m),remove-s(body(m))) + + Circuit(info(c),modules*, main(c)) where : + val modules* = + for m in modules(c) map : + match(m) : + (m:ExModule) : m + (m:InModule) : remove-m(m) + +;;================ EXPAND WHENS ============================= +; This pass does three things: remove last connect semantics, +; remove conditional blocks, and eliminate concept of scoping. + +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" + +; ========== Expand When Utilz ========== + +defn get-entries (hash:HashTable<Expression,Expression>,exps:Streamable<Expression>) -> HashTable<Expression,Expression> : + val hash* = HashTable<Expression,Expression>(exp-hash) + for e in exps do : + val value = get?(hash,e,false) + match(value) : + (value:Expression) : hash*[e] = value + (value:False) : false + hash* +defn get-female-refs (n:Symbol,t:Type,g:Gender) -> List<Expression> : + val exps = fast-create-exps(WRef(n,t,ExpKind(),g)) + val exps* = Vector<Expression>() + for i in 0 to length(exps) do : + switch { _ == get-gender(t,i,g)} : + BI-GENDER : add(exps*,exps[i]) + FEMALE : add(exps*,exps[i]) + else : false + to-list(exps*) +defn get-gender (t:Type, i:Int, g:Gender) -> Gender : + val f = get-flip(t,i,DEFAULT) + g * f +defn print-hash (h:HashTable<Expression,Expression>) : + for x in h do : + println(x) + +; ------------ Pass ------------------- +defn expand-whens (c:Circuit) -> Circuit : + defn void-all (m:InModule) -> InModule : + ;clear-hashes() + defn void-all-s (s:Stmt) -> Stmt : + match(s) : + (s:DefWire|DefRegister|WDefInstance|DefMemory) : + val voids = Vector<Stmt>() + for e in get-female-refs(name(s),get-type(s),get-gender(s)) do : + add(voids,Connect(info(s),e,WVoid())) + Begin(List(s,to-list(voids))) + (s) : map(void-all-s,s) + val voids = Vector<Stmt>() + for p in ports(m) do : + for e in get-female-refs(name(p),type(p),get-gender(p)) do : + add(voids,Connect(info(p),e,WVoid())) + val body* = void-all-s(body(m)) + InModule(info(m),name(m),ports(m),Begin(list(Begin(to-list(voids)),body*))) + + defn expand-whens (m:InModule) -> [HashTable<Expression,Expression> Vector<Stmt>] : + val simlist = Vector<Stmt>() + defn expand-whens (s:Stmt,netlist:HashTable<Expression,Expression>,p:Expression) -> Stmt : + match(s) : + (s:Connect) : netlist[loc(s)] = exp(s) + (s:Conditionally) : + val exps = Vector<Expression>() + defn prefetch (s:Stmt) -> Stmt: + match(s) : + (s:Connect) : + add(exps,loc(s)) + s + (s) : map(prefetch,s) + prefetch(conseq(s)) + val c-netlist = get-entries(netlist,exps) + expand-whens(conseq(s),c-netlist,AND(p,pred(s))) + expand-whens(alt(s),netlist,AND(p,NOT(pred(s)))) + for lvalue in keys(c-netlist) do : + val value = get?(netlist,lvalue,false) + match(value) : + (value:Expression) : + netlist[lvalue] = MUX(pred(s),c-netlist[lvalue],value) + (value:False) : + netlist[lvalue] = c-netlist[lvalue] + (s:Print) : + if p == one : add(simlist,s) + else : add(simlist,Print(info(s),string(s),args(s),clk(s),AND(p,en(s)))) + (s:Stop) : + if p == one : add(simlist,s) + else : add(simlist,Stop(info(s),ret(s),clk(s),AND(p,en(s)))) + (s) : map(expand-whens{_,netlist,p},s) + s + val netlist = HashTable<Expression,Expression>(exp-hash) + expand-whens(body(m),netlist,one) + + ;println("Netlist:") + ;println(netlist) + ;println("Simlist:") + ;println(simlist) + [ netlist simlist ] + + defn create-module (netlist:HashTable<Expression,Expression>,simlist:Vector<Stmt>,m:InModule) -> InModule : + val stmts = Vector<Stmt>() + val connections = Vector<Stmt>() + ;clear-hashes() + defn replace-void (e:Expression,rvalue:Expression) -> Expression : + match(rvalue) : + (rv:WVoid) : e + (rv) : map(replace-void{e,_},rv) + defn create (s:Stmt) -> Stmt : + match(s) : + (s:DefWire|DefRegister|WDefInstance|DefMemory) : + add(stmts,s) + for e in get-female-refs(name(s),get-type(s),get-gender(s)) do : + val rvalue = + if s typeof DefRegister : replace-void(e,netlist[e]) + else : netlist[e] + add(connections,Connect(info(s),e,rvalue)) + (s:DefPoison|DefNode) : + add(stmts,s) + (s) : map(create,s) + s + create(body(m)) + for p in ports(m) do : + for e in get-female-refs(name(p),type(p),get-gender(p)) do : + add(connections,Connect(info(p),e,netlist[e])) + for x in simlist do : + add(stmts,x) + InModule(info(m),name(m),ports(m),Begin(list(Begin(to-list(stmts)),Begin(to-list(connections))))) + + val voided-modules = + for m in modules(c) map : + match(m) : + (m:ExModule) : m + (m:InModule) : + val m* = void-all(m as InModule) + m* + val modules* = + for m in voided-modules map : + match(m) : + (m:ExModule) : m + (m:InModule) : + val [netlist simlist] = expand-whens(m) + create-module(netlist,simlist,m) + Circuit(info(c),modules*,main(c)) + +;;================ Module Duplication ================== +; Duplicates modules so that no module is instantiated +; more than once. + +;public defstruct ModuleDuplication <: Pass +;public defmethod pass (b:ModuleDuplication) -> (Circuit -> Circuit) : module-duplication +;public defmethod name (b:ModuleDuplication) -> String : "Module Duplication" +;public defmethod short-name (b:ModuleDuplication) -> String : "mod-dup" +; +;;------------ Helper Functions ------------- +; +;;------------ Pass ------------------ +; +;public defn module-duplication (c:Circuit) : +; val modules* = Vector<Module>() +; val m-names = HashTable<Symbol,Int>(symbol-hash) +; defn rename (n:Symbol) -> Symbol : +; val int = get?(m-names,n,0) +; m-names[n] = int + 1 +; val n* = symbol-join([n module-expand-delin int]) +; val m = for x in modules(c) find : name(x) == n +; match(m) : +; (m:InModule) : add(modules*,InModule(info(m),n*, ports(m), rename-s(body(m)))) +; (m:ExModule) : add(modules*,ExModule(info(m),n*, ports(m))) +; (m:False) : error("Shouldn't be here") +; n* +; +; defn rename-e (e:Expression) -> Expression : +; match(e) : +; (e:Ref) : Ref(rename(name(e)),type(e)) +; (e) : error("Shouldn't be here") +; defn rename-s (s:Stmt) -> Stmt : +; match(s) : +; (s:WDefInstance) : WDefInstance(info(s),name(s),rename-e(module(s))) +; (s) : map(rename-s,s) +; +; val top = for m in modules(c) find : name(m) == main(c) +; match(top) : +; (m:InModule) : add(modules*,InModule(info(m),name(m), ports(m), rename-s(body(m)))) +; (m:ExModule) : m +; (m:False) : error("Shouldn't be here") +; +; Circuit(info(c),to-list(modules*), main(c)) +; +; +;;;================ Deadcode Elimination =================== +;; Walks the circuit, starting from the outputs from the top +;; level module. All components that are not reached are +;; deleted +; +;public defstruct DeadcodeElimination <: Pass +;public defmethod pass (b:DeadcodeElimination) -> (Circuit -> Circuit) : deadcode-elimination +;public defmethod name (b:DeadcodeElimination) -> String : "Deadcode Elimination" +;public defmethod short-name (b:DeadcodeElimination) -> String : "deadcode-elim" +; +;;------------ Helper Functions ------------- +; +;;------------ Pass ------------------ +; +;public defn deadcode-elimination (c:Circuit) : c +; +;;;================ INFER WIDTHS ============================= +;; First, you replace all unknown widths with a unique width +;; variable. +;; Then, you collect all width constraints. +;; Then, you solve width constraints. +;; 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 definterface Constraint +public defstruct WGeq <: Constraint : + loc : Width + exp : Width +public defmethod print (o:OutputStream, c:WGeq) : + print-all(o,[ loc(c) " >= " exp(c)]) +defn apply (a:Int|False,b:Int|False, f: (Int,Int) -> Int) -> Int|False : + if a typeof Int and b typeof Int : f(a as Int, b as Int) + else : false + +defn solve-constraints (l:List<WGeq>) -> HashTable<Symbol,Width> : + defn contains? (n:Symbol,h:HashTable<Symbol,?>) -> True|False : key?(h,n) + defn make-unique (ls:List<WGeq>) -> HashTable<Symbol,Width> : + val h = HashTable<Symbol,Width>(symbol-hash) + for g in ls do : + match(loc(g)) : + (w:VarWidth) : + val n = name(w) + if contains?(n,h) : h[n] = MaxWidth(list(exp(g),h[n])) + else : h[n] = exp(g) + (w) : w + h + defn simplify (w:Width) -> Width : + match(map(simplify,w)) : + (w:MaxWidth) : + val v = Vector<Width>() + for w* in args(w) do : + match(w*) : + (w*:MaxWidth) : + for x in args(w*) do : add(v,x) + (w*) : add(v,w*) + MaxWidth(unique(v)) + (w:PlusWidth) : + match(arg1(w),arg2(w)) : + (w1:IntWidth,w2:IntWidth) : IntWidth(plus(width(w1),width(w2))) + (w1,w2) : w + (w:MinusWidth) : + match(arg1(w),arg2(w)) : + (w1:IntWidth,w2:IntWidth) : IntWidth(minus(width(w1),width(w2))) + (w1,w2) : w + (w:ExpWidth) : + match(arg1(w)) : + (w1:IntWidth) : IntWidth(pow(to-long(2),width(w1)) - to-long(1)) + (w1) : w + (w) : w + defn substitute (w:Width,h:HashTable<Symbol,Width>) -> Width : + ;println-all-debug(["Substituting for [" w "]"]) + val w* = simplify(w) + ;println-all-debug(["After Simplify: [" w* "]"]) + match(map(substitute{_,h},simplify(w))) : + (w:VarWidth) : + ;println-debug("matched varwidth!") + if contains?(name(w),h) : + ;println-debug("Contained!") + ;println-all-debug(["Width: " w]) + ;println-all-debug(["Accessed: " h[name(w)]]) + val t = simplify(substitute(h[name(w)],h)) + ;val t = h[name(w)] + ;println-all-debug(["Width after sub: " t]) + h[name(w)] = t + t + else : w + (w): + ;println-all-debug(["not varwidth!" w]) + w + defn b-sub (w:Width,h:HashTable<Symbol,Width>) -> Width: + match(map(b-sub{_,h},w)) : + (w:VarWidth) : + if key?(h,name(w)) : h[name(w)] + else : w + (w) : w + defn remove-cycle (n:Symbol,w:Width) -> Width : + ;println-all-debug(["Removing cycle for " n " inside " w]) + val w* = match(map(remove-cycle{n,_},w)) : + (w:MaxWidth) : MaxWidth(to-list(filter({_ != VarWidth(n)},args(w)))) + (w:MinusWidth) : + if arg1(w) == VarWidth(n) : arg1(w) + else : w + (w) : w + ;println-all-debug(["After removing cycle for " n ", returning " w*]) + w* + defn self-rec? (n:Symbol,w:Width) -> True|False : + var has? = false + defn look (w:Width) -> Width : + match(map(look,w)) : + (w:VarWidth) : if name(w) == n : has? = true + (w) : w + w + look(w) + has? + + ; Forward solve + ; Returns a solved list where each constraint undergoes: + ; 1) Continuous Solving (using triangular solving) + ; 2) Remove Cycles + ; 3) Move to solved if not self-recursive + val u = make-unique(l) + println-debug("======== UNIQUE CONSTRAINTS ========") + for x in u do : println-debug(x) + println-debug("====================================") + + val f = HashTable<Symbol,Width>(symbol-hash) + val o = Vector<Symbol>() + for x in u do : + println-debug("==== SOLUTIONS TABLE ====") + for x in f do : println-debug(x) + println-debug("=========================") + + val [n e] = [key(x) value(x)] + + val e-sub = substitute(e,f) + println-debug(["Solving " n " => " e]) + println-debug(["After Substitute: " n " => " e-sub]) + println-debug("==== SOLUTIONS TABLE (Post Substitute) ====") + for x in f do : println-debug(x) + println-debug("=========================") + val e* = remove-cycle{n,_} $ e-sub + ;println-debug(["After Remove Cycle: " n " => " e*]) + if not self-rec?(n,e*) : + ;println-all-debug(["Not rec!: " n " => " e*]) + ;println-all-debug(["Adding [" n "=>" e* "] to Solutions Table"]) + add(o,n) + f[n] = e* + + println-debug("Forward Solved Constraints") + for x in f do : println-debug(x) + + ; Backwards Solve + val b = HashTable<Symbol,Width>(symbol-hash) + for i in (length(o) - 1) through 0 by -1 do : + val n = o[i] + println-all-debug(["SOLVE BACK: [" n " => " f[n] "]"]) + println-debug("==== SOLUTIONS TABLE ====") + for x in b do : println-debug(x) + println-debug("=========================") + val e* = simplify(b-sub(f[n],b)) + println-all-debug(["BACK RETURN: [" n " => " e* "]"]) + b[n] = e* + println-debug("==== SOLUTIONS TABLE (Post backsolve) ====") + for x in b do : println-debug(x) + println-debug("=========================") + b + +public defn width! (t:Type) -> Width : + match(t) : + (t:UIntType) : width(t) + (t:SIntType) : width(t) + (t:ClockType) : IntWidth(1) + (t) : error("No width!") +public defn width! (e:Expression) -> Width : width!(type(e)) + +defn reduce-var-widths (c:Circuit,h:HashTable<Symbol,Width>) -> Circuit : + defn evaluate (w:Width) -> Width : + defn apply (a:Long|False,f:(Long) -> Long) -> Long|False : + if a typeof Long : f(a as Long) + else : false + defn apply (a:Long|False,b:Long|False, f: (Long,Long) -> Long) -> Long|False : + if a typeof Long and b typeof Long : f(a as Long, b as Long) + else : false + defn apply-l (l:List<Long|False>,f:(Long,Long) -> Long) -> Long|False : + if length(l) == 0 : to-long(0) + else : apply(head(l),apply-l(tail(l),f),f) + defn max (a:Long,b:Long) -> Long : + if a >= b : a + else : b + defn solve (w:Width) -> False|Long : + match(w) : + (w:VarWidth) : + val w* = get?(h,name(w),false) + match(w*) : + (w:VarWidth) : false + (w:False) : false + (w) : solve(w as Width) + (w:MaxWidth) : apply-l(map(solve,args(w)),max) + (w:PlusWidth) : apply(solve(arg1(w)),solve(arg2(w)),{plus(_,_)}) + (w:MinusWidth) : apply(solve(arg1(w)),solve(arg2(w)),{minus(_,_)}) + (w:ExpWidth) : apply(to-long(2),solve(arg1(w)),{minus(pow(_,_),to-long(1))}) + (w:IntWidth) : width(w) + (w) : + println(w) + error("Shouldn't be here") + + val s = solve(w) + match(s) : + (s:Long) : IntWidth(s) + (s) : w + + defn reduce-var-widths-w (w:Width) -> Width : + println-all-debug(["REPLACE: " w]) + val w* = evaluate(w) + println-all-debug(["WITH: " w*]) + w* + + val modules* = for m in modules(c) map : + val ports* = for p in ports(m) map : + Port(info(p),name(p),direction(p),mapr(reduce-var-widths-w,type(p))) + + match(m) : + (m:ExModule) : ExModule(info(m),name(m),ports*) + (m:InModule) : InModule(info(m),name(m),ports*,mapr(reduce-var-widths-w,body(m))) + + Circuit(info(c),modules*,main(c)) + +defn infer-widths (c:Circuit) -> Circuit : + val v = Vector<WGeq>() + defn constrain (w1:Width,w2:Width) -> False : constrain(w1,w2,DEFAULT) + defn constrain (w1:Width,w2:Width,f:Flip) -> False : + switch { _ == f } : + DEFAULT : add(v,WGeq(w1,w2)) + REVERSE : add(v,WGeq(w2,w1)) + defn get-constraints (t1:Type,t2:Type,f:Flip) -> False : + match(t1,t2) : + (t1:UIntType,t2:UIntType) : constrain(width(t1),width(t2)) + (t1:SIntType,t2:SIntType) : constrain(width(t1),width(t2)) + (t1:BundleType,t2:BundleType) : + for (f1 in fields(t1),f2 in fields(t2)) do : + get-constraints(type(f1),type(f2),flip(f1) * f) + (t1:VectorType,t2:VectorType) : + get-constraints(type(t1),type(t2),f) + defn get-constraints-e (e:Expression) -> Expression : + match(map(get-constraints-e,e)) : + (e:DoPrim) : + if op(e) == MUX-OP : + constrain(width!(args(e)[0]),ONE) + constrain(ONE,width!(args(e)[0])) + e + (e) : e + defn get-constraints (s:Stmt) -> Stmt : + match(map(get-constraints-e,s)) : + (s:Connect) : + ;constrain(width!(loc(s)),width!(exp(s))) + ;s + val n = get-size(loc(s)) + val ce-loc = fast-create-exps(loc(s)) + val ce-exp = fast-create-exps(exp(s)) + for i in 0 to n do : + val loc* = ce-loc[i] + val exp* = ce-exp[i] + switch { _ == get-flip(type(loc(s)),i,DEFAULT) } : + DEFAULT : constrain(width!(loc*),width!(exp*)) + REVERSE : constrain(width!(exp*),width!(loc*)) + s + (s:BulkConnect) : + val ls = get-valid-points(type(loc(s)),type(exp(s)),DEFAULT,DEFAULT) + for x in ls do : + println(x) + println(fast-create-exps(loc(s))) + println(fast-create-exps(exp(s))) + val loc* = fast-create-exps(loc(s))[x[0]] + val exp* = fast-create-exps(exp(s))[x[1]] + switch { _ == get-flip(type(loc(s)),x[0],DEFAULT) } : + DEFAULT : constrain(width!(loc*),width!(exp*)) + REVERSE : constrain(width!(exp*),width!(loc*)) + s + (s:DefRegister) : + constrain(width!(reset(s)),ONE) + constrain(ONE,width!(reset(s))) + get-constraints(type(s),type(init(s)),DEFAULT) + s + (s:Conditionally) : + add(v,WGeq(width!(pred(s)),ONE)) + add(v,WGeq(ONE,width!(pred(s)))) + map(get-constraints,s) + (s) : map(get-constraints,s) + + for m in modules(c) do : + match(m) : + (m:InModule) : get-constraints(body(m)) + (m) : false + println-debug("======== ALL CONSTRAINTS ========") + for x in v do : println-debug(x) + println-debug("=================================") + val h = solve-constraints(to-list(v)) + println-debug("======== SOLVED CONSTRAINTS ========") + for x in h do : println-debug(x) + println-debug("====================================") + reduce-var-widths(Circuit(info(c),modules(c),main(c)),h) + +; ================ All Resolving Passes ================ +public defstruct Resolve <: Pass +public defmethod pass (b:Resolve) -> (Circuit -> Circuit) : resolve +public defmethod name (b:Resolve) -> String : "Resolve" +public defmethod short-name (b:Resolve) -> String : "resolve" + +defn resolve (c:Circuit) -> Circuit : + infer-widths $ + resolve-genders $ + infer-types $ + resolve-kinds $ c + +;;================= 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,InModule>(symbol-hash) +; val h-s = HashTable<Symbol,Stmt>(symbol-hash) +; defn inline-inst (s:Stmt) -> Stmt : +; match(map(inline-inst,s)) : +; (s:WDefInstance) : +; val n = name(module(s) as WRef) +; val m = h[n] +; val body* = +; if key?(h-s,n) : h-s[n] +; else : +; val v = Vector<Stmt>() +; for p in ports(m) do : +; add(v,DefWire(info(s),name(p),type(p))) +; add(v,inline-inst(body(m))) +; Begin(to-list(v)) +; h-s[n] = body* +; rename-s(body*,name(s)) +; (s) : map(inline-inst-e,s) +; defn inline-inst-e (e:Expression) -> Expression : +; match(map(inline-inst-e,e)) : +; (e:WSubField) : +; match(kind(exp(e) as WRef)) : +; (k:InstanceKind) : +; WRef(symbol-join([name(exp(e) as WRef) inline-delin name(e)]),type(e),k,gender(e)) +; (k:MemKind) : e +; (e) : e +; defn rename (ref:Symbol,n:Symbol) -> Symbol : symbol-join([n inline-delin 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) inline-delin name(e)]),type(e),k,gender(e)) +; (k:MemKind) : e +; (e) : e +; defn rename-s (s:Stmt,n:Symbol) -> Stmt : +; map{rename-e{_,n},_} $ match(map(rename-s{_,n},s)) : +; (s:DefWire) : DefWire(info(s),rename(name(s),n),type(s)) +; (s:DefPoison) : DefPoison(info(s),rename(name(s),n),type(s)) +; (s:DefRegister) : DefRegister(info(s),rename(name(s),n),type(s),clock(s),reset(s)) +; (s:WDefInstance) : error("Shouldn't be here") +; (s:DefMemory) : DefMemory(info(s),rename(name(s),n),type(s),seq?(s),clock(s),size(s)) +; (s:DefNode) : DefNode(info(s),rename(name(s),n),value(s)) +; (s) : s +; for m in modules(c) do : +; match(m) : +; (m:ExModule) : error("Cannot inline with external modules") +; (m:InModule) : h[name(m)] = m +; val top = (for m in modules(c) find : name(m) == main(c)) as InModule +; Circuit(info(c),list(InModule(info(top),name(top),ports(top),inline-inst(body(top)))),main(c)) + +;;================= 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 (m:InModule) -> InModule : + val v = Vector<Stmt>() + val sh = get-sym-hash(m,keys(v-keywords)) + defn split-exp-s (s:Stmt) -> Stmt : + val base = match(s) : + (s:Connect) : lowered-name(loc(s)) + (s:DefNode) : name(s) + (s:DefRegister) : name(s) + (s) : `F + defn split (e:Expression) -> Expression : + val n = firrtl-gensym(`GEN,sh) + add(v,DefNode(info(s),n,e)) + WRef(n,type(e),kind(e),gender(e)) + defn split-exp-e (e:Expression,i:Int) -> Expression : + match(map(split-exp-e{_,i + 1},e)) : + (e:DoPrim) : + if i > 0 : split(e) + else : e + (e) : e + match(map(split-exp-e{_,0},s)) : + (s:Begin) : map(split-exp-s,s) + (s) : + add(v,s) + s + split-exp-s(body(m)) + InModule(info(m),name(m),ports(m),Begin(to-list(v))) + +defn split-exp (c:Circuit) -> Circuit : + val modules* = for m in modules(c) map : + match(m) : + (m:InModule) : split-exp(m) + (m:ExModule) : m + Circuit(info(c),modules*,main(c)) + + +;;================= Special Rename ======================== +;; Returns a new Circuit with only real IR nodes. +;public defstruct SpecialRename <: Pass : +; original-sym : Symbol +; new-sym : Symbol +;public defmethod pass (b:SpecialRename) -> (Circuit -> Circuit) : special-rename{original-sym(b),new-sym(b),_:Circuit} +;public defmethod name (b:SpecialRename) -> String : "Special Rename" +;public defmethod short-name (b:SpecialRename) -> String : "special-rename" +; +;public defn special-rename (original-sym:Symbol,new-sym:Symbol,c:Circuit) : +; defn rename (s:Symbol) -> Symbol : +; val y = Vector<String>() +; val os = to-string $ original-sym +; val ns = to-string $ new-sym +; defn rename (st:String) -> False : +; if st == os : +; add(y,ns) +; else if length(st) <= length(os) : +; add(y,st) +; else : +; if substring(st,0,length(os)) == os : +; add(y,ns) +; ;println(st) +; ;println(substring(st,length(os),length(st))) +; rename(substring(st,length(os),length(st))) +; else : +; add(y,substring(st,0,1)) +; rename(substring(st,1,length(st))) +; rename(to-string(s)) +; to-symbol $ string-join $ to-list(y) +; defn to-type (t:Type) -> Type : +; match(map(to-type,t)) : +; (t:BundleType) : BundleType $ +; for f in fields(t) map : Field(rename(name(f)),flip(f),type(f)) +; (t) : t +; defn to-exp (e:Expression) -> Expression : +; map{to-type,_} $ match(map(to-exp,e)) : +; (e:Ref) : Ref(rename(name(e)), type(e)) +; (e:Subfield) : Subfield(exp(e),rename(name(e)),type(e)) +; (e) : e +; defn to-stmt (s:Stmt) -> Stmt : +; map{to-type,_} $ match(map(to-exp,s)) : +; (s:DefWire) : DefWire(info(s),rename(name(s)),type(s)) +; (s:DefPoison) : DefPoison(info(s),rename(name(s)),type(s)) +; (s:DefRegister) : DefRegister(info(s),rename(name(s)),type(s),clock(s),reset(s)) +; (s:WDefInstance) : WDefInstance(info(s),rename(name(s)),module(s)) +; (s:DefMemory) : DefMemory(info(s),rename(name(s)),type(s),seq?(s),clock(s),size(s)) +; (s:DefNode) : DefNode(info(s),rename(name(s)),value(s)) +; (s:DefAccessor) : DefAccessor(info(s),rename(name(s)),source(s),index(s),acc-dir(s)) +; (s) : map(to-stmt,s) +; +; defn to-port (p:Port) -> Port : Port(info(p),rename(name(p)),direction(p),type(p)) +; +; Circuit(info(c),modules*, main(c)) where : +; val modules* = +; for m in modules(c) map : +; match(m) : +; (m:InModule) : InModule(info(m),name(m), map(to-port,ports(m)), to-stmt(body(m))) +; (m:ExModule) : m +; +; +;;========== Pad Widths ================== +; +;public defstruct Pad <: Pass +;public defmethod pass (b:Pad) -> (Circuit -> Circuit) : pad-widths +;public defmethod name (b:Pad) -> String : "Pad Widths" +; +;;------------ Helper Functions -------------- +;defn int-width! (t:Type) -> Long : +; match(width!(t)) : +; (w:IntWidth) : width(w) +; (w) : error("Non-int width") +; +;defn set-width (desired:Long,t:Type) -> Type : +; match(t) : +; (t:UIntType) : UIntType(IntWidth(desired)) +; (t:SIntType) : SIntType(IntWidth(desired)) +; (t) : error("Non-ground type") +; +;defn lmax (l1:Long, l2:Long) -> Long : +; if l1 > l2 : l1 +; else : l2 +; +;;------------- Pad Widths ------------------- +; +;defn pad-widths-e (desired:Long,e:Expression) -> Expression : +; defn trim (desired:Long, e:Expression) : +; ;; println-all(["TRIM " desired " e " e]) +; DoPrim(BITS-SELECT-OP,list(e),list(to-int(to-string(desired)) - 1, 0),set-width(desired,type(e))) +; defn pad (desired:Long, e:Expression) : +; ;; println-all(["PAD " desired " e " e]) +; DoPrim(PAD-OP,list(e),list(to-int $ to-string(desired)),set-width(desired,type(e))) +; defn trim-pad (desired:Long, e:Expression) : +; val i = int-width!(type(e)) +; if i > desired : trim(desired, e) +; else if i == desired : e +; else : pad(desired, e) +; defn self-pad-widths-e (e:Expression) -> Expression : +; pad-widths-e(int-width!(type(e)), e) +; ;; println-all(["PAD-E " desired " " e]) +; match(e) : +; (e:DoPrim) : +; val new-desired = reduce(lmax, to-long(0), map(int-width!{type(_)}, args(e))) +; ;; println-all([" NEW DESIRED " new-desired]) +; val e* = +; if contains?([CONCAT-OP, DYN-SHIFT-RIGHT-OP, DYN-SHIFT-LEFT-OP], op(e)) : +; DoPrim(op(e), map(self-pad-widths-e, args(e)), consts(e), type(e)) +; else if contains?([MUX-OP], op(e)) : +; DoPrim(op(e), list(pad-widths-e(to-long(1), args(e)[0]), pad-widths-e(new-desired, args(e)[1]), pad-widths-e(new-desired, args(e)[2])), consts(e), type(e)) +; else : +; map(pad-widths-e{new-desired,_},e) +; trim-pad(desired, e*) +; (e:Ref|Subfield|Index) : +; trim-pad(desired, e) +; (e:UIntValue) : +; val i = int-width!(type(e)) +; if i > desired : trim(desired, e) +; else : UIntValue(value(e),IntWidth(desired)) +; (e:SIntValue) : +; val i = int-width!(type(e)) +; if i > desired : trim(desired, e) +; else : SIntValue(value(e),IntWidth(desired)) +; (e) : error(to-string $ e) +; +;defn pad-widths-s (s:Stmt) -> Stmt : +; ;; println-all(["PAD-S " s]) +; match(map(pad-widths-s,s)) : +; (s:Connect) : +; val i = int-width!(type(loc(s))) +; val loc* = pad-widths-e(i,loc(s)) +; val exp* = pad-widths-e(i,exp(s)) +; Connect(info(s),loc*,exp*) +; (s:PrintfStmt) : +; val args* = for x in args(s) map : +; val i = int-width!(type(x)) +; pad-widths-e(i,x) +; PrintfStmt(info(s),string(s),args*) +; (s:DefNode) : +; val i = int-width!(type(value(s))) +; val exp* = pad-widths-e(i,value(s)) +; DefNode(info(s),name(s),exp*) +; (s:Conditionally) : +; val i = int-width!(type(pred(s))) +; val pred* = pad-widths-e(i,pred(s)) +; Conditionally(info(s),pred*,conseq(s),alt(s)) +; (s) : s +; +;public defn pad-widths (c:Circuit) -> Circuit : +; Circuit{info(c),_,main(c)} $ +; for m in modules(c) map : +; match(m) : +; (m:ExModule) : m +; (m:InModule) : InModule(info(m),name(m),ports(m),pad-widths-s(body(m))) +; +; + +;============== Common Subexpression Elimination =========== +;NOT DONE + +;public defstruct CSE <: Pass +;public defmethod pass (b:CSE) -> (Circuit -> Circuit) : const-prop +;public defmethod name (b:CSE) -> String : "Common Subexpression Elimination" +;public defmethod short-name (b:ConstProp) -> String : "cse" +; +;defn cse-m (m:InModule) -> InModule : +; val cse-hash = HashTable<Expression,Int>(exp-hash) +; val placed? = HashTable<Expression,True|False>(exp-hash) +; +; defn cse-s (s:Stmt) -> Stmt : +; val stmts = Vector<Stmt>() +; defn cse-e (e:Expression) -> Expression +; match(s) : +; +; defn build-e (e:Expression) -> Expression : +; match(e) : +; (e:DoPrim) : +; if key?(cse-hash,e) : +; cse-hash[e] = cse-hash[e] + 1 +; else : +; cse-hash[e] = 1 +; placed?[e] = false +; (e) : e +; defn build-s (s:Stmt) -> Stmt : map{build-s,_} $ map(build-e,s) +; +; build-s(body(m)) +; InModule(info(m),name(m),ports(m),cse-s(body(m))) +; +;public defn cse (c:Circuit) -> Circuit : +; Circuit{info(c),_,main(c)} $ +; for m in modules(c) map : +; match(m) : +; (m:ExModule) : m +; (m:InModule) : cse-m(m) + + + +;;============= Constant Propagation ================ +; +public defstruct ConstProp <: Pass +public defmethod pass (b:ConstProp) -> (Circuit -> Circuit) : const-prop +public defmethod name (b:ConstProp) -> String : "Constant Propagation" +public defmethod short-name (b:ConstProp) -> String : "const-prop" + +defn const-prop-e (e:Expression) -> Expression : + match(map(const-prop-e,e)) : + (e:DoPrim) : + switch {op(e) == _} : + DYN-SHIFT-RIGHT-OP : + match(args(e)[1]) : + (x:UIntValue|SIntValue) : + DoPrim(SHIFT-RIGHT-OP,list(args(e)[0]),list(to-int(value(x))),UnknownType()) + (x) : e + DYN-SHIFT-LEFT-OP : + match(args(e)[1]) : + (x:UIntValue|SIntValue) : + DoPrim(SHIFT-LEFT-OP,list(args(e)[0]),list(to-int(value(x))),UnknownType()) + (x) : e + SHIFT-RIGHT-OP : + match(args(e)[0]) : + (x:UIntValue) : + val b = rsh(value(x),consts(e)[0]) + UIntValue(b,width(type(e) as UIntType)) + (x:SIntValue) : + val b = rsh(value(x),consts(e)[0]) + SIntValue(b,width(type(e) as SIntType)) + (x) : e + BITS-SELECT-OP : + match(args(e)[0]) : + (x:UIntValue) : + val b = bits(value(x),consts(e)[0] + 1,consts(e)[1]) + UIntValue(b,width(type(e) as UIntType)) + (x) : e + BIT-SELECT-OP : + match(args(e)[0]) : + (x:UIntValue) : + val i = bit(value(x),consts(e)[0]) + UIntValue(i,width(type(e) as UIntType)) + (x) : e + else : e + (e) : e + +defn const-prop-s (s:Stmt) -> Stmt : + map{const-prop-e,_} $ map(const-prop-s,s) + +public defn const-prop (c:Circuit) -> Circuit : + Circuit{info(c),_,main(c)} $ + for m in modules(c) map : + match(m) : + (m:ExModule) : m + (m:InModule) : InModule(info(m),name(m),ports(m),const-prop-s(body(m))) + +;============= Condense Mems ================ +; +;public defstruct CondenseMems <: Pass +;public defmethod pass (b:CondenseMems) -> (Circuit -> Circuit) : condense-mems +;public defmethod name (b:CondenseMems) -> String : "Condense Mems" +;public defmethod short-name (b:CondenseMems) -> String : "condense-mems" +; +;;------------- Utils --------------- +; +;defn concat (es:List<Expression>) -> Expression : +; if length(es) == 1 : head(es) +; else : CAT(head(es),cat(tail(es))) +;defn cast (t:Type,e:Expression) -> Expression : +; match(t) : +; (t:UIntType) : e +; (t:SIntType) : DoPrim(AS-SINT-OP,list(e),list(),SIntType(get-width(t))) +;defn get-width-index (e:Expression) -> Long : +; match(e) : +; (e:WRef) : 0 +; (e:WSubField) : +; var w = get-width-index(exp(e)) +; var found? = false +; for f in fields(type(exp(e)) as BundleType) do : +; if name(f) == name(e) : +; found? = true +; if found? == false : +; w = w + get-width(type(f)) +; w +; (e:WSubIndex) : +; get-width-index(exp(e)) + get-width(type(e)) * value(e) +;defn root-ref (e:Expression) -> Expression : +; match(e) : +; (e:WRef) : e +; (e:WSubField|WSubIndex) : root-ref(e) +;defn flatten (e:Expression) -> Expression : +; match(e) : +; (e:WRef) : e +; (e:WSubField|WSubIndex) : +; val base = get-width-index(e) +; val off = get-width(type(e)) +; DoPrim(BITS-SELECT-OP,list(root-ref(e)),list(base,off),UIntType(IntWidth(off))) +; +;;------------- Pass ------------------ + +;defn condense-mems (m:InModule) -> InModule : +; val mem-assigns = HashTable<Expression,Expression>(exp-hash) +; defn collect-mems (s:Stmt) -> Stmt : +; match(s) : +; (s:Connect) : +; defn condense-mems-e (e:Expression) -> Expression : +; val e* = match(e) : +; (e:WRef|WSubField|WSubIndex) : +; if (kind(e) typeof MemKind) : cast(type(e),flatten(e)) +; else : e +; (e:UIntValue|SIntValue) : e +; (e:DoPrim) : map(condense-mems-e,e) +; defn condense-mems (s:Stmt) -> Stmt : +; match(s) : +; (s:DefMemory) : +; val stmts = Vector<Stmt>() +; val s* = map(flatten,s) +; add(stmts,s*) +; val mem = WRef(name(s),type(s),MemKind(),UNKNOWN-GENDER) +; for f in fields(type(s) as BundleType) do : +; val data-name = +; if contains?(writers(s),name(f)) : `data +; else if contains(readwriters(s),name(f)) : `wdata +; else : false +; match(data-name) : +; (f:False) : false +; (n:Symbol) : +; val port = WSubField(mem,name(f),type(f),UNKNOWN-GENDER) +; val es = create-exps(WSubField(port,n,field-type(type(port),n),UNKNOWN-GENDER)) +; val e* = concat $ for e in es map : +; map(condense-mems-e,mem-assigns[e]) +; add(stmts,Connect(info(s),WSubField(port,n,data-type(s*),UNKNOWN-GENDER),e*)) +; Begin(to-list(stmts)) +; (s:Connect) : +; if kind(loc(s)) typeof MemKind : EmptyStmt() +; else : map(condense-mems-e, s) +; (s) : map{condense-mems,_} $ map(condense-mems-e, s) +; InModule(info(m),name(m),ports(m),condense-mems(body(m))) +; +;defn condense-mems (c:Circuit) -> Circuit : +; Circuit{info(c),_,main(c)} $ +; for m in modules(c) map : +; match(m) : +; (m:ExModule) : m +; (m:InModule) : condense-mems(m) + +;============= Lower Types ================ +; +public defstruct LowerTypes <: Pass +public defmethod pass (b:LowerTypes) -> (Circuit -> Circuit) : lower-types +public defmethod name (b:LowerTypes) -> String : "Lower Types" +public defmethod short-name (b:LowerTypes) -> String : "lower-types" + +;------------- Utils --------------- +defn is-ground? (t:Type) -> True|False : + match(t) : + (t:UIntType|SIntType) : true + (t) : false +defn data? (ex:Expression) -> True|False : + match(kind(ex)) : + (k:MemKind) : match(ex) : + (ex:WRef|WSubIndex) : false + (ex:WSubField) : + var yes? = switch { _ == name(ex) } : + `wdata : true + `rdata : true + `data : true + `mask : true + else : false + yes? and match(exp(ex)) : + (e:WSubField) : + contains?(ports(kind(e) as MemKind),name(e)) and (exp(e) typeof WRef) + (e) : false + (ex) : false + (k) : false + +defn expand-name (e:Expression) -> List<Symbol> : + val names = Vector<Symbol>() + defn expand-name-e (e:Expression) -> Expression : + match(map(expand-name-e,e)) : + (e:WRef) : add(names,name(e)) + (e:WSubField) : add(names,name(e)) + (e:WSubIndex) : add(names,to-symbol(value(e))) + e + expand-name-e(e) + to-list(names) + + +defn lower-other-mem (e:Expression, dt:Type) -> List<Expression> : + val names = expand-name(e) + if length(names) < 3 : error("Shouldn't be here") + for x in fast-create-exps(names[0],dt) map : + var base = lowered-name(x) + for (x in names,i in 0 to false) do : + if i >= 3 : base = symbol-join([base `_ x]) + val m = WRef(base, UnknownType(), kind(e), UNKNOWN-GENDER) + val p = WSubField(m,to-symbol(names[1]),UnknownType(),UNKNOWN-GENDER) + WSubField(p,to-symbol(names[2]),UnknownType(),UNKNOWN-GENDER) + +defn lower-data-mem (e:Expression) -> Expression : + val names = expand-name(e) + if length(names) < 3 : error("Shouldn't be here") + else : + var base = names[0] + for (x in names,i in 0 to false) do : + if i >= 3 : base = symbol-join([base `_ x]) + val m = WRef(base, UnknownType(), kind(e), UNKNOWN-GENDER) + val p = WSubField(m,to-symbol(names[1]),UnknownType(),UNKNOWN-GENDER) + WSubField(p,to-symbol(names[2]),UnknownType(),UNKNOWN-GENDER) + +defn merge (a:Symbol,b:Symbol,x:Symbol) -> Symbol : symbol-join([a x b]) +defn lowered-name (e:Expression) -> Symbol : + match(e) : + (e:WRef) : name(e) + (e:WSubField) : merge(lowered-name(exp(e)),name(e),`_) + (e:WSubIndex) : merge(lowered-name(exp(e)),to-symbol(value(e)),`_) +defn root-ref (e:Expression) -> WRef : + match(e) : + (e:WRef) : e + (e:WSubField|WSubIndex|WSubAccess) : root-ref(exp(e)) + (e:WIndexer) : root-ref(exps(e)[0]) + +;------------- Pass ------------------ + +defn lower-types (m:Module) -> Module : + val mdt = HashTable<Symbol,Type>(symbol-hash) + defn lower-types (s:Stmt) -> Stmt : + defn lower-mem (e:Expression) -> List<Expression> : + val names = expand-name(e) + if contains?([`data `mask `rdata `wdata `wmask],names[2]) : + list(lower-data-mem(e)) + else : + lower-other-mem(e,mdt[name(root-ref(e))]) + defn lower-types-e (e:Expression) -> Expression : + match(e) : + (e:WRef|UIntValue|SIntValue) : e + (e:WSubField) : + match(kind(e)) : + (k:InstanceKind) : + val names = expand-name(e) + var n = names[1] + for (x in names,i in 0 to false) do : + if i > 1 : n = symbol-join([n `_ x]) + WSubField(root-ref(e),n,type(e),gender(e)) + (k:MemKind) : + if not gender(e) == FEMALE : + lower-mem(e)[0] + else : e + (k) : WRef(lowered-name(e),type(e),kind(e),gender(e)) + (e:WSubIndex) : WRef(lowered-name(e),type(e),kind(e),gender(e)) + (e:DoPrim) : map(lower-types-e,e) + match(map(lower-types-e,s)) : + (s:DefWire|DefPoison) : + if is-ground?(type(s)) : s + else : + val es = fast-create-exps(name(s),type(s)) + Begin $ for (e in es, i in 0 to false) map : + defn replace-type (t:Type) -> Type : type(e) + defn replace-name (n:Symbol) -> Symbol : lowered-name(e) + map{replace-name,_} $ map(replace-type,s) + (s:DefRegister) : + if is-ground?(type(s)) : s + else : + val es = fast-create-exps(name(s),type(s)) + Begin $ for (e in es, i in 0 to false) map : + val init = lower-types-e(fast-create-exps(init(s))[i]) + DefRegister(info(s),lowered-name(e),type(e),clock(s),reset(s),init) + (s:WDefInstance) : + val fields* = for f in fields(type(s) as BundleType) map-append : + val es = fast-create-exps(WRef(name(f),type(f),ExpKind(),flip(f) * MALE)) + for e in es map : + switch { _ == gender(e) } : + MALE : Field(lowered-name(e),DEFAULT,type(f)) + FEMALE : Field(lowered-name(e),REVERSE,type(f)) + WDefInstance(info(s),name(s),module(s),BundleType(fields*)) + (s:DefMemory) : + mdt[name(s)] = data-type(s) + if is-ground?(data-type(s)) : s + else : + val es = fast-create-exps(name(s),data-type(s)) + Begin $ for e in es map : + DefMemory(info(s),lowered-name(e),type(e),depth(s),write-latency(s),read-latency(s),readers(s),writers(s),readwriters(s)) + (s:Connect) : + if kind(loc(s)) typeof MemKind : + val es = lower-mem(loc(s)) + Begin $ for e in es map : + Connect(info(s),e,exp(s)) + else : s + (s) : map(lower-types,s) + + val ports* = + for p in ports(m) map-append : + val es = fast-create-exps(WRef(name(p),type(p),PortKind(),to-gender(direction(p)))) + for e in es map : + Port(info(p),lowered-name(e),to-dir(gender(e)),type(e)) + match(m) : + (m:ExModule) : ExModule(info(m),name(m),ports*) + (m:InModule) : InModule(info(m),name(m),ports*,lower-types(body(m))) + +defn lower-types (c:Circuit) -> Circuit : + Circuit{info(c),_,main(c)} $ + for m in modules(c) map : lower-types(m) + +;============ VERILOG ============== + +public defstruct Verilog <: Pass : + with-output: (() -> False) -> False +public defmethod pass (b:Verilog) -> (Circuit -> Circuit) : emit-verilog{with-output(b),_} +public defmethod name (b:Verilog) -> String : "To Verilog" +public defmethod short-name (b:Verilog) -> String : "To Verilog" + +;============ Utilz ============= +defstruct VIndent +defstruct VRandom +val tab = VIndent() +val ran = VRandom() +defn wref (n:Symbol,t:Type) : WRef(n,t,ExpKind(),UNKNOWN-GENDER) +defn escape (s:String) -> String : + val s* = Vector<String>() + add(s*,"\"");" + var percent = false + for c in s do : + if c == '\n' : + add(s*,"\\n") + else : + if c == 'x' and percent : + add(s*,"h") + else : add(s*,to-string(c)) + percent = c == '%' + add(s*,"\"");" + string-join(s*) +defn remove-root (ex:Expression) -> Expression : + match(exp(ex as WSubField)) : + (e:WSubField) : remove-root(e) + (e:WRef) : WRef(name(ex as WSubField),type(ex),InstanceKind(),UNKNOWN-GENDER) +defn !empty? (s:Vector) -> True|False : + if length(s) == 0 : false + else : true +defn long! (t:Type) -> Long : + match(t) : + (t:UIntType|SIntType) : width(width(t) as IntWidth) + (t:BundleType) : + var w = to-long(0) + for f in fields(t) do : + w = w + long!(type(f)) + w + (t:VectorType) : to-long(size(t)) * long!(type(t)) + +defn rand-string (t:Type) -> Streamable : + val w* = ((long!(t) + to-long(31)) / to-long(32)) + ["{" w* "{" ran "}};"] +defn emit (x:?) : emit(x,0) +defn emit (x:?, top:Int) : + match(x) : + (e:Expression) : + turn-off-debug(false) + match(e) : + (e:DoPrim) : emit(op-stream(e), top + 1) + (e:WRef) : print(e) + (e:WSubField) : print(lowered-name(e)) + (e:WSubAccess) : print-all([lowered-name(exp(e)) "[" lowered-name(index(e)) "]"]) + (e:WSubIndex) : print(e) + (e:UIntValue|SIntValue) : v-print(e) + turn-on-debug(false) + (t:Type) : + match(t) : + (t:UIntType|SIntType) : + val w = long!(t) - to-long(1) + if w > to-long(0) : print-all(["[" w ":0]"]) + else : print("");" + (t:ClockType) : print("");" + (t:VectorType) : + emit(type(t), top + 1) + print-all(["[" size(t) - 1 ":0]"]) + (t) : println(t) + + (p:Direction) : + switch {_ == p} : + INPUT : print("input") + OUTPUT : print("output") + (s:Symbol) : print(s) + (i:Int) : print(i) + (i:Long) : print(i) + (s:String) : print(s) + (t:VIndent) : print(" ") + (r:VRandom) : print("$random") + (s:Streamable) : + for x in s do : + emit(x, top + 1) + if top == 0 : print("\n") + +;------------- PASS ----------------- +defn v-print (e:UIntValue|SIntValue) : + val str = to-string(value(e)) + val out = substring(str,1,length(str) - 1) + print $ string-join $ match(e) : + (e:UIntValue) : [long!(type(e)) "'" out] + (e:SIntValue) : [long!(type(e)) "'s" out] +defn op-stream (doprim:DoPrim) -> Streamable : + defn cast-if (e:Expression) -> ? : + val signed? = for x in args(doprim) any? : type(x) typeof SIntType + if not signed? : e + else : match(type(e)) : + (t:SIntType) : ["$signed(" e ")"] + (t:UIntType) : ["$signed({1'b0," e "})"] + defn cast (e:Expression) -> ? : + match(type(doprim)) : + (t:UIntType) : e + (t:SIntType) : ["$signed(" e ")"] + defn a0 () -> Expression : args(doprim)[0] + defn a1 () -> Expression : args(doprim)[1] + defn a2 () -> Expression : args(doprim)[2] + defn c0 () -> Int : consts(doprim)[0] + defn c1 () -> Int : consts(doprim)[1] + + switch {_ == op(doprim)} : + ADD-OP : [cast-if(a0()) " + " cast-if(a1())] + SUB-OP : [cast-if(a0()) " - " cast-if(a1())] + MUL-OP : [cast-if(a0()) " * " cast-if(a1()) ] + DIV-OP : [cast-if(a0()) " / " cast-if(a1()) ] + MOD-OP : [cast-if(a0()) " % " cast-if(a1()) ] + QUO-OP : [cast-if(a0()) " / " cast-if(a1()) ] + REM-OP : [cast-if(a0()) " % " cast-if(a1()) ] + ADD-WRAP-OP : [cast-if(a0()), " + " cast-if(a1())] + SUB-WRAP-OP : [cast-if(a0()), " - " cast-if(a1())] + LESS-OP : [cast-if(a0()) " < " cast-if(a1())] + LESS-EQ-OP : [cast-if(a0()) " <= " cast-if(a1())] + GREATER-OP : [cast-if(a0()) " > " cast-if(a1())] + GREATER-EQ-OP : [cast-if(a0()) " >= " cast-if(a1())] + NEQUIV-OP : [cast-if(a0()) " != " cast-if(a1())] + EQUIV-OP : [cast-if(a0()) " == " cast-if(a1())] + NEQUAL-OP : [cast-if(a0()) " != " cast-if(a1())] + EQUAL-OP : [cast-if(a0()) " == " cast-if(a1())] + MUX-OP : [a0() " ? " cast(a1()) " : " cast(a2())] + PAD-OP : + val w = long!(type(a0())) + val diff = (to-long(c0()) - w) + if w == to-long(0) : [ a0() ] + else : match(type(doprim)) : + (t:SIntType) : ["{{" diff "{" a0() "[" w - to-long(1) "]}}, " a0() " }"] + (t) : ["{{" diff "'d0 }, " a0() " }"] + AS-UINT-OP : ["$unsigned(" a0() ")"] + AS-SINT-OP : ["$signed(" a0() ")"] + DYN-SHIFT-LEFT-OP : [cast(a0()) " << " a1()] + DYN-SHIFT-RIGHT-OP : + match(type(doprim)) : + (t:SIntType) : [cast(a0()) " >>> " a1()] + (t) : [cast(a0()) " >> " a1()] + SHIFT-LEFT-OP : [cast(a0()) " << " c0()] + SHIFT-RIGHT-OP : [cast(a0()) "[" long!(type(a0())) - to-long(1) ":" c0() "]"] + NEG-OP : ["-{" cast(a0()) "}"] + CONVERT-OP : + match(type(a0())) : + (t:UIntType) : ["{1'b0," cast(a0()) "}"] + (t:SIntType) : [cast(a0())] + BIT-NOT-OP : ["~ " cast(a0())] + BIT-AND-OP : [cast(a0()) " & " cast(a1())] + BIT-OR-OP : [cast(a0()) " | " cast(a1())] + BIT-XOR-OP : [cast(a0()) " ^ " cast(a1())] + CONCAT-OP : ["{" cast(a0()) "," cast(a1()) "}"] + BIT-SELECT-OP : [cast(a0()) "[" c0() "]"] + BITS-SELECT-OP : [cast(a0()) "[" c0() ":" c1() "]"] + BIT-AND-REDUCE-OP : + val v = Vector<Streamable>() + for b in 0 to to-int(long!(type(doprim))) do : + add(v,[cast(a0()) "[" b "]"]) + join(v," & ") + BIT-OR-REDUCE-OP : + val v = Vector<Streamable>() + for b in 0 to to-int(long!(type(doprim))) do : + add(v,[cast(a0() ) "[" b "]"]) + join(v," | ") + BIT-XOR-REDUCE-OP : + val v = Vector<Streamable>() + for b in 0 to to-int(long!(type(doprim))) do : + add(v,[cast(a0() ) "[" b "]"]) + join(v," ^ ") + +defn emit-verilog (m:InModule) -> Module : + val netlist = HashTable<Expression,Expression>(exp-hash) + val simlist = Vector<Stmt>() + val namehash = get-sym-hash(m,keys(v-keywords)) + defn build-netlist (s:Stmt) -> Stmt : + match(s) : + (s:Connect) : netlist[loc(s)] = exp(s) + (s:Conditionally) : add(simlist,s) + (s:DefNode) : + val e = WRef(name(s),get-type(s),NodeKind(),MALE) + netlist[e] = value(s) + (s) : map(build-netlist,s) + s + + val portdefs = Vector<Streamable>() + val declares = Vector<Streamable>() + val assigns = Vector<Streamable>() + val at-clock = HashTable<Expression,Vector<Streamable>>(exp-hash) + val initials = Vector<Streamable>() + val simulates = Vector<Streamable>() + defn declare (b:Symbol,n:Symbol,t:Type) : + match(t) : + (t:VectorType) : add(declares,[b " " type(t) " " n " [0:" size(t) - 1 "];"]) + (t) : add(declares,[b " " t " " n ";"]) + defn assign (e:Expression,value:Expression) : + add(assigns,["assign " e " = " value]) + defn update-and-reset (e:Expression,clk:Expression,reset?:Expression,init:Expression) : + if not key?(at-clock,clk) : + at-clock[clk] = Vector<Streamable>() + add(at-clock[clk],["if(" reset? ") begin"]) + add(at-clock[clk],[tab e " <= " init]) + add(at-clock[clk],["end else"]) + add(at-clock[clk],[tab e " <= " netlist[e]]) + add(at-clock[clk],["end"]) + defn update (e:Expression,value:Expression,clk:Expression,en:Expression) : + if not key?(at-clock,clk) : + at-clock[clk] = Vector<Streamable>() + if en == one : + add(at-clock[clk],[e " <= " value]) + else : + add(at-clock[clk],["if(" en ") begin"]) + add(at-clock[clk],[tab e " <= " value]) + add(at-clock[clk],["end"]) + defn initialize (e:Expression) : + add(initials,[e " = " rand-string(type(e))]) + defn initialize-mem (n:Symbol,i:Int,t:Type) : + add(initials,["for (initvar = 0; initvar < " i "; initvar = initvar+1)"]) + val index = WRef(`initvar,UnknownType(),ExpKind(),UNKNOWN-GENDER) + add(initials,[tab WSubAccess(wref(n,t),index,UnknownType(),FEMALE), " = " rand-string(t)]) + defn instantiate (n:Symbol,m:Symbol,es:List<Expression>) : + add(declares,[m " " n " ("]) + for (e in es,i in 1 to false) do : + val s = [tab "." remove-root(e) "(" lowered-name(e) ")"] + if i == length(es) : add(declares,[s ","]) + else : add(declares,s) + add(declares,[");"]) + for e in es do : + declare(`wire,lowered-name(e),type(e)) + val e* = WRef(lowered-name(e),type(e),kind(e),gender(e)) + if (gender(e) == FEMALE) : assign(e*,netlist[e]) + defn simulate (clk:Expression,en:Expression,s:Streamable) : + if not key?(at-clock,clk) : + at-clock[clk] = Vector<Streamable>() + add(at-clock[clk],["`ifndef SYNTHESIS"]) + add(at-clock[clk],[tab "if(" en ") begin"]) + add(at-clock[clk],[tab tab s]) + add(at-clock[clk],[tab "end"]) + add(at-clock[clk],["`endif"]) + defn stop (ret:Int) -> Streamable : + ["$fdisplay(32/'h80000002," ret ");$finish;"] + defn printf (str:String,args:List<Expression>) -> Streamable : + val str* = join(List(escape(str),args),",") + ["$fdisplay(32/'h80000002," str* ");"] + defn delay (e:Expression, n:Int, clk:Expression) -> Expression : + var e* = e + for i in 0 to n do : + val name = firrtl-gensym(`GEN,namehash) + declare(`reg,name,type(e)) + val e** = WRef(name,type(e),ExpKind(),UNKNOWN-GENDER) + update(e**,e*,clk,one) + e* = e** + e* + defn build-ports () : + for (p in ports(m),i in 0 to false) do : + var end = ",\n" + if length(ports(m)) - 1 == i : + end = "\n);\n" + switch {_ == direction(p)} : + INPUT : + add(portdefs,[direction(p) " " type(p) " " name(p) ]) + OUTPUT : + add(portdefs,[direction(p) " " type(p) " " name(p) ]) + val e* = WRef(name(p),type(p),PortKind(),FEMALE) + assign(e*,netlist[e*]) + if length(ports(m)) == 0 : print(");\n") + defn build-streams (s:Stmt) -> Stmt : + match(s) : + (s:Connect) : s + (s:DefWire) : + declare(`wire,name(s),type(s)) + val e = wref(name(s),type(s)) + assign(e,netlist[e]) + (s:DefRegister) : + declare(`reg,name(s),type(s)) + val e = wref(name(s),type(s)) + update-and-reset(e,clock(s),reset(s),init(s)) + initialize(e) + (s:DefPoison) : + declare(`reg,name(s),type(s)) + val e = wref(name(s),type(s)) + initialize(e) + (s:DefNode) : + declare(`wire,name(s),type(value(s))) + assign(WRef(name(s),type(value(s)),NodeKind(),MALE),value(s)) + (s:Stop) : simulate(clk(s),en(s),stop(ret(s))) + (s:Print) : simulate(clk(s),en(s),printf(string(s),args(s))) + (s:WDefInstance) : + val es = fast-create-exps(WRef(name(s),type(s),InstanceKind(),MALE)) + instantiate(name(s),module(s),es) + (s:DefMemory) : + val mem = WRef(name(s),get-type(s),MemKind(append-all([readers(s) writers(s) readwriters(s)])),UNKNOWN-GENDER) + defn mem-exp (p:Symbol,f:Symbol) : + val t1 = field-type(type(mem),p) + val t2 = field-type(t1,f) + WSubField{_,f,t2,UNKNOWN-GENDER} $ + WSubField{_,p,t1,UNKNOWN-GENDER} $ + mem + + declare(`reg,name(s),VectorType(data-type(s),depth(s))) + initialize-mem(name(s),depth(s),data-type(s)) + for r in readers(s) do : + val data = mem-exp(r,`data) + val addr = mem-exp(r,`addr) + val en = mem-exp(r,`en) + val clk = mem-exp(r,`clk) + + declare(`wire,lowered-name(data),type(data)) + declare(`wire,lowered-name(addr),type(addr)) + declare(`wire,lowered-name(en),type(en)) + declare(`wire,lowered-name(clk),type(clk)) + + ; Read port + assign(addr,netlist[addr]) ;Connects value to m.r.addr + assign(en,netlist[en]) ;Connects value to m.r.en + assign(clk,netlist[clk]) ;Connects value to m.r.clk + val addr* = delay(addr,read-latency(s),clk) + val en* = delay(en,read-latency(s),clk) + val mem-port = WSubAccess(mem,addr*,UnknownType(),UNKNOWN-GENDER) + update(data,mem-port,clk,en*) ; m.r.data <= m[addr*] + + for w in writers(s) do : + val data = mem-exp(w,`data) + val addr = mem-exp(w,`addr) + val mask = mem-exp(w,`mask) + val en = mem-exp(w,`en) + val clk = mem-exp(w,`clk) + + declare(`wire,lowered-name(data),type(data)) + declare(`wire,lowered-name(addr),type(addr)) + declare(`wire,lowered-name(mask),type(mask)) + declare(`wire,lowered-name(en),type(en)) + declare(`wire,lowered-name(clk),type(clk)) + + ; Write port + assign(data,netlist[data]) + assign(addr,netlist[addr]) + assign(mask,netlist[mask]) + assign(en,netlist[en]) + assign(clk,netlist[clk]) + + val data* = delay(data,write-latency(s) - 1,clk) + val addr* = delay(addr,write-latency(s) - 1,clk) + val mask* = delay(mask,write-latency(s) - 1,clk) + val en* = delay(en,write-latency(s) - 1,clk) + val mem-port = WSubAccess(mem,addr*,UnknownType(),UNKNOWN-GENDER) + update(mem-port,data*,clk,AND(en*,mask*)) + + for rw in readwriters(s) do : + val rdata = mem-exp(rw,`rdata) + val raddr = mem-exp(rw,`raddr) + val ren = mem-exp(rw,`ren) + val wdata = mem-exp(rw,`wdata) + val waddr = mem-exp(rw,`waddr) + val wmask = mem-exp(rw,`wmask) + val wen = mem-exp(rw,`wen) + val clk = mem-exp(rw,`clk) + + declare(`wire,lowered-name(rdata),type(rdata)) + declare(`wire,lowered-name(raddr),type(raddr)) + declare(`wire,lowered-name(ren),type(ren)) + declare(`wire,lowered-name(wdata),type(wdata)) + declare(`wire,lowered-name(waddr),type(waddr)) + declare(`wire,lowered-name(wmask),type(wmask)) + declare(`wire,lowered-name(wen),type(wen)) + declare(`wire,lowered-name(clk),type(clk)) + + ; Both + assign(clk,netlist[clk]) + + ; Read + assign(raddr,netlist[raddr]) + assign(ren,netlist[ren]) + val raddr* = delay(raddr,read-latency(s),clk) + val ren* = delay(ren,read-latency(s),clk) + val rmem-port = WSubAccess(mem,raddr*,UnknownType(),UNKNOWN-GENDER) + update(rdata,rmem-port,clk,ren*) + + ; Write + assign(wdata,netlist[wdata]) + assign(waddr,netlist[waddr]) + assign(wmask,netlist[wmask]) + assign(wen,netlist[wen]) + + val wdata* = delay(wdata,write-latency(s) - 1,clk) + val waddr* = delay(waddr,write-latency(s) - 1,clk) + val wmask* = delay(wmask,write-latency(s) - 1,clk) + val wen* = delay(wen,write-latency(s) - 1,clk) + val wmem-port = WSubAccess(mem,waddr*,UnknownType(),UNKNOWN-GENDER) + update(wmem-port,wdata*,clk,AND(wen*,wmask*)) + (s:Begin) : map(build-streams,s) + s + + defn emit-streams () : + emit(["module " name(m) "("]) + if !empty?(portdefs) : + for (x in portdefs, i in 0 to false) do : + if i != length(portdefs) : emit([tab x ","]) + else : emit([tab x]) + emit([");"]) + + if !empty?(declares) : + for x in declares do : emit([tab x]) + + if !empty?(assigns) : + for x in assigns do : emit([tab x]) + + if !empty?(initials) : + emit(["`ifndef SYNTHESIS"]) + emit([" integer initvar;"]) + emit([" initial begin"]) + emit([" #0.002;"]) + for x in initials do : + emit([tab x]) + emit([" end"]) + emit(["`endif"]) + + for clk-stream in at-clock do : + if !empty?(value(clk-stream)) : + emit([tab "always @(posedge " key(clk-stream) ") begin"]) + for x in value(clk-stream) do : + emit([tab tab x]) + emit([tab "end"]) + + emit(["endmodule"]) + + build-netlist(body(m)) + build-ports() + build-streams(body(m)) + emit-streams() + m + +defn emit-verilog (with-output:(() -> False) -> False, c:Circuit) : + with-output $ fn () : + for m in modules(c) do : + match(m) : + (m:InModule) : emit-verilog(m) + (m:ExModule) : false + c + + |
