Skip to content

Commit

Permalink
Updated Spec. Added scoped-reg which exposes on-reset bug. Fixed lowe…
Browse files Browse the repository at this point in the history
…ring bug
  • Loading branch information
azidar committed May 13, 2015
1 parent 791334c commit 2cf26ba
Show file tree
Hide file tree
Showing 9 changed files with 725 additions and 442 deletions.
11 changes: 10 additions & 1 deletion TODO
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,23 @@
================================================

======== Current Tasks ========
Declared references needs to understand scope
Size of vector type must be non-negative
Check for recursively defined instances
Update spec
<>
Add Unit Tests for each pass
Separate passes into discrete chunks
Push all tests entirely through
Check after each pass
write test that checks instance types are correctly lowered
move width inference earlier

======== Update Core ==========
Add source locaters
Add exmodule
Add vptype
Add readwriteport

======== Check Passes ==========
Well-formed high firrtl
Expand Down Expand Up @@ -83,7 +90,9 @@ Convert to scala
Firrtl interpreter (in scala)

======== Update Spec ========
Add Not to spec
Look through all primops
change parser to other unknown thing for vptype?
Add optional type to node
add assertions and printfs
cannot connect directly to a mem (loc can never contain a mem)
Front-end needs to guarantee unique names per module.
Expand Down
39 changes: 35 additions & 4 deletions notes/primop-inference.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,28 @@
Support on-reset for now, but it will get deprecated. It was originally included to make it easier for the front-end to support Vec(Reg), but since this was a bad decision in Chisel, we shouldn't muddy up FIRRTL to compensate.
For now, we will add which of the reset signal for registers in their declaration, so on-reset will use that instead of the implicit reset
Delete implicit reset, always make it explicit
Clock will be a subtype of Port. Need to make sure it isn't used in any logic. It will be included in the declaration of registers.

Primops - Different widths
Backends will emit different things based on the type of the input arguments, and the widths.
e.g.
SInt<7> + SInt<4>
For C++ : need to sign-extend SInt<4> and add to SInt<7>
For Verilog : Emit as is, which will generate a 4-bit add and an increment circuit
Verilog does not want it sign extended, so we should not ensure that widths should be different
For backends that need strict width inference, you should write your own padding pass, and checking pass.

Primops - Input Type dependence
To simplify all passes other than the backend, only the generic ops will be supported. All combinations (-uu,-us,...) that actually require different behaviors will need to look at the type of the operands.
We decided to make a resolve&check pass that is separate from lowering, and is done immediately after parsing the file. This will do all the type inference. By making this pass available, the backends can
guarantee the in-memory AST will have types and be type-checked.

Assignment - expanding?
We didn't discuss this, but my hunch is we should make it loose in that it allows connections of a smaller width expression to a larger width expression




The design of the primitive operations follows the following principles:
(1) if operand types are known (i.e. FIRRTL front-end), primops whose return type is statically known (no future type introspection needed) are available
(2) if operand types are not known (i.e. hand-writing FIRRTL pass), generic primops can be used, and a future pass will perform type introspection to replace the generic with the specific primop
Expand Down Expand Up @@ -36,15 +61,21 @@ div
divus(a,b) -> s,a.w+1 ; if divide by -1
divsu(a,b) -> s,a.w ; if divide by 1
divss(a,b) -> s,a.w+1 ; if divide by -1


quo
quouu -> u, a.w
quous -> s, a.w + 1
quosu -> s, a.w
quoss -> u, a.w + 1

mod
moduu(a,d) -> u,d.w
modus(a,d) -> u,d.w-1
modus(a,d) -> u,d.w
modsu(a,d) -> u,d.w
modss(a,d) -> u,d.w-1
modss(a,d) -> u,d.w

rem
remuu(a,b) -> u,min(a.w,b.w) ; 15 % 16 = 15. All remainders must be less than b or a.
remuu(a,b) -> u,b.w ; 15 % 16 = 15. All remainders must be less than b or a.
remus(a,b) -> u,b.w ; -1 % 32 = 31. Remainder can be larger than abs(a), but not larger than b.
remsu(a,b) -> s,b.w ; 1 % -32 = -31. abs(rem) can be larger than abs(a), but not larger than abs(b).
remss(a,b) -> s,b.w ; strictly superset of us and su.
Expand Down
Binary file modified spec/spec.pdf
Binary file not shown.
727 changes: 350 additions & 377 deletions spec/spec.tex

Large diffs are not rendered by default.

120 changes: 81 additions & 39 deletions src/main/stanza/errors.stanza
Original file line number Diff line number Diff line change
Expand Up @@ -194,7 +194,10 @@ public defn check-high-form (c:Circuit) -> Circuit :

defn check-high-form-m (m:Module) -> False :
val names = Vector<Symbol>()
for m in modules(c) do :
add(names,name(m))
for p in ports(m) do :
add(names,name(p))
if name(p) == `reset :
if direction(p) == OUTPUT :
add(errors,WrongReset(info!(m),name(m)))
Expand All @@ -205,6 +208,8 @@ public defn check-high-form (c:Circuit) -> Circuit :
else :
add(errors,WrongReset(info!(m),name(m)))


add(names,`reset)
check-high-form-s(body(m),names)
false

Expand Down Expand Up @@ -238,28 +243,32 @@ defn OnResetNotReg (info:FileInfo, name:Symbol) :
; 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<PassExceptioPassException>()
val errors = Vector<PassException>()
defn check-not-mem (info:FileInfo,e:Expression) -> False :
match(map(check-not-mem{info,_},e)) :
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(exp(e))
(e:WIndex) : check-not-mem(exp(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 :
match(map(check-is-reg{info,_},e)) :
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(exp(e))
(e:WIndex) : check-is-reg(exp(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 :
match(map(check-is-mem{info,_},e)) :
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(exp(e))
(e:WIndex) : check-is-mem(exp(e))
(e:WSubfield) : check-is-mem(info,exp(e))
(e:WIndex) : check-is-mem(info,exp(e))
(e) : false

defn check-kinds-e (info:FileInfo,e:Expression) -> False :
match(map(check-kinds-e{info,_},e)) :
do(check-kinds-e{info,_},e)
match(e) :
(e:ReadPort) :
check-is-mem(info,mem(e))
check-not-mem(info,index(e))
Expand All @@ -270,21 +279,21 @@ public defn check-kinds (c:Circuit) -> Circuit :
check-not-mem(info,enable(e))
(e:Pad) :
check-not-mem(info,value(e))
(e) : map(check-not-mem{info,_},e)
defn check-kinds-s (s:Stmt) -> Stmt :
map{check-kinds-s,_} $ {
match(map(check-kinds-e{info!(s),_},s)) :
(s:DefNode) : check-not-mem(info!(s),value(s))
(s:DefAccessor) : check-not-mem(info!(s),index(s))
(s:Conditionally) : check-not-mem(info!(s),pred(s))
(s:Connect) :
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
s }()
(e) : do(check-not-mem{info,_},e)
defn check-kinds-s (s:Stmt) -> False :
do(check-kinds-e{info!(s),_:Expression},s)
match(s) :
(s:DefNode) : check-not-mem(info!(s),value(s))
(s:DefAccessor) : check-not-mem(info!(s),index(s))
(s:Conditionally) : check-not-mem(info!(s),pred(s))
(s:Connect) :
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 :
check-kinds-s(body(m))
Expand All @@ -307,13 +316,45 @@ defn SubfieldNotInBundle (info:FileInfo, name:Symbol) :
PassException $ string-join $
[info ": Subfield " name " is not in bundle."]

defn SubfieldOnNonBundle (info:FileInfo, name:Symbol) :
PassException $ string-join $
[info ": Subfield " name " is accessed on a non-bundle."]

defn IndexTooLarge (info:FileInfo, value:Int) :
PassException $ string-join $
[info ": Index with value " value " is too large."]

defn IndexOnNonVector (info:FileInfo) :
PassException $ string-join $
[info ": Index illegal on non-vector type."]

defn IndexNotUInt (info:FileInfo) :
PassException $ string-join $
[info ": Index is not of UIntType."]

defn EnableNotUInt (info:FileInfo) :
PassException $ string-join $
[info ": Enable is not of UIntType."]

defn PadNotGround (info:FileInfo) :
PassException $ string-join $
[info ": Illegal Pad on non-ground type."]

defn InvalidConnect (info:FileInfo) :
PassException $ string-join $
[info ": Type mismatch."]

defn PredNotUInt (info:FileInfo) :
PassException $ string-join $
[info ": Predicate not a UIntType."]

;---------------- Helper Functions --------------
defn equal? (t1:Type,t2:Type) -> True|False :
defmethod equal? (t1:Type,t2:Type) -> True|False :
match(t1,t2) :
(t1:UIntType,t2:UIntType) : true
(t1:SIntType,t2:SIntType) : true
(t1:BundleType,t2:BundleType) :
val same? = true
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
Expand All @@ -324,27 +365,27 @@ defn equal? (t1:Type,t2:Type) -> True|False :
else : false
(t1,t2) : false

defn u() -> UIntType : UIntType(UnknownWidth())
defn s() -> SIntType : SIntType(UnknownWidth())
defn u () -> UIntType : UIntType(UnknownWidth())
defn s () -> SIntType : SIntType(UnknownWidth())

;----------------- Check Types Pass ---------------------
public defn check-types (c:Circuit) -> Circuit :
val errors = Vector<PassExceptioPassException>()
defn check-types-e (info:FileInfo,e:Expression) -> Expression
match(map(check-types-e{info,_},s)) :
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(v) find : name(p) == s
val ft = for p in fields(t) find : name(p) == s
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)
(e:DoPrim) : false ;check-types-primop(e)
(e:ReadPort|WritePort) :
if type(index(e)) != u() : add(errors,IndexNotUInt(info))
if type(enable(e)) != u() : add(errors,EnableNotUInt(info))
Expand All @@ -357,13 +398,14 @@ public defn check-types (c:Circuit) -> Circuit :
e
defn check-types-s (s:Stmt) -> Stmt :
map{check-types-s,_} $
match(map(check-types-e,s)) :
match(map(check-types-e{info!(s),_},s)) :
(s:Connect|OnReset) :
if type(loc(s)) == type(exp(s)) : add(errors,InvalidConnect(info!(s)))
s
(s:Conditionally) :
if type(pred(s)) != u() : add(errors,PredNotUInt(info))
(s) : false
s
if type(pred(s)) != u() : add(errors,PredNotUInt(info!(s)))
s
(s) : s

for m in modules(c) do :
check-types-s(body(m))
Expand Down
41 changes: 20 additions & 21 deletions src/main/stanza/passes.stanza
Original file line number Diff line number Diff line change
Expand Up @@ -18,44 +18,43 @@ public defn PassExceptions (xs:Streamable<PassException>) :
PassException(string-join(xs, "\n"))

;=============== WORKING IR ================================
definterface Kind
defstruct WireKind <: Kind
defstruct RegKind <: Kind
defstruct InstanceKind <: Kind
defstruct ReadAccessorKind <: Kind
defstruct WriteAccessorKind <: Kind
defstruct PortKind <: Kind
defstruct NodeKind <: Kind ; All elems except structural memory, wires

defstruct MemKind <: Kind
defstruct ModuleKind <: Kind
defstruct AccessorKind <: Kind
public definterface Kind
public defstruct WireKind <: Kind
public defstruct RegKind <: Kind
public defstruct InstanceKind <: Kind
public defstruct ReadAccessorKind <: Kind
public defstruct WriteAccessorKind <: Kind
public defstruct PortKind <: Kind
public defstruct NodeKind <: Kind ; All elems except structural memory, wires
public defstruct MemKind <: Kind
public defstruct ModuleKind <: Kind
public defstruct AccessorKind <: Kind

public definterface Gender
public val MALE = new Gender
public val FEMALE = new Gender
public val UNKNOWN-GENDER = new Gender
public val BI-GENDER = new Gender

defstruct WRef <: Expression :
public defstruct WRef <: Expression :
name: Symbol
type: Type with: (as-method => true)
kind: Kind
gender: Gender with: (as-method => true)

defstruct WSubfield <: Expression :
public defstruct WSubfield <: Expression :
exp: Expression
name: Symbol
type: Type with: (as-method => true)
gender: Gender with: (as-method => true)

defstruct WIndex <: Expression :
public defstruct WIndex <: Expression :
exp: Expression
value: Int
type: Type with: (as-method => true)
gender: Gender with: (as-method => true)

defstruct WDefAccessor <: Stmt :
public defstruct WDefAccessor <: Stmt :
name: Symbol
source: Expression
index: Expression
Expand Down Expand Up @@ -719,18 +718,18 @@ defn expand-expr (e:Expression) -> List<EF> :
for x in generate-entry(name(e),type(e)) map :
EF(WRef(name(x),type(x),kind(e),gender(e)), flip(x))
(e:WSubfield) :
val f = {_ as Field} $
for f in fields(type(exp(e)) as BundleType) find : name(f) == name(e)
if inst?(exp(e)) :
val i = exp(e)
val f = {_ as Field} $
for f in fields(type(i) as BundleType) find : name(f) == name(e)
println-all(["here with " exp(e)])
for x in generate-entry(name(f),type(f)) map :
EF(WSubfield(i,name(x),type(x),gender(e)),flip(x))
EF(WSubfield(exp(e),name(x),type(x),gender(e)),flip(x))
else :
val exps = expand-expr(exp(e))
val begin = index-of-elem(type(exp(e)) as BundleType,name(e))
val len = num-elems(type(e))
val ret = headn(tailn(exps,begin),len)
for r in ret map : EF(exp(r),DEFAULT)
for r in ret map : EF(exp(r),flip(r) * flip(f))
(e:WIndex) :
val exps = expand-expr(exp(e))
val len = num-elems(type(e))
Expand Down
Loading

0 comments on commit 2cf26ba

Please sign in to comment.