Re-implement parallel mapping
- Support byte-masked SRAM, yay - Also nuke a bunch of bugs
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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"""
|
||||
|
||||
@@ -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(_ + _)
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user