aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorazidar2015-12-10 12:27:56 -0800
committerazidar2016-01-16 14:28:17 -0800
commit0246ab2479724fb0118bb7a25577c71e2a038223 (patch)
treee3a5aa22a3712d28b5b094580cd50babd6520e2f
parentbe78d49aa01c097978f69a3b022acb2047fdf438 (diff)
WIP, hit semantic bug in WSubAccess
-rw-r--r--src/main/stanza/compilers.stanza2
-rw-r--r--src/main/stanza/errors.stanza1795
-rw-r--r--src/main/stanza/firrtl-test-main.stanza2
-rw-r--r--src/main/stanza/ir-parser.stanza2
-rw-r--r--src/main/stanza/ir-utils.stanza2
-rw-r--r--src/main/stanza/passes.stanza59
-rw-r--r--test/features/InitializeVec.fir9
-rw-r--r--test/features/SeqMem.fir42
-rw-r--r--test/features/Stop.fir15
-rw-r--r--test/features/TwoClocks.fir9
10 files changed, 965 insertions, 972 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 ------------------
diff --git a/test/features/InitializeVec.fir b/test/features/InitializeVec.fir
index ef6400a0..1cc44daf 100644
--- a/test/features/InitializeVec.fir
+++ b/test/features/InitializeVec.fir
@@ -1,5 +1,5 @@
; RUN: firrtl -i %s -o %s.v -X verilog -p c 2>&1 | tee %s.out | FileCheck %s
-; XFAIL: *
+
;CHECK: Done!
circuit Tst :
module Tst :
@@ -16,7 +16,6 @@ circuit Tst :
outs[3].valid <= UInt<1>(0)
outs[3].bits <= UInt<1>(0)
in.ready <= UInt<1>(1)
- infer accessor out = outs[in.bits]
- when out.ready :
- out.bits <= UInt<7>(99)
- out.valid <= UInt<1>(1)
+ when outs[in.bits].ready :
+ outs[in.bits].bits <= UInt<7>(99)
+ outs[in.bits].valid <= UInt<1>(1)
diff --git a/test/features/SeqMem.fir b/test/features/SeqMem.fir
index 354bd8de..d97435af 100644
--- a/test/features/SeqMem.fir
+++ b/test/features/SeqMem.fir
@@ -10,15 +10,37 @@ circuit Top :
i0 <= UInt(10)
- cmem m-com : UInt<128>[32], clk
- infer accessor r-com = m-com[i]
- infer accessor w-com = m-com[i]
- j <= r-com
- w-com <= j
+ mem m-com :
+ data-type => UInt<128>
+ depth => 32
+ reader => r
+ writer => w
+ read-latency => 0
+ write-latency => 1
+ m-com.r.addr <= i
+ m-com.r.en <= UInt(1)
+ m-com.r.clk <= clk
+ m-com.w.addr <= i
+ m-com.w.mask <= UInt(1)
+ m-com.w.en <= UInt(1)
+ m-com.w.clk <= clk
+ j <= m-com.r.data
+ m-com.w.data <= j
- smem m-seq : UInt<128>[32], clk
- infer accessor r-seq = m-seq[i]
- infer accessor w-seq = m-seq[i]
- j <= r-seq
- w-seq <= j
+ mem m-seq :
+ data-type => UInt<128>
+ depth => 32
+ reader => r
+ writer => w
+ read-latency => 1
+ write-latency => 1
+ m-seq.r.addr <= i
+ m-seq.r.en <= UInt(1)
+ m-seq.r.clk <= clk
+ m-seq.w.addr <= i
+ m-seq.w.mask <= UInt(1)
+ m-seq.w.en <= UInt(1)
+ m-seq.w.clk <= clk
+ j <= m-seq.r.data
+ m-seq.w.data <= j
diff --git a/test/features/Stop.fir b/test/features/Stop.fir
index 16e25416..d0957324 100644
--- a/test/features/Stop.fir
+++ b/test/features/Stop.fir
@@ -1,6 +1,6 @@
; RUN: firrtl -i %s -o %s.v -X verilog -p c 2>&1 | tee %s.out | FileCheck %s
-;CHECK: Lower To Ground
+;CHECK: Expand Whens
circuit Top :
module Top :
@@ -8,14 +8,13 @@ circuit Top :
input q : UInt<1>
input clk : Clock
when p :
- stop(clk,0)
+ stop(clk,UInt(1),0)
when q :
- stop(clk,1)
- stop(clk,3)
-
-;CHECK: when p : stop(clk, 0)
-;CHECK: when q : stop(clk, 1)
-;CHECK: stop(clk, 3)
+ stop(clk,UInt(1),1)
+ stop(clk,UInt(1),3)
+;CHECK: stop(clk, and(p, UInt("h1")), 0)
+;CHECK: stop(clk, and(q, UInt("h1")), 1)
+;CHECK: stop(clk, UInt("h1"), 3)
;CHECK: Done!
diff --git a/test/features/TwoClocks.fir b/test/features/TwoClocks.fir
index f68a2769..6562d3e1 100644
--- a/test/features/TwoClocks.fir
+++ b/test/features/TwoClocks.fir
@@ -5,15 +5,14 @@ circuit Top :
input clk2 : Clock
input reset1 : UInt<1>
input reset2 : UInt<1>
- reg src : UInt<10>, clk1, reset1
- reg sink : UInt<10>, clk2, reset2
+ reg src : UInt<10>, clk1, reset1, UInt(0)
+ reg sink : UInt<10>, clk2, reset2, UInt(0)
- onreset src <= UInt(0)
src <= addw(src,UInt(1))
- reg sync_A : UInt<10>, clk2, reset2
+ reg sync_A : UInt<10>, clk2, reset2, UInt(0)
sync_A <= src
- reg sync_B : UInt<10>, clk2, reset2
+ reg sync_B : UInt<10>, clk2, reset2, UInt(0)
sync_B <= sync_A
sink <= sync_B