From de66405fe823bb4190705b3060ad87696922a383 Mon Sep 17 00:00:00 2001 From: Edward Wang Date: Mon, 31 Jul 2017 15:36:03 -0700 Subject: [PATCH] Write flop tests using generator --- macros/src/test/scala/SynFlops.scala | 637 ++++++++++++++------------- 1 file changed, 319 insertions(+), 318 deletions(-) diff --git a/macros/src/test/scala/SynFlops.scala b/macros/src/test/scala/SynFlops.scala index 2b3ff531..0394dc40 100644 --- a/macros/src/test/scala/SynFlops.scala +++ b/macros/src/test/scala/SynFlops.scala @@ -1,333 +1,334 @@ -//~ package barstools.tapeout.transforms.macros +package barstools.macros -//~ import java.io.File +// Use this trait for tests that invoke the memory compiler without lib. +trait HasNoLibTestGenerator extends HasSimpleTestGenerator { + this: MacroCompilerSpec with HasSRAMGenerator => -//~ 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> + // If there isn't a lib, then the "lib" will become a FIRRTL "mem", which + // in turn becomes synthesized flops. + // Therefore, make "lib" width/depth equal to the mem. + override lazy val libDepth = memDepth + override lazy val libWidth = memWidth + // Do the same for port names. + override lazy val libPortPrefix = memPortPrefix - //~ 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) -//~ } + // If there is no lib, don't generate a body. + override def generateBody = "" +} -//~ 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> +// Test flop synthesis of the memory compiler. - //~ 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) -//~ } +trait HasSynFlopsTestGenerator extends HasSimpleTestGenerator { + this: MacroCompilerSpec with HasSRAMGenerator => + def generateFlops: String = { +s""" + mem ram : + data-type => UInt<${libWidth}> + depth => ${libDepth} + read-latency => 1 + write-latency => 1 + readwriter => RW_0 + read-under-write => undefined + ram.RW_0.clk <= ${libPortPrefix}_clk + ram.RW_0.addr <= ${libPortPrefix}_addr + ram.RW_0.en <= UInt<1>("h1") + ram.RW_0.wmode <= ${libPortPrefix}_write_en + ${libPortPrefix}_dout <= ram.RW_0.rdata + ram.RW_0.wdata <= ${libPortPrefix}_din + ram.RW_0.wmask <= UInt<1>("h1") +""" + } -//~ 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> + // If there is no lib, put the flops definition into the body. + abstract override def generateBody = { + if (this.isInstanceOf[HasNoLibTestGenerator]) generateFlops else super.generateBody + } - //~ 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) -//~ } + // If there is no lib, don't generate a footer, since the flops definition + // will be in the body. + override def generateFooter = { + if (this.isInstanceOf[HasNoLibTestGenerator]) "" else +s""" + module ${lib_name} : +${generateFooterPorts} -//~ 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> +${generateFlops} +""" + } - //~ 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> +class Synflops2048x8_noLib extends MacroCompilerSpec with HasSRAMGenerator with HasNoLibTestGenerator with HasSynFlopsTestGenerator { + override lazy val memDepth = 2048 + override lazy val memWidth = 8 - //~ 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) + compileExecuteAndTest(mem, None, v, output, true) +} - //~ 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> +class Synflops2048x16_noLib extends MacroCompilerSpec with HasSRAMGenerator with HasNoLibTestGenerator with HasSynFlopsTestGenerator { + override lazy val memDepth = 2048 + override lazy val memWidth = 16 - //~ 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) -//~ } + compileExecuteAndTest(mem, None, v, output, true) +} -//~ 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> +class Synflops8192x16_noLib extends MacroCompilerSpec with HasSRAMGenerator with HasNoLibTestGenerator with HasSynFlopsTestGenerator { + override lazy val memDepth = 8192 + override lazy val memWidth = 16 - //~ 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) -//~ } + compileExecuteAndTest(mem, None, v, output, true) +} + +class Synflops2048x16_depth_Lib extends MacroCompilerSpec with HasSRAMGenerator with HasSimpleDepthTestGenerator with HasSynFlopsTestGenerator { + override lazy val memDepth = 2048 + override lazy val libDepth = 1024 + override lazy val width = 16 + + compileExecuteAndTest(mem, lib, v, output, true) +} + +class Synflops2048x64_width_Lib extends MacroCompilerSpec with HasSRAMGenerator with HasSimpleWidthTestGenerator with HasSynFlopsTestGenerator { + override lazy val memWidth = 64 + override lazy val libWidth = 8 + override lazy val depth = 1024 + + compileExecuteAndTest(mem, lib, v, output, true) +} + +class Synflops_SplitPorts_Read_Write extends MacroCompilerSpec with HasSRAMGenerator with HasSimpleDepthTestGenerator with HasSynFlopsTestGenerator { + import mdf.macrolib._ + + override lazy val memDepth = 2048 + override lazy val libDepth = 1024 + override lazy val width = 8 + + override def generateLibSRAM = SRAMMacro( + macroType=SRAM, + name=lib_name, + width=width, + depth=libDepth, + family="1r1w", + ports=Seq( + generateReadPort("innerA", width, libDepth), + generateWritePort("innerB", width, libDepth) + ) + ) + + override def generateMemSRAM = SRAMMacro( + macroType=SRAM, + name=mem_name, + width=width, + depth=memDepth, + family="1r1w", + ports=Seq( + generateReadPort("outerB", width, memDepth), + generateWritePort("outerA", width, memDepth) + ) + ) + + override def generateHeader = +""" +circuit target_memory : + module target_memory : + input outerB_clk : Clock + input outerB_addr : UInt<11> + output outerB_dout : UInt<8> + input outerA_clk : Clock + input outerA_addr : UInt<11> + input outerA_din : UInt<8> + input outerA_write_en : UInt<1> +""" + + override def generateBody = +""" + node outerB_addr_sel = bits(outerB_addr, 10, 10) + reg outerB_addr_sel_reg : UInt<1>, outerB_clk with : + reset => (UInt<1>("h0"), outerB_addr_sel_reg) + outerB_addr_sel_reg <= mux(UInt<1>("h1"), outerB_addr_sel, outerB_addr_sel_reg) + node outerA_addr_sel = bits(outerA_addr, 10, 10) + inst mem_0_0 of awesome_lib_mem + mem_0_0.innerB_clk <= outerA_clk + mem_0_0.innerB_addr <= outerA_addr + mem_0_0.innerB_din <= bits(outerA_din, 7, 0) + mem_0_0.innerB_write_en <= and(and(outerA_write_en, UInt<1>("h1")), eq(outerA_addr_sel, UInt<1>("h0"))) + mem_0_0.innerA_clk <= outerB_clk + mem_0_0.innerA_addr <= outerB_addr + node outerB_dout_0_0 = bits(mem_0_0.innerA_dout, 7, 0) + node outerB_dout_0 = outerB_dout_0_0 + inst mem_1_0 of awesome_lib_mem + mem_1_0.innerB_clk <= outerA_clk + mem_1_0.innerB_addr <= outerA_addr + mem_1_0.innerB_din <= bits(outerA_din, 7, 0) + mem_1_0.innerB_write_en <= and(and(outerA_write_en, UInt<1>("h1")), eq(outerA_addr_sel, UInt<1>("h1"))) + mem_1_0.innerA_clk <= outerB_clk + mem_1_0.innerA_addr <= outerB_addr + node outerB_dout_1_0 = bits(mem_1_0.innerA_dout, 7, 0) + node outerB_dout_1 = outerB_dout_1_0 + outerB_dout <= mux(eq(outerB_addr_sel_reg, UInt<1>("h0")), outerB_dout_0, mux(eq(outerB_addr_sel_reg, UInt<1>("h1")), outerB_dout_1, UInt<1>("h0"))) +""" + + override def generateFooterPorts = +""" + input innerA_clk : Clock + input innerA_addr : UInt<10> + output innerA_dout : UInt<8> + input innerB_clk : Clock + input innerB_addr : UInt<10> + input innerB_din : UInt<8> + input innerB_write_en : UInt<1> +""" + + override def generateFlops = +""" + mem ram : + data-type => UInt<8> + depth => 1024 + read-latency => 1 + write-latency => 1 + reader => R_0 + writer => W_0 + read-under-write => undefined + ram.R_0.clk <= innerA_clk + ram.R_0.addr <= innerA_addr + ram.R_0.en <= UInt<1>("h1") + innerA_dout <= ram.R_0.data + ram.W_0.clk <= innerB_clk + ram.W_0.addr <= innerB_addr + ram.W_0.en <= innerB_write_en + ram.W_0.data <= innerB_din + ram.W_0.mask <= UInt<1>("h1") +""" + + "Non-masked split lib; split mem" should "syn flops fine" in { + compileExecuteAndTest(mem, lib, v, output, true) + } +} + +class Synflops_SplitPorts_MaskedMem_Read_MaskedWrite extends MacroCompilerSpec with HasSRAMGenerator with HasSimpleDepthTestGenerator with HasSynFlopsTestGenerator { + import mdf.macrolib._ + + override lazy val memDepth = 2048 + override lazy val libDepth = 1024 + override lazy val width = 8 + override lazy val memMaskGran = Some(8) + override lazy val libMaskGran = Some(1) + + override def generateLibSRAM = SRAMMacro( + macroType=SRAM, + name=lib_name, + width=width, + depth=libDepth, + family="1r1w", + ports=Seq( + generateReadPort("innerA", width, libDepth), + generateWritePort("innerB", width, libDepth, libMaskGran) + ) + ) + + override def generateMemSRAM = SRAMMacro( + macroType=SRAM, + name=mem_name, + width=width, + depth=memDepth, + family="1r1w", + ports=Seq( + generateReadPort("outerB", width, memDepth), + generateWritePort("outerA", width, memDepth, memMaskGran) + ) + ) + + override def generateHeader = +""" +circuit target_memory : + module target_memory : + input outerB_clk : Clock + input outerB_addr : UInt<11> + output outerB_dout : UInt<8> + input outerA_clk : Clock + input outerA_addr : UInt<11> + input outerA_din : UInt<8> + input outerA_write_en : UInt<1> + input outerA_mask : UInt<1> +""" + + override def generateBody = +""" + node outerB_addr_sel = bits(outerB_addr, 10, 10) + reg outerB_addr_sel_reg : UInt<1>, outerB_clk with : + reset => (UInt<1>("h0"), outerB_addr_sel_reg) + outerB_addr_sel_reg <= mux(UInt<1>("h1"), outerB_addr_sel, outerB_addr_sel_reg) + node outerA_addr_sel = bits(outerA_addr, 10, 10) + inst mem_0_0 of awesome_lib_mem + mem_0_0.innerB_clk <= outerA_clk + mem_0_0.innerB_addr <= outerA_addr + mem_0_0.innerB_din <= bits(outerA_din, 7, 0) + mem_0_0.innerB_mask <= cat(bits(outerA_mask, 0, 0), cat(bits(outerA_mask, 0, 0), cat(bits(outerA_mask, 0, 0), cat(bits(outerA_mask, 0, 0), cat(bits(outerA_mask, 0, 0), cat(bits(outerA_mask, 0, 0), cat(bits(outerA_mask, 0, 0), bits(outerA_mask, 0, 0)))))))) + mem_0_0.innerB_write_en <= and(and(outerA_write_en, UInt<1>("h1")), eq(outerA_addr_sel, UInt<1>("h0"))) + mem_0_0.innerA_clk <= outerB_clk + mem_0_0.innerA_addr <= outerB_addr + node outerB_dout_0_0 = bits(mem_0_0.innerA_dout, 7, 0) + node outerB_dout_0 = outerB_dout_0_0 + inst mem_1_0 of awesome_lib_mem + mem_1_0.innerB_clk <= outerA_clk + mem_1_0.innerB_addr <= outerA_addr + mem_1_0.innerB_din <= bits(outerA_din, 7, 0) + mem_1_0.innerB_mask <= cat(bits(outerA_mask, 0, 0), cat(bits(outerA_mask, 0, 0), cat(bits(outerA_mask, 0, 0), cat(bits(outerA_mask, 0, 0), cat(bits(outerA_mask, 0, 0), cat(bits(outerA_mask, 0, 0), cat(bits(outerA_mask, 0, 0), bits(outerA_mask, 0, 0)))))))) + mem_1_0.innerB_write_en <= and(and(outerA_write_en, UInt<1>("h1")), eq(outerA_addr_sel, UInt<1>("h1"))) + mem_1_0.innerA_clk <= outerB_clk + mem_1_0.innerA_addr <= outerB_addr + node outerB_dout_1_0 = bits(mem_1_0.innerA_dout, 7, 0) + node outerB_dout_1 = outerB_dout_1_0 + outerB_dout <= mux(eq(outerB_addr_sel_reg, UInt<1>("h0")), outerB_dout_0, mux(eq(outerB_addr_sel_reg, UInt<1>("h1")), outerB_dout_1, UInt<1>("h0"))) +""" + + override def generateFooterPorts = +""" + input innerA_clk : Clock + input innerA_addr : UInt<10> + output innerA_dout : UInt<8> + input innerB_clk : Clock + input innerB_addr : UInt<10> + input innerB_din : UInt<8> + input innerB_write_en : UInt<1> + input innerB_mask : UInt<8> +""" + + override def generateFlops = +""" + mem ram : + data-type => UInt<1>[8] + depth => 1024 + read-latency => 1 + write-latency => 1 + reader => R_0 + writer => W_0 + read-under-write => undefined + ram.R_0.clk <= innerA_clk + ram.R_0.addr <= innerA_addr + ram.R_0.en <= UInt<1>("h1") + innerA_dout <= 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]))))))) + ram.W_0.clk <= innerB_clk + ram.W_0.addr <= innerB_addr + ram.W_0.en <= innerB_write_en + ram.W_0.data[0] <= bits(innerB_din, 0, 0) + ram.W_0.data[1] <= bits(innerB_din, 1, 1) + ram.W_0.data[2] <= bits(innerB_din, 2, 2) + ram.W_0.data[3] <= bits(innerB_din, 3, 3) + ram.W_0.data[4] <= bits(innerB_din, 4, 4) + ram.W_0.data[5] <= bits(innerB_din, 5, 5) + ram.W_0.data[6] <= bits(innerB_din, 6, 6) + ram.W_0.data[7] <= bits(innerB_din, 7, 7) + ram.W_0.mask[0] <= bits(innerB_mask, 0, 0) + ram.W_0.mask[1] <= bits(innerB_mask, 1, 1) + ram.W_0.mask[2] <= bits(innerB_mask, 2, 2) + ram.W_0.mask[3] <= bits(innerB_mask, 3, 3) + ram.W_0.mask[4] <= bits(innerB_mask, 4, 4) + ram.W_0.mask[5] <= bits(innerB_mask, 5, 5) + ram.W_0.mask[6] <= bits(innerB_mask, 6, 6) + ram.W_0.mask[7] <= bits(innerB_mask, 7, 7) +""" + + "masked split lib; masked split mem" should "syn flops fine" in { + compileExecuteAndTest(mem, lib, v, output, true) + } +}