diff --git a/src/main/scala/gemmini/Configs.scala b/src/main/scala/gemmini/Configs.scala index 5e6b0336..bdf4b65d 100644 --- a/src/main/scala/gemmini/Configs.scala +++ b/src/main/scala/gemmini/Configs.scala @@ -50,6 +50,7 @@ object GemminiConfigs { ex_queue_length = 8, rob_entries = 16, sp_banks = 4, + sp_singleported = true, acc_banks = 2, sp_capacity = CapacityInKilobytes(256), shifter_banks = 1, // TODO add separate parameters for left and up shifter banks diff --git a/src/main/scala/gemmini/DSEConfigs.scala b/src/main/scala/gemmini/DSEConfigs.scala index 51bdc192..a0d0aa85 100644 --- a/src/main/scala/gemmini/DSEConfigs.scala +++ b/src/main/scala/gemmini/DSEConfigs.scala @@ -24,6 +24,7 @@ object DSEBaseConfig { sp_banks = 4, // TODO support one-bank designs acc_banks = 1, sp_capacity = CapacityInKilobytes(64), + sp_singleported = false, shifter_banks = 1, // TODO add separate parameters for left and up shifter banks dataflow = Dataflow.OS, acc_capacity = CapacityInKilobytes(16), diff --git a/src/main/scala/gemmini/ExecuteController.scala b/src/main/scala/gemmini/ExecuteController.scala index c3601d50..cc8d3b04 100644 --- a/src/main/scala/gemmini/ExecuteController.scala +++ b/src/main/scala/gemmini/ExecuteController.scala @@ -324,7 +324,6 @@ class ExecuteController[T <: Data, U <: Data, V <: Data](xLen: Int, tagWidth: In val a_fire = a_valid && a_ready - dontTouch(a_fire) val b_fire = b_valid && b_ready val d_fire = d_valid && d_ready @@ -371,9 +370,9 @@ class ExecuteController[T <: Data, U <: Data, V <: Data](xLen: Int, tagWidth: In // The last line in this (long) Boolean is just to make sure that we don't think we're done as soon as we begin firing // TODO change when square requirement lifted - val about_to_fire_all_rows = ((a_fire_counter === (block_size-1).U && a_valid) || a_fire_counter === 0.U) && - ((b_fire_counter === (block_size-1).U && b_valid) || b_fire_counter === 0.U) && - ((d_fire_counter === (block_size-1).U && d_valid) || d_fire_counter === 0.U) && + val about_to_fire_all_rows = ((a_fire_counter === (block_size-1).U && a_fire) || a_fire_counter === 0.U) && + ((b_fire_counter === (block_size-1).U && b_fire) || b_fire_counter === 0.U) && + ((d_fire_counter === (block_size-1).U && d_fire) || d_fire_counter === 0.U) && (a_fire_counter =/= 0.U || b_fire_counter =/= 0.U || d_fire_counter =/= 0.U) && cntl_ready diff --git a/src/main/scala/gemmini/GemminiConfigs.scala b/src/main/scala/gemmini/GemminiConfigs.scala index fb9026d4..9a40853e 100644 --- a/src/main/scala/gemmini/GemminiConfigs.scala +++ b/src/main/scala/gemmini/GemminiConfigs.scala @@ -22,6 +22,7 @@ case class GemminiArrayConfig[T <: Data : Arithmetic, U <: Data, V <: Data]( ex_queue_length: Int, rob_entries: Int, sp_banks: Int, // TODO support one-bank designs + sp_singleported: Boolean, sp_capacity: GemminiMemCapacity, acc_banks: Int, acc_capacity: GemminiMemCapacity, diff --git a/src/main/scala/gemmini/Scratchpad.scala b/src/main/scala/gemmini/Scratchpad.scala index 39596cc3..c2695207 100644 --- a/src/main/scala/gemmini/Scratchpad.scala +++ b/src/main/scala/gemmini/Scratchpad.scala @@ -95,7 +95,7 @@ class ScratchpadWriteIO(val n: Int, val w: Int, val mask_len: Int) extends Bundl val data = Output(UInt(w.W)) } -class ScratchpadBank(n: Int, w: Int, mem_pipeline: Int, aligned_to: Int) extends Module { +class ScratchpadBank(n: Int, w: Int, mem_pipeline: Int, aligned_to: Int, single_ported: Boolean) extends Module { // This is essentially a pipelined SRAM with the ability to stall pipeline stages require(w % aligned_to == 0 || w < aligned_to) @@ -107,9 +107,11 @@ class ScratchpadBank(n: Int, w: Int, mem_pipeline: Int, aligned_to: Int) extends val write = Flipped(new ScratchpadWriteIO(n, w, mask_len)) }) - // val mem = SyncReadMem(n, UInt(w.W)) val mem = SyncReadMem(n, Vec(mask_len, mask_elem)) + // When the scratchpad is single-ported, the writes take precedence + val singleport_busy_with_write = single_ported.B && io.write.en + when (io.write.en) { if (aligned_to >= w) mem.write(io.write.addr, io.write.data.asTypeOf(Vec(mask_len, mask_elem))) @@ -119,7 +121,13 @@ class ScratchpadBank(n: Int, w: Int, mem_pipeline: Int, aligned_to: Int) extends val raddr = io.read.req.bits.addr val ren = io.read.req.fire() - val rdata = mem.read(raddr, ren).asUInt() + val rdata = if (single_ported) { + assert(!(ren && io.write.en)) + mem.read(raddr, ren && !io.write.en).asUInt() + } else { + mem.read(raddr, ren).asUInt() + } + val fromDMA = io.read.req.bits.fromDMA // Make a queue which buffers the result of an SRAM read if it can't immediately be consumed @@ -129,7 +137,7 @@ class ScratchpadBank(n: Int, w: Int, mem_pipeline: Int, aligned_to: Int) extends q.io.enq.bits.fromDMA := RegNext(fromDMA) val q_will_be_empty = (q.io.count +& q.io.enq.fire()) - q.io.deq.fire() === 0.U - io.read.req.ready := q_will_be_empty + io.read.req.ready := q_will_be_empty && !singleport_busy_with_write // Build the rest of the resp pipeline val rdata_p = Pipeline(q.io.deq, mem_pipeline) @@ -297,7 +305,7 @@ class Scratchpad[T <: Data, U <: Data, V <: Data](config: GemminiArrayConfig[T, io.busy := writer.module.io.busy || reader.module.io.busy || write_issue_q.io.deq.valid { - val banks = Seq.fill(sp_banks) { Module(new ScratchpadBank(sp_bank_entries, spad_w, mem_pipeline, aligned_to)) } + val banks = Seq.fill(sp_banks) { Module(new ScratchpadBank(sp_bank_entries, spad_w, mem_pipeline, aligned_to, config.sp_singleported)) } val bank_ios = VecInit(banks.map(_.io)) // Getting the output of the bank that's about to be issued to the writer @@ -315,6 +323,7 @@ class Scratchpad[T <: Data, U <: Data, V <: Data](config: GemminiArrayConfig[T, // TODO we tie the write dispatch queue's, and write issue queue's, ready and valid signals together here val dmawrite = write_dispatch_q.valid && write_issue_q.io.enq.ready && + !(bio.write.en && config.sp_singleported.B) && !write_dispatch_q.bits.laddr.is_acc_addr && write_dispatch_q.bits.laddr.sp_bank() === i.U bio.read.req.valid := exread || (dmawrite && !write_dispatch_q.bits.laddr.is_garbage())