aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/main/stanza/compilers.stanza56
-rw-r--r--src/main/stanza/errors.stanza232
-rw-r--r--src/main/stanza/passes.stanza8
-rw-r--r--test/errors/high-form/NegWidth.fir2
-rw-r--r--test/errors/width/NegWidth.fir9
-rw-r--r--test/errors/width/SmallWidth.fir13
-rw-r--r--test/errors/width/UninferredWidth.fir12
7 files changed, 210 insertions, 122 deletions
diff --git a/src/main/stanza/compilers.stanza b/src/main/stanza/compilers.stanza
index eb0a36c4..b9a3028a 100644
--- a/src/main/stanza/compilers.stanza
+++ b/src/main/stanza/compilers.stanza
@@ -32,6 +32,7 @@ public defmethod passes (c:StandardFlo) -> List<Pass> :
Inline()
SplitExp()
ToRealIR()
+ CheckWidths()
;RemoveSpecialChars()
CheckHighForm()
CheckLowForm()
@@ -42,34 +43,33 @@ public defstruct StandardVerilog <: Compiler :
with-output : (() -> False) -> False with: (as-method => true)
public defmethod passes (c:StandardVerilog) -> List<Pass> :
to-list $ [
- RemoveSpecialChars()
- RemoveScopes()
- CheckHighForm()
- TempElimination()
- ToWorkingIR()
- ;; MakeExplicitReset()
- ResolveKinds()
- CheckKinds()
- InferTypes()
- CheckTypes()
- ResolveGenders()
- CheckGenders()
- ExpandAccessors()
- LowerToGround()
- ExpandIndexedConnects()
- InferTypes()
- CheckGenders()
- ExpandWhens()
- InferWidths()
- ;Pad()
- ConstProp()
- SplitExp()
- ToRealIR()
- ;RemoveSpecialChars()
- CheckHighForm()
- CheckLowForm()
- CheckInitialization()
- Verilog(with-output(c))
+ RemoveSpecialChars() ;R
+ RemoveScopes() ;R
+ CheckHighForm() ;R
+ TempElimination() ;R
+ ToWorkingIR() ;R -> W
+ ResolveKinds() ;W
+ CheckKinds() ;W
+ InferTypes() ;R
+ CheckTypes() ;R
+ ResolveGenders() ;W
+ CheckGenders() ;W
+ ExpandAccessors() ;W
+ LowerToGround() ;W
+ ExpandIndexedConnects() ;W
+ InferTypes() ;R
+ CheckGenders() ;W
+ ExpandWhens() ;W
+ InferWidths() ;R
+ Pad() ;R
+ ConstProp() ;R
+ SplitExp() ;R
+ ToRealIR() ;W -> R
+ CheckWidths() ;R
+ CheckHighForm() ;R
+ CheckLowForm() ;R
+ CheckInitialization() ;R
+ Verilog(with-output(c)) ;R
]
diff --git a/src/main/stanza/errors.stanza b/src/main/stanza/errors.stanza
index 77e48263..72535242 100644
--- a/src/main/stanza/errors.stanza
+++ b/src/main/stanza/errors.stanza
@@ -16,13 +16,6 @@ defpackage firrtl/errors :
; * Only modules in circuit (no statements or expressions) <- parser
; * Module must be a reference in inst declaration
-;AFTER WIDTH INFERENCE
-; o No names
-; o No Unknowns
-; o All widths are positive
-; o pad's width is greater than value's width
-; o widths are large enough to contain value
-
;AFTER ??????
; o No combinational loops
@@ -92,10 +85,6 @@ defn ModuleNotDefined (info:FileInfo, name:Symbol) :
PassException $ string-join $
[info ": Module " name " is not defined."]
-;defn WrongReset (info:FileInfo, name:Symbol) :
-; PassException $ string-join $
-; [info ": Module " name " has a reset that is not of type UInt<1>."]
-
defn IncorrectNumArgs (info:FileInfo, op:Symbol, n:Int) :
PassException $ string-join $
[info ": [module " mname "] Primop " op " requires " n " expression arguments."]
@@ -106,7 +95,7 @@ defn IncorrectNumConsts (info:FileInfo, op:Symbol, n:Int) :
defn NegWidth (info:FileInfo) :
PassException $ string-join $
- [info ": [module " mname "] Width cannot be negative."]
+ [info ": [module " mname "] Width cannot be negative or zero."]
defn NegVecSize (info:FileInfo) :
PassException $ string-join $
@@ -264,7 +253,7 @@ public defn check-high-form (c:Circuit) -> Circuit :
defn check-high-form-w (info:FileInfo,w:Width,unknown-ok?:True|False) -> Width :
match(w) :
(w:IntWidth) :
- if width(w) < 0 : add(errors,NegWidth(info))
+ if width(w) <= 0 : add(errors,NegWidth(info))
w
(w:UnknownWidth) :
if unknown-ok? == false : add(errors,IllegalUnknownWidth(info))
@@ -363,15 +352,6 @@ public defn check-high-form (c:Circuit) -> Circuit :
mnames[name(m)] = true
for p in ports(m) do :
names[name(p)] = true
- ;if name(p) == `reset :
- ; if direction(p) == OUTPUT :
- ; add(errors,WrongReset(info!(m),name(m)))
- ; else :
- ; if type(p) typeof UIntType :
- ; if width(type(p) as UIntType) != IntWidth(1) :
- ; add(errors,WrongReset(info!(m),name(m)))
- ; else :
- ; add(errors,WrongReset(info!(m),name(m)))
map(check-high-form-t{info(p),_,true},type(p))
map(check-high-form-w{info(p),_,true},type(p))
@@ -466,7 +446,6 @@ public defn check-kinds (c:Circuit) -> Circuit :
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
@@ -833,6 +812,146 @@ public defn check-genders (c:Circuit) -> Circuit :
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) <= 0 : add(errors,NegWidth(info))
+ (w:LongWidth) :
+ 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|SIntValue) :
+ match(width(e)) :
+ (w:IntWidth) :
+ if num-bits(value(e)) > width(w) :
+ add(errors,WidthTooSmall(info,to-string(value(e))))
+ (w:LongWidth) :
+ if to-long(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
@@ -944,70 +1063,3 @@ public defn check-low-form (c:Circuit) -> Circuit :
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
-
-
-
-
diff --git a/src/main/stanza/passes.stanza b/src/main/stanza/passes.stanza
index bf2e27bf..5c09b034 100644
--- a/src/main/stanza/passes.stanza
+++ b/src/main/stanza/passes.stanza
@@ -2049,9 +2049,11 @@ defn reduce-var-widths (c:Circuit,h:HashTable<Symbol,Width>) -> Circuit :
defn solve (w:Width) -> False|Long :
match(w) :
(w:VarWidth) :
- val w* = h[name(w)]
- if w* typeof VarWidth : false
- else : solve(w*)
+ val w* = get?(h,name(w),false)
+ match(w*) :
+ (w:VarWidth) : false
+ (w:False) : false
+ (w) : solve(w as Width)
(w:MaxWidth) : apply-l(map(solve,args(w)),max)
(w:PlusWidth) : apply(solve(arg1(w)),solve(arg2(w)),{plus(_,_)})
(w:MinusWidth) : apply(solve(arg1(w)),solve(arg2(w)),{minus(_,_)})
diff --git a/test/errors/high-form/NegWidth.fir b/test/errors/high-form/NegWidth.fir
index 9b055228..1eb54a34 100644
--- a/test/errors/high-form/NegWidth.fir
+++ b/test/errors/high-form/NegWidth.fir
@@ -1,5 +1,5 @@
; RUN: firrtl -i %s -o %s.v -X verilog -p c 2>&1 | tee %s.out | FileCheck %s
-; CHECK: Width cannot be negative.
+; CHECK: Width cannot be negative or zero.
circuit Top :
module Top :
diff --git a/test/errors/width/NegWidth.fir b/test/errors/width/NegWidth.fir
new file mode 100644
index 00000000..5d5bbf43
--- /dev/null
+++ b/test/errors/width/NegWidth.fir
@@ -0,0 +1,9 @@
+; RUN: firrtl -i %s -o %s.v -X verilog -p ciwT 2>&1 | tee %s.out | FileCheck %s
+; CHECK: Width cannot be negative or zero.
+
+circuit Top :
+ module Top :
+ output y : UInt
+
+ wire x : UInt<2>
+ y := shr(x,4)
diff --git a/test/errors/width/SmallWidth.fir b/test/errors/width/SmallWidth.fir
new file mode 100644
index 00000000..9e26699e
--- /dev/null
+++ b/test/errors/width/SmallWidth.fir
@@ -0,0 +1,13 @@
+; RUN: firrtl -i %s -o %s.v -X verilog -p ciwT 2>&1 | tee %s.out | FileCheck %s
+; CHECK: Width too small for constant "h121".
+; CHECK: Width too small for constant "h13333".
+
+circuit Top :
+ module Top :
+ output z : UInt
+
+ z := add(UInt<4>("h121"),UInt<3>("h13333"))
+
+
+
+
diff --git a/test/errors/width/UninferredWidth.fir b/test/errors/width/UninferredWidth.fir
new file mode 100644
index 00000000..d4cff841
--- /dev/null
+++ b/test/errors/width/UninferredWidth.fir
@@ -0,0 +1,12 @@
+; RUN: firrtl -i %s -o %s.v -X verilog -p ciwTd 2>&1 | tee %s.out | FileCheck %s
+; CHECK: Uninferred width.
+
+circuit Top :
+ module Top :
+ input z : UInt
+
+
+
+
+
+