From e46e877cdfbb394d57fa4dcab12359fe73efb9cc Mon Sep 17 00:00:00 2001 From: Lingrui98 Date: Tue, 8 Nov 2022 21:25:19 +0800 Subject: [PATCH] utils: bump DataModuleTemplate to newest version and add default value to parentModule parameter --- src/main/scala/utils/DataModuleTemplate.scala | 154 +++++++++++++++--- 1 file changed, 130 insertions(+), 24 deletions(-) diff --git a/src/main/scala/utils/DataModuleTemplate.scala b/src/main/scala/utils/DataModuleTemplate.scala index 3e7861ed2..27be90885 100644 --- a/src/main/scala/utils/DataModuleTemplate.scala +++ b/src/main/scala/utils/DataModuleTemplate.scala @@ -19,7 +19,14 @@ package utils import chisel3._ import chisel3.util._ -class RawDataModuleTemplate[T <: Data](gen: T, numEntries: Int, numRead: Int, numWrite: Int, isSync: Boolean) extends Module { +class RawDataModuleTemplate[T <: Data]( + gen: T, + numEntries: Int, + numRead: Int, + numWrite: Int, + isSync: Boolean, + optWrite: Seq[Int] = Seq() +) extends Module { val io = IO(new Bundle { val rvec = Vec(numRead, Input(UInt(numEntries.W))) val rdata = Vec(numRead, Output(gen)) @@ -30,6 +37,10 @@ class RawDataModuleTemplate[T <: Data](gen: T, numEntries: Int, numRead: Int, nu val data = Reg(Vec(numEntries, gen)) + val wen = io.wen.zipWithIndex.map{ case (en, i) => if (optWrite.contains(i)) RegNext(en) else en } + val wvec = io.wvec.zipWithIndex.map{ case (v, i) => if (optWrite.contains(i)) RegEnable(v, io.wen(i)) else v } + val wdata = io.wdata.zipWithIndex.map{ case (d, i) => if (optWrite.contains(i)) RegEnable(d, io.wen(i)) else d } + // read ports val rvec = if (isSync) RegNext(io.rvec) else io.rvec for (i <- 0 until numRead) { @@ -37,55 +48,150 @@ class RawDataModuleTemplate[T <: Data](gen: T, numEntries: Int, numRead: Int, nu io.rdata(i) := Mux1H(rvec(i), data) } + if (optWrite.nonEmpty) { + val data_next = WireInit(data) + val wbypass = io.wen.zip(io.wvec).zip(wdata).zipWithIndex.filter(x => optWrite.contains(x._2)).map(_._1) + for (i <- 0 until numEntries) { + val wbypass_en = wbypass.map(w => RegNext(w._1._1 && w._1._2(i))) + when (VecInit(wbypass_en).asUInt.orR) { + data_next(i) := Mux1H(wbypass_en, wbypass.map(_._2)) + } + } + for (i <- 0 until numRead) { + io.rdata(i) := Mux1H(rvec(i), data_next) + } + } + // write ports for (i <- 0 until numEntries) { - val w = VecInit((0 until numWrite).map(j => io.wen(j) && io.wvec(j)(i))) + val w = VecInit((0 until numWrite).map(j => wen(j) && wvec(j)(i))) assert(PopCount(w) <= 1.U) when (w.asUInt.orR) { - data(i) := Mux1H(w, io.wdata) + data(i) := Mux1H(w, wdata) } } } -class SyncRawDataModuleTemplate[T <: Data](gen: T, numEntries: Int, numRead: Int, numWrite: Int) extends RawDataModuleTemplate(gen, numEntries, numRead, numWrite, true) -class AsyncRawDataModuleTemplate[T <: Data](gen: T, numEntries: Int, numRead: Int, numWrite: Int) extends RawDataModuleTemplate(gen, numEntries, numRead, numWrite, false) +class SyncRawDataModuleTemplate[T <: Data]( + gen: T, numEntries: Int, numRead: Int, numWrite: Int, optWrite: Seq[Int] = Seq() +) extends RawDataModuleTemplate(gen, numEntries, numRead, numWrite, true, optWrite) +class AsyncRawDataModuleTemplate[T <: Data]( + gen: T, numEntries: Int, numRead: Int, numWrite: Int, optWrite: Seq[Int] = Seq() +) extends RawDataModuleTemplate(gen, numEntries, numRead, numWrite, false, optWrite) + +class SyncDataModuleTemplate[T <: Data]( + gen: T, + numEntries: Int, + numRead: Int, + numWrite: Int, + parentModule: String = "", + concatData: Boolean = false, + perReadPortBypassEnable: Option[Seq[Boolean]] = None +) extends Module { + val io = IO(new Bundle { + val raddr = Vec(numRead, Input(UInt(log2Ceil(numEntries).W))) + val rdata = Vec(numRead, Output(gen)) + val wen = Vec(numWrite, Input(Bool())) + val waddr = Vec(numWrite, Input(UInt(log2Ceil(numEntries).W))) + val wdata = Vec(numWrite, Input(gen)) + }) + + override def desiredName: String = s"SyncDataModuleTemplate_${parentModule}_${numEntries}entry" + val dataType = if (concatData) UInt(gen.getWidth.W) else gen + + val maxBankEntries = if (numEntries >= 2 * 64) 64 else 16 + val numBanks = (numEntries + maxBankEntries - 1) / maxBankEntries + def bankOffset(address: UInt): UInt = { + if (numBanks > 1) address(log2Ceil(maxBankEntries) - 1, 0) + else address + } + def bankIndex(address: UInt): UInt = { + if (numBanks > 1) address(log2Ceil(numEntries) - 1, log2Ceil(maxBankEntries)) + else 0.U + } + + // if use bypassEnable to control bypass of each port, + // then we should have a separate bit for each read port + perReadPortBypassEnable.map(en_vec => require(en_vec.length == numRead)) + + val dataBanks = Seq.tabulate(numBanks)(i => { + val bankEntries = if (i < numBanks - 1) maxBankEntries else numEntries - (i * maxBankEntries) + val dataBank = Module(new NegedgeDataModuleTemplate(dataType, bankEntries, numRead, numWrite, parentModule, perReadPortBypassEnable)) + + // delay one clock + val raddr_dup = RegNext(io.raddr) + val wen_dup = RegNext(io.wen) + val waddr_dup = io.wen.zip(io.waddr).map(w => RegEnable(w._2, w._1)) + + // input + dataBank.io.raddr := raddr_dup.map(bankOffset) + dataBank.io.wen := wen_dup.zip(waddr_dup).map{ case (en, addr) => en && bankIndex(addr) === i.U } + dataBank.io.waddr := waddr_dup.map(bankOffset) + if (concatData) { + val wdata_dup = io.wen.zip(io.wdata).map(w => RegEnable(w._2.asTypeOf(dataType), w._1)) + dataBank.io.wdata := wdata_dup + } + else { + dataBank.io.wdata := io.wen.zip(io.wdata).map(w => RegEnable(w._2, w._1)) + } + + dataBank + }) + + // output + val rdata = if (concatData) dataBanks.map(_.io.rdata.map(_.asTypeOf(gen))) else dataBanks.map(_.io.rdata) + for (j <- 0 until numRead) { + val raddr_dup = RegNext(io.raddr(j)) + val index_dec = UIntToOH(bankIndex(raddr_dup), numBanks) + io.rdata(j) := Mux1H(index_dec, rdata.map(_(j))) + } +} -class DataModuleTemplate[T <: Data](gen: T, numEntries: Int, numRead: Int, numWrite: Int, isSync: Boolean) extends Module { +class NegedgeDataModuleTemplate[T <: Data]( + gen: T, + numEntries: Int, + numRead: Int, + numWrite: Int, + parentModule: String, + perReadPortBypassEnable: Option[Seq[Boolean]] = None +) extends Module { val io = IO(new Bundle { - val raddr = Vec(numRead, Input(UInt(log2Up(numEntries).W))) + val raddr = Vec(numRead, Input(UInt(log2Ceil(numEntries).W))) val rdata = Vec(numRead, Output(gen)) val wen = Vec(numWrite, Input(Bool())) - val waddr = Vec(numWrite, Input(UInt(log2Up(numEntries).W))) + val waddr = Vec(numWrite, Input(UInt(log2Ceil(numEntries).W))) val wdata = Vec(numWrite, Input(gen)) }) - val data = Mem(numEntries, gen) + override def desiredName: String = s"NegedgeDataModule_${parentModule}_${numEntries}entry" + val data = Reg(Vec(numEntries, gen)) + // if use bypassEnable to control bypass of each port, + // then we should have a separate bit for each read port + perReadPortBypassEnable.map(en_vec => require(en_vec.length == numRead)) // read ports - val raddr = if (isSync) (RegNext(io.raddr)) else io.raddr for (i <- 0 until numRead) { - io.rdata(i) := data(raddr(i)) - } - - // below is the write ports (with priorities) - for (i <- 0 until numWrite) { - when (io.wen(i)) { - data(io.waddr(i)) := io.wdata(i) + val bypass_en = perReadPortBypassEnable.map(_(i)).getOrElse(true) + val read_by = io.wen.zip(io.waddr).map(w => w._1 && w._2 === io.raddr(i) && bypass_en.B) + val addr_dec = UIntToOH(io.raddr(i), numEntries) + when (VecInit(read_by).asUInt.orR) { + io.rdata(i) := Mux1H(read_by, io.wdata) + } .otherwise { + io.rdata(i) := Mux1H(addr_dec, data) } } - // DataModuleTemplate should not be used when there're any write conflicts - for (i <- 0 until numWrite) { - for (j <- i+1 until numWrite) { - assert(!(io.wen(i) && io.wen(j) && io.waddr(i) === io.waddr(j))) + // write ports + val waddr_dec = io.waddr.map(a => UIntToOH(a)) + for (j <- 0 until numEntries) { + val write_wen = io.wen.zip(waddr_dec).map(w => w._1 && w._2(j)) + when (VecInit(write_wen).asUInt.orR) { + data(j) := Mux1H(write_wen, io.wdata) } } } -class SyncDataModuleTemplate[T <: Data](gen: T, numEntries: Int, numRead: Int, numWrite: Int) extends DataModuleTemplate(gen, numEntries, numRead, numWrite, true) -class AsyncDataModuleTemplate[T <: Data](gen: T, numEntries: Int, numRead: Int, numWrite: Int) extends DataModuleTemplate(gen, numEntries, numRead, numWrite, false) - class Folded1WDataModuleTemplate[T <: Data](gen: T, numEntries: Int, numRead: Int, isSync: Boolean, width: Int, hasResetEn: Boolean = true) extends Module { val io = IO(new Bundle { -- GitLab