defpackage firrtl/passes : import core import verse import firrtl/ir2 import firrtl/ir-utils import firrtl/primops import firrtl-main import firrtl/errors import bigint2 ;============== Pass List ================ public val standard-passes = to-list $ [ CheckHighForm() ;TempElimination() ToWorkingIR() Resolve() ResolveKinds() ;CheckKinds() InferTypes() ;CheckTypes() ResolveGenders() ;CheckGenders() ;ExpandAccessors() ;LowerToGround() ;ExpandIndexedConnects() ;InlineIndexed() ExpandWhens() InferWidths() ;Inline() SplitExp() ;CheckLowForm() ;ToRealIR() ;Pad() ] ;=============== WORKING IR ================================ public definterface Kind public defstruct WireKind <: Kind public defstruct PoisonKind <: Kind public defstruct RegKind <: Kind public defstruct InstanceKind <: Kind public defstruct PortKind <: Kind public defstruct NodeKind <: Kind public defstruct MemKind <: Kind : ports : List public defstruct ExpKind <: Kind public definterface Gender public val MALE = new Gender public val FEMALE = new Gender public val UNKNOWN-GENDER = new Gender public val BI-GENDER = new Gender public defstruct WRef <: Expression : name: Symbol type: Type with: (as-method => true) kind: Kind with: (as-method => true) gender: Gender with: (as-method => true) public defstruct WSubField <: Expression : exp: Expression name: Symbol type: Type with: (as-method => true) gender: Gender with: (as-method => true) public defstruct WSubIndex <: Expression : exp: Expression value: Int type: Type with: (as-method => true) gender: Gender with: (as-method => true) public defstruct WSubAccess <: Expression : exp: Expression index: Expression type: Type with: (as-method => true) gender: Gender with: (as-method => true) defstruct WIndexer <: Expression : exps: List index: Expression type: Type with: (as-method => true) gender : Gender with: (as-method => true) public defstruct WVoid <: Expression public defstruct WInvalid <: Expression public defstruct WDefInstance <: Stmt : info: FileInfo with: (as-method => true) name: Symbol module: Symbol type: Type defmulti gender (e:Expression) -> Gender defmethod gender (e:Expression) : MALE defn get-gender (s:Stmt|Port) -> Gender : match(s) : (s:DefWire|DefRegister) : BI-GENDER (s:WDefInstance|DefNode|DefInstance|DefPoison) : MALE (s:Begin|Connect|BulkConnect|Stop|Print|Empty|IsInvalid) : UNKNOWN-GENDER (s:DefMemory) : MALE (p:Port) : switch { _ == direction(p) } : INPUT : MALE OUTPUT : FEMALE public defmulti kind (e:Expression) -> Kind defmethod kind (e:Expression) : match(e) : (e:WRef) : kind(e) (e:WSubField) : kind(exp(e)) (e:WSubIndex) : kind(exp(e)) (e:WIndexer) : val k = kind(exps(e)[0]) for x in exps(e) do : if k != kind(x) : error("All kinds of exps of WIndexer must be the same") k (e) : ExpKind() defmethod info (stmt:Begin) -> FileInfo : FileInfo() defmethod info (stmt:Empty) -> FileInfo : FileInfo() defmethod type (exp:UIntValue) -> Type : UIntType(width(exp)) defmethod type (exp:SIntValue) -> Type : SIntType(width(exp)) defmethod type (exp:WVoid) -> Type : UnknownType() defmethod type (exp:WInvalid) -> Type : UnknownType() defmethod get-type (s:WDefInstance) -> Type : type(s) 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:WInvalid,e2:WInvalid) : 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:Mux,e2:Mux) : (cond(e1) == cond(e2)) and (tval(e1) == tval(e2)) and (fval(e1) == fval(e2)) (e1:ValidIf,e2:ValidIf) : (cond(e1) == cond(e2)) and (value(e1) == value(e2)) (e1,e2) : false ; ================= PRINTERS =================== defmethod print (o:OutputStream, g:Gender) : print{o, _} $ switch {g == _} : MALE : "m" FEMALE: "f" BI-GENDER : "b" UNKNOWN-GENDER: "u" ;============== DEBUG STUFF ============================= public var PRINT-TYPES : True|False = false public var PRINT-KINDS : True|False = false public var PRINT-WIDTHS : True|False = false public var PRINT-TWIDTHS : True|False = false public var PRINT-GENDERS : True|False = false public var PRINT-CIRCUITS : True|False = false public var PRINT-DEBUG : True|False = false public var PRINT-INFO : True|False = false ;========= TO TURN OFF =========== var old-PRINT-TYPES : True|False = false var old-PRINT-KINDS : True|False = false var old-PRINT-WIDTHS : True|False = false var old-PRINT-TWIDTHS : True|False = false var old-PRINT-GENDERS : True|False = false var old-PRINT-CIRCUITS : True|False = false var old-PRINT-DEBUG : True|False = false var old-PRINT-INFO : True|False = false defmethod turn-off-debug (x:False) : old-PRINT-TYPES = PRINT-TYPES old-PRINT-KINDS = PRINT-KINDS old-PRINT-WIDTHS = PRINT-WIDTHS old-PRINT-TWIDTHS = PRINT-TWIDTHS old-PRINT-GENDERS = PRINT-GENDERS old-PRINT-CIRCUITS = PRINT-CIRCUITS old-PRINT-DEBUG = PRINT-DEBUG old-PRINT-INFO = PRINT-INFO PRINT-TYPES = false PRINT-KINDS = false PRINT-WIDTHS = false PRINT-TWIDTHS = false PRINT-GENDERS = false PRINT-CIRCUITS = false PRINT-DEBUG = false PRINT-INFO = false defmethod turn-on-debug (x:False) : PRINT-TYPES = old-PRINT-TYPES PRINT-KINDS = old-PRINT-KINDS PRINT-WIDTHS = old-PRINT-WIDTHS PRINT-TWIDTHS = old-PRINT-TWIDTHS PRINT-GENDERS = old-PRINT-GENDERS PRINT-CIRCUITS = old-PRINT-CIRCUITS PRINT-DEBUG = old-PRINT-DEBUG PRINT-INFO = old-PRINT-INFO ;=== ThePrinters === public defn println-all-debug (l:?) -> False : if PRINT-DEBUG : println-all(l) else : false public defn println-debug (s:?) -> False : if PRINT-DEBUG : println(s) else : false defmethod print (o:OutputStream, k:Kind) : print{o, _} $ match(k) : (k:WireKind) : "wire" (k:PoisonKind) : "poison" (k:RegKind) : "reg" (k:PortKind) : "port" (k:MemKind) : "mem" (k:NodeKind) : "node" (k:InstanceKind) : "inst" (k:ExpKind) : "exp" defn hasGender (e:?) : e typeof Expression defn hasWidth (e:?) : e typeof UIntType|SIntType|UIntValue|SIntValue defn hasType (e:?) : e typeof Expression|DefWire|DefRegister|DefPoison |VectorType|Port|UIntValue|SIntValue defn hasKind (e:?) : e typeof Expression defn hasInfo (e:?) : e typeof Stmt|Port|Circuit|Module defn any-debug? (e:?) : (hasGender(e) and PRINT-GENDERS) or (hasType(e) and PRINT-TYPES) or (hasWidth(e) and PRINT-WIDTHS) or (hasKind(e) and PRINT-KINDS) or (hasInfo(e) and PRINT-INFO) defmethod print-debug (o:OutputStream, e:Expression|Stmt|Type|Port|Field|Module|Circuit) : defn wipe-width (t:Type) -> Type : match(t) : (t:UIntType) : UIntType(UnknownWidth()) (t:SIntType) : SIntType(UnknownWidth()) (t) : map(wipe-width,t) if any-debug?(e) : print(o,"@") if PRINT-KINDS and hasKind(e) : print-all(o,[""]) if PRINT-TYPES and hasType(e) : print-all(o,[""]) if PRINT-TWIDTHS and hasType(e): print-all(o,[""]) if PRINT-WIDTHS and hasWidth(e): print-all(o,[""]) if PRINT-GENDERS and hasGender(e): print-all(o,[""]) if PRINT-INFO and hasInfo(e): print-all(o,[""]) defmethod print (o:OutputStream, e:WRef) : print(o,name(e)) print-debug(o,e as ?) defmethod print (o:OutputStream, e:WSubField) : print-all(o,[exp(e) "." name(e)]) print-debug(o,e as ?) defmethod print (o:OutputStream, e:WSubIndex) : print-all(o,[exp(e) "[" value(e) "]"]) print-debug(o,e as ?) defmethod print (o:OutputStream, e:WSubAccess) : print-all(o,[exp(e) "[" index(e) "]"]) print-debug(o,e as ?) defmethod print (o:OutputStream, e:WVoid) : print(o,"VOID") print-debug(o,e as ?) defmethod print (o:OutputStream, e:WInvalid) : print(o,"INVALID") print-debug(o,e as ?) defmethod print (o:OutputStream, c:WIndexer) : print-all(o, [exps(c) "[" index(c) "]"]) print-debug(o,c as ?) defmethod print (o:OutputStream, c:WDefInstance) : print-all(o, ["inst " name(c) " of " module(c) " : " type(c)]) print-debug(o,c as ?) defmethod map (f: Expression -> Expression, e: WSubField) : WSubField(f(exp(e)), name(e), type(e), gender(e)) defmethod map (f: Expression -> Expression, e: WSubIndex) : WSubIndex(f(exp(e)), value(e), type(e), gender(e)) defmethod map (f: Expression -> Expression, e: WSubAccess) : WSubAccess(f(exp(e)), f(index(e)), type(e), gender(e)) defmethod map (f: Type -> Type, e: WRef) : WRef(name(e), f(type(e)), kind(e), gender(e)) defmethod map (f: Type -> Type, e: WSubField) : WSubField(exp(e), name(e), f(type(e)), gender(e)) defmethod map (f: Type -> Type, e: WSubIndex) : WSubIndex(exp(e), value(e), f(type(e)), gender(e)) defmethod map (f: Type -> Type, e: WSubAccess) : WSubAccess(exp(e), index(e), f(type(e)), gender(e)) defmethod map (f: Type -> Type, s: WDefInstance) : WDefInstance(info(s),name(s),module(s),f(type(s))) ;================ WIDTH LIBRARY ==================== public val ONE = IntWidth(1) public defstruct VarWidth <: Width : name: Symbol public defstruct PlusWidth <: Width : arg1 : Width arg2 : Width public defstruct MinusWidth <: Width : arg1 : Width arg2 : Width public defstruct MaxWidth <: Width : args : List public defstruct ExpWidth <: Width : arg1 : Width val width-name-hash = HashTable(symbol-hash) public defmulti map (f: Width -> Width, w:?T&Width) -> T defmethod map (f: Width -> Width, w:Width) -> Width : match(w) : (w:MaxWidth) : MaxWidth(map(f,args(w))) (w:PlusWidth) : PlusWidth(f(arg1(w)),f(arg2(w))) (w:MinusWidth) : MinusWidth(f(arg1(w)),f(arg2(w))) (w:ExpWidth) : ExpWidth(f(arg1(w))) (w) : w public defmethod print (o:OutputStream, w:VarWidth) : print(o,name(w)) public defmethod print (o:OutputStream, w:MaxWidth) : print-all(o,["max" args(w)]) public defmethod print (o:OutputStream, w:PlusWidth) : print-all(o,[ "(" arg1(w) " + " arg2(w) ")"]) public defmethod print (o:OutputStream, w:MinusWidth) : print-all(o,[ "(" arg1(w) " - " arg2(w) ")"]) public defmethod print (o:OutputStream, w:ExpWidth) : print-all(o,[ "exp(" arg1(w) ")"]) defn remove-unknowns-w (w:Width) -> Width : match(w) : (w:UnknownWidth) : VarWidth(firrtl-gensym(`w,width-name-hash)) (w) : w defn remove-unknowns (t:Type) -> Type : mapr(remove-unknowns-w,t) defmethod equal? (w1:Width,w2:Width) -> True|False : match(w1,w2) : (w1:VarWidth,w2:VarWidth) : name(w1) == name(w2) (w1:MaxWidth,w2:MaxWidth) : label 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 (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) defn to-field (p:Port) -> Field : if direction(p) == OUTPUT : Field(name(p),DEFAULT,type(p)) else if direction(p) == INPUT : Field(name(p),REVERSE,type(p)) else : error("Shouldn't be here") defn to-dir (g:Gender) -> Direction : switch {_ == g} : MALE : INPUT FEMALE : OUTPUT defn to-gender (d:Direction) -> Gender : switch {_ == d} : INPUT: MALE OUTPUT: FEMALE public defn mux-type-and-widths (e1:Expression,e2:Expression) -> Type : mux-type-and-widths(type(e1),type(e2)) public defn mux-type-and-widths (t1:Type,t2:Type) -> Type : defn wmax (w1:Width,w2:Width) -> Width : match(w1,w2) : (w1:IntWidth,w2:IntWidth) : IntWidth(max(width(w1),width(w2))) (w1,w2) : MaxWidth(list(w1,w2)) if t1 == t2 : match(t1,t2) : (t1:UIntType,t2:UIntType) : UIntType(wmax(width(t1),width(t2))) (t1:SIntType,t2:SIntType) : SIntType(wmax(width(t1),width(t2))) (t1:VectorType,t2:VectorType) : VectorType(mux-type-and-widths(type(t1),type(t2)),size(t1)) (t1:BundleType,t2:BundleType) : BundleType $ for (f1 in fields(t1),f2 in fields(t2)) map : Field(name(f1),flip(f1),mux-type-and-widths(type(f1),type(f2))) else : UnknownType() ;================= 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() ; for c in to-string(n) do : ; add(v,get-new-string(c)) ; val n* = symbol-join(v) ; if key?(v-keywords,n*) : ; symbol-join([n* `_]) ; else : ; n* ; defn rename-t (t:Type) -> Type : ; match(t) : ; (t:BundleType) : BundleType $ ; for f in fields(t) map : ; Field(rename(name(f)),flip(f),rename-t(type(f))) ; (t:VectorType) : VectorType(rename-t(type(t)),size(t)) ; (t) : t ; defn rename-e (e:Expression) -> Expression : ; match(e) : ; (e:Ref) : Ref(rename(name(e)),rename-t(type(e))) ; (e:Subfield) : Subfield(rename-e(exp(e)),rename(name(e)),rename-t(type(e))) ; (e:Index) : Index(rename-e(exp(e)),value(e),rename-t(type(e))) ; (e:DoPrim) : DoPrim{op(e),_,consts(e),rename-t(type(e))} $ for x in args(e) map : rename-e(x) ; (e:UIntValue) : e ; (e:SIntValue) : e ; defn rename-s (s:Stmt) -> Stmt : ; match(s) : ; (s:DefWire) : DefWire(info(s),rename(name(s)),rename-t(type(s))) ; (s:DefPoison) : DefPoison(info(s),rename(name(s)),rename-t(type(s))) ; (s:DefRegister) : DefRegister(info(s),rename(name(s)),rename-t(type(s)),rename-e(clock(s)),rename-e(reset(s))) ; (s:WDefInstance) : WDefInstance(info(s),rename(name(s)),rename-e(module(s))) ; (s:DefMemory) : DefMemory(info(s),rename(name(s)),rename-t(type(s)),seq?(s),rename-e(clock(s)),size(s)) ; (s:DefNode) : DefNode(info(s),rename(name(s)),rename-e(value(s))) ; (s:DefAccessor) : DefAccessor(info(s),rename(name(s)),rename-e(source(s)),rename-e(index(s)),acc-dir(s)) ; (s:Conditionally) : Conditionally(info(s),rename-e(pred(s)),rename-s(conseq(s)),rename-s(alt(s))) ; (s:Begin) : Begin $ for b in body(s) map : rename-s(b) ; (s:OnReset) : OnReset(info(s),rename-e(loc(s)),rename-e(exp(s))) ; (s:BulkConnect) : BulkConnect(info(s),rename-e(loc(s)),rename-e(exp(s))) ; (s:Connect) : Connect(info(s),rename-e(loc(s)),rename-e(exp(s))) ; (s:EmptyStmt) : s ; (s:StopStmt) : s ; (s:PrintfStmt) : PrintfStmt(info(s),string(s),map(rename-e,args(s))) ; ; Circuit(info(c),modules*, rename(main(c))) where : ; val modules* = ; for m in modules(c) map : ; match(m) : ; (m:InModule) : ; val ports* = for p in ports(m) map : ; Port(info(p),rename(name(p)),direction(p),rename-t(type(p))) ; InModule(info(m),rename(name(m)), ports*, rename-s(body(m))) ; (m:ExModule) : m ;================= Temporary Variable Elimination ======================== ; Returns a new Circuit where temporary variables are removed and returns ; the resulting nested expression ;public defstruct TempElimination <: Pass ;public defmethod pass (b:TempElimination) -> (Circuit -> Circuit) : temp-elimination ;public defmethod name (b:TempElimination) -> String : "Temp Elimination" ;public defmethod short-name (b:TempElimination) -> String : "temp-elim" ; ;defn temp-elimination (c:Circuit) : ; defn is-temp? (n:Symbol) -> True|False : ; to-string(n)[0] == 'T' ; defn temp-elim (m:InModule) : ; val h = HashTable(symbol-hash) ; defn temp-elim-e (e:Expression) : ; match(map(temp-elim-e,e)) : ; (e:Ref) : ; if key?(h,name(e)) : h[name(e)] ; else : e ; (e) : e ; defn temp-elim-s (s:Stmt) : ; match(map(temp-elim-e,s)) : ; (s:DefNode) : ; if is-temp?(name(s)) : ; h[name(s)] = value(s) ; EmptyStmt() ; else : s ; (s) : map(temp-elim-s,s) ; InModule(info(m),name(m), ports(m), temp-elim-s(body(m))) ; ; Circuit(info(c),modules*, main(c)) where : ; val modules* = ; for m in modules(c) map : ; match(m) : ; (m:InModule) : temp-elim(m) ; (m:ExModule) : m ;================= Bring to Working IR ======================== ; Returns a new Circuit with Refs, Subfields, Indexes and DefAccessors ; replaced with IR-internal nodes that contain additional ; information (kind, gender) public defstruct ToWorkingIR <: Pass public defmethod pass (b:ToWorkingIR) -> (Circuit -> Circuit) : to-working-ir public defmethod name (b:ToWorkingIR) -> String : "Working IR" public defmethod short-name (b:ToWorkingIR) -> String : "to-working-ir" defn to-working-ir (c:Circuit) : defn to-exp (e:Expression) -> Expression : match(map(to-exp,e)) : (e:Ref) : WRef(name(e), type(e), NodeKind(), UNKNOWN-GENDER) (e:SubField) : WSubField(exp(e), name(e), type(e), UNKNOWN-GENDER) (e:SubIndex) : WSubIndex(exp(e), value(e), type(e), UNKNOWN-GENDER) (e:SubAccess) : WSubAccess(exp(e), index(e), type(e), UNKNOWN-GENDER) (e) : e defn to-stmt (s:Stmt) -> Stmt : match(map(to-exp,s)) : (s:DefInstance) : WDefInstance(info(s),name(s),module(s),UnknownType()) (s) : map(to-stmt,s) Circuit(info(c),modules*, main(c)) where : val modules* = for m in modules(c) map : match(m) : (m:InModule) : InModule(info(m),name(m), ports(m), to-stmt(body(m))) (m:ExModule) : m ;=============== Resolve Kinds ============================= ; It is useful for the compiler to know information about ; objects referenced. This information is stored in the kind ; field in WRef. This pass walks the graph and returns a new ; Circuit where all WRef kinds are resolved public defstruct ResolveKinds <: Pass public defmethod pass (b:ResolveKinds) -> (Circuit -> Circuit) : resolve-kinds public defmethod name (b:ResolveKinds) -> String : "Resolve Kinds" public defmethod short-name (b:ResolveKinds) -> String : "resolve-kinds" defn resolve-kinds (c:Circuit) : defn resolve (body:Stmt, kinds:HashTable) : defn resolve-stmt (s:Stmt) -> Stmt : map{resolve-expr,_} $ map(resolve-stmt,s) defn resolve-expr (e:Expression) -> Expression : match(e) : (e:WRef) : WRef(name(e),type(e),kinds[name(e)],gender(e)) (e) : map(resolve-expr,e) resolve-stmt(body) defn find (m:Module, kinds:HashTable) : defn find-stmt (s:Stmt) -> Stmt : match(s) : (s:DefWire) : kinds[name(s)] = WireKind() (s:DefPoison) : kinds[name(s)] = PoisonKind() (s:DefNode) : kinds[name(s)] = NodeKind() (s:DefRegister) : kinds[name(s)] = RegKind() (s:WDefInstance) : kinds[name(s)] = InstanceKind() (s:DefMemory) : kinds[name(s)] = MemKind(append-all([readers(s) writers(s) readwriters(s)])) (s) : false map(find-stmt,s) for p in ports(m) do : kinds[name(p)] = PortKind() match(m) : (m:InModule) : find-stmt(body(m)) (m:ExModule) : false defn resolve-kinds (m:Module, c:Circuit) -> Module : val kinds = HashTable(symbol-hash) find(m,kinds) match(m) : (m:InModule) : val body! = resolve(body(m),kinds) InModule(info(m),name(m),ports(m),body!) (m:ExModule) : ExModule(info(m),name(m),ports(m)) Circuit(info(c),modules*, main(c)) where : val modules* = for m in modules(c) map : resolve-kinds(m,c) ;============== INFER TYPES ================================ ; ------------------ Utils ------------------------- defn set-type (s:Stmt,t:Type) -> Stmt : match(s) : (s:DefWire) : DefWire(info(s),name(s),t) (s:DefRegister) : DefRegister(info(s),name(s),t,clock(s),reset(s),init(s)) (s:DefMemory) : DefMemory(info(s),name(s),t,depth(s),write-latency(s),read-latency(s),readers(s),writers(s),readwriters(s)) (s:DefNode) : s (s:DefPoison) : DefPoison(info(s),name(s),t) ; ------------------ Pass ------------------------- public defstruct InferTypes <: Pass public defmethod pass (b:InferTypes) -> (Circuit -> Circuit) : infer-types public defmethod name (b:InferTypes) -> String : "Infer Types" public defmethod short-name (b:InferTypes) -> String : "infer-types" defn infer-types (c:Circuit) -> Circuit : val module-types = HashTable(symbol-hash) defn infer-types (m:Module) -> Module : val types = HashTable(symbol-hash) defn infer-types-e (e:Expression) -> Expression : match(map(infer-types-e,e)) : (e:ValidIf) : ValidIf(cond(e),value(e),type(value(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:Mux) : Mux(cond(e),tval(e),fval(e),mux-type-and-widths(tval(e),fval(e))) (e:UIntValue|SIntValue) : e defn infer-types-s (s:Stmt) -> Stmt : match(s) : (s:DefRegister) : val t = remove-unknowns(get-type(s)) types[name(s)] = t map(infer-types-e,set-type(s,t)) (s:DefWire|DefPoison|DefNode) : val s* = map(infer-types-e,s) val t = remove-unknowns(get-type(s*)) types[name(s*)] = t set-type(s*,t) (s:DefMemory) : val t = remove-unknowns(get-type(s)) types[name(s)] = t val dt = remove-unknowns(data-type(s)) set-type(s,dt) (s:WDefInstance) : types[name(s)] = module-types[module(s)] WDefInstance(info(s),name(s),module(s),module-types[module(s)]) (s) : map{infer-types-e,_} $ map(infer-types-s,s) for p in ports(m) do : types[name(p)] = type(p) match(m) : (m:InModule) : InModule(info(m),name(m),ports(m),infer-types-s(body(m))) (m:ExModule) : m ; MAIN val modules* = for m in modules(c) map : val ports* = for p in ports(m) map : Port(info(p),name(p),direction(p),remove-unknowns(type(p))) match(m) : (m:InModule) : InModule(info(m),name(m),ports*,body(m)) (m:ExModule) : ExModule(info(m),name(m),ports*) for m in modules* do : module-types[name(m)] = module-type(m) Circuit{info(c), _, main(c) } $ for m in modules* map : infer-types(m) ;============= RESOLVE GENDER ============================ ; To ensure a proper circuit, we must ensure that assignments ; only work on expressions that can be assigned to. Similarly, ; we must ensure that only expressions that can be read from ; are used to assign from. This invariant requires each ; expression's gender to be inferred. ; Various elements can be bi-gender (e.g. wires) and can ; thus be treated as either female or male. Conversely, some ; elements are single-gender (e.g. accessors, ports). public defstruct ResolveGenders <: Pass public defmethod pass (b:ResolveGenders) -> (Circuit -> Circuit) : resolve-genders public defmethod name (b:ResolveGenders) -> String : "Resolve Genders" public defmethod short-name (b:ResolveGenders) -> String : "resolve-genders" defn resolve-genders (c:Circuit) : defn resolve-e (e:Expression,g:Gender) -> Expression : match(e) : (e:WRef) : WRef(name(e),type(e),kind(e),g) (e:WSubField) : val exp* = switch { _ == field-flip(type(exp(e)),name(e)) } : DEFAULT : resolve-e(exp(e),g) REVERSE : resolve-e(exp(e),swap(g)) WSubField(exp*,name(e),type(e),g) (e:WSubIndex) : val exp* = resolve-e(exp(e),g) WSubIndex(exp*,value(e),type(e),g) (e:WSubAccess) : val exp* = resolve-e(exp(e),g) val index* = resolve-e(index(e),MALE) WSubAccess(exp*,index*,type(e),g) (e:WIndexer) : val exps* = map(resolve-e{_,g},exps(e)) val index* = resolve-e(index(e),MALE) WIndexer(exps*,index*,type(e),g) (e) : map(resolve-e{_,g},e) defn resolve-s (s:Stmt) -> Stmt : match(s) : (s:IsInvalid) : val exp* = resolve-e(exp(s),FEMALE) IsInvalid(info(s),exp*) (s:Connect) : val loc* = resolve-e(loc(s),FEMALE) val exp* = resolve-e(exp(s),MALE) Connect(info(s),loc*,exp*) (s:BulkConnect) : val loc* = resolve-e(loc(s),FEMALE) val exp* = resolve-e(exp(s),MALE) BulkConnect(info(s),loc*,exp*) (s) : map{resolve-s,_} $ map(resolve-e{_,MALE},s) Circuit(info(c),modules*, main(c)) where : val modules* = for m in modules(c) map : match(m) : (m:InModule) : val body* = resolve-s(body(m)) InModule(info(m),name(m),ports(m),body*) (m:ExModule) : m ;============= Pull Muxes =============== public defstruct PullMuxes <: Pass public defmethod pass (b:PullMuxes) -> (Circuit -> Circuit) : pull-muxes public defmethod name (b:PullMuxes) -> String : "Pull Muxes" public defmethod short-name (b:PullMuxes) -> String : "pull-muxes" defn pull-muxes (c:Circuit) -> Circuit : defn pull-muxes-e (e:Expression) -> Expression : map{pull-muxes-e,_} $ match(map(pull-muxes-e,e)) : (e:WRef) : e (e:WSubField) : match(exp(e)) : (e*:Mux) : Mux(cond(e*),WSubField(tval(e*),name(e),type(e),gender(e)),WSubField(fval(e*),name(e),type(e),gender(e)),type(e)) (e*:ValidIf) : ValidIf(cond(e*),WSubField(value(e*),name(e),type(e),gender(e)),type(e)) (e*) : e (e:WSubIndex) : match(exp(e)) : (e*:Mux) : Mux(cond(e*),WSubIndex(tval(e*),value(e),type(e),gender(e)),WSubIndex(fval(e*),value(e),type(e),gender(e)),type(e)) (e*:ValidIf) : ValidIf(cond(e*),WSubIndex(value(e*),value(e),type(e),gender(e)),type(e)) (e*) : e (e:WSubAccess) : match(exp(e)) : (e*:Mux) : Mux(cond(e*),WSubAccess(tval(e*),index(e),type(e),gender(e)),WSubAccess(fval(e*),index(e),type(e),gender(e)),type(e)) (e*:ValidIf) : ValidIf(cond(e*),WSubAccess(value(e*),index(e),type(e),gender(e)),type(e)) (e*) : e (e:Mux) : e (e:ValidIf) : e (e) : e defn pull-muxes (s:Stmt) -> Stmt : map(pull-muxes-e,map(pull-muxes,s)) Circuit{info(c),_,main(c)} $ for m in modules(c) map : match(m) : (m:InModule) : InModule(info(m),name(m),ports(m),pull-muxes(body(m))) (m:ExModule) : m ;================ 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-flip (t:Type, i:Int, f:Flip) -> Flip : if i >= get-size(t) : error("Shouldn't be here") val x = match(t) : (t:UIntType|SIntType|ClockType) : f (t:BundleType) : label 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 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") x defn get-point (e:Expression) -> Int : match(e) : (e:WRef) : 0 (e:WSubField) : var i = 0 for f in fields(type(exp(e)) as BundleType) find : val b = name(f) == name(e) if not b : i = i + get-size(type(f)) b i (e:WSubIndex) : value(e) * get-size(e) (e:WSubAccess) : get-point(exp(e)) defn create-exps (n:Symbol, t:Type) -> List : create-exps(WRef(n,t,ExpKind(),UNKNOWN-GENDER)) defn create-exps (e:Expression) -> List : match(e) : (e:Mux) : for (e1 in create-exps(tval(e)), e2 in create-exps(fval(e))) map : Mux(cond(e),e1,e2,mux-type-and-widths(e1,e2)) (e:ValidIf) : for e1 in create-exps(value(e)) map : ValidIf(cond(e),e1,type(e1)) (e) : match(type(e)) : (t:UIntType|SIntType|ClockType) : list(e) (t:BundleType) : for f in fields(t) map-append : create-exps(WSubField(e,name(f),type(f),gender(e) * flip(f))) (t:VectorType) : for i in 0 to size(t) map-append : create-exps(WSubIndex(e,i,type(t),gender(e))) defn gexp-hash (e:Expression) -> Int : turn-off-debug(false) val ls = to-list([mname `.... e `.... gender(e) `.... type(e)]) ;val ls = to-list([e `.... gender(e) `.... type(e)]) val i = symbol-hash(symbol-join(ls)) ;val i = symbol-hash(to-symbol(to-string(e))) turn-on-debug(false) i val hashed-create-exps = HashTable>(gexp-hash) defn fast-create-exps (n:Symbol, t:Type) -> List : fast-create-exps(WRef(n,t,ExpKind(),UNKNOWN-GENDER)) defn fast-create-exps (e:Expression) -> List : if key?(hashed-create-exps,e) : hashed-create-exps[e] else : match(e) : (e:Mux) : val x = for (e1 in create-exps(tval(e)), e2 in create-exps(fval(e))) map : Mux(cond(e),e1,e2,mux-type-and-widths(e1,e2)) hashed-create-exps[e] = x x (e:ValidIf) : val x = for e1 in create-exps(value(e)) map : ValidIf(cond(e),e1,type(e1)) hashed-create-exps[e] = x x (e) : val es = Vector>() match(type(e)) : (t:UIntType|SIntType|ClockType) : add(es,list(e)) (t:BundleType) : for f in fields(t) do : add(es,fast-create-exps(WSubField(e,name(f),type(f),gender(e) * flip(f)))) (t:VectorType) : for i in 0 to size(t) do : add(es,fast-create-exps(WSubIndex(e,i,type(t),gender(e)))) val x = append-all(es) hashed-create-exps[e] = x x ;---------------- Pass --------------------- defn expand-connects (c:Circuit) -> Circuit : defn expand-connects (m:InModule) -> InModule : mname = name(m) val genders = HashTable(symbol-hash) defn expand-s (s:Stmt) -> Stmt : defn set-gender (e:Expression) -> Expression : match(map(set-gender,e)) : (e:WRef) : WRef(name(e),type(e),kind(e),genders[name(e)]) (e:WSubField) : val f = {_ as Field} $ for f in fields(type(exp(e)) as BundleType) find : name(f) == name(e) val gender* = gender(exp(e)) * flip(f) WSubField(exp(e),name(e),type(e),gender*) (e:WSubIndex) : WSubIndex(exp(e),value(e),type(e),gender(exp(e))) (e:WSubAccess) : WSubAccess(exp(e),index(e),type(e),gender(exp(e))) (e) : e match(s) : (s:DefWire|DefRegister) : genders[name(s)] = BI-GENDER s (s:WDefInstance|DefMemory|DefPoison|DefNode) : genders[name(s)] = MALE s (s:IsInvalid) : val n = get-size(exp(s)) val invalids = Vector() val exps = create-exps(exp(s)) for i in 0 to n do : val exp* = exps[i] val gexp* = set-gender(exp*) switch { _ == gender(gexp*) } : BI-GENDER : add(invalids,IsInvalid(info(s),exp*)) FEMALE : add(invalids,IsInvalid(info(s),exp*)) else : false if length(invalids) == 0 : Empty() else if length(invalids) == 1 : invalids[0] else : Begin(to-list(invalids)) (s:Connect) : val n = get-size(loc(s)) val connects = Vector() val locs = create-exps(loc(s)) val exps = create-exps(exp(s)) for i in 0 to n do : val loc* = locs[i] val exp* = exps[i] add{connects,_} $ switch { _ == get-flip(type(loc(s)),i,DEFAULT) } : DEFAULT : Connect(info(s),loc*,exp*) REVERSE : Connect(info(s),exp*,loc*) Begin(to-list(connects)) (s:BulkConnect) : val ls = get-valid-points(type(loc(s)),type(exp(s)),DEFAULT,DEFAULT) val connects = Vector() val locs = create-exps(loc(s)) val exps = create-exps(exp(s)) for x in ls do : val loc* = locs[x[0]] val exp* = exps[x[1]] add{connects,_} $ switch { _ == get-flip(type(loc(s)),x[0],DEFAULT) } : DEFAULT : Connect(info(s),loc*,exp*) REVERSE : Connect(info(s),exp*,loc*) Begin(to-list(connects)) (s) : map(expand-s,s) for p in ports(m) do : genders[name(p)] = to-gender(direction(p)) InModule(info(m),name(m),ports(m),expand-s(body(m))) Circuit(info(c),modules*, main(c)) where : val modules* = for m in modules(c) map : match(m) : (m:ExModule) : m (m:InModule) : expand-connects(m) ;;;================ REPLACE INDEXERS ========================= ; This pass inlines all accessors to non-memory vector typed ; components. public defstruct RemoveAccesses <: Pass public defmethod pass (b:RemoveAccesses) -> (Circuit -> Circuit) : remove-access public defmethod name (b:RemoveAccesses) -> String : "Remove Accesses" public defmethod short-name (b:RemoveAccesses) -> String : "remove-access" defstruct Location : base : Expression guard : Expression defmethod print (o:OutputStream,x:Location) : print-all(o,["[" base(x) " , " guard(x) "]"]) defn get-locations (e:Expression) -> List : match(e) : (e:WRef) : map(Location{_,one},create-exps(e)) (e:WSubIndex|WSubField) : val ls = get-locations(exp(e)) val start = get-point(e) val end = start + get-size(e) val stride = get-size(exp(e)) val ls* = Vector() var c = 0 for i in 0 to length(ls) do : if (i % stride >= start and i % stride < end) : add(ls*,ls[i]) to-list(ls*) (e:WSubAccess) : val ls = get-locations(exp(e)) val stride = get-size(e) val wrap = size(type(exp(e)) as VectorType) val ls* = Vector() var c = 0 for i in 0 to length(ls) do : if c % wrap == 0 : c = 0 val base* = base(ls[i]) val guard* = AND(guard(ls[i]),EQV(uint(c),index(e))) add(ls*,Location(base*,guard*)) if (i + 1) % stride == 0 : c = c + 1 to-list(ls*) defn has-access? (e:Expression) -> True|False : var ret = false defn rec-has-access (e:Expression) -> Expression : match(e) : (e:WSubAccess) : ret = true e (e) : map(rec-has-access,e) rec-has-access(e) ret defn remove-access (c:Circuit) : defn remove-m (m:InModule) -> InModule : val sh = get-sym-hash(m,keys(v-keywords)) mname = name(m) defn remove-s (s:Stmt) -> Stmt : val stmts = Vector() defn create-temp (e:Expression) -> Expression : val n = firrtl-gensym(`GEN,sh) add(stmts,DefWire(info(s),n,type(e))) WRef(n,type(e),kind(e),gender(e)) defn remove-e (e:Expression) -> Expression : ;NOT RECURSIVE (except primops) INTENTIONALLY! match(e) : (e:DoPrim) : map(remove-e,e) (e:Mux) : map(remove-e,e) (e:ValidIf) : map(remove-e,e) (e:UIntValue|SIntValue) : e (e) : if has-access?(e) : val rs = get-locations(e) val foo = for x in rs find : (guard(x)) != one if foo == false : error("Shouldn't be here") else : val temp = create-temp(e) val temps = create-exps(temp) defn get-temp (i:Int) : temps[i % length(temps)] for (x in rs, i in 0 to false) do : if i < length(temps) : add(stmts,Connect(info(s),get-temp(i),base(x))) else : add(stmts,Conditionally(info(s),guard(x),Connect(info(s),get-temp(i),base(x)),Empty())) temp else : e val s* = match(s) : (s:Connect) : if has-access?(loc(s)) : val ls = get-locations(loc(s)) val loc* = if length(ls) == 1 and guard(head(ls)) == one : loc(s) else : val temp = create-temp(loc(s)) for x in ls do : add(stmts,Conditionally(info(s),guard(x),Connect(info(s),base(x),temp),Empty())) temp Connect(info(s),loc*,remove-e(exp(s))) else : Connect(info(s),loc(s),remove-e(exp(s))) (s) : map{remove-s,_} $ map(remove-e,s) add(stmts,s*) if length(stmts) != 1 : Begin(to-list(stmts)) else : stmts[0] InModule(info(m),name(m),ports(m),remove-s(body(m))) Circuit(info(c),modules*, main(c)) where : val modules* = for m in modules(c) map : match(m) : (m:ExModule) : m (m:InModule) : remove-m(m) ;;================ EXPAND WHENS ============================= ; This pass does three things: remove last connect semantics, ; remove conditional blocks, and eliminate concept of scoping. public defstruct ExpandWhens <: Pass public defmethod pass (b:ExpandWhens) -> (Circuit -> Circuit) : expand-whens public defmethod name (b:ExpandWhens) -> String : "Expand Whens" public defmethod short-name (b:ExpandWhens) -> String : "expand-whens" ; ========== Expand When Utilz ========== defn get-entries (hash:HashTable,exps:Streamable) -> HashTable : val hash* = HashTable(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 : val exps = create-exps(WRef(n,t,ExpKind(),g)) val exps* = Vector() for i in 0 to length(exps) do : switch { _ == get-gender(t,i,g)} : BI-GENDER : add(exps*,exps[i]) FEMALE : add(exps*,exps[i]) else : false to-list(exps*) defn get-gender (t:Type, i:Int, g:Gender) -> Gender : val f = get-flip(t,i,DEFAULT) g * f defn print-hash (h:HashTable) : for x in h do : println(x) ; ------------ Pass ------------------- defn expand-whens (c:Circuit) -> Circuit : defn void-all (m:InModule) -> InModule : mname = name(m) defn void-all-s (s:Stmt) -> Stmt : match(s) : (s:DefWire|DefRegister|WDefInstance|DefMemory) : val voids = Vector() 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() 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 Vector] : val simlist = Vector() mname = name(m) defn expand-whens (s:Stmt,netlist:HashTable,p:Expression) -> Stmt : match(s) : (s:Connect) : netlist[loc(s)] = exp(s) (s:IsInvalid) : netlist[exp(s)] = WInvalid() (s:Conditionally) : val exps = Vector() 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) : val tv = c-netlist[lvalue] val fv = value val res = match(tv,fv) : (tv:WInvalid,fv:WInvalid) : WInvalid() (tv:WInvalid,fv) : ValidIf(NOT(pred(s)),fv,type(fv)) (tv,fv:WInvalid) : ValidIf(pred(s),tv,type(tv)) (tv,fv) : Mux(pred(s),tv,fv,mux-type-and-widths(tv,fv)) netlist[lvalue] = res (value:False) : netlist[lvalue] = c-netlist[lvalue] (s:Print) : if p == one : add(simlist,s) else : add(simlist,Print(info(s),string(s),args(s),clk(s),AND(p,en(s)))) (s:Stop) : if p == one : add(simlist,s) else : add(simlist,Stop(info(s),ret(s),clk(s),AND(p,en(s)))) (s) : map(expand-whens{_,netlist,p},s) s val netlist = HashTable(exp-hash) expand-whens(body(m),netlist,one) ;println("Netlist:") ;println(netlist) ;println("Simlist:") ;println(simlist) [ netlist simlist ] defn create-module (netlist:HashTable,simlist:Vector,m:InModule) -> InModule : mname = name(m) val stmts = Vector() val connections = Vector() 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] val con = match(rvalue) : (rvalue:WInvalid) : IsInvalid(info(s),e) (rvalue) : Connect(info(s),e,rvalue) add(connections,con) (s:DefPoison|DefNode) : add(stmts,s) (s) : map(create,s) s create(body(m)) for p in ports(m) do : for e in get-female-refs(name(p),type(p),get-gender(p)) do : val rvalue = netlist[e] val con = match(rvalue) : (rvalue:WInvalid) : IsInvalid(info(p),e) (rvalue) : Connect(info(p),e,rvalue) add(connections,con) for x in simlist do : add(stmts,x) InModule(info(m),name(m),ports(m),Begin(list(Begin(to-list(stmts)),Begin(to-list(connections))))) val voided-modules = for m in modules(c) map : match(m) : (m:ExModule) : m (m:InModule) : val m* = void-all(m as InModule) m* val modules* = for m in voided-modules map : match(m) : (m:ExModule) : m (m:InModule) : val [netlist simlist] = expand-whens(m) create-module(netlist,simlist,m) Circuit(info(c),modules*,main(c)) ;;================ Module Duplication ================== ; Duplicates modules so that no module is instantiated ; more than once. ;public defstruct ModuleDuplication <: Pass ;public defmethod pass (b:ModuleDuplication) -> (Circuit -> Circuit) : module-duplication ;public defmethod name (b:ModuleDuplication) -> String : "Module Duplication" ;public defmethod short-name (b:ModuleDuplication) -> String : "mod-dup" ; ;;------------ Helper Functions ------------- ; ;;------------ Pass ------------------ ; ;public defn module-duplication (c:Circuit) : ; val modules* = Vector() ; val m-names = HashTable(symbol-hash) ; defn rename (n:Symbol) -> Symbol : ; val int = get?(m-names,n,0) ; m-names[n] = int + 1 ; val n* = symbol-join([n module-expand-delin int]) ; val m = for x in modules(c) find : name(x) == n ; match(m) : ; (m:InModule) : add(modules*,InModule(info(m),n*, ports(m), rename-s(body(m)))) ; (m:ExModule) : add(modules*,ExModule(info(m),n*, ports(m))) ; (m:False) : error("Shouldn't be here") ; n* ; ; defn rename-e (e:Expression) -> Expression : ; match(e) : ; (e:Ref) : Ref(rename(name(e)),type(e)) ; (e) : error("Shouldn't be here") ; defn rename-s (s:Stmt) -> Stmt : ; match(s) : ; (s:WDefInstance) : WDefInstance(info(s),name(s),rename-e(module(s))) ; (s) : map(rename-s,s) ; ; val top = for m in modules(c) find : name(m) == main(c) ; match(top) : ; (m:InModule) : add(modules*,InModule(info(m),name(m), ports(m), rename-s(body(m)))) ; (m:ExModule) : m ; (m:False) : error("Shouldn't be here") ; ; Circuit(info(c),to-list(modules*), main(c)) ; ; ;;;================ Deadcode Elimination =================== ;; Walks the circuit, starting from the outputs from the top ;; level module. All components that are not reached are ;; deleted ; ;public defstruct DeadcodeElimination <: Pass ;public defmethod pass (b:DeadcodeElimination) -> (Circuit -> Circuit) : deadcode-elimination ;public defmethod name (b:DeadcodeElimination) -> String : "Deadcode Elimination" ;public defmethod short-name (b:DeadcodeElimination) -> String : "deadcode-elim" ; ;;------------ Helper Functions ------------- ; ;;------------ Pass ------------------ ; ;public defn deadcode-elimination (c:Circuit) : c ; ;;;================ INFER WIDTHS ============================= ;; First, you replace all unknown widths with a unique width ;; variable. ;; Then, you collect all width constraints. ;; Then, you solve width constraints. ;; Finally, you replace all width variables with the solved ;; widths. ;; Low FIRRTL Pass. public defstruct InferWidths <: Pass public defmethod pass (b:InferWidths) -> (Circuit -> Circuit) : infer-widths public defmethod name (b:InferWidths) -> String : "Infer Widths" public defmethod short-name (b:InferWidths) -> String : "infer-widths" public definterface Constraint public defstruct WGeq <: Constraint : loc : Width exp : Width public defmethod print (o:OutputStream, c:WGeq) : print-all(o,[ loc(c) " >= " exp(c)]) defn apply (a:Int|False,b:Int|False, f: (Int,Int) -> Int) -> Int|False : if a typeof Int and b typeof Int : f(a as Int, b as Int) else : false defn solve-constraints (l:List) -> HashTable : defn contains? (n:Symbol,h:HashTable) -> True|False : key?(h,n) defn make-unique (ls:List) -> HashTable : val h = HashTable(symbol-hash) for g in ls do : match(loc(g)) : (w:VarWidth) : val n = name(w) if contains?(n,h) : h[n] = MaxWidth(list(exp(g),h[n])) else : h[n] = exp(g) (w) : w h defn simplify (w:Width) -> Width : match(map(simplify,w)) : (w:MaxWidth) : val v = Vector() for w* in args(w) do : match(w*) : (w*:MaxWidth) : for x in args(w*) do : add(v,x) (w*) : add(v,w*) MaxWidth(unique(v)) (w:PlusWidth) : match(arg1(w),arg2(w)) : (w1:IntWidth,w2:IntWidth) : IntWidth(plus(width(w1),width(w2))) (w1,w2) : w (w:MinusWidth) : match(arg1(w),arg2(w)) : (w1:IntWidth,w2:IntWidth) : IntWidth(minus(width(w1),width(w2))) (w1,w2) : w (w:ExpWidth) : match(arg1(w)) : (w1:IntWidth) : IntWidth(pow(to-long(2),width(w1)) - to-long(1)) (w1) : w (w) : w defn substitute (w:Width,h:HashTable) -> Width : ;println-all-debug(["Substituting for [" w "]"]) val w* = simplify(w) ;println-all-debug(["After Simplify: [" w* "]"]) match(map(substitute{_,h},simplify(w))) : (w:VarWidth) : ;println-debug("matched varwidth!") if contains?(name(w),h) : ;println-debug("Contained!") ;println-all-debug(["Width: " w]) ;println-all-debug(["Accessed: " h[name(w)]]) val t = simplify(substitute(h[name(w)],h)) ;val t = h[name(w)] ;println-all-debug(["Width after sub: " t]) h[name(w)] = t t else : w (w): ;println-all-debug(["not varwidth!" w]) w defn b-sub (w:Width,h:HashTable) -> Width: match(map(b-sub{_,h},w)) : (w:VarWidth) : if key?(h,name(w)) : h[name(w)] else : w (w) : w defn remove-cycle (n:Symbol,w:Width) -> Width : ;println-all-debug(["Removing cycle for " n " inside " w]) val w* = match(map(remove-cycle{n,_},w)) : (w:MaxWidth) : MaxWidth(to-list(filter({_ != VarWidth(n)},args(w)))) (w:MinusWidth) : if arg1(w) == VarWidth(n) : arg1(w) else : w (w) : w ;println-all-debug(["After removing cycle for " n ", returning " w*]) w* defn self-rec? (n:Symbol,w:Width) -> True|False : var has? = false defn look (w:Width) -> Width : match(map(look,w)) : (w:VarWidth) : if name(w) == n : has? = true (w) : w w look(w) has? ; Forward solve ; Returns a solved list where each constraint undergoes: ; 1) Continuous Solving (using triangular solving) ; 2) Remove Cycles ; 3) Move to solved if not self-recursive val u = make-unique(l) println-debug("======== UNIQUE CONSTRAINTS ========") for x in u do : println-debug(x) println-debug("====================================") val f = HashTable(symbol-hash) val o = Vector() for x in u do : println-debug("==== SOLUTIONS TABLE ====") for x in f do : println-debug(x) println-debug("=========================") val [n e] = [key(x) value(x)] val e-sub = substitute(e,f) println-debug(["Solving " n " => " e]) println-debug(["After Substitute: " n " => " e-sub]) println-debug("==== SOLUTIONS TABLE (Post Substitute) ====") for x in f do : println-debug(x) println-debug("=========================") val e* = remove-cycle{n,_} $ e-sub ;println-debug(["After Remove Cycle: " n " => " e*]) if not self-rec?(n,e*) : ;println-all-debug(["Not rec!: " n " => " e*]) ;println-all-debug(["Adding [" n "=>" e* "] to Solutions Table"]) add(o,n) f[n] = e* println-debug("Forward Solved Constraints") for x in f do : println-debug(x) ; Backwards Solve val b = HashTable(symbol-hash) for i in (length(o) - 1) through 0 by -1 do : val n = o[i] println-all-debug(["SOLVE BACK: [" n " => " f[n] "]"]) println-debug("==== SOLUTIONS TABLE ====") for x in b do : println-debug(x) println-debug("=========================") val e* = simplify(b-sub(f[n],b)) println-all-debug(["BACK RETURN: [" n " => " e* "]"]) b[n] = e* println-debug("==== SOLUTIONS TABLE (Post backsolve) ====") for x in b do : println-debug(x) println-debug("=========================") b public defn width! (t:Type) -> Width : match(t) : (t:UIntType) : width(t) (t:SIntType) : width(t) (t:ClockType) : IntWidth(1) (t) : error("No width!") public defn width! (e:Expression) -> Width : width!(type(e)) defn reduce-var-widths (c:Circuit,h:HashTable) -> Circuit : defn evaluate (w:Width) -> Width : defn apply (a:Long|False,f:(Long) -> Long) -> Long|False : if a typeof Long : f(a as Long) else : false defn apply (a:Long|False,b:Long|False, f: (Long,Long) -> Long) -> Long|False : if a typeof Long and b typeof Long : f(a as Long, b as Long) else : false defn apply-l (l:List,f:(Long,Long) -> Long) -> Long|False : if length(l) == 0 : to-long(0) else : apply(head(l),apply-l(tail(l),f),f) defn max (a:Long,b:Long) -> Long : if a >= b : a else : b defn solve (w:Width) -> False|Long : match(w) : (w:VarWidth) : val w* = get?(h,name(w),false) match(w*) : (w:VarWidth) : false (w:False) : false (w) : solve(w as Width) (w:MaxWidth) : apply-l(map(solve,args(w)),max) (w:PlusWidth) : apply(solve(arg1(w)),solve(arg2(w)),{plus(_,_)}) (w:MinusWidth) : apply(solve(arg1(w)),solve(arg2(w)),{minus(_,_)}) (w:ExpWidth) : apply(to-long(2),solve(arg1(w)),{minus(pow(_,_),to-long(1))}) (w:IntWidth) : width(w) (w) : println(w) error("Shouldn't be here") val s = solve(w) match(s) : (s:Long) : IntWidth(s) (s) : w defn reduce-var-widths-w (w:Width) -> Width : println-all-debug(["REPLACE: " w]) val w* = evaluate(w) println-all-debug(["WITH: " w*]) w* val modules* = for m in modules(c) map : val ports* = for p in ports(m) map : Port(info(p),name(p),direction(p),mapr(reduce-var-widths-w,type(p))) match(m) : (m:ExModule) : ExModule(info(m),name(m),ports*) (m:InModule) : mname = name(m) InModule(info(m),name(m),ports*,mapr(reduce-var-widths-w,body(m))) Circuit(info(c),modules*,main(c)) defn infer-widths (c:Circuit) -> Circuit : val v = Vector() 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:Mux) : constrain(width!(cond(e)),ONE) constrain(ONE,width!(cond(e))) e (e) : e defn get-constraints (s:Stmt) -> Stmt : match(map(get-constraints-e,s)) : (s:Connect) : ;constrain(width!(loc(s)),width!(exp(s))) ;s val n = get-size(loc(s)) val ce-loc = create-exps(loc(s)) val ce-exp = create-exps(exp(s)) for i in 0 to n do : val loc* = ce-loc[i] val exp* = ce-exp[i] switch { _ == get-flip(type(loc(s)),i,DEFAULT) } : DEFAULT : constrain(width!(loc*),width!(exp*)) REVERSE : constrain(width!(exp*),width!(loc*)) s (s:BulkConnect) : val ls = get-valid-points(type(loc(s)),type(exp(s)),DEFAULT,DEFAULT) for x in ls do : ;println(x) ;println(create-exps(loc(s))) ;println(create-exps(exp(s))) val loc* = create-exps(loc(s))[x[0]] val exp* = create-exps(exp(s))[x[1]] switch { _ == get-flip(type(loc(s)),x[0],DEFAULT) } : DEFAULT : constrain(width!(loc*),width!(exp*)) REVERSE : constrain(width!(exp*),width!(loc*)) s (s:DefRegister) : constrain(width!(reset(s)),ONE) constrain(ONE,width!(reset(s))) get-constraints(type(s),type(init(s)),DEFAULT) s (s:Conditionally) : add(v,WGeq(width!(pred(s)),ONE)) add(v,WGeq(ONE,width!(pred(s)))) map(get-constraints,s) (s) : map(get-constraints,s) for m in modules(c) do : match(m) : (m:InModule) : mname = name(m) get-constraints(body(m)) (m) : false println-debug("======== ALL CONSTRAINTS ========") for x in v do : println-debug(x) println-debug("=================================") val h = solve-constraints(to-list(v)) println-debug("======== SOLVED CONSTRAINTS ========") for x in h do : println-debug(x) println-debug("====================================") reduce-var-widths(Circuit(info(c),modules(c),main(c)),h) ; ================ All Resolving Passes ================ public defstruct Resolve <: Pass public defmethod pass (b:Resolve) -> (Circuit -> Circuit) : resolve public defmethod name (b:Resolve) -> String : "Resolve" public defmethod short-name (b:Resolve) -> String : "resolve" defn resolve (c:Circuit) -> Circuit : check-width $ infer-widths $ check-genders $ resolve-genders $ check-types $ infer-types $ resolve-kinds $ c ;;================= Inline Instances ======================== ;; Inlines instances. Assumes module with same name as the ;; Circuit is the top level module ;public defstruct Inline <: Pass ;public defmethod pass (b:Inline) -> (Circuit -> Circuit) : inline-instances ;public defmethod name (b:Inline) -> String : "Inline Instances" ;public defmethod short-name (b:Inline) -> String : "inline-instances" ; ;defn inline-instances (c:Circuit) : ; val h = HashTable(symbol-hash) ; val h-s = HashTable(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() ; for p in ports(m) do : ; add(v,DefWire(info(s),name(p),type(p))) ; add(v,inline-inst(body(m))) ; Begin(to-list(v)) ; h-s[n] = body* ; rename-s(body*,name(s)) ; (s) : map(inline-inst-e,s) ; defn inline-inst-e (e:Expression) -> Expression : ; match(map(inline-inst-e,e)) : ; (e:WSubField) : ; match(kind(exp(e) as WRef)) : ; (k:InstanceKind) : ; WRef(symbol-join([name(exp(e) as WRef) inline-delin name(e)]),type(e),k,gender(e)) ; (k:MemKind) : e ; (e) : e ; defn rename (ref:Symbol,n:Symbol) -> Symbol : symbol-join([n inline-delin ref]) ; defn rename-e (e:Expression,n:Symbol) -> Expression : ; match(map(rename-e{_,n},e)) : ; (e:WRef) : WRef(rename(name(e),n),type(e),kind(e),gender(e)) ; (e:WSubField) : ; match(kind(exp(e) as WRef)) : ; (k:InstanceKind) : ; WRef(symbol-join([name(exp(e) as WRef) inline-delin name(e)]),type(e),k,gender(e)) ; (k:MemKind) : e ; (e) : e ; defn rename-s (s:Stmt,n:Symbol) -> Stmt : ; map{rename-e{_,n},_} $ match(map(rename-s{_,n},s)) : ; (s:DefWire) : DefWire(info(s),rename(name(s),n),type(s)) ; (s:DefPoison) : DefPoison(info(s),rename(name(s),n),type(s)) ; (s:DefRegister) : DefRegister(info(s),rename(name(s),n),type(s),clock(s),reset(s)) ; (s:WDefInstance) : error("Shouldn't be here") ; (s:DefMemory) : DefMemory(info(s),rename(name(s),n),type(s),seq?(s),clock(s),size(s)) ; (s:DefNode) : DefNode(info(s),rename(name(s),n),value(s)) ; (s) : s ; for m in modules(c) do : ; match(m) : ; (m:ExModule) : error("Cannot inline with external modules") ; (m:InModule) : h[name(m)] = m ; val top = (for m in modules(c) find : name(m) == main(c)) as InModule ; Circuit(info(c),list(InModule(info(top),name(top),ports(top),inline-inst(body(top)))),main(c)) ;;================= Split Expressions ======================== ;; Intended to only work on low firrtl public defstruct SplitExp <: Pass public defmethod pass (b:SplitExp) -> (Circuit -> Circuit) : split-exp public defmethod name (b:SplitExp) -> String : "Split Expressions" public defmethod short-name (b:SplitExp) -> String : "split-expressions" defn split-exp (m:InModule) -> InModule : mname = name(m) val v = Vector() val sh = get-sym-hash(m,keys(v-keywords)) defn split-exp-s (s:Stmt) -> Stmt : val base = match(s) : (s:Connect) : lowered-name(loc(s)) (s:DefNode) : name(s) (s:DefRegister) : name(s) (s) : `F defn split (e:Expression) -> Expression : val n = firrtl-gensym(`GEN,sh) add(v,DefNode(info(s),n,e)) WRef(n,type(e),kind(e),gender(e)) defn split-exp-e (e:Expression,i:Int) -> Expression : match(map(split-exp-e{_,i + 1},e)) : (e:DoPrim) : if i > 0 : split(e) else : e (e) : e match(map(split-exp-e{_,0},s)) : (s:Begin) : map(split-exp-s,s) (s) : add(v,s) s split-exp-s(body(m)) InModule(info(m),name(m),ports(m),Begin(to-list(v))) defn split-exp (c:Circuit) -> Circuit : val modules* = for m in modules(c) map : match(m) : (m:InModule) : split-exp(m) (m:ExModule) : m Circuit(info(c),modules*,main(c)) ;;================= Special Rename ======================== ;; Returns a new Circuit with only real IR nodes. ;public defstruct SpecialRename <: Pass : ; original-sym : Symbol ; new-sym : Symbol ;public defmethod pass (b:SpecialRename) -> (Circuit -> Circuit) : special-rename{original-sym(b),new-sym(b),_:Circuit} ;public defmethod name (b:SpecialRename) -> String : "Special Rename" ;public defmethod short-name (b:SpecialRename) -> String : "special-rename" ; ;public defn special-rename (original-sym:Symbol,new-sym:Symbol,c:Circuit) : ; defn rename (s:Symbol) -> Symbol : ; val y = Vector() ; val os = to-string $ original-sym ; val ns = to-string $ new-sym ; defn rename (st:String) -> False : ; if st == os : ; add(y,ns) ; else if length(st) <= length(os) : ; add(y,st) ; else : ; if substring(st,0,length(os)) == os : ; add(y,ns) ; ;println(st) ; ;println(substring(st,length(os),length(st))) ; rename(substring(st,length(os),length(st))) ; else : ; add(y,substring(st,0,1)) ; rename(substring(st,1,length(st))) ; rename(to-string(s)) ; to-symbol $ string-join $ to-list(y) ; defn to-type (t:Type) -> Type : ; match(map(to-type,t)) : ; (t:BundleType) : BundleType $ ; for f in fields(t) map : Field(rename(name(f)),flip(f),type(f)) ; (t) : t ; defn to-exp (e:Expression) -> Expression : ; map{to-type,_} $ match(map(to-exp,e)) : ; (e:Ref) : Ref(rename(name(e)), type(e)) ; (e:Subfield) : Subfield(exp(e),rename(name(e)),type(e)) ; (e) : e ; defn to-stmt (s:Stmt) -> Stmt : ; map{to-type,_} $ match(map(to-exp,s)) : ; (s:DefWire) : DefWire(info(s),rename(name(s)),type(s)) ; (s:DefPoison) : DefPoison(info(s),rename(name(s)),type(s)) ; (s:DefRegister) : DefRegister(info(s),rename(name(s)),type(s),clock(s),reset(s)) ; (s:WDefInstance) : WDefInstance(info(s),rename(name(s)),module(s)) ; (s:DefMemory) : DefMemory(info(s),rename(name(s)),type(s),seq?(s),clock(s),size(s)) ; (s:DefNode) : DefNode(info(s),rename(name(s)),value(s)) ; (s:DefAccessor) : DefAccessor(info(s),rename(name(s)),source(s),index(s),acc-dir(s)) ; (s) : map(to-stmt,s) ; ; defn to-port (p:Port) -> Port : Port(info(p),rename(name(p)),direction(p),type(p)) ; ; Circuit(info(c),modules*, main(c)) where : ; val modules* = ; for m in modules(c) map : ; match(m) : ; (m:InModule) : InModule(info(m),name(m), map(to-port,ports(m)), to-stmt(body(m))) ; (m:ExModule) : m ; ; ;;========== Pad Widths ================== ; ;public defstruct Pad <: Pass ;public defmethod pass (b:Pad) -> (Circuit -> Circuit) : pad-widths ;public defmethod name (b:Pad) -> String : "Pad Widths" ; ;;------------ Helper Functions -------------- ;defn int-width! (t:Type) -> Long : ; match(width!(t)) : ; (w:IntWidth) : width(w) ; (w) : error("Non-int width") ; ;defn set-width (desired:Long,t:Type) -> Type : ; match(t) : ; (t:UIntType) : UIntType(IntWidth(desired)) ; (t:SIntType) : SIntType(IntWidth(desired)) ; (t) : error("Non-ground type") ; ;defn lmax (l1:Long, l2:Long) -> Long : ; if l1 > l2 : l1 ; else : l2 ; ;;------------- Pad Widths ------------------- ; ;defn pad-widths-e (desired:Long,e:Expression) -> Expression : ; defn trim (desired:Long, e:Expression) : ; ;; println-all(["TRIM " desired " e " e]) ; DoPrim(BITS-SELECT-OP,list(e),list(to-int(to-string(desired)) - 1, 0),set-width(desired,type(e))) ; defn pad (desired:Long, e:Expression) : ; ;; println-all(["PAD " desired " e " e]) ; DoPrim(PAD-OP,list(e),list(to-int $ to-string(desired)),set-width(desired,type(e))) ; defn trim-pad (desired:Long, e:Expression) : ; val i = int-width!(type(e)) ; if i > desired : trim(desired, e) ; else if i == desired : e ; else : pad(desired, e) ; defn self-pad-widths-e (e:Expression) -> Expression : ; pad-widths-e(int-width!(type(e)), e) ; ;; println-all(["PAD-E " desired " " e]) ; match(e) : ; (e:DoPrim) : ; val new-desired = reduce(lmax, to-long(0), map(int-width!{type(_)}, args(e))) ; ;; println-all([" NEW DESIRED " new-desired]) ; val e* = ; if contains?([CONCAT-OP, DYN-SHIFT-RIGHT-OP, DYN-SHIFT-LEFT-OP], op(e)) : ; DoPrim(op(e), map(self-pad-widths-e, args(e)), consts(e), type(e)) ; else if contains?([MUX-OP], op(e)) : ; DoPrim(op(e), list(pad-widths-e(to-long(1), args(e)[0]), pad-widths-e(new-desired, args(e)[1]), pad-widths-e(new-desired, args(e)[2])), consts(e), type(e)) ; else : ; map(pad-widths-e{new-desired,_},e) ; trim-pad(desired, e*) ; (e:Ref|Subfield|Index) : ; trim-pad(desired, e) ; (e:UIntValue) : ; val i = int-width!(type(e)) ; if i > desired : trim(desired, e) ; else : UIntValue(value(e),IntWidth(desired)) ; (e:SIntValue) : ; val i = int-width!(type(e)) ; if i > desired : trim(desired, e) ; else : SIntValue(value(e),IntWidth(desired)) ; (e) : error(to-string $ e) ; ;defn pad-widths-s (s:Stmt) -> Stmt : ; ;; println-all(["PAD-S " s]) ; match(map(pad-widths-s,s)) : ; (s:Connect) : ; val i = int-width!(type(loc(s))) ; val loc* = pad-widths-e(i,loc(s)) ; val exp* = pad-widths-e(i,exp(s)) ; Connect(info(s),loc*,exp*) ; (s:PrintfStmt) : ; val args* = for x in args(s) map : ; val i = int-width!(type(x)) ; pad-widths-e(i,x) ; PrintfStmt(info(s),string(s),args*) ; (s:DefNode) : ; val i = int-width!(type(value(s))) ; val exp* = pad-widths-e(i,value(s)) ; DefNode(info(s),name(s),exp*) ; (s:Conditionally) : ; val i = int-width!(type(pred(s))) ; val pred* = pad-widths-e(i,pred(s)) ; Conditionally(info(s),pred*,conseq(s),alt(s)) ; (s) : s ; ;public defn pad-widths (c:Circuit) -> Circuit : ; Circuit{info(c),_,main(c)} $ ; for m in modules(c) map : ; match(m) : ; (m:ExModule) : m ; (m:InModule) : InModule(info(m),name(m),ports(m),pad-widths-s(body(m))) ; ; ;============== Common Subexpression Elimination =========== ;NOT DONE ;public defstruct CSE <: Pass ;public defmethod pass (b:CSE) -> (Circuit -> Circuit) : const-prop ;public defmethod name (b:CSE) -> String : "Common Subexpression Elimination" ;public defmethod short-name (b:ConstProp) -> String : "cse" ; ;defn cse-m (m:InModule) -> InModule : ; val cse-hash = HashTable(exp-hash) ; val placed? = HashTable(exp-hash) ; ; defn cse-s (s:Stmt) -> Stmt : ; val stmts = Vector() ; defn cse-e (e:Expression) -> Expression ; match(s) : ; ; defn build-e (e:Expression) -> Expression : ; match(e) : ; (e:DoPrim) : ; if key?(cse-hash,e) : ; cse-hash[e] = cse-hash[e] + 1 ; else : ; cse-hash[e] = 1 ; placed?[e] = false ; (e) : e ; defn build-s (s:Stmt) -> Stmt : map{build-s,_} $ map(build-e,s) ; ; build-s(body(m)) ; InModule(info(m),name(m),ports(m),cse-s(body(m))) ; ;public defn cse (c:Circuit) -> Circuit : ; Circuit{info(c),_,main(c)} $ ; for m in modules(c) map : ; match(m) : ; (m:ExModule) : m ; (m:InModule) : cse-m(m) ;;============= Constant Propagation ================ ; public defstruct ConstProp <: Pass public defmethod pass (b:ConstProp) -> (Circuit -> Circuit) : const-prop public defmethod name (b:ConstProp) -> String : "Constant Propagation" public defmethod short-name (b:ConstProp) -> String : "const-prop" defn const-prop-e (e:Expression) -> Expression : match(map(const-prop-e,e)) : (e:DoPrim) : switch {op(e) == _} : ;DYN-SHIFT-RIGHT-OP : ; match(args(e)[1]) : ; (x:UIntValue|SIntValue) : ; DoPrim(SHIFT-RIGHT-OP,list(args(e)[0]),list(to-int(value(x))),UnknownType()) ; (x) : e ;DYN-SHIFT-LEFT-OP : ; match(args(e)[1]) : ; (x:UIntValue|SIntValue) : ; DoPrim(SHIFT-LEFT-OP,list(args(e)[0]),list(to-int(value(x))),UnknownType()) ; (x) : e SHIFT-RIGHT-OP : match(args(e)[0]) : (x:UIntValue) : val b = rsh(value(x),consts(e)[0]) UIntValue(b,width(type(e) as UIntType)) (x:SIntValue) : val b = rsh(value(x),consts(e)[0]) SIntValue(b,width(type(e) as SIntType)) (x) : e BITS-SELECT-OP : match(args(e)[0]) : (x:UIntValue) : val b = bits(value(x),consts(e)[0] + 1,consts(e)[1]) UIntValue(b,width(type(e) as UIntType)) (x) : e BIT-SELECT-OP : match(args(e)[0]) : (x:UIntValue) : val i = bit(value(x),consts(e)[0]) UIntValue(i,width(type(e) as UIntType)) (x) : e else : e (e) : e defn const-prop-s (s:Stmt) -> Stmt : map{const-prop-e,_} $ map(const-prop-s,s) public defn const-prop (c:Circuit) -> Circuit : Circuit{info(c),_,main(c)} $ for m in modules(c) map : match(m) : (m:ExModule) : m (m:InModule) : mname = name(m) 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 : ; 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(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() ; val s* = map(flatten,s) ; add(stmts,s*) ; val mem = WRef(name(s),type(s),MemKind(),UNKNOWN-GENDER) ; for f in fields(type(s) as BundleType) do : ; val data-name = ; if contains?(writers(s),name(f)) : `data ; else if contains(readwriters(s),name(f)) : `wdata ; else : false ; match(data-name) : ; (f:False) : false ; (n:Symbol) : ; val port = WSubField(mem,name(f),type(f),UNKNOWN-GENDER) ; val es = create-exps(WSubField(port,n,field-type(type(port),n),UNKNOWN-GENDER)) ; val e* = concat $ for e in es map : ; map(condense-mems-e,mem-assigns[e]) ; add(stmts,Connect(info(s),WSubField(port,n,data-type(s*),UNKNOWN-GENDER),e*)) ; Begin(to-list(stmts)) ; (s:Connect) : ; if kind(loc(s)) typeof MemKind : EmptyStmt() ; else : map(condense-mems-e, s) ; (s) : map{condense-mems,_} $ map(condense-mems-e, s) ; InModule(info(m),name(m),ports(m),condense-mems(body(m))) ; ;defn condense-mems (c:Circuit) -> Circuit : ; Circuit{info(c),_,main(c)} $ ; for m in modules(c) map : ; match(m) : ; (m:ExModule) : m ; (m:InModule) : condense-mems(m) ;============= Lower Types ================ ; public defstruct LowerTypes <: Pass public defmethod pass (b:LowerTypes) -> (Circuit -> Circuit) : lower-types public defmethod name (b:LowerTypes) -> String : "Lower Types" public defmethod short-name (b:LowerTypes) -> String : "lower-types" ;------------- Utils --------------- defn is-ground? (t:Type) -> True|False : match(t) : (t:UIntType|SIntType) : true (t) : false defn data? (ex:Expression) -> True|False : match(kind(ex)) : (k:MemKind) : match(ex) : (ex:WRef|WSubIndex) : false (ex:WSubField) : var yes? = switch { _ == name(ex) } : `rdata : true `data : true `mask : true else : false yes? and match(exp(ex)) : (e:WSubField) : contains?(ports(kind(e) as MemKind),name(e)) and (exp(e) typeof WRef) (e) : false (ex) : false (k) : false defn expand-name (e:Expression) -> List : val names = Vector() defn expand-name-e (e:Expression) -> Expression : match(map(expand-name-e,e)) : (e:WRef) : add(names,name(e)) (e:WSubField) : add(names,name(e)) (e:WSubIndex) : add(names,to-symbol(value(e))) e expand-name-e(e) to-list(names) defn lower-other-mem (e:Expression, dt:Type) -> List : val names = expand-name(e) if length(names) < 3 : error("Shouldn't be here") for x in create-exps(names[0],dt) map : var base = lowered-name(x) for (x in names,i in 0 to false) do : if i >= 3 : base = symbol-join([base `_ x]) val m = WRef(base, UnknownType(), kind(e), UNKNOWN-GENDER) val p = WSubField(m,to-symbol(names[1]),UnknownType(),UNKNOWN-GENDER) WSubField(p,to-symbol(names[2]),UnknownType(),UNKNOWN-GENDER) defn lower-data-mem (e:Expression) -> Expression : val names = expand-name(e) if length(names) < 3 : error("Shouldn't be here") else : var base = names[0] for (x in names,i in 0 to false) do : if i >= 3 : base = symbol-join([base `_ x]) val m = WRef(base, UnknownType(), kind(e), UNKNOWN-GENDER) val p = WSubField(m,to-symbol(names[1]),UnknownType(),UNKNOWN-GENDER) WSubField(p,to-symbol(names[2]),UnknownType(),UNKNOWN-GENDER) defn merge (a:Symbol,b:Symbol,x:Symbol) -> Symbol : symbol-join([a x b]) val hashed-lowered-name = HashTable(gexp-hash) defn fast-lowered-name (e:Expression) -> Symbol : val x = get?(hashed-lowered-name,e,false) match(x) : (x:Symbol) : x (x:False) : match(e) : (e:WRef) : name(e) (e:WSubField) : merge(fast-lowered-name(exp(e)),name(e),`_) (e:WSubIndex) : merge(fast-lowered-name(exp(e)),to-symbol(value(e)),`_) defn lowered-name (e:Expression) -> Symbol : match(e) : (e:WRef) : name(e) (e:WSubField) : merge(lowered-name(exp(e)),name(e),`_) (e:WSubIndex) : merge(lowered-name(exp(e)),to-symbol(value(e)),`_) defn root-ref (e:Expression) -> WRef : match(e) : (e:WRef) : e (e:WSubField|WSubIndex|WSubAccess) : root-ref(exp(e)) (e:WIndexer) : root-ref(exps(e)[0]) ;------------- Pass ------------------ defn lower-types (m:Module) -> Module : val mdt = HashTable(symbol-hash) mname = name(m) defn lower-types (s:Stmt) -> Stmt : defn lower-mem (e:Expression) -> List : val names = expand-name(e) if contains?([`data `mask `rdata],names[2]) : list(lower-data-mem(e)) else : lower-other-mem(e,mdt[name(root-ref(e))]) defn lower-types-e (e:Expression) -> Expression : match(e) : (e:WRef|UIntValue|SIntValue) : e (e:WSubField|WSubIndex) : match(kind(e)) : (k:InstanceKind) : val names = expand-name(e) var n = names[1] for (x in names,i in 0 to false) do : if i > 1 : n = symbol-join([n `_ x]) WSubField(root-ref(e),n,type(e),gender(e)) (k:MemKind) : if not gender(e) == FEMALE : lower-mem(e)[0] else : e (k) : WRef(lowered-name(e),type(e),kind(e),gender(e)) (e:DoPrim) : map(lower-types-e,e) (e:Mux) : map(lower-types-e,e) (e:ValidIf) : map(lower-types-e,e) match(s) : (s:DefWire|DefPoison) : if is-ground?(type(s)) : s else : val es = create-exps(name(s),type(s)) Begin $ for (e in es, i in 0 to false) map : defn replace-type (t:Type) -> Type : type(e) defn replace-name (n:Symbol) -> Symbol : lowered-name(e) map{replace-name,_} $ map(replace-type,s) (s:DefRegister) : if is-ground?(type(s)) : s else : val es = create-exps(name(s),type(s)) Begin $ for (e in es, i in 0 to false) map : val init = lower-types-e(create-exps(init(s))[i]) DefRegister(info(s),lowered-name(e),type(e),clock(s),reset(s),init) (s:WDefInstance) : val fields* = for f in fields(type(s) as BundleType) map-append : val es = create-exps(WRef(name(f),type(f),ExpKind(),flip(f) * MALE)) for e in es map : switch { _ == gender(e) } : MALE : Field(lowered-name(e),DEFAULT,type(f)) FEMALE : Field(lowered-name(e),REVERSE,type(f)) WDefInstance(info(s),name(s),module(s),BundleType(fields*)) (s:DefMemory) : mdt[name(s)] = data-type(s) if is-ground?(data-type(s)) : s else : val es = create-exps(name(s),data-type(s)) Begin $ for e in es map : DefMemory(info(s),lowered-name(e),type(e),depth(s),write-latency(s),read-latency(s),readers(s),writers(s),readwriters(s)) (s:IsInvalid) : val s* = map(lower-types-e,s) if kind(exp(s*)) typeof MemKind : val es = lower-mem(exp(s*)) Begin $ for e in es map : IsInvalid(info(s*),e) else : s* (s:Connect) : val s* = map(lower-types-e,s) if kind(loc(s*)) typeof MemKind : val es = lower-mem(loc(s*)) Begin $ for e in es map : Connect(info(s*),e,exp(s*)) else : s* (s:DefNode) : val locs = create-exps(name(s),type(value(s))) val n = length(locs) val nodes = Vector() val exps = create-exps(value(s)) for i in 0 to n do : val loc* = locs[i] val exp* = exps[i] add(nodes,DefNode(info(s),lowered-name(loc*),lower-types-e(exp*))) if n == 1 : nodes[0] else : Begin(to-list(nodes)) (s) : map(lower-types-e,map(lower-types,s)) 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))) defn lower-types (c:Circuit) -> Circuit : Circuit{info(c),_,main(c)} $ for m in modules(c) map : lower-types(m) ;============ RENAME VERILOG KEYWORDS ============= public defstruct VerilogRename <: Pass public defmethod pass (b:VerilogRename) -> (Circuit -> Circuit) : verilog-rename public defmethod name (b:VerilogRename) -> String : "Verilog Rename" public defmethod short-name (b:VerilogRename) -> String : "Verilog Rename" defn verilog-rename (c:Circuit) -> Circuit : defn verilog-rename-n (n:Symbol) -> Symbol : if key?(v-keywords,n) : symbol-join([n `$]) else : n defn verilog-rename-e (e:Expression) -> Expression : match(e) : (e:WRef) : WRef(verilog-rename-n(name(e)),type(e),kind(e),gender(e)) (e) : map(verilog-rename-e,e) defn verilog-rename-s (s:Stmt) -> Stmt : map{verilog-rename-n,_} $ map{verilog-rename-e,_} $ map(verilog-rename-s,s) Circuit{info(c),_,main(c)} $ for m in modules(c) map : val ports* = for p in ports(m) map : Port(info(p),verilog-rename-n(name(p)),direction(p),type(p)) match(m) : (m:InModule) : InModule(info(m),name(m),ports*,verilog-rename-s(body(m))) (m:ExModule) : 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 = " " val ran = VRandom() defn wref (n:Symbol,t:Type) : WRef(n,t,ExpKind(),UNKNOWN-GENDER) defn escape (s:String) -> String : val s* = Vector() add(s*,"\"");" var percent = false for c in s do : if c == '\n' : add(s*,"\\n") else : if c == 'x' and percent : add(s*,"h") else : add(s*,to-string(c)) percent = c == '%' add(s*,"\"");" string-join(s*) defn remove-root (ex:Expression) -> Expression : match(exp(ex as WSubField)) : (e:WSubField) : remove-root(e) (e:WRef) : WRef(name(ex as WSubField),type(ex),InstanceKind(),UNKNOWN-GENDER) defn !empty? (s:Vector) -> True|False : if length(s) == 0 : false else : true defn long! (t:Type) -> Long : match(t) : (t:UIntType|SIntType) : width(width(t) as IntWidth) (t:BundleType) : var w = to-long(0) for f in fields(t) do : w = w + long!(type(f)) w (t:VectorType) : to-long(size(t)) * long!(type(t)) (t:ClockType) : to-long(1) defn rand-string (t:Type) -> Streamable : val w* = ((long!(t) + to-long(31)) / to-long(32)) ["{" w* "{" ran "}}"] defn emit (x:?) : emit(x,0) defn emit (x:?, top:Int) : defn cast (e:Expression) -> ? : match(type(e)) : (t:UIntType) : e (t:SIntType) : ["$signed(" e ")"] match(x) : (e:Expression) : turn-off-debug(false) match(e) : (e:DoPrim) : emit(op-stream(e), top + 1) (e:Mux) : emit([cond(e) " ? " cast(tval(e)) " : " cast(fval(e))],top + 1) (e:ValidIf) : emit([cast(value(e))],top + 1) (e:WRef) : print(e) (e:WSubField) : print(lowered-name(e)) (e:WSubAccess) : print-all([lowered-name(exp(e)) "[" lowered-name(index(e)) "]"]) (e:WSubIndex) : print(e) (e:UIntValue|SIntValue) : v-print(e) turn-on-debug(false) (t:Type) : match(t) : (t:UIntType|SIntType) : val w = long!(t) - to-long(1) if w > to-long(0) : print-all(["[" w ":0]"]) else : print("");" (t:ClockType) : print("");" (t:VectorType) : emit(type(t), top + 1) print-all(["[" size(t) - 1 ":0]"]) (t) : println(t) (p:Direction) : switch {_ == p} : INPUT : print("input") OUTPUT : print("output") (s:Symbol) : print(s) (i:Int) : print(i) (i:Long) : print(i) (s:String) : print(s) (t:VIndent) : print(" ") (r:VRandom) : print("$random") (s:Streamable) : for x in s do : emit(x, top + 1) if top == 0 : print("\n") ;------------- PASS ----------------- defn v-print (e:UIntValue|SIntValue) : val str = to-string(value(e)) val out = substring(str,1,length(str) - 1) print $ string-join $ match(e) : (e:UIntValue) : [long!(type(e)) "'" out] (e:SIntValue) : [long!(type(e)) "'s" out] defn op-stream (doprim:DoPrim) -> Streamable : defn cast-if (e:Expression) -> ? : val signed? = for x in args(doprim) any? : type(x) typeof SIntType if not signed? : e else : match(type(e)) : (t:SIntType) : ["$signed(" e ")"] (t:UIntType) : ["$signed({1'b0," e "})"] defn cast (e:Expression) -> ? : match(type(doprim)) : (t:UIntType) : e (t:SIntType) : ["$signed(" e ")"] defn a0 () -> Expression : args(doprim)[0] defn a1 () -> Expression : args(doprim)[1] defn a2 () -> Expression : args(doprim)[2] defn c0 () -> Int : consts(doprim)[0] defn c1 () -> Int : consts(doprim)[1] switch {_ == op(doprim)} : ADD-OP : [cast-if(a0()) " + " cast-if(a1())] SUB-OP : [cast-if(a0()) " - " cast-if(a1())] MUL-OP : [cast-if(a0()) " * " cast-if(a1()) ] DIV-OP : [cast-if(a0()) " / " cast-if(a1()) ] MOD-OP : [cast-if(a0()) " % " cast-if(a1()) ] QUO-OP : [cast-if(a0()) " / " cast-if(a1()) ] REM-OP : [cast-if(a0()) " % " cast-if(a1()) ] ADD-WRAP-OP : [cast-if(a0()), " + " cast-if(a1())] SUB-WRAP-OP : [cast-if(a0()), " - " cast-if(a1())] LESS-OP : [cast-if(a0()) " < " cast-if(a1())] LESS-EQ-OP : [cast-if(a0()) " <= " cast-if(a1())] GREATER-OP : [cast-if(a0()) " > " cast-if(a1())] GREATER-EQ-OP : [cast-if(a0()) " >= " cast-if(a1())] NEQUIV-OP : [cast-if(a0()) " != " cast-if(a1())] EQUIV-OP : [cast-if(a0()) " == " cast-if(a1())] NEQUAL-OP : [cast-if(a0()) " != " cast-if(a1())] EQUAL-OP : [cast-if(a0()) " == " cast-if(a1())] ;MUX-OP : [a0() " ? " cast(a1()) " : " cast(a2())] PAD-OP : val w = long!(type(a0())) val diff = (to-long(c0()) - w) if w == to-long(0) : [ a0() ] else : match(type(doprim)) : (t:SIntType) : ["{{" diff "{" a0() "[" w - to-long(1) "]}}, " a0() " }"] (t) : ["{{" diff "'d0 }, " a0() " }"] AS-UINT-OP : ["$unsigned(" a0() ")"] AS-SINT-OP : ["$signed(" a0() ")"] DYN-SHIFT-LEFT-OP : [cast(a0()) " << " a1()] DYN-SHIFT-RIGHT-OP : match(type(doprim)) : (t:SIntType) : [cast(a0()) " >>> " a1()] (t) : [cast(a0()) " >> " a1()] SHIFT-LEFT-OP : [cast(a0()) " << " c0()] SHIFT-RIGHT-OP : [a0() "[" long!(type(a0())) - to-long(1) ":" c0() "]"] NEG-OP : ["-{" cast(a0()) "}"] CONVERT-OP : match(type(a0())) : (t:UIntType) : ["{1'b0," cast(a0()) "}"] (t:SIntType) : [cast(a0())] BIT-NOT-OP : ["~ " cast(a0())] BIT-AND-OP : [cast(a0()) " & " cast(a1())] BIT-OR-OP : [cast(a0()) " | " cast(a1())] BIT-XOR-OP : [cast(a0()) " ^ " cast(a1())] CONCAT-OP : ["{" cast(a0()) "," cast(a1()) "}"] BIT-SELECT-OP : [a0() "[" c0() "]"] BITS-SELECT-OP : [a0() "[" c0() ":" c1() "]"] BIT-AND-REDUCE-OP : val v = Vector() for b in 0 to to-int(long!(type(doprim))) do : add(v,[cast(a0()) "[" b "]"]) join(v," & ") BIT-OR-REDUCE-OP : val v = Vector() for b in 0 to to-int(long!(type(doprim))) do : add(v,[cast(a0() ) "[" b "]"]) join(v," | ") BIT-XOR-REDUCE-OP : val v = Vector() for b in 0 to to-int(long!(type(doprim))) do : add(v,[cast(a0() ) "[" b "]"]) join(v," ^ ") defn emit-verilog (m:InModule) -> Module : mname = name(m) val netlist = HashTable(exp-hash) val simlist = Vector() val namehash = get-sym-hash(m,keys(v-keywords)) defn build-netlist (s:Stmt) -> Stmt : match(s) : (s:Connect) : netlist[loc(s)] = exp(s) (s:IsInvalid) : val n = firrtl-gensym(`GEN,namehash) val e = wref(n,type(exp(s))) netlist[exp(s)] = e (s:Conditionally) : add(simlist,s) (s:DefNode) : val e = WRef(name(s),get-type(s),NodeKind(),MALE) netlist[e] = value(s) (s) : map(build-netlist,s) s val portdefs = Vector() val declares = Vector() val instdeclares = Vector() val assigns = Vector() val at-clock = HashTable>(exp-hash) val initials = Vector() val simulates = Vector() defn declare (b:Symbol,n:Symbol,t:Type) : match(t) : (t:VectorType) : add(declares,[b " " type(t) " " n " [0:" size(t) - 1 "];"]) (t) : add(declares,[b " " t " " n ";"]) defn assign (e:Expression,value:Expression) : add(assigns,["assign " e " = " value ";"]) defn update-and-reset (r:Expression,clk:Expression,reset?:Expression,init:Expression) : if not key?(at-clock,clk) : at-clock[clk] = Vector() defn add-update (e:Expression,tabs:String) : match(e) : (e:Mux) : add(at-clock[clk],[tabs "if(" cond(e) ") begin"]) add-update(tval(e),string-join([tabs tab])) add(at-clock[clk],[tabs "end else begin"]) add-update(fval(e),string-join([tabs tab])) add(at-clock[clk],[tabs "end"]) (e) : if e == r : add(at-clock[clk],[tabs ";"]) else : add(at-clock[clk],[tabs r " <= " e ";"]) val tv = init val fv = netlist[r] add-update(Mux(reset?,tv,fv,mux-type-and-widths(tv,fv)),"");" defn update (e:Expression,value:Expression,clk:Expression,en:Expression) : if not key?(at-clock,clk) : at-clock[clk] = Vector() if en == one : add(at-clock[clk],[e " <= " value ";"]) else : add(at-clock[clk],["if(" en ") begin"]) add(at-clock[clk],[tab e " <= " value ";"]) add(at-clock[clk],["end"]) defn initialize (e:Expression) : add(initials,[e " = " rand-string(type(e)) ";"]) defn initialize-mem (n:Symbol,i:Int,t:Type) : add(initials,["for (initvar = 0; initvar < " i "; initvar = initvar+1)"]) val index = WRef(`initvar,UnknownType(),ExpKind(),UNKNOWN-GENDER) add(initials,[tab WSubAccess(wref(n,t),index,UnknownType(),FEMALE), " = " rand-string(t) ";"]) defn instantiate (n:Symbol,m:Symbol,es:List) : add(instdeclares,[m " " n " ("]) for (e in es,i in 0 to false) do : val s = [tab "." remove-root(e) "(" lowered-name(e) ")"] if i != length(es) - 1 : add(instdeclares,[s ","]) else : add(instdeclares,s) add(instdeclares,[");"]) for e in es do : declare(`wire,lowered-name(e),type(e)) val e* = WRef(lowered-name(e),type(e),kind(e),gender(e)) if (gender(e) == FEMALE) : assign(e*,netlist[e]) defn simulate (clk:Expression,en:Expression,s:Streamable) : if not key?(at-clock,clk) : at-clock[clk] = Vector() 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) -> Streamable : val str* = join(List(escape(str),args),",") ["$fwrite(32'h80000002," str* ");"] defn delay (e:Expression, n:Int, clk:Expression) -> Expression : var e* = e for i in 0 to n do : val name = firrtl-gensym(`GEN,namehash) declare(`reg,name,type(e)) val e** = WRef(name,type(e),ExpKind(),UNKNOWN-GENDER) update(e**,e*,clk,one) e* = e** e* defn build-ports () : for (p in ports(m),i in 0 to false) do : var end = ",\n" if length(ports(m)) - 1 == i : end = "\n);\n" switch {_ == direction(p)} : INPUT : add(portdefs,[direction(p) " " type(p) " " name(p) ]) OUTPUT : add(portdefs,[direction(p) " " type(p) " " name(p) ]) val e* = WRef(name(p),type(p),PortKind(),FEMALE) assign(e*,netlist[e*]) if length(ports(m)) == 0 : print(");\n") defn build-streams (s:Stmt) -> Stmt : match(s) : (s:Connect) : s (s:DefWire) : declare(`wire,name(s),type(s)) val e = wref(name(s),type(s)) assign(e,netlist[e]) (s:DefRegister) : declare(`reg,name(s),type(s)) val e = wref(name(s),type(s)) update-and-reset(e,clock(s),reset(s),init(s)) initialize(e) (s:IsInvalid) : val wref = netlist[exp(s)] as WRef declare(`reg,name(wref),type(exp(s))) initialize(wref) (s:DefPoison) : val n = name(s) val e = wref(n,type(s)) declare(`reg,n,type(e)) initialize(e) (s:DefNode) : declare(`wire,name(s),type(value(s))) assign(WRef(name(s),type(value(s)),NodeKind(),MALE),value(s)) (s:Stop) : simulate(clk(s),en(s),stop(ret(s))) (s:Print) : simulate(clk(s),en(s),printf(string(s),args(s))) (s:WDefInstance) : val es = create-exps(WRef(name(s),type(s),InstanceKind(),MALE)) instantiate(name(s),module(s),es) (s:DefMemory) : val mem = WRef(name(s),get-type(s),MemKind(append-all([readers(s) writers(s) readwriters(s)])),UNKNOWN-GENDER) defn mem-exp (p:Symbol,f:Symbol) : val t1 = field-type(type(mem),p) val t2 = field-type(t1,f) WSubField{_,f,t2,UNKNOWN-GENDER} $ WSubField{_,p,t1,UNKNOWN-GENDER} $ mem declare(`reg,name(s),VectorType(data-type(s),depth(s))) initialize-mem(name(s),depth(s),data-type(s)) for r in readers(s) do : val data = mem-exp(r,`data) val addr = mem-exp(r,`addr) val en = mem-exp(r,`en) val clk = mem-exp(r,`clk) declare(`wire,lowered-name(data),type(data)) declare(`wire,lowered-name(addr),type(addr)) declare(`wire,lowered-name(en),type(en)) declare(`wire,lowered-name(clk),type(clk)) ; Read port assign(addr,netlist[addr]) ;Connects value to m.r.addr assign(en,netlist[en]) ;Connects value to m.r.en assign(clk,netlist[clk]) ;Connects value to m.r.clk val addr* = delay(addr,read-latency(s),clk) val en* = delay(en,read-latency(s),clk) val mem-port = WSubAccess(mem,addr*,UnknownType(),UNKNOWN-GENDER) assign(data,mem-port) for w in writers(s) do : val data = mem-exp(w,`data) val addr = mem-exp(w,`addr) val mask = mem-exp(w,`mask) val en = mem-exp(w,`en) val clk = mem-exp(w,`clk) declare(`wire,lowered-name(data),type(data)) declare(`wire,lowered-name(addr),type(addr)) declare(`wire,lowered-name(mask),type(mask)) declare(`wire,lowered-name(en),type(en)) declare(`wire,lowered-name(clk),type(clk)) ; Write port assign(data,netlist[data]) assign(addr,netlist[addr]) assign(mask,netlist[mask]) assign(en,netlist[en]) assign(clk,netlist[clk]) val data* = delay(data,write-latency(s) - 1,clk) val addr* = delay(addr,write-latency(s) - 1,clk) val mask* = delay(mask,write-latency(s) - 1,clk) val en* = delay(en,write-latency(s) - 1,clk) val mem-port = WSubAccess(mem,addr*,UnknownType(),UNKNOWN-GENDER) update(mem-port,data*,clk,AND(en*,mask*)) for rw in readwriters(s) do : val rmode = mem-exp(rw,`rmode) val rdata = mem-exp(rw,`rdata) val data = mem-exp(rw,`data) val mask = mem-exp(rw,`mask) val addr = mem-exp(rw,`addr) val en = mem-exp(rw,`en) val clk = mem-exp(rw,`clk) declare(`wire,lowered-name(rmode),type(rmode)) declare(`wire,lowered-name(rdata),type(rdata)) declare(`wire,lowered-name(data),type(data)) declare(`wire,lowered-name(mask),type(mask)) declare(`wire,lowered-name(addr),type(addr)) declare(`wire,lowered-name(en),type(en)) declare(`wire,lowered-name(clk),type(clk)) ; Assigned to lowered wires of each assign(clk,netlist[clk]) assign(addr,netlist[addr]) assign(data,netlist[data]) assign(addr,netlist[addr]) assign(mask,netlist[mask]) assign(en,netlist[en]) assign(rmode,netlist[rmode]) ; Delay new signals by latency val raddr* = delay(addr,read-latency(s),clk) val waddr* = delay(addr,write-latency(s) - 1,clk) val en* = delay(en,write-latency(s) - 1,clk) val rmod* = delay(rmode,write-latency(s) - 1,clk) val data* = delay(data,write-latency(s) - 1,clk) val mask* = delay(mask,write-latency(s) - 1,clk) ; Write val rmem-port = WSubAccess(mem,raddr*,UnknownType(),UNKNOWN-GENDER) assign(rdata,rmem-port) val wmem-port = WSubAccess(mem,waddr*,UnknownType(),UNKNOWN-GENDER) update(wmem-port,data*,clk,AND(AND(en*,mask*),NOT(rmode))) (s:Begin) : map(build-streams,s) s defn emit-streams () : emit(["module " name(m) "("]) if !empty?(portdefs) : for (x in portdefs, i in 0 to false) do : if i != length(portdefs) - 1 : emit([tab x ","]) else : emit([tab x]) emit([");"]) if !empty?(declares) : for x in declares do : emit([tab x]) if !empty?(instdeclares) : for x in instdeclares do : emit([tab x]) if !empty?(assigns) : for x in assigns do : emit([tab x]) if !empty?(initials) : emit(["`ifndef SYNTHESIS"]) emit([" integer initvar;"]) emit([" initial begin"]) emit([" #0.002;"]) for x in initials do : emit([tab x]) emit([" end"]) emit(["`endif"]) for clk-stream in at-clock do : if !empty?(value(clk-stream)) : emit([tab "always @(posedge " key(clk-stream) ") begin"]) for x in value(clk-stream) do : emit([tab tab x]) emit([tab "end"]) emit(["endmodule"]) build-netlist(body(m)) build-ports() build-streams(body(m)) emit-streams() m defn emit-verilog (with-output:(() -> False) -> False, c:Circuit) : with-output $ fn () : for m in modules(c) do : match(m) : (m:InModule) : emit-verilog(m) (m:ExModule) : false c