aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorazidar2015-11-06 18:55:39 -0800
committerazidar2016-01-16 14:28:16 -0800
commit9113d54b61b681215a3cc9fcf44e64167fad0568 (patch)
tree3cf0e1d3e48397a71c398fad38bef8af0c827e09 /src
parentffa090c10d6210395e3f304e56008e2183a85698 (diff)
WIP. Compiles, need to test
Diffstat (limited to 'src')
-rw-r--r--src/main/stanza/bigint2.stanza25
-rw-r--r--src/main/stanza/errorstemp.stanza994
-rw-r--r--src/main/stanza/firrtl-test-main.stanza39
-rw-r--r--src/main/stanza/ir-parser.stanza2
-rw-r--r--src/main/stanza/ir-utils.stanza46
-rw-r--r--src/main/stanza/passes.stanza372
-rw-r--r--src/main/stanza/passes.stanza22662
-rw-r--r--src/main/stanza/passes.stanza32687
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
+
+