From 5d3bebd2b91cddebb7c1ab750a5150277231b1cf Mon Sep 17 00:00:00 2001 From: Edward Wang Date: Wed, 9 Aug 2017 00:57:38 -0700 Subject: [PATCH] Re-implement parallel mapping - Support byte-masked SRAM, yay - Also nuke a bunch of bugs --- macros/src/main/scala/MacroCompiler.scala | 145 ++++++++++++++---- macros/src/test/scala/MacroCompilerSpec.scala | 55 ++++++- macros/src/test/scala/Masks.scala | 95 +++++++++++- macros/src/test/scala/SimpleSplitDepth.scala | 21 +-- macros/src/test/scala/SimpleSplitWidth.scala | 34 ++-- macros/src/test/scala/SpecificExamples.scala | 89 +++-------- 6 files changed, 291 insertions(+), 148 deletions(-) diff --git a/macros/src/main/scala/MacroCompiler.scala b/macros/src/main/scala/MacroCompiler.scala index 6c0306a8..162e015a 100644 --- a/macros/src/main/scala/MacroCompiler.scala +++ b/macros/src/main/scala/MacroCompiler.scala @@ -53,35 +53,113 @@ class MacroCompilerPass(mems: Option[Seq[Macro]], val pairedPorts = mem.sortedPorts zip lib.sortedPorts // Parallel mapping - val pairs = ArrayBuffer[(BigInt, BigInt)]() - var last = 0 - for (i <- 0 until mem.src.width) { - if (i <= last + 1) { - /* Palmer: Every memory is going to have to fit at least a single bit. */ - // continue - } else if ((i - last) % lib.src.width.toInt == 0) { - /* Palmer: It's possible that we rolled over a memory's width here, - if so generate one. */ - pairs += ((last, i-1)) - last = i - } else { - /* Palmer: FIXME: This is a mess, I must just be super confused. */ - for ((memPort, libPort) <- pairedPorts) { - (memPort.src.maskGran, libPort.src.maskGran) match { - case (_, Some(p)) if p == 1 => // continue - case (Some(p), _) if i % p == 0 => - pairs += ((last, i-1)) - last = i - case (_, None) => // continue - case (_, Some(p)) if p == lib.src.width => // continue - case _ => - System.err println "Bit-mask (or unmasked) target memories are supported only" - return None + + /** + * This is a list of submemories by width. + * The tuples are (lsb, msb) inclusive. + * e.g. (0, 7) and (8, 15) might be a split for a width=16 memory into two + * width=8 memories. + */ + val bitPairs = ArrayBuffer[(BigInt, BigInt)]() + var currentLSB = 0 + + // Process every bit in the mem width. + for (memBit <- 0 until mem.src.width) { + val bitsInCurrentMem = memBit - currentLSB + + /** + * Helper function to check if it's time to split memories. + * @param effectiveLibWidth Split memory when we have this many bits. + */ + def splitMemory(effectiveLibWidth: Int): Unit = { + if (bitsInCurrentMem == effectiveLibWidth) { + bitPairs += ((currentLSB, memBit - 1)) + currentLSB = memBit + } + } + + for ((memPort, libPort) <- pairedPorts) { + + // Make sure we don't have a maskGran larger than the width of the memory. + assert (memPort.src.effectiveMaskGran <= memPort.src.width) + assert (libPort.src.effectiveMaskGran <= libPort.src.width) + + val libWidth = libPort.src.width + + // Don't consider cases of maskGran == width as "masked" since those masks + // effectively function as write-enable bits. + val memMask = if (memPort.src.effectiveMaskGran == memPort.src.width) None else memPort.src.maskGran + val libMask = if (libPort.src.effectiveMaskGran == libPort.src.width) None else libPort.src.maskGran + + (memMask, libMask) match { + // Neither lib nor mem is masked. + // No problems here. + case (None, None) => splitMemory(libWidth) + + // Only the lib is masked. + // Not an issue; we can just make all the bits in the lib mask enabled. + case (None, Some(p)) => splitMemory(libWidth) + + // Only the mem is masked. + case (Some(p), None) => { + if (p % libPort.src.width == 0) { + // If the mem mask is a multiple of the lib width, then we're good. + // Just roll over every lib width as usual. + // e.g. lib width=4, mem maskGran={4, 8, 12, 16, ...} + splitMemory(libWidth) + } else if (libPort.src.width % p == 0) { + // Lib width is a multiple of the mem mask. + // Consider the case where mem mask = 4 but lib width = 8, unmasked. + // We can still compile, but will need to waste the extra bits. + splitMemory(memMask.get) + } else { + // No neat multiples. + // We might still be able to compile extremely inefficiently. + if (p < libPort.src.width) { + // Compile using mem mask as the effective width. (note that lib is not masked) + // e.g. mem mask = 3, lib width = 8 + splitMemory(memMask.get) + } else { + // e.g. mem mask = 13, lib width = 8 + System.err.println(s"Unmasked target memory: unaligned mem maskGran ${p} with lib (${lib.src.name}) width ${libPort.src.width} not supported") + return None + } + } + } + + // Both lib and mem are masked. + case (Some(m), Some(l)) => { + if (m == l) { + // Lib maskGran == mem maskGran, no problems + splitMemory(libWidth) + } else if (m > l) { + // Mem maskGran > lib maskGran + if (m % l == 0) { + // Mem maskGran is a multiple of lib maskGran, carry on as normal. + splitMemory(libWidth) + } else { + System.err.println(s"Mem maskGran ${m} is not a multiple of lib maskGran ${l}: currently not supported") + return None + } + } else { // m < l + // Lib maskGran > mem maskGran. + if (l % m == 0) { + // Lib maskGran is a multiple of mem maskGran. + // e.g. lib maskGran = 8, mem maskGran = 4. + // In this case we can only compile very wastefully (by treating + // lib as a mem maskGran width memory) :( + splitMemory(memMask.get) + } else { + System.err.println(s"Lib maskGran ${m} is not a multiple of mem maskGran ${l}: currently not supported") + return None + } + } } } } } - pairs += ((last, mem.src.width.toInt - 1)) + // Add in the last chunk if there are any leftovers + bitPairs += ((currentLSB, mem.src.width.toInt - 1)) // Serial mapping val stmts = ArrayBuffer[Statement]() @@ -116,7 +194,7 @@ class MacroCompilerPass(mems: Option[Seq[Macro]], } } for ((off, i) <- (0 until mem.src.depth by lib.src.depth).zipWithIndex) { - for (j <- pairs.indices) { + for (j <- bitPairs.indices) { val name = s"mem_${i}_${j}" stmts += WDefInstance(NoInfo, name, lib.src.name, lib.tpe) // connect extra ports @@ -141,7 +219,7 @@ class MacroCompilerPass(mems: Option[Seq[Macro]], and(e, addrMatch) } val cats = ArrayBuffer[Expression]() - for (((low, high), j) <- pairs.zipWithIndex) { + for (((low, high), j) <- bitPairs.zipWithIndex) { val inst = WRef(s"mem_${i}_${j}", lib.tpe) def connectPorts2(mem: Expression, @@ -221,11 +299,18 @@ class MacroCompilerPass(mems: Option[Seq[Macro]], if (libPort.src.effectiveMaskGran == libPort.src.width) { bits(WRef(mem), low / memPort.src.effectiveMaskGran) } else { - require(libPort.src.effectiveMaskGran == 1, "only single-bit mask supported for now") - require(isPowerOfTwo(libPort.src.effectiveMaskGran), "only powers of two masks supported for now") - cat(((low to high) map (i => bits(WRef(mem), i / memPort.src.effectiveMaskGran))).reverse) + val effectiveLibWidth = if (memPort.src.maskGran.get < libPort.src.effectiveMaskGran) memPort.src.maskGran.get else libPort.src.width + cat(((0 until libPort.src.width by libPort.src.effectiveMaskGran) map (i => { + if (memPort.src.maskGran.get < libPort.src.effectiveMaskGran && i >= effectiveLibWidth) { + // If the memMaskGran is smaller than the lib's gran, then + // zero out the upper bits. + zero + } else { + bits(WRef(mem), (low + i) / memPort.src.effectiveMaskGran) + } + })).reverse) } case None => /* Palmer: If there is no input port on the source memory port diff --git a/macros/src/test/scala/MacroCompilerSpec.scala b/macros/src/test/scala/MacroCompilerSpec.scala index afdfe4f8..6c941a3f 100644 --- a/macros/src/test/scala/MacroCompilerSpec.scala +++ b/macros/src/test/scala/MacroCompilerSpec.scala @@ -201,6 +201,9 @@ trait HasSimpleTestGenerator { def extraPorts: Seq[mdf.macrolib.MacroExtraPort] = List() def extraTag: String = "" + // "Effective" libMaskGran by considering write_enable. + val effectiveLibMaskGran = libMaskGran.getOrElse(libWidth) + // Override this in the sub-generator if you need a more specific name. // Defaults to using reflection to pull the name of the test using this // generator. @@ -242,16 +245,62 @@ trait HasSimpleTestGenerator { writeToLib(lib, Seq(libSRAM)) writeToMem(mem, Seq(memSRAM)) + // For masks, width it's a bit tricky since we have to consider cases like + // memMaskGran = 4 and libMaskGran = 8. + // Consider the actually usable libWidth in cases like the above. + val usableLibWidth = if (memMaskGran.getOrElse(Int.MaxValue) < effectiveLibMaskGran) memMaskGran.get else libWidth + // Number of lib instances needed to hold the mem, in both directions. // Round up (e.g. 1.5 instances = effectively 2 instances) val depthInstances = math.ceil(memDepth.toFloat / libDepth).toInt - val widthInstances = math.ceil(memWidth.toFloat / libWidth).toInt + val widthInstances = math.ceil(memWidth.toFloat / usableLibWidth).toInt + // Number of width bits in the last width-direction memory. // e.g. if memWidth = 16 and libWidth = 8, this would be 8 since the last memory 0_1 has 8 bits of input width. // e.g. if memWidth = 9 and libWidth = 8, this would be 1 since the last memory 0_1 has 1 bit of input width. - val lastWidthBits = if (memWidth % libWidth == 0) libWidth else (memWidth % libWidth) + val lastWidthBits = if (memWidth % usableLibWidth == 0) usableLibWidth else (memWidth % usableLibWidth) val selectBits = mem_addr_width - lib_addr_width + /** + * Convenience function to generate a mask statement. + * @param widthInst Width instance (mem_0_x) + * @param depthInst Depth instance (mem_x_0) + */ + def generateMaskStatement(widthInst: Int, depthInst: Int): String = { + // Width of this submemory. + val myMemWidth = if (widthInst == widthInstances - 1) lastWidthBits else usableLibWidth + // Base bit of this submemory. + // e.g. if libWidth is 8 and this is submemory 2 (0-indexed), then this + // would be 16. + val myBaseBit = usableLibWidth*widthInst + + if (libMaskGran.isDefined) { + if (memMaskGran.isEmpty) { + // If there is no memory mask, we should just turn all the lib mask + // bits high. + s"""mem_${depthInst}_${widthInst}.lib_mask <= UInt<${libMaskBits}>("h${((1 << libMaskBits) - 1).toHexString}")""" + } else { + // Calculate which bit of outer_mask contains the given bit. + // e.g. if memMaskGran = 2, libMaskGran = 1 and libWidth = 4, then + // calculateMaskBit({0, 1}) = 0 and calculateMaskBit({1, 2}) = 1 + def calculateMaskBit(bit:Int): Int = bit / memMaskGran.getOrElse(memWidth) + + val bitsArr = ((libMaskBits - 1 to 0 by -1) map (x => { + if (x*libMaskGran.get > myMemWidth) { + // If we have extra mask bits leftover after the effective width, + // disable those bits. + """UInt<1>("h0")""" + } else { + val outerMaskBit = calculateMaskBit(x*libMaskGran.get + myBaseBit) + s"bits(outer_mask, ${outerMaskBit}, ${outerMaskBit})" + } + })) + val maskVal = bitsArr.reduceRight((bit, rest) => s"cat($bit, $rest)") + s"mem_${depthInst}_${widthInst}.lib_mask <= ${maskVal}" + } + } else "" + } + // Generate the header (contains the circuit statement and the target memory // module. def generateHeader(): String = { @@ -293,8 +342,6 @@ circuit $mem_name : def generateFooter(): String = { require (libSRAM.ports.size == 1, "Footer generator only supports single port lib") - val readEnable = if (libSRAM.ports(0).readEnable.isDefined) s"input ${libPortPrefix}_read_en : UInt<1>" else "" - val footerMask = if (libHasMask) s"input ${libPortPrefix}_mask : UInt<${libMaskBits}>" else "" s""" extmodule $lib_name : ${generateFooterPorts} diff --git a/macros/src/test/scala/Masks.scala b/macros/src/test/scala/Masks.scala index c00a162d..b4fef89a 100644 --- a/macros/src/test/scala/Masks.scala +++ b/macros/src/test/scala/Masks.scala @@ -4,14 +4,105 @@ import mdf.macrolib._ // Test the ability of the compiler to deal with various mask combinations. -// Simple powers of two with bit-masked lib. - trait MasksTestSettings { this: MacroCompilerSpec with HasSRAMGenerator with HasSimpleDepthTestGenerator => override lazy val memDepth = 2048 override lazy val libDepth = 1024 } +// Try all four different kinds of mask config: +/** + * + * Non-masked mem Masked mem + * --------------------------------- + * Non-masked lib | | | + * --------------------------------- + * Masked lib | | | + * --------------------------------- + */ + +class Masks_FourTypes_NonMaskedMem_NonMaskedLib extends MacroCompilerSpec with HasSRAMGenerator with HasSimpleWidthTestGenerator { + override lazy val depth = 1024 + override lazy val memWidth = 32 + override lazy val memMaskGran = None + override lazy val libWidth = 8 + override lazy val libMaskGran = None + + compileExecuteAndTest(mem, lib, v, output) +} + +class Masks_FourTypes_NonMaskedMem_MaskedLib extends MacroCompilerSpec with HasSRAMGenerator with HasSimpleWidthTestGenerator { + override lazy val depth = 1024 + override lazy val memWidth = 32 + override lazy val memMaskGran = None + override lazy val libWidth = 8 + override lazy val libMaskGran = Some(2) + + compileExecuteAndTest(mem, lib, v, output) +} + +class Masks_FourTypes_MaskedMem_NonMaskedLib extends MacroCompilerSpec with HasSRAMGenerator with HasSimpleWidthTestGenerator { + override lazy val depth = 1024 + override lazy val memWidth = 32 + override lazy val memMaskGran = Some(8) + override lazy val libWidth = 8 + override lazy val libMaskGran = None + + compileExecuteAndTest(mem, lib, v, output) +} + +class Masks_FourTypes_MaskedMem_NonMaskedLib_SmallerMaskGran extends MacroCompilerSpec with HasSRAMGenerator with HasSimpleWidthTestGenerator { + override lazy val depth = 1024 + override lazy val memWidth = 32 + override lazy val memMaskGran = Some(4) + override lazy val libWidth = 8 + override lazy val libMaskGran = None + + compileExecuteAndTest(mem, lib, v, output) +} + +class Masks_FourTypes_MaskedMem_MaskedLib extends MacroCompilerSpec with HasSRAMGenerator with HasSimpleWidthTestGenerator { + override lazy val depth = 1024 + override lazy val memWidth = 32 + override lazy val memMaskGran = Some(8) + override lazy val libWidth = 16 + override lazy val libMaskGran = Some(4) + + compileExecuteAndTest(mem, lib, v, output) +} + +class Masks_FourTypes_MaskedMem_MaskedLib_SameMaskGran extends MacroCompilerSpec with HasSRAMGenerator with HasSimpleWidthTestGenerator { + override lazy val depth = 1024 + override lazy val memWidth = 32 + override lazy val memMaskGran = Some(8) + override lazy val libWidth = 16 + override lazy val libMaskGran = Some(8) + + compileExecuteAndTest(mem, lib, v, output) +} + +class Masks_FourTypes_MaskedMem_MaskedLib_SmallerMaskGran extends MacroCompilerSpec with HasSRAMGenerator with HasSimpleWidthTestGenerator { + override lazy val depth = 1024 + override lazy val memWidth = 64 + override lazy val memMaskGran = Some(4) + override lazy val libWidth = 32 + override lazy val libMaskGran = Some(8) + + compileExecuteAndTest(mem, lib, v, output) +} + +// FPGA-style byte-masked memories. + +class Masks_FPGAStyle_32_8 extends MacroCompilerSpec with HasSRAMGenerator with HasSimpleDepthTestGenerator with MasksTestSettings { + override lazy val width = 32 + override lazy val memMaskGran = Some(32) + override lazy val libMaskGran = Some(8) + + compileExecuteAndTest(mem, lib, v, output) +} + +// Simple powers of two with bit-masked lib. + class Masks_PowersOfTwo_8_1 extends MacroCompilerSpec with HasSRAMGenerator with HasSimpleDepthTestGenerator with MasksTestSettings { override lazy val width = 64 override lazy val memMaskGran = Some(8) diff --git a/macros/src/test/scala/SimpleSplitDepth.scala b/macros/src/test/scala/SimpleSplitDepth.scala index d8be8fe5..442e44c7 100644 --- a/macros/src/test/scala/SimpleSplitDepth.scala +++ b/macros/src/test/scala/SimpleSplitDepth.scala @@ -29,26 +29,7 @@ s""" } for (i <- 0 to depthInstances - 1) { - // We only support simple masks for now (either libMask == memMask or libMask == 1) - val maskStatement = if (libHasMask) { - if (libMaskGran.get == memMaskGran.get) { - s"""mem_${i}_0.lib_mask <= bits(outer_mask, 0, 0)""" - } else if (libMaskGran.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 memMaskGran.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 maskStatement = generateMaskStatement(0, i) val enableIdentifier = if (selectBits > 0) s"""eq(outer_addr_sel, UInt<${selectBits}>("h${i.toHexString}"))""" else "UInt<1>(\"h1\")" output.append( s""" diff --git a/macros/src/test/scala/SimpleSplitWidth.scala b/macros/src/test/scala/SimpleSplitWidth.scala index b25c7d1b..de00a235 100644 --- a/macros/src/test/scala/SimpleSplitWidth.scala +++ b/macros/src/test/scala/SimpleSplitWidth.scala @@ -24,40 +24,28 @@ trait HasSimpleWidthTestGenerator extends HasSimpleTestGenerator { // Generate submemory connection blocks. output append (for (i <- 0 to widthInstances - 1) yield { // Width of this submemory. - val myMemWidth = if (i == widthInstances - 1) lastWidthBits else libWidth + val myMemWidth = if (i == widthInstances - 1) lastWidthBits else usableLibWidth // Base bit of this submemory. // e.g. if libWidth is 8 and this is submemory 2 (0-indexed), then this // would be 16. - val myBaseBit = libWidth*i + val myBaseBit = usableLibWidth*i - val maskStatement = if (libMaskGran.isDefined) { - if (memMaskGran.isEmpty) { - // If there is no memory mask, we should just turn all the lib mask - // bits high. - s"""mem_0_${i}.lib_mask <= UInt<${libMaskBits}>("h${((1 << libMaskBits) - 1).toHexString}")""" - } else if (libMaskGran.get == memMaskGran.get) { - s"mem_0_${i}.lib_mask <= bits(outer_mask, ${i}, ${i})" - } else if (libMaskGran.get == 1) { - // Calculate which bit of outer_mask contains the given bit. - // e.g. if memMaskGran = 2, libMaskGran = 1 and libWidth = 4, then - // calculateMaskBit({0, 1}) = 0 and calculateMaskBit({1, 2}) = 1 - def calculateMaskBit(bit:Int): Int = (bit / libMaskGran.get) / memMaskGran.getOrElse(memWidth) + val maskStatement = generateMaskStatement(i, 0) + + // We need to use writeEnable as a crude "mask" if mem has a mask but + // lib does not. + val writeEnableBit = if (libMaskGran.isEmpty && memMaskGran.isDefined) { + val outerMaskBit = myBaseBit / memMaskGran.get + s"bits(outer_mask, ${outerMaskBit}, ${outerMaskBit})" + } else """UInt<1>("h1")""" - val bitsArr = ((libMaskBits - 1 to 0 by -1) map (x => { - val outerMaskBit = calculateMaskBit(x*libMaskGran.get + myBaseBit) - s"bits(outer_mask, ${outerMaskBit}, ${outerMaskBit})" - })) - val maskVal = bitsArr.init.foldRight(bitsArr.last)((bit, rest) => s"cat($bit, $rest)") - s"mem_0_${i}.lib_mask <= ${maskVal}" - } else "" // We support only bit-level masks for now. - } else "" s""" mem_0_${i}.lib_clk <= outer_clk mem_0_${i}.lib_addr <= outer_addr node outer_dout_0_${i} = bits(mem_0_${i}.lib_dout, ${myMemWidth - 1}, 0) mem_0_${i}.lib_din <= bits(outer_din, ${myBaseBit + myMemWidth - 1}, ${myBaseBit}) ${maskStatement} - mem_0_${i}.lib_write_en <= and(and(outer_write_en, UInt<1>("h1")), UInt<1>("h1")) + mem_0_${i}.lib_write_en <= and(and(outer_write_en, ${writeEnableBit}), UInt<1>("h1")) """ }).reduceLeft(_ + _) diff --git a/macros/src/test/scala/SpecificExamples.scala b/macros/src/test/scala/SpecificExamples.scala index 7167ce61..fb884084 100644 --- a/macros/src/test/scala/SpecificExamples.scala +++ b/macros/src/test/scala/SpecificExamples.scala @@ -188,90 +188,41 @@ circuit T_2172_ext : input RW0_wmode : UInt<1> input RW0_wmask : UInt<4> - inst mem_0_0 of SRAM1RW64x8 - inst mem_0_1 of SRAM1RW64x8 - inst mem_0_2 of SRAM1RW64x8 - inst mem_0_3 of SRAM1RW64x8 - inst mem_0_4 of SRAM1RW64x8 - inst mem_0_5 of SRAM1RW64x8 - inst mem_0_6 of SRAM1RW64x8 - inst mem_0_7 of SRAM1RW64x8 - inst mem_0_8 of SRAM1RW64x8 - inst mem_0_9 of SRAM1RW64x8 - inst mem_0_10 of SRAM1RW64x8 - inst mem_0_11 of SRAM1RW64x8 + inst mem_0_0 of SRAM1RW64x32 + inst mem_0_1 of SRAM1RW64x32 + inst mem_0_2 of SRAM1RW64x32 + inst mem_0_3 of SRAM1RW64x32 mem_0_0.clk <= RW0_clk mem_0_0.addr <= RW0_addr - node RW0_rdata_0_0 = bits(mem_0_0.dout, 7, 0) - mem_0_0.din <= bits(RW0_wdata, 7, 0) + node RW0_rdata_0_0 = bits(mem_0_0.dout, 19, 0) + mem_0_0.din <= bits(RW0_wdata, 19, 0) mem_0_0.write_en <= and(and(RW0_wmode, bits(RW0_wmask, 0, 0)), UInt<1>("h1")) mem_0_1.clk <= RW0_clk mem_0_1.addr <= RW0_addr - node RW0_rdata_0_1 = bits(mem_0_1.dout, 7, 0) - mem_0_1.din <= bits(RW0_wdata, 15, 8) - mem_0_1.write_en <= and(and(RW0_wmode, bits(RW0_wmask, 0, 0)), UInt<1>("h1")) + node RW0_rdata_0_1 = bits(mem_0_1.dout, 19, 0) + mem_0_1.din <= bits(RW0_wdata, 39, 20) + mem_0_1.write_en <= and(and(RW0_wmode, bits(RW0_wmask, 1, 1)), UInt<1>("h1")) mem_0_2.clk <= RW0_clk mem_0_2.addr <= RW0_addr - node RW0_rdata_0_2 = bits(mem_0_2.dout, 3, 0) - mem_0_2.din <= bits(RW0_wdata, 19, 16) - mem_0_2.write_en <= and(and(RW0_wmode, bits(RW0_wmask, 0, 0)), UInt<1>("h1")) + node RW0_rdata_0_2 = bits(mem_0_2.dout, 19, 0) + mem_0_2.din <= bits(RW0_wdata, 59, 40) + mem_0_2.write_en <= and(and(RW0_wmode, bits(RW0_wmask, 2, 2)), UInt<1>("h1")) mem_0_3.clk <= RW0_clk mem_0_3.addr <= RW0_addr - node RW0_rdata_0_3 = bits(mem_0_3.dout, 7, 0) - mem_0_3.din <= bits(RW0_wdata, 27, 20) - mem_0_3.write_en <= and(and(RW0_wmode, bits(RW0_wmask, 1, 1)), UInt<1>("h1")) - mem_0_4.clk <= RW0_clk - mem_0_4.addr <= RW0_addr - node RW0_rdata_0_4 = bits(mem_0_4.dout, 7, 0) - mem_0_4.din <= bits(RW0_wdata, 35, 28) - mem_0_4.write_en <= and(and(RW0_wmode, bits(RW0_wmask, 1, 1)), UInt<1>("h1")) - mem_0_5.clk <= RW0_clk - mem_0_5.addr <= RW0_addr - node RW0_rdata_0_5 = bits(mem_0_5.dout, 3, 0) - mem_0_5.din <= bits(RW0_wdata, 39, 36) - mem_0_5.write_en <= and(and(RW0_wmode, bits(RW0_wmask, 1, 1)), UInt<1>("h1")) - mem_0_6.clk <= RW0_clk - mem_0_6.addr <= RW0_addr - node RW0_rdata_0_6 = bits(mem_0_6.dout, 7, 0) - mem_0_6.din <= bits(RW0_wdata, 47, 40) - mem_0_6.write_en <= and(and(RW0_wmode, bits(RW0_wmask, 2, 2)), UInt<1>("h1")) - mem_0_7.clk <= RW0_clk - mem_0_7.addr <= RW0_addr - node RW0_rdata_0_7 = bits(mem_0_7.dout, 7, 0) - mem_0_7.din <= bits(RW0_wdata, 55, 48) - mem_0_7.write_en <= and(and(RW0_wmode, bits(RW0_wmask, 2, 2)), UInt<1>("h1")) - mem_0_8.clk <= RW0_clk - mem_0_8.addr <= RW0_addr - node RW0_rdata_0_8 = bits(mem_0_8.dout, 3, 0) - mem_0_8.din <= bits(RW0_wdata, 59, 56) - mem_0_8.write_en <= and(and(RW0_wmode, bits(RW0_wmask, 2, 2)), UInt<1>("h1")) - mem_0_9.clk <= RW0_clk - mem_0_9.addr <= RW0_addr - node RW0_rdata_0_9 = bits(mem_0_9.dout, 7, 0) - mem_0_9.din <= bits(RW0_wdata, 67, 60) - mem_0_9.write_en <= and(and(RW0_wmode, bits(RW0_wmask, 3, 3)), UInt<1>("h1")) - mem_0_10.clk <= RW0_clk - mem_0_10.addr <= RW0_addr - node RW0_rdata_0_10 = bits(mem_0_10.dout, 7, 0) - mem_0_10.din <= bits(RW0_wdata, 75, 68) - mem_0_10.write_en <= and(and(RW0_wmode, bits(RW0_wmask, 3, 3)), UInt<1>("h1")) - mem_0_11.clk <= RW0_clk - mem_0_11.addr <= RW0_addr - node RW0_rdata_0_11 = bits(mem_0_11.dout, 3, 0) - mem_0_11.din <= bits(RW0_wdata, 79, 76) - mem_0_11.write_en <= and(and(RW0_wmode, bits(RW0_wmask, 3, 3)), UInt<1>("h1")) - node RW0_rdata_0 = cat(RW0_rdata_0_11, cat(RW0_rdata_0_10, cat(RW0_rdata_0_9, cat(RW0_rdata_0_8, cat(RW0_rdata_0_7, cat(RW0_rdata_0_6, cat(RW0_rdata_0_5, cat(RW0_rdata_0_4, cat(RW0_rdata_0_3, cat(RW0_rdata_0_2, cat(RW0_rdata_0_1, RW0_rdata_0_0))))))))))) + node RW0_rdata_0_3 = bits(mem_0_3.dout, 19, 0) + mem_0_3.din <= bits(RW0_wdata, 79, 60) + mem_0_3.write_en <= and(and(RW0_wmode, bits(RW0_wmask, 3, 3)), UInt<1>("h1")) + node RW0_rdata_0 = cat(RW0_rdata_0_3, cat(RW0_rdata_0_2, cat(RW0_rdata_0_1, RW0_rdata_0_0))) RW0_rdata <= mux(UInt<1>("h1"), RW0_rdata_0, UInt<1>("h0")) - extmodule SRAM1RW64x8 : + extmodule SRAM1RW64x32 : input clk : Clock input addr : UInt<6> - input din : UInt<8> - output dout : UInt<8> + input din : UInt<32> + output dout : UInt<32> input write_en : UInt<1> - defname = SRAM1RW64x8 - + defname = SRAM1RW64x32 module T_1090_ext : input RW0_clk : Clock