add SynFlops
This commit is contained in:
@@ -25,22 +25,10 @@ object MacroCompilerAnnotation {
|
||||
}
|
||||
}
|
||||
|
||||
class MacroCompilerPass(memFile: Option[File],
|
||||
libFile: Option[File]) extends firrtl.passes.Pass {
|
||||
require(memFile.isDefined)
|
||||
private val mems: Option[Seq[Macro]] = readJSON(memFile) map (_ map (x => new Macro(x)))
|
||||
private val libs: Option[Seq[Macro]] = readJSON(libFile) map (_ map (x => new Macro(x)))
|
||||
|
||||
class MacroCompilerPass(mems: Option[Seq[Macro]],
|
||||
libs: Option[Seq[Macro]]) extends firrtl.passes.Pass {
|
||||
def compile(mem: Macro, lib: Macro): Option[(Module, ExtModule)] = {
|
||||
val pairedPorts = (
|
||||
(mem.ports filter (p => p.inputName.isDefined && !p.outputName.isDefined)) ++ // write
|
||||
(mem.ports filter (p => !p.inputName.isDefined && p.outputName.isDefined)) ++ // read
|
||||
(mem.ports filter (p => p.inputName.isDefined && p.outputName.isDefined)) // read writers
|
||||
) zip (
|
||||
(lib.ports filter (p => p.inputName.isDefined && !p.outputName.isDefined)) ++ // write
|
||||
(lib.ports filter (p => !p.inputName.isDefined && p.outputName.isDefined)) ++ // read
|
||||
(lib.ports filter (p => p.inputName.isDefined && p.outputName.isDefined)) // read writers
|
||||
)
|
||||
val pairedPorts = mem.sortedPorts zip lib.sortedPorts
|
||||
|
||||
// Parallel mapping
|
||||
val pairs = ArrayBuffer[(BigInt, BigInt)]()
|
||||
@@ -74,7 +62,6 @@ class MacroCompilerPass(memFile: Option[File],
|
||||
pairs += ((last, mem.width.toInt - 1))
|
||||
|
||||
// Serial mapping
|
||||
val instType = BundleType(lib.ports flatMap (_.tpe.fields))
|
||||
val stmts = ArrayBuffer[Statement]()
|
||||
val selects = HashMap[String, Expression]()
|
||||
val outputs = HashMap[String, ArrayBuffer[(Expression, Expression)]]()
|
||||
@@ -93,7 +80,7 @@ class MacroCompilerPass(memFile: Option[File],
|
||||
for ((off, i) <- (0 until mem.depth.toInt by lib.depth.toInt).zipWithIndex) {
|
||||
for (j <- pairs.indices) {
|
||||
val name = s"mem_${i}_${j}"
|
||||
stmts += WDefInstance(NoInfo, name, lib.name, instType)
|
||||
stmts += WDefInstance(NoInfo, name, lib.name, lib.tpe)
|
||||
// connect extra ports
|
||||
stmts ++= lib.extraPorts map { case (portName, portValue) =>
|
||||
Connect(NoInfo, WSubField(WRef(name), portName), portValue)
|
||||
@@ -109,12 +96,7 @@ class MacroCompilerPass(memFile: Option[File],
|
||||
def andAddrMatch(e: Expression) = and(e, addrMatch)
|
||||
val cats = ArrayBuffer[Expression]()
|
||||
for (((low, high), j) <- pairs.zipWithIndex) {
|
||||
val inst = WRef(s"mem_${i}_${j}", instType)
|
||||
def invert(exp: Expression, polarity: Option[PortPolarity]) =
|
||||
polarity match {
|
||||
case Some(ActiveLow) | Some(NegativeEdge) => not(exp)
|
||||
case _ => exp
|
||||
}
|
||||
val inst = WRef(s"mem_${i}_${j}", lib.tpe)
|
||||
|
||||
def connectPorts(mem: Expression,
|
||||
lib: String,
|
||||
@@ -344,10 +326,13 @@ class MacroCompilerTransform extends Transform {
|
||||
def inputForm = HighForm
|
||||
def outputForm = HighForm
|
||||
def execute(state: CircuitState) = getMyAnnotations(state) match {
|
||||
case Seq(MacroCompilerAnnotation(state.circuit.main, mem, lib, synflops)) =>
|
||||
case Seq(MacroCompilerAnnotation(state.circuit.main, memFile, libFile, synflops)) =>
|
||||
require(memFile.isDefined)
|
||||
val mems: Option[Seq[Macro]] = readJSON(memFile) map (_ map (x => new Macro(x)))
|
||||
val libs: Option[Seq[Macro]] = readJSON(libFile) map (_ map (x => new Macro(x)))
|
||||
val transforms = Seq(
|
||||
new MacroCompilerPass(mem, lib),
|
||||
// TODO: Syn flops
|
||||
new MacroCompilerPass(mems, libs),
|
||||
new SynFlopsPass(synflops, libs getOrElse mems.get),
|
||||
firrtl.passes.SplitExpressions
|
||||
)
|
||||
((transforms foldLeft state)((s, xform) => xform runTransform s))
|
||||
@@ -359,7 +344,7 @@ class MacroCompiler extends Compiler {
|
||||
def transforms =
|
||||
Seq(new MacroCompilerTransform) ++
|
||||
getLoweringTransforms(firrtl.HighForm, firrtl.LowForm) // ++
|
||||
// Seq(new LowFirrtlOptimization) // Todo: This is dangerous...
|
||||
// Seq(new LowFirrtlOptimization) // Todo: This is dangerous
|
||||
}
|
||||
|
||||
object MacroCompiler extends App {
|
||||
|
||||
110
tapeout/src/main/scala/transforms/macros/SynFlops.scala
Normal file
110
tapeout/src/main/scala/transforms/macros/SynFlops.scala
Normal file
@@ -0,0 +1,110 @@
|
||||
// See LICENSE for license details.
|
||||
|
||||
package barstools.tapeout.transforms.macros
|
||||
|
||||
import firrtl._
|
||||
import firrtl.ir._
|
||||
import firrtl.Utils._
|
||||
import firrtl.passes.MemPortUtils.{memPortField, memType}
|
||||
import Utils._
|
||||
|
||||
class SynFlopsPass(synflops: Boolean, libs: Seq[Macro]) extends firrtl.passes.Pass {
|
||||
lazy val libMods = (libs map { lib => lib.name -> {
|
||||
val dataType = (lib.ports foldLeft (None: Option[BigInt]))((res, port) =>
|
||||
(res, port.maskName) match {
|
||||
case (_, None) =>
|
||||
res
|
||||
case (None, Some(_)) =>
|
||||
Some(port.effectiveMaskGran)
|
||||
case (Some(x), Some(_)) =>
|
||||
assert(x == port.effectiveMaskGran)
|
||||
res
|
||||
}
|
||||
) match {
|
||||
case None => UIntType(IntWidth(lib.width))
|
||||
case Some(gran) => VectorType(UIntType(IntWidth(gran)), (lib.width / gran).toInt)
|
||||
}
|
||||
|
||||
val mem = DefMemory(
|
||||
NoInfo,
|
||||
"ram",
|
||||
dataType,
|
||||
lib.depth.toInt,
|
||||
1, // writeLatency
|
||||
0, // readLatency
|
||||
(lib.readers ++ lib.readwriters).indices map (i => s"R_$i"),
|
||||
(lib.writers ++ lib.readwriters).indices map (i => s"W_$i"),
|
||||
Nil
|
||||
)
|
||||
|
||||
val readConnects = (lib.readers ++ lib.readwriters).zipWithIndex flatMap { case (r, i) =>
|
||||
val clock = invert(WRef(r.clockName), r.clockPolarity)
|
||||
val address = invert(WRef(r.addressName), r.addressPolarity)
|
||||
val enable = (r.chipEnableName, r.readEnableName) match {
|
||||
case (Some(en), Some(re)) =>
|
||||
and(invert(WRef(en), r.chipEnablePolarity),
|
||||
invert(WRef(re), r.readEnablePolarity))
|
||||
case (Some(en), None) => invert(WRef(en), r.chipEnablePolarity)
|
||||
case (None, Some(re)) => invert(WRef(re), r.readEnablePolarity)
|
||||
case (None, None) => one
|
||||
}
|
||||
val data = memPortField(mem, s"R_$i", "data")
|
||||
val read = (dataType: @unchecked) match {
|
||||
case VectorType(tpe, size) => cat(((0 until size) map (k =>
|
||||
WSubIndex(data, k, tpe, UNKNOWNGENDER))).reverse)
|
||||
case _: UIntType => data
|
||||
}
|
||||
val addrReg = WRef(s"R_${i}_addr_reg", r.AddrType, RegKind)
|
||||
Seq(
|
||||
DefRegister(NoInfo, addrReg.name, r.AddrType, clock, zero, addrReg),
|
||||
Connect(NoInfo, memPortField(mem, s"R_$i", "clk"), clock),
|
||||
Connect(NoInfo, memPortField(mem, s"R_$i", "addr"), addrReg),
|
||||
Connect(NoInfo, memPortField(mem, s"R_$i", "en"), enable),
|
||||
Connect(NoInfo, WRef(r.outputName.get), read),
|
||||
Connect(NoInfo, addrReg, Mux(enable, address, addrReg, UnknownType))
|
||||
)
|
||||
}
|
||||
|
||||
val writeConnects = (lib.writers ++ lib.readwriters).zipWithIndex flatMap { case (w, i) =>
|
||||
val clock = invert(WRef(w.clockName), w.clockPolarity)
|
||||
val address = invert(WRef(w.addressName), w.addressPolarity)
|
||||
val enable = (w.chipEnableName, w.writeEnableName) match {
|
||||
case (Some(en), Some(we)) =>
|
||||
and(invert(WRef(en), w.chipEnablePolarity),
|
||||
invert(WRef(we), w.writeEnablePolarity))
|
||||
case (Some(en), None) => invert(WRef(en), w.chipEnablePolarity)
|
||||
case (None, Some(we)) => invert(WRef(we), w.writeEnablePolarity)
|
||||
case (None, None) => zero // is it possible?
|
||||
}
|
||||
val mask = memPortField(mem, s"W_$i", "mask")
|
||||
val data = memPortField(mem, s"W_$i", "data")
|
||||
val write = invert(WRef(w.inputName.get), w.inputPolarity)
|
||||
Seq(
|
||||
Connect(NoInfo, memPortField(mem, s"W_$i", "clk"), clock),
|
||||
Connect(NoInfo, memPortField(mem, s"W_$i", "addr"), address),
|
||||
Connect(NoInfo, memPortField(mem, s"W_$i", "en"), enable)
|
||||
) ++ (dataType match {
|
||||
case VectorType(tpe, size) =>
|
||||
val width = bitWidth(tpe).toInt
|
||||
((0 until size) map (k =>
|
||||
Connect(NoInfo, WSubIndex(data, k, tpe, UNKNOWNGENDER),
|
||||
bits(write, (k + 1) * width - 1, k * width)))) ++
|
||||
((0 until size) map (k =>
|
||||
Connect(NoInfo, WSubIndex(mask, k, BoolType, UNKNOWNGENDER),
|
||||
bits(WRef(w.maskName.get), k))))
|
||||
case _: UIntType =>
|
||||
Seq(Connect(NoInfo, data, write), Connect(NoInfo, mask, one))
|
||||
})
|
||||
}
|
||||
lib.module(Block(mem +: (readConnects ++ writeConnects)))
|
||||
}}).toMap
|
||||
|
||||
def run(c: Circuit): Circuit = {
|
||||
if (!synflops) c
|
||||
else {
|
||||
val circuit = c.copy(modules = (c.modules map (m => libMods getOrElse (m.name, m))))
|
||||
// print(circuit.serialize)
|
||||
circuit
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -48,9 +48,9 @@ case class MacroPort(
|
||||
width: BigInt,
|
||||
depth: BigInt) {
|
||||
val effectiveMaskGran = maskGran.getOrElse(width)
|
||||
private val AddrType = UIntType(IntWidth(ceilLog2(depth) max 1))
|
||||
private val DataType = UIntType(IntWidth(width))
|
||||
private val MaskType = UIntType(IntWidth(width / effectiveMaskGran))
|
||||
val AddrType = UIntType(IntWidth(ceilLog2(depth) max 1))
|
||||
val DataType = UIntType(IntWidth(width))
|
||||
val MaskType = UIntType(IntWidth(width / effectiveMaskGran))
|
||||
val tpe = BundleType(Seq(
|
||||
Field(clockName, Flip, ClockType),
|
||||
Field(addressName, Flip, AddrType)) ++
|
||||
@@ -93,6 +93,10 @@ class Macro(lib: Map[String, Any]) {
|
||||
depth
|
||||
)
|
||||
}
|
||||
val writers = ports filter (p => p.inputName.isDefined && !p.outputName.isDefined)
|
||||
val readers = ports filter (p => !p.inputName.isDefined && p.outputName.isDefined)
|
||||
val readwriters = ports filter (p => p.inputName.isDefined && p.outputName.isDefined)
|
||||
val sortedPorts = writers ++ readers ++ readwriters
|
||||
val extraPorts = lib get "extra ports" match {
|
||||
case None => Nil
|
||||
case Some(p) => p.asInstanceOf[List[_]] map { x =>
|
||||
@@ -104,6 +108,7 @@ class Macro(lib: Map[String, Any]) {
|
||||
(name -> UIntLiteral(value, IntWidth(width)))
|
||||
}
|
||||
}
|
||||
val tpe = BundleType(ports flatMap (_.tpe.fields))
|
||||
private val modPorts = (ports flatMap (_.ports)) ++
|
||||
(extraPorts map { case (name, value) => Port(NoInfo, name, Input, value.tpe) })
|
||||
val blackbox = ExtModule(NoInfo, name, modPorts, name, Nil)
|
||||
@@ -140,4 +145,10 @@ object Utils {
|
||||
else DoPrim(PrimOps.Cat, Seq(es.head, cat(es.tail)), Nil, UnknownType)
|
||||
def not(e: Expression) =
|
||||
DoPrim(PrimOps.Not, Seq(e), Nil, e.tpe)
|
||||
|
||||
def invert(exp: Expression, polarity: Option[PortPolarity]) =
|
||||
polarity match {
|
||||
case Some(ActiveLow) | Some(NegativeEdge) => not(exp)
|
||||
case _ => exp
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ import firrtl.ir.{Circuit, NoInfo}
|
||||
import firrtl.passes.RemoveEmpty
|
||||
import firrtl.Parser.parse
|
||||
import java.io.{File, StringWriter}
|
||||
import Utils.readJSON
|
||||
|
||||
abstract class MacroCompilerSpec extends org.scalatest.FlatSpec with org.scalatest.Matchers {
|
||||
val macroDir = new File("tapeout/src/test/resources/macros")
|
||||
@@ -19,11 +20,16 @@ abstract class MacroCompilerSpec extends org.scalatest.FlatSpec with org.scalate
|
||||
MacroCompiler.run(args(mem, lib, v, synflops))
|
||||
}
|
||||
|
||||
def execute(mem: Option[File], lib: Option[File], synflops: Boolean, output: String) {
|
||||
require(mem.isDefined)
|
||||
val macros = Utils.readJSON(mem).get map (x => (new Macro(x)).blackbox)
|
||||
def execute(memFile: Option[File], libFile: Option[File], synflops: Boolean, output: String) {
|
||||
require(memFile.isDefined)
|
||||
val mems = readJSON(memFile) map (_ map (x => new Macro(x)))
|
||||
val libs = readJSON(libFile) map (_ map (x => new Macro(x)))
|
||||
val macros = mems.get map (_.blackbox)
|
||||
val circuit = Circuit(NoInfo, macros, macros.last.name)
|
||||
val passes = Seq(new MacroCompilerPass(mem, lib), RemoveEmpty)
|
||||
val passes = Seq(
|
||||
new MacroCompilerPass(mems, libs),
|
||||
new SynFlopsPass(synflops, libs getOrElse mems.get),
|
||||
RemoveEmpty)
|
||||
val result = (passes foldLeft circuit)((c, pass) => pass run c)
|
||||
val gold = RemoveEmpty run parse(output)
|
||||
(result.serialize) should be (gold.serialize)
|
||||
|
||||
333
tapeout/src/test/scala/transforms/macros/SynFlops.scala
Normal file
333
tapeout/src/test/scala/transforms/macros/SynFlops.scala
Normal file
@@ -0,0 +1,333 @@
|
||||
package barstools.tapeout.transforms.macros
|
||||
|
||||
import java.io.File
|
||||
|
||||
class Synflops2048x16_mrw extends MacroCompilerSpec {
|
||||
val mem = new File(macroDir, "mem-2048x16-mrw.json")
|
||||
val v = new File(testDir, "syn_flops_2048x16_mrw.v")
|
||||
val output =
|
||||
"""
|
||||
circuit name_of_sram_module :
|
||||
module name_of_sram_module :
|
||||
input clock : Clock
|
||||
input RW0A : UInt<11>
|
||||
input RW0I : UInt<16>
|
||||
output RW0O : UInt<16>
|
||||
input RW0E : UInt<1>
|
||||
input RW0W : UInt<1>
|
||||
input RW0M : UInt<2>
|
||||
|
||||
mem ram :
|
||||
data-type => UInt<8>[2]
|
||||
depth => 2048
|
||||
read-latency => 0
|
||||
write-latency => 1
|
||||
reader => R_0
|
||||
writer => W_0
|
||||
read-under-write => undefined
|
||||
reg R_0_addr_reg : UInt<11>, clock with :
|
||||
reset => (UInt<1>("h0"), R_0_addr_reg)
|
||||
ram.R_0.clk <= clock
|
||||
ram.R_0.addr <= R_0_addr_reg
|
||||
ram.R_0.en <= RW0E
|
||||
RW0O <= cat(ram.R_0.data[1], ram.R_0.data[0])
|
||||
R_0_addr_reg <= mux(RW0E, RW0A, R_0_addr_reg)
|
||||
ram.W_0.clk <= clock
|
||||
ram.W_0.addr <= RW0A
|
||||
ram.W_0.en <= and(RW0E, RW0W)
|
||||
ram.W_0.data[0] <= bits(RW0I, 7, 0)
|
||||
ram.W_0.data[1] <= bits(RW0I, 15, 8)
|
||||
ram.W_0.mask[0] <= bits(RW0M, 0, 0)
|
||||
ram.W_0.mask[1] <= bits(RW0M, 1, 1)
|
||||
"""
|
||||
compile(mem, None, v, true)
|
||||
execute(Some(mem), None, true, output)
|
||||
}
|
||||
|
||||
class Synflops2048x8_r_mw extends MacroCompilerSpec {
|
||||
val mem = new File(macroDir, "mem-2048x8-r-mw.json")
|
||||
val v = new File(testDir, "syn_flops_2048x8_r_mw.v")
|
||||
val output =
|
||||
"""
|
||||
circuit name_of_sram_module :
|
||||
module name_of_sram_module :
|
||||
input clock : Clock
|
||||
input W0A : UInt<11>
|
||||
input W0I : UInt<8>
|
||||
input W0E : UInt<1>
|
||||
input W0M : UInt<1>
|
||||
input clock : Clock
|
||||
input R0A : UInt<11>
|
||||
output R0O : UInt<8>
|
||||
|
||||
mem ram :
|
||||
data-type => UInt<8>[1]
|
||||
depth => 2048
|
||||
read-latency => 0
|
||||
write-latency => 1
|
||||
reader => R_0
|
||||
writer => W_0
|
||||
read-under-write => undefined
|
||||
reg R_0_addr_reg : UInt<11>, clock with :
|
||||
reset => (UInt<1>("h0"), R_0_addr_reg)
|
||||
ram.R_0.clk <= clock
|
||||
ram.R_0.addr <= R_0_addr_reg
|
||||
ram.R_0.en <= UInt<1>("h1")
|
||||
R0O <= ram.R_0.data[0]
|
||||
R_0_addr_reg <= mux(UInt<1>("h1"), R0A, R_0_addr_reg)
|
||||
ram.W_0.clk <= clock
|
||||
ram.W_0.addr <= W0A
|
||||
ram.W_0.en <= W0E
|
||||
ram.W_0.data[0] <= bits(W0I, 7, 0)
|
||||
ram.W_0.mask[0] <= bits(W0M, 0, 0)
|
||||
"""
|
||||
compile(mem, None, v, true)
|
||||
execute(Some(mem), None, true, output)
|
||||
}
|
||||
|
||||
class Synflops2048x10_rw extends MacroCompilerSpec {
|
||||
val mem = new File(macroDir, "lib-2048x10-rw.json")
|
||||
val v = new File(testDir, "syn_flops_2048x10_rw.v")
|
||||
val output =
|
||||
"""
|
||||
circuit vendor_sram :
|
||||
module vendor_sram :
|
||||
input clock : Clock
|
||||
input RW0A : UInt<11>
|
||||
input RW0I : UInt<10>
|
||||
output RW0O : UInt<10>
|
||||
input RW0E : UInt<1>
|
||||
input RW0W : UInt<1>
|
||||
|
||||
mem ram :
|
||||
data-type => UInt<10>
|
||||
depth => 2048
|
||||
read-latency => 0
|
||||
write-latency => 1
|
||||
reader => R_0
|
||||
writer => W_0
|
||||
read-under-write => undefined
|
||||
reg R_0_addr_reg : UInt<11>, clock with :
|
||||
reset => (UInt<1>("h0"), R_0_addr_reg)
|
||||
ram.R_0.clk <= clock
|
||||
ram.R_0.addr <= R_0_addr_reg
|
||||
ram.R_0.en <= RW0E
|
||||
RW0O <= ram.R_0.data
|
||||
R_0_addr_reg <= mux(RW0E, RW0A, R_0_addr_reg)
|
||||
ram.W_0.clk <= clock
|
||||
ram.W_0.addr <= RW0A
|
||||
ram.W_0.en <= and(RW0E, RW0W)
|
||||
ram.W_0.data <= RW0I
|
||||
ram.W_0.mask <= UInt<1>("h1")
|
||||
"""
|
||||
compile(mem, None, v, true)
|
||||
execute(Some(mem), None, true, output)
|
||||
}
|
||||
|
||||
class Synflops2048x8_mrw_re extends MacroCompilerSpec {
|
||||
val mem = new File(macroDir, "lib-2048x8-mrw-re.json")
|
||||
val v = new File(testDir, "syn_flops_2048x8_mrw_re.v")
|
||||
val output =
|
||||
"""
|
||||
circuit vendor_sram :
|
||||
module vendor_sram :
|
||||
input clock : Clock
|
||||
input RW0A : UInt<11>
|
||||
input RW0I : UInt<8>
|
||||
output RW0O : UInt<8>
|
||||
input RW0E : UInt<1>
|
||||
input RW0R : UInt<1>
|
||||
input RW0W : UInt<1>
|
||||
input RW0M : UInt<1>
|
||||
|
||||
mem ram :
|
||||
data-type => UInt<8>[1]
|
||||
depth => 2048
|
||||
read-latency => 0
|
||||
write-latency => 1
|
||||
reader => R_0
|
||||
writer => W_0
|
||||
read-under-write => undefined
|
||||
reg R_0_addr_reg : UInt<11>, clock with :
|
||||
reset => (UInt<1>("h0"), R_0_addr_reg)
|
||||
ram.R_0.clk <= clock
|
||||
ram.R_0.addr <= R_0_addr_reg
|
||||
ram.R_0.en <= and(RW0E, not(RW0R))
|
||||
RW0O <= ram.R_0.data[0]
|
||||
R_0_addr_reg <= mux(and(RW0E, not(RW0R)), RW0A, R_0_addr_reg)
|
||||
ram.W_0.clk <= clock
|
||||
ram.W_0.addr <= RW0A
|
||||
ram.W_0.en <= and(RW0E, RW0W)
|
||||
ram.W_0.data[0] <= bits(RW0I, 7, 0)
|
||||
ram.W_0.mask[0] <= bits(RW0M, 0, 0)
|
||||
"""
|
||||
compile(mem, None, v, true)
|
||||
execute(Some(mem), None, true, output)
|
||||
}
|
||||
|
||||
class Synflops2048x16_n28 extends MacroCompilerSpec {
|
||||
val mem = new File(macroDir, "lib-2048x16-n28.json")
|
||||
val v = new File(testDir, "syn_flops_2048x16_n28.v")
|
||||
val output =
|
||||
"""
|
||||
circuit vendor_sram_4 :
|
||||
module vendor_sram_16 :
|
||||
input clock : Clock
|
||||
input RW0A : UInt<11>
|
||||
input RW0I : UInt<16>
|
||||
output RW0O : UInt<16>
|
||||
input RW0E : UInt<1>
|
||||
input RW0W : UInt<1>
|
||||
input RW0M : UInt<16>
|
||||
|
||||
mem ram :
|
||||
data-type => UInt<1>[16]
|
||||
depth => 2048
|
||||
read-latency => 0
|
||||
write-latency => 1
|
||||
reader => R_0
|
||||
writer => W_0
|
||||
read-under-write => undefined
|
||||
reg R_0_addr_reg : UInt<11>, clock with :
|
||||
reset => (UInt<1>("h0"), R_0_addr_reg)
|
||||
ram.R_0.clk <= clock
|
||||
ram.R_0.addr <= R_0_addr_reg
|
||||
ram.R_0.en <= RW0E
|
||||
RW0O <= cat(ram.R_0.data[15], cat(ram.R_0.data[14], cat(ram.R_0.data[13], cat(ram.R_0.data[12], cat(ram.R_0.data[11], cat(ram.R_0.data[10], cat(ram.R_0.data[9], cat(ram.R_0.data[8], cat(ram.R_0.data[7], cat(ram.R_0.data[6], cat(ram.R_0.data[5], cat(ram.R_0.data[4], cat(ram.R_0.data[3], cat(ram.R_0.data[2], cat(ram.R_0.data[1], ram.R_0.data[0])))))))))))))))
|
||||
R_0_addr_reg <= mux(RW0E, RW0A, R_0_addr_reg)
|
||||
ram.W_0.clk <= clock
|
||||
ram.W_0.addr <= RW0A
|
||||
ram.W_0.en <= and(RW0E, RW0W)
|
||||
ram.W_0.data[0] <= bits(RW0I, 0, 0)
|
||||
ram.W_0.data[1] <= bits(RW0I, 1, 1)
|
||||
ram.W_0.data[2] <= bits(RW0I, 2, 2)
|
||||
ram.W_0.data[3] <= bits(RW0I, 3, 3)
|
||||
ram.W_0.data[4] <= bits(RW0I, 4, 4)
|
||||
ram.W_0.data[5] <= bits(RW0I, 5, 5)
|
||||
ram.W_0.data[6] <= bits(RW0I, 6, 6)
|
||||
ram.W_0.data[7] <= bits(RW0I, 7, 7)
|
||||
ram.W_0.data[8] <= bits(RW0I, 8, 8)
|
||||
ram.W_0.data[9] <= bits(RW0I, 9, 9)
|
||||
ram.W_0.data[10] <= bits(RW0I, 10, 10)
|
||||
ram.W_0.data[11] <= bits(RW0I, 11, 11)
|
||||
ram.W_0.data[12] <= bits(RW0I, 12, 12)
|
||||
ram.W_0.data[13] <= bits(RW0I, 13, 13)
|
||||
ram.W_0.data[14] <= bits(RW0I, 14, 14)
|
||||
ram.W_0.data[15] <= bits(RW0I, 15, 15)
|
||||
ram.W_0.mask[0] <= bits(RW0M, 0, 0)
|
||||
ram.W_0.mask[1] <= bits(RW0M, 1, 1)
|
||||
ram.W_0.mask[2] <= bits(RW0M, 2, 2)
|
||||
ram.W_0.mask[3] <= bits(RW0M, 3, 3)
|
||||
ram.W_0.mask[4] <= bits(RW0M, 4, 4)
|
||||
ram.W_0.mask[5] <= bits(RW0M, 5, 5)
|
||||
ram.W_0.mask[6] <= bits(RW0M, 6, 6)
|
||||
ram.W_0.mask[7] <= bits(RW0M, 7, 7)
|
||||
ram.W_0.mask[8] <= bits(RW0M, 8, 8)
|
||||
ram.W_0.mask[9] <= bits(RW0M, 9, 9)
|
||||
ram.W_0.mask[10] <= bits(RW0M, 10, 10)
|
||||
ram.W_0.mask[11] <= bits(RW0M, 11, 11)
|
||||
ram.W_0.mask[12] <= bits(RW0M, 12, 12)
|
||||
ram.W_0.mask[13] <= bits(RW0M, 13, 13)
|
||||
ram.W_0.mask[14] <= bits(RW0M, 14, 14)
|
||||
ram.W_0.mask[15] <= bits(RW0M, 15, 15)
|
||||
|
||||
module vendor_sram_4 :
|
||||
input clock : Clock
|
||||
input RW0A : UInt<11>
|
||||
input RW0I : UInt<4>
|
||||
output RW0O : UInt<4>
|
||||
input RW0E : UInt<1>
|
||||
input RW0W : UInt<1>
|
||||
input RW0M : UInt<4>
|
||||
|
||||
mem ram :
|
||||
data-type => UInt<1>[4]
|
||||
depth => 2048
|
||||
read-latency => 0
|
||||
write-latency => 1
|
||||
reader => R_0
|
||||
writer => W_0
|
||||
read-under-write => undefined
|
||||
reg R_0_addr_reg : UInt<11>, clock with :
|
||||
reset => (UInt<1>("h0"), R_0_addr_reg)
|
||||
ram.R_0.clk <= clock
|
||||
ram.R_0.addr <= R_0_addr_reg
|
||||
ram.R_0.en <= RW0E
|
||||
RW0O <= cat(ram.R_0.data[3], cat(ram.R_0.data[2], cat(ram.R_0.data[1], ram.R_0.data[0])))
|
||||
R_0_addr_reg <= mux(RW0E, RW0A, R_0_addr_reg)
|
||||
ram.W_0.clk <= clock
|
||||
ram.W_0.addr <= RW0A
|
||||
ram.W_0.en <= and(RW0E, RW0W)
|
||||
ram.W_0.data[0] <= bits(RW0I, 0, 0)
|
||||
ram.W_0.data[1] <= bits(RW0I, 1, 1)
|
||||
ram.W_0.data[2] <= bits(RW0I, 2, 2)
|
||||
ram.W_0.data[3] <= bits(RW0I, 3, 3)
|
||||
ram.W_0.mask[0] <= bits(RW0M, 0, 0)
|
||||
ram.W_0.mask[1] <= bits(RW0M, 1, 1)
|
||||
ram.W_0.mask[2] <= bits(RW0M, 2, 2)
|
||||
ram.W_0.mask[3] <= bits(RW0M, 3, 3)
|
||||
"""
|
||||
compile(mem, None, v, true)
|
||||
execute(Some(mem), None, true, output)
|
||||
}
|
||||
|
||||
class Synflops32x32_2rw extends MacroCompilerSpec {
|
||||
val mem = new File(macroDir, "lib-32x32-2rw.json")
|
||||
val v = new File(testDir, "syn_flops_32x32_2rw.v")
|
||||
val output =
|
||||
"""
|
||||
circuit SRAM2RW32x32 :
|
||||
module SRAM2RW32x32 :
|
||||
input CE1 : Clock
|
||||
input A1 : UInt<5>
|
||||
input I1 : UInt<32>
|
||||
output O1 : UInt<32>
|
||||
input CSB1 : UInt<1>
|
||||
input OEB1 : UInt<1>
|
||||
input WEB1 : UInt<1>
|
||||
input CE2 : Clock
|
||||
input A2 : UInt<5>
|
||||
input I2 : UInt<32>
|
||||
output O2 : UInt<32>
|
||||
input CSB2 : UInt<1>
|
||||
input OEB2 : UInt<1>
|
||||
input WEB2 : UInt<1>
|
||||
|
||||
mem ram :
|
||||
data-type => UInt<32>
|
||||
depth => 32
|
||||
read-latency => 0
|
||||
write-latency => 1
|
||||
reader => R_0
|
||||
reader => R_1
|
||||
writer => W_0
|
||||
writer => W_1
|
||||
read-under-write => undefined
|
||||
reg R_0_addr_reg : UInt<5>, CE1 with :
|
||||
reset => (UInt<1>("h0"), R_0_addr_reg)
|
||||
ram.R_0.clk <= CE1
|
||||
ram.R_0.addr <= R_0_addr_reg
|
||||
ram.R_0.en <= and(not(CSB1), not(OEB1))
|
||||
O1 <= ram.R_0.data
|
||||
R_0_addr_reg <= mux(and(not(CSB1), not(OEB1)), A1, R_0_addr_reg)
|
||||
reg R_1_addr_reg : UInt<5>, CE2 with :
|
||||
reset => (UInt<1>("h0"), R_1_addr_reg)
|
||||
ram.R_1.clk <= CE2
|
||||
ram.R_1.addr <= R_1_addr_reg
|
||||
ram.R_1.en <= and(not(CSB2), not(OEB2))
|
||||
O2 <= ram.R_1.data
|
||||
R_1_addr_reg <= mux(and(not(CSB2), not(OEB2)), A2, R_1_addr_reg)
|
||||
ram.W_0.clk <= CE1
|
||||
ram.W_0.addr <= A1
|
||||
ram.W_0.en <= and(not(CSB1), not(WEB1))
|
||||
ram.W_0.data <= I1
|
||||
ram.W_0.mask <= UInt<1>("h1")
|
||||
ram.W_1.clk <= CE2
|
||||
ram.W_1.addr <= A2
|
||||
ram.W_1.en <= and(not(CSB2), not(WEB2))
|
||||
ram.W_1.data <= I2
|
||||
ram.W_1.mask <= UInt<1>("h1")
|
||||
"""
|
||||
compile(mem, None, v, true)
|
||||
execute(Some(mem), None, true, output)
|
||||
}
|
||||
Reference in New Issue
Block a user