From 607e810b1ddfeab99b584fea166c9733ea867e6f Mon Sep 17 00:00:00 2001 From: Edward Wang Date: Fri, 21 Jul 2017 15:16:26 -0700 Subject: [PATCH] Autogenerate almost all the depth tests --- .../transforms/macros/MacroCompilerSpec.scala | 5 +- .../transforms/macros/SimpleSplitDepth.scala | 384 ++++++++++-------- 2 files changed, 223 insertions(+), 166 deletions(-) diff --git a/tapeout/src/test/scala/transforms/macros/MacroCompilerSpec.scala b/tapeout/src/test/scala/transforms/macros/MacroCompilerSpec.scala index a9939715..c42d4b77 100644 --- a/tapeout/src/test/scala/transforms/macros/MacroCompilerSpec.scala +++ b/tapeout/src/test/scala/transforms/macros/MacroCompilerSpec.scala @@ -86,7 +86,7 @@ trait HasSRAMGenerator { import mdf.macrolib._ // Generate a "simple" SRAM (active high/positive edge, 1 read-write port). - def generateSRAM(name: String, prefix: String, width: Int, depth: Int, maskGran: Option[Int] = None): SRAMMacro = { + def generateSRAM(name: String, prefix: String, width: Int, depth: Int, maskGran: Option[Int] = None, extraPorts: Seq[MacroExtraPort] = List()): SRAMMacro = { val realPrefix = prefix + "_" SRAMMacro( macroType=SRAM, @@ -110,7 +110,8 @@ trait HasSRAMGenerator { maskGran=maskGran, width=width, depth=depth // These numbers don't matter here. - )) + )), + extraPorts=extraPorts ) } } diff --git a/tapeout/src/test/scala/transforms/macros/SimpleSplitDepth.scala b/tapeout/src/test/scala/transforms/macros/SimpleSplitDepth.scala index fc6a0b2e..d25aeb27 100644 --- a/tapeout/src/test/scala/transforms/macros/SimpleSplitDepth.scala +++ b/tapeout/src/test/scala/transforms/macros/SimpleSplitDepth.scala @@ -15,15 +15,28 @@ trait HasSimpleDepthTestGenerator { def width: Int def mem_depth: Int def lib_depth: Int + def mem_maskGran: Option[Int] = None + def lib_maskGran: Option[Int] = None + def extraPorts: Seq[mdf.macrolib.MacroExtraPort] = List() require (mem_depth >= lib_depth) override val memPrefix = testDir override val libPrefix = testDir - val mem = s"mem-${mem_depth}x${width}-rw.json" - val lib = s"lib-${lib_depth}x${width}-rw.json" - val v = s"split_depth_${mem_depth}x${width}_rw.v" + // Convenience variables to check if a mask exists. + val memHasMask = mem_maskGran != None + val libHasMask = lib_maskGran != None + // We need to figure out how many mask bits there are in the mem. + val memMaskBits = if (memHasMask) width / mem_maskGran.get else 0 + val libMaskBits = if (libHasMask) width / lib_maskGran.get else 0 + // Generate "mrw" vs "rw" tags. + val memTag = (if (memHasMask) "m" else "") + "rw" + val libTag = (if (libHasMask) "m" else "") + "rw" + + val mem = s"mem-${mem_depth}x${width}-${memTag}.json" + val lib = s"lib-${lib_depth}x${width}-${libTag}.json" + val v = s"split_depth_${mem_depth}x${width}_${memTag}.v" val mem_name = "target_memory" val mem_addr_width = ceilLog2(mem_depth) @@ -31,15 +44,16 @@ trait HasSimpleDepthTestGenerator { val lib_name = "awesome_lib_mem" val lib_addr_width = ceilLog2(lib_depth) - writeToLib(lib, Seq(generateSRAM(lib_name, "lib", width, lib_depth))) - writeToMem(mem, Seq(generateSRAM(mem_name, "outer", width, mem_depth))) + writeToLib(lib, Seq(generateSRAM(lib_name, "lib", width, lib_depth, lib_maskGran, extraPorts))) + writeToMem(mem, Seq(generateSRAM(mem_name, "outer", width, mem_depth, mem_maskGran))) // Number of lib instances needed to hold the mem. // Round up (e.g. 1.5 instances = effectively 2 instances) val expectedInstances = math.ceil(mem_depth.toFloat / lib_depth).toInt val selectBits = mem_addr_width - lib_addr_width - var output = -s""" + + val headerMask = if (memHasMask) s"input outer_mask : UInt<${memMaskBits}>" else "" + val header = s""" circuit $mem_name : module $mem_name : input outer_clk : Clock @@ -47,8 +61,24 @@ circuit $mem_name : input outer_din : UInt<$width> output outer_dout : UInt<$width> input outer_write_en : UInt<1> + ${headerMask} """ + val footerMask = if (libHasMask) s"input lib_mask : UInt<${libMaskBits}>" else "" + val footer = s""" + extmodule $lib_name : + input lib_clk : Clock + input lib_addr : UInt<$lib_addr_width> + input lib_din : UInt<$width> + output lib_dout : UInt<$width> + input lib_write_en : UInt<1> + ${footerMask} + + defname = $lib_name +""" + + var output = header + if (selectBits > 0) { output += s""" @@ -57,6 +87,26 @@ s""" } for (i <- 0 to expectedInstances - 1) { + // We only support simple masks for now (either libMask == memMask or libMask == 1) + val maskStatement = if (libHasMask) { + if (lib_maskGran.get == mem_maskGran.get) { + s"""mem_${i}_0.lib_mask <= bits(outer_mask, 0, 0)""" + } else if (lib_maskGran.get == 1) { + // Construct a mask string. + // Each bit gets the # of bits specified in maskGran. + // Specify in descending order (MSB first) + + // This builds an array like m[1], m[1], m[0], m[0] + val maskBitsArr: Seq[String] = ((memMaskBits - 1 to 0 by -1) flatMap (maskBit => { + ((0 to mem_maskGran.get - 1) map (_ => s"bits(outer_mask, ${maskBit}, ${maskBit})")) + })) + // Now build it into a recursive string like + // cat(m[1], cat(m[1], cat(m[0], m[0]))) + val maskBitsStr: String = maskBitsArr.reverse.tail.foldLeft(maskBitsArr.reverse.head)((prev: String, next: String) => s"cat(${next}, ${prev})") + s"""mem_${i}_0.lib_mask <= ${maskBitsStr}""" + } else "" // TODO: implement when non-bitmasked memories are supported + } else "" // No mask + val enableIdentifier = if (selectBits > 0) s"""eq(outer_addr_sel, UInt<${selectBits}>("h${i.toHexString}"))""" else "UInt<1>(\"h1\")" output += s""" @@ -65,6 +115,7 @@ s""" mem_${i}_0.lib_addr <= outer_addr node outer_dout_${i}_0 = bits(mem_${i}_0.lib_dout, ${width - 1}, 0) mem_${i}_0.lib_din <= bits(outer_din, ${width - 1}, 0) + ${maskStatement} mem_${i}_0.lib_write_en <= and(and(outer_write_en, UInt<1>("h1")), ${enableIdentifier}) node outer_dout_${i} = outer_dout_${i}_0 """ @@ -85,17 +136,7 @@ s""" output += """mux(UInt<1>("h1"), outer_dout_0, UInt<1>("h0"))""" } - output += -s""" - extmodule $lib_name : - input lib_clk : Clock - input lib_addr : UInt<$lib_addr_width> - input lib_din : UInt<$width> - output lib_dout : UInt<$width> - input lib_write_en : UInt<1> - - defname = $lib_name -""" + output += footer } // Try different widths @@ -174,109 +215,123 @@ class SplitDepth2049x8_rw extends MacroCompilerSpec with HasSRAMGenerator with H // Masked RAMs -class SplitDepth2048x8_mrw extends MacroCompilerSpec { - val mem = "mem-2048x8-mrw.json" - val lib = "lib-1024x8-mrw.json" - val v = "split_depth_2048x8_mrw.v" - val output = -""" -circuit name_of_sram_module : - module name_of_sram_module : - input clock : Clock - input RW0A : UInt<11> - input RW0I : UInt<8> - output RW0O : UInt<8> - input RW0E : UInt<1> - input RW0W : UInt<1> - input RW0M : UInt<1> +// Test for mem mask == lib mask (i.e. mask is a write enable bit) +class SplitDepth2048x32_mrw_lib32 extends MacroCompilerSpec with HasSRAMGenerator with HasSimpleDepthTestGenerator { + override lazy val width = 32 + override lazy val mem_depth = 2048 + override lazy val lib_depth = 1024 + override lazy val mem_maskGran = Some(32) + override lazy val lib_maskGran = Some(32) - node RW0A_sel = bits(RW0A, 10, 10) - inst mem_0_0 of vendor_sram - mem_0_0.clock <= clock - mem_0_0.RW0A <= RW0A - node RW0O_0_0 = bits(mem_0_0.RW0O, 7, 0) - mem_0_0.RW0I <= bits(RW0I, 7, 0) - mem_0_0.RW0M <= bits(RW0M, 0, 0) - mem_0_0.RW0W <= and(RW0W, eq(RW0A_sel, UInt<1>("h0"))) - mem_0_0.RW0E <= and(RW0E, eq(RW0A_sel, UInt<1>("h0"))) - node RW0O_0 = RW0O_0_0 - inst mem_1_0 of vendor_sram - mem_1_0.clock <= clock - mem_1_0.RW0A <= RW0A - node RW0O_1_0 = bits(mem_1_0.RW0O, 7, 0) - mem_1_0.RW0I <= bits(RW0I, 7, 0) - mem_1_0.RW0M <= bits(RW0M, 0, 0) - mem_1_0.RW0W <= and(RW0W, eq(RW0A_sel, UInt<1>("h1"))) - mem_1_0.RW0E <= and(RW0E, eq(RW0A_sel, UInt<1>("h1"))) - node RW0O_1 = RW0O_1_0 - RW0O <= mux(eq(RW0A_sel, UInt<1>("h0")), RW0O_0, mux(eq(RW0A_sel, UInt<1>("h1")), RW0O_1, UInt<1>("h0"))) - - extmodule vendor_sram : - input clock : Clock - input RW0A : UInt<10> - input RW0I : UInt<8> - output RW0O : UInt<8> - input RW0E : UInt<1> - input RW0W : UInt<1> - input RW0M : UInt<1> - - defname = vendor_sram -""" compile(mem, lib, v, false) execute(mem, lib, false, output) } -//~ class SplitDepth2048x8_n28 extends MacroCompilerSpec { - //~ val mem = new File(macroDir, "mem-2048x8-mrw.json") - //~ val lib = new File(macroDir, "lib-1024x8-n28.json") - //~ val v = new File(testDir, "split_depth_2048x8_n28.v") - //~ val output = -//~ """ -//~ circuit name_of_sram_module : - //~ module name_of_sram_module : - //~ input clock : Clock - //~ input RW0A : UInt<11> - //~ input RW0I : UInt<8> - //~ output RW0O : UInt<8> - //~ input RW0E : UInt<1> - //~ input RW0W : UInt<1> - //~ input RW0M : UInt<1> +class SplitDepth2048x8_mrw_lib8 extends MacroCompilerSpec with HasSRAMGenerator with HasSimpleDepthTestGenerator { + override lazy val width = 8 + override lazy val mem_depth = 2048 + override lazy val lib_depth = 1024 + override lazy val mem_maskGran = Some(8) + override lazy val lib_maskGran = Some(8) - //~ node RW0A_sel = bits(RW0A, 10, 10) - //~ inst mem_0_0 of vendor_sram - //~ mem_0_0.clock <= clock - //~ mem_0_0.RW0A <= RW0A - //~ node RW0O_0_0 = bits(mem_0_0.RW0O, 7, 0) - //~ mem_0_0.RW0I <= bits(RW0I, 7, 0) - //~ mem_0_0.RW0M <= cat(bits(RW0M, 0, 0), cat(bits(RW0M, 0, 0), cat(bits(RW0M, 0, 0), cat(bits(RW0M, 0, 0), cat(bits(RW0M, 0, 0), cat(bits(RW0M, 0, 0), cat(bits(RW0M, 0, 0), bits(RW0M, 0, 0)))))))) - //~ mem_0_0.RW0W <= and(RW0W, eq(RW0A_sel, UInt<1>("h0"))) - //~ mem_0_0.RW0E <= and(RW0E, eq(RW0A_sel, UInt<1>("h0"))) - //~ node RW0O_0 = RW0O_0_0 - //~ inst mem_1_0 of vendor_sram - //~ mem_1_0.clock <= clock - //~ mem_1_0.RW0A <= RW0A - //~ node RW0O_1_0 = bits(mem_1_0.RW0O, 7, 0) - //~ mem_1_0.RW0I <= bits(RW0I, 7, 0) - //~ mem_1_0.RW0M <= cat(bits(RW0M, 0, 0), cat(bits(RW0M, 0, 0), cat(bits(RW0M, 0, 0), cat(bits(RW0M, 0, 0), cat(bits(RW0M, 0, 0), cat(bits(RW0M, 0, 0), cat(bits(RW0M, 0, 0), bits(RW0M, 0, 0)))))))) - //~ mem_1_0.RW0W <= and(RW0W, eq(RW0A_sel, UInt<1>("h1"))) - //~ mem_1_0.RW0E <= and(RW0E, eq(RW0A_sel, UInt<1>("h1"))) - //~ node RW0O_1 = RW0O_1_0 - //~ RW0O <= mux(eq(RW0A_sel, UInt<1>("h0")), RW0O_0, mux(eq(RW0A_sel, UInt<1>("h1")), RW0O_1, UInt<1>("h0"))) + compile(mem, lib, v, false) + execute(mem, lib, false, output) +} - //~ extmodule vendor_sram : - //~ input clock : Clock - //~ input RW0A : UInt<10> - //~ input RW0I : UInt<8> - //~ output RW0O : UInt<8> - //~ input RW0E : UInt<1> - //~ input RW0W : UInt<1> - //~ input RW0M : UInt<8> +// Non-bit level mask +class SplitDepth2048x64_mrw_mem32_lib8 extends MacroCompilerSpec with HasSRAMGenerator with HasSimpleDepthTestGenerator { + override lazy val width = 64 + override lazy val mem_depth = 2048 + override lazy val lib_depth = 1024 + override lazy val mem_maskGran = Some(32) + override lazy val lib_maskGran = Some(8) - //~ defname = vendor_sram -//~ """ - //~ compile(mem, lib, v, false) - //~ execute(mem, lib, false, output) -//~ } + it should "be enabled when non-bitmasked memories are supported" is (pending) + //compile(mem, lib, v, false) + //execute(mem, lib, false, output) +} + +// Bit level mask +class SplitDepth2048x32_mrw_mem16_lib1 extends MacroCompilerSpec with HasSRAMGenerator with HasSimpleDepthTestGenerator { + override lazy val width = 32 + override lazy val mem_depth = 2048 + override lazy val lib_depth = 1024 + override lazy val mem_maskGran = Some(16) + override lazy val lib_maskGran = Some(1) + + compile(mem, lib, v, false) + execute(mem, lib, false, output) +} + +class SplitDepth2048x32_mrw_mem8_lib1 extends MacroCompilerSpec with HasSRAMGenerator with HasSimpleDepthTestGenerator { + override lazy val width = 32 + override lazy val mem_depth = 2048 + override lazy val lib_depth = 1024 + override lazy val mem_maskGran = Some(8) + override lazy val lib_maskGran = Some(1) + + compile(mem, lib, v, false) + execute(mem, lib, false, output) +} + +class SplitDepth2048x32_mrw_mem4_lib1 extends MacroCompilerSpec with HasSRAMGenerator with HasSimpleDepthTestGenerator { + override lazy val width = 32 + override lazy val mem_depth = 2048 + override lazy val lib_depth = 1024 + override lazy val mem_maskGran = Some(4) + override lazy val lib_maskGran = Some(1) + + compile(mem, lib, v, false) + execute(mem, lib, false, output) +} + +class SplitDepth2048x32_mrw_mem2_lib1 extends MacroCompilerSpec with HasSRAMGenerator with HasSimpleDepthTestGenerator { + override lazy val width = 32 + override lazy val mem_depth = 2048 + override lazy val lib_depth = 1024 + override lazy val mem_maskGran = Some(2) + override lazy val lib_maskGran = Some(1) + + compile(mem, lib, v, false) + execute(mem, lib, false, output) +} + +// Non-powers of 2 mask sizes +class SplitDepth2048x32_mrw_mem3_lib1 extends MacroCompilerSpec with HasSRAMGenerator with HasSimpleDepthTestGenerator { + override lazy val width = 32 + override lazy val mem_depth = 2048 + override lazy val lib_depth = 1024 + override lazy val mem_maskGran = Some(3) + override lazy val lib_maskGran = Some(1) + + it should "be enabled when non-power of two masks are supported" is (pending) + //compile(mem, lib, v, false) + //execute(mem, lib, false, output) +} + +class SplitDepth2048x32_mrw_mem7_lib1 extends MacroCompilerSpec with HasSRAMGenerator with HasSimpleDepthTestGenerator { + override lazy val width = 32 + override lazy val mem_depth = 2048 + override lazy val lib_depth = 1024 + override lazy val mem_maskGran = Some(7) + override lazy val lib_maskGran = Some(1) + + it should "be enabled when non-power of two masks are supported" is (pending) + //compile(mem, lib, v, false) + //execute(mem, lib, false, output) +} + +class SplitDepth2048x32_mrw_mem9_lib1 extends MacroCompilerSpec with HasSRAMGenerator with HasSimpleDepthTestGenerator { + override lazy val width = 32 + override lazy val mem_depth = 2048 + override lazy val lib_depth = 1024 + override lazy val mem_maskGran = Some(9) + override lazy val lib_maskGran = Some(1) + + it should "be enabled when non-power of two masks are supported" is (pending) + //compile(mem, lib, v, false) + //execute(mem, lib, false, output) +} //~ class SplitDepth2048x8_r_mw extends MacroCompilerSpec { //~ val mem = new File(macroDir, "mem-2048x8-r-mw.json") @@ -338,58 +393,59 @@ circuit name_of_sram_module : //~ execute(mem, lib, false, output) //~ } +// Try an extra port +class SplitDepth2048x8_extraPort extends MacroCompilerSpec with HasSRAMGenerator with HasSimpleDepthTestGenerator { + import mdf.macrolib._ -//~ class SplitDepth2048x8_mrw_Sleep extends MacroCompilerSpec { - //~ val mem = new File(macroDir, "mem-2048x8-mrw.json") - //~ val lib = new File(macroDir, "lib-1024x8-sleep.json") - //~ val v = new File(testDir, "split_depth_2048x8_sleep.v") - //~ val output = -//~ """ -//~ circuit name_of_sram_module : - //~ module name_of_sram_module : - //~ input clock : Clock - //~ input RW0A : UInt<11> - //~ input RW0I : UInt<8> - //~ output RW0O : UInt<8> - //~ input RW0E : UInt<1> - //~ input RW0W : UInt<1> - //~ input RW0M : UInt<1> + override lazy val width = 8 + override lazy val mem_depth = 2048 + override lazy val lib_depth = 1024 + override lazy val extraPorts = List( + MacroExtraPort(name="extra_port", width=8, portType=Constant, value=0xff) + ) - //~ node RW0A_sel = bits(RW0A, 10, 10) - //~ inst mem_0_0 of vendor_sram - //~ mem_0_0.sleep <= UInt<1>("h0") - //~ mem_0_0.clock <= clock - //~ mem_0_0.RW0A <= RW0A - //~ node RW0O_0_0 = bits(mem_0_0.RW0O, 7, 0) - //~ mem_0_0.RW0I <= bits(RW0I, 7, 0) - //~ mem_0_0.RW0M <= bits(RW0M, 0, 0) - //~ mem_0_0.RW0W <= and(RW0W, eq(RW0A_sel, UInt<1>("h0"))) - //~ mem_0_0.RW0E <= and(RW0E, eq(RW0A_sel, UInt<1>("h0"))) - //~ node RW0O_0 = RW0O_0_0 - //~ inst mem_1_0 of vendor_sram - //~ mem_1_0.sleep <= UInt<1>("h0") - //~ mem_1_0.clock <= clock - //~ mem_1_0.RW0A <= RW0A - //~ node RW0O_1_0 = bits(mem_1_0.RW0O, 7, 0) - //~ mem_1_0.RW0I <= bits(RW0I, 7, 0) - //~ mem_1_0.RW0M <= bits(RW0M, 0, 0) - //~ mem_1_0.RW0W <= and(RW0W, eq(RW0A_sel, UInt<1>("h1"))) - //~ mem_1_0.RW0E <= and(RW0E, eq(RW0A_sel, UInt<1>("h1"))) - //~ node RW0O_1 = RW0O_1_0 - //~ RW0O <= mux(eq(RW0A_sel, UInt<1>("h0")), RW0O_0, mux(eq(RW0A_sel, UInt<1>("h1")), RW0O_1, UInt<1>("h0"))) + val outputCustom = +""" +circuit target_memory : + module target_memory : + input outer_clk : Clock + input outer_addr : UInt<11> + input outer_din : UInt<8> + output outer_dout : UInt<8> + input outer_write_en : UInt<1> - //~ extmodule vendor_sram : - //~ input clock : Clock - //~ input RW0A : UInt<10> - //~ input RW0I : UInt<8> - //~ output RW0O : UInt<8> - //~ input RW0E : UInt<1> - //~ input RW0W : UInt<1> - //~ input RW0M : UInt<1> - //~ input sleep : UInt<1> + node outer_addr_sel = bits(outer_addr, 10, 10) - //~ defname = vendor_sram -//~ """ - //~ compile(mem, lib, v, false) - //~ execute(mem, lib, false, output) -//~ } + inst mem_0_0 of awesome_lib_mem + mem_0_0.extra_port <= UInt<8>("hff") + mem_0_0.lib_clk <= outer_clk + mem_0_0.lib_addr <= outer_addr + node outer_dout_0_0 = bits(mem_0_0.lib_dout, 7, 0) + mem_0_0.lib_din <= bits(outer_din, 7, 0) + + mem_0_0.lib_write_en <= and(and(outer_write_en, UInt<1>("h1")), eq(outer_addr_sel, UInt<1>("h0"))) + node outer_dout_0 = outer_dout_0_0 + + inst mem_1_0 of awesome_lib_mem + mem_1_0.extra_port <= UInt<8>("hff") + mem_1_0.lib_clk <= outer_clk + mem_1_0.lib_addr <= outer_addr + node outer_dout_1_0 = bits(mem_1_0.lib_dout, 7, 0) + mem_1_0.lib_din <= bits(outer_din, 7, 0) + + mem_1_0.lib_write_en <= and(and(outer_write_en, UInt<1>("h1")), eq(outer_addr_sel, UInt<1>("h1"))) + node outer_dout_1 = outer_dout_1_0 + outer_dout <= mux(eq(outer_addr_sel, UInt<1>("h0")), outer_dout_0, mux(eq(outer_addr_sel, UInt<1>("h1")), outer_dout_1, UInt<1>("h0"))) + extmodule awesome_lib_mem : + input lib_clk : Clock + input lib_addr : UInt<10> + input lib_din : UInt<8> + output lib_dout : UInt<8> + input lib_write_en : UInt<1> + input extra_port : UInt<8> + + defname = awesome_lib_mem + """ + compile(mem, lib, v, false) + execute(mem, lib, false, outputCustom) +}