aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorazidar2015-10-07 14:48:04 -0700
committerazidar2015-10-07 14:49:54 -0700
commit4183c648b719eac9da26e2d9d34fa852ebdbfd20 (patch)
tree87d216e61563d0498c29953b824848ab92a7ade9
parent9f2e1fd28f8526f7b68dc4b0ea030ceded720697 (diff)
Added Printf and Stop to firrtl. #23 #24.
-rw-r--r--TODO1
-rw-r--r--src/main/stanza/errors.stanza58
-rw-r--r--src/main/stanza/firrtl-ir.stanza8
-rw-r--r--src/main/stanza/ir-parser.stanza2
-rw-r--r--src/main/stanza/ir-utils.stanza24
-rw-r--r--src/main/stanza/passes.stanza99
-rw-r--r--src/main/stanza/verilog.stanza46
-rw-r--r--test/errors/high-form/Printf.fir15
-rw-r--r--test/features/Printf.fir19
-rw-r--r--test/features/Stop.fir20
10 files changed, 260 insertions, 32 deletions
diff --git a/TODO b/TODO
index 1c85c5f1..ad9948cb 100644
--- a/TODO
+++ b/TODO
@@ -3,6 +3,7 @@ Support ASIC backend
Mem of vec, should just work?
ASIC rams (pass to replace smem with black box)
Readwrite Port
+Add %s, %b, %e etc. to spec
================================================
========== ADAM's BIG ARSE TODO LIST ============
diff --git a/src/main/stanza/errors.stanza b/src/main/stanza/errors.stanza
index ad289ea0..b6a854af 100644
--- a/src/main/stanza/errors.stanza
+++ b/src/main/stanza/errors.stanza
@@ -109,6 +109,19 @@ defn IllegalUnknownWidth (info:FileInfo) :
PassException $ string-join $
[info ": [module " mname "] Widths must be defined for memories and poison nodes."]
+defn BadPrintf (info:FileInfo,x:Char) :
+ PassException $ string-join $
+ [info ": [module " mname "] Bad printf format: \"%" x "\""];"
+
+defn BadPrintfTrailing (info:FileInfo) :
+ PassException $ string-join $
+ [info ": [module " mname "] Bad printf format: trailing \"%\""];"
+
+defn BadPrintfIncorrectNum (info:FileInfo) :
+ PassException $ string-join $
+ [info ": [module " mname "] Bad printf format: incorrect number of arguments"];"
+
+
;---------------- Helper Functions --------------
defn has-flip? (t:Type) -> True|False :
var has? = false
@@ -198,7 +211,7 @@ defn contains?<?T> (c:?T,cs:Streamable<?T>) -> True|False :
; (s:False) : 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) :
@@ -248,6 +261,20 @@ defn check-high-form-primop (e:DoPrim, errors:Vector<PassException>,info:FileInf
public defn check-high-form (c:Circuit) -> Circuit :
val errors = Vector<PassException>()
+
+ defn check-fstring (info:FileInfo,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))
+ 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 :
match(e) :
(e:UIntValue|SIntValue|DoPrim) :
@@ -337,6 +364,10 @@ public defn check-high-form (c:Circuit) -> Circuit :
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:PrintfStmt) :
+ 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)
@@ -445,6 +476,9 @@ public defn check-kinds (c:Circuit) -> Circuit :
println(type(source(s)))
add(errors,AccessVecOrMem(info(s)))
(s:Conditionally) : check-not-mem(info(s),pred(s))
+ (s:PrintfStmt) :
+ 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))
@@ -510,6 +544,10 @@ 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."]
@@ -556,8 +594,8 @@ defmethod equal? (t1:Type,t2:Type) -> True|False :
else : false
(t1,t2) : false
-defn u () -> UIntType : UIntType(UnknownWidth())
-defn s () -> SIntType : SIntType(UnknownWidth())
+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 :
@@ -676,8 +714,12 @@ public defn check-types (c:Circuit) -> Circuit :
(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:PrintfStmt) :
+ 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)) != u() : add(errors,PredNotUInt(info(s)))
+ 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
@@ -808,6 +850,9 @@ public defn check-genders (c:Circuit) -> Circuit :
(s:Connect) :
check-gender(info(s),genders,loc(s),FEMALE)
check-gender(info(s),genders,exp(s),MALE)
+ (s:PrintfStmt) :
+ 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)
@@ -817,6 +862,7 @@ public defn check-genders (c:Circuit) -> Circuit :
(s:Conditionally) :
check-gender(info(s),genders,pred(s),MALE)
(s:EmptyStmt) : false
+ (s:StopStmt) : false
(s:Begin) : false
@@ -1056,6 +1102,9 @@ public defn check-low-form (c:Circuit) -> Circuit :
add(insts,name(s))
(s:DefNode) :
check-correct-exp(info(s),value(s))
+ (s:PrintfStmt) :
+ for x in args(s) do :
+ check-correct-exp(info(s),x)
(s:DefRegister) : false
(s:DefAccessor) : false
(s:Conditionally) :
@@ -1071,6 +1120,7 @@ public defn check-low-form (c:Circuit) -> Circuit :
else : assigned?[to-symbol $ to-string $ e] = true
(e) : check-correct-exp(info(s),e)
(s:EmptyStmt) : false
+ (s:StopStmt) : false
(s:Begin) : do(check-low-form-s,s)
match(m) :
diff --git a/src/main/stanza/firrtl-ir.stanza b/src/main/stanza/firrtl-ir.stanza
index 0ed785c7..5bc1ea68 100644
--- a/src/main/stanza/firrtl-ir.stanza
+++ b/src/main/stanza/firrtl-ir.stanza
@@ -155,6 +155,14 @@ public defstruct Connect <: Stmt : ;LOW
info: FileInfo with: (as-method => true)
loc: Expression
exp: Expression
+public defstruct StopStmt <: Stmt : ;LOW
+ info: FileInfo with: (as-method => true)
+ ret: Int
+public defstruct PrintfStmt <: Stmt : ;LOW
+ info: FileInfo with: (as-method => true)
+ string: String
+ args: List<Expression>
+
public defstruct EmptyStmt <: Stmt ;LOW
public definterface Type
diff --git a/src/main/stanza/ir-parser.stanza b/src/main/stanza/ir-parser.stanza
index c2c7cfa5..a4ca89f7 100644
--- a/src/main/stanza/ir-parser.stanza
+++ b/src/main/stanza/ir-parser.stanza
@@ -246,6 +246,8 @@ defsyntax firrtl :
stmt = (write accessor ?name:#id! #=! ?s:#exp![?i:#exp$]) : DefAccessor(first-info(form),name,s,i,WRITE)
stmt = (infer accessor ?name:#id! #=! ?s:#exp![?i:#exp$]) : DefAccessor(first-info(form),name,s,i,INFER)
stmt = (rdwr accessor ?name:#id! #=! ?s:#exp![?i:#exp$]) : DefAccessor(first-info(form),name,s, i,RDWR)
+ stmt = (stop(?ret:#int)) : StopStmt(first-info(form),ret)
+ stmt = (printf(?str:#string ?es:#exp ...)) : PrintfStmt(first-info(form),str,es)
stmt = (?s:#stmt/when) : s
stmt = (?x:#exp := ?y:#exp!) : Connect(first-info(form),x, y)
diff --git a/src/main/stanza/ir-utils.stanza b/src/main/stanza/ir-utils.stanza
index ffc9b39e..59c7c36a 100644
--- a/src/main/stanza/ir-utils.stanza
+++ b/src/main/stanza/ir-utils.stanza
@@ -110,6 +110,11 @@ public defmethod print (o:OutputStream, p:Pass) :
;============== Various Useful Functions ==============
+public defn add-all (v1:Vector,v2:Vector) -> False :
+ for x in v2 do :
+ add(v1,x)
+
+
public defn ceil-log2 (i:Long) -> Long :
defn* loop (n:Long, l:Long) :
if n < i :
@@ -138,6 +143,17 @@ public defn req-num-bits (i: Int) -> Int :
else : i
ceil-log2(i* + 1) + 1
+defn escape (s:String) -> String :
+ val s* = Vector<String>()
+ add(s*,"\"");"
+ for c in s do :
+ if c == '\n' :
+ add(s*,"\\n")
+ else : add(s*,to-string(c))
+ add(s*,"\"");"
+ string-join(s*)
+ ;"
+
;============== PRINTERS ===================================
defmethod print (o:OutputStream, d:Flip) :
@@ -261,6 +277,13 @@ defmethod print (o:OutputStream, c:Stmt) :
print-all(o, ["onreset " loc(c) " := " exp(c)])
(c:EmptyStmt) :
print(o, "skip")
+ (c:StopStmt) :
+ print-all(o, ["stop(" ret(c) ")"])
+ (c:PrintfStmt) :
+ print-all(o, ["printf("]) ;"
+ print-all(o, join(List(escape(string(c)),args(c)), ", "))
+ print(o, ")")
+
if not c typeof Conditionally|Begin|EmptyStmt : print-debug(o,c)
defmethod print (o:OutputStream, t:Type) :
@@ -352,6 +375,7 @@ defmethod map (f: Expression -> Expression, c:Stmt) -> Stmt :
(c:Connect) : Connect(info(c),f(loc(c)), f(exp(c)))
(c:BulkConnect) : BulkConnect(info(c),f(loc(c)), f(exp(c)))
(c:OnReset) : OnReset(info(c),f(loc(c)),f(exp(c)))
+ (c:PrintfStmt) : PrintfStmt(info(c),string(c),map(f,args(c)))
(c) : c
public defmulti map<?T> (f: Stmt -> Stmt, c:?T&Stmt) -> T
diff --git a/src/main/stanza/passes.stanza b/src/main/stanza/passes.stanza
index f0c4d242..f2931bc8 100644
--- a/src/main/stanza/passes.stanza
+++ b/src/main/stanza/passes.stanza
@@ -186,7 +186,7 @@ public var PRINT-GENDERS : True|False = false
public var PRINT-CIRCUITS : True|False = false
public var PRINT-DEBUG : True|False = false
public var PRINT-INFO : True|False = false
-;=== Printers ===
+;=== ThePrinters ===
public defn println-all-debug (l:?) -> False :
if PRINT-DEBUG : println-all(l)
@@ -358,6 +358,8 @@ defn remove-special-chars (c:Circuit) :
(s:BulkConnect) : BulkConnect(info(s),rename-e(loc(s)),rename-e(exp(s)))
(s:Connect) : Connect(info(s),rename-e(loc(s)),rename-e(exp(s)))
(s:EmptyStmt) : s
+ (s:StopStmt) : s
+ (s:PrintfStmt) : PrintfStmt(info(s),string(s),map(rename-e,args(s)))
Circuit(info(c),modules*, rename(main(c))) where :
val modules* =
@@ -693,7 +695,7 @@ defn infer-types (s:Stmt, l:List<KeyValue<Symbol,Type>>) -> [Stmt List<KeyValue<
val [s*,l*] = infer-types(conseq(s),l)
val [s**,l**] = infer-types(alt(s),l)
[Conditionally(info(s),pred(s),s*,s**),l]
- (s:Connect|BulkConnect|OnReset|EmptyStmt) : [s,l]
+ (s:Connect|BulkConnect|OnReset|EmptyStmt|StopStmt|PrintfStmt) : [s,l]
defn infer-types (m:Module, l:List<KeyValue<Symbol,Type>>) -> Module :
val ptypes =
@@ -812,6 +814,8 @@ defn resolve-genders (c:Circuit) :
val conseq* = resolve-stmt(conseq(s))
val alt* = resolve-stmt(alt(s))
Conditionally(info(s),pred*,conseq*,alt*)
+ (s:PrintfStmt) :
+ PrintfStmt(info(s),string(s),map(resolve-expr{_,MALE},args(s)))
(s) : map(resolve-stmt,s)
defn resolve-expr (e:Expression,desired:Gender) -> Expression :
@@ -1122,7 +1126,10 @@ defn lower (body:Stmt) -> Stmt :
[MALE,FEMALE] : DecFromIndexer(info(s),index*,exps,name(ntf),type(ntf))
(s:Conditionally) :
Conditionally(info(s),exp(head $ expand-expr(pred(s))),lower-stmt(conseq(s)),lower-stmt(alt(s)))
- (s:Begin|EmptyStmt) : map(lower-stmt,s)
+ (s:PrintfStmt) :
+ val args* = for x in args(s) map : exp(head(expand-expr(x)))
+ PrintfStmt(info(s),string(s),args*)
+ (s:Begin|EmptyStmt|StopStmt) : map(lower-stmt,s)
lower-stmt(body)
@@ -1534,11 +1541,23 @@ defn merge-resets (assign:HashTable<Symbol,SymbolicValue>, resets:HashTable<Symb
(a:False,r:False) : error("Shouldn't be here")
table
+defn mark (vs:Vector<[Stmt,Expression]>,pred:Expression) -> False :
+ for i in 0 to length(vs) do :
+ val [s,e] = vs[i]
+ vs[i] = [s, AND(e,pred)]
+
+; ------ Print Debug Info ------
+defn print-table (t:HashTable<Symbol,SymbolicValue>,s:String) :
+ println-debug(s)
+ for x in t do : println-debug(x)
+
+
defn build-tables (s:Stmt,
assign:HashTable<Symbol,SymbolicValue>,
resets:HashTable<Symbol,SymbolicValue>,
flattn:HashTable<Symbol,True|False>,
rsignals:HashTable<Symbol,Expression>,
+ simuls:Vector<[Stmt,Expression]>,
) -> False :
match(s) :
(s:DefWire) :
@@ -1580,26 +1599,28 @@ defn build-tables (s:Stmt,
val assign-a = deepcopy(assign)
val resets-c = deepcopy(resets)
val resets-a = deepcopy(resets)
- build-tables(conseq(s),assign-c,resets-c,flattn,rsignals)
- build-tables(alt(s),assign-a,resets-a,flattn,rsignals)
+ val simuls-c = Vector<[Stmt,Expression]>()
+ val simuls-a = Vector<[Stmt,Expression]>()
+ build-tables(conseq(s),assign-c,resets-c,flattn,rsignals,simuls-c)
+ build-tables(alt(s),assign-a,resets-a,flattn,rsignals,simuls-a)
for i in get-unique-keys(list(assign-c,assign-a)) do :
assign[i] = combine(flattn,assign-c,assign-a,i) as SymbolicValue
val r = combine(flattn,resets-c,resets-a,i)
match(r) :
(r:SymbolicValue) : resets[i] = r
(r) : false
- println-debug("TABLE-C")
- for x in assign-c do : println-debug(x)
- println-debug("TABLE-A")
- for x in assign-a do : println-debug(x)
- println-debug("TABLE")
- for x in assign do : println-debug(x)
- println-debug("RESET-C")
- for x in resets-c do : println-debug(x)
- println-debug("RESET-A")
- for x in resets-a do : println-debug(x)
- println-debug("RESET")
- for x in resets do : println-debug(x)
+
+ mark(simuls-c,pred(s))
+ mark(simuls-a,DoPrim(BIT-NOT-OP,list(pred(s)),list(),UIntType(LongWidth(1))))
+ add-all(simuls,simuls-c)
+ add-all(simuls,simuls-a)
+
+ print-table(assign-c,"TABLE-C")
+ print-table(assign-a,"TABLE-A")
+ print-table(assign,"TABLE")
+ print-table(resets-c,"RESET-C")
+ print-table(resets-a,"RESET-A")
+ print-table(resets,"RESET")
(s:Connect|OnReset) :
val key* = match(loc(s)) :
(e:WRef) : name(e)
@@ -1607,7 +1628,9 @@ defn build-tables (s:Stmt,
(e) : error("Shouldn't be here with ~" % [e])
if s typeof Connect : assign[key*] = SVExp(exp(s))
if s typeof OnReset : resets[key*] = SVExp(exp(s))
- (s:Begin) : for s* in body(s) do: build-tables(s*,assign,resets,flattn,rsignals)
+ (s:Begin) : for s* in body(s) do: build-tables(s*,assign,resets,flattn,rsignals,simuls)
+ (s:StopStmt|PrintfStmt) :
+ add(simuls,[s one])
(s:DefMemory|DefPoison|DefNode|EmptyStmt) : false
@@ -1635,6 +1658,7 @@ defn is-referenced? (referenced?:HashTable<Symbol,True>, s:Stmt) -> True|False :
match(s) :
(s:DefPoison|DefWire|DefRegister|DefAccessor|DefMemory|DefNode) : key?(referenced?,name(s))
(s:DefInstance) : true
+ (s:PrintfStmt|StopStmt|Conditionally) : true
;--------------- Expand Whens Pass -------------------
@@ -1698,7 +1722,7 @@ public defn expand-whens (c:Circuit) -> Circuit :
val sref = WSubfield(ref,f,bundle-field-type(type(module(s)),f),FEMALE)
if not has-nul?(table[n]) :
add{cons,_} $ Connect(info(s),sref,to-exp(table[n]) as Expression)
- (s:Connect|Conditionally|OnReset|Begin|EmptyStmt) : false
+ (s:Connect|Conditionally|OnReset|Begin|EmptyStmt|StopStmt|PrintfStmt) : false
s
defn expand-whens (m:Module) -> Module :
@@ -1709,13 +1733,14 @@ public defn expand-whens (c:Circuit) -> Circuit :
val resets = HashTable<Symbol,SymbolicValue>(symbol-hash)
val flattn = HashTable<Symbol,True|False>(symbol-hash)
val rsignals = HashTable<Symbol,Expression>(symbol-hash)
+ val simuls = Vector<[Stmt,Expression]>()
for p in ports(m) do :
if direction(p) == OUTPUT :
assign[name(p)] = SVNul()
flattn[name(p)] = false
- build-tables(body(m),assign,resets,flattn,rsignals)
+ build-tables(body(m),assign,resets,flattn,rsignals,simuls)
for x in assign do : assign[key(x)] = optimize(value(x))
for x in resets do : resets[key(x)] = optimize(value(x))
@@ -1736,6 +1761,11 @@ public defn expand-whens (c:Circuit) -> Circuit :
expand-whens(ports(m),table,cons)
expand-whens(body(m),table,decs,cons)
+ for se in simuls do :
+ val [s e] = se
+ if e == one : add(decs,s)
+ else : add(decs,Conditionally(info(s),e,s,EmptyStmt()))
+
val referenced? = HashTable<Symbol,True>(symbol-hash)
for x in table do :
mark-referenced(referenced?,value(x))
@@ -2052,6 +2082,8 @@ defn gen-constraints (m:Module, h:HashTable<Symbol,Type>, v:Vector<WGeq>) -> Mod
val e = gen-constraints(exp(s))
add(v,WGeq(width!(type(l)),width!(type(e))))
Connect(info(s),l,e)
+ (s:PrintfStmt) :
+ PrintfStmt(info(s),string(s),map(gen-constraints,args(s)))
(s:Conditionally) :
val p = gen-constraints(pred(s))
add(v,WGeq(width!(type(p)),LongWidth(1)))
@@ -2326,14 +2358,26 @@ defn split-exp (c:Circuit) :
;Predicate
val pred* = map(split-exp-e{_,full-name(pred(s)),info(s)},pred(s))
- ;Connect
- val c = conseq(s) as Connect
- val exp* = map(split-exp-e{_,full-name(loc(c)),info(c)},exp(c))
- val conseq* = Connect(info(c),loc(c),exp*)
- add(v,Conditionally(info(s),pred*,conseq*,alt(s)))
+ ;Connect TODO Broken for stop/printf
+ match(conseq(s)) :
+ (c:Connect) :
+ val exp* = map(split-exp-e{_,full-name(loc(c)),info(c)},exp(c))
+ val conseq* = Connect(info(c),loc(c),exp*)
+ add(v,Conditionally(info(s),pred*,conseq*,alt(s)))
+ (c:PrintfStmt) :
+ val args* = for x in args(c) map :
+ map(split-exp-e{_,false,info(c)},x)
+ val conseq* = PrintfStmt(info(c),string(c),args*)
+ add(v,Conditionally(info(s),pred*,conseq*,alt(s)))
+ (c:StopStmt) :
+ add(v,Conditionally(info(s),pred*,c,alt(s)))
(s:Connect) :
val exp* = map(split-exp-e{_,full-name(loc(s)),info(s)},exp(s))
add(v,Connect(info(s),loc(s),exp*))
+ (s:PrintfStmt) :
+ val args* = for x in args(s) map :
+ map(split-exp-e{_,false,info(s)},x)
+ add(v,PrintfStmt(info(s),string(s),args*))
(s:DefNode) :
val exp* = map(split-exp-e{_,name(s),info(s)},value(s))
add(v,DefNode(info(s),name(s),exp*))
@@ -2488,6 +2532,11 @@ defn pad-widths-s (s:Stmt) -> Stmt :
val loc* = pad-widths-e(i,loc(s))
val exp* = pad-widths-e(i,exp(s))
Connect(info(s),loc*,exp*)
+ (s:PrintfStmt) :
+ val args* = for x in args(s) map :
+ val i = int-width!(type(x))
+ pad-widths-e(i,x)
+ PrintfStmt(info(s),string(s),args*)
(s:DefNode) :
val i = int-width!(type(value(s)))
val exp* = pad-widths-e(i,value(s))
diff --git a/src/main/stanza/verilog.stanza b/src/main/stanza/verilog.stanza
index ef78659a..5cf42323 100644
--- a/src/main/stanza/verilog.stanza
+++ b/src/main/stanza/verilog.stanza
@@ -54,6 +54,20 @@ defn get-name (e:Expression) -> Symbol :
(e:Subfield) : error("Shouldn't be here")
(e) : error("Shouldn't be here")
+defn escape (s:String) -> String :
+ val s* = Vector<String>()
+ add(s*,"\"");"
+ var percent = false
+ for c in s do :
+ if c == '\n' :
+ add(s*,"\\n")
+ else :
+ if c == 'x' and percent :
+ add(s*,"h")
+ else : add(s*,to-string(c))
+ percent = c == '%'
+ add(s*,"\"");"
+ string-join(s*)
;============ Verilog Backend =============
defn emit-as-type (e:Expression,t:Type) -> String :
@@ -168,15 +182,32 @@ defn emit-module (m:InModule) :
val decs = HashTable<Symbol,Stmt>(symbol-hash) ; all declarations, for fast lookups
val cons = HashTable<Symbol,Expression>(symbol-hash) ; all connections
val ens = HashTable<Symbol,Expression>(symbol-hash) ; all enables
+ val simuls = Vector<Streamable>()
defn build-table (s:Stmt) -> False :
match(s) :
(s:DefWire|DefPoison|DefRegister|DefAccessor|DefMemory|DefNode|DefInstance) :
add(vdecs,name(s) => s)
decs[name(s)] = s
(s:Conditionally) :
- val n = get-name(loc(conseq(s) as Connect))
- ens[n] = pred(s)
- cons[n] = exp(conseq(s) as Connect)
+ match(conseq(s)) :
+ (c:Connect) :
+ val n = get-name(loc(c))
+ ens[n] = pred(s)
+ cons[n] = exp(conseq(s) as Connect)
+ (c:PrintfStmt) :
+ add(simuls,["if(" emit(pred(s)) ") begin"])
+ add(simuls,[" $fdisplay(32/'h80000002," string-join(List(escape(string(c)),map(emit,args(c))), ", ") ");"])
+ add(simuls,["end"])
+ (c:StopStmt) :
+ add(simuls,["if(" emit(pred(s)) ") begin"])
+ add(simuls,[" $fdisplay(32/'h80000002," ret(c) ");"])
+ add(simuls,[" $finish;"])
+ add(simuls,["end"])
+ (s:PrintfStmt) :
+ add(simuls,["$fdisplay(32/'h80000002," string-join(List(escape(string(s)),map(emit,args(s))), ", ") ");"])
+ (c:StopStmt) :
+ add(simuls,["$fdisplay(32/'h80000002," ret(c) ");"])
+ add(simuls,["$finish;"])
(s:Connect) :
val n = get-name(loc(s))
cons[n] = exp(s)
@@ -321,6 +352,15 @@ defn emit-module (m:InModule) :
print(" ")
println-all(u)
println(" end")
+
+ if length(simuls) != 0 :
+ println("`ifndef SYNTHESIS")
+ println(" always @(*) begin")
+ for x in simuls do :
+ print(" ")
+ println-all(x)
+ println(" end")
+ println("`endif")
println("endmodule")
diff --git a/test/errors/high-form/Printf.fir b/test/errors/high-form/Printf.fir
new file mode 100644
index 00000000..7f285d3e
--- /dev/null
+++ b/test/errors/high-form/Printf.fir
@@ -0,0 +1,15 @@
+; RUN: firrtl -i %s -o %s.v -X verilog -p c 2>&1 | tee %s.out | FileCheck %s
+
+circuit Top :
+ module Top :
+ input x : {y : UInt<1>}
+ input p : UInt<1>
+ printf("Hello World%!\n",x)
+ printf("Hello World%")
+ printf("Hello World%d %s %h %x",x,x,x)
+
+;CHECK: Bad printf format: "%!"
+;CHECK: Bad printf format: trailing "%"
+;CHECK: Bad printf format: incorrect number of arguments
+;CHECK: Bad printf format: "%h"
+;CHECK: Bad printf format: incorrect number of arguments
diff --git a/test/features/Printf.fir b/test/features/Printf.fir
new file mode 100644
index 00000000..8449825f
--- /dev/null
+++ b/test/features/Printf.fir
@@ -0,0 +1,19 @@
+; RUN: firrtl -i %s -o %s.v -X verilog -p c 2>&1 | tee %s.out | FileCheck %s
+
+;CHECK: Lower To Ground
+circuit Top :
+ module Top :
+ input x : {y : UInt<1>}
+ input p : UInt<1>
+ printf("Hello World!\n")
+ printf("Hello World! %x\n", x.y)
+ when p :
+ printf("In consequence\n")
+ else :
+ printf("In alternate\n")
+
+;CHECK: printf("Hello World!\n")
+;CHECK: printf("Hello World! %x\n", x$y)
+;CHECK: when p : printf("In consequence\n")
+;CHECK: when not(p) : printf("In alternate\n")
+;CHECK: Done!
diff --git a/test/features/Stop.fir b/test/features/Stop.fir
new file mode 100644
index 00000000..fc8869fa
--- /dev/null
+++ b/test/features/Stop.fir
@@ -0,0 +1,20 @@
+; RUN: firrtl -i %s -o %s.v -X verilog -p c 2>&1 | tee %s.out | FileCheck %s
+
+;CHECK: Lower To Ground
+
+circuit Top :
+ module Top :
+ input p : UInt<1>
+ input q : UInt<1>
+ when p :
+ stop(0)
+ when q :
+ stop(1)
+ stop(3)
+
+;CHECK: when p : stop(0)
+;CHECK: when q : stop(1)
+;CHECK: stop(3)
+
+;CHECK: Done!
+