diff options
| author | azidar | 2016-02-06 09:59:13 -0800 |
|---|---|---|
| committer | azidar | 2016-02-09 18:57:07 -0800 |
| commit | 69597a7d57236bc43c964f7714bfa8ed53bf3bee (patch) | |
| tree | dd9d9870fe4fb2d21690d1757177fd10facfab99 | |
| parent | bf900917c50a440632dbcaae17bcfe9613d14452 (diff) | |
Added constprop,v-wrap,v-rename. All set to attempt like->like comparison of rocketchip
| -rw-r--r-- | src/main/scala/firrtl/Compiler.scala | 13 | ||||
| -rw-r--r-- | src/main/scala/firrtl/Emitter.scala | 578 | ||||
| -rw-r--r-- | src/main/scala/firrtl/PrimOps.scala | 6 | ||||
| -rw-r--r-- | src/main/scala/firrtl/Utils.scala | 20 | ||||
| -rw-r--r-- | src/main/scala/firrtl/WIR.scala | 9 | ||||
| -rw-r--r-- | src/main/scala/firrtl/passes/Passes.scala | 170 | ||||
| -rw-r--r-- | src/main/stanza/chirrtl.stanza | 16 | ||||
| -rw-r--r-- | src/main/stanza/passes.stanza | 2 |
8 files changed, 778 insertions, 36 deletions
diff --git a/src/main/scala/firrtl/Compiler.scala b/src/main/scala/firrtl/Compiler.scala index 34feab99..d2f9fc0e 100644 --- a/src/main/scala/firrtl/Compiler.scala +++ b/src/main/scala/firrtl/Compiler.scala @@ -22,6 +22,7 @@ object VerilogCompiler extends Compiler { // Copied from Stanza implementation val passes = Seq( //CheckHighForm, + FromCHIRRTL, ToWorkingIR, ResolveKinds, InferTypes, @@ -31,14 +32,20 @@ object VerilogCompiler extends Compiler { ExpandConnects, RemoveAccesses, ExpandWhens, - CheckInitialization, + //CheckInitialization, ConstProp, - ToWorkingIR, ResolveKinds, InferTypes, ResolveGenders, InferWidths, - LowerTypes + LowerTypes, + ResolveKinds, + InferTypes, + ResolveGenders, + InferWidths, + VerilogWrap, + SplitExp, + VerilogRename ) def run(c: Circuit, w: Writer) { diff --git a/src/main/scala/firrtl/Emitter.scala b/src/main/scala/firrtl/Emitter.scala index 09302fb3..596c1f93 100644 --- a/src/main/scala/firrtl/Emitter.scala +++ b/src/main/scala/firrtl/Emitter.scala @@ -11,6 +11,10 @@ import scala.io.Source import Utils._ import firrtl.passes._ +import WrappedExpression._ +// Datastructures +import scala.collection.mutable.HashMap +import scala.collection.mutable.ArrayBuffer trait Emitter extends LazyLogging { def run(c: Circuit, w: Writer) @@ -20,22 +24,562 @@ object FIRRTLEmitter extends Emitter { def run(c: Circuit, w: Writer) = w.write(c.serialize) } +case class VIndent() +case class VRandom() object VerilogEmitter extends Emitter { - // Currently just trap into Stanza - def run(c: Circuit, w: Writer) - { - logger.debug(s"Verilog Emitter is not yet implemented in Scala") - val toStanza = Files.createTempFile(Paths.get(""), "verilog", ".fir") - val fromStanza = Files.createTempFile(Paths.get(""), "verilog", ".fir") - Files.write(toStanza, c.serialize.getBytes) - - val cmd = Seq("firrtl-stanza", "-i", toStanza.toString, "-o", fromStanza.toString, "-b", "verilog") - logger.debug(cmd.mkString(" ")) - val ret = cmd.! - // Copy from Stanza output to user requested outputFile (we can't get filename from Writer) - Source.fromFile(fromStanza.toString) foreach { w.write(_) } - - Files.delete(toStanza) - Files.delete(fromStanza) - } + val tab = " " + val ran = VRandom() + var w:Option[Writer] = None + var mname = "" + def wref (n:String,t:Type) = WRef(n,t,ExpKind(),UNKNOWNGENDER) + def escape (s:String) : String = { + val sx = ArrayBuffer[String]() + sx += "\"" + var percent:Boolean = false + for (c <- s) { + if (c == '\n') sx += "\\n" + else { + if((c == 'x') && percent) sx += "h" else sx += c.toString + } + percent = (c == '%') + } + sx += "\"" + sx.reduce(_ + _) + } + def remove_root (ex:Expression) : Expression = { + (ex.as[WSubField].get.exp) match { + case (e:WSubField) => remove_root(e) + case (e:WRef) => WRef(ex.as[WSubField].get.name,tpe(ex),InstanceKind(),UNKNOWNGENDER) + } + } + def not_empty (s:ArrayBuffer[_]) : Boolean = if (s.size == 0) false else true + def rand_string (t:Type) : Seq[Any] = { + val wx = ((long_BANG(t) + 31) / 32) + Seq("{",wx,"{",ran,"}}") + } + def emit (x:Any) = emit2(x,0) + def emit2 (x:Any, top:Int) : Unit = { + def cast (e:Expression) : Any = { + (tpe(e)) match { + case (t:UIntType) => e + case (t:SIntType) => Seq("$signed(",e,")") + } + } + (x) match { + case (e:Expression) => { + (e) match { + case (e:DoPrim) => emit2(op_stream(e), top + 1) + case (e:Mux) => emit2(Seq(e.cond," ? ",cast(e.tval)," : ",cast(e.fval)),top + 1) + case (e:ValidIf) => emit2(Seq(cast(e.value)),top + 1) + case (e:WRef) => w.get.write(e.serialize()) + case (e:WSubField) => w.get.write(lowered_name(e)) + case (e:WSubAccess) => w.get.write(lowered_name(e.exp) + "[" + lowered_name(e.index) + "]") + case (e:WSubIndex) => w.get.write(e.serialize()) + case (_:UIntValue|_:SIntValue) => v_print(e) + } + } + case (t:Type) => { + (t) match { + case (_:UIntType|_:SIntType) => + val wx = long_BANG(t) - 1 + if (wx > 0) w.get.write("[" + wx + ":0]") else w.get.write("") + case (t:ClockType) => w.get.write("") + case (t:VectorType) => + emit2(t.tpe, top + 1) + w.get.write("[" + (t.size - 1) + ":0]") + case (t) => error("Shouldn't be here"); w.get.write(t.serialize()) + } + } + case (p:Direction) => { + p match { + case INPUT => w.get.write("input") + case OUTPUT => w.get.write("output") + } + } + case (s:String) => w.get.write(s) + case (i:Int) => w.get.write(i) + case (i:Long) => w.get.write(i.toInt) + case (t:VIndent) => w.get.write(" ") + case (r:VRandom) => w.get.write("$random") + case (s:Seq[Any]) => { + s.foreach((x:Any) => emit2(x.as[Any], top + 1)) + if (top == 0) w.get.write("\n") + } + } + } + + //;------------- PASS ----------------- + def v_print (e:Expression) = { + e match { + case (e:UIntValue) => { + val str = e.value.toString + val out = str.substring(1,str.length() - 1) + w.get.write(long_BANG(tpe(e)).toString + "'" + out) + } + case (e:SIntValue) => { + val str = e.value.toString + val out = str.substring(1,str.length() - 1) + w.get.write(long_BANG(tpe(e)).toString + "'s" + out) + } + } + } + def op_stream (doprim:DoPrim) : Seq[Any] = { + def cast_if (e:Expression) : Any = { + val signed = doprim.args.find(x => tpe(x).typeof[SIntType]) + if (signed == None) e + else tpe(e) match { + case (t:SIntType) => Seq("$signed(",e,")") + case (t:UIntType) => Seq("$signed({1'b0,",e,"})") + } + } + def cast (e:Expression) : Any = { + (doprim.tpe) match { + case (t:UIntType) => e + case (t:SIntType) => Seq("$signed(",e,")") + } + } + def cast_as (e:Expression) : Any = { + (tpe(e)) match { + case (t:UIntType) => e + case (t:SIntType) => Seq("$signed(",e,")") + } + } + def a0 () : Expression = doprim.args(0) + def a1 () : Expression = doprim.args(1) + def a2 () : Expression = doprim.args(2) + def c0 () : Int = doprim.consts(0).toInt + def c1 () : Int = doprim.consts(1).toInt + + doprim.op match { + case ADD_OP => Seq(cast_if(a0())," + ", cast_if(a1())) + case ADDW_OP => Seq(cast_if(a0())," + ", cast_if(a1())) + case SUB_OP => Seq(cast_if(a0())," _ ", cast_if(a1())) + case SUBW_OP => Seq(cast_if(a0())," _ ", cast_if(a1())) + case MUL_OP => Seq(cast_if(a0())," * ", cast_if(a1()) ) + case DIV_OP => Seq(cast_if(a0())," / ", cast_if(a1()) ) + case REM_OP => Seq(cast_if(a0())," % ", cast_if(a1()) ) + case LESS_OP => Seq(cast_if(a0())," < ", cast_if(a1())) + case LESS_EQ_OP => Seq(cast_if(a0())," <= ", cast_if(a1())) + case GREATER_OP => Seq(cast_if(a0())," > ", cast_if(a1())) + case GREATER_EQ_OP => Seq(cast_if(a0())," >= ", cast_if(a1())) + case EQUAL_OP => Seq(cast_if(a0())," == ", cast_if(a1())) + case NEQUAL_OP => Seq(cast_if(a0())," != ", cast_if(a1())) + case PAD_OP => { + val w = long_BANG(tpe(a0())) + val diff = (c0() - w) + if (w == 0) Seq(a0()) + else doprim.tpe match { + case (t:SIntType) => Seq("{{",diff,"{",a0(),"[",w - 1,"]}}, ",a0()," }") + case (t) => Seq("{{",diff,"'d0 }, ",a0()," }") + } + } + case AS_UINT_OP => Seq("$unsigned(",a0(),")") + case AS_SINT_OP => Seq("$signed(",a0(),")") + case AS_CLOCK_OP => Seq("$unsigned(",a0(),")") + case DYN_SHIFT_LEFT_OP => Seq(cast(a0())," << ", a1()) + case DYN_SHIFT_RIGHT_OP => { + (doprim.tpe) match { + case (t:SIntType) => Seq(cast(a0())," >>> ",a1()) + case (t) => Seq(cast(a0())," >> ",a1()) + } + } + case SHIFT_LEFT_OP => Seq(cast(a0())," << ",c0()) + case SHIFT_RIGHT_OP => Seq(a0(),"[", long_BANG(tpe(a0())) - 1,":",c0(),"]") + case NEG_OP => Seq("-{",cast(a0()),"}") + case CONVERT_OP => { + tpe(a0()) match { + case (t:UIntType) => Seq("{1'b0,",cast(a0()),"}") + case (t:SIntType) => Seq(cast(a0())) + } + } + case NOT_OP => Seq("~",a0()) + case AND_OP => Seq(cast_as(a0())," & ", cast_as(a1())) + case OR_OP => Seq(cast_as(a0())," | ", cast_as(a1())) + case XOR_OP => Seq(cast_as(a0())," ^ ", cast_as(a1())) + case AND_REDUCE_OP => { + val v = ArrayBuffer[Seq[Any]]() + for (b <- 0 until long_BANG(doprim.tpe).toInt) { + v += Seq(cast(a0()),"[",b,"]") + } + v.reduce(_ + " & " + _) + } + case OR_REDUCE_OP => { + val v = ArrayBuffer[Seq[Any]]() + for (b <- 0 until long_BANG(doprim.tpe).toInt) { + v += Seq(cast(a0()),"[",b,"]") + } + v.reduce(_ + " | " + _) + } + case XOR_REDUCE_OP => { + val v = ArrayBuffer[Seq[Any]]() + for (b <- 0 until long_BANG(doprim.tpe).toInt) { + v += Seq(cast(a0()),"[",b,"]") + } + v.reduce(_ + " ^ " + _) + } + case CONCAT_OP => Seq("{",cast(a0()),",",cast(a1()),"}") + case BITS_SELECT_OP => { + if (c0() == c1()) Seq(a0(),"[",c0(),"]") + else Seq(a0(),"[",c0(),":",c1(),"]") + } + case HEAD_OP => { + val w = long_BANG(tpe(a0())) + val high = w - 1 + val low = w - c0() + Seq(a0(),"[",high,":",low,"]") + } + case TAIL_OP => { + val w = long_BANG(tpe(a0())) + val low = w - c0() - 1 + Seq(a0(),"[",low,":",0,"]") + } + } + } + + def emit_verilog (m:InModule) : Module = { + mname = m.name + val netlist = HashMap[WrappedExpression,Expression]() + val simlist = ArrayBuffer[Stmt]() + val namehash = sym_hash + def build_netlist (s:Stmt) : Stmt = { + s match { + case (s:Connect) => netlist(s.loc) = s.exp + case (s:IsInvalid) => { + val n = firrtl_gensym("GEN",namehash) + val e = wref(n,tpe(s.exp)) + netlist(s.exp) = e + } + case (s:Conditionally) => simlist += s + case (s:DefNode) => { + val e = WRef(s.name,get_type(s),NodeKind(),MALE) + netlist(e) = s.value + } + case (s) => sMap(build_netlist,s) + } + s + } + + val portdefs = ArrayBuffer[Seq[Any]]() + val declares = ArrayBuffer[Seq[Any]]() + val instdeclares = ArrayBuffer[Seq[Any]]() + val assigns = ArrayBuffer[Seq[Any]]() + val at_clock = HashMap[Expression,ArrayBuffer[Seq[Any]]]() + val initials = ArrayBuffer[Seq[Any]]() + val simulates = ArrayBuffer[Seq[Any]]() + def declare (b:String,n:String,t:Type) = { + t match { + case (t:VectorType) => declares += Seq(b," ",t.tpe," ",n," [0:",t.size - 1,"];") + case (t) => declares += Seq(b," ",t," ",n,";") + } + } + def assign (e:Expression,value:Expression) = + assigns += Seq("assign ",e," = ",value,";") + def update_and_reset (r:Expression,clk:Expression,reset:Expression,init:Expression) = { + if (!at_clock.contains(clk)) { at_clock(clk) = ArrayBuffer[Seq[Any]]() } + def add_update (e:Expression,tabs:String) : Unit = { + e match { + case (e:Mux) => { + at_clock(clk) += Seq(tabs,"if(",e.cond,") begin") + add_update(e.tval,tabs + tab) + at_clock(clk) += Seq(tabs,"end else begin") + add_update(e.fval,tabs + tab) + at_clock(clk) += Seq(tabs,"end") + } + case (e) => { + if (e == r) at_clock(clk) += Seq(tabs,";") + else at_clock(clk) += Seq(tabs,r," <= ",e,";") + } + } + } + val tv = init + val fv = netlist(r) + add_update(Mux(reset,tv,fv,mux_type_and_widths(tv,fv)),"") + } + def update (e:Expression,value:Expression,clk:Expression,en:Expression) = { + if (at_clock.contains(clk)) at_clock(clk) = ArrayBuffer[Seq[Any]]() + if (weq(en,one)) at_clock(clk) += Seq(e," <= ",value,";") + else { + at_clock(clk) += Seq("if(",en,") begin") + at_clock(clk) += Seq(tab,e," <= ",value,";") + at_clock(clk) += Seq("end") + } + } + def initialize (e:Expression) = initials += Seq(e," = ",rand_string(tpe(e)),";") + def initialize_mem (n:String,i:Int,t:Type) = { + initials += Seq("for (initvar = 0; initvar < ",i,"; initvar = initvar+1)") + val index = WRef("initvar",UnknownType(),ExpKind(),UNKNOWNGENDER) + initials += Seq(tab,WSubAccess(wref(n,t),index,UnknownType(),FEMALE), " = ",rand_string(t),";") + } + def instantiate (n:String,m:String,es:Seq[Expression]) = { + instdeclares += Seq(m," ",n," (") + (es,0 until es.size).zipped.foreach{ (e,i) => { + val s = Seq(tab,".",remove_root(e),"(",lowered_name(e),")") + if (i != es.size - 1) instdeclares += Seq(s,",") + else instdeclares += s + }} + instdeclares += Seq(");") + for (e <- es) { + declare("wire",lowered_name(e),tpe(e)) + val ex = WRef(lowered_name(e),tpe(e),kind(e),gender(e)) + if (gender(e) == FEMALE) assign(ex,netlist(e)) + } + } + def simulate (clk:Expression,en:Expression,s:Seq[Any]) = { + if (!at_clock.contains(clk)) at_clock(clk) = ArrayBuffer[Seq[Any]]() + at_clock(clk) += Seq("`ifndef SYNTHESIS") + at_clock(clk) += Seq(tab,"if(",en,") begin") + at_clock(clk) += Seq(tab,tab,s) + at_clock(clk) += Seq(tab,"end") + at_clock(clk) += Seq("`endif") + } + def stop (ret:Int) : Seq[Any] = { + Seq("$fdisplay(32'h80000002,\"",ret,"\");$finish;") + } + def printf (str:String,args:Seq[Expression]) : Seq[Any] = { + val strx = (Seq(escape(str)) ++ args).reduce(_ + "," + _) + Seq("$fwrite(32'h80000002,",strx,");") + } + def delay (e:Expression, n:Int, clk:Expression) : Expression = { + var ex = e + for (i <- 0 until n) { + val name = firrtl_gensym("GEN",namehash) + declare("reg",name,tpe(e)) + val exx = WRef(name,tpe(e),ExpKind(),UNKNOWNGENDER) + update(exx,ex,clk,one) + ex = exx + } + ex + } + def build_ports () = { + (m.ports,0 until m.ports.size).zipped.foreach{(p,i) => { + var end = ",\n" + if (m.ports.size - 1 == i) end = "\n);\n" + p.direction match { + case INPUT => portdefs += Seq(p.direction," ",p.tpe," ",p.name) + case OUTPUT => { + portdefs += Seq(p.direction," ",p.tpe," ",p.name) + val ex = WRef(p.name,p.tpe,PortKind(),FEMALE) + assign(ex,netlist(ex)) + } + } + }} + if (m.ports.size == 0) w.get.write(");\n") + } + def build_streams (s:Stmt) : Stmt = { + s match { + case (s:Connect) => s + case (s:DefWire) => + declare("wire",s.name,s.tpe) + val e = wref(s.name,s.tpe) + assign(e,netlist(e)) + case (s:DefRegister) => { + declare("reg",s.name,s.tpe) + val e = wref(s.name,s.tpe) + update_and_reset(e,s.clock,s.reset,s.init) + initialize(e) + } + case (s:IsInvalid) => { + val wref = netlist(s.exp).as[WRef].get + declare("reg",wref.name,tpe(s.exp)) + initialize(wref) + } + case (s:DefPoison) => { + val n = s.name + val e = wref(n,s.tpe) + declare("reg",n,tpe(e)) + initialize(e) + } + case (s:DefNode) => { + declare("wire",s.name,tpe(s.value)) + assign(WRef(s.name,tpe(s.value),NodeKind(),MALE),s.value) + } + case (s:Stop) => simulate(s.clk,s.en,stop(s.ret)) + case (s:Print) => simulate(s.clk,s.en,printf(s.string,s.args)) + case (s:WDefInstance) => { + val es = create_exps(WRef(s.name,s.tpe,InstanceKind(),MALE)) + instantiate(s.name,s.module,es) + } + case (s:DefMemory) => { + val mem = WRef(s.name,get_type(s),MemKind(s.readers ++ s.writers ++ s.readwriters),UNKNOWNGENDER) + def mem_exp (p:String,f:String) = { + val t1 = field_type(mem.tpe,p) + val t2 = field_type(t1,f) + val x = WSubField(mem,p,t1,UNKNOWNGENDER) + WSubField(x,f,t2,UNKNOWNGENDER) + } + + declare("reg",s.name,VectorType(s.data_type,s.depth)) + initialize_mem(s.name,s.depth,s.data_type) + for (r <- s.readers ) { + val data = mem_exp(r,"data") + val addr = mem_exp(r,"addr") + val en = mem_exp(r,"en") + val clk = mem_exp(r,"clk") + + declare("wire",lowered_name(data),tpe(data)) + declare("wire",lowered_name(addr),tpe(addr)) + declare("wire",lowered_name(en),tpe(en)) + declare("wire",lowered_name(clk),tpe(clk)) + + //; Read port + assign(addr,netlist(addr)) //;Connects value to m.r.addr + assign(en,netlist(en)) //;Connects value to m.r.en + assign(clk,netlist(clk)) //;Connects value to m.r.clk + val addrx = delay(addr,s.read_latency,clk) + val enx = delay(en,s.read_latency,clk) + val mem_port = WSubAccess(mem,addrx,UnknownType(),UNKNOWNGENDER) + assign(data,mem_port) + } + + for (w <- s.writers ) { + val data = mem_exp(w,"data") + val addr = mem_exp(w,"addr") + val mask = mem_exp(w,"mask") + val en = mem_exp(w,"en") + val clk = mem_exp(w,"clk") + + declare("wire",lowered_name(data),tpe(data)) + declare("wire",lowered_name(addr),tpe(addr)) + declare("wire",lowered_name(mask),tpe(mask)) + declare("wire",lowered_name(en),tpe(en)) + declare("wire",lowered_name(clk),tpe(clk)) + + //; Write port + assign(data,netlist(data)) + assign(addr,netlist(addr)) + assign(mask,netlist(mask)) + assign(en,netlist(en)) + assign(clk,netlist(clk)) + + val datax = delay(data,s.write_latency - 1,clk) + val addrx = delay(addr,s.write_latency - 1,clk) + val maskx = delay(mask,s.write_latency - 1,clk) + val enx = delay(en,s.write_latency - 1,clk) + val mem_port = WSubAccess(mem,addrx,UnknownType(),UNKNOWNGENDER) + update(mem_port,datax,clk,AND(enx,maskx)) + } + + for (rw <- s.readwriters) { + val wmode = mem_exp(rw,"wmode") + val rdata = mem_exp(rw,"rdata") + val data = mem_exp(rw,"data") + val mask = mem_exp(rw,"mask") + val addr = mem_exp(rw,"addr") + val en = mem_exp(rw,"en") + val clk = mem_exp(rw,"clk") + + declare("wire",lowered_name(wmode),tpe(wmode)) + declare("wire",lowered_name(rdata),tpe(rdata)) + declare("wire",lowered_name(data),tpe(data)) + declare("wire",lowered_name(mask),tpe(mask)) + declare("wire",lowered_name(addr),tpe(addr)) + declare("wire",lowered_name(en),tpe(en)) + declare("wire",lowered_name(clk),tpe(clk)) + + //; Assigned to lowered wires of each + assign(clk,netlist(clk)) + assign(addr,netlist(addr)) + assign(data,netlist(data)) + assign(addr,netlist(addr)) + assign(mask,netlist(mask)) + assign(en,netlist(en)) + assign(wmode,netlist(wmode)) + + //; Delay new signals by latency + val raddrx = delay(addr,s.read_latency,clk) + val waddrx = delay(addr,s.write_latency - 1,clk) + val enx = delay(en,s.write_latency - 1,clk) + val rmodx = delay(wmode,s.write_latency - 1,clk) + val datax = delay(data,s.write_latency - 1,clk) + val maskx = delay(mask,s.write_latency - 1,clk) + + //; Write + + val rmem_port = WSubAccess(mem,raddrx,UnknownType(),UNKNOWNGENDER) + assign(rdata,rmem_port) + val wmem_port = WSubAccess(mem,waddrx,UnknownType(),UNKNOWNGENDER) + update(wmem_port,datax,clk,AND(AND(enx,maskx),wmode)) + } + } + case (s:Begin) => sMap(build_streams _,s) + } + s + } + + def emit_streams () = { + emit(Seq("module ",m.name,"(")) + if (not_empty(portdefs)) { + (portdefs,0 until portdefs.size).zipped.foreach{ (x,i) => { + if (i != portdefs.size - 1) emit(Seq(tab,x,",")) + else emit(Seq(tab,x)) + }} + } + emit(Seq(");")) + + if (not_empty(declares)) { + for (x <- declares) emit(Seq(tab,x)) + } + if (not_empty(instdeclares)) { + for (x <- instdeclares) emit(Seq(tab,x)) + } + if (not_empty(assigns)) { + for (x <- assigns) emit(Seq(tab,x)) + } + if (not_empty(initials)) { + emit(Seq("`ifndef SYNTHESIS")) + emit(Seq(" integer initvar;")) + emit(Seq(" initial begin")) + emit(Seq(" #0.002;")) + for (x <- initials) { + emit(Seq(tab,x)) + } + emit(Seq(" end")) + emit(Seq("`endif")) + } + + for (clk_stream <- at_clock) { + if (not_empty(clk_stream._2)) { + emit(Seq(tab,"always @(posedge ",clk_stream._1,") begin")) + for (x <- clk_stream._2) { + emit(Seq(tab,tab,x)) + } + emit(Seq(tab,"end")) + } + } + + emit(Seq("endmodule")) + } + + build_netlist(m.body) + build_ports() + build_streams(m.body) + emit_streams() + m + } + + def run(c: Circuit, w: Writer) = { + this.w = Some(w) + for (m <- c.modules) { + m match { + case (m:InModule) => emit_verilog(m) + case (m:ExModule) => false + } + } + } + //def run(c: Circuit, w: Writer) + //{ + // logger.debug(s"Verilog Emitter is not yet implemented in Scala") + // val toStanza = Files.createTempFile(Paths.get(""), "verilog", ".fir") + // val fromStanza = Files.createTempFile(Paths.get(""), "verilog", ".fir") + // Files.write(toStanza, c.serialize.getBytes) + + // val cmd = Seq("firrtl-stanza", "-i", toStanza.toString, "-o", fromStanza.toString, "-b", "verilog") + // logger.debug(cmd.mkString(" ")) + // val ret = cmd.! + // // Copy from Stanza output to user requested outputFile (we can't get filename from Writer) + // Source.fromFile(fromStanza.toString) foreach { w.write(_) } + + // Files.delete(toStanza) + // Files.delete(fromStanza) + //} } diff --git a/src/main/scala/firrtl/PrimOps.scala b/src/main/scala/firrtl/PrimOps.scala index 790fa538..f947be35 100644 --- a/src/main/scala/firrtl/PrimOps.scala +++ b/src/main/scala/firrtl/PrimOps.scala @@ -40,7 +40,11 @@ object PrimOps extends LazyLogging { CONCAT_OP -> "cat", BITS_SELECT_OP -> "bits", HEAD_OP -> "head", - TAIL_OP -> "tail" + TAIL_OP -> "tail", + + //This are custom, we need to refactor to enable easily extending FIRRTL with custom primops + ADDW_OP -> "addw", + SUBW_OP -> "subw" ) lazy val listing: Seq[String] = PrimOps.mapPrimOp2String.map { case (k,v) => v } toSeq private val mapString2PrimOp = mapPrimOp2String.map(_.swap) diff --git a/src/main/scala/firrtl/Utils.scala b/src/main/scala/firrtl/Utils.scala index b9fb49c6..b66b0932 100644 --- a/src/main/scala/firrtl/Utils.scala +++ b/src/main/scala/firrtl/Utils.scala @@ -125,6 +125,13 @@ object Utils { } } } + def lowered_name (e:Expression) : String = { + (e) match { + case (e:WRef) => e.name + case (e:WSubField) => lowered_name(e.exp) + "_" + e.name + case (e:WSubIndex) => lowered_name(e.exp) + "_" + e.value + } + } def get_flip (t:Type, i:Int, f:Flip) : Flip = { if (i >= get_size(t)) error("Shouldn't be here") val x = t match { @@ -228,6 +235,19 @@ object Utils { case t => error("No width!") } } + def long_BANG (t:Type) : Long = { + (t) match { + case (t:UIntType) => t.width.as[IntWidth].get.width.toLong + case (t:SIntType) => t.width.as[IntWidth].get.width.toLong + case (t:BundleType) => { + var w = 0 + for (f <- t.fields) { w = w + long_BANG(f.tpe).toInt } + w + } + case (t:VectorType) => t.size * long_BANG(t.tpe) + case (t:ClockType) => 1 + } + } // ================================= def error(str:String) = throw new FIRRTLException(str) def debug(node: AST)(implicit flags: FlagMap): String = { diff --git a/src/main/scala/firrtl/WIR.scala b/src/main/scala/firrtl/WIR.scala index 26e3a131..8ebfa9a6 100644 --- a/src/main/scala/firrtl/WIR.scala +++ b/src/main/scala/firrtl/WIR.scala @@ -4,7 +4,6 @@ package firrtl import scala.collection.Seq import Utils._ - trait Kind case class WireKind() extends Kind case class PoisonKind() extends Kind @@ -29,6 +28,14 @@ case class WVoid() extends Expression case class WInvalid() extends Expression case class WDefInstance(info:Info,name:String,module:String,tpe:Type) extends Stmt +case object ADDW_OP extends PrimOp +case object SUBW_OP extends PrimOp + +object WrappedExpression { + def apply (e:Expression) = new WrappedExpression(e) + def we (e:Expression) = new WrappedExpression(e) + def weq (e1:Expression,e2:Expression) = we(e1) == we(e2) +} class WrappedExpression (val e1:Expression) { override def equals (we:Any) = { we match { diff --git a/src/main/scala/firrtl/passes/Passes.scala b/src/main/scala/firrtl/passes/Passes.scala index d3d7027a..89d27733 100644 --- a/src/main/scala/firrtl/passes/Passes.scala +++ b/src/main/scala/firrtl/passes/Passes.scala @@ -906,7 +906,7 @@ object RemoveAccesses extends Pass { } } -object ExpandWhens extends Pass with StanzaPass { +object ExpandWhens extends Pass { def name = "Expand Whens" var mname = "" // ; ========== Expand When Utilz ========== @@ -1111,7 +1111,62 @@ object CheckInitialization extends Pass with StanzaPass { object ConstProp extends Pass with StanzaPass { def name = "Constant Propogation" + var mname = "" def run (c:Circuit): Circuit = stanzaPass(c, "const-prop") + def const_prop_e (e:Expression) : Expression = { + eMap(const_prop_e _,e) match { + case (e:DoPrim) => { + e.op match { + case SHIFT_RIGHT_OP => { + (e.args(0)) match { + case (x:UIntValue) => { + val b = x.value >> e.consts(0).toInt + UIntValue(b,tpe(e).as[UIntType].get.width) + } + case (x:SIntValue) => { + val b = x.value >> e.consts(0).toInt + SIntValue(b,tpe(e).as[SIntType].get.width) + } + case (x) => e + } + } + case BITS_SELECT_OP => { + e.args(0) match { + case (x:UIntValue) => { + val hi = e.consts(0).toInt + val lo = e.consts(1).toInt + require(hi >= lo) + val b = (x.value >> lo) & ((BigInt(1) << (hi - lo + 1)) - 1) + UIntValue(b,tpe(e).as[UIntType].get.width) + } + case (x) => { + if (long_BANG(tpe(e)) == long_BANG(tpe(x))) { + if (tpe(x).typeof[UIntType] != None) x + else DoPrim(AS_UINT_OP,Seq(x),Seq(),tpe(e)) + } + else e + } + } + } + case (_) => e + } + } + case (e) => e + } + } + def const_prop_s (s:Stmt) : Stmt = eMap(const_prop_e _, sMap(const_prop_s _,s)) + def const_prop (c:Circuit) : Circuit = { + val modulesx = c.modules.map{ m => { + m match { + case (m:ExModule) => m + case (m:InModule) => { + mname = m.name + InModule(m.info,m.name,m.ports,const_prop_s(m.body)) + } + } + }} + Circuit(c.info,modulesx,c.main) + } } object LoToVerilog extends Pass with StanzaPass { @@ -1119,19 +1174,113 @@ object LoToVerilog extends Pass with StanzaPass { def run (c:Circuit): Circuit = stanzaPass(c, "lo-to-verilog") } -object VerilogWrap extends Pass with StanzaPass { +object FromCHIRRTL extends Pass with StanzaPass { + def name = "From CHIRRTL" + def run (c:Circuit): Circuit = stanzaPass(c, "from-chirrtl") +} + +object VerilogWrap extends Pass { def name = "Verilog Wrap" - def run (c:Circuit): Circuit = stanzaPass(c, "verilog-wrap") + var mname = "" + def v_wrap_e (e:Expression) : Expression = { + eMap(v_wrap_e _,e) match { + case (e:DoPrim) => { + def a0 () = e.args(0) + if (e.op == TAIL_OP) { + (a0()) match { + case (e0:DoPrim) => { + if (e0.op == ADD_OP) DoPrim(ADDW_OP,e0.args,Seq(),tpe(e)) + else if (e0.op == SUB_OP) DoPrim(SUBW_OP,e0.args,Seq(),tpe(e)) + else e + } + case (e0) => e + } + } + else e + } + case (e) => e + } + } + def v_wrap_s (s:Stmt) : Stmt = eMap(v_wrap_e _,sMap(v_wrap_s _,s)) + def run (c:Circuit): Circuit = { + val modulesx = c.modules.map{ m => { + (m) match { + case (m:InModule) => { + mname = m.name + InModule(m.info,m.name,m.ports,v_wrap_s(m.body)) + } + case (m:ExModule) => m + } + }} + Circuit(c.info,modulesx,c.main) + } } -object SplitExp extends Pass with StanzaPass { +object SplitExp extends Pass { def name = "Split Expressions" - def run (c:Circuit): Circuit = stanzaPass(c, "split-expressions") + var mname = "" + def split_exp (m:InModule) : InModule = { + mname = m.name + val v = ArrayBuffer[Stmt]() + val sh = sym_hash + def split_exp_s (s:Stmt) : Stmt = { + def split (e:Expression) : Expression = { + val n = firrtl_gensym("GEN",sh) + v += DefNode(info(s),n,e) + WRef(n,tpe(e),kind(e),gender(e)) + } + def split_exp_e (i:Int)(e:Expression) : Expression = { + eMap(split_exp_e(i + 1) _,e) match { + case (e:DoPrim) => if (i > 0) split(e) else e + case (e) => e + } + } + eMap(split_exp_e(0) _,s) match { + case (s:Begin) => sMap(split_exp_s _,s) + case (s) => v += s; s + } + } + split_exp_s(m.body) + InModule(m.info,m.name,m.ports,Begin(v)) + } + + def run (c:Circuit): Circuit = { + val modulesx = c.modules.map{ m => { + (m) match { + case (m:InModule) => split_exp(m) + case (m:ExModule) => m + } + }} + Circuit(c.info,modulesx,c.main) + } } -object VerilogRename extends Pass with StanzaPass { +object VerilogRename extends Pass { def name = "Verilog Rename" - def run (c:Circuit): Circuit = stanzaPass(c, "verilog-rename") + def run (c:Circuit): Circuit = { + def verilog_rename_n (n:String) : String = { + if (v_keywords.contains(n)) (n + "$") else n + } + def verilog_rename_e (e:Expression) : Expression = { + (e) match { + case (e:WRef) => WRef(verilog_rename_n(e.name),e.tpe,kind(e),gender(e)) + case (e) => eMap(verilog_rename_e,e) + } + } + def verilog_rename_s (s:Stmt) : Stmt = { + stMap(verilog_rename_n _,eMap(verilog_rename_e _,sMap(verilog_rename_s _,s))) + } + val modulesx = c.modules.map{ m => { + val portsx = m.ports.map{ p => { + Port(p.info,verilog_rename_n(p.name),p.direction,p.tpe) + }} + m match { + case (m:InModule) => InModule(m.info,m.name,portsx,verilog_rename_s(m.body)) + case (m:ExModule) => m + } + }} + Circuit(c.info,modulesx,c.main) + } } object LowerTypes extends Pass { @@ -1204,13 +1353,6 @@ object LowerTypes extends Pass { } } def merge (a:String,b:String,x:String) : String = a + x + b - def lowered_name (e:Expression) : String = { - (e) match { - case (e:WRef) => e.name - case (e:WSubField) => lowered_name(e.exp) + "_" + e.name - case (e:WSubIndex) => lowered_name(e.exp) + "_" + e.value - } - } def root_ref (e:Expression) : WRef = { (e) match { case (e:WRef) => e diff --git a/src/main/stanza/chirrtl.stanza b/src/main/stanza/chirrtl.stanza index 0a07fcf0..fc770764 100644 --- a/src/main/stanza/chirrtl.stanza +++ b/src/main/stanza/chirrtl.stanza @@ -11,6 +11,7 @@ public val chirrtl-passes = to-list $ [ CInferTypes() CInferMDir() RemoveCHIRRTL() + FromCHIRRTL() ] ; =============================== @@ -421,3 +422,18 @@ defn remove-chirrtl (c:Circuit) : (m:ExModule) : m +;============ FromCHIRRTL ============== + +public defstruct FromCHIRRTL <: Pass +public defmethod pass (b:FromCHIRRTL) -> (Circuit -> Circuit) : from-chirrtl +public defmethod name (b:FromCHIRRTL) -> String : "From CHIRRTL" +public defmethod short-name (b:FromCHIRRTL) -> String : "from-chirrtl" + +defn from-chirrtl (c:Circuit) -> Circuit : + val c1 = c-infer-types(c) + ;println(c1) + val c2 = infer-mdir(c1) + ;println(c2) + val c3 = remove-chirrtl(c2) + ;println(c3) + c3 diff --git a/src/main/stanza/passes.stanza b/src/main/stanza/passes.stanza index 155c1b0a..9d7a1b97 100644 --- a/src/main/stanza/passes.stanza +++ b/src/main/stanza/passes.stanza @@ -2895,3 +2895,5 @@ defn lo-to-verilog (with-output:(() -> False) -> False, c:Circuit) : val c5 = verilog-rename(c4) ;println(c5) emit-verilog(with-output,c5) + + |
