Correct multi-ported memory compilation (#27)

* Correct multi-ported memory compilation

It was incorrectly splitting multiple times before. Fixed the issue and
added regression tests for this issue.

* Add 1 read 1 write test
This commit is contained in:
edwardcwang
2017-10-06 18:04:49 -07:00
committed by GitHub
parent e1499fcdc0
commit c884a2fb15
5 changed files with 2869 additions and 36 deletions

View File

@@ -91,6 +91,17 @@ class MacroCompilerPass(mems: Option[Seq[Macro]],
libs: Option[Seq[Macro]],
costMetric: CostMetric = CostMetric.default,
mode: MacroCompilerAnnotation.CompilerMode = MacroCompilerAnnotation.Default) extends firrtl.passes.Pass {
// Helper function to check the legality of bitPairs.
// e.g. ((0,21), (22,43)) is legal
// ((0,21), (22,21)) is illegal and will throw an assert
private def checkBitPairs(bitPairs: Seq[(BigInt, BigInt)]): Unit = {
bitPairs.foldLeft(BigInt(-1))((lastBit, nextPair) => {
assert(lastBit + 1 == nextPair._1, s"Pair's first bit ${nextPair._1} does not follow last bit ${lastBit}");
assert(nextPair._2 >= nextPair._1, s"Pair ${nextPair} in bitPairs ${bitPairs} is illegal");
nextPair._2
})
}
def compile(mem: Macro, lib: Macro): Option[(Module, ExtModule)] = {
val pairedPorts = mem.sortedPorts zip lib.sortedPorts
@@ -103,23 +114,33 @@ class MacroCompilerPass(mems: Option[Seq[Macro]],
* width=8 memories.
*/
val bitPairs = ArrayBuffer[(BigInt, BigInt)]()
var currentLSB = 0
var currentLSB: BigInt = 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
}
}
// We'll need to find a bitPair that works for *all* the ports of the memory.
// e.g. unmasked read port and masked write port.
// For each port, store a tentative candidate for the split.
// Afterwards, figure out which one to use.
val bitPairCandidates = ArrayBuffer[(BigInt, BigInt)]()
for ((memPort, libPort) <- pairedPorts) {
// Sanity check to make sure we only split once per bit, once per port.
var alreadySplit: Boolean = false
// 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 = {
assert (!alreadySplit)
if (bitsInCurrentMem == effectiveLibWidth) {
bitPairCandidates += ((currentLSB, memBit - 1))
alreadySplit = true
}
}
// 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)
@@ -204,9 +225,23 @@ class MacroCompilerPass(mems: Option[Seq[Macro]],
}
}
}
// Choose an actual bit pair to add.
// We'll have to choose the smallest one (e.g. unmasked read port might be more tolerant of a bigger split than the masked write port).
if (bitPairCandidates.length == 0) {
// No pair needed to split, just continue
} else {
val bestPair = bitPairCandidates.reduceLeft((leftPair, rightPair) => {
if (leftPair._2 - leftPair._1 + 1 > rightPair._2 - rightPair._1 + 1) leftPair else rightPair
})
bitPairs += bestPair
currentLSB = bestPair._2 + BigInt(1) // advance the LSB pointer
}
}
// Add in the last chunk if there are any leftovers
bitPairs += ((currentLSB, mem.src.width.toInt - 1))
// Check bit pairs
checkBitPairs(bitPairs)
// Depth mapping
val stmts = ArrayBuffer[Statement]()

File diff suppressed because it is too large Load Diff

View File

@@ -301,47 +301,77 @@ trait HasSimpleTestGenerator {
} else ""
}
/** Helper function to generate a port.
* @param prefix Memory port prefix (e.g. "x" for ports like "x_clk")
* @param addrWidth Address port width
* @param width data width
* @param write Has a write port?
* @param writeEnable Has a write enable port?
* @param read Has a read port?
* @param readEnable Has a read enable port?
* @param mask Mask granularity (# bits) of the port or None. */
def generatePort(prefix: String, addrWidth: Int, width: Int, write: Boolean, writeEnable: Boolean, read: Boolean, readEnable: Boolean, mask: Option[Int]): String = {
val readStr = if (read) s"output ${prefix}_dout : UInt<$width>" else ""
val writeStr = if (write) s"input ${prefix}_din : UInt<$width>" else ""
val readEnableStr = if (readEnable) s"input ${prefix}_read_en : UInt<1>" else ""
val writeEnableStr = if (writeEnable) s"input ${prefix}_write_en : UInt<1>" else ""
val maskStr = mask match {
case Some(maskBits: Int) => s"input ${prefix}_mask : UInt<${maskBits}>"
case _ => ""
}
s"""
input ${prefix}_clk : Clock
input ${prefix}_addr : UInt<$addrWidth>
${writeStr}
${readStr}
${readEnableStr}
${writeEnableStr}
${maskStr}
"""
}
/** Helper function to generate a RW footer port.
* @param prefix Memory port prefix (e.g. "x" for ports like "x_clk")
* @param readEnable Has a read enable port?
* @param mask Mask granularity (# bits) of the port or None. */
def generateReadWriteFooterPort(prefix: String, readEnable: Boolean, mask: Option[Int]): String = {
generatePort(libPortPrefix, lib_addr_width, libWidth,
write=true, writeEnable=true, read=true, readEnable=readEnable, mask)
}
/** Helper function to generate a RW header port.
* @param prefix Memory port prefix (e.g. "x" for ports like "x_clk")
* @param readEnable Has a read enable port?
* @param mask Mask granularity (# bits) of the port or None. */
def generateReadWriteHeaderPort(prefix: String, readEnable: Boolean, mask: Option[Int]): String = {
generatePort(memPortPrefix, mem_addr_width, memWidth,
write=true, writeEnable=true, read=true, readEnable=readEnable, mask)
}
// Generate the header memory ports.
def generateHeaderPorts(): String = {
require (memSRAM.ports.size == 1, "Header generator only supports single RW port mem")
generateReadWriteHeaderPort(memPortPrefix, memSRAM.ports(0).readEnable.isDefined, if (memHasMask) Some(memMaskBits) else None)
}
// Generate the header (contains the circuit statement and the target memory
// module.
def generateHeader(): String = {
require (memSRAM.ports.size == 1, "Header generator only supports single port mem")
val readEnable = if (memSRAM.ports(0).readEnable.isDefined) s"input ${memPortPrefix}_read_en : UInt<1>" else ""
val headerMask = if (memHasMask) s"input ${memPortPrefix}_mask : UInt<${memMaskBits}>" else ""
s"""
circuit $mem_name :
module $mem_name :
input ${memPortPrefix}_clk : Clock
input ${memPortPrefix}_addr : UInt<$mem_addr_width>
input ${memPortPrefix}_din : UInt<$memWidth>
output ${memPortPrefix}_dout : UInt<$memWidth>
${readEnable}
input ${memPortPrefix}_write_en : UInt<1>
${headerMask}
${generateHeaderPorts}
"""
}
// Generate the target memory ports.
def generateFooterPorts(): 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"""
input ${libPortPrefix}_clk : Clock
input ${libPortPrefix}_addr : UInt<$lib_addr_width>
input ${libPortPrefix}_din : UInt<$libWidth>
output ${libPortPrefix}_dout : UInt<$libWidth>
${readEnable}
input ${libPortPrefix}_write_en : UInt<1>
${footerMask}
"""
require (libSRAM.ports.size == 1, "Footer generator only supports single RW port mem")
generateReadWriteFooterPort(libPortPrefix, libSRAM.ports(0).readEnable.isDefined, if (libHasMask) Some(libMaskBits) else None)
}
// Generate the footer (contains the target memory extmodule declaration by default).
def generateFooter(): String = {
require (libSRAM.ports.size == 1, "Footer generator only supports single port lib")
s"""
extmodule $lib_name :
${generateFooterPorts}

View File

@@ -0,0 +1,392 @@
package barstools.macros
// Test that the memory compiler works fine for compiling multi-port memories.
// TODO: extend test generator to also automatically generate multi-ported memories.
class SplitWidth_2rw extends MacroCompilerSpec with HasSRAMGenerator with HasSimpleWidthTestGenerator {
import mdf.macrolib._
override lazy val depth = 1024
override lazy val memWidth = 64
override lazy val memMaskGran = Some(16)
override lazy val libWidth = 16
override def generateMemSRAM() = {
SRAMMacro(
name=mem_name,
width=memWidth,
depth=memDepth,
family="2rw",
ports=Seq(generateTestPort(
"portA", memWidth, memDepth, maskGran=memMaskGran,
write=true, writeEnable=true,
read=true, readEnable=true
), generateTestPort(
"portB", memWidth, memDepth, maskGran=memMaskGran,
write=true, writeEnable=true,
read=true, readEnable=true
))
)
}
override def generateLibSRAM() = {
SRAMMacro(
name=lib_name,
width=libWidth,
depth=libDepth,
family="2rw",
ports=Seq(generateTestPort(
"portA", libWidth, libDepth,
write=true, writeEnable=true,
read=true, readEnable=true
), generateTestPort(
"portB", libWidth, libDepth,
write=true, writeEnable=true,
read=true, readEnable=true
))
)
}
override def generateHeaderPorts() = {
generateReadWriteHeaderPort("portA", true, Some(memMaskBits)) + "\n" + generateReadWriteHeaderPort("portB", true, Some(memMaskBits))
}
override def generateFooterPorts() = {
generateReadWriteFooterPort("portA", true, None) + "\n" + generateReadWriteFooterPort("portB", true, None)
}
override def generateBody() =
"""
inst mem_0_0 of awesome_lib_mem
inst mem_0_1 of awesome_lib_mem
inst mem_0_2 of awesome_lib_mem
inst mem_0_3 of awesome_lib_mem
mem_0_0.portA_clk <= portA_clk
mem_0_0.portA_addr <= portA_addr
node portA_dout_0_0 = bits(mem_0_0.portA_dout, 15, 0)
mem_0_0.portA_din <= bits(portA_din, 15, 0)
mem_0_0.portA_read_en <= and(portA_read_en, UInt<1>("h1"))
mem_0_0.portA_write_en <= and(and(portA_write_en, bits(portA_mask, 0, 0)), UInt<1>("h1"))
mem_0_1.portA_clk <= portA_clk
mem_0_1.portA_addr <= portA_addr
node portA_dout_0_1 = bits(mem_0_1.portA_dout, 15, 0)
mem_0_1.portA_din <= bits(portA_din, 31, 16)
mem_0_1.portA_read_en <= and(portA_read_en, UInt<1>("h1"))
mem_0_1.portA_write_en <= and(and(portA_write_en, bits(portA_mask, 1, 1)), UInt<1>("h1"))
mem_0_2.portA_clk <= portA_clk
mem_0_2.portA_addr <= portA_addr
node portA_dout_0_2 = bits(mem_0_2.portA_dout, 15, 0)
mem_0_2.portA_din <= bits(portA_din, 47, 32)
mem_0_2.portA_read_en <= and(portA_read_en, UInt<1>("h1"))
mem_0_2.portA_write_en <= and(and(portA_write_en, bits(portA_mask, 2, 2)), UInt<1>("h1"))
mem_0_3.portA_clk <= portA_clk
mem_0_3.portA_addr <= portA_addr
node portA_dout_0_3 = bits(mem_0_3.portA_dout, 15, 0)
mem_0_3.portA_din <= bits(portA_din, 63, 48)
mem_0_3.portA_read_en <= and(portA_read_en, UInt<1>("h1"))
mem_0_3.portA_write_en <= and(and(portA_write_en, bits(portA_mask, 3, 3)), UInt<1>("h1"))
node portA_dout_0 = cat(portA_dout_0_3, cat(portA_dout_0_2, cat(portA_dout_0_1, portA_dout_0_0)))
mem_0_0.portB_clk <= portB_clk
mem_0_0.portB_addr <= portB_addr
node portB_dout_0_0 = bits(mem_0_0.portB_dout, 15, 0)
mem_0_0.portB_din <= bits(portB_din, 15, 0)
mem_0_0.portB_read_en <= and(portB_read_en, UInt<1>("h1"))
mem_0_0.portB_write_en <= and(and(portB_write_en, bits(portB_mask, 0, 0)), UInt<1>("h1"))
mem_0_1.portB_clk <= portB_clk
mem_0_1.portB_addr <= portB_addr
node portB_dout_0_1 = bits(mem_0_1.portB_dout, 15, 0)
mem_0_1.portB_din <= bits(portB_din, 31, 16)
mem_0_1.portB_read_en <= and(portB_read_en, UInt<1>("h1"))
mem_0_1.portB_write_en <= and(and(portB_write_en, bits(portB_mask, 1, 1)), UInt<1>("h1"))
mem_0_2.portB_clk <= portB_clk
mem_0_2.portB_addr <= portB_addr
node portB_dout_0_2 = bits(mem_0_2.portB_dout, 15, 0)
mem_0_2.portB_din <= bits(portB_din, 47, 32)
mem_0_2.portB_read_en <= and(portB_read_en, UInt<1>("h1"))
mem_0_2.portB_write_en <= and(and(portB_write_en, bits(portB_mask, 2, 2)), UInt<1>("h1"))
mem_0_3.portB_clk <= portB_clk
mem_0_3.portB_addr <= portB_addr
node portB_dout_0_3 = bits(mem_0_3.portB_dout, 15, 0)
mem_0_3.portB_din <= bits(portB_din, 63, 48)
mem_0_3.portB_read_en <= and(portB_read_en, UInt<1>("h1"))
mem_0_3.portB_write_en <= and(and(portB_write_en, bits(portB_mask, 3, 3)), UInt<1>("h1"))
node portB_dout_0 = cat(portB_dout_0_3, cat(portB_dout_0_2, cat(portB_dout_0_1, portB_dout_0_0)))
portA_dout <= mux(UInt<1>("h1"), portA_dout_0, UInt<1>("h0"))
portB_dout <= mux(UInt<1>("h1"), portB_dout_0, UInt<1>("h0"))
"""
compileExecuteAndTest(mem, lib, v, output)
}
class SplitWidth_1r_1w extends MacroCompilerSpec with HasSRAMGenerator with HasSimpleWidthTestGenerator {
import mdf.macrolib._
override lazy val depth = 1024
override lazy val memWidth = 64
override lazy val memMaskGran = Some(16)
override lazy val libWidth = 16
override def generateMemSRAM() = {
SRAMMacro(
name=mem_name,
width=memWidth,
depth=memDepth,
family="1r1w",
ports=Seq(generateTestPort(
"portA", memWidth, memDepth, maskGran=memMaskGran,
write=false, writeEnable=false,
read=true, readEnable=true
), generateTestPort(
"portB", memWidth, memDepth, maskGran=memMaskGran,
write=true, writeEnable=true,
read=false, readEnable=false
))
)
}
override def generateLibSRAM() = {
SRAMMacro(
name=lib_name,
width=libWidth,
depth=libDepth,
family="1r1w",
ports=Seq(generateTestPort(
"portA", libWidth, libDepth,
write=false, writeEnable=false,
read=true, readEnable=true
), generateTestPort(
"portB", libWidth, libDepth,
write=true, writeEnable=true,
read=false, readEnable=false
))
)
}
override def generateHeaderPorts() = {
generatePort("portA", mem_addr_width, memWidth,
write=false, writeEnable=false, read=true, readEnable=true, Some(memMaskBits)) + "\n" +
generatePort("portB", mem_addr_width, memWidth,
write=true, writeEnable=true, read=false, readEnable=false, Some(memMaskBits))
}
override def generateFooterPorts() = {
generatePort("portA", lib_addr_width, libWidth,
write=false, writeEnable=false, read=true, readEnable=true, None) + "\n" +
generatePort("portB", lib_addr_width, libWidth,
write=true, writeEnable=true, read=false, readEnable=false, None)
}
override def generateBody() =
"""
inst mem_0_0 of awesome_lib_mem
inst mem_0_1 of awesome_lib_mem
inst mem_0_2 of awesome_lib_mem
inst mem_0_3 of awesome_lib_mem
mem_0_0.portB_clk <= portB_clk
mem_0_0.portB_addr <= portB_addr
mem_0_0.portB_din <= bits(portB_din, 15, 0)
mem_0_0.portB_write_en <= and(and(portB_write_en, bits(portB_mask, 0, 0)), UInt<1>("h1"))
mem_0_1.portB_clk <= portB_clk
mem_0_1.portB_addr <= portB_addr
mem_0_1.portB_din <= bits(portB_din, 31, 16)
mem_0_1.portB_write_en <= and(and(portB_write_en, bits(portB_mask, 1, 1)), UInt<1>("h1"))
mem_0_2.portB_clk <= portB_clk
mem_0_2.portB_addr <= portB_addr
mem_0_2.portB_din <= bits(portB_din, 47, 32)
mem_0_2.portB_write_en <= and(and(portB_write_en, bits(portB_mask, 2, 2)), UInt<1>("h1"))
mem_0_3.portB_clk <= portB_clk
mem_0_3.portB_addr <= portB_addr
mem_0_3.portB_din <= bits(portB_din, 63, 48)
mem_0_3.portB_write_en <= and(and(portB_write_en, bits(portB_mask, 3, 3)), UInt<1>("h1"))
mem_0_0.portA_clk <= portA_clk
mem_0_0.portA_addr <= portA_addr
node portA_dout_0_0 = bits(mem_0_0.portA_dout, 15, 0)
mem_0_0.portA_read_en <= and(portA_read_en, UInt<1>("h1"))
mem_0_1.portA_clk <= portA_clk
mem_0_1.portA_addr <= portA_addr
node portA_dout_0_1 = bits(mem_0_1.portA_dout, 15, 0)
mem_0_1.portA_read_en <= and(portA_read_en, UInt<1>("h1"))
mem_0_2.portA_clk <= portA_clk
mem_0_2.portA_addr <= portA_addr
node portA_dout_0_2 = bits(mem_0_2.portA_dout, 15, 0)
mem_0_2.portA_read_en <= and(portA_read_en, UInt<1>("h1"))
mem_0_3.portA_clk <= portA_clk
mem_0_3.portA_addr <= portA_addr
node portA_dout_0_3 = bits(mem_0_3.portA_dout, 15, 0)
mem_0_3.portA_read_en <= and(portA_read_en, UInt<1>("h1"))
node portA_dout_0 = cat(portA_dout_0_3, cat(portA_dout_0_2, cat(portA_dout_0_1, portA_dout_0_0)))
portA_dout <= mux(UInt<1>("h1"), portA_dout_0, UInt<1>("h0"))
"""
compileExecuteAndTest(mem, lib, v, output)
}
class SplitWidth_2rw_differentMasks extends MacroCompilerSpec with HasSRAMGenerator with HasSimpleWidthTestGenerator {
import mdf.macrolib._
override lazy val depth = 1024
override lazy val memWidth = 64
override lazy val memMaskGran = Some(16)
override lazy val libWidth = 16
lazy val memMaskGranB = 8 // these generators are run at constructor time
override def generateMemSRAM() = {
println(memMaskGranB)
SRAMMacro(
name=mem_name,
width=memWidth,
depth=memDepth,
family="2rw",
ports=Seq(generateTestPort(
"portA", memWidth, memDepth, maskGran=memMaskGran,
write=true, writeEnable=true,
read=true, readEnable=true
), generateTestPort(
"portB", memWidth, memDepth, maskGran=Some(memMaskGranB),
write=true, writeEnable=true,
read=true, readEnable=true
))
)
}
override def generateLibSRAM() = {
SRAMMacro(
name=lib_name,
width=libWidth,
depth=libDepth,
family="2rw",
ports=Seq(generateTestPort(
"portA", libWidth, libDepth,
write=true, writeEnable=true,
read=true, readEnable=true
), generateTestPort(
"portB", libWidth, libDepth,
write=true, writeEnable=true,
read=true, readEnable=true
))
)
}
override def generateHeaderPorts() = {
generateReadWriteHeaderPort("portA", true, Some(memMaskBits)) + "\n" + generateReadWriteHeaderPort("portB", true, Some(memWidth / memMaskGranB))
}
override def generateFooterPorts() = {
generateReadWriteFooterPort("portA", true, None) + "\n" + generateReadWriteFooterPort("portB", true, None)
}
override def generateBody() =
"""
inst mem_0_0 of awesome_lib_mem
inst mem_0_1 of awesome_lib_mem
inst mem_0_2 of awesome_lib_mem
inst mem_0_3 of awesome_lib_mem
inst mem_0_4 of awesome_lib_mem
inst mem_0_5 of awesome_lib_mem
inst mem_0_6 of awesome_lib_mem
inst mem_0_7 of awesome_lib_mem
mem_0_0.portA_clk <= portA_clk
mem_0_0.portA_addr <= portA_addr
node portA_dout_0_0 = bits(mem_0_0.portA_dout, 7, 0)
mem_0_0.portA_din <= bits(portA_din, 7, 0)
mem_0_0.portA_read_en <= and(portA_read_en, UInt<1>("h1"))
mem_0_0.portA_write_en <= and(and(portA_write_en, bits(portA_mask, 0, 0)), UInt<1>("h1"))
mem_0_1.portA_clk <= portA_clk
mem_0_1.portA_addr <= portA_addr
node portA_dout_0_1 = bits(mem_0_1.portA_dout, 7, 0)
mem_0_1.portA_din <= bits(portA_din, 15, 8)
mem_0_1.portA_read_en <= and(portA_read_en, UInt<1>("h1"))
mem_0_1.portA_write_en <= and(and(portA_write_en, bits(portA_mask, 0, 0)), UInt<1>("h1"))
mem_0_2.portA_clk <= portA_clk
mem_0_2.portA_addr <= portA_addr
node portA_dout_0_2 = bits(mem_0_2.portA_dout, 7, 0)
mem_0_2.portA_din <= bits(portA_din, 23, 16)
mem_0_2.portA_read_en <= and(portA_read_en, UInt<1>("h1"))
mem_0_2.portA_write_en <= and(and(portA_write_en, bits(portA_mask, 1, 1)), UInt<1>("h1"))
mem_0_3.portA_clk <= portA_clk
mem_0_3.portA_addr <= portA_addr
node portA_dout_0_3 = bits(mem_0_3.portA_dout, 7, 0)
mem_0_3.portA_din <= bits(portA_din, 31, 24)
mem_0_3.portA_read_en <= and(portA_read_en, UInt<1>("h1"))
mem_0_3.portA_write_en <= and(and(portA_write_en, bits(portA_mask, 1, 1)), UInt<1>("h1"))
mem_0_4.portA_clk <= portA_clk
mem_0_4.portA_addr <= portA_addr
node portA_dout_0_4 = bits(mem_0_4.portA_dout, 7, 0)
mem_0_4.portA_din <= bits(portA_din, 39, 32)
mem_0_4.portA_read_en <= and(portA_read_en, UInt<1>("h1"))
mem_0_4.portA_write_en <= and(and(portA_write_en, bits(portA_mask, 2, 2)), UInt<1>("h1"))
mem_0_5.portA_clk <= portA_clk
mem_0_5.portA_addr <= portA_addr
node portA_dout_0_5 = bits(mem_0_5.portA_dout, 7, 0)
mem_0_5.portA_din <= bits(portA_din, 47, 40)
mem_0_5.portA_read_en <= and(portA_read_en, UInt<1>("h1"))
mem_0_5.portA_write_en <= and(and(portA_write_en, bits(portA_mask, 2, 2)), UInt<1>("h1"))
mem_0_6.portA_clk <= portA_clk
mem_0_6.portA_addr <= portA_addr
node portA_dout_0_6 = bits(mem_0_6.portA_dout, 7, 0)
mem_0_6.portA_din <= bits(portA_din, 55, 48)
mem_0_6.portA_read_en <= and(portA_read_en, UInt<1>("h1"))
mem_0_6.portA_write_en <= and(and(portA_write_en, bits(portA_mask, 3, 3)), UInt<1>("h1"))
mem_0_7.portA_clk <= portA_clk
mem_0_7.portA_addr <= portA_addr
node portA_dout_0_7 = bits(mem_0_7.portA_dout, 7, 0)
mem_0_7.portA_din <= bits(portA_din, 63, 56)
mem_0_7.portA_read_en <= and(portA_read_en, UInt<1>("h1"))
mem_0_7.portA_write_en <= and(and(portA_write_en, bits(portA_mask, 3, 3)), UInt<1>("h1"))
node portA_dout_0 = cat(portA_dout_0_7, cat(portA_dout_0_6, cat(portA_dout_0_5, cat(portA_dout_0_4, cat(portA_dout_0_3, cat(portA_dout_0_2, cat(portA_dout_0_1, portA_dout_0_0)))))))
mem_0_0.portB_clk <= portB_clk
mem_0_0.portB_addr <= portB_addr
node portB_dout_0_0 = bits(mem_0_0.portB_dout, 7, 0)
mem_0_0.portB_din <= bits(portB_din, 7, 0)
mem_0_0.portB_read_en <= and(portB_read_en, UInt<1>("h1"))
mem_0_0.portB_write_en <= and(and(portB_write_en, bits(portB_mask, 0, 0)), UInt<1>("h1"))
mem_0_1.portB_clk <= portB_clk
mem_0_1.portB_addr <= portB_addr
node portB_dout_0_1 = bits(mem_0_1.portB_dout, 7, 0)
mem_0_1.portB_din <= bits(portB_din, 15, 8)
mem_0_1.portB_read_en <= and(portB_read_en, UInt<1>("h1"))
mem_0_1.portB_write_en <= and(and(portB_write_en, bits(portB_mask, 1, 1)), UInt<1>("h1"))
mem_0_2.portB_clk <= portB_clk
mem_0_2.portB_addr <= portB_addr
node portB_dout_0_2 = bits(mem_0_2.portB_dout, 7, 0)
mem_0_2.portB_din <= bits(portB_din, 23, 16)
mem_0_2.portB_read_en <= and(portB_read_en, UInt<1>("h1"))
mem_0_2.portB_write_en <= and(and(portB_write_en, bits(portB_mask, 2, 2)), UInt<1>("h1"))
mem_0_3.portB_clk <= portB_clk
mem_0_3.portB_addr <= portB_addr
node portB_dout_0_3 = bits(mem_0_3.portB_dout, 7, 0)
mem_0_3.portB_din <= bits(portB_din, 31, 24)
mem_0_3.portB_read_en <= and(portB_read_en, UInt<1>("h1"))
mem_0_3.portB_write_en <= and(and(portB_write_en, bits(portB_mask, 3, 3)), UInt<1>("h1"))
mem_0_4.portB_clk <= portB_clk
mem_0_4.portB_addr <= portB_addr
node portB_dout_0_4 = bits(mem_0_4.portB_dout, 7, 0)
mem_0_4.portB_din <= bits(portB_din, 39, 32)
mem_0_4.portB_read_en <= and(portB_read_en, UInt<1>("h1"))
mem_0_4.portB_write_en <= and(and(portB_write_en, bits(portB_mask, 4, 4)), UInt<1>("h1"))
mem_0_5.portB_clk <= portB_clk
mem_0_5.portB_addr <= portB_addr
node portB_dout_0_5 = bits(mem_0_5.portB_dout, 7, 0)
mem_0_5.portB_din <= bits(portB_din, 47, 40)
mem_0_5.portB_read_en <= and(portB_read_en, UInt<1>("h1"))
mem_0_5.portB_write_en <= and(and(portB_write_en, bits(portB_mask, 5, 5)), UInt<1>("h1"))
mem_0_6.portB_clk <= portB_clk
mem_0_6.portB_addr <= portB_addr
node portB_dout_0_6 = bits(mem_0_6.portB_dout, 7, 0)
mem_0_6.portB_din <= bits(portB_din, 55, 48)
mem_0_6.portB_read_en <= and(portB_read_en, UInt<1>("h1"))
mem_0_6.portB_write_en <= and(and(portB_write_en, bits(portB_mask, 6, 6)), UInt<1>("h1"))
mem_0_7.portB_clk <= portB_clk
mem_0_7.portB_addr <= portB_addr
node portB_dout_0_7 = bits(mem_0_7.portB_dout, 7, 0)
mem_0_7.portB_din <= bits(portB_din, 63, 56)
mem_0_7.portB_read_en <= and(portB_read_en, UInt<1>("h1"))
mem_0_7.portB_write_en <= and(and(portB_write_en, bits(portB_mask, 7, 7)), UInt<1>("h1"))
node portB_dout_0 = cat(portB_dout_0_7, cat(portB_dout_0_6, cat(portB_dout_0_5, cat(portB_dout_0_4, cat(portB_dout_0_3, cat(portB_dout_0_2, cat(portB_dout_0_1, portB_dout_0_0)))))))
portA_dout <= mux(UInt<1>("h1"), portA_dout_0, UInt<1>("h0"))
portB_dout <= mux(UInt<1>("h1"), portB_dout_0, UInt<1>("h0"))
"""
compileExecuteAndTest(mem, lib, v, output)
}

File diff suppressed because it is too large Load Diff