diff options
| author | azidar | 2015-12-10 12:27:56 -0800 |
|---|---|---|
| committer | azidar | 2016-01-16 14:28:17 -0800 |
| commit | 0246ab2479724fb0118bb7a25577c71e2a038223 (patch) | |
| tree | e3a5aa22a3712d28b5b094580cd50babd6520e2f /src | |
| parent | be78d49aa01c097978f69a3b022acb2047fdf438 (diff) | |
WIP, hit semantic bug in WSubAccess
Diffstat (limited to 'src')
| -rw-r--r-- | src/main/stanza/compilers.stanza | 2 | ||||
| -rw-r--r-- | src/main/stanza/errors.stanza | 1795 | ||||
| -rw-r--r-- | src/main/stanza/firrtl-test-main.stanza | 2 | ||||
| -rw-r--r-- | src/main/stanza/ir-parser.stanza | 2 | ||||
| -rw-r--r-- | src/main/stanza/ir-utils.stanza | 2 | ||||
| -rw-r--r-- | src/main/stanza/passes.stanza | 59 |
6 files changed, 918 insertions, 944 deletions
diff --git a/src/main/stanza/compilers.stanza b/src/main/stanza/compilers.stanza index 1598be21..ec65bdca 100644 --- a/src/main/stanza/compilers.stanza +++ b/src/main/stanza/compilers.stanza @@ -58,12 +58,12 @@ public defmethod passes (c:StandardVerilog) -> List<Pass> : ;CheckTypes() ;R ExpandAccesses() ;W ExpandConnects() ;W + ;ReplaceIndexers() ResolveKinds() ;W InferTypes() ;R ResolveGenders() ;W ;LowerToGround() ;W ;ExpandIndexedConnects() ;W - ReplaceIndexers() ;InferTypes() ;R ;CheckGenders() ;W ExpandWhens() ;W diff --git a/src/main/stanza/errors.stanza b/src/main/stanza/errors.stanza index 5b0d3864..0aa036e9 100644 --- a/src/main/stanza/errors.stanza +++ b/src/main/stanza/errors.stanza @@ -39,87 +39,92 @@ public defmethod name (b:CheckHighForm) -> String : "High Form Check" public defmethod short-name (b:CheckHighForm) -> String : "high-form-check" var mname = "" +var sinfo! = FileInfo() ;----------------- Errors ------------------------ -defn NotUnique (info:FileInfo, name:Symbol) : +defn NotUnique (name:Symbol) : PassException $ string-join $ - [info ": [module " mname "] Reference " name " does not have a unique name."] + [sinfo! ": [module " mname "] Reference " name " does not have a unique name."] -defn IsPrefix (info:FileInfo, prefix:Symbol) : +defn IsPrefix (prefix:Symbol) : PassException $ string-join $ - [info ": [module " mname "] Symbol " prefix " is a prefix."] + [sinfo! ": [module " mname "] Symbol " prefix " is a prefix."] -defn InvalidLOC (info:FileInfo) : +defn InvalidLOC () : PassException $ string-join $ - [info ": [module " mname "] Invalid connect to an expression that is not a reference or a WritePort."] + [sinfo! ": [module " mname "] Invalid connect to an expression that is not a reference or a WritePort."] -defn NegUInt (info:FileInfo) : +defn NegUInt () : PassException $ string-join $ - [info ": [module " mname "] UIntValue cannot be negative."] + [sinfo! ": [module " mname "] UIntValue cannot be negative."] -defn UndeclaredReference (info:FileInfo, name:Symbol) : +defn UndeclaredReference (name:Symbol) : PassException $ string-join $ - [info ": [module " mname "] Reference " name " is not declared."] + [sinfo! ": [module " mname "] Reference " name " is not declared."] -defn PoisonWithFlip (info:FileInfo, name:Symbol) : +defn PoisonWithFlip (name:Symbol) : PassException $ string-join $ - [info ": [module " mname "] Poison " name " cannot be a bundle type with flips."] + [sinfo! ": [module " mname "] Poison " name " cannot be a bundle type with flips."] -defn MemWithFlip (info:FileInfo, name:Symbol) : +defn MemWithFlip (name:Symbol) : PassException $ string-join $ - [info ": [module " mname "] Memory " name " cannot be a bundle type with flips."] + [sinfo! ": [module " mname "] Memory " name " cannot be a bundle type with flips."] -defn InvalidSubfield (info:FileInfo) : +defn InvalidSubfield () : PassException $ string-join $ - [info ": [module " mname "] Invalid subfield access to non-reference."] + [sinfo! ": [module " mname "] Invalid subfield access to non-reference."] -defn InvalidIndex (info:FileInfo) : +defn InvalidIndex () : PassException $ string-join $ - [info ": [module " mname "] Invalid index access to non-reference."] + [sinfo! ": [module " mname "] Invalid index access to non-reference."] -defn NoTopModule (info:FileInfo, name:Symbol) : +defn InvalidAccess () : PassException $ string-join $ - [info ": A single module must be named " name "."] + [sinfo! ": [module " mname "] Invalid access to non-reference."] + +defn NoTopModule (name:Symbol) : + PassException $ string-join $ + [sinfo! ": A single module must be named " name "."] -defn ModuleNotDefined (info:FileInfo, name:Symbol) : +defn ModuleNotDefined (name:Symbol) : PassException $ string-join $ - [info ": Module " name " is not defined."] + [sinfo! ": Module " name " is not defined."] -defn IncorrectNumArgs (info:FileInfo, op:Symbol, n:Int) : +defn IncorrectNumArgs (op:Symbol, n:Int) : PassException $ string-join $ - [info ": [module " mname "] Primop " op " requires " n " expression arguments."] + [sinfo! ": [module " mname "] Primop " op " requires " n " expression arguments."] -defn IncorrectNumConsts (info:FileInfo, op:Symbol, n:Int) : +defn IncorrectNumConsts (op:Symbol, n:Int) : PassException $ string-join $ - [info ": [module " mname "] Primop " op " requires " n " integer arguments."] + [sinfo! ": [module " mname "] Primop " op " requires " n " integer arguments."] -defn NegWidth (info:FileInfo) : +defn NegWidth () : PassException $ string-join $ - [info ": [module " mname "] Width cannot be negative or zero."] + [sinfo! ": [module " mname "] Width cannot be negative or zero."] -defn NegVecSize (info:FileInfo) : +defn NegVecSize () : PassException $ string-join $ - [info ": [module " mname "] Vector type size cannot be negative."] + [sinfo! ": [module " mname "] Vector type size cannot be negative."] -defn NegMemSize (info:FileInfo) : +defn NegMemSize () : PassException $ string-join $ - [info ": [module " mname "] Memory size cannot be negative or zero."] + [sinfo! ": [module " mname "] Memory size cannot be negative or zero."] -defn IllegalUnknownWidth (info:FileInfo) : +defn IllegalUnknownWidth () : PassException $ string-join $ - [info ": [module " mname "] Widths must be defined for memories and poison nodes."] + [sinfo! ": [module " mname "] Widths must be defined for memories and poison nodes."] -defn BadPrintf (info:FileInfo,x:Char) : +defn BadPrintf (x:Char) : PassException $ string-join $ - [info ": [module " mname "] Bad printf format: \"%" x "\""];" + [sinfo! ": [module " mname "] Bad printf format: \"%" x "\""];" -defn BadPrintfTrailing (info:FileInfo) : +defn BadPrintfTrailing () : PassException $ string-join $ - [info ": [module " mname "] Bad printf format: trailing \"%\""];" + [sinfo! ": [module " mname "] Bad printf format: trailing \"%\""];" -defn BadPrintfIncorrectNum (info:FileInfo) : +defn BadPrintfIncorrectNum () : PassException $ string-join $ - [info ": [module " mname "] Bad printf format: incorrect number of arguments"];" + [sinfo! ": [module " mname "] Bad printf format: incorrect number of arguments"];" ;---------------- Helper Functions -------------- @@ -212,925 +217,877 @@ defn contains?<?T> (c:?T,cs:Streamable<?T>) -> True|False : ; (s:String) : myret(string-join([char(trie) s])) ; false -defn check-high-form-primop (e:DoPrim, errors:Vector<PassException>,info:FileInfo) -> False : - defn correct-num (ne:Int|False,nc:Int) -> False : - if not (ne typeof False) : - if length(args(e)) != ne as Int : add(errors,IncorrectNumArgs(info,to-symbol(op(e)),ne as Int)) - if length(consts(e)) != nc : add(errors,IncorrectNumConsts(info,to-symbol $ op(e),nc)) - - switch {op(e) == _} : - ADD-OP : correct-num(2,0) - SUB-OP : correct-num(2,0) - MUL-OP : correct-num(2,0) - DIV-OP : correct-num(2,0) - MOD-OP : correct-num(2,0) - QUO-OP : correct-num(2,0) - REM-OP : correct-num(2,0) - ADD-WRAP-OP : correct-num(2,0) - SUB-WRAP-OP : correct-num(2,0) - LESS-OP : correct-num(2,0) - LESS-EQ-OP : correct-num(2,0) - GREATER-OP : correct-num(2,0) - GREATER-EQ-OP : correct-num(2,0) - EQUAL-OP : correct-num(2,0) - NEQUAL-OP : correct-num(2,0) - EQUIV-OP : correct-num(2,0) - NEQUIV-OP : correct-num(2,0) - MUX-OP : correct-num(3,0) - PAD-OP : correct-num(1,1) - AS-UINT-OP : correct-num(1,0) - AS-SINT-OP : correct-num(1,0) - DYN-SHIFT-LEFT-OP : correct-num(2,0) - DYN-SHIFT-RIGHT-OP : correct-num(2,0) - SHIFT-LEFT-OP : correct-num(1,1) - SHIFT-RIGHT-OP : correct-num(1,1) - CONVERT-OP : correct-num(1,0) - NEG-OP : correct-num(1,0) - BIT-NOT-OP : correct-num(1,0) - BIT-AND-OP : correct-num(2,0) - BIT-OR-OP : correct-num(2,0) - BIT-XOR-OP : correct-num(2,0) - BIT-AND-REDUCE-OP : correct-num(false,0) - BIT-OR-REDUCE-OP : correct-num(false,0) - BIT-XOR-REDUCE-OP : correct-num(false,0) - CONCAT-OP : correct-num(2,0) - BIT-SELECT-OP : correct-num(1,1) - BITS-SELECT-OP : correct-num(1,2) ;--------------- Check High Form Pass ------------------- public defn check-high-form (c:Circuit) -> Circuit : val errors = Vector<PassException>() - - - defn check-fstring (info:FileInfo,s:String,i:Int) -> False : + defn check-high-form-primop (e:DoPrim) -> False : + defn correct-num (ne:Int|False,nc:Int) -> False : + if not (ne typeof False) : + if length(args(e)) != ne as Int : add(errors,IncorrectNumArgs(to-symbol(op(e)),ne as Int)) + if length(consts(e)) != nc : add(errors,IncorrectNumConsts(to-symbol $ op(e),nc)) + + switch {op(e) == _} : + ADD-OP : correct-num(2,0) + SUB-OP : correct-num(2,0) + MUL-OP : correct-num(2,0) + DIV-OP : correct-num(2,0) + MOD-OP : correct-num(2,0) + QUO-OP : correct-num(2,0) + REM-OP : correct-num(2,0) + ADD-WRAP-OP : correct-num(2,0) + SUB-WRAP-OP : correct-num(2,0) + LESS-OP : correct-num(2,0) + LESS-EQ-OP : correct-num(2,0) + GREATER-OP : correct-num(2,0) + GREATER-EQ-OP : correct-num(2,0) + EQUAL-OP : correct-num(2,0) + NEQUAL-OP : correct-num(2,0) + EQUIV-OP : correct-num(2,0) + NEQUIV-OP : correct-num(2,0) + MUX-OP : correct-num(3,0) + PAD-OP : correct-num(1,1) + AS-UINT-OP : correct-num(1,0) + AS-SINT-OP : correct-num(1,0) + DYN-SHIFT-LEFT-OP : correct-num(2,0) + DYN-SHIFT-RIGHT-OP : correct-num(2,0) + SHIFT-LEFT-OP : correct-num(1,1) + SHIFT-RIGHT-OP : correct-num(1,1) + CONVERT-OP : correct-num(1,0) + NEG-OP : correct-num(1,0) + BIT-NOT-OP : correct-num(1,0) + BIT-AND-OP : correct-num(2,0) + BIT-OR-OP : correct-num(2,0) + BIT-XOR-OP : correct-num(2,0) + BIT-AND-REDUCE-OP : correct-num(false,0) + BIT-OR-REDUCE-OP : correct-num(false,0) + BIT-XOR-REDUCE-OP : correct-num(false,0) + CONCAT-OP : correct-num(2,0) + BIT-SELECT-OP : correct-num(1,1) + BITS-SELECT-OP : correct-num(1,2) + + defn check-fstring (s:String,i:Int) -> False : val valid-formats = "bedxs" var percent = false var ret = true var npercents = 0 for x in s do : if (not contains?(valid-formats,x)) and percent : - add(errors,BadPrintf(info,x)) + add(errors,BadPrintf(x)) if x == '%' : npercents = npercents + 1 percent = x == '%' - if percent : add(errors,BadPrintfTrailing(info)) - if npercents != i : add(errors,BadPrintfIncorrectNum(info)) - - defn check-valid-loc (info:FileInfo,e:Expression) -> False : + if percent : add(errors,BadPrintfTrailing()) + if npercents != i : add(errors,BadPrintfIncorrectNum()) + defn check-valid-loc (e:Expression) -> False : match(e) : (e:UIntValue|SIntValue|DoPrim) : - add(errors,InvalidLOC(info)) + add(errors,InvalidLOC()) (e) : false - - defn check-high-form-w (info:FileInfo,w:Width,unknown-ok?:True|False) -> Width : + defn check-high-form-w (w:Width) -> Width : match(w) : (w:IntWidth) : - if width(w) <= to-long(0) : add(errors,NegWidth(info)) - w - (w:UnknownWidth) : - if unknown-ok? == false : add(errors,IllegalUnknownWidth(info)) + if width(w) <= to-long(0) : add(errors,NegWidth()) w (w) : w - - defn check-high-form-t (info:FileInfo,t:Type,unknown-ok?:True|False) -> Type : - match(map(check-high-form-t{info,_,true},t)) : + defn check-high-form-t (t:Type) -> Type : + match(map(check-high-form-t,t)) : (t:VectorType) : - if size(t) < 0 : add(errors,NegVecSize(info)) + if size(t) < 0 : add(errors,NegVecSize()) (t) : false - map(check-high-form-w{info,_:Width,unknown-ok?},t) - - defn check-high-form-e (info:FileInfo,e:Expression,names:HashTable<Symbol,True>) -> Expression : - match(map(check-high-form-e{info,_,names},e)) : - (e:Ref) : - if not key?(names,name(e)) : - add(errors,UndeclaredReference(info,name(e))) - (e:Subfield) : - match(exp(e)) : - (e:Ref|Subfield|Index) : false - (e) : add(errors,InvalidSubfield(info)) - (e:Index) : - match(exp(e)) : - (e:Ref|Subfield|Index) : false - (e) : add(errors,InvalidIndex(info)) - (e:DoPrim) : check-high-form-primop(e,errors,info) - (e:UIntValue) : false - ;if neg?(value(e)) : add(errors,NegUInt(info)) - (e) : false - map(check-high-form-w{info,_:Width,true},e) - map(check-high-form-t{info,_:Type,true},e) - e - - defn check-high-form-s (s:Stmt,names:HashTable<Symbol,True>,mnames:HashTable<Symbol,True>) -> Stmt : - defn check-name (info:FileInfo,name:Symbol) -> False : - if key?(names,name) : add(errors,NotUnique(info,name)) - map(check-high-form-t{info(s),_:Type,true},s) + map(check-high-form-w,t) - map{check-high-form-s{_,names,mnames},_} $ { - match(s) : ;map(check-high-form-e{info(s),_,names},s)) : - (s:DefWire) : - check-name(info(s),name(s)) - names[name(s)] = true + defn check-high-form-m (m:Module) -> Module : + val names = HashTable<Symbol,True>(symbol-hash) + val mnames = HashTable<Symbol,True>(symbol-hash) + defn check-high-form-e (e:Expression) -> Expression : + defn valid-subexp (e:Expression) -> Expression : + match(e) : + (e:Ref|SubField|SubIndex|SubAccess) : false + (e) : add(errors,InvalidSubfield()) + e + match(map(check-high-form-e,e)) : + (e:Ref) : + if not key?(names,name(e)) : + add(errors,UndeclaredReference(name(e))) + (e:DoPrim) : check-high-form-primop(e) + (e:UIntValue) : false + (e) : map(valid-subexp,e) + map(check-high-form-w,e) + map(check-high-form-t,e) + e + defn check-high-form-s (s:Stmt) -> Stmt : + defn check-name (name:Symbol) -> Symbol : + if key?(names,name) : add(errors,NotUnique(name)) + else : names[name] = true + name + sinfo! = info(s) + map(check-high-form-t,s) + map(check-high-form-e,s) + match(s) : + (s:DefWire|DefRegister|DefNode|Conditionally|Stop|Begin) : false (s:DefPoison) : - check-name(info(s),name(s)) - if has-flip?(type(s)) : add(errors, PoisonWithFlip(info(s), name(s))) - names[name(s)] = true - check-high-form-t(info(s),type(s),false) - (s:DefRegister) : - check-name(info(s),name(s)) - names[name(s)] = true - check-high-form-e(info(s),reset(s),names) - check-high-form-e(info(s),clock(s),names) + if has-flip?(type(s)) : add(errors, PoisonWithFlip(name(s))) + check-high-form-t(type(s)) (s:DefMemory) : - check-name(info(s),name(s)) - names[name(s)] = true - if has-flip?(type(s)) : add(errors, MemWithFlip(info(s), name(s))) - if size(s) <= 0 : add(errors,NegMemSize(info(s))) - check-high-form-t(info(s),type(s),false) - check-high-form-e(info(s),clock(s),names) + if has-flip?(data-type(s)) : add(errors, MemWithFlip(name(s))) + if depth(s) <= 0 : add(errors,NegMemSize()) (s:DefInstance) : - if not contains?(name(module(s) as Ref),map(name,modules(c))) : - add(errors, ModuleNotDefined(info(s),name(module(s) as Ref))) - check-name(info(s),name(s)) - names[name(s)] = true - (s:DefNode) : - check-name(info(s),name(s)) - check-high-form-e(info(s),value(s),names) - names[name(s)] = true - (s:DefAccessor) : - check-name(info(s),name(s)) - check-high-form-e(info(s),index(s),names) - check-high-form-e(info(s),source(s),names) - names[name(s)] = true - (s:Connect) : - 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:Print) : - for x in args(s) do: - check-high-form-e(info(s),x,names) - check-fstring(info(s),string(s),length(args(s))) - (s:BulkConnect) : - 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:OnReset) : - check-high-form-e(info(s),loc(s),names) - check-high-form-e(info(s),exp(s),names) - (s:Conditionally) : - check-high-form-e(info(s),pred(s),names) + if not contains?(module(s),map(name,modules(c))) : + add(errors, ModuleNotDefined(module(s))) + (s:Connect) : check-valid-loc(loc(s)) + (s:Print) : check-fstring(string(s),length(args(s))) + (s:BulkConnect) : check-valid-loc(loc(s)) (s) : false - s }() - defn check-high-form-m (m:Module) -> False : + map(check-name,s) + map(check-high-form-s,s) + mname = name(m) - val names = HashTable<Symbol,True>(symbol-hash) - val mnames = HashTable<Symbol,True>(symbol-hash) for m in modules(c) do : mnames[name(m)] = true for p in ports(m) do : names[name(p)] = true - map(check-high-form-t{info(p),_,true},type(p)) - map(check-high-form-w{info(p),_,true},type(p)) + map(check-high-form-t,type(p)) + map(check-high-form-w,type(p)) match(m) : (m:ExModule) : false - (m:InModule) : check-high-form-s(body(m),names,mnames) - ;match(any-prefixes?(names,to-string(sym),to-string(sym))) : - ;(s:False) : false - ;(s:String) : add(errors,IsPrefix(info,to-symbol(s))) - false + (m:InModule) : check-high-form-s(body(m)) + m var number-top-m = 0 for m in modules(c) do : if name(m) == main(c) : number-top-m = number-top-m + 1 check-high-form-m(m) - if number-top-m != 1 : add(errors,NoTopModule(info!(c),main(c))) - throw(PassExceptions(errors)) when not empty?(errors) - c - -;================= KIND CHECK ========================== -; o Cannot connect directly to a mem ever -; o onreset can only handle a register -; o Cannot use a mem in anything except an accessor, Readport, or Writeport - -public defstruct CheckKinds <: Pass -public defmethod pass (b:CheckKinds) -> (Circuit -> Circuit) : check-kinds -public defmethod name (b:CheckKinds) -> String : "Check Kinds" -public defmethod short-name (b:CheckKinds) -> String : "check-kinds" - -;----------------- Errors --------------------- -defn NotMem (info:FileInfo, name:Symbol) : - PassException $ string-join $ - [info ": [module " mname "] Reference " name " must be a mem."] - -defn IsMem (info:FileInfo, name:Symbol) : - PassException $ string-join $ - [info ": [module " mname "] Reference " name " cannot be a mem."] - -defn OnResetNotReg (info:FileInfo, name:Symbol) : - PassException $ string-join $ - [info ": [module " mname "] Illegal on-reset to non-reg reference " name "."] - -defn AccessVecOrMem (info:FileInfo) : - PassException $ string-join $ - [info ": [module " mname "] Accessors can only access vector-typed components or memories."] - -;----------------- Check Kinds Pass --------------------- -; I may have been overeager in looking for places where mems can't be, as mems are guaranteed to have a vector -; type, and this will get caught in the type check pass -public defn check-kinds (c:Circuit) -> Circuit : - val errors = Vector<PassException>() - defn get-kind (e:Expression) -> Kind : - match(e) : - (e:WRef) : kind(e) - (e:WSubfield) : get-kind(exp(e)) - (e:WIndex) : get-kind(exp(e)) - defn check-not-mem (info:FileInfo,e:Expression) -> False : - do(check-not-mem{info,_},e) - match(e) : - (e:WRef) : if kind(e) == MemKind() : add(errors,IsMem(info,name(e))) - (e:WSubfield) : check-not-mem(info,exp(e)) - (e:WIndex) : check-not-mem(info,exp(e)) - (e) : false - defn check-is-reg (info:FileInfo,e:Expression) -> False : - do(check-is-reg{info,_},e) - match(e) : - (e:WRef) : if kind(e) != RegKind() : add(errors,OnResetNotReg(info,name(e))) - (e:WSubfield) : check-is-reg(info,exp(e)) - (e:WIndex) : check-is-reg(info,exp(e)) - (e) : false - defn check-is-mem (info:FileInfo,e:Expression) -> False : - do(check-is-mem{info,_},e) - match(e) : - (e:WRef) : if kind(e) != MemKind() : add(errors,NotMem(info,name(e))) - (e:WSubfield) : check-is-mem(info,exp(e)) - (e:WIndex) : check-is-mem(info,exp(e)) - (e) : false - - defn check-kinds-s (s:Stmt) -> False : - match(s) : - (s:DefNode) : check-not-mem(info(s),value(s)) - (s:DefAccessor) : - check-not-mem(info(s),index(s)) - if (get-kind(source(s)) != MemKind()) and (not type(source(s)) typeof VectorType) : - println(get-kind(source(s))) - println(type(source(s))) - add(errors,AccessVecOrMem(info(s))) - (s:Conditionally) : check-not-mem(info(s),pred(s)) - (s:Print) : - for x in args(s) do : - check-not-mem(info(s),x) - (s:Connect) : - check-not-mem(info(s),loc(s)) - check-not-mem(info(s),exp(s)) - (s:BulkConnect) : - check-not-mem(info(s),loc(s)) - check-not-mem(info(s),exp(s)) - (s:OnReset) : - check-is-reg(info(s),loc(s)) - check-not-mem(info(s),exp(s)) - (s) : false - do(check-kinds-s,s) - - for m in modules(c) do : - mname = name(m) - match(m) : - (m:ExModule) : false - (m:InModule) : check-kinds-s(body(m)) - throw(PassExceptions(errors)) when not empty?(errors) - c - -;==================== CHECK TYPES ===================== -; o Subfields are only on bundles, before type inference <- need to not error, just do unknown-type -; o Indexes are only on vectors -; o pred in conditionally must be of type UInt -; o enable/index in read/writeports must be UInt -; o node's value cannot be a bundle with a flip in it -; o := has same types -; o 2nd arg in dshr/l must be UInt, in general do primops -; o clock must be ClockType -; o reset must be UInt<1> - -public defstruct CheckTypes <: Pass -public defmethod pass (b:CheckTypes) -> (Circuit -> Circuit) : check-types -public defmethod name (b:CheckTypes) -> String : "Check Types" -public defmethod short-name (b:CheckTypes) -> String : "check-types" - -;----------------- Errors --------------------- -defn SubfieldNotInBundle (info:FileInfo, name:Symbol) : - PassException $ string-join $ - [info ": [module " mname "] Subfield " name " is not in bundle."] - -defn SubfieldOnNonBundle (info:FileInfo, name:Symbol) : - PassException $ string-join $ - [info ": [module " mname "] Subfield " name " is accessed on a non-bundle."] - -defn IndexTooLarge (info:FileInfo, value:Int) : - PassException $ string-join $ - [info ": [module " mname "] Index with value " value " is too large."] - -defn IndexOnNonVector (info:FileInfo) : - PassException $ string-join $ - [info ": [module " mname "] Index illegal on non-vector type."] - -defn IndexNotUInt (info:FileInfo) : - PassException $ string-join $ - [info ": [module " mname "] Index is not of UIntType."] - -defn EnableNotUInt (info:FileInfo) : - PassException $ string-join $ - [info ": [module " mname "] Enable is not of UIntType."] - -defn InvalidConnect (info:FileInfo) : - PassException $ string-join $ - [info ": [module " mname "] Type mismatch."] - -defn PrintfArgNotGround (info:FileInfo) : - PassException $ string-join $ - [info ": [module " mname "] Printf arguments must be either UIntType or SIntType."] - -defn PredNotUInt (info:FileInfo) : - PassException $ string-join $ - [info ": [module " mname "] Predicate not a UIntType."] - -defn OpNotGround (info:FileInfo, op:Symbol) : - PassException $ string-join $ - [info ": [module " mname "] Primop " op " cannot operate on non-ground types."] - -defn OpNotUInt (info:FileInfo, op:Symbol,e:Symbol) : - PassException $ string-join $ - [info ": [module " mname "] Primop " op " requires argument " e " to be a UInt type."] - -defn OpNotAllUInt (info:FileInfo, op:Symbol) : - PassException $ string-join $ - [info ": [module " mname "] Primop " op " requires all arguments to be UInt type."] - -defn OpNotAllSameType (info:FileInfo, op:Symbol) : - PassException $ string-join $ - [info ": [module " mname "] Primop " op " requires all operands to have the same type."] - -defn NodeIllegalFlips (info:FileInfo) : - PassException $ string-join $ - [info ": [module " mname "] Node cannot be a bundle type with flips."] - -defn OnResetIllegalFlips (info:FileInfo) : - PassException $ string-join $ - [info ": [module " mname "] The register in onreset cannot be a bundle type with flips."] - -;---------------- Helper Functions -------------- -defmethod equal? (t1:Type,t2:Type) -> True|False : - match(t1,t2) : - (t1:ClockType,t2:ClockType) : true - (t1:UIntType,t2:UIntType) : true - (t1:SIntType,t2:SIntType) : true - (t1:BundleType,t2:BundleType) : - var same? = true - for (f1 in fields(t1),f2 in fields(t2)) do : - if flip(f1) != flip(f2) : same? = false - if name(f1) != name(f2) : same? = false - if type(f1) != type(f2) : same? = false - same? - (t1:VectorType,t2:VectorType) : - if type(t1) == type(t2) and size(t1) == size(t2) : true - else : false - (t1,t2) : false - -defn ut () -> UIntType : UIntType(UnknownWidth()) -defn st () -> SIntType : SIntType(UnknownWidth()) - -defn check-types-primop (e:DoPrim, errors:Vector<PassException>,info:FileInfo) -> False : - defn all-same-type (ls:List<Expression>) -> False : - var error? = false - for x in ls do : - if type(head(ls)) != type(x) : - error? = true - if error? : add(errors,OpNotAllSameType(info,to-symbol $ op(e))) - defn all-ground (ls:List<Expression>) -> False : - var error? = false - for x in ls do : - if not (type(x) typeof UIntType or type(x) typeof SIntType) : - error? = true - if error? : add(errors,OpNotGround(info,to-symbol $ op(e))) - defn all-uint (ls:List<Expression>) -> False : - var error? = false - for x in ls do : - if not (type(x) typeof UIntType) : - error? = true - if error? : add(errors,OpNotAllUInt(info,to-symbol $ op(e))) - defn is-uint (x:Expression) -> False : - var error? = false - if not (type(x) typeof UIntType) : - error? = true - if error? : add(errors,OpNotUInt(info,to-symbol $ op(e),to-symbol(x))) - - all-ground(args(e)) - - switch {op(e) == _} : - ADD-OP : false - SUB-OP : false - MUL-OP : false - DIV-OP : false - MOD-OP : false - QUO-OP : false - REM-OP : false - ADD-WRAP-OP : false - SUB-WRAP-OP : false - LESS-OP : false - LESS-EQ-OP : false - GREATER-OP : false - GREATER-EQ-OP : false - EQUAL-OP : false - NEQUAL-OP : false - EQUIV-OP : all-same-type(args(e)) - NEQUIV-OP : all-same-type(args(e)) - MUX-OP : - all-same-type(tail(args(e))) - is-uint(head(args(e))) - PAD-OP : false - AS-UINT-OP : false - AS-SINT-OP : false - DYN-SHIFT-LEFT-OP : is-uint(args(e)[1]) - DYN-SHIFT-RIGHT-OP : is-uint(args(e)[1]) - SHIFT-LEFT-OP : false - SHIFT-RIGHT-OP : false - CONVERT-OP : false - NEG-OP : false - BIT-NOT-OP : all-same-type(args(e)) - BIT-AND-OP : all-same-type(args(e)) - BIT-OR-OP : all-same-type(args(e)) - BIT-XOR-OP : all-same-type(args(e)) - BIT-SELECT-OP : false - BITS-SELECT-OP : false - BIT-AND-REDUCE-OP : all-uint(args(e)) - BIT-OR-REDUCE-OP : all-uint(args(e)) - BIT-XOR-REDUCE-OP : all-uint(args(e)) - CONCAT-OP : all-uint(args(e)) - -;----------------- Check Types Pass --------------------- -public defn check-types (c:Circuit) -> Circuit : - val errors = Vector<PassException>() - defn check-types-e (info:FileInfo,e:Expression) -> Expression : - match(map(check-types-e{info,_},e)) : - (e:WRef) : e - (e:WSubfield) : - match(type(exp(e))) : - (t:BundleType) : - val ft = for p in fields(t) find : name(p) == name(e) - if ft == false : add(errors,SubfieldNotInBundle(info,name(e))) - (t) : add(errors,SubfieldOnNonBundle(info,name(e))) - (e:WIndex) : - match(type(exp(e))) : - (t:VectorType) : - if value(e) >= size(t) : add(errors,IndexTooLarge(info,value(e))) - (t) : add(errors,IndexOnNonVector(info)) - (e:DoPrim) : check-types-primop(e,errors,info) - (e:UIntValue|SIntValue) : false - e - - defn bulk-equals? (t1:Type,t2:Type) -> True|False : - match(t1,t2) : - (t1:BundleType,t2:BundleType) : - var same? = true - for (f1 in fields(t1),f2 in fields(t2)) do : - if name(f1) == name(f2) : - if flip(f1) != flip(f2) : same? = false - if not bulk-equals?(type(f1),type(f2)) : same? = false - same? - (t1:ClockType,t2:ClockType) : true - (t1:UIntType,t2:UIntType) : true - (t1:SIntType,t2:SIntType) : true - (t1:VectorType,t2:VectorType) : - if bulk-equals?(type(t1),type(t2)) : true - else : false - (t1,t2) : false - - defn check-types-s (s:Stmt) -> Stmt : - map{check-types-s,_} $ { - match(map(check-types-e{info(s),_},s)) : - (s:Connect) : - if type(loc(s)) != type(exp(s)) : add(errors,InvalidConnect(info(s))) - (s:BulkConnect) : - if not bulk-equals?(type(loc(s)),type(exp(s))) : - add(errors,InvalidConnect(info(s))) - (s: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:Print) : - for x in args(s) do : - if type(x) != ut() and type(x) != st(): - add(errors,PrintfArgNotGround(info(s))) - (s:Conditionally) : - if type(pred(s)) != ut() : add(errors,PredNotUInt(info(s))) - (s:DefNode) : - if has-flip?(type(value(s))) : add(errors,NodeIllegalFlips(info(s))) - (s) : false - s }() - - for m in modules(c) do : - mname = name(m) - match(m) : - (m:ExModule) : false - (m:InModule) : check-types-s(body(m)) - throw(PassExceptions(errors)) when not empty?(errors) - c - -;================= GENDER CHECK ========================== -; o Nodes always male -; o Accessors only have one gender, unless rdwr -; o output/input only one gender -; o correctly check for the base bundle - -public defstruct CheckGenders <: Pass -public defmethod pass (b:CheckGenders) -> (Circuit -> Circuit) : check-genders -public defmethod name (b:CheckGenders) -> String : "Check Genders" -public defmethod short-name (b:CheckGenders) -> String : "check-genders" - -;----------------- Errors --------------------- -defn WrongGender (info:FileInfo,expr:Symbol,wrong:Symbol,right:Symbol) : - PassException $ string-join $ - [info ": [module " mname "] Expression " expr " is used as a " wrong " but can only be used as a " right "."] - -defn InferDirection (info:FileInfo,name:Symbol) : - PassException $ string-join $ - [info ": [module " mname "] Accessor " name " has a direction that requires inference."] - -;---------------- Helper Functions -------------- -defn dir-to-gender (d:PortDirection) -> Gender : - switch {_ == d} : - INPUT : MALE - OUTPUT : FEMALE ;BI-GENDER - -defn gender (s:DefAccessor) -> Gender : - switch {_ == acc-dir(s)} : - READ : MALE - WRITE : FEMALE - INFER : UNKNOWN-GENDER - RDWR : BI-GENDER - -defn as-srcsnk (g:Gender) -> Symbol : - switch {_ == g} : - MALE : `source - FEMALE : `sink - UNKNOWN-GENDER : `unknown - BI-GENDER : `sourceOrSink - -;----------------- Check Genders Pass --------------------- - -public defn check-genders (c:Circuit) -> Circuit : - val errors = Vector<PassException>() - defn get-kind (e:Expression) -> Kind : - match(e) : - (e:WRef) : kind(e) - (e:WSubfield) : get-kind(exp(e)) - (e:WIndex) : get-kind(exp(e)) - (e) : NodeKind() - - defn check-gender (info:FileInfo,genders:HashTable<Symbol,Gender>,e:Expression,desired:Gender) -> False : - val gender = get-gender(e,genders) - val kind* = get-kind(e) - val flip? = - match(type(e)) : - (t:BundleType) : - for f in fields(t) any? : flip(f) == REVERSE - (t) : false - - ;println(e) - ;println(gender) - ;println(desired) - ;println(kind*) - ;println(desired == gender) - ;if gender != desired and gender != BI-GENDER: - switch fn ([x,y]) : gender == x and desired == y : - [MALE, FEMALE] : - add(errors,WrongGender(info,to-symbol(e),as-srcsnk(desired),as-srcsnk(gender))) - [FEMALE, MALE] : - if kind* != PortKind() and kind* != InstanceKind(): - add(errors,WrongGender(info,to-symbol(e),as-srcsnk(desired),as-srcsnk(gender))) - else : false - - defn get-gender (e:Expression,genders:HashTable<Symbol,Gender>) -> Gender : - match(e) : - (e:WRef) : genders[name(e)] - (e:WSubfield) : - val f = {_ as Field} $ for f in fields(type(exp(e)) as BundleType) find : name(f) == name(e) - get-gender(exp(e),genders) * flip(f) - (e:WIndex) : get-gender(exp(e),genders) - (e:DoPrim) : MALE - (e:UIntValue) : MALE - (e:SIntValue) : MALE - - defn check-genders-e (info:FileInfo,e:Expression,genders:HashTable<Symbol,Gender>) -> False : - do(check-genders-e{info,_,genders},e) - match(e) : - (e:WRef) : false - (e:WSubfield) : false - (e:WIndex) : false - (e:DoPrim) : - for e in args(e) do : - check-gender(info,genders,e,MALE) - (e:UIntValue) : false - (e:SIntValue) : false - - defn check-genders-s (s:Stmt,genders:HashTable<Symbol,Gender>) -> False : - do(check-genders-e{info(s),_:Expression,genders},s) - do(check-genders-s{_:Stmt,genders},s) - match(s) : - (s:DefWire) : genders[name(s)] = BI-GENDER - (s:DefPoison) : genders[name(s)] = MALE - (s:DefRegister) : genders[name(s)] = BI-GENDER - (s:DefNode) : - check-gender(info(s),genders,value(s),MALE) - genders[name(s)] = MALE - (s:DefMemory) : genders[name(s)] = BI-GENDER - (s:DefInstance) : genders[name(s)] = MALE - (s:DefAccessor) : - if acc-dir(s) == INFER : add(errors,InferDirection(info(s),name(s))) - check-gender(info(s),genders,index(s),MALE) - check-gender(info(s),genders,source(s),gender(s)) - genders[name(s)] = gender(s) - (s:Connect) : - check-gender(info(s),genders,loc(s),FEMALE) - check-gender(info(s),genders,exp(s),MALE) - (s:Print) : - for x in args(s) do : - check-gender(info(s),genders,x,MALE) - (s:BulkConnect) : - check-gender(info(s),genders,loc(s),FEMALE) - check-gender(info(s),genders,exp(s),MALE) - (s:OnReset) : - check-gender(info(s),genders,loc(s),FEMALE) - check-gender(info(s),genders,exp(s),MALE) - (s:Conditionally) : - check-gender(info(s),genders,pred(s),MALE) - (s:Empty) : false - (s:Stop) : false - (s:Begin) : false - - - for m in modules(c) do : - mname = name(m) - val genders = HashTable<Symbol,Gender>(symbol-hash) - for p in ports(m) do : - genders[name(p)] = dir-to-gender(direction(p)) - match(m) : - (m:ExModule) : false - (m:InModule) : check-genders-s(body(m),genders) - throw(PassExceptions(errors)) when not empty?(errors) - c - -;;================ Initialization Check ================== -; Error on all componenents that are not connected to. - -public defstruct CheckInitialization <: Pass -public defmethod pass (b:CheckInitialization) -> (Circuit -> Circuit) : check-init -public defmethod name (b:CheckInitialization) -> String : "Check Initialization" -public defmethod short-name (b:CheckInitialization) -> String : "check-init" - -;----------------- Errors ------------------------ - -defn RefNotInitialized (info:FileInfo, name:Symbol) : - PassException $ string-join $ - [info ": [module " mname "] Reference " name " is not fully initialized."] - -;------------ Helper Functions ------------- - -;------------ Pass ------------------ - -public defn check-init (c:Circuit) : - val errors = Vector<PassException>() - - defn check-init-m (m:InModule) : - val init? = HashTable<Symbol,FileInfo|True>(symbol-hash) - defn get-name (e:Expression) -> Symbol : - match(e) : - (e:Ref) : name(e) - (e:Subfield) : symbol-join([get-name(exp(e)) `. name(e)]) - (e) : error("Shouldn't be here") - - defn check-init-s (s:Stmt) : - do(check-init-s,s) - match(s) : - (s:DefWire|DefRegister) : init?[name(s)] = info(s) - (s:DefAccessor) : - if acc-dir(s) == WRITE : init?[name(s)] = info(s) - (s:DefInstance) : - for f in fields(type(module(s)) as BundleType) do : - if flip(f) == REVERSE : - init?[symbol-join([name(s) `. name(f)])] = info(s) - (s:Connect) : - init?[get-name(loc(s))] = true - (s) : false - - for p in ports(m) do : - if direction(p) == OUTPUT : - init?[name(p)] = info(p) - - check-init-s(body(m)) - - for x in init? do : - match(value(x)) : - (v:FileInfo) : add(errors, RefNotInitialized(v,key(x))) - (v) : false - - for m in modules(c) do : - mname = name(m) - match(m) : - (m:InModule) : check-init-m(m) - (m) : false - - throw(PassExceptions(errors)) when not empty?(errors) - c - -;================= Width Check ========================== -;AFTER WIDTH INFERENCE -; * No names -; * No Unknowns -; * All widths are positive -; * widths are large enough to contain value - - -public defstruct CheckWidths <: Pass -public defmethod pass (b:CheckWidths) -> (Circuit -> Circuit) : check-width -public defmethod name (b:CheckWidths) -> String : "Width Check" -public defmethod short-name (b:CheckWidths) -> String : "width-check" - -;----------------- Errors ------------------------ - -defn UninferredWidth (info:FileInfo) : - PassException $ string-join $ - [info ": [module " mname "] Uninferred width."] - -defn WidthTooSmall (info:FileInfo,v:String) : - PassException $ string-join $ - [info ": [module " mname "] Width too small for constant " v "."] - -;---------------- Helper Functions -------------- - -;--------------- Check Width Pass ------------------- -public defn check-width (c:Circuit) -> Circuit : - val errors = Vector<PassException>() - - defn check-width-m (m:Module) -> False : - defn check-width-w (info:FileInfo,w:Width) -> Width : - match(w) : - (w:IntWidth) : - if width(w) <= to-long(0) : add(errors,NegWidth(info)) - (w) : - add(errors,UninferredWidth(info)) - w - - defn check-width-e (info:FileInfo,e:Expression) -> Expression : - match(map(check-width-e{info,_},e)) : - (e:UIntValue) : - match(width(e)) : - (w:IntWidth) : - if max(to-long(1),to-long(req-num-bits(value(e)) - 1)) > width(w) : - add(errors,WidthTooSmall(info,to-string(value(e)))) - (w) : add(errors,UninferredWidth(info)) - check-width-w(info,width(e)) - (e:SIntValue) : - match(width(e)) : - (w:IntWidth) : - if to-long(req-num-bits(value(e))) > width(w) : - add(errors,WidthTooSmall(info,to-string(value(e)))) - (w) : add(errors,UninferredWidth(info)) - check-width-w(info,width(e)) - (e:DoPrim) : false - (e) : false - - ;mapr(check-width-w{info,_},type(map(check-width-e{info,_},e))) - e - - defn check-width-s (s:Stmt) -> Stmt : - map(check-width-e{info(s),_},map(check-width-s,s)) - map(mapr{check-width-w{info(s),_},_:Type},s) - - for p in ports(m) do : - mapr(check-width-w{info(p),_},type(p)) - - match(m) : - (m:ExModule) : false - (m:InModule) : check-width-s(body(m)) - false - - for m in modules(c) do : - mname = name(m) - check-width-m(m) - throw(PassExceptions(errors)) when not empty?(errors) - c - - -;================= Low Form Check ========================== -;AFTER LOWERING -; o All things connect to once -; o no reg -; o no accessors -; o only vecs are for memories -; o no bundles (future, will have them for mems) -; o only predicated conditional connects - -public defstruct CheckLowForm <: Pass -public defmethod pass (b:CheckLowForm) -> (Circuit -> Circuit) : check-low-form -public defmethod name (b:CheckLowForm) -> String : "Low Form Check" -public defmethod short-name (b:CheckLowForm) -> String : "low-form-check" - -;----------------- Errors ------------------------ -defn InvalidVec (info:FileInfo,name:Symbol) : - PassException $ string-join $ - [info ": [module " mname "] Expression " name " has an illegal vector type."] - -defn InvalidBundle (info:FileInfo,name:Symbol) : - PassException $ string-join $ - [info ": [module " mname "] Expression " name " has an illegal bundle type."] - -defn NoWhen (info:FileInfo) : - PassException $ string-join $ - [info ": [module " mname "] Illegal when statement. No when statements with multiple statements are allowed in low firrtl."] - -defn SingleAssignment (info:FileInfo,name:Symbol) : - PassException $ string-join $ - [info ": [module " mname "] Illegal assignment to " name ". Wires can only be assigned to once."] - -defn NoOnReset (info:FileInfo) : - PassException $ string-join $ - [info ": [module " mname "] Invalid use of on-reset. No on-resets are allowed in low firrtl."] - -defn NoBulkConnect (info:FileInfo) : - PassException $ string-join $ - [info ": [module " mname "] Invalid use of <>. No <>'s are allowed in low firrtl."] - -;---------------- Helper Functions -------------- - -;--------------- Check Low Form Pass ------------------- -public defn check-low-form (c:Circuit) -> Circuit : - val errors = Vector<PassException>() - - defn check-low-form-t (info:FileInfo,t:Type,name:Symbol) -> False : - match(t) : - (t:VectorType) : add(errors,InvalidVec(info,name)) - (t:BundleType) : add(errors,InvalidBundle(info,name)) - (t) : false - - defn check-low-form-m (m:Module) -> False : - for p in ports(m) do : - check-low-form-t(info(p),type(p),name(p)) - - val assigned? = HashTable<Symbol,True>(symbol-hash) - val insts = Vector<Symbol>() - val mems = Vector<Symbol>() - defn check-correct-exp (info:FileInfo,e:Expression) -> False : - do(check-correct-exp{info,_:Expression},e) - match(e) : - (e:Ref) : - if contains?(insts,name(e)) : - for f in fields(type(e) as BundleType) do : - check-low-form-t(info,type(f),name(e)) - if contains?(mems,name(e)) : - check-low-form-t(info,type(type(e) as VectorType),name(e)) - (e) : false ;check-low-form-t(info,type(e),to-symbol $ to-string(e)) - defn check-low-form-s (s:Stmt) -> False : - match(s) : - (s:DefWire) : - check-low-form-t(info(s),type(s),name(s)) - (s:DefPoison) : - check-low-form-t(info(s),type(s),name(s)) - (s:DefMemory) : - check-low-form-t(info(s),type(s),name(s)) - add(mems,name(s)) - (s:DefInstance) : - for f in fields(type(module(s)) as BundleType) do : - check-low-form-t(info(s),type(f),name(s)) - add(insts,name(s)) - (s:DefNode) : - check-correct-exp(info(s),value(s)) - (s:Print) : - for x in args(s) do : - check-correct-exp(info(s),x) - (s:DefRegister) : false - (s:DefAccessor) : false - (s:Conditionally) : - if (not alt(s) typeof Empty) or (conseq(s) typeof Begin) : add(errors,NoWhen(info(s))) - (s:OnReset) : add(errors,NoOnReset(info(s))) - (s:BulkConnect) : add(errors,NoBulkConnect(info(s))) - (s:Connect) : - check-correct-exp(info(s),exp(s)) - match(loc(s)) : - (e:Ref|Subfield) : - val n* = to-symbol $ to-string $ e - if key?(assigned?,n*) : add(errors,SingleAssignment(info(s),n*)) - else : assigned?[to-symbol $ to-string $ e] = true - (e) : check-correct-exp(info(s),e) - (s:Empty) : false - (s:Stop) : false - (s:Begin) : do(check-low-form-s,s) - - match(m) : - (m:ExModule) : false - (m:InModule) : check-low-form-s(body(m)) - false - - for m in modules(c) do : - mname = name(m) - check-low-form-m(m) + sinfo! = info!(c) + if number-top-m != 1 : add(errors,NoTopModule(main(c))) throw(PassExceptions(errors)) when not empty?(errors) c +;;================= KIND CHECK ========================== +;; o Cannot connect directly to a mem ever +;; o onreset can only handle a register +;; o Cannot use a mem in anything except an accessor, Readport, or Writeport +; +;public defstruct CheckKinds <: Pass +;public defmethod pass (b:CheckKinds) -> (Circuit -> Circuit) : check-kinds +;public defmethod name (b:CheckKinds) -> String : "Check Kinds" +;public defmethod short-name (b:CheckKinds) -> String : "check-kinds" +; +;;----------------- Errors --------------------- +;defn NotMem (info:FileInfo, name:Symbol) : +; PassException $ string-join $ +; [info ": [module " mname "] Reference " name " must be a mem."] +; +;defn IsMem (info:FileInfo, name:Symbol) : +; PassException $ string-join $ +; [info ": [module " mname "] Reference " name " cannot be a mem."] +; +;defn OnResetNotReg (info:FileInfo, name:Symbol) : +; PassException $ string-join $ +; [info ": [module " mname "] Illegal on-reset to non-reg reference " name "."] +; +;defn AccessVecOrMem (info:FileInfo) : +; PassException $ string-join $ +; [info ": [module " mname "] Accessors can only access vector-typed components or memories."] +; +;;----------------- Check Kinds Pass --------------------- +;; I may have been overeager in looking for places where mems can't be, as mems are guaranteed to have a vector +;; type, and this will get caught in the type check pass +;public defn check-kinds (c:Circuit) -> Circuit : +; val errors = Vector<PassException>() +; defn get-kind (e:Expression) -> Kind : +; match(e) : +; (e:WRef) : kind(e) +; (e:WSubfield) : get-kind(exp(e)) +; (e:WIndex) : get-kind(exp(e)) +; defn check-not-mem (info:FileInfo,e:Expression) -> False : +; do(check-not-mem{info,_},e) +; match(e) : +; (e:WRef) : if kind(e) == MemKind() : add(errors,IsMem(info,name(e))) +; (e:WSubfield) : check-not-mem(info,exp(e)) +; (e:WIndex) : check-not-mem(info,exp(e)) +; (e) : false +; defn check-is-reg (info:FileInfo,e:Expression) -> False : +; do(check-is-reg{info,_},e) +; match(e) : +; (e:WRef) : if kind(e) != RegKind() : add(errors,OnResetNotReg(info,name(e))) +; (e:WSubfield) : check-is-reg(info,exp(e)) +; (e:WIndex) : check-is-reg(info,exp(e)) +; (e) : false +; defn check-is-mem (info:FileInfo,e:Expression) -> False : +; do(check-is-mem{info,_},e) +; match(e) : +; (e:WRef) : if kind(e) != MemKind() : add(errors,NotMem(info,name(e))) +; (e:WSubfield) : check-is-mem(info,exp(e)) +; (e:WIndex) : check-is-mem(info,exp(e)) +; (e) : false +; +; defn check-kinds-s (s:Stmt) -> False : +; match(s) : +; (s:DefNode) : check-not-mem(info(s),value(s)) +; (s:DefAccessor) : +; check-not-mem(info(s),index(s)) +; if (get-kind(source(s)) != MemKind()) and (not type(source(s)) typeof VectorType) : +; println(get-kind(source(s))) +; println(type(source(s))) +; add(errors,AccessVecOrMem(info(s))) +; (s:Conditionally) : check-not-mem(info(s),pred(s)) +; (s:Print) : +; for x in args(s) do : +; check-not-mem(info(s),x) +; (s:Connect) : +; check-not-mem(info(s),loc(s)) +; check-not-mem(info(s),exp(s)) +; (s:BulkConnect) : +; check-not-mem(info(s),loc(s)) +; check-not-mem(info(s),exp(s)) +; (s:OnReset) : +; check-is-reg(info(s),loc(s)) +; check-not-mem(info(s),exp(s)) +; (s) : false +; do(check-kinds-s,s) +; +; for m in modules(c) do : +; mname = name(m) +; match(m) : +; (m:ExModule) : false +; (m:InModule) : check-kinds-s(body(m)) +; throw(PassExceptions(errors)) when not empty?(errors) +; c +; +;;==================== CHECK TYPES ===================== +;; o Subfields are only on bundles, before type inference <- need to not error, just do unknown-type +;; o Indexes are only on vectors +;; o pred in conditionally must be of type UInt +;; o enable/index in read/writeports must be UInt +;; o node's value cannot be a bundle with a flip in it +;; o := has same types +;; o 2nd arg in dshr/l must be UInt, in general do primops +;; o clock must be ClockType +;; o reset must be UInt<1> +; +;public defstruct CheckTypes <: Pass +;public defmethod pass (b:CheckTypes) -> (Circuit -> Circuit) : check-types +;public defmethod name (b:CheckTypes) -> String : "Check Types" +;public defmethod short-name (b:CheckTypes) -> String : "check-types" +; +;;----------------- Errors --------------------- +;defn SubfieldNotInBundle (info:FileInfo, name:Symbol) : +; PassException $ string-join $ +; [info ": [module " mname "] Subfield " name " is not in bundle."] +; +;defn SubfieldOnNonBundle (info:FileInfo, name:Symbol) : +; PassException $ string-join $ +; [info ": [module " mname "] Subfield " name " is accessed on a non-bundle."] +; +;defn IndexTooLarge (info:FileInfo, value:Int) : +; PassException $ string-join $ +; [info ": [module " mname "] Index with value " value " is too large."] +; +;defn IndexOnNonVector (info:FileInfo) : +; PassException $ string-join $ +; [info ": [module " mname "] Index illegal on non-vector type."] +; +;defn IndexNotUInt (info:FileInfo) : +; PassException $ string-join $ +; [info ": [module " mname "] Index is not of UIntType."] +; +;defn EnableNotUInt (info:FileInfo) : +; PassException $ string-join $ +; [info ": [module " mname "] Enable is not of UIntType."] +; +;defn InvalidConnect (info:FileInfo) : +; PassException $ string-join $ +; [info ": [module " mname "] Type mismatch."] +; +;defn PrintfArgNotGround (info:FileInfo) : +; PassException $ string-join $ +; [info ": [module " mname "] Printf arguments must be either UIntType or SIntType."] +; +;defn PredNotUInt (info:FileInfo) : +; PassException $ string-join $ +; [info ": [module " mname "] Predicate not a UIntType."] +; +;defn OpNotGround (info:FileInfo, op:Symbol) : +; PassException $ string-join $ +; [info ": [module " mname "] Primop " op " cannot operate on non-ground types."] +; +;defn OpNotUInt (info:FileInfo, op:Symbol,e:Symbol) : +; PassException $ string-join $ +; [info ": [module " mname "] Primop " op " requires argument " e " to be a UInt type."] +; +;defn OpNotAllUInt (info:FileInfo, op:Symbol) : +; PassException $ string-join $ +; [info ": [module " mname "] Primop " op " requires all arguments to be UInt type."] +; +;defn OpNotAllSameType (info:FileInfo, op:Symbol) : +; PassException $ string-join $ +; [info ": [module " mname "] Primop " op " requires all operands to have the same type."] +; +;defn NodeIllegalFlips (info:FileInfo) : +; PassException $ string-join $ +; [info ": [module " mname "] Node cannot be a bundle type with flips."] +; +;defn OnResetIllegalFlips (info:FileInfo) : +; PassException $ string-join $ +; [info ": [module " mname "] The register in onreset cannot be a bundle type with flips."] +; +;;---------------- Helper Functions -------------- +;defmethod equal? (t1:Type,t2:Type) -> True|False : +; match(t1,t2) : +; (t1:ClockType,t2:ClockType) : true +; (t1:UIntType,t2:UIntType) : true +; (t1:SIntType,t2:SIntType) : true +; (t1:BundleType,t2:BundleType) : +; var same? = true +; for (f1 in fields(t1),f2 in fields(t2)) do : +; if flip(f1) != flip(f2) : same? = false +; if name(f1) != name(f2) : same? = false +; if type(f1) != type(f2) : same? = false +; same? +; (t1:VectorType,t2:VectorType) : +; if type(t1) == type(t2) and size(t1) == size(t2) : true +; else : false +; (t1,t2) : false +; +;defn ut () -> UIntType : UIntType(UnknownWidth()) +;defn st () -> SIntType : SIntType(UnknownWidth()) +; +;defn check-types-primop (e:DoPrim, errors:Vector<PassException>,info:FileInfo) -> False : +; defn all-same-type (ls:List<Expression>) -> False : +; var error? = false +; for x in ls do : +; if type(head(ls)) != type(x) : +; error? = true +; if error? : add(errors,OpNotAllSameType(info,to-symbol $ op(e))) +; defn all-ground (ls:List<Expression>) -> False : +; var error? = false +; for x in ls do : +; if not (type(x) typeof UIntType or type(x) typeof SIntType) : +; error? = true +; if error? : add(errors,OpNotGround(info,to-symbol $ op(e))) +; defn all-uint (ls:List<Expression>) -> False : +; var error? = false +; for x in ls do : +; if not (type(x) typeof UIntType) : +; error? = true +; if error? : add(errors,OpNotAllUInt(info,to-symbol $ op(e))) +; defn is-uint (x:Expression) -> False : +; var error? = false +; if not (type(x) typeof UIntType) : +; error? = true +; if error? : add(errors,OpNotUInt(info,to-symbol $ op(e),to-symbol(x))) +; +; all-ground(args(e)) +; +; switch {op(e) == _} : +; ADD-OP : false +; SUB-OP : false +; MUL-OP : false +; DIV-OP : false +; MOD-OP : false +; QUO-OP : false +; REM-OP : false +; ADD-WRAP-OP : false +; SUB-WRAP-OP : false +; LESS-OP : false +; LESS-EQ-OP : false +; GREATER-OP : false +; GREATER-EQ-OP : false +; EQUAL-OP : false +; NEQUAL-OP : false +; EQUIV-OP : all-same-type(args(e)) +; NEQUIV-OP : all-same-type(args(e)) +; MUX-OP : +; all-same-type(tail(args(e))) +; is-uint(head(args(e))) +; PAD-OP : false +; AS-UINT-OP : false +; AS-SINT-OP : false +; DYN-SHIFT-LEFT-OP : is-uint(args(e)[1]) +; DYN-SHIFT-RIGHT-OP : is-uint(args(e)[1]) +; SHIFT-LEFT-OP : false +; SHIFT-RIGHT-OP : false +; CONVERT-OP : false +; NEG-OP : false +; BIT-NOT-OP : all-same-type(args(e)) +; BIT-AND-OP : all-same-type(args(e)) +; BIT-OR-OP : all-same-type(args(e)) +; BIT-XOR-OP : all-same-type(args(e)) +; BIT-SELECT-OP : false +; BITS-SELECT-OP : false +; BIT-AND-REDUCE-OP : all-uint(args(e)) +; BIT-OR-REDUCE-OP : all-uint(args(e)) +; BIT-XOR-REDUCE-OP : all-uint(args(e)) +; CONCAT-OP : all-uint(args(e)) +; +;;----------------- Check Types Pass --------------------- +;public defn check-types (c:Circuit) -> Circuit : +; val errors = Vector<PassException>() +; defn check-types-e (info:FileInfo,e:Expression) -> Expression : +; match(map(check-types-e{info,_},e)) : +; (e:WRef) : e +; (e:WSubfield) : +; match(type(exp(e))) : +; (t:BundleType) : +; val ft = for p in fields(t) find : name(p) == name(e) +; if ft == false : add(errors,SubfieldNotInBundle(info,name(e))) +; (t) : add(errors,SubfieldOnNonBundle(info,name(e))) +; (e:WIndex) : +; match(type(exp(e))) : +; (t:VectorType) : +; if value(e) >= size(t) : add(errors,IndexTooLarge(info,value(e))) +; (t) : add(errors,IndexOnNonVector(info)) +; (e:DoPrim) : check-types-primop(e,errors,info) +; (e:UIntValue|SIntValue) : false +; e +; +; defn bulk-equals? (t1:Type,t2:Type) -> True|False : +; match(t1,t2) : +; (t1:BundleType,t2:BundleType) : +; var same? = true +; for (f1 in fields(t1),f2 in fields(t2)) do : +; if name(f1) == name(f2) : +; if flip(f1) != flip(f2) : same? = false +; if not bulk-equals?(type(f1),type(f2)) : same? = false +; same? +; (t1:ClockType,t2:ClockType) : true +; (t1:UIntType,t2:UIntType) : true +; (t1:SIntType,t2:SIntType) : true +; (t1:VectorType,t2:VectorType) : +; if bulk-equals?(type(t1),type(t2)) : true +; else : false +; (t1,t2) : false +; +; defn check-types-s (s:Stmt) -> Stmt : +; map{check-types-s,_} $ { +; match(map(check-types-e{info(s),_},s)) : +; (s:Connect) : +; if type(loc(s)) != type(exp(s)) : add(errors,InvalidConnect(info(s))) +; (s:BulkConnect) : +; if not bulk-equals?(type(loc(s)),type(exp(s))) : +; add(errors,InvalidConnect(info(s))) +; (s: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:Print) : +; for x in args(s) do : +; if type(x) != ut() and type(x) != st(): +; add(errors,PrintfArgNotGround(info(s))) +; (s:Conditionally) : +; if type(pred(s)) != ut() : add(errors,PredNotUInt(info(s))) +; (s:DefNode) : +; if has-flip?(type(value(s))) : add(errors,NodeIllegalFlips(info(s))) +; (s) : false +; s }() +; +; for m in modules(c) do : +; mname = name(m) +; match(m) : +; (m:ExModule) : false +; (m:InModule) : check-types-s(body(m)) +; throw(PassExceptions(errors)) when not empty?(errors) +; c +; +;;================= GENDER CHECK ========================== +;; o Nodes always male +;; o Accessors only have one gender, unless rdwr +;; o output/input only one gender +;; o correctly check for the base bundle +; +;public defstruct CheckGenders <: Pass +;public defmethod pass (b:CheckGenders) -> (Circuit -> Circuit) : check-genders +;public defmethod name (b:CheckGenders) -> String : "Check Genders" +;public defmethod short-name (b:CheckGenders) -> String : "check-genders" +; +;;----------------- Errors --------------------- +;defn WrongGender (info:FileInfo,expr:Symbol,wrong:Symbol,right:Symbol) : +; PassException $ string-join $ +; [info ": [module " mname "] Expression " expr " is used as a " wrong " but can only be used as a " right "."] +; +;defn InferDirection (info:FileInfo,name:Symbol) : +; PassException $ string-join $ +; [info ": [module " mname "] Accessor " name " has a direction that requires inference."] +; +;;---------------- Helper Functions -------------- +;defn dir-to-gender (d:PortDirection) -> Gender : +; switch {_ == d} : +; INPUT : MALE +; OUTPUT : FEMALE ;BI-GENDER +; +;defn gender (s:DefAccessor) -> Gender : +; switch {_ == acc-dir(s)} : +; READ : MALE +; WRITE : FEMALE +; INFER : UNKNOWN-GENDER +; RDWR : BI-GENDER +; +;defn as-srcsnk (g:Gender) -> Symbol : +; switch {_ == g} : +; MALE : `source +; FEMALE : `sink +; UNKNOWN-GENDER : `unknown +; BI-GENDER : `sourceOrSink +; +;;----------------- Check Genders Pass --------------------- +; +;public defn check-genders (c:Circuit) -> Circuit : +; val errors = Vector<PassException>() +; defn get-kind (e:Expression) -> Kind : +; match(e) : +; (e:WRef) : kind(e) +; (e:WSubfield) : get-kind(exp(e)) +; (e:WIndex) : get-kind(exp(e)) +; (e) : NodeKind() +; +; defn check-gender (info:FileInfo,genders:HashTable<Symbol,Gender>,e:Expression,desired:Gender) -> False : +; val gender = get-gender(e,genders) +; val kind* = get-kind(e) +; val flip? = +; match(type(e)) : +; (t:BundleType) : +; for f in fields(t) any? : flip(f) == REVERSE +; (t) : false +; +; ;println(e) +; ;println(gender) +; ;println(desired) +; ;println(kind*) +; ;println(desired == gender) +; ;if gender != desired and gender != BI-GENDER: +; switch fn ([x,y]) : gender == x and desired == y : +; [MALE, FEMALE] : +; add(errors,WrongGender(info,to-symbol(e),as-srcsnk(desired),as-srcsnk(gender))) +; [FEMALE, MALE] : +; if kind* != PortKind() and kind* != InstanceKind(): +; add(errors,WrongGender(info,to-symbol(e),as-srcsnk(desired),as-srcsnk(gender))) +; else : false +; +; defn get-gender (e:Expression,genders:HashTable<Symbol,Gender>) -> Gender : +; match(e) : +; (e:WRef) : genders[name(e)] +; (e:WSubfield) : +; val f = {_ as Field} $ for f in fields(type(exp(e)) as BundleType) find : name(f) == name(e) +; get-gender(exp(e),genders) * flip(f) +; (e:WIndex) : get-gender(exp(e),genders) +; (e:DoPrim) : MALE +; (e:UIntValue) : MALE +; (e:SIntValue) : MALE +; +; defn check-genders-e (info:FileInfo,e:Expression,genders:HashTable<Symbol,Gender>) -> False : +; do(check-genders-e{info,_,genders},e) +; match(e) : +; (e:WRef) : false +; (e:WSubfield) : false +; (e:WIndex) : false +; (e:DoPrim) : +; for e in args(e) do : +; check-gender(info,genders,e,MALE) +; (e:UIntValue) : false +; (e:SIntValue) : false +; +; defn check-genders-s (s:Stmt,genders:HashTable<Symbol,Gender>) -> False : +; do(check-genders-e{info(s),_:Expression,genders},s) +; do(check-genders-s{_:Stmt,genders},s) +; match(s) : +; (s:DefWire) : genders[name(s)] = BI-GENDER +; (s:DefPoison) : genders[name(s)] = MALE +; (s:DefRegister) : genders[name(s)] = BI-GENDER +; (s:DefNode) : +; check-gender(info(s),genders,value(s),MALE) +; genders[name(s)] = MALE +; (s:DefMemory) : genders[name(s)] = BI-GENDER +; (s:DefInstance) : genders[name(s)] = MALE +; (s:DefAccessor) : +; if acc-dir(s) == INFER : add(errors,InferDirection(info(s),name(s))) +; check-gender(info(s),genders,index(s),MALE) +; check-gender(info(s),genders,source(s),gender(s)) +; genders[name(s)] = gender(s) +; (s:Connect) : +; check-gender(info(s),genders,loc(s),FEMALE) +; check-gender(info(s),genders,exp(s),MALE) +; (s:Print) : +; for x in args(s) do : +; check-gender(info(s),genders,x,MALE) +; (s:BulkConnect) : +; check-gender(info(s),genders,loc(s),FEMALE) +; check-gender(info(s),genders,exp(s),MALE) +; (s:OnReset) : +; check-gender(info(s),genders,loc(s),FEMALE) +; check-gender(info(s),genders,exp(s),MALE) +; (s:Conditionally) : +; check-gender(info(s),genders,pred(s),MALE) +; (s:Empty) : false +; (s:Stop) : false +; (s:Begin) : false +; +; +; for m in modules(c) do : +; mname = name(m) +; val genders = HashTable<Symbol,Gender>(symbol-hash) +; for p in ports(m) do : +; genders[name(p)] = dir-to-gender(direction(p)) +; match(m) : +; (m:ExModule) : false +; (m:InModule) : check-genders-s(body(m),genders) +; throw(PassExceptions(errors)) when not empty?(errors) +; c +; +;;;================ Initialization Check ================== +;; Error on all componenents that are not connected to. +; +;public defstruct CheckInitialization <: Pass +;public defmethod pass (b:CheckInitialization) -> (Circuit -> Circuit) : check-init +;public defmethod name (b:CheckInitialization) -> String : "Check Initialization" +;public defmethod short-name (b:CheckInitialization) -> String : "check-init" +; +;;----------------- Errors ------------------------ +; +;defn RefNotInitialized (info:FileInfo, name:Symbol) : +; PassException $ string-join $ +; [info ": [module " mname "] Reference " name " is not fully initialized."] +; +;;------------ Helper Functions ------------- +; +;;------------ Pass ------------------ +; +;public defn check-init (c:Circuit) : +; val errors = Vector<PassException>() +; +; defn check-init-m (m:InModule) : +; val init? = HashTable<Symbol,FileInfo|True>(symbol-hash) +; defn get-name (e:Expression) -> Symbol : +; match(e) : +; (e:Ref) : name(e) +; (e:Subfield) : symbol-join([get-name(exp(e)) `. name(e)]) +; (e) : error("Shouldn't be here") +; +; defn check-init-s (s:Stmt) : +; do(check-init-s,s) +; match(s) : +; (s:DefWire|DefRegister) : init?[name(s)] = info(s) +; (s:DefAccessor) : +; if acc-dir(s) == WRITE : init?[name(s)] = info(s) +; (s:DefInstance) : +; for f in fields(type(module(s)) as BundleType) do : +; if flip(f) == REVERSE : +; init?[symbol-join([name(s) `. name(f)])] = info(s) +; (s:Connect) : +; init?[get-name(loc(s))] = true +; (s) : false +; +; for p in ports(m) do : +; if direction(p) == OUTPUT : +; init?[name(p)] = info(p) +; +; check-init-s(body(m)) +; +; for x in init? do : +; match(value(x)) : +; (v:FileInfo) : add(errors, RefNotInitialized(v,key(x))) +; (v) : false +; +; for m in modules(c) do : +; mname = name(m) +; match(m) : +; (m:InModule) : check-init-m(m) +; (m) : false +; +; throw(PassExceptions(errors)) when not empty?(errors) +; c +; +;;================= Width Check ========================== +;;AFTER WIDTH INFERENCE +;; * No names +;; * No Unknowns +;; * All widths are positive +;; * widths are large enough to contain value +; +; +;public defstruct CheckWidths <: Pass +;public defmethod pass (b:CheckWidths) -> (Circuit -> Circuit) : check-width +;public defmethod name (b:CheckWidths) -> String : "Width Check" +;public defmethod short-name (b:CheckWidths) -> String : "width-check" +; +;;----------------- Errors ------------------------ +; +;defn UninferredWidth (info:FileInfo) : +; PassException $ string-join $ +; [info ": [module " mname "] Uninferred width."] +; +;defn WidthTooSmall (info:FileInfo,v:String) : +; PassException $ string-join $ +; [info ": [module " mname "] Width too small for constant " v "."] +; +;;---------------- Helper Functions -------------- +; +;;--------------- Check Width Pass ------------------- +;public defn check-width (c:Circuit) -> Circuit : +; val errors = Vector<PassException>() +; +; defn check-width-m (m:Module) -> False : +; defn check-width-w (info:FileInfo,w:Width) -> Width : +; match(w) : +; (w:IntWidth) : +; if width(w) <= to-long(0) : add(errors,NegWidth(info)) +; (w) : +; add(errors,UninferredWidth(info)) +; w +; +; defn check-width-e (info:FileInfo,e:Expression) -> Expression : +; match(map(check-width-e{info,_},e)) : +; (e:UIntValue) : +; match(width(e)) : +; (w:IntWidth) : +; if max(to-long(1),to-long(req-num-bits(value(e)) - 1)) > width(w) : +; add(errors,WidthTooSmall(info,to-string(value(e)))) +; (w) : add(errors,UninferredWidth(info)) +; check-width-w(info,width(e)) +; (e:SIntValue) : +; match(width(e)) : +; (w:IntWidth) : +; if to-long(req-num-bits(value(e))) > width(w) : +; add(errors,WidthTooSmall(info,to-string(value(e)))) +; (w) : add(errors,UninferredWidth(info)) +; check-width-w(info,width(e)) +; (e:DoPrim) : false +; (e) : false +; +; ;mapr(check-width-w{info,_},type(map(check-width-e{info,_},e))) +; e +; +; defn check-width-s (s:Stmt) -> Stmt : +; map(check-width-e{info(s),_},map(check-width-s,s)) +; map(mapr{check-width-w{info(s),_},_:Type},s) +; +; for p in ports(m) do : +; mapr(check-width-w{info(p),_},type(p)) +; +; match(m) : +; (m:ExModule) : false +; (m:InModule) : check-width-s(body(m)) +; false +; +; for m in modules(c) do : +; mname = name(m) +; check-width-m(m) +; throw(PassExceptions(errors)) when not empty?(errors) +; c +; +; +;;================= Low Form Check ========================== +;;AFTER LOWERING +;; o All things connect to once +;; o no reg +;; o no accessors +;; o only vecs are for memories +;; o no bundles (future, will have them for mems) +;; o only predicated conditional connects +; +;public defstruct CheckLowForm <: Pass +;public defmethod pass (b:CheckLowForm) -> (Circuit -> Circuit) : check-low-form +;public defmethod name (b:CheckLowForm) -> String : "Low Form Check" +;public defmethod short-name (b:CheckLowForm) -> String : "low-form-check" +; +;;----------------- Errors ------------------------ +;defn InvalidVec (info:FileInfo,name:Symbol) : +; PassException $ string-join $ +; [info ": [module " mname "] Expression " name " has an illegal vector type."] +; +;defn InvalidBundle (info:FileInfo,name:Symbol) : +; PassException $ string-join $ +; [info ": [module " mname "] Expression " name " has an illegal bundle type."] +; +;defn NoWhen (info:FileInfo) : +; PassException $ string-join $ +; [info ": [module " mname "] Illegal when statement. No when statements with multiple statements are allowed in low firrtl."] +; +;defn SingleAssignment (info:FileInfo,name:Symbol) : +; PassException $ string-join $ +; [info ": [module " mname "] Illegal assignment to " name ". Wires can only be assigned to once."] +; +;defn NoOnReset (info:FileInfo) : +; PassException $ string-join $ +; [info ": [module " mname "] Invalid use of on-reset. No on-resets are allowed in low firrtl."] +; +;defn NoBulkConnect (info:FileInfo) : +; PassException $ string-join $ +; [info ": [module " mname "] Invalid use of <>. No <>'s are allowed in low firrtl."] +; +;;---------------- Helper Functions -------------- +; +;;--------------- Check Low Form Pass ------------------- +;public defn check-low-form (c:Circuit) -> Circuit : +; val errors = Vector<PassException>() +; +; defn check-low-form-t (info:FileInfo,t:Type,name:Symbol) -> False : +; match(t) : +; (t:VectorType) : add(errors,InvalidVec(info,name)) +; (t:BundleType) : add(errors,InvalidBundle(info,name)) +; (t) : false +; +; defn check-low-form-m (m:Module) -> False : +; for p in ports(m) do : +; check-low-form-t(info(p),type(p),name(p)) +; +; val assigned? = HashTable<Symbol,True>(symbol-hash) +; val insts = Vector<Symbol>() +; val mems = Vector<Symbol>() +; defn check-correct-exp (info:FileInfo,e:Expression) -> False : +; do(check-correct-exp{info,_:Expression},e) +; match(e) : +; (e:Ref) : +; if contains?(insts,name(e)) : +; for f in fields(type(e) as BundleType) do : +; check-low-form-t(info,type(f),name(e)) +; if contains?(mems,name(e)) : +; check-low-form-t(info,type(type(e) as VectorType),name(e)) +; (e) : false ;check-low-form-t(info,type(e),to-symbol $ to-string(e)) +; defn check-low-form-s (s:Stmt) -> False : +; match(s) : +; (s:DefWire) : +; check-low-form-t(info(s),type(s),name(s)) +; (s:DefPoison) : +; check-low-form-t(info(s),type(s),name(s)) +; (s:DefMemory) : +; check-low-form-t(info(s),type(s),name(s)) +; add(mems,name(s)) +; (s:DefInstance) : +; for f in fields(type(module(s)) as BundleType) do : +; check-low-form-t(info(s),type(f),name(s)) +; add(insts,name(s)) +; (s:DefNode) : +; check-correct-exp(info(s),value(s)) +; (s:Print) : +; for x in args(s) do : +; check-correct-exp(info(s),x) +; (s:DefRegister) : false +; (s:DefAccessor) : false +; (s:Conditionally) : +; if (not alt(s) typeof Empty) or (conseq(s) typeof Begin) : add(errors,NoWhen(info(s))) +; (s:OnReset) : add(errors,NoOnReset(info(s))) +; (s:BulkConnect) : add(errors,NoBulkConnect(info(s))) +; (s:Connect) : +; check-correct-exp(info(s),exp(s)) +; match(loc(s)) : +; (e:Ref|Subfield) : +; val n* = to-symbol $ to-string $ e +; if key?(assigned?,n*) : add(errors,SingleAssignment(info(s),n*)) +; else : assigned?[to-symbol $ to-string $ e] = true +; (e) : check-correct-exp(info(s),e) +; (s:Empty) : false +; (s:Stop) : false +; (s:Begin) : do(check-low-form-s,s) +; +; match(m) : +; (m:ExModule) : false +; (m:InModule) : check-low-form-s(body(m)) +; false +; +; for m in modules(c) do : +; mname = name(m) +; check-low-form-m(m) +; throw(PassExceptions(errors)) when not empty?(errors) +; c +; diff --git a/src/main/stanza/firrtl-test-main.stanza b/src/main/stanza/firrtl-test-main.stanza index c1876dbb..b429ecfb 100644 --- a/src/main/stanza/firrtl-test-main.stanza +++ b/src/main/stanza/firrtl-test-main.stanza @@ -10,7 +10,7 @@ #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") diff --git a/src/main/stanza/ir-parser.stanza b/src/main/stanza/ir-parser.stanza index 896eed6f..94cc1a6a 100644 --- a/src/main/stanza/ir-parser.stanza +++ b/src/main/stanza/ir-parser.stanza @@ -274,8 +274,6 @@ defsyntax firrtl : val read-latency = grab1({_ typeof ReadLatency},"read-latency") val depth = grab1({_ typeof Depth},"depth") val dt = grab1({_ typeof DataType},"data type") - println("Parser!") - println(dt) DefMemory(first-info(form),name,dt,depth,write-latency,read-latency,readers,writers,readwriters) 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) diff --git a/src/main/stanza/ir-utils.stanza b/src/main/stanza/ir-utils.stanza index fdd22acb..a0942d50 100644 --- a/src/main/stanza/ir-utils.stanza +++ b/src/main/stanza/ir-utils.stanza @@ -319,7 +319,7 @@ defmethod print (o:OutputStream, c:Stmt) : (c:Empty) : print(o, "skip") (c:Stop) : - print-all(o, ["stop(" ret(c) ", " clk(c) ", " en(c) ")"]) + print-all(o, ["stop(" clk(c) ", " en(c) ", " ret(c) ")"]) (c:Print) : print-all(o, ["printf(" clk(c) ", " en(c) ", "]) ;" print-all(o, join(List(escape(string(c)),args(c)), ", ")) diff --git a/src/main/stanza/passes.stanza b/src/main/stanza/passes.stanza index 4f219def..143f8067 100644 --- a/src/main/stanza/passes.stanza +++ b/src/main/stanza/passes.stanza @@ -5,12 +5,12 @@ defpackage firrtl/passes : import firrtl/ir-utils import firrtl/primops import firrtl-main - ;import firrtl/errors + import firrtl/errors import bigint2 ;============== Pass List ================ public val standard-passes = to-list $ [ - ;CheckHighForm() + CheckHighForm() ;TempElimination() ToWorkingIR() ResolveKinds() @@ -843,23 +843,38 @@ defn expand-vector (e:Expression,g:Gender) -> List<Expression> : 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-s (s:Stmt) -> Stmt : - map{expand-s,_} $ map(expand-e,s) + defn expand-m (m:InModule) -> InModule : + val sh = get-sym-hash(m,keys(v-keywords)) + defn expand-s (s:Stmt) -> Stmt : + val stmts = Vector<Stmt>() + defn when-chain (exps:List<Expression>,e:Expression,index:Expression,to?:True|False) : + for (x in exps,i in 0 to length(exps)) do : + if to? : + add(stmts,Conditionally(info(s),EQV(uint(i),index),Connect(info(s),x,e),Empty())) + else : + add(stmts,Conditionally(info(s),EQV(uint(i),index),Connect(info(s),e,x),Empty())) + defn expand-e (e:Expression) -> Expression : + match(map(expand-e,e)) : + (e:WSubAccess) : + val n = firrtl-gensym(`GEN,sh) + add(stmts,DefWire(info(s),n,type(e))) + val ls = expand-vector(exp(e),gender(e)) + val e* = WRef(n,type(e),kind(e),gender(e)) + when-chain(ls,e*,index(e),gender(e) == FEMALE) + e* + (e) : e + val s* = map(expand-e,s) + add(stmts,s*) + map{expand-s,_} $ Begin(to-list(stmts)) + + 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) : - InModule(info(m),name(m),ports(m),expand-s(body(m))) + (m:InModule) : expand-m(m) ;================ EXPAND CONNECTS ================== @@ -981,8 +996,12 @@ defn expand-connects (c:Circuit) -> Circuit : println-all(["get-point: " get-point(e)]) exp-lib[name(root-ref(e))][get-point(e) + point] (e:WIndexer) : + println-all(["lib: " exp-lib[name(root-ref(e))]]) + println-all(["get-point: " get-point(e)]) val exps* = for e* in exps(e) map : expand-e(e*,point) + println-all(["exps: " exps*]) + println("HERE!!!") WIndexer(exps*,index(e),type(exps*[0]),gender(exps*[0])) (e:DoPrim) : e (e) : e @@ -1045,17 +1064,16 @@ public defn replace-indexer (c:Circuit) -> Circuit : 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:WIndexer) : mux-chain(exps(e),0,index(e)) (e) : e defn replace-s (s:Stmt) -> Stmt : - match(map(replace-e,s)) : + match(s) : (s:Connect) : + val exp* = replace-e(exp(s)) match(loc(s)) : - (e:WIndexer) : when-chain(exps(e),exp(s),index(e),info(s)) + (e:WIndexer) : when-chain(exps(e),exp*,index(e),info(s)) (e) : s - (s) : map(replace-s, s) + (s) : map(replace-s, map(replace-e,s)) Circuit{info(c),_,main(c)} $ for m in modules(c) map : match(m) : @@ -1997,7 +2015,8 @@ defn lowered-name (e:Expression) -> Symbol : defn root-ref (e:Expression) -> WRef : match(e) : (e:WRef) : e - (e:WSubField|WSubIndex) : root-ref(exp(e)) + (e:WSubField|WSubIndex|WSubAccess) : root-ref(exp(e)) + (e:WIndexer) : root-ref(exps(e)[0]) ;------------- Pass ------------------ |
