diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/main/stanza/compilers.stanza | 109 | ||||
| -rw-r--r-- | src/main/stanza/custom-compiler.stanza | 94 | ||||
| -rw-r--r-- | src/main/stanza/custom-passes.stanza | 286 | ||||
| -rw-r--r-- | src/main/stanza/errors.stanza | 28 | ||||
| -rw-r--r-- | src/main/stanza/firrtl-ir.stanza | 56 | ||||
| -rw-r--r-- | src/main/stanza/firrtl-main.stanza | 1 | ||||
| -rw-r--r-- | src/main/stanza/firrtl-test-main.stanza | 18 | ||||
| -rw-r--r-- | src/main/stanza/ir-parser.stanza | 95 | ||||
| -rw-r--r-- | src/main/stanza/ir-utils.stanza | 144 | ||||
| -rw-r--r-- | src/main/stanza/passes.stanza | 4126 | ||||
| -rw-r--r-- | src/main/stanza/primop.stanza | 325 | ||||
| -rw-r--r-- | src/main/stanza/symbolic-value.stanza | 71 | ||||
| -rw-r--r-- | src/main/stanza/verilog.stanza | 141 |
13 files changed, 2876 insertions, 2618 deletions
diff --git a/src/main/stanza/compilers.stanza b/src/main/stanza/compilers.stanza index 88a4141a..bed150ba 100644 --- a/src/main/stanza/compilers.stanza +++ b/src/main/stanza/compilers.stanza @@ -2,43 +2,42 @@ defpackage firrtl/compiler : import core import verse import firrtl/passes - import firrtl/errors - import firrtl/flo - import firrtl/verilog - import firrtl/firrtl + ;import firrtl/errors + ;import firrtl/flo + ;import firrtl/verilog import firrtl/ir2 import firrtl/ir-utils -public defstruct StandardFlo <: Compiler : - with-output : (() -> False) -> False with: (as-method => true) -public defmethod passes (c:StandardFlo) -> List<Pass> : - to-list $ [ - RemoveSpecialChars() - RemoveScopes() - CheckHighForm() - ;; TempElimination() - ToWorkingIR() - ResolveKinds() - CheckKinds() - InferTypes() - CheckTypes() - ResolveGenders() - CheckGenders() - ExpandAccessors() - LowerToGround() - InlineIndexed() - ExpandWhens() - InferWidths() - Pad() - Inline() - SplitExp() - ToRealIR() - CheckWidths() - ;RemoveSpecialChars() - CheckHighForm() - CheckLowForm() - Flo(with-output(c)) - ] +;public defstruct StandardFlo <: Compiler : +; with-output : (() -> False) -> False with: (as-method => true) +;public defmethod passes (c:StandardFlo) -> List<Pass> : +; to-list $ [ +; RemoveSpecialChars() +; RemoveScopes() +; CheckHighForm() +; ;; TempElimination() +; ToWorkingIR() +; ResolveKinds() +; CheckKinds() +; InferTypes() +; CheckTypes() +; ResolveGenders() +; CheckGenders() +; ExpandAccessors() +; LowerToGround() +; InlineIndexed() +; ExpandWhens() +; InferWidths() +; Pad() +; Inline() +; SplitExp() +; ToRealIR() +; CheckWidths() +; ;RemoveSpecialChars() +; CheckHighForm() +; CheckLowForm() +; Flo(with-output(c)) +; ] public defstruct StandardVerilog <: Compiler : with-output : (() -> False) -> False with: (as-method => true) @@ -46,37 +45,37 @@ public defmethod backend (c:StandardVerilog) -> List<Pass> : to-list $ [ Verilog(with-output(c)) ] public defmethod passes (c:StandardVerilog) -> List<Pass> : to-list $ [ - RemoveSpecialChars() ;R + ;RemoveSpecialChars() ;R ;RemoveScopes() ;R - CheckHighForm() ;R - TempElimination() ;R + ;CheckHighForm() ;R + ;TempElimination() ;R ; Needs to check number of uses ToWorkingIR() ;R -> W ResolveKinds() ;W InferTypes() ;R ResolveGenders() ;W - CheckGenders() ;W - CheckKinds() ;W - CheckTypes() ;R - ExpandAccessors() ;W - LowerToGround() ;W - ;ExpandIndexedConnects() ;W - InlineIndexed() - InferTypes() ;R + ;CheckGenders() ;W + ;CheckKinds() ;W + ;CheckTypes() ;R + ExpandAccesses() ;W + ExpandConnects() ;W ResolveGenders() ;W - CheckTypes() ;R - CheckGenders() ;W + ;LowerToGround() ;W + ;ExpandIndexedConnects() ;W + ReplaceIndexers() + ;InferTypes() ;R + ;CheckGenders() ;W ExpandWhens() ;W InferWidths() ;R - ToRealIR() ;W -> R - CheckWidths() ;R - Pad() ;R + ;ToRealIR() ;W -> R + ;CheckWidths() ;R + ;Pad() ;R ConstProp() ;R SplitExp() ;R - CheckWidths() ;R - CheckHighForm() ;R - CheckLowForm() ;R - CheckInitialization() ;R - Verilog(with-output(c)) ;R + ;CheckWidths() ;R + ;CheckHighForm() ;R + ;CheckLowForm() ;R + ;CheckInitialization() ;R + ;Verilog(with-output(c)) ;R ] public defstruct StandardFIRRTL <: Compiler : diff --git a/src/main/stanza/custom-compiler.stanza b/src/main/stanza/custom-compiler.stanza index 0f43da58..908f70ff 100644 --- a/src/main/stanza/custom-compiler.stanza +++ b/src/main/stanza/custom-compiler.stanza @@ -1,47 +1,47 @@ -defpackage firrtl/custom-compiler : - import core - import verse - import firrtl/ir-utils - import firrtl/ir2 - import firrtl/passes - import firrtl/errors - import firrtl/verilog - import firrtl/custom-passes - -public defstruct InstrumentedVerilog <: Compiler : - with-output: (() -> False) -> False with: (as-method => true) - args: List<String> -public defmethod passes (c:InstrumentedVerilog) -> List<Pass> : - to-list $ [ - WhenCoverage(args(c)[0],args(c)[1]) - RemoveSpecialChars() - RemoveScopes() - CheckHighForm() - TempElimination() - ToWorkingIR() - ;; MakeExplicitReset() - ResolveKinds() - CheckKinds() - InferTypes() - CheckTypes() - ResolveGenders() - CheckGenders() - ExpandAccessors() - LowerToGround() - InlineIndexed() - InferTypes() - CheckGenders() - ExpandWhens() - InferWidths() - ;Pad() - ConstProp() - SplitExp() - ToRealIR() - ;RemoveSpecialChars() - CheckHighForm() - CheckLowForm() - CheckInitialization() - Verilog(with-output(c)) - ] - - +;defpackage firrtl/custom-compiler : +; import core +; import verse +; import firrtl/ir-utils +; import firrtl/ir2 +; import firrtl/passes +; import firrtl/errors +; import firrtl/verilog +; import firrtl/custom-passes +; +;public defstruct InstrumentedVerilog <: Compiler : +; with-output: (() -> False) -> False with: (as-method => true) +; args: List<String> +;public defmethod passes (c:InstrumentedVerilog) -> List<Pass> : +; to-list $ [ +; WhenCoverage(args(c)[0],args(c)[1]) +; RemoveSpecialChars() +; RemoveScopes() +; CheckHighForm() +; TempElimination() +; ToWorkingIR() +; ;; MakeExplicitReset() +; ResolveKinds() +; CheckKinds() +; InferTypes() +; CheckTypes() +; ResolveGenders() +; CheckGenders() +; ExpandAccessors() +; LowerToGround() +; InlineIndexed() +; InferTypes() +; CheckGenders() +; ExpandWhens() +; InferWidths() +; ;Pad() +; ConstProp() +; SplitExp() +; ToRealIR() +; ;RemoveSpecialChars() +; CheckHighForm() +; CheckLowForm() +; CheckInitialization() +; Verilog(with-output(c)) +; ] +; +; diff --git a/src/main/stanza/custom-passes.stanza b/src/main/stanza/custom-passes.stanza index ed71784d..65c5fa9b 100644 --- a/src/main/stanza/custom-passes.stanza +++ b/src/main/stanza/custom-passes.stanza @@ -1,122 +1,17 @@ -defpackage firrtl/custom-passes : - import core - import verse - import firrtl/ir-utils - import firrtl/ir2 - import bigint2 - -;============ When Coverage ============= -public defstruct WhenCoverage <: Pass : - port-name : String - reg-name : String -public defmethod pass (b:WhenCoverage) -> (Circuit -> Circuit) : when-coverage{port-name(b),reg-name(b),_} -public defmethod name (b:WhenCoverage) -> String : "When Coverage" -public defmethod short-name (b:WhenCoverage) -> String : "when-coverage" - -;============ Utilz ============= -defn concat-all (ls:List<Expression>) -> Expression : - if length(ls) == 0 : error("Shouldn't be here") - if length(ls) == 1 : head(ls) - else : DoPrim( CONCAT-OP, - list(head(ls),concat-all(tail(ls))), - list(), - UIntType(UnknownWidth())) - -;============ When Coverage Pass ============= -;port width = 1 bit per scope + portwidths of all instances - -defn needs-instrumentation (m:Module,ms:List<Module>,instrument?:HashTable<Symbol,True|False>) -> False : - defn needs-instrumentation-s (s:Stmt) -> False : - match(s) : - (s:Conditionally) :instrument?[name(m)] = true - (s:DefInstance) : - val module-of-inst = for x in ms find : name(x) == name(module(s) as Ref) - if module-of-inst != false : - needs-instrumentation(module-of-inst as Module,ms,instrument?) - instrument?[name(m)] = instrument?[name(module-of-inst as Module)] - (s) : false - do(needs-instrumentation-s,s) - - match(m) : - (m:InModule) : do(needs-instrumentation-s,body(m)) - (m:ExModule) : false - -defn when-coverage (port-name:Symbol, reg-name:Symbol, instrument?:HashTable<Symbol,True|False>, m:InModule) -> InModule : - val when-bits = Vector<Ref>() - val inst-bits = Vector<Ref>() - val sym = HashTable<Symbol,Int>(symbol-hash) - val w1 = LongWidth(1) - val t1 = UIntType(w1) - val u1 = UIntValue(BigIntLit("h1"),w1) - defn when-coverage (s:Stmt) -> Stmt : - match(s) : - (s:Conditionally) : - val ref = Ref(firrtl-gensym(reg-name,sym),t1) - add(when-bits,ref) - val conseq* = Begin(list(Connect(FileInfo()ref,u1),conseq(s))) - map(when-coverage,Conditionally(info(s),pred(s),conseq*,alt(s))) - (s:DefInstance) : - if instrument?[name(module(s) as Ref)] : - val ref = Ref(firrtl-gensym(port-name,sym),UIntType(UnknownWidth())) - add(inst-bits,ref) - val sfld = Subfield(Ref(name(s),UnknownType()),port-name,UnknownType()) - Begin(list(s,Connect(FileInfo(),ref,sfld))) - else : s - (s) : map(when-coverage,s) - - val body* = when-coverage(body(m)) - val logic = Vector<Stmt>() - val port-ref = Ref(port-name,UIntType(UnknownWidth())) - - val w-ls = to-list $ when-bits - if length(w-ls) != 0 : - val reg-ref = Ref(reg-name,UIntType(LongWidth(length(w-ls)))) - ;add{logic,_} $ DefRegister(FileInfo(),name(reg-ref),type(reg-ref)) TODO add clock and reset - for (x in w-ls, i in 0 to false) do : - add{logic,_} $ DefWire(FileInfo(),name(x),type(x)) - add{logic,_} $ Connect(FileInfo(),x,DoPrim(BIT-SELECT-OP,list(reg-ref),list(i),UIntType(w1))) - add{logic,_} $ Connect(FileInfo(),reg-ref,concat-all(w-ls)) - add{logic,_} $ OnReset(FileInfo(),reg-ref,UIntValue(BigIntLit("h0"),LongWidth(length(w-ls)))) - - val i-ls = to-list $ inst-bits - if length(i-ls) != 0 : - for (x in i-ls, i in 0 to false) do : - add{logic,_} $ DefWire(FileInfo(),name(x),type(x)) - add{logic,_} $ Connect(FileInfo(),x,UIntValue(BigIntLit("h0"),UnknownWidth())) - - if instrument?[name(m)] : add{logic,_} $ Connect(FileInfo(),port-ref,concat-all(append(w-ls,i-ls))) - - if length(logic) != 0 : - val ports* = List(Port(FileInfo(),port-name,OUTPUT,UIntType(UnknownWidth())),ports(m)) - val body** = Begin(list(Begin(to-list $ logic),body*)) - InModule(info(m),name(m),ports*,body**) - else : m - -public defn when-coverage (port-name:String, reg-name:String, c:Circuit) : - val instrument? = HashTable<Symbol,True|False>(symbol-hash) - for m in modules(c) do : - instrument?[name(m)] = false - val top = for m in modules(c) find : name(m) == main(c) - if top != false : needs-instrumentation(top as Module,modules(c),instrument?) - - val modules* = for m in modules(c) map : - match(m) : - (m:InModule) : - when-coverage(to-symbol $ port-name,to-symbol $ reg-name,instrument?,m) - (m:ExModule) : m - Circuit(info(c),modules*,main(c)) - -;;============ Temporal Check ============= -;public defstruct TemporalAssert : -; module : String -; name : String -; value : Int -; cycle : Int -;public defstruct InsertTemporalAsserts <: Pass : -; asserts : List<TemporalAssert> -;public defmethod pass (b:InsertTemporalAsserts) -> (Circuit -> Circuit) : insert-temporal-assert{asserts(b),_} -;public defmethod name (b:InsertTemporalAsserts) -> String : "Insert Temporal Assert" -;public defmethod short-name (b:InsertTemporalAsserts) -> String : "insert-temporal-assert" +;defpackage firrtl/custom-passes : +; import core +; import verse +; import firrtl/ir-utils +; import firrtl/ir2 +; import bigint2 +; +;;============ When Coverage ============= +;public defstruct WhenCoverage <: Pass : +; port-name : String +; reg-name : String +;public defmethod pass (b:WhenCoverage) -> (Circuit -> Circuit) : when-coverage{port-name(b),reg-name(b),_} +;public defmethod name (b:WhenCoverage) -> String : "When Coverage" +;public defmethod short-name (b:WhenCoverage) -> String : "when-coverage" ; ;;============ Utilz ============= ;defn concat-all (ls:List<Expression>) -> Expression : @@ -127,28 +22,17 @@ public defn when-coverage (port-name:String, reg-name:String, c:Circuit) : ; list(), ; UIntType(UnknownWidth())) ; -;;============ Insert Temporal Asserts Pass ============= -; -; -;public defn insert-temporal-assert (asserts:List<TemporalAssert>,m:Module) -> Module : -; -; for statement in body(m) do : -; -; for a in asserts do : -; val mod* = for m in modules(c) find : name(m) == module(a) -; match(mod*) : -; (m:False) : error("Module not found") -; (m:Module) : -; +;;============ When Coverage Pass ============= +;;port width = 1 bit per scope + portwidths of all instances ; -;defn needs-ita-instrumentation (m:Module,ms:List<Module>,instrument?:HashTable<Symbol,True|False>,asserts:List<TemporalAssert>) -> False : +;defn needs-instrumentation (m:Module,ms:List<Module>,instrument?:HashTable<Symbol,True|False>) -> False : ; defn needs-instrumentation-s (s:Stmt) -> False : ; match(s) : -; (s:DefWire|DefRegister) : instrument?[name(m)] = contains?(name(s),map(name,asserts)) +; (s:Conditionally) :instrument?[name(m)] = true ; (s:DefInstance) : ; val module-of-inst = for x in ms find : name(x) == name(module(s) as Ref) ; if module-of-inst != false : -; needs-ita-instrumentation(module-of-inst as Module,ms,instrument?,asserts) +; needs-instrumentation(module-of-inst as Module,ms,instrument?) ; instrument?[name(m)] = instrument?[name(module-of-inst as Module)] ; (s) : false ; do(needs-instrumentation-s,s) @@ -157,17 +41,17 @@ public defn when-coverage (port-name:String, reg-name:String, c:Circuit) : ; (m:InModule) : do(needs-instrumentation-s,body(m)) ; (m:ExModule) : false ; -;defn insert-temporal-asserts (port-name:Symbol,assert-name:Symbol,asserts:List<TemporalAssert>,instrument?:HashTable<Symbol,True|False>, m:InModule) -> InModule : +;defn when-coverage (port-name:Symbol, reg-name:Symbol, instrument?:HashTable<Symbol,True|False>, m:InModule) -> InModule : ; val when-bits = Vector<Ref>() ; val inst-bits = Vector<Ref>() ; val sym = HashTable<Symbol,Int>(symbol-hash) ; val w1 = LongWidth(1) ; val t1 = UIntType(w1) -; val u1 = UIntValue(to-long $ 1,w1) -; defn insert-temporal-asserts (s:Stmt) -> Stmt : +; val u1 = UIntValue(BigIntLit("h1"),w1) +; defn when-coverage (s:Stmt) -> Stmt : ; match(s) : -; (s:DefWire|DefRegister) : -; val ref = Ref(firrtl-gensym(name(s),sym),t1) +; (s:Conditionally) : +; val ref = Ref(firrtl-gensym(reg-name,sym),t1) ; add(when-bits,ref) ; val conseq* = Begin(list(Connect(FileInfo()ref,u1),conseq(s))) ; map(when-coverage,Conditionally(info(s),pred(s),conseq*,alt(s))) @@ -187,18 +71,18 @@ public defn when-coverage (port-name:String, reg-name:String, c:Circuit) : ; val w-ls = to-list $ when-bits ; if length(w-ls) != 0 : ; val reg-ref = Ref(reg-name,UIntType(LongWidth(length(w-ls)))) -; add{logic,_} $ DefRegister(FileInfo(),name(reg-ref),type(reg-ref)) -; add{logic,_} $ OnReset(FileInfo(),reg-ref,UIntValue(to-long $ 0,LongWidth(length(w-ls)))) +; ;add{logic,_} $ DefRegister(FileInfo(),name(reg-ref),type(reg-ref)) TODO add clock and reset ; for (x in w-ls, i in 0 to false) do : ; add{logic,_} $ DefWire(FileInfo(),name(x),type(x)) ; add{logic,_} $ Connect(FileInfo(),x,DoPrim(BIT-SELECT-OP,list(reg-ref),list(i),UIntType(w1))) ; add{logic,_} $ Connect(FileInfo(),reg-ref,concat-all(w-ls)) +; add{logic,_} $ OnReset(FileInfo(),reg-ref,UIntValue(BigIntLit("h0"),LongWidth(length(w-ls)))) ; ; val i-ls = to-list $ inst-bits ; if length(i-ls) != 0 : ; for (x in i-ls, i in 0 to false) do : ; add{logic,_} $ DefWire(FileInfo(),name(x),type(x)) -; add{logic,_} $ Connect(FileInfo(),x,UIntValue(to-long $ 0,UnknownWidth())) +; add{logic,_} $ Connect(FileInfo(),x,UIntValue(BigIntLit("h0"),UnknownWidth())) ; ; if instrument?[name(m)] : add{logic,_} $ Connect(FileInfo(),port-ref,concat-all(append(w-ls,i-ls))) ; @@ -222,3 +106,119 @@ public defn when-coverage (port-name:String, reg-name:String, c:Circuit) : ; (m:ExModule) : m ; Circuit(info(c),modules*,main(c)) ; +;;;============ Temporal Check ============= +;;public defstruct TemporalAssert : +;; module : String +;; name : String +;; value : Int +;; cycle : Int +;;public defstruct InsertTemporalAsserts <: Pass : +;; asserts : List<TemporalAssert> +;;public defmethod pass (b:InsertTemporalAsserts) -> (Circuit -> Circuit) : insert-temporal-assert{asserts(b),_} +;;public defmethod name (b:InsertTemporalAsserts) -> String : "Insert Temporal Assert" +;;public defmethod short-name (b:InsertTemporalAsserts) -> String : "insert-temporal-assert" +;; +;;;============ Utilz ============= +;;defn concat-all (ls:List<Expression>) -> Expression : +;; if length(ls) == 0 : error("Shouldn't be here") +;; if length(ls) == 1 : head(ls) +;; else : DoPrim( CONCAT-OP, +;; list(head(ls),concat-all(tail(ls))), +;; list(), +;; UIntType(UnknownWidth())) +;; +;;;============ Insert Temporal Asserts Pass ============= +;; +;; +;;public defn insert-temporal-assert (asserts:List<TemporalAssert>,m:Module) -> Module : +;; +;; for statement in body(m) do : +;; +;; for a in asserts do : +;; val mod* = for m in modules(c) find : name(m) == module(a) +;; match(mod*) : +;; (m:False) : error("Module not found") +;; (m:Module) : +;; +;; +;;defn needs-ita-instrumentation (m:Module,ms:List<Module>,instrument?:HashTable<Symbol,True|False>,asserts:List<TemporalAssert>) -> False : +;; defn needs-instrumentation-s (s:Stmt) -> False : +;; match(s) : +;; (s:DefWire|DefRegister) : instrument?[name(m)] = contains?(name(s),map(name,asserts)) +;; (s:DefInstance) : +;; val module-of-inst = for x in ms find : name(x) == name(module(s) as Ref) +;; if module-of-inst != false : +;; needs-ita-instrumentation(module-of-inst as Module,ms,instrument?,asserts) +;; instrument?[name(m)] = instrument?[name(module-of-inst as Module)] +;; (s) : false +;; do(needs-instrumentation-s,s) +;; +;; match(m) : +;; (m:InModule) : do(needs-instrumentation-s,body(m)) +;; (m:ExModule) : false +;; +;;defn insert-temporal-asserts (port-name:Symbol,assert-name:Symbol,asserts:List<TemporalAssert>,instrument?:HashTable<Symbol,True|False>, m:InModule) -> InModule : +;; val when-bits = Vector<Ref>() +;; val inst-bits = Vector<Ref>() +;; val sym = HashTable<Symbol,Int>(symbol-hash) +;; val w1 = LongWidth(1) +;; val t1 = UIntType(w1) +;; val u1 = UIntValue(to-long $ 1,w1) +;; defn insert-temporal-asserts (s:Stmt) -> Stmt : +;; match(s) : +;; (s:DefWire|DefRegister) : +;; val ref = Ref(firrtl-gensym(name(s),sym),t1) +;; add(when-bits,ref) +;; val conseq* = Begin(list(Connect(FileInfo()ref,u1),conseq(s))) +;; map(when-coverage,Conditionally(info(s),pred(s),conseq*,alt(s))) +;; (s:DefInstance) : +;; if instrument?[name(module(s) as Ref)] : +;; val ref = Ref(firrtl-gensym(port-name,sym),UIntType(UnknownWidth())) +;; add(inst-bits,ref) +;; val sfld = Subfield(Ref(name(s),UnknownType()),port-name,UnknownType()) +;; Begin(list(s,Connect(FileInfo(),ref,sfld))) +;; else : s +;; (s) : map(when-coverage,s) +;; +;; val body* = when-coverage(body(m)) +;; val logic = Vector<Stmt>() +;; val port-ref = Ref(port-name,UIntType(UnknownWidth())) +;; +;; val w-ls = to-list $ when-bits +;; if length(w-ls) != 0 : +;; val reg-ref = Ref(reg-name,UIntType(LongWidth(length(w-ls)))) +;; add{logic,_} $ DefRegister(FileInfo(),name(reg-ref),type(reg-ref)) +;; add{logic,_} $ OnReset(FileInfo(),reg-ref,UIntValue(to-long $ 0,LongWidth(length(w-ls)))) +;; for (x in w-ls, i in 0 to false) do : +;; add{logic,_} $ DefWire(FileInfo(),name(x),type(x)) +;; add{logic,_} $ Connect(FileInfo(),x,DoPrim(BIT-SELECT-OP,list(reg-ref),list(i),UIntType(w1))) +;; add{logic,_} $ Connect(FileInfo(),reg-ref,concat-all(w-ls)) +;; +;; val i-ls = to-list $ inst-bits +;; if length(i-ls) != 0 : +;; for (x in i-ls, i in 0 to false) do : +;; add{logic,_} $ DefWire(FileInfo(),name(x),type(x)) +;; add{logic,_} $ Connect(FileInfo(),x,UIntValue(to-long $ 0,UnknownWidth())) +;; +;; if instrument?[name(m)] : add{logic,_} $ Connect(FileInfo(),port-ref,concat-all(append(w-ls,i-ls))) +;; +;; if length(logic) != 0 : +;; val ports* = List(Port(FileInfo(),port-name,OUTPUT,UIntType(UnknownWidth())),ports(m)) +;; val body** = Begin(list(Begin(to-list $ logic),body*)) +;; InModule(info(m),name(m),ports*,body**) +;; else : m +;; +;;public defn when-coverage (port-name:String, reg-name:String, c:Circuit) : +;; val instrument? = HashTable<Symbol,True|False>(symbol-hash) +;; for m in modules(c) do : +;; instrument?[name(m)] = false +;; val top = for m in modules(c) find : name(m) == main(c) +;; if top != false : needs-instrumentation(top as Module,modules(c),instrument?) +;; +;; val modules* = for m in modules(c) map : +;; match(m) : +;; (m:InModule) : +;; when-coverage(to-symbol $ port-name,to-symbol $ reg-name,instrument?,m) +;; (m:ExModule) : m +;; Circuit(info(c),modules*,main(c)) +;; diff --git a/src/main/stanza/errors.stanza b/src/main/stanza/errors.stanza index b6a854af..5b0d3864 100644 --- a/src/main/stanza/errors.stanza +++ b/src/main/stanza/errors.stanza @@ -283,7 +283,7 @@ public defn check-high-form (c:Circuit) -> Circuit : defn check-high-form-w (info:FileInfo,w:Width,unknown-ok?:True|False) -> Width : match(w) : - (w:LongWidth) : + (w:IntWidth) : if width(w) <= to-long(0) : add(errors,NegWidth(info)) w (w:UnknownWidth) : @@ -364,7 +364,7 @@ public defn check-high-form (c:Circuit) -> Circuit : check-valid-loc(info(s),loc(s)) check-high-form-e(info(s),loc(s),names) check-high-form-e(info(s),exp(s),names) - (s:PrintfStmt) : + (s:Print) : for x in args(s) do: check-high-form-e(info(s),x,names) check-fstring(info(s),string(s),length(args(s))) @@ -476,7 +476,7 @@ public defn check-kinds (c:Circuit) -> Circuit : println(type(source(s))) add(errors,AccessVecOrMem(info(s))) (s:Conditionally) : check-not-mem(info(s),pred(s)) - (s:PrintfStmt) : + (s:Print) : for x in args(s) do : check-not-mem(info(s),x) (s:Connect) : @@ -714,7 +714,7 @@ public defn check-types (c:Circuit) -> Circuit : (s:OnReset) : if type(loc(s)) != type(exp(s)) : add(errors,InvalidConnect(info(s))) if has-flip?(type(loc(s))) : add(errors,OnResetIllegalFlips(info(s))) - (s:PrintfStmt) : + (s:Print) : for x in args(s) do : if type(x) != ut() and type(x) != st(): add(errors,PrintfArgNotGround(info(s))) @@ -850,7 +850,7 @@ public defn check-genders (c:Circuit) -> Circuit : (s:Connect) : check-gender(info(s),genders,loc(s),FEMALE) check-gender(info(s),genders,exp(s),MALE) - (s:PrintfStmt) : + (s:Print) : for x in args(s) do : check-gender(info(s),genders,x,MALE) (s:BulkConnect) : @@ -861,8 +861,8 @@ public defn check-genders (c:Circuit) -> Circuit : check-gender(info(s),genders,exp(s),MALE) (s:Conditionally) : check-gender(info(s),genders,pred(s),MALE) - (s:EmptyStmt) : false - (s:StopStmt) : false + (s:Empty) : false + (s:Stop) : false (s:Begin) : false @@ -972,7 +972,7 @@ public defn check-width (c:Circuit) -> Circuit : defn check-width-m (m:Module) -> False : defn check-width-w (info:FileInfo,w:Width) -> Width : match(w) : - (w:LongWidth) : + (w:IntWidth) : if width(w) <= to-long(0) : add(errors,NegWidth(info)) (w) : add(errors,UninferredWidth(info)) @@ -982,14 +982,14 @@ public defn check-width (c:Circuit) -> Circuit : match(map(check-width-e{info,_},e)) : (e:UIntValue) : match(width(e)) : - (w:LongWidth) : + (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:LongWidth) : + (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)) @@ -1102,13 +1102,13 @@ public defn check-low-form (c:Circuit) -> Circuit : add(insts,name(s)) (s:DefNode) : check-correct-exp(info(s),value(s)) - (s:PrintfStmt) : + (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 EmptyStmt) or (conseq(s) typeof Begin) : add(errors,NoWhen(info(s))) + 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) : @@ -1119,8 +1119,8 @@ public defn check-low-form (c:Circuit) -> Circuit : 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:EmptyStmt) : false - (s:StopStmt) : false + (s:Empty) : false + (s:Stop) : false (s:Begin) : do(check-low-form-s,s) match(m) : diff --git a/src/main/stanza/firrtl-ir.stanza b/src/main/stanza/firrtl-ir.stanza index d3f60646..ec53465e 100644 --- a/src/main/stanza/firrtl-ir.stanza +++ b/src/main/stanza/firrtl-ir.stanza @@ -13,24 +13,18 @@ public val scope-delin = `_ public val inline-delin = `_ public val delin = `_ -public definterface PortDirection -public val INPUT = new PortDirection -public val OUTPUT = new PortDirection +public definterface Direction +public val INPUT = new Direction +public val OUTPUT = new Direction public definterface Flip public val DEFAULT = new Flip public val REVERSE = new Flip -public definterface AccDirection -public val READ = new AccDirection -public val WRITE = new AccDirection -public val INFER = new AccDirection -public val RDWR = new AccDirection - public definterface Width public defstruct UnknownWidth <: Width -public defn LongWidth (width:Int) : LongWidth(to-long(width)) -public defstruct LongWidth <: Width : +public defn IntWidth (width:Int) : IntWidth(to-long(width)) +public defstruct IntWidth <: Width : width: Long public definterface PrimOp @@ -78,14 +72,18 @@ public defmulti type (e:Expression) -> Type public defstruct Ref <: Expression : name: Symbol type: Type with: (as-method => true) -public defstruct Subfield <: Expression : +public defstruct SubField <: Expression : exp: Expression name: Symbol type: Type with: (as-method => true) -public defstruct Index <: Expression : +public defstruct SubIndex <: Expression : exp: Expression value: Int type: Type with: (as-method => true) +public defstruct SubAccess <: Expression : + exp: Expression + index: Expression + type: Type with: (as-method => true) public defstruct UIntValue <: Expression : value: BigInt width: Width @@ -111,27 +109,25 @@ public defstruct DefRegister <: Stmt : type: Type clock: Expression reset: Expression + init: Expression public defstruct DefInstance <: Stmt : ;LOW info: FileInfo with: (as-method => true) name: Symbol - module: Expression + module: Symbol public defstruct DefMemory <: Stmt : ;LOW info: FileInfo with: (as-method => true) name: Symbol - type: Type - seq?: True|False - clock: Expression - size: Int + data-type: Type + depth: Int + write-latency: Int + read-latency: Int + readers: List<Symbol> + writers: List<Symbol> + readwriters: List<Symbol> public defstruct DefNode <: Stmt : ;LOW info: FileInfo with: (as-method => true) name: Symbol value: Expression -public defstruct DefAccessor <: Stmt : - info: FileInfo with: (as-method => true) - name: Symbol - source: Expression - index: Expression - acc-dir: AccDirection public defstruct DefPoison <: Stmt : ;LOW info: FileInfo with: (as-method => true) name: Symbol @@ -143,10 +139,6 @@ public defstruct Conditionally <: Stmt : alt: Stmt public defstruct Begin <: Stmt : ;LOW body: List<Stmt> -public defstruct OnReset <: Stmt : - info: FileInfo with: (as-method => true) - loc: Expression - exp: Expression public defstruct BulkConnect <: Stmt : info: FileInfo with: (as-method => true) loc: Expression @@ -155,17 +147,17 @@ public defstruct Connect <: Stmt : ;LOW info: FileInfo with: (as-method => true) loc: Expression exp: Expression -public defstruct StopStmt <: Stmt : ;LOW +public defstruct Stop <: Stmt : ;LOW info: FileInfo with: (as-method => true) ret: Int clk: Expression -public defstruct PrintfStmt <: Stmt : ;LOW +public defstruct Print <: Stmt : ;LOW info: FileInfo with: (as-method => true) string: String args: List<Expression> clk: Expression -public defstruct EmptyStmt <: Stmt ;LOW +public defstruct Empty <: Stmt ;LOW public definterface Type public defstruct UIntType <: Type : @@ -188,7 +180,7 @@ public defstruct Field : public defstruct Port : info: FileInfo name: Symbol - direction: PortDirection + direction: Direction type: Type public definterface Module diff --git a/src/main/stanza/firrtl-main.stanza b/src/main/stanza/firrtl-main.stanza index 2ccbc1b6..e77c712e 100644 --- a/src/main/stanza/firrtl-main.stanza +++ b/src/main/stanza/firrtl-main.stanza @@ -10,6 +10,7 @@ #include("passes.stanza") #include("primop.stanza") #include("errors.stanza") +#include("symbolic-value.stanza") defpackage firrtl-main : import core diff --git a/src/main/stanza/firrtl-test-main.stanza b/src/main/stanza/firrtl-test-main.stanza index 238a2afc..9c68bc92 100644 --- a/src/main/stanza/firrtl-test-main.stanza +++ b/src/main/stanza/firrtl-test-main.stanza @@ -10,15 +10,15 @@ #include("ir-parser.stanza") #include("passes.stanza") #include("primop.stanza") -#include("errors.stanza") +;#include("errors.stanza") #include("compilers.stanza") -#include("flo.stanza") -#include("verilog.stanza") -#include("firrtl.stanza") +;#include("flo.stanza") +;#include("verilog.stanza") +#include("symbolic-value.stanza") ;Custom Packages -#include("custom-passes.stanza") -#include("custom-compiler.stanza") +;#include("custom-passes.stanza") +;#include("custom-compiler.stanza") defpackage firrtl-main : import core @@ -31,8 +31,8 @@ defpackage firrtl-main : import firrtl/ir-utils import firrtl/compiler ;Custom Packages - import firrtl/custom-passes - import firrtl/custom-compiler + ;import firrtl/custom-passes + ;import firrtl/custom-compiler defn set-printvars! (p:List<Char>) : if contains(p,'t') : PRINT-TYPES = true @@ -137,7 +137,7 @@ defn main () : else : error("Invalid backend flag!") else : switch {_ == compiler} : - "flo" : error("Flo backend not currently supported.") + ;"flo" : error("Flo backend not currently supported.") ; run-passes(circuit*,StandardFlo(with-output)) "verilog" : run-passes(circuit*,StandardVerilog(with-output)) "firrtl" : run-passes(circuit*,StandardFIRRTL(with-output)) diff --git a/src/main/stanza/ir-parser.stanza b/src/main/stanza/ir-parser.stanza index c4480afb..8f4c41dd 100644 --- a/src/main/stanza/ir-parser.stanza +++ b/src/main/stanza/ir-parser.stanza @@ -7,6 +7,22 @@ defpackage firrtl/parser : import bigint2 import firrtl/ir-utils +;======= Convenience Types =========== +;definterface MStat +;defstruct Reader <: MStat : +; value: Symbol +;defstruct Writer <: MStat : +; value: Symbol +;defstruct ReadWriter <: MStat : +; value: Symbol +;defstruct ReadLatency <: MStat : +; value: Int +;defstruct WriteLatency <: MStat : +; value: Int +;defstruct DataType <: MStat : +; value: Type +;defstruct Depth <: MStat : +; value: Int ;======= Convenience Functions ======== defn first-info? (form) -> FileInfo|False : match(form) : @@ -147,10 +163,6 @@ defsyntax firrtl : FPE(form, "Expected a vector type here.") when t not-typeof VectorType t - ;Error if not an accessor direction - accdir! = (?a:#accdir) : a - accdir! != () : FPE(form, "Expected an accessor direction here.") - ;Error if not an expression exp! = (?e:#exp) : e exp! != () : FPE(form, "Expected an expression here.") @@ -221,33 +233,51 @@ defsyntax firrtl : field = (flip ?name:#id! #:! ?type:#type!) : Field(name, REVERSE, type) field = (?name:#id #:! ?type:#type!) : Field(name, DEFAULT, type) - defrule accdir : - accdir = (read) : READ - accdir = (write) : WRITE - accdir = (infer) : INFER - accdir = (rdwr) : RDWR - defrule width : - width = (?x:#int) : LongWidth(x) + width = (?x:#int) : IntWidth(x) width = (?) : UnknownWidth() ;Main Statement Productions + ;defrule mstat : + ; mstat = (reader ?name:#id!) : Reader(name) + ; mstat = (writer ?name:#id!) : Writer(name) + ; mstat = (read-writer ?name:#id!) : ReadWriter(name) + ; mstat = (read-latency #:! ?i:#int!) : ReadLatency(i) + ; mstat = (write-latency #:! ?i:#int!) : WriteLatency(i) + ; mstat = (data-type #:! ?t:#type!) : DataType(t) + ; mstat = (depth #:! ?i:#int!) : Depth(i) defrule statements : - stmt = (skip) : EmptyStmt() + stmt = (skip) : Empty() stmt = (wire ?name:#id! #:! ?t:#type!) : DefWire(first-info(form),name, t) - stmt = (reg ?name:#id! #:! ?t:#type! ?clk:#exp! ?reset:#exp!) : DefRegister(first-info(form),name, t,clk,reset) - stmt = (cmem ?name:#id! #:! ?t:#vectype! ?clk:#exp!) : DefMemory(first-info(form),name, type(t), false, clk, size(t)) - stmt = (smem ?name:#id! #:! ?t:#vectype! ?clk:#exp!) : DefMemory(first-info(form),name, type(t), true, clk, size(t)) - stmt = (inst ?name:#id! #of! ?m:#ref!) : DefInstance(first-info(form),name,m) + stmt = (reg ?name:#id! #:! ?t:#type! ?clk:#exp! ?reset:#exp! ?init:#exp!) : DefRegister(first-info(form),name, t,clk,reset,init) + stmt = (mem ?name:#id! #:! ?data-type:#type! ?depth:#int ?writers:#id! ... ?wl:#int ?readers:#id! ... ?rl:#int ?readwriters:#id! ...) : + DefMemory(first-info(form),name,data-type,depth,wl,rl,readers,writers,readwriters) + ;val rl = Vector<Int>() + ;var wl = Vector<Int>() + ;var de = Vector<Int>() + ;var dt = Vector<Type>() + ;val rs = Vector<Symbol>() + ;val ws = Vector<Symbol>() + ;val rws = Vector<Symbol>() + ;for x in stats do : + ; match(x as MStat) : + ; (x:Reader) : add(rs,value(x)) + ; (x:Writer) : add(ws,value(x)) + ; (x:ReadWriter) : add(rws,value(x)) + ; (x:ReadLatency) : add(rl,value(x)) + ; (x:WriteLatency) : add(wl,value(x)) + ; (x:DataType) : add(dt,value(x)) + ; (x:Depth) : add(de,value(x)) + ;if length(rl) != 1 : FPE(stats, "Can only specify one read-latency.") + ;if length(wl) != 1 : FPE(stats, "Can only specify one write-latency.") + ;if length(de) != 1 : FPE(stats, "Can only specify one depth.") + ;if length(dt) != 1 : FPE(stats, "Can only specify one data-type.") + ;DefMemory(first-info(form),name,dt[0],de[0],wl[0],rl[0],to-list(rs),to-list(ws),to-list(rws)) + 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 = (onreset ?x:#exp := ?y:#exp!) : OnReset(first-info(form),x,y) - stmt = (read accessor ?name:#id! #=! ?s:#exp![?i:#exp$]) : DefAccessor(first-info(form),name,s,i,READ) - stmt = (write accessor ?name:#id! #=! ?s:#exp![?i:#exp$]) : DefAccessor(first-info(form),name,s,i,WRITE) - stmt = (infer accessor ?name:#id! #=! ?s:#exp![?i:#exp$]) : DefAccessor(first-info(form),name,s,i,INFER) - stmt = (rdwr accessor ?name:#id! #=! ?s:#exp![?i:#exp$]) : DefAccessor(first-info(form),name,s, i,RDWR) - stmt = (stop( ?clk:#exp!, ?ret:#int)) : StopStmt(first-info(form),ret,clk) - stmt = (printf( ?clk:#exp!, ?str:#string ?es:#exp ...)) : PrintfStmt(first-info(form),str,es,clk) + stmt = (stop(?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 stmt = (?x:#exp := ?y:#exp!) : Connect(first-info(form),x, y) @@ -268,14 +298,15 @@ defsyntax firrtl : stmt/when = (when ?pred:#exp! #:! ?conseq:#stmt! else #:! ?alt:#stmt!) : Conditionally(first-info(form),pred, conseq, alt) stmt/when = (when ?pred:#exp! #:! ?conseq:#stmt!) : - Conditionally(first-info(form),pred, conseq, EmptyStmt()) + Conditionally(first-info(form),pred, conseq, Empty()) ;Main Expressions defrule exp : ;Suffix Operators exp = (?x:#expterm ?ops:#expop ...) : apply-suffix-ops(x, ops) - expop = ((@get ?f:#int)) : (fn (x) : Index(x, f, UnknownType())) - expop = (. ?f:#id!) : (fn (x) : Subfield(x, f, UnknownType())) + expop = ((@get ?f:#int)) : (fn (x) : SubIndex(x, f, UnknownType())) + expop = ((@get ?f:#exp!)) : (fn (x) : SubAccess(x, f, UnknownType())) + expop = (. ?f:#id!) : (fn (x) : SubField(x, f, UnknownType())) ;Prefix Operators expterm = (?t:#inttype(?v:#string)) : @@ -283,7 +314,7 @@ defsyntax firrtl : match(t) : (t:UIntType) : match(width(t)) : - (w:LongWidth) : + (w:IntWidth) : if to-long(max(1,(req-num-bits(b) - 1))) > width(w) : FPE(form, "Width too small for UIntValue.") UIntValue(b, w) @@ -291,7 +322,7 @@ defsyntax firrtl : UIntValue(b, w) (t:SIntType) : match(width(t)) : - (w:LongWidth) : + (w:IntWidth) : if to-long(req-num-bits(b)) > width(w) : FPE(form, "Width too small for SIntValue.") SIntValue(b, w) @@ -304,18 +335,18 @@ defsyntax firrtl : if (v as Int) < 0 : FPE(form, "UIntValue cannot be negative.") match(width(t)) : - (w:LongWidth) : + (w:IntWidth) : UIntValue(BigIntLit(v as Int,to-int(width(w)) + 1),w) (w) : val num-bits = req-num-bits(v as Int) - UIntValue(BigIntLit(v as Int,num-bits), LongWidth(max(1,num-bits - 1))) + UIntValue(BigIntLit(v as Int,num-bits), IntWidth(max(1,num-bits - 1))) (t:SIntType) : match(width(t)) : - (w:LongWidth) : + (w:IntWidth) : SIntValue(BigIntLit(v as Int,to-int(width(w))),w) (w) : val num-bits = req-num-bits(v as Int) - SIntValue(BigIntLit(v as Int,num-bits), LongWidth(num-bits)) + SIntValue(BigIntLit(v as Int,num-bits), IntWidth(num-bits)) expterm = (?op:#sym(?es:#exp ... ?ints:#int ... ?rest ...)) : if not empty?(rest) : diff --git a/src/main/stanza/ir-utils.stanza b/src/main/stanza/ir-utils.stanza index 8b25c10b..442e5713 100644 --- a/src/main/stanza/ir-utils.stanza +++ b/src/main/stanza/ir-utils.stanza @@ -2,6 +2,7 @@ defpackage firrtl/ir-utils : import core import verse import firrtl/ir2 + import bigint2 ;============== DEBUG STUFF ============================= @@ -13,19 +14,18 @@ defn generated? (s:String) -> False|Int : for i in 1 to length(s) - 1 find : val sub = substring(s,i + 1) s[i] == '_' and digits?(sub) and s[i - 1] != '_' - -public defn firrtl-gensym (s:Symbol) -> Symbol : - firrtl-gensym(s,HashTable<Symbol,Int>(symbol-hash)) -public defn firrtl-gensym (sym-hash:HashTable<Symbol,Int>) -> Symbol : - firrtl-gensym(`gen,sym-hash) - defn digits? (s:String) -> True|False : val digits = "0123456789" var yes = true for c in s do : if not contains?(digits,c) : yes = false yes - + +val gen-names = HashTable<Symbol,Int>(symbol-hash) +public defn firrtl-gensym (s:Symbol) -> Symbol : + firrtl-gensym(s,HashTable<Symbol,Int>(symbol-hash)) +public defn firrtl-gensym (sym-hash:HashTable<Symbol,Int>) -> Symbol : + firrtl-gensym(`gen,sym-hash) public defn firrtl-gensym (s:Symbol,sym-hash:HashTable<Symbol,Int>) -> Symbol : defn get-name (s:Symbol) -> Symbol : if key?(sym-hash,s) : @@ -76,6 +76,57 @@ public defn get-sym-hash (m:InModule,keywords:Streamable<Symbol>) -> HashTable<S map(to-port,ports(m)) sym-hash +; ======== Expression Computation Library =========== + +public defn BoolType () : UIntType(IntWidth(1)) +public val zero = UIntValue(BigIntLit(0),IntWidth(1)) +public val one = UIntValue(BigIntLit(1),IntWidth(1)) +public defn uint (i:Int) -> UIntValue : + UIntValue(BigIntLit(i),UnknownWidth()) +public defn sint (i:Int) -> SIntValue : + SIntValue(BigIntLit(i),UnknownWidth()) + +public defn AND (e1:Expression,e2:Expression) -> Expression : + if e1 == e2 : e1 + else if e1 == zero or e2 == zero : zero + else if e1 == one : e2 + else if e2 == one : e1 + else : DoPrim(BIT-AND-OP,list(e1,e2),list(),UIntType(IntWidth(1))) + +public defn OR (e1:Expression,e2:Expression) -> Expression : + if e1 == e2 : e1 + else if e1 == one or e2 == one : one + else if e1 == zero : e2 + else if e2 == zero : e1 + else : DoPrim(BIT-OR-OP,list(e1,e2),list(),UIntType(IntWidth(1))) + +public defn EQV (e1:Expression,e2:Expression) -> Expression : + DoPrim(EQUIV-OP,list(e1,e2),list(),type(e1)) + +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)) + +public defn NOT (e1:Expression) -> Expression : + if e1 == one : zero + else if e1 == zero : one + else : DoPrim(EQUIV-OP,list(e1,zero),list(),UIntType(IntWidth(1))) + +public defn children (e:Expression) -> List<Expression> : + val es = Vector<Expression>() + defn f (e:Expression) : + add(es,e) + e + map(f,e) + to-list(es) + +public defn exp-hash (e:Expression) -> Int : + turn-off-debug() + val i = symbol-hash(to-symbol(to-string(e))) + turn-on-debug() + i ;============== Exceptions ===================== public definterface PassException <: Exception @@ -155,15 +206,7 @@ defmethod print (o:OutputStream, d:Flip) : DEFAULT : "" REVERSE: "flip" -defmethod print (o:OutputStream, d:AccDirection) : - print{o, _} $ - switch {d == _} : - READ : "read" - WRITE: "write" - INFER: "infer" - RDWR: "rdwr" - -defmethod print (o:OutputStream, d:PortDirection) : +defmethod print (o:OutputStream, d:Direction) : print{o, _} $ switch {d == _} : INPUT : "input" @@ -173,7 +216,7 @@ defmethod print (o:OutputStream, w:Width) : print{o, _} $ match(w) : (w:UnknownWidth) : "?" - (w:LongWidth) : width(w) + (w:IntWidth) : width(w) defmethod print (o:OutputStream, op:PrimOp) : print{o, _} $ @@ -219,8 +262,9 @@ defmethod print (o:OutputStream, op:PrimOp) : defmethod print (o:OutputStream, e:Expression) : match(e) : (e:Ref) : print(o, name(e)) - (e:Subfield) : print-all(o, [exp(e) "." name(e)]) - (e:Index) : print-all(o, [exp(e) "[" value(e) "]"]) + (e:SubField) : print-all(o, [exp(e) "." name(e)]) + (e:SubIndex) : print-all(o, [exp(e) "[" value(e) "]"]) + (e:SubAccess) : print-all(o, [exp(e) "[" index(e) "]"]) (e:UIntValue) : print-all(o, ["UInt(" value(e) ")"]) (e:SIntValue) : print-all(o, ["SInt(" value(e) ")"]) (e:DoPrim) : @@ -237,16 +281,22 @@ defmethod print (o:OutputStream, c:Stmt) : (c:DefWire) : print-all(o,["wire " name(c) " : " type(c)]) (c:DefRegister) : - print-all(o,["reg " name(c) " : " type(c) ", " clock(c) ", " reset(c)]) + print-all(o,["reg " name(c) " : " type(c) ", " clock(c) ", " reset(c) ", " init(c)]) (c:DefMemory) : - if seq?(c) : print-all(o,["smem " name(c) " : " VectorType(type(c),size(c)) ", " clock(c)]) - else : print-all(o,["cmem " name(c) " : " VectorType(type(c),size(c)) ", " clock(c)]) + print-all(o,["mem " name(c) " : "]) + print-debug(o,c) + print(o,"\n") + print-all(io,["data-type: " data-type(c) "\n"]) + print-all(io,["depth: " depth(c) "\n"]) + print-all(io,["write-latency: " write-latency(c) "\n"]) + print-all(io,["read-latency: " read-latency(c) "\n"]) + print-all(io,["readers: " readers(c) "\n"]) + print-all(io,["writers: " writers(c) "\n"]) + print-all(io,["readwriters: " readwriters(c) "\n"]) (c:DefInstance) : print-all(o,["inst " name(c) " of " module(c)]) (c:DefNode) : print-all(o,["node " name(c) " = " value(c)]) - (c:DefAccessor) : - print-all(o,[acc-dir(c) " accessor " name(c) " = " source(c) "[" index(c) "]"]) (c:Conditionally) : if conseq(c) typeof Begin : print-all(o, ["when " pred(c) " :"]) @@ -256,7 +306,7 @@ defmethod print (o:OutputStream, c:Stmt) : else : print-all(o, ["when " pred(c) " : " conseq(c)]) print-debug(o,c) - if alt(c) not-typeof EmptyStmt : + if alt(c) not-typeof Empty: print(o, "\nelse :") print(io, "\n") print(io,alt(c)) @@ -266,18 +316,16 @@ defmethod print (o:OutputStream, c:Stmt) : print-all(o, [loc(c) " := " exp(c)]) (c:BulkConnect) : print-all(o, [loc(c) " <> " exp(c)]) - (c:OnReset) : - print-all(o, ["onreset " loc(c) " := " exp(c)]) - (c:EmptyStmt) : + (c:Empty) : print(o, "skip") - (c:StopStmt) : - print-all(o, ["stop(" clk(c) ", " ret(c) ")"]) - (c:PrintfStmt) : - print-all(o, ["printf(" clk(c) ", " ]) ;" + (c:Stop) : + print-all(o, ["stop(" ret(c) ", " clk(c) ")"]) + (c:Print) : + print-all(o, ["printf(" clk(c) ", "]) ;" print-all(o, join(List(escape(string(c)),args(c)), ", ")) print(o, ")") - if not c typeof Conditionally|Begin|EmptyStmt : print-debug(o,c) + if not c typeof Conditionally|Begin|Empty: print-debug(o,c) defmethod print (o:OutputStream, t:Type) : match(t) : @@ -351,8 +399,9 @@ public defn map<?T> (f: Type -> Type, t:?T&Type) -> T : public defmulti map<?T> (f: Expression -> Expression, e:?T&Expression) -> T defmethod map (f: Expression -> Expression, e:Expression) -> Expression : match(e) : - (e:Subfield) : Subfield(f(exp(e)), name(e), type(e)) - (e:Index) : Index(f(exp(e)), value(e), type(e)) + (e:SubField) : SubField(f(exp(e)), name(e), type(e)) + (e:SubIndex) : SubIndex(f(exp(e)), value(e), type(e)) + (e:SubAccess) : SubAccess(f(exp(e)), f(index(e)), type(e)) (e:DoPrim) : DoPrim(op(e), map(f, args(e)), consts(e), type(e)) (e) : e @@ -361,9 +410,8 @@ 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)) - (c:DefAccessor) : DefAccessor(info(c),f(name(c)), source(c), index(c),acc-dir(c)) - (c:DefRegister) : DefRegister(info(c),f(name(c)), type(c), clock(c), reset(c)) - (c:DefMemory) : DefMemory(info(c),f(name(c)), type(c), seq?(c), clock(c), size(c)) + (c:DefRegister) : DefRegister(info(c),f(name(c)), type(c), clock(c), reset(c), init(c)) + (c:DefMemory) : DefMemory(info(c),f(name(c)), data-type(c), depth(c), write-latency(c), read-latency(c), readers(c), writers(c), readwriters(c)) (c:DefNode) : DefNode(info(c),f(name(c)),value(c)) (c:DefInstance) : DefInstance(info(c),f(name(c)), module(c)) (c) : c @@ -371,17 +419,14 @@ defmethod map (f: Symbol -> Symbol, c:Stmt) -> Stmt : public defmulti map<?T> (f: Expression -> Expression, c:?T&Stmt) -> T defmethod map (f: Expression -> Expression, c:Stmt) -> Stmt : match(c) : - (c:DefAccessor) : DefAccessor(info(c),name(c), f(source(c)), f(index(c)),acc-dir(c)) - (c:DefRegister) : DefRegister(info(c),name(c), type(c), f(clock(c)), f(reset(c))) - (c:DefMemory) : DefMemory(info(c),name(c), type(c), seq?(c), f(clock(c)), size(c)) + (c:DefRegister) : DefRegister(info(c),name(c), type(c), f(clock(c)), f(reset(c)), f(init(c))) (c:DefNode) : DefNode(info(c),name(c), f(value(c))) - (c:DefInstance) : DefInstance(info(c),name(c), f(module(c))) + ;(c:DefInstance) : DefInstance(info(c),name(c), f(module(c))) (c:Conditionally) : Conditionally(info(c),f(pred(c)), conseq(c), alt(c)) (c:Connect) : Connect(info(c),f(loc(c)), f(exp(c))) (c:BulkConnect) : BulkConnect(info(c),f(loc(c)), f(exp(c))) - (c:OnReset) : OnReset(info(c),f(loc(c)),f(exp(c))) - (c:PrintfStmt) : PrintfStmt(info(c),string(c),map(f,args(c)),f(clk(c))) - (c:StopStmt) : StopStmt(info(c),ret(c),f(clk(c))) + (c:Stop) : Stop(info(c),ret(c),f(clk(c))) + (c:Print) : Print(info(c),string(c),map(f,args(c)),f(clk(c))) (c) : c public defmulti map<?T> (f: Stmt -> Stmt, c:?T&Stmt) -> T @@ -409,8 +454,9 @@ public defmulti map<?T> (f: Type -> Type, c:?T&Expression) -> T defmethod map (f: Type -> Type, c:Expression) -> Expression : match(c) : (c:Ref) : Ref(name(c),f(type(c))) - (c:Subfield) : Subfield(exp(c),name(c),f(type(c))) - (c:Index) : Index(exp(c),value(c),f(type(c))) + (c:SubField) : SubField(exp(c),name(c),f(type(c))) + (c:SubIndex) : SubIndex(exp(c),value(c),f(type(c))) + (c:SubAccess) : SubAccess(exp(c),index(c),f(type(c))) (c:DoPrim) : DoPrim(op(c),args(c),consts(c),f(type(c))) (c) : c @@ -419,8 +465,8 @@ defmethod map (f: Type -> Type, c:Stmt) -> Stmt : match(c) : (c:DefPoison) : DefPoison(info(c),name(c),f(type(c))) (c:DefWire) : DefWire(info(c),name(c),f(type(c))) - (c:DefRegister) : DefRegister(info(c),name(c),f(type(c)),clock(c),reset(c)) - (c:DefMemory) : DefMemory(info(c),name(c),f(type(c)),seq?(c),clock(c),size(c)) + (c:DefRegister) : DefRegister(info(c),name(c),f(type(c)),clock(c),reset(c),init(c)) + (c:DefMemory) : DefMemory(info(c),name(c), f(data-type(c)), depth(c), write-latency(c), read-latency(c), readers(c), writers(c), readwriters(c)) (c) : c public defmulti mapr<?T> (f: Width -> Width, t:?T&Type) -> T diff --git a/src/main/stanza/passes.stanza b/src/main/stanza/passes.stanza index 35c1a92f..dcd4c319 100644 --- a/src/main/stanza/passes.stanza +++ b/src/main/stanza/passes.stanza @@ -5,50 +5,43 @@ defpackage firrtl/passes : import firrtl/ir-utils import firrtl/primops import firrtl-main - import firrtl/errors - import firrtl/verilog - import firrtl/firrtl + ;import firrtl/errors + import firrtl/symbolic-value import bigint2 ;============== Pass List ================ public val standard-passes = to-list $ [ - RemoveSpecialChars() - CheckHighForm() - TempElimination() - ToWorkingIR() - ResolveKinds() - InferTypes() - ResolveGenders() - CheckGenders() - CheckKinds() - CheckTypes() - ExpandAccessors() - LowerToGround() - InlineIndexed() - ExpandWhens() - InferWidths() - ToRealIR() - CheckWidths() - Pad() - ConstProp() - SplitExp() - CheckLowForm() - CheckInitialization() + ;CheckHighForm() + ;TempElimination() + ToWorkingIR() + ;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 ReadAccessorKind <: Kind -public defstruct WriteAccessorKind <: Kind public defstruct PortKind <: Kind -public defstruct NodeKind <: Kind ; All elems except structural memory, wires +public defstruct NodeKind <: Kind public defstruct MemKind <: Kind -public defstruct ModuleKind <: Kind -public defstruct AccessorKind <: Kind +public defstruct ExpKind <: Kind public definterface Gender public val MALE = new Gender @@ -59,116 +52,130 @@ public val BI-GENDER = new Gender public defstruct WRef <: Expression : name: Symbol type: Type with: (as-method => true) - kind: Kind + kind: Kind with: (as-method => true) gender: Gender with: (as-method => true) - -public defstruct WSubfield <: Expression : +public defstruct WSubField <: Expression : exp: Expression name: Symbol type: Type with: (as-method => true) gender: Gender with: (as-method => true) - -public defstruct WIndex <: Expression : +public defstruct WSubIndex <: Expression : exp: Expression value: Int type: Type with: (as-method => true) gender: Gender with: (as-method => true) - -defstruct DecFromIndexer <: Stmt : - info: FileInfo 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> - name: Symbol - type: Type - -defstruct DecToIndexer <: Stmt : - info: FileInfo with: (as-method => true) index: Expression - exps: List<Expression> + type: Type with: (as-method => true) + gender : Gender with: (as-method => true) +defstruct WVoid <: Expression +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 -;================ WORKING IR UTILS ========================= -;defmethod equal? (f1:Flip, f2:Flip) -> True|False : -; switch fn ([x,y]) : f1 == x and f2 == y : -; [DEFAULT,DEFAULT] : true -; [REVERSE,REVERSE] : true -; else : false - -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 - -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:PortDirection) -> PortDirection : - switch {_ == d} : - OUTPUT : INPUT - INPUT : OUTPUT - -public defn times (flip:Flip,d:PortDirection) -> PortDirection : flip * d -public defn times (d:PortDirection,flip:Flip) -> PortDirection : - 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) +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 + (p:Port) : + switch { _ == direction(p) } : + INPUT : MALE + OUTPUT : FEMALE -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") +defmulti kind (e:Expression) -> Kind +defmethod kind (e:Expression) : ExpKind() -defn to-dir (g:Gender) -> PortDirection : - switch {_ == g} : - MALE : INPUT - FEMALE : OUTPUT +defmethod info (stmt:Begin) -> FileInfo : FileInfo() +defmethod info (stmt:Empty) -> FileInfo : FileInfo() -defn gender (s:DefAccessor) -> Gender : - switch {_ == acc-dir(s)} : - READ : MALE - WRITE : FEMALE - INFER : UNKNOWN-GENDER - RDWR : BI-GENDER +defmethod type (exp:UIntValue) -> Type : UIntType(width(exp)) +defmethod type (exp:SIntValue) -> Type : SIntType(width(exp)) -defn to-acc-dir (g:Gender) -> AccDirection : - switch {_ == g} : - MALE : READ - FEMALE : WRITE - UNKNOWN-GENDER : INFER - BI-GENDER : RDWR +defn get-type (s:Stmt) -> Type : + match(s) : + (s:DefWire|DefPoison|DefRegister|WDefInstance) : type(s) + (s:DefNode) : type(value(s)) + (s:DefMemory) : + val data-type = data-type(s) + 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 rdata = Field(`data,REVERSE,data-type) + val wdata = Field(`data,DEFAULT,data-type) + val wmask = match(data-type) : + (t:VectorType) : Field(`mask,DEFAULT,VectorType(BoolType(),size(t))) + (t:BundleType) : + val fields* = for f in fields(t) map : + Field(name(f),flip(f),BoolType()) + Field(`mask, DEFAULT, BundleType(fields*)) + 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([rdata,addr,en,clk])) + val write-type = BundleType(to-list([wdata,wmask,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() -defmulti gender (e:Expression) -> Gender -defmethod gender (e:Expression) : - MALE +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 == _} : @@ -177,12 +184,6 @@ defmethod print (o:OutputStream, g:Gender) : BI-GENDER : "b" UNKNOWN-GENDER: "u" -defmethod info (stmt:Begin) -> FileInfo : FileInfo() -defmethod info (stmt:EmptyStmt) -> FileInfo : FileInfo() - -defmethod type (exp:UIntValue) -> Type : UIntType(width(exp)) -defmethod type (exp:SIntValue) -> Type : SIntType(width(exp)) - ;============== DEBUG STUFF ============================= public var PRINT-TYPES : True|False = false public var PRINT-KINDS : True|False = false @@ -192,6 +193,36 @@ 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 +public defn turn-off-debug () : + 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 +public defn turn-on-debug () : + 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 : @@ -208,28 +239,24 @@ defmethod print (o:OutputStream, k:Kind) : (k:WireKind) : "wire" (k:PoisonKind) : "poison" (k:RegKind) : "reg" - (k:AccessorKind) : "accessor" (k:PortKind) : "port" (k:MemKind) : "mem" - (k:NodeKind) : "n" - (k:ModuleKind) : "module" + (k:NodeKind) : "node" (k:InstanceKind) : "inst" - (k:ReadAccessorKind) : "racc" - (k:WriteAccessorKind) : "wacc" + (k:ExpKind) : "exp" defn hasGender (e:?) : - e typeof WRef|WSubfield|WIndex|DefAccessor + e typeof Expression defn hasWidth (e:?) : e typeof UIntType|SIntType|UIntValue|SIntValue defn hasType (e:?) : - e typeof Ref|Subfield|Index|DoPrim|WRef|WSubfield - |WIndex|DefWire|DefRegister|DefMemory|DefPoison + e typeof Expression|DefWire|DefRegister|DefPoison |VectorType|Port|UIntValue|SIntValue defn hasKind (e:?) : - e typeof WRef + e typeof Expression defn hasInfo (e:?) : e typeof Stmt|Port|Circuit|Module @@ -259,246 +286,304 @@ defmethod print-debug (o:OutputStream, e:Expression|Stmt|Type|Port|Field|Module| defmethod print (o:OutputStream, e:WRef) : print(o,name(e)) print-debug(o,e as ?) - -defmethod print (o:OutputStream, e:WSubfield) : +defmethod print (o:OutputStream, e:WSubField) : print-all(o,[exp(e) "." name(e)]) print-debug(o,e as ?) - -defmethod print (o:OutputStream, e:WIndex) : +defmethod print (o:OutputStream, e:WSubIndex) : print-all(o,[exp(e) "[" value(e) "]"]) print-debug(o,e as ?) - -defmethod print (o:OutputStream, c:DecFromIndexer) : - print-all(o, ["indexer " exps(c) "[" index(c) "] = " name(c) " : " type(c)]) +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:DecToIndexer) : - print-all(o, ["indexer " name(c) " = " exps(c) "[" index(c) "] : " type(c)]) +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: WIndex) : - WIndex(f(exp(e)), value(e), type(e), gender(e)) - -defmethod map (f: Expression -> Expression, c:DecFromIndexer) : - DecFromIndexer(info(c),f(index(c)), map(f, exps(c)), name(c), type(c)) -defmethod map (f: Expression -> Expression, c:DecToIndexer) : - DecToIndexer(info(c),f(index(c)), map(f, exps(c)), name(c), type(c)) -defmethod map (f: Symbol -> Symbol, c:DecFromIndexer) : - DecFromIndexer(info(c),index(c), exps(c), f(name(c)), type(c)) -defmethod map (f: Symbol -> Symbol, c:DecToIndexer) : - DecToIndexer(info(c),index(c), exps(c), f(name(c)), type(c)) +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: WIndex) : - WIndex(exp(e), value(e), f(type(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)) -;================= Remove Special Characters ======================== -; Returns a new Circuit where all names have all special characters -; removed, except _. +defmethod map (f: Type -> Type, s: WDefInstance) : + WDefInstance(info(s),name(s),module(s),f(type(s))) -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:DefInstance) : DefInstance(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)),rename-e(clk(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 +;================ WIDTH LIBRARY ==================== -;================= Remove Scopes ======================== -; Returns a new Circuit where duplicate names have been -; renamed. - -public defstruct RemoveScopes <: Pass -public defmethod pass (b:RemoveScopes) -> (Circuit -> Circuit) : remove-scopes -public defmethod name (b:RemoveScopes) -> String : "Remove Scopes" -public defmethod short-name (b:RemoveScopes) -> String : "rem-scopes" - -;------------ Helper Functions ------------- - -defn lookup (n:Symbol, env:Vector<HashTable<Symbol,Int>>) -> Symbol : lookup(n,env,length(env) - 1) -defn lookup (n:Symbol, env:Vector<HashTable<Symbol,Int>>, index:Int) -> Symbol : - if index < 0 : n - else : - if not key?(env[index],n) : lookup(n,env,index - 1) - else : symbol-join([n scope-delin (env[index])[n]]) - -;------------ Pass ------------------ - -defn remove-scopes (c:Circuit) : - defn remove-scopes (m:InModule) : - val occurrences = HashTable<Symbol,Int>(symbol-hash) - val uses = HashTable<Symbol,Int>(symbol-hash) - defn rename (n:Symbol,env:Vector<HashTable<Symbol,Int>>) -> Symbol : - if occurrences[n] > 1 : - val i = get?(uses,n,0) - uses[n] = i + 1 - env[length(env) - 1][n] = i - symbol-join([n scope-delin i]) - else : n - defn build-s (s:Stmt) : - match(s) : - (s:DefWire|DefRegister|DefInstance|DefMemory|DefNode|DefAccessor|DefPoison) : - occurrences[name(s)] = get?(occurrences,name(s),0) + 1 - (s) : do(build-s,s) - defn remove-scopes-e (e:Expression,env:Vector<HashTable<Symbol,Int>>) : - match(map(remove-scopes-e{_,env},e)) : - (e:Ref) : Ref(lookup(name(e),env),type(e)) - (e) : e - defn remove-scopes-s (s:Stmt,env:Vector<HashTable<Symbol,Int>>) -> Stmt : - match(map(remove-scopes-e{_,env},s)) : - (s:DefWire) : DefWire(info(s),rename(name(s),env),type(s)) - (s:DefPoison) : DefPoison(info(s),rename(name(s),env),type(s)) - (s:DefRegister) : DefRegister(info(s),rename(name(s),env),type(s),clock(s),reset(s)) - (s:DefInstance) : DefInstance(info(s),rename(name(s),env),module(s)) - (s:DefMemory) : DefMemory(info(s),rename(name(s),env),type(s),seq?(s),clock(s),size(s)) - (s:DefNode) : DefNode(info(s),rename(name(s),env),value(s)) - (s:DefAccessor) : DefAccessor(info(s),rename(name(s),env),source(s),index(s),acc-dir(s)) - (s:Conditionally) : - add(env,HashTable<Symbol,Int>(symbol-hash)) - val conseq* = remove-scopes-s(conseq(s),env) - pop(env) +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) - add(env,HashTable<Symbol,Int>(symbol-hash)) - val alt* = remove-scopes-s(alt(s),env) - pop(env) - Conditionally(info(s),pred(s),conseq*,alt*) - (s) : map(remove-scopes-s{_,env},s) +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 - ;build occurrences table - for p in ports(m) do : - occurrences[name(p)] = get?(occurrences,name(p),0) + 1 - build-s(body(m)) - - ;rename - val env = Vector<HashTable<Symbol,Int>>() - add(env,HashTable<Symbol,Int>(symbol-hash)) - val ports* = - for p in ports(m) map : - Port(info(p),rename(name(p),env),direction(p),type(p)) - val body* = remove-scopes-s(body(m),env) - - InModule(info(m),name(m), ports*, body*) +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 {_ == g} : + INPUT: MALE + OUPUT: 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 - Circuit(info(c),modules*, main(c)) where : - val modules* = - for m in modules(c) map : - match(m) : - (m:InModule) : remove-scopes(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 +;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 @@ -514,11 +599,14 @@ 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:Index) : WIndex(exp(e), value(e), type(e), 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 : - map{to-stmt,_} $ map(to-exp,s) + 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* = @@ -527,57 +615,6 @@ defn to-working-ir (c:Circuit) : (m:InModule) : InModule(info(m),name(m), ports(m), to-stmt(body(m))) (m:ExModule) : m -;=============== MAKE EXPLICIT RESET ======================= -; All modules have an implicit reset signal - however, the -; programmer can explicitly reference this signal if desired. -; This pass makes all implicit resets explicit while -; preserving any previously explicit resets -; If reset is not explicitly passed to instantiations, then this -; pass autmatically connects the parent module's reset to the -; instantiation's reset - -;public defstruct MakeExplicitReset <: Pass -;public defmethod pass (b:MakeExplicitReset) -> (Circuit -> Circuit) : make-explicit-reset -;public defmethod name (b:MakeExplicitReset) -> String : "Make Explicit Reset" -;public defmethod short-name (b:MakeExplicitReset) -> String : "make-explicit-reset" -; -;defn make-explicit-reset (c:Circuit) : -; defn find-explicit (c:Circuit) -> List<Symbol> : -; defn explicit? (m:Module) -> True|False : -; for p in ports(m) any? : -; name(p) == `reset -; val explicit-reset = Vector<Symbol>() -; for m in modules(c) do: -; if explicit?(m) : add(explicit-reset,name(m)) -; to-list(explicit-reset) -; -; defn make-explicit (m:Module, explicit-reset:List<Symbol>) -> Module : -; defn route-reset (s:Stmt) -> Stmt : -; match(s) : -; (s:DefInstance) : -; val iref = WSubfield(WRef(name(s), UnknownType(), InstanceKind(), UNKNOWN-GENDER),`reset,UnknownType(),UNKNOWN-GENDER) -; val pref = WRef(`reset, UnknownType(), PortKind(), MALE) -; Begin(to-list([s,Connect(info(s),iref,pref)])) -; (s) : map(route-reset,s) -; -; var ports! = ports(m) -; if not contains?(explicit-reset,name(m)) : -; ports! = append(ports(m),list(Port(FileInfo(),`reset,INPUT,UIntType(LongWidth(1))))) -; match(m) : -; (m:InModule) : -; val body! = route-reset(body(m)) -; InModule(info(m),name(m),ports!,body!) -; (m:ExModule) : ExModule(info(m),name(m),ports!) -; -; defn make-explicit-reset (m:Module, c:Circuit) -> Module : -; val explicit-reset = find-explicit(c) -; make-explicit(m,explicit-reset) -; -; Circuit(info(c),modules*, main(c)) where : -; val modules* = -; for m in modules(c) map : -; make-explicit-reset(m,c) - ;=============== Resolve Kinds ============================= ; It is useful for the compiler to know information about ; objects referenced. This information is stored in the kind @@ -604,17 +641,15 @@ defn resolve-kinds (c:Circuit) : defn find (m:Module, kinds:HashTable<Symbol,Kind>) : defn find-stmt (s:Stmt) -> Stmt : match(s) : - (s:DefWire) : kinds[name(s)] = NodeKind() + (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:DefInstance) : kinds[name(s)] = InstanceKind() + (s:WDefInstance) : kinds[name(s)] = InstanceKind() (s:DefMemory) : kinds[name(s)] = MemKind() - (s:DefAccessor) : kinds[name(s)] = AccessorKind() (s) : false map(find-stmt,s) - kinds[name(m)] = ModuleKind() for p in ports(m) do : kinds[name(p)] = PortKind() match(m) : @@ -623,8 +658,6 @@ defn resolve-kinds (c:Circuit) : defn resolve-kinds (m:Module, c:Circuit) -> Module : val kinds = HashTable<Symbol,Kind>(symbol-hash) - for m in modules(c) do : - kinds[name(m)] = ModuleKind() find(m,kinds) match(m) : (m:InModule) : @@ -647,89 +680,73 @@ defn resolve-kinds (c:Circuit) : ; resolving the subexpressions in its elements. ; Type errors are not checked in this pass, as this is ; postponed for a later/earlier pass. -public defstruct InferTypes <: Pass -public defmethod pass (b:InferTypes) -> (Circuit -> Circuit) : infer-types -public defmethod name (b:InferTypes) -> String : "Infer Types" -public defmethod short-name (b:InferTypes) -> String : "infer-types" -defn type (m:Module) -> Type : - BundleType(for p in ports(m) map : to-field(p)) -defn get-type (b:Symbol,l:List<KeyValue<Symbol,Type>>) -> Type : - val ma = for kv in l find : b == key(kv) - if ma != false : - val ret = value(ma as KeyValue<Symbol,Type>) - ret - else : - UnknownType() -defn bundle-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() +; ------------------ Utils ------------------------- -defn get-vector-subtype (v:Type) -> Type : - match(v) : - (v:VectorType) : type(v) - (v) : UnknownType() +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) -defn infer-exp-types (e:Expression, l:List<KeyValue<Symbol,Type>>) -> Expression : - val r = map(infer-exp-types{_,l},e) - match(r) : - (e:WRef) : WRef(name(e), get-type(name(e),l),kind(e),gender(e)) - (e:WSubfield) : WSubfield(exp(e),name(e), bundle-field-type(type(exp(e)),name(e)),gender(e)) - (e:WIndex) : WIndex(exp(e),value(e), get-vector-subtype(type(exp(e))),gender(e)) - (e:DoPrim) : lower-and-type-primop(e) - ;DoPrim(op(e),args(e),consts(e),get-primop-rettype(e)) - (e:UIntValue|SIntValue) : e - -defn infer-types (s:Stmt, l:List<KeyValue<Symbol,Type>>) -> [Stmt List<KeyValue<Symbol,Type>>] : - match(map(infer-exp-types{_,l},s)) : - (s:Begin) : - var env = l - val body* = - for s in body(s) map : - val [s*,l*] = infer-types(s,env) - env = l* - s* - [Begin(body*),env] - (s:DefWire) : [s,List(name(s) => type(s),l)] - (s:DefPoison) : [s,List(name(s) => type(s),l)] - (s:DefRegister) : [s,List(name(s) => type(s),l)] - (s:DefMemory) : [s,List(name(s) => type(s),l)] - (s:DefInstance) : [s, List(name(s) => type(module(s)),l)] - (s:DefNode) : [s, List(name(s) => type(value(s)),l)] - (s:DefAccessor) : [s, List(name(s) => type(s),l)] - (s:Conditionally) : - val [s*,l*] = infer-types(conseq(s),l) - val [s**,l**] = infer-types(alt(s),l) - [Conditionally(info(s),pred(s),s*,s**),l] - (s:Connect|BulkConnect|OnReset|EmptyStmt|StopStmt|PrintfStmt) : [s,l] - -defn infer-types (m:Module, l:List<KeyValue<Symbol,Type>>) -> Module : - val ptypes = - for p in ports(m) map : - name(p) => type(p) - println-all-debug(append(ptypes,l)) - match(m) : - (m:InModule) : - val [s,l*] = infer-types(body(m),append(ptypes, l)) - InModule(info(m),name(m),ports(m),s) - (m:ExModule) : m + +; ------------------ 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 l = + 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(map(infer-types-e,s)) : + (s:DefWire|DefPoison|DefRegister|DefMemory|DefNode) : + val t = remove-unknowns(get-type(s)) + types[name(s)] = t + set-type(s,t) + (s:WDefInstance) : + types[name(s)] = module-types[module(s)] + WDefInstance(info(s),name(s),module(s),module-types[module(s)]) + (s) : map(infer-types-s,s) + for p in ports(m) do : + types[name(p)] = type(p) + match(m) : + (m:InModule) : + val s* = infer-types-s(body(m)) + InModule(info(m),name(m),ports(m),s*) + (m:ExModule) : m + + ; MAIN + val modules* = for m in modules(c) map : - name(m) => BundleType(map(to-field,ports(m))) - println-all-debug(l) + 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(c) map : - infer-types(m,l) - -;============= RESOLVE ACCESSOR GENDER ============================ + 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 @@ -738,135 +755,54 @@ defn infer-types (c:Circuit) -> Circuit : ; 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). -; Because accessor gender is not known during declaration, -; this pass requires iterating until a fixed point is reached. public defstruct ResolveGenders <: Pass public defmethod pass (b:ResolveGenders) -> (Circuit -> Circuit) : resolve-genders public defmethod name (b:ResolveGenders) -> String : "Resolve Genders" public defmethod short-name (b:ResolveGenders) -> String : "resolve-genders" -; Notes -; Is there a case where an incorrect gender would cause a weird result in resolving an accessor gender, such that a following gender check is wrong/right which it shouldn't be? - -; I don't think so, because there is no way for resolving an accessor gender to change something from wrong -> right, so it will always fail in the gender check. -; As such, it doesn't matter what the accessor gender gets resolved to, as it will fail anyways - -; In the example below, FIRRTL will say accessor gender could not be resolved. Once this is fixed, then we will error "Cannot connect from an output, out" -; output out : UInt -; accessor x = m[i] -; x := out -; out := x - -defn bundle-field-flip (n:Symbol,t:Type) -> Flip : - match(t) : - (b:BundleType) : - val field = for f in fields(b) find : name(f) == n - match(field): - (f:Field) : flip(f) - (f) : error(string-join(["Could not find " n " in bundle "])) - (b) : error(string-join(["Accessing subfield " n " on a non-Bundle type."])) - defn resolve-genders (c:Circuit) : - defn resolve-module (m:Module, genders:HashTable<Symbol,Gender>) -> Module : - var done? = true - - defn resolve-iter (m:Module) -> Module : - match(m) : - (m:InModule) : - val body* = resolve-stmt(body(m)) - InModule(info(m),name(m),ports(m),body*) - (m:ExModule) : m - - defn get-gender (n:Symbol,g:Gender) -> Gender : - defn force-gender (n:Symbol,g:Gender) -> Gender : - genders[n] = g - done? = false - g - val entry = get?(genders,n,false) - match(entry) : - (g*:Gender) : - if g* == UNKNOWN-GENDER and g == UNKNOWN-GENDER : g - else if g* != UNKNOWN-GENDER and g == UNKNOWN-GENDER : g* - else if g* == UNKNOWN-GENDER and g != UNKNOWN-GENDER : force-gender(n,g) - else : g* - (g*:False) : force-gender(n,g) - - defn resolve-stmt (s:Stmt) -> Stmt : - match(s) : - (s:DefPoison) : - get-gender(name(s),MALE) - s - (s:DefWire) : - get-gender(name(s),BI-GENDER) - s - (s:DefRegister) : - get-gender(name(s),BI-GENDER) - s - (s:DefMemory) : - get-gender(name(s),BI-GENDER) - s - (s:DefNode) : - DefNode(info(s),name(s),resolve-expr(value(s),get-gender(name(s),MALE))) - (s:DefInstance) : - get-gender(name(s),MALE) - DefInstance(info(s),name(s),resolve-expr(module(s),MALE)) - (s:DefAccessor) : - val gender* = get-gender(name(s),gender(s)) - val index* = resolve-expr(index(s),MALE) - val source* = resolve-expr(source(s),gender*) - DefAccessor(info(s),name(s),source*,index*,to-acc-dir(gender*)) - (s:Connect) : - Connect(info(s),resolve-expr(loc(s),FEMALE),resolve-expr(exp(s),MALE)) - (s:BulkConnect) : - BulkConnect(info(s),resolve-expr(loc(s),FEMALE),resolve-expr(exp(s),MALE)) - (s:OnReset) : - OnReset(info(s),resolve-expr(loc(s),FEMALE),resolve-expr(exp(s),MALE)) - (s:Conditionally) : - val pred* = resolve-expr(pred(s),MALE) - val conseq* = resolve-stmt(conseq(s)) - val alt* = resolve-stmt(alt(s)) - Conditionally(info(s),pred*,conseq*,alt*) - (s:PrintfStmt) : - PrintfStmt(info(s),string(s),map(resolve-expr{_,MALE},args(s)),clk(s)) - (s) : map(resolve-stmt,s) - - defn resolve-expr (e:Expression,desired:Gender) -> Expression : - match(e) : - (e:WRef) : - val gender = get-gender(name(e),desired) - WRef{name(e),type(e),kind(e),_} $ - if gender == BI-GENDER : desired - else : gender - (e:WSubfield) : - val field-flip = bundle-field-flip(name(e),type(exp(e))) - val exp* = resolve-expr(exp(e),field-flip * desired) - val gender* = field-flip * gender(exp*) - WSubfield(exp*,name(e),type(e),gender*) - (e:WIndex) : - val exp* = resolve-expr(exp(e),desired) - val gender* = gender(exp*) - WIndex(exp*,value(e),type(e),gender*) - (e) : map(resolve-expr{_,MALE},e) - - var module* = resolve-iter(m) - println-debug(genders) - while not done? : - done? = true - module* = resolve-iter(m) - ;println-debug(genders) - module* - - defn resolve-genders (m:Module, c:Circuit) -> Module : - val genders = HashTable<Symbol,Gender>(symbol-hash) - ;for p in ports(m) do : - ;if direction(p) == INPUT : genders[name(p)] = MALE - ;else : genders[name(p)] = FEMALE - resolve-module(m,genders) - + 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 : - resolve-genders(m,c) + 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 @@ -875,60 +811,26 @@ defn resolve-genders (c:Circuit) : ; of the accessor, it is transformed into DecFromIndexer (male) or ; DecToIndexer (female) -public defstruct ExpandAccessors <: Pass -public defmethod pass (b:ExpandAccessors) -> (Circuit -> Circuit) : expand-accessors -public defmethod name (b:ExpandAccessors) -> String : "Expand Accessors" -public defmethod short-name (b:ExpandAccessors) -> String : "expand-accessors" +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) -> List<Expression> : +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(WIndex(e,i,type(t),gender(e as ?))) ;always be WRef|WSubfield|WIndex - -defn set-gender (e:Expression, g:Gender) -> Expression : - match(map(set-gender{_,g},e)) : - (e:WRef) : WRef(name(e),type(e),kind(e),g) - (e) : e - -defn expand-accessors (c:Circuit) : - var sh = HashTable<Symbol,Int>(symbol-hash) - var rds = HashTable<Symbol,Symbol>(symbol-hash) - var wrs = HashTable<Symbol,Symbol>(symbol-hash) - - defn expand-exp (e:Expression) -> Expression : - match(map(expand-exp,e)) : - (e:WRef) : - val n* = - if key?(rds,name(e)) : - switch {_ == gender(e)} : - MALE : rds[name(e)] - FEMALE : wrs[name(e)] - BI-GENDER : error("Bigender") - UNKNOWN-GENDER : error("Unknown") - else : name(e) - WRef(n*,type(e),kind(e),gender(e)) + list(WSubIndex(e,i,type(t),g)) ;always be WRef|WSubField|WSubIndex + +defn expand-accesses (c:Circuit) : + defn expand-e (e:Expression) -> Expression : + match(map(expand-e,e)) : + (e:WSubAccess) : + val ls = expand-vector(exp(e),gender(e)) + WIndexer(ls,index(e),type(e),gender(e)) (e) : e - defn expand-stmt (s:Stmt) -> Stmt : - match(s) : - (s:DefAccessor) : - println-all-debug(["Matched DefAcc with " name(s)]) - if get-kind(source(s)) typeof MemKind: s - else : - val vtype = type(type(source(s)) as VectorType) - switch {acc-dir(s) == _} : - READ : DecToIndexer(info(s),index(s),expand-vector(source(s)),name(s), vtype) - WRITE : DecFromIndexer(info(s),index(s),expand-vector(source(s)),name(s), vtype) - INFER : error("Shouldn't be here") - RDWR : - rds[name(s)] = firrtl-gensym(name(s),sh) - val msrc = set-gender(source(s),MALE) - val dti = DecToIndexer(info(s),index(s),expand-vector(msrc),rds[name(s)], vtype) - wrs[name(s)] = firrtl-gensym(name(s),sh) - val fsrc = set-gender(source(s),FEMALE) - val dfi = DecFromIndexer(info(s),index(s),expand-vector(fsrc),wrs[name(s)], vtype) - Begin(list(map(expand-exp,dti),map(expand-exp,dfi))) - (s) : map{expand-stmt,_} $ map(expand-exp,s) + defn expand-s (s:Stmt) -> Stmt : + map{expand-s,_} $ map(expand-e,s) Circuit(info(c),modules*, main(c)) where : val modules* = @@ -936,420 +838,199 @@ defn expand-accessors (c:Circuit) : match(m) : (m:ExModule) : m (m:InModule) : - sh = get-sym-hash(m) - rds = HashTable<Symbol,Symbol>(symbol-hash) - wrs = HashTable<Symbol,Symbol>(symbol-hash) - InModule(info(m),name(m),ports(m),expand-stmt(body(m))) - -;;=============== LOWERING TO GROUND TYPES ============================= -; All non-ground (elevated) types (Vectors, Bundles) are expanded out to -; individual ground types. -; This pass involves filling a table mapping the name of elevated types -; to the lowered ground expression names and genders. This allows -; references to be resolved. -public defstruct LowerToGround <: Pass -public defmethod pass (b:LowerToGround) -> (Circuit -> Circuit) : lower-to-ground -public defmethod name (b:LowerToGround) -> String : "Lower To Ground" -public defmethod short-name (b:LowerToGround) -> String : "lower-to-ground" - -defstruct EF : - exp : Expression - flip : Flip - -defmethod print (o:OutputStream,e:EF) : - print-all(o, ["EF(" exp(e) "," flip(e) ")"]) - -defmethod print (o:OutputStream,e:NTF) : - print-all(o, ["NTF(" name(e) "," type(e) "," flip(e) ")"]) + InModule(info(m),name(m),ports(m),expand-s(body(m))) -defstruct NTF : - name : Symbol - type : Type - flip : Flip -defn num-elems (t:Type) -> Int : +;================ 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 + num-elems(type(f)) + sum = sum + get-size(type(f)) sum - (t:VectorType) : size(t) * num-elems(type(t)) + (t:VectorType) : size(t) * get-size(type(t)) (t) : 1 - -defn index-of-elem (t:BundleType, s:Symbol) -> Int : - var sum = 0 - label<Int> ret : - for f in fields(t) do : - if s == name(f) : ret(sum) - else : sum = sum + num-elems(type(f)) - error("Shouldn't be here") - -defn generate-entry (n:Symbol,t:Type) -> List<NTF> : - defn v-uniquify (n*:Symbol) -> Symbol : symbol-join([n vector-expand-delin n*]) - defn b-uniquify (n*:Symbol) -> Symbol : symbol-join([n bundle-expand-delin n*]) +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 = -1 + for f in fields(type(exp(e)) as BundleType) find : + i = i + 1 + name(f) == name(e) + get-point(exp(e)) + i + (e:WSubIndex) : + get-point(exp(e)) + value(e) + (e:WIndexer) : + get-point(exps(e)[0]) +defn get-valid-points (t1:Type,t2:Type,flip1:Flip,flip2:Flip) -> List<[Int,Int]> : + 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]>() + for i in 0 to length(fields(t1)) do : + for j in 0 to length(fields(t2)) do : + 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] + i, x[1] + j]) + to-list(points) + (t1:VectorType,t2:VectorType) : + val points = Vector<[Int,Int]>() + 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] + i, x[1] + i]) + to-list(points) +defn create-exps (n:Symbol, t:Type) -> List<Expression> : + 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) (t:BundleType) : for f in fields(t) map-append : - val es = generate-entry(name(f),type(f)) - for e in es map : - NTF(b-uniquify(name(e)),type(e),flip(e) * flip(f)) + create-exps(WSubField(e,name(f),type(f),gender(e) * flip(f))) (t:VectorType) : for i in 0 to size(t) map-append : - val es = generate-entry(to-symbol(i),type(t)) - for e in es map : - NTF(v-uniquify(name(e)),type(e),flip(e)) - (t) : list $ NTF(n,t,DEFAULT) + create-exps(WSubIndex(e,i,type(t),gender(e))) -defn expand-expr (e:Expression) -> List<EF> : - defn inst? (e:Expression) -> True|False : - match(e) : - (e:WRef) : kind(e) == InstanceKind() - (e) : false - match(e) : - (e:WRef) : - if inst?(e) : - for f in fields(type(e) as BundleType) map-append : - for x in generate-entry(name(f),type(f)) map : - EF(WSubfield(e,name(x),type(x),gender(e) * flip(x)),flip(f) * flip(x)) - else : - for x in generate-entry(name(e),type(e)) map : - EF(WRef(name(x),type(x),kind(e),gender(e) * flip(x)), flip(x)) - (e:WSubfield) : - val f = {_ as Field} $ - for f in fields(type(exp(e)) as BundleType) find : name(f) == name(e) - if inst?(exp(e)) : - ;; println-all(["here with " exp(e)]) - for x in generate-entry(name(f),type(f)) map : - EF(WSubfield(exp(e),name(x),type(x),gender(e)),flip(x)) - else : - val exps = expand-expr(exp(e)) - val begin = index-of-elem(type(exp(e)) as BundleType,name(e)) - val len = num-elems(type(e)) - val ret = headn(tailn(exps,begin),len) - for r in ret map : EF(exp(r),flip(r) * flip(f)) - (e:WIndex) : - val exps = expand-expr(exp(e)) - val len = num-elems(type(e)) - headn(tailn(exps,len * value(e)),len) - ;(e:Pad) : - ;val v = exp(head(expand-expr(value(e)))) - ;list(EF(Pad(v,width(e),type(e)),DEFAULT)) - (e:DoPrim) : - val vargs = Vector<Expression>() - val vflips = Vector<Flip>() - for x in args(e) do : - val r = head(expand-expr(x)) - add(vargs,exp(r)) - add(vflips,flip(r)) - list(EF(DoPrim(op(e),to-list(vargs),consts(e),type(e)),DEFAULT)) - (e) : list(EF(e,DEFAULT)) - -defn lower-ports (ports:List<Port>) -> List<Port> : - for p in ports map-append : - for x in generate-entry(name(p),type(p)) map : - Port(info(p),name(x),direction(p) * flip(x),type(x)) - -defn get-kind (e:Expression) -> Kind : - match(e) : - (e:WRef) : kind(e) - (e:WSubfield) : get-kind(exp(e)) - (e:WIndex) : get-kind(exp(e)) - -defn type (s:DefAccessor) -> Type : - if get-kind(source(s)) == MemKind() : type(source(s)) - else : type(type(source(s)) as VectorType) +;---------------- Pass --------------------- -defn base-name (e:Expression) -> Symbol : - match(e) : - (e:WRef) : name(e) - (e:WSubfield) : base-name(exp(e)) - (e:WIndex) : base-name(exp(e)) +defn expand-connects (c:Circuit) -> Circuit : + defn expand-connects (m:InModule) -> InModule : + val exp-lib = HashTable<Symbol,List<Expression>>(symbol-hash) + defn create-lib (s:Stmt) -> Stmt : + match(s) : + (s:DefWire|DefRegister|WDefInstance|DefNode|DefPoison) : ;TODO Memories? + exp-lib[name(s)] = create-exps(name(s),get-type(s)) + s + (s) : map(create-lib,s) + defn expand-e (e:Expression, point:Int) -> Expression : + defn lookup-exp (e:Expression, point:Int) -> Expression : + match(e) : + (e:WRef) : exp-lib[name(e)][point] + (e:WSubField|WSubIndex) : lookup-exp(exp(e), point + get-point(e)) + (e) : error("Shouldn't be here") + match(e) : + (e:WRef|WSubField|WSubIndex) : lookup-exp(e,point) + (e:WIndexer) : + val exps* = + for e* in exps(e) map : + expand-e(e*,point) + WIndexer(exps*,index(e),type(exps*[0]),gender(exps*[0])) + (e:DoPrim) : e + (e) : e + defn expand-s (s:Stmt) -> Stmt : + match(s) : + (s:Connect) : + val n = get-size(loc(s)) + val connects = Vector<Stmt>() + for i in 0 to n do : + val loc* = expand-e(loc(s),i) + val exp* = expand-e(exp(s),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>() + for x in ls do : + val loc* = expand-e(loc(s),x[0]) + val exp* = expand-e(exp(s),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) -defn set-gender (e:Expression,g:Gender,f:Flip) -> Expression : - match(e) : - (e:WRef) : WRef(name(e),type(e),kind(e),g) - (e:WSubfield) : WSubfield(set-gender(exp(e),g * f,DEFAULT),name(e),type(e),g) - (e) : e + for p in ports(m) do : + exp-lib[name(p)] = create-exps(name(p),type(p)) + create-lib(body(m)) + InModule(info(m),name(m),ports(m),expand-s(body(m))) -defn lower (body:Stmt) -> Stmt : - defn lower-stmt (s:Stmt) -> Stmt : - ;; println(s) - match(s) : - (s:DefPoison) : Begin $ - for x in generate-entry(name(s),type(s)) map : - DefPoison(info(s),name(x),type(x)) - (s:DefWire) : Begin $ - for x in generate-entry(name(s),type(s)) map : - DefWire(info(s),name(x),type(x)) - (s:DefRegister) : Begin{_} $ - for x in generate-entry(name(s),type(s)) map : - DefRegister(info(s),name(x),type(x),clock(s),reset(s)) - (s:DefInstance) : - val fields = - for f in fields(type(module(s)) as BundleType) map-append : - val etfs = generate-entry(name(f),type(f)) - for etf in etfs map : - Field(name(etf),flip(etf) * flip(f),type(etf)) - val m = module(s) as WRef - DefInstance(info(s),name(s),WRef(name(m),BundleType(fields),kind(m),gender(m))) - (s:DefNode) : Begin $ - for x in expand-expr(value(s)) map : - DefNode(info(s),name(s),exp(x)) - (s:DefMemory) : Begin $ - for x in generate-entry(name(s),type(s)) map : - DefMemory(info(s),name(x),type(x),seq?(s),clock(s),size(s)) - (s:DefAccessor) : - val ls = generate-entry(name(s),type(s)) - val rs = generate-entry(name(source(s) as WRef),type(s)) - val index* = exp(head $ expand-expr(index(s))) - Begin $ for (l in ls, r in rs) map: - if flip(r) == REVERSE : error("Shouldn't be here") - val memref = WRef(name(r),type(r),MemKind(),gender(s)) - DefAccessor(info(s),name(l),memref,index*,to-acc-dir(gender(s))) - (s:OnReset|Connect) : Begin $ - for (l in expand-expr(loc(s)), r in expand-expr(exp(s))) map : - val lgender = FEMALE * flip(l) - val rgender = MALE * flip(r) - val l* = set-gender(exp(l),lgender,flip(l)) - val r* = set-gender(exp(r),rgender,flip(r)) - println-all-debug(["Left: " l " with Gender: " lgender]) - println-all-debug(["Right: " r " with Gender: " rgender]) - switch fn ([x,y]) : lgender == x and rgender == y : - [FEMALE,MALE] : - if s typeof Connect : Connect(info(s),l*,r*) - else : OnReset(info(s),l*,r*) - [MALE,FEMALE] : - if s typeof Connect : Connect(info(s),r*,l*) - else : OnReset(info(s),r*,l*) - (s:BulkConnect) : - val ls-fake = generate-entry(`null,type(loc(s))) - val rs-fake = generate-entry(`null,type(exp(s))) - val ls = expand-expr(loc(s)) - val rs = expand-expr(exp(s)) - val ls* = Vector<EF>() - val rs* = Vector<EF>() - for (l-fake in ls-fake,l in ls) do : - for (r-fake in rs-fake, r in rs) do : - if name(l-fake) == name(r-fake) and flip(l-fake) == flip(r-fake) and type(l-fake) == type(r-fake) : - add(ls*,l) - add(rs*,r) - Begin $ for (l in to-list(ls*), r in to-list(rs*)) map : - val lgender = FEMALE * flip(l) - val rgender = MALE * flip(r) - val l* = set-gender(exp(l),lgender,flip(l)) - val r* = set-gender(exp(r),rgender,flip(r)) - println-all-debug(["Left: " l " with Gender: " lgender]) - println-all-debug(["Right: " r " with Gender: " rgender]) - switch fn ([x,y]) : lgender == x and rgender == y : - [FEMALE,MALE] : Connect(info(s),l*,r*) - [MALE,FEMALE] : Connect(info(s),r*,l*) - (s:DecToIndexer|DecFromIndexer) : Begin(ls) where : - val ctable = HashTable<Symbol,Vector<EF>>(symbol-hash) - val index* = exp(head $ expand-expr(index(s))) - for e in exps(s) do : - for (r in expand-expr(e), ntf in generate-entry(name(s),type(s))) do: - val n = name(ntf) - val x = get?(ctable,n,Vector<EF>()) - add(x,r) - ctable[n] = x - val default-gender = match(s) : - (s:DecToIndexer) : FEMALE - (s:DecFromIndexer) : MALE - val ls = for ntf in generate-entry(name(s),type(s)) map : - val n = name(ntf) - val dec-gender = default-gender * flip(ntf) - for x in ctable[n] do : - if (flip(x) * swap(default-gender)) == dec-gender : - error("Shouldn't be here") - val exps-gender = swap(dec-gender) - ;val l* = set-gender(exp(l),lgender,flip(ntf)) - val exps = to-list $ for e in ctable[n] map : - set-gender(exp(e),exps-gender,flip(e)) - switch fn ([x,y]) : dec-gender == x and exps-gender == y : - [FEMALE,MALE] : DecToIndexer(info(s),index*,exps,name(ntf),type(ntf)) - [MALE,FEMALE] : DecFromIndexer(info(s),index*,exps,name(ntf),type(ntf)) - (s:Conditionally) : - Conditionally(info(s),exp(head $ expand-expr(pred(s))),lower-stmt(conseq(s)),lower-stmt(alt(s))) - (s:PrintfStmt) : - val args* = for x in args(s) map : exp(head(expand-expr(x))) - PrintfStmt(info(s),string(s),args*,clk(s)) - (s:Begin|EmptyStmt|StopStmt) : map(lower-stmt,s) - - lower-stmt(body) - -defn lower-module (c:Circuit,m:Module) -> Module : - val ports* = lower-ports(ports(m)) - match(m) : - (m:InModule) : - val body* = lower(body(m)) - InModule(info(m),name(m),ports*,body*) - (m:ExModule) : - ExModule(info(m),name(m),ports*) - -defn lower-to-ground (c:Circuit) -> Circuit : Circuit(info(c),modules*, main(c)) where : val modules* = for m in modules(c) map : - lower-module(c,m) - - -;;=========== CONVERT MULTI CONNECTS to WHEN ================ -; This pass converts DecFromIndexer and DecToIndexer -; into a series of when statements. TODO what about initial -; values? -;public defstruct ExpandIndexedConnects <: Pass -;public defmethod pass (b:ExpandIndexedConnects) -> (Circuit -> Circuit) : expand-connect-indexed -;public defmethod name (b:ExpandIndexedConnects) -> String : "Expand Indexed Connects" -;public defmethod short-name (b:ExpandIndexedConnects) -> String : "expand-indexed-connects" -; -;defn expand-connect-indexed-stmt (s: Stmt,sh:HashTable<Symbol,Int>) -> Stmt : -; defn equality (e1:Expression,e2:Expression) -> Expression : -; DoPrim(EQUIV-OP,list(e1,e2),List(),UIntType(UnknownWidth())) -; defn get-name (e:Expression) -> Symbol : -; match(e) : -; (e:WRef) : name(e) -; (e:WSubfield) : symbol-join([get-name(exp(e)) `. name(e)]) -; (e:WIndex) : symbol-join([get-name(exp(e)) `. to-symbol(value(e))]) -; (e) : `F -; match(s) : -; (s:DecFromIndexer) : Begin $ -; if length(locs(s)) == 0 : list(EmptyStmt()) -; else : -; val ref = WRef(firrtl-gensym(get-name(index(s)),sh),type(index(s)),NodeKind(),UNKNOWN-GENDER) -; append( -; list(DefNode(info(s),name(ref),index(s))) -; to-list $ -; for (i in 0 to false, l in locs(s)) stream : Conditionally( -; info(s), -; equality(ref,UIntValue(BigIntLit(i),UnknownWidth())), -; Connect(info(s),l,exp(s)), -; EmptyStmt() -; ) -; ) -; (s:DecToIndexer) : Begin $ -; if length(exps(s)) == 0 : list(EmptyStmt()) -; else : -; val ref = WRef(firrtl-gensym(get-name(index(s)),sh),type(index(s)),NodeKind(),UNKNOWN-GENDER) -; append( -; list(Connect(info(s),loc(s),head(exps(s))),DefNode(info(s),name(ref),index(s))) -; to-list $ -; for (i in 1 to false, e in tail(exps(s))) stream : Conditionally( -; info(s), -; equality(ref,UIntValue(BigIntLit(i),UnknownWidth())), -; Connect(info(s),loc(s),e), -; EmptyStmt() -; ) -; ) -; (s) : map(expand-connect-indexed-stmt{_,sh},s) -; -;defn expand-connect-indexed (m: Module) -> Module : -; match(m) : -; (m:InModule) : -; val sh = get-sym-hash(m,keys(v-keywords)) -; InModule(info(m),name(m),ports(m),expand-connect-indexed-stmt(body(m),sh)) -; (m:ExModule) : m -; -;defn expand-connect-indexed (c: Circuit) -> Circuit : -; Circuit(info(c),modules*, main(c)) where : -; val modules* = -; for m in modules(c) map : -; expand-connect-indexed(m) + match(m) : + (m:ExModule) : m + (m:InModule) : expand-connects(m) + -;;================ INLINE ACCESSORS ========================= +;;================ REPLACE INDEXERS ========================= ; This pass inlines all accessors to non-memory vector typed ; components. -public defstruct InlineIndexed <: Pass -public defmethod pass (b:InlineIndexed) -> (Circuit -> Circuit) : inline-indexed -public defmethod name (b:InlineIndexed) -> String : "Inline Indexers" -public defmethod short-name (b:InlineIndexed) -> String : "inline-indexers" - -;------------ Helper Functions -------------- -defn get-name (e:Expression) -> Symbol : - match(e) : - (e:WRef) : name(e) - (e:WSubfield) : symbol-join([get-name(exp(e)) `. name(e)]) - (e:WIndex) : symbol-join([get-name(exp(e)) `. to-symbol(value(e))]) - (e) : `F - -defn equality (e1:Expression,i:Int) -> Expression : - DoPrim(EQUIV-OP,list(e1,UIntValue(BigIntLit(i),UnknownWidth())), - List(),UIntType(UnknownWidth())) - +public defstruct ReplaceIndexers <: Pass +public defmethod pass (b:ReplaceIndexers) -> (Circuit -> Circuit) : replace-indexer +public defmethod name (b:ReplaceIndexers) -> String : "Replace Indexer" +public defmethod short-name (b:ReplaceIndexers) -> String : "replace-indexers" -;------------- Inline Accessors ------------- - - - -defn inline-indexed-m (m:InModule) -> InModule : - val sh = get-sym-hash(m,keys(v-keywords)) - val ih = HashTable<Symbol,Stmt>(symbol-hash) - defn inline-indexed-s (s:Stmt) -> Stmt : +public defn replace-indexer (c:Circuit) -> Circuit : + defn mux-chain (exps:List<Expression>,i:Int,index:Expression) -> Expression : + if length(exps) == 1 : head(exps) + else : MUX(EQV(uint(i),index),head(exps),mux-chain(tail(exps),i + 1,index)) + defn when-chain (exps:List<Expression>,e:Expression,index:Expression,info:FileInfo) -> Stmt : val stmts = Vector<Stmt>() - - defn expand-indexed (indexer:WRef,indexed-dec:Stmt) -> Expression : - val index = index(indexed-dec as DecFromIndexer|DecToIndexer) - val index-name = firrtl-gensym(get-name(index),sh) - val index-ref = WRef(index-name,type(index),NodeKind(),MALE) - val replace-name = firrtl-gensym(get-name(indexer),sh) - val replace-ref = WRef(replace-name,type(indexer),kind(indexer),gender(indexer)) - - add(stmts, DefWire(info(indexed-dec),name(replace-ref),type(replace-ref))) - add(stmts, DefNode(info(indexed-dec),index-name,index)) - match(indexed-dec) : - (s:DecFromIndexer) : - if (gender(replace-ref) != FEMALE) : - println(replace-ref) - error("Shouldn't be here") - for (i in 0 to false, e in exps(s)) do : - val eq = equality(index-ref,i) - val cond = Conditionally(info(s),eq,Connect(info(s),e,replace-ref),EmptyStmt()) - add(stmts,map(inline-indexed-s,cond)) - (s:DecToIndexer) : - if (gender(replace-ref) != MALE) : - println(gender(replace-ref)) - println(replace-ref) - println(indexed-dec) - println(indexer) - error("Shouldn't be here") - val cnct = Connect(info(s),replace-ref,head(exps(s))) - add(stmts,map(inline-indexed-e,cnct)) - ;println-all(["exps: " exps(s)]) - for (i in 1 to false, e in tail(exps(s))) do : - val eq = equality(index-ref,i) - val cond = Conditionally(info(s),eq,Connect(info(s),replace-ref,e),EmptyStmt()) - add(stmts,map(inline-indexed-s,cond)) - replace-ref - - defn inline-indexed-e (e:Expression) -> Expression : - match(map(inline-indexed-e,e)) : - (e:WRef) : - if key?(ih,name(e)) : - val indexer = ih[name(e)] - expand-indexed(e,indexer) - else : e - (e) : e - - match(s) : - (s:DecFromIndexer|DecToIndexer) : - ih[name(s)] = s - firrtl-gensym(name(s),sh) - add(stmts,EmptyStmt()) - (s) : - val s* = map(inline-indexed-e,s) - add(stmts,map(inline-indexed-s,s*)) - if length(stmts) == 1 : stmts[0] - else : Begin(to-list(stmts)) - - InModule(info(m),name(m),ports(m),inline-indexed-s(body(m))) - -public defn inline-indexed (c:Circuit) -> Circuit : + for (x in exps,i in 0 to length(exps)) do : + add(stmts,Conditionally(info,EQV(uint(i),index),Connect(info,x,e),Empty())) + Begin(to-list(stmts)) + defn replace-e (e:Expression) -> Expression : + match(map(replace-e,e)) : + (e:WIndexer) : + if gender(e) == MALE : mux-chain(exps(e),0,index(e)) + else : e ;is handled in replace-s + (e) : e + defn replace-s (s:Stmt) -> Stmt : + match(map(replace-e,s)) : + (s:Connect) : + match(loc(s)) : + (e:WIndexer) : when-chain(exps(e),exp(s),index(e),info(s)) + (e) : s + (s) : map(replace-s, s) Circuit{info(c),_,main(c)} $ for m in modules(c) map : match(m) : (m:ExModule) : m - (m:InModule) : inline-indexed-m(m) + (m:InModule) : InModule(info(m),name(m),ports(m),replace-s(body(m))) ;;================ EXPAND WHENS ============================= ; This pass does three things: remove last connect semantics, @@ -1370,177 +1051,178 @@ public defn inline-indexed (c:Circuit) -> Circuit : ; The ReadPort enable is calcuated by scanning all entries in ; the table for when this is referenced (a read). All conditions ; are accumulated and OR'ed together. + public defstruct ExpandWhens <: Pass public defmethod pass (b:ExpandWhens) -> (Circuit -> Circuit) : expand-whens public defmethod name (b:ExpandWhens) -> String : "Expand Whens" public defmethod short-name (b:ExpandWhens) -> String : "expand-whens" -; ======== Expression Computation Library =========== - -val zero = UIntValue(BigIntLit(0),LongWidth(1)) -val one = UIntValue(BigIntLit(1),LongWidth(1)) +; ========== Expand When Utilz ========== -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) +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 = 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 - (e1:WRef,e2:WRef) : name(e1) == name(e2) - (e1:WSubfield,e2:WSubfield) : - (name(e1) == name(e2)) and (exp(e1) == exp(e2)) - (e1:WIndex,e2:WIndex) : - (value(e1) == value(e2)) and (exp(e1) == exp(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 + 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|Stop) : add(simlist,Conditionally(info(s),p,s,Empty())) + (s) : map(expand-whens{_,netlist,p},s) + s + val netlist = HashTable<Expression,Expression>(exp-hash) + expand-whens(body(m),netlist,one) + + [ netlist simlist ] + + defn create-module (netlist:HashTable<Expression,Expression>,simlist:Vector<Stmt>,m:InModule) -> InModule : + val stmts = 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(stmts,Connect(info(s),e,rvalue)) + (s:DefPoison|DefNode|Stop|Print) : + 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(stmts,Connect(info(p),e,netlist[e])) + for x in simlist do : + add(stmts,x) + InModule(info(m),name(m),ports(m),Begin(to-list(stmts))) -defn AND (e1:Expression,e2:Expression) -> Expression : - if e1 == e2 : e1 - else if e1 == zero or e2 == zero : zero - else if e1 == one : e2 - else if e2 == one : e1 - else : DoPrim(BIT-AND-OP,list(e1,e2),list(),UIntType(LongWidth(1))) - -defn OR (e1:Expression,e2:Expression) -> Expression : - if e1 == e2 : e1 - else if e1 == one or e2 == one : one - else if e1 == zero : e2 - else if e2 == zero : e1 - else : DoPrim(BIT-OR-OP,list(e1,e2),list(),UIntType(LongWidth(1))) - -defn NOT (e1:Expression) -> Expression : - if e1 == one : zero - else if e1 == zero : one - else : DoPrim(EQUIV-OP,list(e1,zero),list(),UIntType(LongWidth(1))) - -defn children (e:Expression) -> List<Expression> : - val es = Vector<Expression>() - defn f (e:Expression) : - add(es,e) - e - map(f,e) - to-list(es) - -; ======= Symbolic Value Library ========== -public definterface SymbolicValue -public defstruct SVExp <: SymbolicValue : - exp : Expression -public defstruct SVMux <: SymbolicValue : - pred : Expression - conseq : SymbolicValue - alt : SymbolicValue -public defstruct SVNul <: SymbolicValue - -defmethod print (o:OutputStream, sv:SymbolicValue) : - match(sv) : - (sv: SVExp) : print(o, exp(sv)) - (sv: SVMux) : print-all(o, ["(" pred(sv) " ? " conseq(sv) " : " alt(sv) ")"]) - (sv: SVNul) : print(o, "SVNUL") - -defn map (f: Expression -> Expression, sv:SymbolicValue) -> SymbolicValue : - match(sv) : - (sv:SVMux) : SVMux(f(pred(sv)),conseq(sv),alt(sv)) - (sv:SVExp) : SVExp(f(exp(sv))) - (sv:SVNul) : sv - -defmulti map<?T> (f: SymbolicValue -> SymbolicValue, sv:?T&SymbolicValue) -> T -defmethod map (f: SymbolicValue -> SymbolicValue, sv:SymbolicValue) -> SymbolicValue : - match(sv) : - (sv: SVMux) : SVMux(pred(sv),f(conseq(sv)),f(alt(sv))) - (sv) : sv - -defn do (f:SymbolicValue -> ?, s:SymbolicValue) -> False : - defn f* (sv:SymbolicValue) -> SymbolicValue : - f(sv) - sv - map(f*,s) - false - -defn dor (f:SymbolicValue -> ?, e:SymbolicValue) -> False : - do(f,e) - defn f* (x:SymbolicValue) -> SymbolicValue : - dor(f,x) - x - map(f*,e) - false - -defmethod equal? (a:SymbolicValue,b:SymbolicValue) -> True|False : - match(a,b) : - (a:SVNul,b:SVNul) : true - (a:SVExp,b:SVExp) : exp(a) == exp(b) - (a:SVMux,b:SVMux) : pred(a) == pred(b) and conseq(a) == conseq(b) and alt(a) == alt(b) - (a,b) : false - -;TODO add invert to primop -defn optimize (sv:SymbolicValue) -> SymbolicValue : - match(map(optimize,sv)) : - (sv:SVMux) : - if conseq(sv) == alt(sv) : conseq(sv) - else : - match(conseq(sv),alt(sv)) : - (c:SVExp,a:SVExp) : - if exp(c) == one and exp(a) == zero : SVExp(pred(sv)) - else if exp(c) == zero and exp(a) == one : SVExp(NOT(pred(sv))) - else if exp(c) == exp(a) : c - else : sv - (c,a) : sv - (sv) : sv + 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)) -; ========== Expand When Utilz ========== -defn deepcopy (t:HashTable<Symbol,SymbolicValue>) -> HashTable<Symbol,SymbolicValue> : - t0 where : - val t0 = HashTable<Symbol,SymbolicValue>(symbol-hash) - for x in t do : - t0[key(x)] = value(x) -defn get-unique-keys (ts:List<HashTable<Symbol,SymbolicValue>>) -> Streamable<Symbol> : - val h = HashTable<Symbol,True>(symbol-hash) - for v in ts do : - for t in v do : - h[key(t)] = true - keys(h) - -defn has-nul? (sv:SymbolicValue) -> True|False : - var has? = false - if sv typeof SVNul : has? = true - for x in sv dor : - if x typeof SVNul : has? = true - has? -defn remove-nul (sv:SymbolicValue) -> SymbolicValue : - match(map(remove-nul,sv)) : - (sv:SVMux) : - match(conseq(sv),alt(sv)) : - (c,a:SVNul) : c - (c:SVNul,a) : a - (c,a) : sv - (sv) : sv -defn to-exp (sv:SymbolicValue) -> Expression|False : - match(remove-nul(sv)) : - (sv:SVMux) : - DoPrim(MUX-OP, - list(pred(sv),to-exp(conseq(sv)) as Expression,to-exp(alt(sv)) as Expression), - list(), - UIntType(LongWidth(1))) - (sv:SVExp) : exp(sv) - (sv:SVNul) : false -defn reduce-or (l:List<True|False>) -> True|False : - if length(l) == 0 : false - else : head(l) or reduce-or(tail(l)) -defn reduce-or (l:List<Expression>) -> Expression : - if length(l) == 0 : zero - else : OR(head(l) reduce-or(tail(l))) +;defn has-nul? (sv:SymbolicValue) -> True|False : +; var has? = false +; if sv typeof SVNul : has? = true +; for x in sv dor : +; if x typeof SVNul : has? = true +; has? +;defn remove-nul (sv:SymbolicValue) -> SymbolicValue : +; match(map(remove-nul,sv)) : +; (sv:SVMux) : +; match(conseq(sv),alt(sv)) : +; (c,a:SVNul) : c +; (c:SVNul,a) : a +; (c,a) : sv +; (sv) : sv +;defn to-exp (sv:SymbolicValue) -> Expression|False : +; match(remove-nul(sv)) : +; (sv:SVMux) : +; DoPrim(MUX-OP, +; list(pred(sv),to-exp(conseq(sv)) as Expression,to-exp(alt(sv)) as Expression), +; list(), +; UIntType(IntWidth(1))) +; (sv:SVExp) : exp(sv) +; (sv:SVNul) : false +;defn reduce-or (l:List<True|False>) -> True|False : +; if length(l) == 0 : false +; else : head(l) or reduce-or(tail(l)) +;defn reduce-or (l:List<Expression>) -> Expression : +; if length(l) == 0 : zero +; else : OR(head(l) reduce-or(tail(l))) ; ========= Expand When Pass =========== + + + +;Can either check initialization here or in separate pass +;defn expand-whens (c:Circuit) +; +; Circuit(info(c),modules*, main(c)) where : +; val modules* = +; for m in modules(c) map : +; expand-whens(m) + + + + + ; TODO: replace stmt with wr (WRefs). The KIND of wref will help figure out what to emit as far as ; declarations, especially with not declaring anything for ports. We need WRefs, and not just Kinds, ; because we need the name of the symbolic expression. I think? Or maybe we can use the key? @@ -1554,421 +1236,369 @@ defn reduce-or (l:List<Expression>) -> Expression : ; enables:Calculated off of assigns. ;---------------- Helper Functions -------------- -defn get-read-enable (sym:Symbol,table:HashTable<Symbol,SymbolicValue>) -> Expression : - defn get-single-read-enable (sym:Symbol,sv:SymbolicValue) -> Expression : - defn active (e:Expression) -> True|False : - match(e) : - (e:WRef) : name(e) == sym - (e) : reduce-or{_} $ map(active,children(e)) - (e) : false - match(sv) : - (sv: SVNul) : zero - (sv: SVExp) : - if active(exp(sv)) : one - else : zero - (sv: SVMux) : - val e0 = get-single-read-enable(sym,SVExp(pred(sv))) - val e1 = get-single-read-enable(sym,conseq(sv)) - val e2 = get-single-read-enable(sym,alt(sv)) - if e1 == e2 : OR(e0,e1) - else : OR(e0,OR(AND(pred(sv),e1),AND(NOT(pred(sv)),e2))) - reduce-or $ to-list $ for y in table stream : get-single-read-enable(sym,value(y)) - -defn get-write-enable (sv:SymbolicValue) -> SymbolicValue : - match(map(get-write-enable,sv)) : - (sv: SVExp) : SVExp(one) - (sv: SVNul) : SVExp(zero) - (sv) : sv - -defn merge-resets (assign:HashTable<Symbol,SymbolicValue>, resets:HashTable<Symbol,SymbolicValue>, rsignals:HashTable<Symbol,Expression>) -> HashTable<Symbol,SymbolicValue> : - val table = HashTable<Symbol,SymbolicValue>(symbol-hash) - for i in get-unique-keys(list(assign,resets)) do : - table[i] = match(get?(assign,i,false),get?(resets,i,false)) : - (a:SymbolicValue,r:SymbolicValue) : - if r typeof SVNul : a - else : SVMux(rsignals[i],r,a) - (a:SymbolicValue,r:False) : a - (a:False,r:SymbolicValue) : SVMux(rsignals[i],r,SVNul()) - (a:False,r:False) : error("Shouldn't be here") - table - -defn mark (vs:Vector<[Stmt,Expression]>,pred:Expression) -> False : - for i in 0 to length(vs) do : - val [s,e] = vs[i] - vs[i] = [s, AND(e,pred)] - -; ------ Print Debug Info ------ -defn print-table (t:HashTable<Symbol,SymbolicValue>,s:String) : - println-debug(s) - for x in t do : println-debug(x) - - -defn build-tables (s:Stmt, - assign:HashTable<Symbol,SymbolicValue>, - resets:HashTable<Symbol,SymbolicValue>, - flattn:HashTable<Symbol,True|False>, - rsignals:HashTable<Symbol,Expression>, - simuls:Vector<[Stmt,Expression]>, - ) -> False : - match(s) : - (s:DefWire) : - assign[name(s)] = SVNul() - flattn[name(s)] = true - (s:DefRegister) : - assign[name(s)] = SVNul() - flattn[name(s)] = true - rsignals[name(s)] = reset(s) - resets[name(s)] = SVNul() - (s:DefAccessor) : - assign[name(s)] = SVNul() - flattn[name(s)] = false - (s:DefInstance) : ;TODO only add instance input ports. This probably involves correcting instance genders - for f in fields(type(module(s)) as BundleType) do : - if flip(f) == REVERSE : - println-all-debug(["Instance: " s " has input " f]) - val n = to-symbol("~.~" % [name(s),name(f)]) ; only on inputs - assign[n] = SVNul() - flattn[n] = true - (s:Conditionally) : - defn combine (flattn:HashTable<Symbol,True|False>, - table-c:HashTable<Symbol,SymbolicValue>, - table-a:HashTable<Symbol,SymbolicValue>, - i:Symbol) -> SymbolicValue|False : - match(get?(table-c,i,false),get?(table-a,i,false)) : - (c:SymbolicValue,a:SymbolicValue) : - if c == a : c - else : SVMux(pred(s),c,a) - (c:SymbolicValue,a:False) : - if flattn[i] : c - else : SVMux(pred(s),c,SVNul()) - (c:False,a:SymbolicValue) : - if flattn[i] : a - else : SVMux(pred(s),SVNul(),a) - (c:False,a:False) : false - - val assign-c = deepcopy(assign) - val assign-a = deepcopy(assign) - val resets-c = deepcopy(resets) - val resets-a = deepcopy(resets) - val simuls-c = Vector<[Stmt,Expression]>() - val simuls-a = Vector<[Stmt,Expression]>() - build-tables(conseq(s),assign-c,resets-c,flattn,rsignals,simuls-c) - build-tables(alt(s),assign-a,resets-a,flattn,rsignals,simuls-a) - for i in get-unique-keys(list(assign-c,assign-a)) do : - assign[i] = combine(flattn,assign-c,assign-a,i) as SymbolicValue - val r = combine(flattn,resets-c,resets-a,i) - match(r) : - (r:SymbolicValue) : resets[i] = r - (r) : false - - mark(simuls-c,pred(s)) - mark(simuls-a,DoPrim(BIT-NOT-OP,list(pred(s)),list(),UIntType(LongWidth(1)))) - add-all(simuls,simuls-c) - add-all(simuls,simuls-a) - - print-table(assign-c,"TABLE-C") - print-table(assign-a,"TABLE-A") - print-table(assign,"TABLE") - print-table(resets-c,"RESET-C") - print-table(resets-a,"RESET-A") - print-table(resets,"RESET") - (s:Connect|OnReset) : - val key* = match(loc(s)) : - (e:WRef) : name(e) - (e:WSubfield) : symbol-join([name(exp(e) as ?) `. name(e)]) - (e) : error("Shouldn't be here with ~" % [e]) - if s typeof Connect : assign[key*] = SVExp(exp(s)) - if s typeof OnReset : resets[key*] = SVExp(exp(s)) - (s:Begin) : for s* in body(s) do: build-tables(s*,assign,resets,flattn,rsignals,simuls) - (s:StopStmt|PrintfStmt) : - add(simuls,[s one]) - (s:DefMemory|DefPoison|DefNode|EmptyStmt) : false - - -defn mark-referenced (referenced?:HashTable<Symbol,True>, s:Stmt) -> False : - defn mark-referenced-e (e:Expression) -> Expression : - match(map(mark-referenced-e,e)) : - (e:WRef) : - referenced?[name(e)] = true - e - (e) : e - do(mark-referenced{referenced?,_:Stmt},s) - map(mark-referenced-e,s) - false - -defn mark-referenced (referenced?:HashTable<Symbol,True>, sv:SymbolicValue) -> SymbolicValue : - defn mark-referenced-e (e:Expression) -> Expression : - match(map(mark-referenced-e,e)) : - (e:WRef) : - referenced?[name(e)] = true - e - (e) : e - map{mark-referenced-e,_} $ map(mark-referenced{referenced?,_:SymbolicValue},sv) - -defn is-referenced? (referenced?:HashTable<Symbol,True>, s:Stmt) -> True|False : - match(s) : - (s:DefPoison|DefWire|DefRegister|DefAccessor|DefMemory|DefNode) : key?(referenced?,name(s)) - (s:DefInstance) : true - (s:PrintfStmt|StopStmt|Conditionally) : true - -;--------------- Expand Whens Pass ------------------- - -public defn expand-whens (c:Circuit) -> Circuit : - - defn expand-whens (ports:List<Port>, table:HashTable<Symbol,SymbolicValue>,cons:Vector<Stmt>) -> False : - for p in ports do : - if direction(p) == OUTPUT : - val ref = WRef(name(p),type(p),PortKind(),FEMALE) - if not has-nul?(table[name(p)]) : - add{cons,_} $ Connect(FileInfo(),ref,to-exp(table[name(p)]) as Expression) - - defn expand-whens (s:Stmt, table:HashTable<Symbol,SymbolicValue>,decs:Vector<Stmt>,cons:Vector<Stmt>) -> Stmt : - match(map(expand-whens{_,table,decs,cons},s)) : - (s:DefNode) : - add(decs,s) - (s:DefMemory) : - add(decs,s) - (s:DefPoison) : - add(decs,s) - (s:DefWire) : - add(decs,s) - val ref = WRef(name(s),type(s),NodeKind(),FEMALE) - if not has-nul?(table[name(s)]) : - add{cons,_} $ Connect(info(s),ref,to-exp(table[name(s)]) as Expression) - (s:DefRegister) : - add(decs,s) - val e = to-exp(table[name(s)]) - match(e) : - (e:Expression) : - val ref = WRef(name(s),type(s),NodeKind(),FEMALE) - val en = to-exp(optimize $ get-write-enable(table[name(s)])) as Expression - if en == one : - add{cons,_} $ Connect(info(s),ref,e) - else : - add{cons,_} $ Conditionally(info(s),en,Connect(info(s),ref,e),EmptyStmt()) - (e:False) : false - (s:DefAccessor) : - add(decs,s) - val t = type(s) - val n = name(s) - if gender(s) == FEMALE : - val ref = WRef(n,t,WriteAccessorKind(),FEMALE) - val e = to-exp(table[n]) - match(e) : - (e:Expression) : - val en = (to-exp $ optimize $ get-write-enable(table[n])) as Expression - if en == one : - add{cons,_} $ Connect(info(s),ref,e) - else : - add{cons,_} $ Conditionally(info(s),en,Connect(info(s),ref,e),EmptyStmt()) - (e:False) : false - (s:DefInstance) : - add(decs,s) - for f in fields(type(module(s)) as BundleType) map : - if flip(f) == REVERSE : - val n = to-symbol("~.~" % [name(s),name(f)]) ; only on inputs - val x = to-symbol(split(to-string(n),'.')[0]) - val f = to-symbol(split(to-string(n),'.')[1]) - val ref = WRef(x,type(module(s)),InstanceKind(),FEMALE) - val sref = WSubfield(ref,f,bundle-field-type(type(module(s)),f),FEMALE) - if not has-nul?(table[n]) : - add{cons,_} $ Connect(info(s),sref,to-exp(table[n]) as Expression) - (s:Connect|Conditionally|OnReset|Begin|EmptyStmt|StopStmt|PrintfStmt) : false - s - - defn expand-whens (m:Module) -> Module : - match(m) : - (m:ExModule) : m - (m:InModule) : - val assign = HashTable<Symbol,SymbolicValue>(symbol-hash) - val resets = HashTable<Symbol,SymbolicValue>(symbol-hash) - val flattn = HashTable<Symbol,True|False>(symbol-hash) - val rsignals = HashTable<Symbol,Expression>(symbol-hash) - val simuls = Vector<[Stmt,Expression]>() - - for p in ports(m) do : - if direction(p) == OUTPUT : - assign[name(p)] = SVNul() - flattn[name(p)] = false - - build-tables(body(m),assign,resets,flattn,rsignals,simuls) - for x in assign do : assign[key(x)] = optimize(value(x)) - for x in resets do : resets[key(x)] = optimize(value(x)) - - ;val enables = get-enables(assign,kinds) - ;for x in enables do : enables[key(x)] = optimize(value(x)) - - ;println-debug("====== Assigns ======") - ;for x in assign do : println-debug(x) - ;println-debug("====== Resets ======") - ;for x in resets do : println-debug(x) - - val table = merge-resets(assign,resets,rsignals) - ;println-debug("====== Table ======") - ;for x in table do : println-debug(x) - - val decs = Vector<Stmt>() - val cons = Vector<Stmt>() - expand-whens(ports(m),table,cons) - expand-whens(body(m),table,decs,cons) - - for se in simuls do : - val [s e] = se - if e == one : add(decs,s) - else : add(decs,Conditionally(info(s),e,s,EmptyStmt())) - - val referenced? = HashTable<Symbol,True>(symbol-hash) - for x in table do : - mark-referenced(referenced?,value(x)) - if value(x) != SVNul() : - referenced?[key(x)] = true - for x in decs do : - mark-referenced(referenced?,x) - val decs* = Vector<Stmt>() - for x in decs do : - if is-referenced?(referenced?,x) : add(decs*,x) - - InModule(info(m),name(m),ports(m),Begin(to-list(append(decs*,to-list(cons))))) - - val c* = Circuit(info(c),modules*, main(c)) where : - val modules* = - for m in modules(c) map : - expand-whens(m) - ;throw(PassExceptions(errors)) when not empty?(errors) - c* +;defn get-read-enable (sym:Symbol,table:HashTable<Symbol,SymbolicValue>) -> Expression : +; defn get-single-read-enable (sym:Symbol,sv:SymbolicValue) -> Expression : +; defn active (e:Expression) -> True|False : +; match(e) : +; (e:WRef) : name(e) == sym +; (e) : reduce-or{_} $ map(active,children(e)) +; (e) : false +; match(sv) : +; (sv: SVNul) : zero +; (sv: SVExp) : +; if active(exp(sv)) : one +; else : zero +; (sv: SVMux) : +; val e0 = get-single-read-enable(sym,SVExp(pred(sv))) +; val e1 = get-single-read-enable(sym,conseq(sv)) +; val e2 = get-single-read-enable(sym,alt(sv)) +; if e1 == e2 : OR(e0,e1) +; else : OR(e0,OR(AND(pred(sv),e1),AND(NOT(pred(sv)),e2))) +; reduce-or $ to-list $ for y in table stream : get-single-read-enable(sym,value(y)) +; +;defn get-write-enable (sv:SymbolicValue) -> SymbolicValue : +; match(map(get-write-enable,sv)) : +; (sv: SVExp) : SVExp(one) +; (sv: SVNul) : SVExp(zero) +; (sv) : sv +; +;defn merge-resets (assign:HashTable<Symbol,SymbolicValue>, resets:HashTable<Symbol,SymbolicValue>, rsignals:HashTable<Symbol,Expression>) -> HashTable<Symbol,SymbolicValue> : +; val table = HashTable<Symbol,SymbolicValue>(symbol-hash) +; for i in get-unique-keys(list(assign,resets)) do : +; table[i] = match(get?(assign,i,false),get?(resets,i,false)) : +; (a:SymbolicValue,r:SymbolicValue) : +; if r typeof SVNul : a +; else : SVMux(rsignals[i],r,a) +; (a:SymbolicValue,r:False) : a +; (a:False,r:SymbolicValue) : SVMux(rsignals[i],r,SVNul()) +; (a:False,r:False) : error("Shouldn't be here") +; table +; +;defn mark (vs:Vector<[Stmt,Expression]>,pred:Expression) -> False : +; for i in 0 to length(vs) do : +; val [s,e] = vs[i] +; vs[i] = [s, AND(e,pred)] +; +;; ------ Print Debug Info ------ +;defn print-table (t:HashTable<Symbol,SymbolicValue>,s:String) : +; println-debug(s) +; for x in t do : println-debug(x) +; +; +;defn build-tables (s:Stmt, +; assign:HashTable<Symbol,SymbolicValue>, +; resets:HashTable<Symbol,SymbolicValue>, +; flattn:HashTable<Symbol,True|False>, +; rsignals:HashTable<Symbol,Expression>, +; simuls:Vector<[Stmt,Expression]>, +; ) -> False : +; match(s) : +; (s:DefWire) : +; assign[name(s)] = SVNul() +; flattn[name(s)] = true +; (s:DefRegister) : +; assign[name(s)] = SVNul() +; flattn[name(s)] = true +; rsignals[name(s)] = reset(s) +; resets[name(s)] = SVNul() +; (s:DefAccessor) : +; assign[name(s)] = SVNul() +; flattn[name(s)] = false +; (s:WDefInstance) : ;TODO only add instance input ports. This probably involves correcting instance genders +; for f in fields(type(module(s)) as BundleType) do : +; if flip(f) == REVERSE : +; println-all-debug(["Instance: " s " has input " f]) +; val n = to-symbol("~.~" % [name(s),name(f)]) ; only on inputs +; assign[n] = SVNul() +; flattn[n] = true +; (s:Conditionally) : +; defn combine (flattn:HashTable<Symbol,True|False>, +; table-c:HashTable<Symbol,SymbolicValue>, +; table-a:HashTable<Symbol,SymbolicValue>, +; i:Symbol) -> SymbolicValue|False : +; match(get?(table-c,i,false),get?(table-a,i,false)) : +; (c:SymbolicValue,a:SymbolicValue) : +; if c == a : c +; else : SVMux(pred(s),c,a) +; (c:SymbolicValue,a:False) : +; if flattn[i] : c +; else : SVMux(pred(s),c,SVNul()) +; (c:False,a:SymbolicValue) : +; if flattn[i] : a +; else : SVMux(pred(s),SVNul(),a) +; (c:False,a:False) : false +; +; val assign-c = deepcopy(assign) +; val assign-a = deepcopy(assign) +; val resets-c = deepcopy(resets) +; val resets-a = deepcopy(resets) +; val simuls-c = Vector<[Stmt,Expression]>() +; val simuls-a = Vector<[Stmt,Expression]>() +; build-tables(conseq(s),assign-c,resets-c,flattn,rsignals,simuls-c) +; build-tables(alt(s),assign-a,resets-a,flattn,rsignals,simuls-a) +; for i in get-unique-keys(list(assign-c,assign-a)) do : +; assign[i] = combine(flattn,assign-c,assign-a,i) as SymbolicValue +; val r = combine(flattn,resets-c,resets-a,i) +; match(r) : +; (r:SymbolicValue) : resets[i] = r +; (r) : false +; +; mark(simuls-c,pred(s)) +; mark(simuls-a,DoPrim(BIT-NOT-OP,list(pred(s)),list(),UIntType(IntWidth(1)))) +; add-all(simuls,simuls-c) +; add-all(simuls,simuls-a) +; +; print-table(assign-c,"TABLE-C") +; print-table(assign-a,"TABLE-A") +; print-table(assign,"TABLE") +; print-table(resets-c,"RESET-C") +; print-table(resets-a,"RESET-A") +; print-table(resets,"RESET") +; (s:Connect|OnReset) : +; val key* = match(loc(s)) : +; (e:WRef) : name(e) +; (e:WSubField) : symbol-join([name(exp(e) as ?) `. name(e)]) +; (e) : error("Shouldn't be here with ~" % [e]) +; if s typeof Connect : assign[key*] = SVExp(exp(s)) +; if s typeof OnReset : resets[key*] = SVExp(exp(s)) +; (s:Begin) : for s* in body(s) do: build-tables(s*,assign,resets,flattn,rsignals,simuls) +; (s:StopStmt|PrintfStmt) : +; add(simuls,[s one]) +; (s:DefMemory|DefPoison|DefNode|EmptyStmt) : false +; +; +;defn mark-referenced (referenced?:HashTable<Symbol,True>, s:Stmt) -> False : +; defn mark-referenced-e (e:Expression) -> Expression : +; match(map(mark-referenced-e,e)) : +; (e:WRef) : +; referenced?[name(e)] = true +; e +; (e) : e +; do(mark-referenced{referenced?,_:Stmt},s) +; map(mark-referenced-e,s) +; false +; +;defn mark-referenced (referenced?:HashTable<Symbol,True>, sv:SymbolicValue) -> SymbolicValue : +; defn mark-referenced-e (e:Expression) -> Expression : +; match(map(mark-referenced-e,e)) : +; (e:WRef) : +; referenced?[name(e)] = true +; e +; (e) : e +; map{mark-referenced-e,_} $ map(mark-referenced{referenced?,_:SymbolicValue},sv) +; +;defn is-referenced? (referenced?:HashTable<Symbol,True>, s:Stmt) -> True|False : +; match(s) : +; (s:DefPoison|DefWire|DefRegister|DefAccessor|DefMemory|DefNode) : key?(referenced?,name(s)) +; (s:WDefInstance) : true +; (s:PrintfStmt|StopStmt|Conditionally) : true +; +;;--------------- Expand Whens Pass ------------------- +; +;public defn expand-whens (c:Circuit) -> Circuit : +; +; defn expand-whens (ports:List<Port>, table:HashTable<Symbol,SymbolicValue>,cons:Vector<Stmt>) -> False : +; for p in ports do : +; if direction(p) == OUTPUT : +; val ref = WRef(name(p),type(p),PortKind(),FEMALE) +; if not has-nul?(table[name(p)]) : +; add{cons,_} $ Connect(FileInfo(),ref,to-exp(table[name(p)]) as Expression) +; +; defn expand-whens (s:Stmt, table:HashTable<Symbol,SymbolicValue>,decs:Vector<Stmt>,cons:Vector<Stmt>) -> Stmt : +; match(map(expand-whens{_,table,decs,cons},s)) : +; (s:DefNode) : +; add(decs,s) +; (s:DefMemory) : +; add(decs,s) +; (s:DefPoison) : +; add(decs,s) +; (s:DefWire) : +; add(decs,s) +; val ref = WRef(name(s),type(s),NodeKind(),FEMALE) +; if not has-nul?(table[name(s)]) : +; add{cons,_} $ Connect(info(s),ref,to-exp(table[name(s)]) as Expression) +; (s:DefRegister) : +; add(decs,s) +; val e = to-exp(table[name(s)]) +; match(e) : +; (e:Expression) : +; val ref = WRef(name(s),type(s),NodeKind(),FEMALE) +; val en = to-exp(optimize $ get-write-enable(table[name(s)])) as Expression +; if en == one : +; add{cons,_} $ Connect(info(s),ref,e) +; else : +; add{cons,_} $ Conditionally(info(s),en,Connect(info(s),ref,e),EmptyStmt()) +; (e:False) : false +; (s:DefAccessor) : +; add(decs,s) +; val t = type(s) +; val n = name(s) +; if gender(s) == FEMALE : +; val ref = WRef(n,t,WriteAccessorKind(),FEMALE) +; val e = to-exp(table[n]) +; match(e) : +; (e:Expression) : +; val en = (to-exp $ optimize $ get-write-enable(table[n])) as Expression +; if en == one : +; add{cons,_} $ Connect(info(s),ref,e) +; else : +; add{cons,_} $ Conditionally(info(s),en,Connect(info(s),ref,e),EmptyStmt()) +; (e:False) : false +; (s:WDefInstance) : +; add(decs,s) +; for f in fields(type(module(s)) as BundleType) map : +; if flip(f) == REVERSE : +; val n = to-symbol("~.~" % [name(s),name(f)]) ; only on inputs +; val x = to-symbol(split(to-string(n),'.')[0]) +; val f = to-symbol(split(to-string(n),'.')[1]) +; val ref = WRef(x,type(module(s)),InstanceKind(),FEMALE) +; val sref = WSubField(ref,f,bundle-field-type(type(module(s)),f),FEMALE) +; if not has-nul?(table[n]) : +; add{cons,_} $ Connect(info(s),sref,to-exp(table[n]) as Expression) +; (s:Connect|Conditionally|OnReset|Begin|EmptyStmt|StopStmt|PrintfStmt) : false +; s +; +; defn expand-whens (m:Module) -> Module : +; match(m) : +; (m:ExModule) : m +; (m:InModule) : +; val assign = HashTable<Symbol,SymbolicValue>(symbol-hash) +; val resets = HashTable<Symbol,SymbolicValue>(symbol-hash) +; val flattn = HashTable<Symbol,True|False>(symbol-hash) +; val rsignals = HashTable<Symbol,Expression>(symbol-hash) +; val simuls = Vector<[Stmt,Expression]>() +; +; for p in ports(m) do : +; if direction(p) == OUTPUT : +; assign[name(p)] = SVNul() +; flattn[name(p)] = false +; +; build-tables(body(m),assign,resets,flattn,rsignals,simuls) +; for x in assign do : assign[key(x)] = optimize(value(x)) +; for x in resets do : resets[key(x)] = optimize(value(x)) +; +; ;val enables = get-enables(assign,kinds) +; ;for x in enables do : enables[key(x)] = optimize(value(x)) +; +; ;println-debug("====== Assigns ======") +; ;for x in assign do : println-debug(x) +; ;println-debug("====== Resets ======") +; ;for x in resets do : println-debug(x) +; +; val table = merge-resets(assign,resets,rsignals) +; ;println-debug("====== Table ======") +; ;for x in table do : println-debug(x) +; +; val decs = Vector<Stmt>() +; val cons = Vector<Stmt>() +; expand-whens(ports(m),table,cons) +; expand-whens(body(m),table,decs,cons) +; +; for se in simuls do : +; val [s e] = se +; if e == one : add(decs,s) +; else : add(decs,Conditionally(info(s),e,s,EmptyStmt())) +; +; val referenced? = HashTable<Symbol,True>(symbol-hash) +; for x in table do : +; mark-referenced(referenced?,value(x)) +; if value(x) != SVNul() : +; referenced?[key(x)] = true +; for x in decs do : +; mark-referenced(referenced?,x) +; val decs* = Vector<Stmt>() +; for x in decs do : +; if is-referenced?(referenced?,x) : add(decs*,x) +; +; InModule(info(m),name(m),ports(m),Begin(to-list(append(decs*,to-list(cons))))) +; +; val c* = Circuit(info(c),modules*, main(c)) where : +; val modules* = +; for m in modules(c) map : +; expand-whens(m) +; ;throw(PassExceptions(errors)) when not empty?(errors) +; 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:DefInstance) : DefInstance(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 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 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) ")"]) - 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)]) -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:LongWidth,w2:LongWidth) : 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 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 @@ -1997,15 +1627,15 @@ defn solve-constraints (l:List<WGeq>) -> HashTable<Symbol,Width> : MaxWidth(unique(v)) (w:PlusWidth) : match(arg1(w),arg2(w)) : - (w1:LongWidth,w2:LongWidth) : LongWidth(plus(width(w1),width(w2))) + (w1:IntWidth,w2:IntWidth) : IntWidth(plus(width(w1),width(w2))) (w1,w2) : w (w:MinusWidth) : match(arg1(w),arg2(w)) : - (w1:LongWidth,w2:LongWidth) : LongWidth(minus(width(w1),width(w2))) + (w1:IntWidth,w2:IntWidth) : IntWidth(minus(width(w1),width(w2))) (w1,w2) : w (w:ExpWidth) : match(arg1(w)) : - (w1:LongWidth) : LongWidth(pow(to-long(2),width(w1)) - to-long(1)) + (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 : @@ -2110,87 +1740,10 @@ public defn width! (t:Type) -> Width : match(t) : (t:UIntType) : width(t) (t:SIntType) : width(t) - (t:ClockType) : LongWidth(1) + (t:ClockType) : IntWidth(1) (t) : error("No width!") public defn width! (e:Expression) -> Width : width!(type(e)) -defn gen-constraints (m:Module, h:HashTable<Symbol,Type>, v:Vector<WGeq>) -> Module: - defn gen-constraints-s (s:Stmt) -> Stmt : - match(map(gen-constraints-s,s)) : - (s:DefWire) : DefWire(info(s),name(s),h[name(s)]) - (s:DefPoison) : DefPoison(info(s),name(s),h[name(s)]) - (s:DefRegister) : DefRegister(info(s),name(s),h[name(s)],gen-constraints(clock(s)),gen-constraints(reset(s))) - (s:DefAccessor) : DefAccessor(info(s),name(s),gen-constraints(source(s)),gen-constraints(index(s)), acc-dir(s)) - (s:DefInstance) : DefInstance(info(s),name(s),gen-constraints(module(s))) - (s:DefMemory) : DefMemory(info(s),name(s),h[name(s)],seq?(s),gen-constraints(clock(s)),size(s)) - (s:DefNode) : - val l = h[name(s)] - val r = gen-constraints(value(s)) - add(v,WGeq(width!(l),width!(type(r)))) - DefNode(info(s),name(s),r) - (s:Connect) : - val l = gen-constraints(loc(s)) - val e = gen-constraints(exp(s)) - add(v,WGeq(width!(type(l)),width!(type(e)))) - Connect(info(s),l,e) - (s:PrintfStmt) : - PrintfStmt(info(s),string(s),map(gen-constraints,args(s)),gen-constraints(clk(s))) - (s:Conditionally) : - val p = gen-constraints(pred(s)) - add(v,WGeq(width!(type(p)),LongWidth(1))) - add(v,WGeq(LongWidth(1),width!(type(p)))) - map(gen-constraints-s,Conditionally(info(s),p,conseq(s),alt(s))) - (s) : s - - defn gen-constraints (e:Expression) -> Expression : - match(map(gen-constraints,e)) : - (e:WRef) : WRef(name(e),h[name(e)],kind(e),gender(e)) - (e:WSubfield) : WSubfield(exp(e),name(e),bundle-field-type(type(exp(e)),name(e)),gender(e)) - (e:WIndex) : error("Shouldn't be here") - (e:DoPrim) : DoPrim(op(e),args(e),consts(e),primop-gen-constraints(e,v)) - (e:UIntValue) : - match(width(e)) : - (w:UnknownWidth) : - val w* = VarWidth(firrtl-gensym(`w,width-name-hash)) - add(v,WGeq(w*,LongWidth(max(1,req-num-bits(value(e)) - 1)))) - UIntValue(value(e),w*) - (w) : e - (e:SIntValue) : - match(width(e)) : - (w:UnknownWidth) : - val w* = VarWidth(firrtl-gensym(`w,width-name-hash)) - add(v,WGeq(w*,LongWidth(req-num-bits(value(e))))) - SIntValue(value(e),w*) - (w) : e - (e) : e - - val ports* = - for p in ports(m) map : Port(info(p),name(p),direction(p),h[name(p)]) - - match(m) : - (m:ExModule) : ExModule(info(m),name(m),ports*) - (m:InModule) : InModule(info(m),name(m),ports*,gen-constraints-s(body(m))) - -defn build-environment (c:Circuit,m:Module,h:HashTable<Symbol,Type>) -> HashTable<Symbol,Type> : - defn build-environment (s:Stmt) -> False : - match(s) : - (s:DefWire) : h[name(s)] = remove-unknowns(type(s)) - (s:DefPoison) : h[name(s)] = remove-unknowns(type(s)) - (s:DefRegister) : h[name(s)] = remove-unknowns(type(s)) - (s:DefInstance) : h[name(s)] = h[name(module(s) as WRef)] - (s:DefMemory) : h[name(s)] = remove-unknowns(type(s)) - (s:DefAccessor) : h[name(s)] = remove-unknowns(type(s)) - (s:DefNode) : h[name(s)] = remove-unknowns(type(value(s))) - (s) : false - do(build-environment,s) - for p in ports(m) do : - h[name(p)] = bundle-field-type(h[name(m)],name(p)) - - match(m) : - (m:ExModule) : false - (m:InModule) : build-environment(body(m)) - h - 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 : @@ -2217,14 +1770,14 @@ defn reduce-var-widths (c:Circuit,h:HashTable<Symbol,Width>) -> Circuit : (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:LongWidth) : width(w) + (w:IntWidth) : width(w) (w) : println(w) error("Shouldn't be here") val s = solve(w) match(s) : - (s:Long) : LongWidth(s) + (s:Long) : IntWidth(s) (s) : w defn reduce-var-widths-w (w:Width) -> Width : @@ -2243,33 +1796,50 @@ defn reduce-var-widths (c:Circuit,h:HashTable<Symbol,Width>) -> Circuit : Circuit(info(c),modules*,main(c)) -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 infer-widths (c:Circuit) -> Circuit : - defn deepcopy (t:HashTable<Symbol,Type>) -> HashTable<Symbol,Type> : - t0 where : - val t0 = HashTable<Symbol,Type>(symbol-hash) - for x in t do : - t0[key(x)] = value(x) - val v = Vector<WGeq>() - val ports* = HashTable<Symbol,Type>(symbol-hash) - for m in modules(c) do : - ports*[name(m)] = remove-unknowns(BundleType(map(to-field,ports(m)))) - val modules* = for m in modules(c) map : - println-all-debug(["====== MODULE(" name(m) ") ENV ======"]) - val h = build-environment(c,m,deepcopy(ports*)) - for x in h do: println-debug(x) - println-all-debug(["====================================="]) - val m* = gen-constraints(m,h,v) - println-all-debug(["====== MODULE(" name(m) ") ======"]) - println-debug(m*) - println-all-debug(["====================================="]) - m* + 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 + (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("=================================") @@ -2277,348 +1847,367 @@ defn infer-widths (c:Circuit) -> Circuit : println-debug("======== SOLVED CONSTRAINTS ========") for x in h do : println-debug(x) println-debug("====================================") - reduce-var-widths(Circuit(info(c),modules*,main(c)),h) - - -;================= 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:DefInstance) : - 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:DefInstance) : 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)) - -;================= Bring to Real IR ======================== -; Returns a new Circuit with only real IR nodes. -public defstruct ToRealIR <: Pass -public defmethod pass (b:ToRealIR) -> (Circuit -> Circuit) : to-real-ir -public defmethod name (b:ToRealIR) -> String : "Real IR" -public defmethod short-name (b:ToRealIR) -> String : "real-ir" - -defn to-real-ir (c:Circuit) : - defn to-exp (e:Expression) : - match(map(to-exp,e)) : - (e:WRef) : Ref(name(e), type(e)) - (e:WSubfield) : Subfield(exp(e),name(e),type(e)) - (e:WIndex) : error("Shouldn't be here") - (e) : e - defn to-stmt (s:Stmt) : - match(map(to-exp,s)) : - (e:DecFromIndexer) : error("Shouldn't be here") - (e:DecToIndexer) : error("Shouldn't be here") - (e) : map(to-stmt,e) - - 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 - - -;================= Split Expressions ======================== -; Intended to only work on low firrtl + reduce-var-widths(Circuit(info(c),modules(c),main(c)),h) +; +; +;;================= 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)) +; +;;================= Bring to Real IR ======================== +;; Returns a new Circuit with only real IR nodes. +;public defstruct ToRealIR <: Pass +;public defmethod pass (b:ToRealIR) -> (Circuit -> Circuit) : to-real-ir +;public defmethod name (b:ToRealIR) -> String : "Real IR" +;public defmethod short-name (b:ToRealIR) -> String : "real-ir" +; +;defn to-real-ir (c:Circuit) : +; defn to-exp (e:Expression) : +; match(map(to-exp,e)) : +; (e:WRef) : Ref(name(e), type(e)) +; (e:WSubField) : Subfield(exp(e),name(e),type(e)) +; (e:WSubIndex) : error("Shouldn't be here") +; (e) : e +; defn to-stmt (s:Stmt) : +; match(map(to-exp,s)) : +; (e:DecFromIndexer) : error("Shouldn't be here") +; (e:DecToIndexer) : error("Shouldn't be here") +; (e) : map(to-stmt,e) +; +; 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 +; +; +;;================= 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 full-name (e:Expression) -> Symbol|False : - match(e) : - (e:Ref) : name(e) - (e) : false - -defn split-exp (c:Circuit) : - defn split-exp-s (s:Stmt,v:Vector<Stmt>,sh:HashTable<Symbol,Int>) -> False : - defn split-exp-e (e:Expression,n:Symbol|False,info:FileInfo) -> Expression : - match(e) : - (e:DoPrim) : - ;var all-same-type? = true - ;for x in args(e) do : - ; if type(x) != type(e) : all-same-type? = false - ;all-same-type? = false - ;if not all-same-type? : - ;val n* = - ; if n typeof False : firrtl-gensym(`F,sh) - ; else : firrtl-gensym(symbol-join([n as Symbol temp-delin]),sh) - val n* = - if n typeof False : firrtl-gensym(`F,sh) - else : firrtl-gensym(n as Symbol,sh) - add(v,DefNode(info,n*,map(split-exp-e{_,n,info},e))) - Ref(n*,type(e)) - ;else : e - (e) : map(split-exp-e{_,n,info},e) - defn f (s:Stmt) -> False: split-exp-s(s,v,sh) - match(s) : - (s:Begin) : - do(f,s) - (s:Conditionally) : - ;Predicate - val pred* = map(split-exp-e{_,full-name(pred(s)),info(s)},pred(s)) - - ;Connect TODO Broken for stop/printf - match(conseq(s)) : - (c:Connect) : - val exp* = map(split-exp-e{_,full-name(loc(c)),info(c)},exp(c)) - val conseq* = Connect(info(c),loc(c),exp*) - add(v,Conditionally(info(s),pred*,conseq*,alt(s))) - (c:PrintfStmt) : - val args* = for x in args(c) map : - map(split-exp-e{_,false,info(c)},x) - val conseq* = PrintfStmt(info(c),string(c),args*,clk(c)) - add(v,Conditionally(info(s),pred*,conseq*,alt(s))) - (c:StopStmt) : - add(v,Conditionally(info(s),pred*,c,alt(s))) - (s:Connect) : - val exp* = map(split-exp-e{_,full-name(loc(s)),info(s)},exp(s)) - add(v,Connect(info(s),loc(s),exp*)) - (s:PrintfStmt) : - val args* = for x in args(s) map : - map(split-exp-e{_,false,info(s)},x) - add(v,PrintfStmt(info(s),string(s),args*,clk(s))) - (s:DefNode) : - val exp* = map(split-exp-e{_,name(s),info(s)},value(s)) - add(v,DefNode(info(s),name(s),exp*)) - (s) : add(v,map(split-exp-e{_,false,info(s)},s)) - false - - ;val start-time = current-time-us() - Circuit{info(c),_,main(c)} $ - for m in modules(c) map : - match(m) : - (m:InModule) : - val v = Vector<Stmt>() - val sh = get-sym-hash(m,keys(v-keywords)) - ;val before = current-time-us() - start-time - ;println-all(["Before split: " before]) - split-exp-s(body(m),v,sh) - ;val now = current-time-us() - start-time - ;println-all(["After split: " now]) - ;println-all(["Diff: " now - before]) - InModule(info(m),name(m),ports(m),Begin(to-list(v))) - (m:ExModule) : m - -;================= 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:DefInstance) : DefInstance(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" -public defmethod short-name (b:Pad) -> String : "pad-widths" - -;------------ Helper Functions -------------- -defn int-width! (t:Type) -> Long : - match(width!(t)) : - (w:LongWidth) : width(w) - (w) : error("Non-int width") - -defn set-width (desired:Long,t:Type) -> Type : - match(t) : - (t:UIntType) : UIntType(LongWidth(desired)) - (t:SIntType) : SIntType(LongWidth(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),LongWidth(desired)) - (e:SIntValue) : - val i = int-width!(type(e)) - if i > desired : trim(desired, e) - else : SIntValue(value(e),LongWidth(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*,clk(s)) - (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))) - +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) : get-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)) + 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) + else : e + (e) : e + map{split-exp{_,i},_} $ map(split-exp-s,s) + split-exp-s(body(m),v,sh) + InModule(info(m),name(m),ports(m),Begin(to-list(v))) -;============= Constant Propagation ================ +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)) +;defn split-exp (c:Circuit) : +; defn split-exp-s (s:Stmt,v:Vector<Stmt>,sh:HashTable<Symbol,Int>) -> False : +; defn split-exp-e (e:Expression,n:Symbol|False,info:FileInfo) -> Expression : +; match(e) : +; (e:DoPrim) : +; ;var all-same-type? = true +; ;for x in args(e) do : +; ; if type(x) != type(e) : all-same-type? = false +; ;all-same-type? = false +; ;if not all-same-type? : +; ;val n* = +; ; if n typeof False : firrtl-gensym(`F,sh) +; ; else : firrtl-gensym(symbol-join([n as Symbol temp-delin]),sh) +; val n* = +; if n typeof False : firrtl-gensym(`F,sh) +; else : firrtl-gensym(n as Symbol,sh) +; add(v,DefNode(info,n*,map(split-exp-e{_,n,info},e))) +; Ref(n*,type(e)) +; ;else : e +; (e) : map(split-exp-e{_,n,info},e) +; defn f (s:Stmt) -> False: split-exp-s(s,v,sh) +; match(s) : +; (s:Begin) : +; do(f,s) +; (s:Conditionally) : +; ;Predicate +; val pred* = map(split-exp-e{_,full-name(pred(s)),info(s)},pred(s)) +; +; ;Connect TODO Broken for stop/printf +; match(conseq(s)) : +; (c:Connect) : +; val exp* = map(split-exp-e{_,full-name(loc(c)),info(c)},exp(c)) +; val conseq* = Connect(info(c),loc(c),exp*) +; add(v,Conditionally(info(s),pred*,conseq*,alt(s))) +; (c:PrintfStmt) : +; val args* = for x in args(c) map : +; map(split-exp-e{_,false,info(c)},x) +; val conseq* = PrintfStmt(info(c),string(c),args*) +; add(v,Conditionally(info(s),pred*,conseq*,alt(s))) +; (c:StopStmt) : +; add(v,Conditionally(info(s),pred*,c,alt(s))) +; (s:Connect) : +; val exp* = map(split-exp-e{_,full-name(loc(s)),info(s)},exp(s)) +; add(v,Connect(info(s),loc(s),exp*)) +; (s:PrintfStmt) : +; val args* = for x in args(s) map : +; map(split-exp-e{_,false,info(s)},x) +; add(v,PrintfStmt(info(s),string(s),args*)) +; (s:DefNode) : +; val exp* = map(split-exp-e{_,name(s),info(s)},value(s)) +; add(v,DefNode(info(s),name(s),exp*)) +; (s) : add(v,map(split-exp-e{_,false,info(s)},s)) +; false +; +; ;val start-time = current-time-us() +; Circuit{info(c),_,main(c)} $ +; for m in modules(c) map : +; match(m) : +; (m:InModule) : +; val v = Vector<Stmt>() +; val sh = get-sym-hash(m,keys(v-keywords)) +; ;val before = current-time-us() - start-time +; ;println-all(["Before split: " before]) +; split-exp-s(body(m),v,sh) +; ;val now = current-time-us() - start-time +; ;println-all(["After split: " now]) +; ;println-all(["Diff: " now - before]) +; InModule(info(m),name(m),ports(m),Begin(to-list(v))) +; (m:ExModule) : m +; +;;================= 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))) +; +; +;;============= 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" -;------------ Helper Functions -------------- - - -;------------- Pad Widths ------------------- - defn const-prop-e (e:Expression) -> Expression : match(map(const-prop-e,e)) : (e:DoPrim) : @@ -2657,3 +2246,468 @@ public defn const-prop (c:Circuit) -> Circuit : (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 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:WSubIndex) : merge(lowered-name(exp(e)),to-symbol(value(e)),`_) +defn root-ref (e:Expression) -> Expression : + match(e) : + (e:WRef) : e + (e:WSubField|WSubIndex) : root-ref(e) + +;------------- Pass ------------------ + +defn lower-types (s:Stmt) -> Stmt : + defn lower-types-e (e:Expression) -> Expression : + 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)) + (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|DefRegister|DefPoison) : + if is-ground?(type(s)) : s + else : + 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) + 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 : + switch { _ == gender(e) } : + MALE : Field(name(e),DEFAULT,type(f)) + FEMALE : Field(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)) + (s) : map(lower-types,s) + +defn lower-types (c:Circuit) -> Circuit : + Circuit{info(c),_,main(c)} $ + for m in modules(c) map : + val ports* = + for p in ports(m) map-append : + val es = 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))) + +;============ 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 get-width (t:Type) -> Long : + match(t) : + (t:UIntType|SIntType) : width(t) + (t:BundleType) : + var w = 0 + for f in fields do : + w = w + get-width(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) + +defn rand-string (t:Type) -> String : + val w* = ((get-width(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") + + + +;------------- 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 : + 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 + 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] + + print $ string-join $ 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 = width!(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 " }"] + AS-UINT-OP : ["$unsigned(" emit(a0()) ")"] + AS-SINT-OP : ["$signed(" emit(a0()) ")"] + DYN-SHIFT-LEFT-OP : [cast(a0()) " << " emit(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()) "[" width!(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 : + join{_," & "} $ + for b in 0 to width!(type(doprim)) map : + [cast(a0() ) "[" b "]"] + BIT-OR-REDUCE-OP : + join{_," | "} $ + for b in 0 to width!(type(doprim)) map : + [cast(a0() ) "[" b "]"] + BIT-XOR-REDUCE-OP : + join{_," ^ "} $ + for b in 0 to width!(type(doprim)) map : + [cast(a0() ) "[" b "]"] + +defn emit-verilog (m:InModule) -> Module : + val netlist = HashTable<Expression,Expression>(exp-hash) + val simlist = Vector<Stmt>() + 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) + (s) : map(build-netlist,s) + + val declares = Vector<Streamable>() + val at-clock = HashTable<Expression,Vector<Streamable>>(exp-hash) + val initals = 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 update-reset (e:Expression,clk:Expression,reset?:Expression,init:Expression) : + 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,clk:Expression,en:Expression) : + add(at-clock[clk],["if(" en ") begin"]) + add(at-clock[clk],[tab e " <= " netlist[e]]) + add(at-clock[clk],["end"]) + defn initialize (e:Expression) : + add(initals,[e " = " rand-string(type(e))]) + defn initialize-mem (e:Expression,i:Int) : + add(initals,["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))]) + 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 ","]) + 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"]) + 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 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) + (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)) + 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)) + 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)) + (s:Conditionally) : + (s:Stop) : simulate(clk(s),one,stop(ret(s))) + (s:Print) : simulate(clk(s),one,printf(string(s),args(s))) + (s:WDefInstance) : + val es = create-exps(WRef(name(s),type(s),InstanceKind(),BI-GENDER)) + 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) + 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 : + 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*) + + 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 rw in readwriters(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-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)) + (s:Begin) : map(build-streams,s) + + defn emit-streams () : + if !empty?(declares) : + for x in declares do : + emit(x) + + if !empty?(initials) : + emit(["`ifndef SYNTHESIS"]) + emit([" integer initvar;"]) + emit([" initial begin"]) + emit([" #0.002;"]) + for x in initals do : + emit([tab x]) + emit([" end"]) + emit(["`endif"]) + + for clk-stream in at-clock do : + if !empty?(value(clk-stream)) : + emit(["always @(posedge " key(clk-stream) " ) begin"]) + for x in value(clk-stream) do : + emit([tab x]) + emit(["end"]) + + build-netlist(body(m)) + build-streams(body(m)) + emit-streams() + +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/primop.stanza b/src/main/stanza/primop.stanza index b285e0ee..a31b9c51 100644 --- a/src/main/stanza/primop.stanza +++ b/src/main/stanza/primop.stanza @@ -5,132 +5,207 @@ defpackage firrtl/primops : import firrtl/ir-utils import firrtl/passes +defn PLUS (w1:Width,w2:Width) -> Width : PlusWidth(w1,w2) +defn MAX (w1:Width,w2:Width) -> Width : MaxWidth(list(w1,w2)) +defn MINUS (w1:Width,w2:Width) -> Width : MinusWidth(w1,w2) +defn POW (w1:Width) -> Width : ExpWidth(w1) -public defn lower-and-type-primop (e:DoPrim) -> DoPrim : - defn u () : UIntType(UnknownWidth()) - defn s () : SIntType(UnknownWidth()) - defn u-and (op1:Expression,op2:Expression) : - match(type(op1), type(op2)) : - (t1:UIntType, t2:UIntType) : u() - (t1:SIntType, t2) : s() - (t1, t2:SIntType) : s() - (t1, t2) : UnknownType() - - defn of-type (op:Expression) : - match(type(op)) : - (t:UIntType) : u() - (t:SIntType) : s() - (t) : UnknownType() - +public defn set-primop-type (e:DoPrim) -> DoPrim : ;println-all(["Inferencing primop type: " e]) + val o = op(e) + val a = args(e) + val c = consts(e) + defn t1 () : type(a[0]) + defn t2 () : type(a[1]) + defn t3 () : type(a[2]) + defn w1 () : width!(type(a[0])) + defn w2 () : width!(type(a[1])) + defn w3 () : width!(type(a[2])) + defn c1 () : IntWidth(c[0]) + defn c2 () : IntWidth(c[1]) switch {op(e) == _} : - ADD-OP : DoPrim(ADD-OP,args(e),consts(e),u-and(args(e)[0],args(e)[1])) - SUB-OP : DoPrim(SUB-OP,args(e),consts(e),s()) - MUL-OP : DoPrim(MUL-OP,args(e),consts(e),u-and(args(e)[0],args(e)[1])) - DIV-OP : DoPrim(DIV-OP,args(e),consts(e),u-and(args(e)[0],args(e)[1])) - MOD-OP : DoPrim(MOD-OP,args(e),consts(e),of-type(args(e)[0])) - QUO-OP : DoPrim(QUO-OP,args(e),consts(e),u-and(args(e)[0],args(e)[1])) - REM-OP : DoPrim(REM-OP,args(e),consts(e),of-type(args(e)[1])) - ADD-WRAP-OP : DoPrim(ADD-WRAP-OP,args(e),consts(e),u-and(args(e)[0],args(e)[1])) - SUB-WRAP-OP : DoPrim(SUB-WRAP-OP,args(e),consts(e),u-and(args(e)[0],args(e)[1])) - LESS-OP : DoPrim(LESS-OP,args(e),consts(e),u()) - LESS-EQ-OP : DoPrim(LESS-EQ-OP,args(e),consts(e),u()) - GREATER-OP : DoPrim(GREATER-OP,args(e),consts(e),u()) - GREATER-EQ-OP : DoPrim(GREATER-EQ-OP,args(e),consts(e),u()) - EQUAL-OP : DoPrim(EQUAL-OP,args(e),consts(e),u()) - NEQUAL-OP : DoPrim(NEQUAL-OP,args(e),consts(e),u()) - EQUIV-OP : DoPrim(EQUIV-OP,args(e),consts(e),u()) - NEQUIV-OP : DoPrim(NEQUIV-OP,args(e),consts(e),u()) - MUX-OP : DoPrim(MUX-OP,args(e),consts(e),of-type(args(e)[1])) - PAD-OP : DoPrim(PAD-OP,args(e),consts(e),of-type(args(e)[0])) - AS-UINT-OP : DoPrim(AS-UINT-OP,args(e),consts(e),u()) - AS-SINT-OP : DoPrim(AS-SINT-OP,args(e),consts(e),s()) - DYN-SHIFT-LEFT-OP : DoPrim(DYN-SHIFT-LEFT-OP,args(e),consts(e),of-type(args(e)[0])) - DYN-SHIFT-RIGHT-OP : DoPrim(DYN-SHIFT-RIGHT-OP,args(e),consts(e),of-type(args(e)[0])) - SHIFT-LEFT-OP : DoPrim(SHIFT-LEFT-OP,args(e),consts(e),of-type(args(e)[0])) - SHIFT-RIGHT-OP : DoPrim(SHIFT-RIGHT-OP,args(e),consts(e),of-type(args(e)[0])) - CONVERT-OP : DoPrim(CONVERT-OP,args(e),consts(e),s()) - NEG-OP : DoPrim(NEG-OP,args(e),consts(e),s()) - BIT-NOT-OP : DoPrim(op(e),args(e),consts(e),of-type(args(e)[0])) - BIT-AND-OP : DoPrim(op(e),args(e),consts(e),of-type(args(e)[0])) - BIT-OR-OP : DoPrim(op(e),args(e),consts(e),of-type(args(e)[0])) - BIT-XOR-OP : DoPrim(op(e),args(e),consts(e),of-type(args(e)[0])) - BIT-SELECT-OP : DoPrim(op(e),args(e),consts(e),u()) - BITS-SELECT-OP : DoPrim(op(e),args(e),consts(e),u()) - CONCAT-OP : DoPrim(op(e),args(e),consts(e),u()) - BIT-AND-REDUCE-OP : DoPrim(op(e),args(e),consts(e),u()) - BIT-OR-REDUCE-OP : DoPrim(op(e),args(e),consts(e),u()) - BIT-XOR-REDUCE-OP : DoPrim(op(e),args(e),consts(e),u()) - -public defn primop-gen-constraints (e:DoPrim,v:Vector<WGeq>) -> Type : - defn get-max (i0:Int,i1:Int) -> Width : get-max(list(i0,i1)) - defn get-max (ls:List<Int>) -> Width : - MaxWidth $ for i in ls map : width!(args(e)[i]) - defn all-max () -> Width : - MaxWidth $ for x in args(e) map : width!(x) - - println-all-debug(["Looking at " op(e) " with inputs " args(e)]) - val w* = switch {op(e) == _} : - ADD-OP : PlusWidth(get-max(0,1),LongWidth(1)) - SUB-OP : PlusWidth(get-max(0,1),LongWidth(1)) - MUL-OP : PlusWidth(width!(args(e)[0]),width!(args(e)[1])) - DIV-OP : - match(type(args(e)[0]),type(args(e)[1])) : - (t0:UIntType,t1:SIntType) : PlusWidth(width!(args(e)[0]),LongWidth(1)) - (t0:SIntType,t1:SIntType) : PlusWidth(width!(args(e)[0]),LongWidth(1)) - (t0,t1) : width!(args(e)[0]) - MOD-OP : - match(type(args(e)[0]),type(args(e)[1])) : - (t0:SIntType,t1:UIntType) : PlusWidth(width!(args(e)[1]),LongWidth(1)) - (t0,t1) : width!(args(e)[1]) - QUO-OP : - match(type(args(e)[0]),type(args(e)[1])) : - (t0:UIntType,t1:SIntType) : PlusWidth(width!(args(e)[0]),LongWidth(1)) - (t0:SIntType,t1:SIntType) : PlusWidth(width!(args(e)[0]),LongWidth(1)) - (t0,t1) : width!(args(e)[0]) - REM-OP : - match(type(args(e)[0]),type(args(e)[1])) : - (t0:SIntType,t1:UIntType) : PlusWidth(width!(args(e)[1]),LongWidth(1)) - (t0,t1) : width!(args(e)[1]) - ADD-WRAP-OP : get-max(0,1) - SUB-WRAP-OP : get-max(0,1) - LESS-OP : LongWidth(1) - LESS-EQ-OP : LongWidth(1) - GREATER-OP : LongWidth(1) - GREATER-EQ-OP : LongWidth(1) - EQUAL-OP : LongWidth(1) - NEQUAL-OP : LongWidth(1) - EQUIV-OP : LongWidth(1) - NEQUIV-OP : LongWidth(1) - MUX-OP : - add(v,WGeq(LongWidth(1),width!(args(e)[0]))) - add(v,WGeq(width!(args(e)[0]),LongWidth(1))) - get-max(1,2) - PAD-OP : LongWidth(consts(e)[0]) - AS-UINT-OP : width!(args(e)[0]) - AS-SINT-OP : width!(args(e)[0]) - SHIFT-LEFT-OP : PlusWidth(width!(args(e)[0]),LongWidth(consts(e)[0])) - SHIFT-RIGHT-OP : MinusWidth(width!(args(e)[0]),LongWidth(consts(e)[0])) - DYN-SHIFT-LEFT-OP : PlusWidth(width!(args(e)[0]),ExpWidth(width!(args(e)[1]))) - DYN-SHIFT-RIGHT-OP : width!(args(e)[0]) - CONVERT-OP : - match(type(args(e)[0])) : - (t0:UIntType) : PlusWidth(width!(args(e)[0]),LongWidth(1)) - (t0:SIntType) : width!(args(e)[0]) - NEG-OP : PlusWidth(width!(args(e)[0]),LongWidth(1)) - BIT-NOT-OP : width!(args(e)[0]) - BIT-AND-OP : get-max(0,1) - BIT-OR-OP : get-max(0,1) - BIT-XOR-OP : get-max(0,1) - BIT-AND-REDUCE-OP : all-max() - BIT-OR-REDUCE-OP : all-max() - BIT-XOR-REDUCE-OP : all-max() - CONCAT-OP : PlusWidth(width!(args(e)[0]),width!(args(e)[1])) - BIT-SELECT-OP : LongWidth(1) - BITS-SELECT-OP : LongWidth(consts(e)[0] - consts(e)[1] + 1) - - match(type(e)) : - (t:UIntType) : UIntType(w*) - (t:SIntType) : SIntType(w*) - (t) : error("Shouldn't be here") + ADD-OP : DoPrim{o,a,c,_} $ + match(t1(),t2()) : + (t1:UIntType, t2:UIntType) : UIntType(PLUS(MAX(w1(),w2()),ONE)) + (t1:UIntType, t2:SIntType) : SIntType(PLUS(MAX(w1(),w2()),ONE)) + (t1:SIntType, t2:UIntType) : SIntType(PLUS(MAX(w1(),w2()),ONE)) + (t1:SIntType, t2:SIntType) : SIntType(PLUS(MAX(w1(),w2()),ONE)) + SUB-OP : DoPrim{o,a,c,_} $ + match(t1(),t2()) : + (t1:UIntType, t2:UIntType) : SIntType(PLUS(MAX(w1(),w2()),ONE)) + (t1:UIntType, t2:SIntType) : SIntType(PLUS(MAX(w1(),w2()),ONE)) + (t1:SIntType, t2:UIntType) : SIntType(PLUS(MAX(w1(),w2()),ONE)) + (t1:SIntType, t2:SIntType) : SIntType(PLUS(MAX(w1(),w2()),ONE)) + ADD-WRAP-OP : DoPrim{o,a,c,_} $ + match(t1(),t2()) : + (t1:UIntType, t2:UIntType) : UIntType(MAX(w1(),w2())) + (t1:UIntType, t2:SIntType) : SIntType(MAX(w1(),w2())) + (t1:SIntType, t2:UIntType) : SIntType(MAX(w1(),w2())) + (t1:SIntType, t2:SIntType) : SIntType(MAX(w1(),w2())) + SUB-WRAP-OP : DoPrim{o,a,c,_} $ + match(t1(),t2()) : + (t1:UIntType, t2:UIntType) : UIntType(MAX(w1(),w2())) + (t1:UIntType, t2:SIntType) : SIntType(MAX(w1(),w2())) + (t1:SIntType, t2:UIntType) : SIntType(MAX(w1(),w2())) + (t1:SIntType, t2:SIntType) : SIntType(MAX(w1(),w2())) + MUL-OP : DoPrim{o,a,c,_} $ + match(t1(),t2()) : + (t1:UIntType, t2:UIntType) : UIntType(PLUS(w1(),w2())) + (t1:UIntType, t2:SIntType) : SIntType(PLUS(w1(),w2())) + (t1:SIntType, t2:UIntType) : SIntType(PLUS(w1(),w2())) + (t1:SIntType, t2:SIntType) : SIntType(PLUS(w1(),w2())) + DIV-OP : DoPrim{o,a,c,_} $ + match(t1(),t2()) : + (t1:UIntType, t2:UIntType) : UIntType(w1()) + (t1:UIntType, t2:SIntType) : SIntType(PLUS(w1(),w2())) + (t1:SIntType, t2:UIntType) : SIntType(w1()) + (t1:SIntType, t2:SIntType) : SIntType(PLUS(w1(),w2())) + MOD-OP : DoPrim{o,a,c,_} $ + match(t1(),t2()) : + (t1:UIntType, t2:UIntType) : UIntType(w2()) + (t1:UIntType, t2:SIntType) : UIntType(w2()) + (t1:SIntType, t2:UIntType) : SIntType(PLUS(w2(),ONE)) + (t1:SIntType, t2:SIntType) : SIntType(w2()) + QUO-OP : DoPrim{o,a,c,_} $ + match(t1(),t2()) : + (t1:UIntType, t2:UIntType) : UIntType(PLUS(w1(),ONE)) + (t1:UIntType, t2:SIntType) : SIntType(w1()) + (t1:SIntType, t2:UIntType) : SIntType(PLUS(w1(),ONE)) + (t1:SIntType, t2:SIntType) : SIntType(w1()) + REM-OP : DoPrim{o,a,c,_} $ + match(t1(),t2()) : + (t1:UIntType, t2:UIntType) : UIntType(w2()) + (t1:UIntType, t2:SIntType) : SIntType(w2()) + (t1:SIntType, t2:UIntType) : UIntType(PLUS(w2(),ONE)) + (t1:SIntType, t2:SIntType) : SIntType(w2()) + LESS-OP : DoPrim(o,a,c,BoolType()) + LESS-EQ-OP : DoPrim(o,a,c,BoolType()) + GREATER-OP : DoPrim(o,a,c,BoolType()) + GREATER-EQ-OP : DoPrim(o,a,c,BoolType()) + EQUAL-OP : DoPrim(o,a,c,BoolType()) + NEQUAL-OP : DoPrim(o,a,c,BoolType()) + EQUIV-OP : DoPrim(o,a,c,BoolType()) + NEQUIV-OP : DoPrim(o,a,c,BoolType()) + MUX-OP : DoPrim{o,a,c,_} $ + match(t2(),t3()) : + (t2:UIntType, t3:UIntType) : UIntType(MAX(w2(),w3())) + (t2:SIntType, t3:SIntType) : SIntType(MAX(w2(),w3())) + PAD-OP : DoPrim{o,a,c,_} $ + match(t1()) : + (t1:UIntType) : UIntType(c1()) + (t1:SIntType) : SIntType(c1()) + AS-UINT-OP : DoPrim{o,a,c,_} $ + match(t1()) : + (t1:UIntType) : UIntType(w1()) + (t1:SIntType) : UIntType(w1()) + AS-SINT-OP : DoPrim{o,a,c,_} $ + match(t1()) : + (t1:UIntType) : SIntType(w1()) + (t1:SIntType) : SIntType(w1()) + SHIFT-LEFT-OP : DoPrim{o,a,c,_} $ + match(t1()) : + (t1:UIntType) : UIntType(PLUS(w1(),c1())) + (t1:SIntType) : SIntType(PLUS(w1(),c1())) + SHIFT-RIGHT-OP : DoPrim{o,a,c,_} $ + match(t1()) : + (t1:UIntType) : UIntType(MINUS(w1(),c1())) + (t1:SIntType) : SIntType(MINUS(w1(),c1())) + DYN-SHIFT-LEFT-OP : DoPrim{o,a,c,_} $ + match(t1()) : + (t1:UIntType) : UIntType(PLUS(w1(),POW(w2()))) + (t1:SIntType) : SIntType(PLUS(w1(),POW(w2()))) + DYN-SHIFT-RIGHT-OP : DoPrim{o,a,c,_} $ + match(t1()) : + (t1:UIntType) : UIntType(w1()) + (t1:SIntType) : SIntType(w1()) + CONVERT-OP : DoPrim{o,a,c,_} $ + match(t1()) : + (t1:UIntType) : SIntType(PLUS(w1(),ONE)) + (t1:SIntType) : SIntType(w1()) + NEG-OP : DoPrim{o,a,c,_} $ + match(t1()) : + (t1:UIntType) : SIntType(PLUS(w1(),ONE)) + (t1:SIntType) : SIntType(w1()) + BIT-NOT-OP : DoPrim(o,a,c,t1()) + BIT-AND-OP : DoPrim(o,a,c,UIntType(MAX(w1(),w2()))) + BIT-OR-OP : DoPrim(o,a,c,UIntType(MAX(w1(),w2()))) + BIT-XOR-OP : DoPrim(o,a,c,UIntType(MAX(w1(),w2()))) + BIT-AND-REDUCE-OP : DoPrim(o,a,c,BoolType()) + BIT-OR-REDUCE-OP : DoPrim(o,a,c,BoolType()) + BIT-XOR-REDUCE-OP : DoPrim(o,a,c,BoolType()) + CONCAT-OP : DoPrim(o,a,c,UIntType(PLUS(w1(),w2()))) + BIT-SELECT-OP : DoPrim(o,a,c,BoolType()) + BITS-SELECT-OP : DoPrim(o,a,c,UIntType(PLUS(MINUS(c1(),c2()),ONE))) +;public defn primop-gen-constraints (e:DoPrim,v:Vector<WGeq>) -> Type : +; defn get-max (i0:Int,i1:Int) -> Width : get-max(list(i0,i1)) +; defn get-max (ls:List<Int>) -> Width : +; MaxWidth $ for i in ls map : width!(args(e)[i]) +; defn all-max () -> Width : +; MaxWidth $ for x in args(e) map : width!(x) +; +; println-all-debug(["Looking at " op(e) " with inputs " args(e)]) +; val w* = switch {op(e) == _} : +; ADD-OP : PlusWidth(get-max(0,1),IntWidth(1)) +; SUB-OP : PlusWidth(get-max(0,1),IntWidth(1)) +; MUL-OP : PlusWidth(get-max(0,1),get-max(0,1)) +; DIV-OP : +; match(type(args(e)[0]),type(args(e)[1])) : +; (t0:UIntType,t1:SIntType) : PlusWidth(width!(args(e)[0]),IntWidth(1)) +; (t0:SIntType,t1:SIntType) : PlusWidth(width!(args(e)[0]),IntWidth(1)) +; (t0,t1) : width!(args(e)[0]) +; MOD-OP : +; match(type(args(e)[0]),type(args(e)[1])) : +; (t0:SIntType,t1:UIntType) : PlusWidth(width!(args(e)[1]),IntWidth(1)) +; (t0,t1) : width!(args(e)[1]) +; QUO-OP : +; match(type(args(e)[0]),type(args(e)[1])) : +; (t0:UIntType,t1:SIntType) : PlusWidth(width!(args(e)[0]),IntWidth(1)) +; (t0:SIntType,t1:SIntType) : PlusWidth(width!(args(e)[0]),IntWidth(1)) +; (t0,t1) : width!(args(e)[0]) +; REM-OP : +; match(type(args(e)[0]),type(args(e)[1])) : +; (t0:SIntType,t1:UIntType) : PlusWidth(width!(args(e)[1]),IntWidth(1)) +; (t0,t1) : width!(args(e)[1]) +; ADD-WRAP-OP : get-max(0,1) +; SUB-WRAP-OP : get-max(0,1) +; LESS-OP : IntWidth(1) +; LESS-EQ-OP : IntWidth(1) +; GREATER-OP : IntWidth(1) +; GREATER-EQ-OP : IntWidth(1) +; EQUAL-OP : IntWidth(1) +; NEQUAL-OP : IntWidth(1) +; EQUIV-OP : IntWidth(1) +; NEQUIV-OP : IntWidth(1) +; MUX-OP : +; add(v,WGeq(IntWidth(1),width!(args(e)[0]))) +; add(v,WGeq(width!(args(e)[0]),IntWidth(1))) +; get-max(1,2) +; PAD-OP : IntWidth(consts(e)[0]) +; AS-UINT-OP : width!(args(e)[0]) +; AS-SINT-OP : width!(args(e)[0]) +; SHIFT-LEFT-OP : PlusWidth(width!(args(e)[0]),IntWidth(consts(e)[0])) +; SHIFT-RIGHT-OP : MinusWidth(width!(args(e)[0]),IntWidth(consts(e)[0])) +; DYN-SHIFT-LEFT-OP : PlusWidth(width!(args(e)[0]),ExpWidth(width!(args(e)[1]))) +; DYN-SHIFT-RIGHT-OP : width!(args(e)[0]) +; CONVERT-OP : +; match(type(args(e)[0])) : +; (t0:UIntType) : PlusWidth(width!(args(e)[0]),IntWidth(1)) +; (t0:SIntType) : width!(args(e)[0]) +; NEG-OP : PlusWidth(width!(args(e)[0]),IntWidth(1)) +; BIT-NOT-OP : width!(args(e)[0]) +; BIT-AND-OP : get-max(0,1) +; BIT-OR-OP : get-max(0,1) +; BIT-XOR-OP : get-max(0,1) +; BIT-AND-REDUCE-OP : all-max() +; BIT-OR-REDUCE-OP : all-max() +; BIT-XOR-REDUCE-OP : all-max() +; CONCAT-OP : PlusWidth(width!(args(e)[0]),width!(args(e)[1])) +; BIT-SELECT-OP : IntWidth(1) +; BITS-SELECT-OP : IntWidth(consts(e)[0] - consts(e)[1] + 1) +; +; match(type(e)) : +; (t:UIntType) : UIntType(w*) +; (t:SIntType) : SIntType(w*) +; (t) : error("Shouldn't be here") +; diff --git a/src/main/stanza/symbolic-value.stanza b/src/main/stanza/symbolic-value.stanza new file mode 100644 index 00000000..d8ca2024 --- /dev/null +++ b/src/main/stanza/symbolic-value.stanza @@ -0,0 +1,71 @@ +defpackage firrtl/symbolic-value : + import core + import verse + import firrtl/ir2 + import firrtl/ir-utils + +; ======= Symbolic Value Library ========== +public definterface SymbolicValue +public defstruct SVExp <: SymbolicValue : + exp : Expression +public defstruct SVMux <: SymbolicValue : + pred : Expression + conseq : SymbolicValue + alt : SymbolicValue +public defstruct SVNul <: SymbolicValue + +defmethod print (o:OutputStream, sv:SymbolicValue) : + match(sv) : + (sv: SVExp) : print(o, exp(sv)) + (sv: SVMux) : print-all(o, ["(" pred(sv) " ? " conseq(sv) " : " alt(sv) ")"]) + (sv: SVNul) : print(o, "SVNUL") + +defn map (f: Expression -> Expression, sv:SymbolicValue) -> SymbolicValue : + match(sv) : + (sv:SVMux) : SVMux(f(pred(sv)),conseq(sv),alt(sv)) + (sv:SVExp) : SVExp(f(exp(sv))) + (sv:SVNul) : sv + +defmulti map<?T> (f: SymbolicValue -> SymbolicValue, sv:?T&SymbolicValue) -> T +defmethod map (f: SymbolicValue -> SymbolicValue, sv:SymbolicValue) -> SymbolicValue : + match(sv) : + (sv: SVMux) : SVMux(pred(sv),f(conseq(sv)),f(alt(sv))) + (sv) : sv + +defn do (f:SymbolicValue -> ?, s:SymbolicValue) -> False : + defn f* (sv:SymbolicValue) -> SymbolicValue : + f(sv) + sv + map(f*,s) + false + +defn dor (f:SymbolicValue -> ?, e:SymbolicValue) -> False : + do(f,e) + defn f* (x:SymbolicValue) -> SymbolicValue : + dor(f,x) + x + map(f*,e) + false + +defmethod equal? (a:SymbolicValue,b:SymbolicValue) -> True|False : + match(a,b) : + (a:SVNul,b:SVNul) : true + (a:SVExp,b:SVExp) : exp(a) == exp(b) + (a:SVMux,b:SVMux) : pred(a) == pred(b) and conseq(a) == conseq(b) and alt(a) == alt(b) + (a,b) : false + +;TODO add invert to primop +defn optimize (sv:SymbolicValue) -> SymbolicValue : + match(map(optimize,sv)) : + (sv:SVMux) : + if conseq(sv) == alt(sv) : conseq(sv) + else : + match(conseq(sv),alt(sv)) : + (c:SVExp,a:SVExp) : + if exp(c) == one and exp(a) == zero : SVExp(pred(sv)) + else if exp(c) == zero and exp(a) == one : SVExp(NOT(pred(sv))) + else if exp(c) == exp(a) : c + else : sv + (c,a) : sv + (sv) : sv + diff --git a/src/main/stanza/verilog.stanza b/src/main/stanza/verilog.stanza index 7f949b11..21931dd9 100644 --- a/src/main/stanza/verilog.stanza +++ b/src/main/stanza/verilog.stanza @@ -4,19 +4,9 @@ defpackage firrtl/verilog : import firrtl/ir-utils import firrtl/ir2 -;============ 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 ============= - defn width! (w:Width) -> Long : match(w) : - (w:LongWidth) : width(w) + (w:IntWidth) : width(w) (w) : error("Non-supported width type.") defn width! (t:Type) -> Long : @@ -27,7 +17,7 @@ defn width! (t:Type) -> Long : defn emit (w:Width) -> String : match(w) : - (w:LongWidth) : + (w:IntWidth) : if width(w) >= to-long(1) : string-join $ ["[" width(w) - to-long(1) ":0]"] ;TODO check if need to special case 0 or 1 width wires else : "" @@ -36,7 +26,7 @@ defn emit (w:Width) -> String : defn remove-subfield-s (s:Stmt) -> Stmt : defn remove-subfield-e (e:Expression) -> Expression : match(map(remove-subfield-e,e)) : - (e:Subfield) : + (e:SubField) : Ref(to-symbol $ string-join $ [emit(exp(e)) bundle-expand-delin name(e)],type(e)) (e) : e map{remove-subfield-e,_ } $ map(remove-subfield-s,s) @@ -45,13 +35,13 @@ defn get-width (t:Type) -> String : match(t) : (t:UIntType) : emit(width(t)) (t:SIntType) : emit(width(t)) - (t:ClockType) : emit(LongWidth(1)) + (t:ClockType) : emit(IntWidth(1)) (t) : error("Non-supported type.") defn get-name (e:Expression) -> Symbol : match(e) : (e:Ref) : name(e) - (e:Subfield) : error("Shouldn't be here") + (e:SubField) : error("Shouldn't be here") (e) : error("Shouldn't be here") defn escape (s:String) -> String : @@ -96,8 +86,8 @@ defn emit (e:Expression) -> String : val str = to-string(value(e)) val out = substring(str,1,length(str) - 1) string-join $ [width!(type(e)) "'s" out] - (e:Subfield) : error(string-join(["Non-supported expression: " to-string(e)])) - (e:Index) : error(string-join(["Non-supported expression: " to-string(e)])) + (e:SubField) : error(string-join(["Non-supported expression: " to-string(e)])) + (e:SubIndex) : error(string-join(["Non-supported expression: " to-string(e)])) (e:DoPrim) : ;val sargs = map(emit-as-type{_,type(e)},args(e)) ;val xargs = map(emit-signed-if-any{_,args(e)},args(e)) @@ -185,7 +175,7 @@ defn emit-module (m:InModule) : val simuls = HashTable<Symbol,Vector<Streamable>>(symbol-hash) defn build-table (s:Stmt) -> False : match(s) : - (s:DefWire|DefPoison|DefRegister|DefAccessor|DefMemory|DefNode|DefInstance) : + (s:DefWire|DefPoison|DefRegister|DefMemory|DefNode|DefInstance) : add(vdecs,name(s) => s) decs[name(s)] = s (s:Conditionally) : @@ -275,64 +265,63 @@ defn emit-module (m:InModule) : add(inst-ports[sym], ["." name(f) "( " n* " )"]) if flip(f) == REVERSE : add(assigns,["assign " n* " = " emit(cons[n*]) ";"]) - (s:DefAccessor) : - val mem-declaration = decs[name(source(s) as Ref)] as DefMemory - defn jkjjjjjjj - switch {_ == acc-dir(s)} : - READ : - if seq?(mem-declaration) : - val index* = Ref(firrtl-gensym(name(index(s) as Ref),sh),type(index(s))) - add(regs,[ "reg " get-width(type(index*)) " " name(index*) ";"]) ; register index for an additional cycle - - val w = width!(type(index*)) - add(inits,[name(index*) " = " rand-string(w)]) ; initialize registered index - - val my-clk-update = get?(updates,get-name(clock(mem-declaration)),Vector<Streamable>()) - add(my-clk-update,[name(index*) " <= " emit(index(s)) ";"]) ; register index - updates[get-name(clock(mem-declaration))] = my-clk-update - - ; emit read accessor - add(wires,["wire " get-width(type(source(s))) " " sym ";"]) - add(assigns,["assign " sym " = " emit(source(s)) "[" emit(index*) "];"]) - else : - ; emit read accessor - add(wires,["wire " get-width(type(source(s))) " " sym ";"]) - add(assigns,["assign " sym " = " emit(source(s)) "[" emit(index(s)) "];"]) - WRITE : - val my-clk-update = get?(updates,get-name(clock(mem-declaration)),Vector<Streamable>()) - if key?(ens,sym) : - add(my-clk-update,["if(" emit(ens[sym]) ") begin"]) - add(my-clk-update,[" " emit(source(s)) "[" emit(index(s)) "] <= " emit(cons[sym]) ";"]) - add(my-clk-update,["end"]) - else : - add(my-clk-update,[emit(source(s)) "[" emit(index(s)) "] <= " emit(cons[sym]) ";"]) - updates[get-name(clock(mem-declaration))] = my-clk-update - RDWR : - if seq?(mem-declaration) : - ; to make it sequential, register the index for an additional cycle - val index* = Ref(firrtl-gensym(name(index(s) as Ref),sh),type(index(s))) - add(regs,[ "reg " get-width(type(index*)) " " name(index*) ";"]) - val w = width!(type(index*)) - add(inits,[name(index*) " = " rand-string(w)]) - val my-clk-update = get?(updates,get-name(clock(mem-declaration)),Vector<Streamable>()) - add(my-clk-update,[name(index*) " <= " emit(index(s)) ";"]) - updates[get-name(clock(mem-declaration))] = my-clk-update - - ; emit read accessor - add(wires,["wire " get-width(type(source(s))) " " sym ";"]) - add(assigns,["assign " sym " = " emit(source(s)) "[" emit(index*) "];"]) - else : - ; emit read accessor - add(wires,["wire " get-width(type(source(s))) " " sym ";"]) - add(assigns,["assign " sym " = " emit(source(s)) "[" emit(index(s)) "];"]) - val my-clk-update = get?(updates,get-name(clock(mem-declaration)),Vector<Streamable>()) - if key?(ens,sym) : - add(my-clk-update,["if(" emit(ens[sym]) ") begin"]) - add(my-clk-update,[" " emit(source(s)) "[" emit(index(s)) "] <= " emit(cons[sym]) ";"]) - add(my-clk-update,["end"]) - else : - add(my-clk-update,[emit(source(s)) "[" emit(index(s)) "] <= " emit(cons[sym]) ";"]) - updates[get-name(clock(mem-declaration))] = my-clk-update + ;(s:DefAccessor) : + ; val mem-declaration = decs[name(source(s) as Ref)] as DefMemory + ; switch {_ == acc-dir(s)} : + ; READ : + ; if seq?(mem-declaration) : + ; val index* = Ref(firrtl-gensym(name(index(s) as Ref),sh),type(index(s))) + ; add(regs,[ "reg " get-width(type(index*)) " " name(index*) ";"]) ; register index for an additional cycle + + ; val w = width!(type(index*)) + ; add(inits,[name(index*) " = " rand-string(w)]) ; initialize registered index + + ; val my-clk-update = get?(updates,get-name(clock(mem-declaration)),Vector<Streamable>()) + ; add(my-clk-update,[name(index*) " <= " emit(index(s)) ";"]) ; register index + ; updates[get-name(clock(mem-declaration))] = my-clk-update + + ; ; emit read accessor + ; add(wires,["wire " get-width(type(source(s))) " " sym ";"]) + ; add(assigns,["assign " sym " = " emit(source(s)) "[" emit(index*) "];"]) + ; else : + ; ; emit read accessor + ; add(wires,["wire " get-width(type(source(s))) " " sym ";"]) + ; add(assigns,["assign " sym " = " emit(source(s)) "[" emit(index(s)) "];"]) + ; WRITE : + ; val my-clk-update = get?(updates,get-name(clock(mem-declaration)),Vector<Streamable>()) + ; if key?(ens,sym) : + ; add(my-clk-update,["if(" emit(ens[sym]) ") begin"]) + ; add(my-clk-update,[" " emit(source(s)) "[" emit(index(s)) "] <= " emit(cons[sym]) ";"]) + ; add(my-clk-update,["end"]) + ; else : + ; add(my-clk-update,[emit(source(s)) "[" emit(index(s)) "] <= " emit(cons[sym]) ";"]) + ; updates[get-name(clock(mem-declaration))] = my-clk-update + ; RDWR : + ; if seq?(mem-declaration) : + ; ; to make it sequential, register the index for an additional cycle + ; val index* = Ref(firrtl-gensym(name(index(s) as Ref),sh),type(index(s))) + ; add(regs,[ "reg " get-width(type(index*)) " " name(index*) ";"]) + ; val w = width!(type(index*)) + ; add(inits,[name(index*) " = " rand-string(w)]) + ; val my-clk-update = get?(updates,get-name(clock(mem-declaration)),Vector<Streamable>()) + ; add(my-clk-update,[name(index*) " <= " emit(index(s)) ";"]) + ; updates[get-name(clock(mem-declaration))] = my-clk-update + + ; ; emit read accessor + ; add(wires,["wire " get-width(type(source(s))) " " sym ";"]) + ; add(assigns,["assign " sym " = " emit(source(s)) "[" emit(index*) "];"]) + ; else : + ; ; emit read accessor + ; add(wires,["wire " get-width(type(source(s))) " " sym ";"]) + ; add(assigns,["assign " sym " = " emit(source(s)) "[" emit(index(s)) "];"]) + ; val my-clk-update = get?(updates,get-name(clock(mem-declaration)),Vector<Streamable>()) + ; if key?(ens,sym) : + ; add(my-clk-update,["if(" emit(ens[sym]) ") begin"]) + ; add(my-clk-update,[" " emit(source(s)) "[" emit(index(s)) "] <= " emit(cons[sym]) ";"]) + ; add(my-clk-update,["end"]) + ; else : + ; add(my-clk-update,[emit(source(s)) "[" emit(index(s)) "] <= " emit(cons[sym]) ";"]) + ; updates[get-name(clock(mem-declaration))] = my-clk-update ;==== Actually printing module ===== val port-indent = " " |
