From ba79b8da3435bf8fcdcbcefcebbbe96aaa13ce25 Mon Sep 17 00:00:00 2001 From: Hasan Genc Date: Fri, 28 May 2021 02:47:40 -0700 Subject: [PATCH 01/78] Initial attempt --- src/main/scala/gemmini/LoopMatmul.scala | 8 +++- src/main/scala/gemmini/WeightedArbiter.scala | 39 +++++++++++++++----- 2 files changed, 37 insertions(+), 10 deletions(-) diff --git a/src/main/scala/gemmini/LoopMatmul.scala b/src/main/scala/gemmini/LoopMatmul.scala index af9e3061e..2502d157b 100644 --- a/src/main/scala/gemmini/LoopMatmul.scala +++ b/src/main/scala/gemmini/LoopMatmul.scala @@ -647,13 +647,19 @@ class LoopMatmul(block_size: Int, coreMaxAddrBits: Int, rob_size: Int, max_lds: io.busy := cmd.valid || loop_configured // Create ld arbiters - val ldab_arb = Module(new WeightedArbiter(new RoCCCommand(), maxWeightA=255)) // TODO magic numbers + val ldab_arb = Module(new WeightedArbiter(new RoCCCommand(), maxWeightA=255, staticWeightAEnabled=true)) // TODO magic numbers ldab_arb.io.inA <> ldA.io.cmd ldab_arb.io.inB <> ldB.io.cmd val ab_loads_on_same_loop = ldA.io.loop_id === ldB.io.loop_id ldab_arb.io.forceA := !ab_loads_on_same_loop && ldA.io.loop_id === head_loop_id ldab_arb.io.forceB := !ab_loads_on_same_loop && ldB.io.loop_id === head_loop_id ldab_arb.io.weightA := head_loop.weightA + ldab_arb.io.inA_idle := ldA.io.idle + ldab_arb.io.inB_idle := ldB.io.idle + ldab_arb.io.inA_k := ldA.io.k + ldab_arb.io.inA_i := ldA.io.i + ldab_arb.io.inB_k := ldB.io.k + ldab_arb.io.inB_j := ldB.io.j // Create global arbiter val arb = Module(new Arbiter(new RoCCCommand(), 4)) diff --git a/src/main/scala/gemmini/WeightedArbiter.scala b/src/main/scala/gemmini/WeightedArbiter.scala index 2264aeeaa..175e02e98 100644 --- a/src/main/scala/gemmini/WeightedArbiter.scala +++ b/src/main/scala/gemmini/WeightedArbiter.scala @@ -4,7 +4,7 @@ import chisel3._ import chisel3.util._ import Util._ -class WeightedArbiter[T <: Data](t: T, maxWeightA: Int) extends Module { +class WeightedArbiter[T <: Data](t: T, maxWeightA: Int, staticWeightAEnabled: Boolean) extends Module { val io = IO(new Bundle { val inA = Flipped(Decoupled(t)) val inB = Flipped(Decoupled(t)) @@ -12,6 +12,13 @@ class WeightedArbiter[T <: Data](t: T, maxWeightA: Int) extends Module { val forceA = Input(Bool()) val forceB = Input(Bool()) val out = Decoupled(t) + + val inA_idle = Input(Bool()) + val inB_idle = Input(Bool()) + val inA_k = Input(UInt(16.W)) // TODO magic number + val inB_k = Input(UInt(16.W)) // TODO magic number + val inA_i = Input(UInt(16.W)) // TODO magic number + val inB_j = Input(UInt(16.W)) // TODO magic number }) val count = Reg(UInt(log2Up(maxWeightA+1).W)) @@ -20,6 +27,8 @@ class WeightedArbiter[T <: Data](t: T, maxWeightA: Int) extends Module { val weightA = io.weightA + val staticWeightA = weightA === 0.U && staticWeightAEnabled.B + io.inA.ready := false.B io.inB.ready := false.B @@ -27,18 +36,30 @@ class WeightedArbiter[T <: Data](t: T, maxWeightA: Int) extends Module { io.out <> io.inA }.elsewhen(io.forceB) { io.out <> io.inB - }.elsewhen(io.inA.valid && io.inB.valid) { - when (count < weightA) { + }.elsewhen(!staticWeightA) { + when(io.inA.valid && io.inB.valid) { + when(count < weightA) { + io.out <> io.inA + A_chosen := true.B + }.otherwise { + io.out <> io.inB + B_chosen := true.B + } + }.elsewhen(io.inA.valid) { io.out <> io.inA - A_chosen := true.B }.otherwise { io.out <> io.inB - B_chosen := true.B } - }.elsewhen(io.inA.valid) { - io.out <> io.inA }.otherwise { - io.out <> io.inB + when (io.inA_idle) { + io.out <> io.inB + }.elsewhen(io.inB_idle) { + io.out <> io.inA + }.elsewhen(io.inA_k > io.inB_k || (io.inB_k === 0.U && io.inB_j === 0.U)) { + io.out <> io.inB + }.otherwise { + io.out <> io.inA + } } when (io.out.fire()) { @@ -51,5 +72,5 @@ class WeightedArbiter[T <: Data](t: T, maxWeightA: Int) extends Module { assert(!(io.forceA && io.forceB)) assert(!(A_chosen && B_chosen)) - assert((!io.inA.valid && !io.inB.valid) || weightA > 0.U) + assert((!io.inA.valid && !io.inB.valid) || (weightA > 0.U || staticWeightAEnabled.B)) } From 26cac05172f3622e33bd8a3b6077368a79b0e8d2 Mon Sep 17 00:00:00 2001 From: Hasan Genc Date: Fri, 28 May 2021 04:22:57 -0700 Subject: [PATCH 02/78] Add weightA --- software/gemmini-rocc-tests | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/software/gemmini-rocc-tests b/software/gemmini-rocc-tests index 000d2fd3e..9209126f5 160000 --- a/software/gemmini-rocc-tests +++ b/software/gemmini-rocc-tests @@ -1 +1 @@ -Subproject commit 000d2fd3e472103cb2a2c91e3d0afedc85b3738b +Subproject commit 9209126f53626646b60d14df41efe6a2246822fd From 0ee0ffe305c884aab6b6245992ff3f340fbff4e6 Mon Sep 17 00:00:00 2001 From: Hasan Genc Date: Sat, 29 May 2021 03:48:22 -0700 Subject: [PATCH 03/78] Add OoO options to ROB --- src/main/scala/gemmini/ROB.scala | 37 +++++++++++++++++++++++++++----- 1 file changed, 32 insertions(+), 5 deletions(-) diff --git a/src/main/scala/gemmini/ROB.scala b/src/main/scala/gemmini/ROB.scala index de02780bd..86efab1f1 100644 --- a/src/main/scala/gemmini/ROB.scala +++ b/src/main/scala/gemmini/ROB.scala @@ -24,6 +24,11 @@ class ROBIssue[T <: Data](cmd_t: T, rob_entries: Int) extends Bundle { class ROB[T <: Data : Arithmetic, U <: Data, V <: Data](config: GemminiArrayConfig[T, U, V], cmd_t: RoCCCommand) extends Module { import config._ + // TODO make *_ooo config parameters + val ld_ooo = false + val ex_ooo = true + val st_ooo = true + val block_rows = tileRows * meshRows val block_cols = tileColumns * meshColumns @@ -98,7 +103,7 @@ class ROB[T <: Data : Arithmetic, U <: Data, V <: Data](config: GemminiArrayConf val full_entries = Reg(Vec(rob_full_entries, UDValid(new Entry))) val partial_entries = Reg(Vec(rob_partial_entries, UDValid(new Entry))) - val entries = full_entries ++ partial_entries + val entries = full_entries ++ partial_entries // WARNING: The last_allocated_preload code below assumes that full_entries comes before the partial_entries val empty = !entries.map(_.valid).reduce(_ || _) val full = entries.map(_.valid).reduce(_ && _) @@ -109,7 +114,6 @@ class ROB[T <: Data : Arithmetic, U <: Data, V <: Data](config: GemminiArrayConf val solitary_preload = utilization === 1.U && entries.map(e => e.valid && e.bits.cmd.inst.funct === PRELOAD_CMD).reduce(_ || _) io.busy := !empty && !(solitary_preload && io.solitary_preload) - // Config values set by programmer val a_stride = Reg(UInt(16.W)) // TODO magic numbers val c_stride = Reg(UInt(16.W)) // TODO magic numbers @@ -118,6 +122,10 @@ class ROB[T <: Data : Arithmetic, U <: Data, V <: Data](config: GemminiArrayConf val st_block_stride = block_rows.U val pooling_is_enabled = Reg(Bool()) + // Registers to help keep OOO execute working properly + val last_allocated_preload = Reg(UInt(log2Up(rob_entries).W)) + val last_ex_issued_was_preload = RegInit(false.B) + val new_entry = Wire(new Entry) new_entry := DontCare val new_full_allocs = Wire(Vec(rob_full_entries, Bool())) @@ -303,8 +311,16 @@ class ROB[T <: Data : Arithmetic, U <: Data, V <: Data](config: GemminiArrayConf }) val waws = dst_waws_opa - val older_in_same_q = VecInit(entries.map { e => - e.valid && e.bits.q === new_entry.q && !e.bits.issued + val older_in_same_q = VecInit(entries.zipWithIndex.map { case (e, i) => + + val ooo_q = (ld_ooo.B && new_entry.q === ldq) || (ex_ooo.B && new_entry.q === exq) || (st_ooo.B && new_entry.q === stq) + + val is_last_preload = i.U === last_allocated_preload + val new_entry_is_compute = new_entry.cmd.inst.funct === COMPUTE_AND_STAY_CMD || + new_entry.cmd.inst.funct === COMPUTE_AND_FLIP_CMD + + e.valid && e.bits.q === new_entry.q && !e.bits.issued && + (!ooo_q || e.bits.is_config || new_entry.is_config || (is_last_preload && new_entry_is_compute)) }) val is_st_and_must_wait_for_prior_ex_config = VecInit(entries.map { e => @@ -362,13 +378,20 @@ class ROB[T <: Data : Arithmetic, U <: Data, V <: Data](config: GemminiArrayConf }.elsewhen(new_entry.is_config && new_entry.q === stq) { val pool_stride = new_entry.cmd.rs1(5, 4) // TODO magic numbers pooling_is_enabled := pool_stride =/= 0.U + }.elsewhen(new_entry.cmd.inst.funct === PRELOAD_CMD) { + last_allocated_preload := full_alloc_id } } } // Issue commands which are ready to be issued Seq((ldq, io.issue.ld), (stq, io.issue.st), (exq, io.issue.ex)).foreach { case (q, io) => - val issue_valids = entries.map(e => e.valid && e.bits.ready() && !e.bits.issued && e.bits.q === q) + val must_be_compute = q === exq && last_ex_issued_was_preload && ex_ooo.B + + val issue_valids = entries.map { e => + val is_compute = e.bits.cmd.inst.funct === COMPUTE_AND_FLIP_CMD || e.bits.cmd.inst.funct === COMPUTE_AND_STAY_CMD + e.valid && e.bits.ready() && !e.bits.issued && e.bits.q === q && (!must_be_compute || is_compute) + } val issue_sel = PriorityEncoderOH(issue_valids) val issue_id = OHToUInt(issue_sel) val issue_entry = Mux1H(issue_sel, entries) @@ -397,6 +420,10 @@ class ROB[T <: Data : Arithmetic, U <: Data, V <: Data](config: GemminiArrayConf } } + when (io.issue.ex.fire()) { + last_ex_issued_was_preload := io.issue.ex.cmd.inst.funct === PRELOAD_CMD + } + // Mark entries as completed once they've returned when (io.completed.fire()) { entries.foreach(_.bits.deps(io.completed.bits) := false.B) From 7d4f0c8560b2a454e5443615de4817e55f5b6789 Mon Sep 17 00:00:00 2001 From: Hasan Genc Date: Thu, 3 Jun 2021 01:32:00 -0700 Subject: [PATCH 04/78] Add new preload filter and turn off ooo config options --- src/main/scala/gemmini/Configs.scala | 6 + src/main/scala/gemmini/ConfigsFP.scala | 6 + src/main/scala/gemmini/Controller.scala | 24 ++-- src/main/scala/gemmini/DSEConfigs.scala | 6 + src/main/scala/gemmini/GemminiConfigs.scala | 6 + src/main/scala/gemmini/LocalAddr.scala | 4 + src/main/scala/gemmini/MeshWithDelays.scala | 5 + src/main/scala/gemmini/PreloadFilter.scala | 147 ++++++++++++++++++++ src/main/scala/gemmini/ROB.scala | 5 - 9 files changed, 192 insertions(+), 17 deletions(-) create mode 100644 src/main/scala/gemmini/PreloadFilter.scala diff --git a/src/main/scala/gemmini/Configs.scala b/src/main/scala/gemmini/Configs.scala index cd2586503..7e7f4fd6f 100644 --- a/src/main/scala/gemmini/Configs.scala +++ b/src/main/scala/gemmini/Configs.scala @@ -146,6 +146,12 @@ object GemminiConfigs { hardcode_d_to_garbage_addr = false, mesh_output_delay = 1, + + ld_ooo = false, + ex_ooo = false, + st_ooo = false, + + use_preload_filter = true, ) val chipConfig = defaultConfig.copy(sp_capacity=CapacityInKilobytes(64), acc_capacity=CapacityInKilobytes(32), dataflow=Dataflow.WS, diff --git a/src/main/scala/gemmini/ConfigsFP.scala b/src/main/scala/gemmini/ConfigsFP.scala index 2762c93dc..41954b8bd 100644 --- a/src/main/scala/gemmini/ConfigsFP.scala +++ b/src/main/scala/gemmini/ConfigsFP.scala @@ -72,6 +72,12 @@ object GemminiFPConfigs { hardcode_d_to_garbage_addr = false, mesh_output_delay = 0, + + ld_ooo = false, + ex_ooo = false, + st_ooo = false, + + use_preload_filter = true, ) //FP32 Single Precision Configuration diff --git a/src/main/scala/gemmini/Controller.scala b/src/main/scala/gemmini/Controller.scala index cc28697d7..e732cf844 100644 --- a/src/main/scala/gemmini/Controller.scala +++ b/src/main/scala/gemmini/Controller.scala @@ -170,13 +170,11 @@ class GemminiModule[T <: Data: Arithmetic, U <: Data, V <: Data] tiler.io.issue.load.ready := false.B tiler.io.issue.store.ready := false.B tiler.io.issue.exec.ready := false.B - */ rob.io.issue.ld.ready := false.B rob.io.issue.st.ready := false.B rob.io.issue.ex.ready := false.B - /* when (is_cisc_mode) { load_controller.io.cmd <> tiler.io.issue.load store_controller.io.cmd <> tiler.io.issue.store @@ -203,11 +201,13 @@ class GemminiModule[T <: Data: Arithmetic, U <: Data, V <: Data] } */ - load_controller.io.cmd.valid := rob.io.issue.ld.valid - rob.io.issue.ld.ready := load_controller.io.cmd.ready - load_controller.io.cmd.bits.cmd := rob.io.issue.ld.cmd - load_controller.io.cmd.bits.cmd.inst.funct := rob.io.issue.ld.cmd.inst.funct - load_controller.io.cmd.bits.rob_id.push(rob.io.issue.ld.rob_id) + val (rob_issue_ld, rob_issue_ex) = PreloadFilter(outer.config, new RoCCCommand, rob.io.issue.ld, rob.io.issue.ex) + + load_controller.io.cmd.valid := rob_issue_ld.valid + rob_issue_ld.ready := load_controller.io.cmd.ready + load_controller.io.cmd.bits.cmd := rob_issue_ld.cmd + load_controller.io.cmd.bits.cmd.inst.funct := rob_issue_ld.cmd.inst.funct + load_controller.io.cmd.bits.rob_id.push(rob_issue_ld.rob_id) store_controller.io.cmd.valid := rob.io.issue.st.valid rob.io.issue.st.ready := store_controller.io.cmd.ready @@ -215,11 +215,11 @@ class GemminiModule[T <: Data: Arithmetic, U <: Data, V <: Data] store_controller.io.cmd.bits.cmd.inst.funct := rob.io.issue.st.cmd.inst.funct store_controller.io.cmd.bits.rob_id.push(rob.io.issue.st.rob_id) - ex_controller.io.cmd.valid := rob.io.issue.ex.valid - rob.io.issue.ex.ready := ex_controller.io.cmd.ready - ex_controller.io.cmd.bits.cmd := rob.io.issue.ex.cmd - ex_controller.io.cmd.bits.cmd.inst.funct := rob.io.issue.ex.cmd.inst.funct - ex_controller.io.cmd.bits.rob_id.push(rob.io.issue.ex.rob_id) + ex_controller.io.cmd.valid := rob_issue_ex.valid + rob_issue_ex.ready := ex_controller.io.cmd.ready + ex_controller.io.cmd.bits.cmd := rob_issue_ex.cmd + ex_controller.io.cmd.bits.cmd.inst.funct := rob_issue_ex.cmd.inst.funct + ex_controller.io.cmd.bits.rob_id.push(rob_issue_ex.rob_id) // Wire up scratchpad to controllers spad.module.io.dma.read <> load_controller.io.dma diff --git a/src/main/scala/gemmini/DSEConfigs.scala b/src/main/scala/gemmini/DSEConfigs.scala index b71477bb9..e2897c90c 100644 --- a/src/main/scala/gemmini/DSEConfigs.scala +++ b/src/main/scala/gemmini/DSEConfigs.scala @@ -74,6 +74,12 @@ object DSEBaseConfig { max_in_flight_reqs = 16, mesh_output_delay = 1, + + ld_ooo = false, + ex_ooo = false, + st_ooo = false, + + use_preload_filter = true, ) } diff --git a/src/main/scala/gemmini/GemminiConfigs.scala b/src/main/scala/gemmini/GemminiConfigs.scala index 8d6db34f2..a467bbcea 100644 --- a/src/main/scala/gemmini/GemminiConfigs.scala +++ b/src/main/scala/gemmini/GemminiConfigs.scala @@ -66,6 +66,12 @@ case class GemminiArrayConfig[T <: Data : Arithmetic, U <: Data, V <: Data]( mesh_output_delay: Int, + ld_ooo: Boolean, + ex_ooo: Boolean, + st_ooo: Boolean, + + use_preload_filter: Boolean, + headerFileName: String = "gemmini_params.h" ) { val sp_width = meshColumns * tileColumns * inputType.getWidth diff --git a/src/main/scala/gemmini/LocalAddr.scala b/src/main/scala/gemmini/LocalAddr.scala index b003fd7b4..668a30898 100644 --- a/src/main/scala/gemmini/LocalAddr.scala +++ b/src/main/scala/gemmini/LocalAddr.scala @@ -57,6 +57,10 @@ class LocalAddr(sp_banks: Int, sp_bank_entries: Int, acc_banks: Int, acc_bank_en is_acc_addr === other.is_acc_addr && Mux(is_acc_addr, full_acc_addr() > other.full_acc_addr(), full_sp_addr() > other.full_sp_addr()) + def ===(other: LocalAddr) = + is_acc_addr === other.is_acc_addr && + Mux(is_acc_addr, full_acc_addr() > other.full_acc_addr(), full_sp_addr() > other.full_sp_addr()) + def add_with_overflow(other: UInt): Tuple2[LocalAddr, Bool] = { require(isPow2(sp_bank_entries)) // TODO remove this requirement require(isPow2(acc_bank_entries)) // TODO remove this requirement diff --git a/src/main/scala/gemmini/MeshWithDelays.scala b/src/main/scala/gemmini/MeshWithDelays.scala index acab135d6..1b071a28f 100644 --- a/src/main/scala/gemmini/MeshWithDelays.scala +++ b/src/main/scala/gemmini/MeshWithDelays.scala @@ -113,10 +113,15 @@ class MeshWithDelays[T <: Data: Arithmetic, U <: TagQueueTag with Data] val last_fire = fire_counter === total_fires - 1.U && input_next_row_into_spatial_array + val preloads = RegInit(0.U(32.W)) + dontTouch(preloads) + when (io.req.fire()) { req.push(io.req.bits) in_prop := io.req.bits.pe_control.propagate ^ in_prop matmul_id := wrappingAdd(matmul_id, 1.U, max_simultaneous_matmuls) + + preloads := preloads + io.req.bits.pe_control.propagate }.elsewhen (last_fire) { req.valid := req.bits.flush > 1.U req.bits.flush := req.bits.flush - 1.U diff --git a/src/main/scala/gemmini/PreloadFilter.scala b/src/main/scala/gemmini/PreloadFilter.scala new file mode 100644 index 000000000..c4ae812df --- /dev/null +++ b/src/main/scala/gemmini/PreloadFilter.scala @@ -0,0 +1,147 @@ +package gemmini + +import chisel3._ +import chisel3.util._ +import freechips.rocketchip.tile.RoCCCommand +import GemminiISA._ +import Util._ + +class PreloadFilter[T <: Data : Arithmetic, U <: Data, V <: Data](config: GemminiArrayConfig[T, U, V], cmd_t: RoCCCommand) extends Module { + import config._ + + val io = IO(new Bundle { + val in_ld = Flipped(new ROBIssue(cmd_t, rob_entries)) + val in_ex = Flipped(new ROBIssue(cmd_t, rob_entries)) + + val out_ld = new ROBIssue(cmd_t, rob_entries) + val out_ex = new ROBIssue(cmd_t, rob_entries) + }) + + val block_cols = meshColumns * tileColumns + val block_rows = meshRows * tileRows + val block_size = block_rows max block_cols + + class AddressRangeT extends Bundle { + // TODO maybe this should be merged with OpT in ROB.scala? + val start = local_addr_t.cloneType + val end = local_addr_t.cloneType + val wraps_around = Bool() + + def overlaps(other: AddressRangeT): Bool = { + ((other.start <= start && (start < other.end || other.wraps_around)) || + (start <= other.start && (other.start < end || wraps_around))) && + !(start.is_garbage() || other.start.is_garbage()) // TODO the "is_garbage" check might not really be necessary + } + + def ===(other: AddressRangeT): Bool = { + start === other.start && end === other.end && wraps_around === other.wraps_around + } + + def make_this_garbage(dummy: Int=0): Unit = { + start.make_this_garbage() + } + } + + val df = if (dataflow == Dataflow.BOTH) Reg(UInt(1.W)) else dataflow.id.U + val b_transposed = Reg(Bool()) + val preloaded_address = Reg(new AddressRangeT) + val ld_block_strides = Reg(Vec(load_states, UInt(block_stride_bits.W))) + + val ex_set_only_strides = io.in_ex.cmd.rs1(7) // TODO magic numbers + val ex_is_config = io.in_ex.cmd.inst.funct === CONFIG_CMD && io.in_ex.cmd.rs1(1,0).asUInt() === CONFIG_EX && !ex_set_only_strides // TODO magic numbers + val ex_config_dataflow = io.in_ex.cmd.rs1(2) // TODO magic numbers + val ex_config_b_transposed = io.in_ex.cmd.rs1(9) // TODO magic numbers + val ex_is_preload = io.in_ex.cmd.inst.funct === PRELOAD_CMD + val ex_preload_rows = { + val default_rows = io.in_ex.cmd.rs1(48 + log2Up(block_size) - 1, 48).asUInt() // TODO magic numbers + val default_cols = io.in_ex.cmd.rs1(32 + log2Up(block_size) - 1, 32).asUInt() // TODO magic numbers + Mux(b_transposed, default_rows, default_cols) + } + val ex_preload_addr = { + val start = io.in_ex.cmd.rs1(31, 0).asTypeOf(local_addr_t) // TODO magic numbers + val (end, wraps_around) = start.add_with_overflow(ex_preload_rows) + + val addr = Wire(new AddressRangeT) + addr.start := start + addr.end := end + addr.wraps_around := wraps_around + + if (!ex_read_from_acc) { + start.is_acc_addr := false.B + end.is_acc_addr := false.B + } + + addr + } + + val ld_is_config = io.in_ld.cmd.inst.funct === CONFIG_CMD + val ld_id = MuxCase(0.U, Seq((io.in_ld.cmd.inst.funct === LOAD2_CMD) -> 1.U, + (io.in_ld.cmd.inst.funct === LOAD3_CMD) -> 2.U)) + val ld_config_block_stride = io.in_ld.cmd.rs1(31, 16).asUInt() // TODO magic numbers + val ld_total_rows = { + val block_stride = ld_block_strides(ld_id) + val ld_cols = io.in_ld.cmd.rs2(32 + mvin_cols_bits - 1, 32).asUInt() // TODO magic numbers + val ld_rows = io.in_ld.cmd.rs2(48 + mvin_rows_bits - 1, 48).asUInt() // TODO magic numbers + val ld_mats = ld_cols / block_cols.U + (ld_cols % block_cols.U =/= 0.U) + ((ld_mats - 1.U) * block_stride) + ld_rows + } + val ld_addr = { + val start = io.in_ld.cmd.rs2(31, 0).asTypeOf(local_addr_t) // TODO magic numbers + val (end, wraps_around) = start.add_with_overflow(ld_total_rows) + + val addr = Wire(new AddressRangeT) + addr.start := start + addr.end := end + addr.wraps_around := wraps_around + + addr + } + + // Set all state registers + when (io.in_ld.valid) { + when (ld_is_config) { + ld_block_strides(ld_id) := ld_config_block_stride + }.elsewhen(preloaded_address.overlaps(ld_addr)) { + preloaded_address.make_this_garbage() + } + } + + when (io.in_ex.valid) { + when (ex_is_config) { + if (dataflow == Dataflow.BOTH) { + df := ex_config_dataflow + } + b_transposed := ex_config_b_transposed + }.elsewhen(ex_is_preload) { + preloaded_address := ex_preload_addr + } + } + + // Set outputs + io.out_ld <> io.in_ld + io.out_ex <> io.in_ex + + when (ex_is_preload && preloaded_address === ex_preload_addr) { + io.out_ex.cmd.rs1 := (block_rows.U << 48) | (block_cols.U << 32) | GARBAGE_ADDR // TODO magic numbers + } + + when (reset.toBool()) { + preloaded_address.make_this_garbage() + } + + assert(!ex_preload_addr.overlaps(ld_addr)) +} + +object PreloadFilter{ + def apply[T <: Data : Arithmetic, U <: Data, V <: Data](config: GemminiArrayConfig[T, U, V], cmd_t: RoCCCommand, ld_issue: ROBIssue[RoCCCommand], ex_issue: ROBIssue[RoCCCommand]) = { + if (config.use_preload_filter) { + val preload_filter = Module(new PreloadFilter(config, cmd_t)) + preload_filter.io.in_ld <> ld_issue + preload_filter.io.in_ex <> ex_issue + (preload_filter.io.out_ld, preload_filter.io.out_ex) + } else { + (ld_issue, ex_issue) + } + } +} + diff --git a/src/main/scala/gemmini/ROB.scala b/src/main/scala/gemmini/ROB.scala index 86efab1f1..2272d2be3 100644 --- a/src/main/scala/gemmini/ROB.scala +++ b/src/main/scala/gemmini/ROB.scala @@ -24,11 +24,6 @@ class ROBIssue[T <: Data](cmd_t: T, rob_entries: Int) extends Bundle { class ROB[T <: Data : Arithmetic, U <: Data, V <: Data](config: GemminiArrayConfig[T, U, V], cmd_t: RoCCCommand) extends Module { import config._ - // TODO make *_ooo config parameters - val ld_ooo = false - val ex_ooo = true - val st_ooo = true - val block_rows = tileRows * meshRows val block_cols = tileColumns * meshColumns From 83ee60226c971559cbe986e52e5467de92ac7f90 Mon Sep 17 00:00:00 2001 From: Hasan Genc Date: Thu, 3 Jun 2021 01:40:39 -0700 Subject: [PATCH 05/78] Fix assert --- src/main/scala/gemmini/PreloadFilter.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/scala/gemmini/PreloadFilter.scala b/src/main/scala/gemmini/PreloadFilter.scala index c4ae812df..b29f23360 100644 --- a/src/main/scala/gemmini/PreloadFilter.scala +++ b/src/main/scala/gemmini/PreloadFilter.scala @@ -129,7 +129,7 @@ class PreloadFilter[T <: Data : Arithmetic, U <: Data, V <: Data](config: Gemmin preloaded_address.make_this_garbage() } - assert(!ex_preload_addr.overlaps(ld_addr)) + assert(!(io.in_ex.valid && io.in_ld.valid && ex_preload_addr.overlaps(ld_addr))) } object PreloadFilter{ From ba4197b1d802aa3f22d059a3c910b8fa920f55fa Mon Sep 17 00:00:00 2001 From: Hasan Genc Date: Thu, 3 Jun 2021 02:02:41 -0700 Subject: [PATCH 06/78] Add WS check to preload filter --- src/main/scala/gemmini/PreloadFilter.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/scala/gemmini/PreloadFilter.scala b/src/main/scala/gemmini/PreloadFilter.scala index b29f23360..57316900a 100644 --- a/src/main/scala/gemmini/PreloadFilter.scala +++ b/src/main/scala/gemmini/PreloadFilter.scala @@ -121,7 +121,7 @@ class PreloadFilter[T <: Data : Arithmetic, U <: Data, V <: Data](config: Gemmin io.out_ld <> io.in_ld io.out_ex <> io.in_ex - when (ex_is_preload && preloaded_address === ex_preload_addr) { + when (ex_is_preload && df === Dataflow.WS.id.U && preloaded_address === ex_preload_addr) { io.out_ex.cmd.rs1 := (block_rows.U << 48) | (block_cols.U << 32) | GARBAGE_ADDR // TODO magic numbers } From 86860be5ff34acda3b38ebd0b444e19a8b0b413a Mon Sep 17 00:00:00 2001 From: Hasan Genc Date: Thu, 3 Jun 2021 02:03:32 -0700 Subject: [PATCH 07/78] Experiment with making stores OoO --- src/main/scala/gemmini/Configs.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/scala/gemmini/Configs.scala b/src/main/scala/gemmini/Configs.scala index 7e7f4fd6f..574c7d000 100644 --- a/src/main/scala/gemmini/Configs.scala +++ b/src/main/scala/gemmini/Configs.scala @@ -149,7 +149,7 @@ object GemminiConfigs { ld_ooo = false, ex_ooo = false, - st_ooo = false, + st_ooo = true, use_preload_filter = true, ) From 3121bb8bbfe509fac1b8d916cd252b68bfc4fbcb Mon Sep 17 00:00:00 2001 From: Hasan Genc Date: Thu, 3 Jun 2021 03:16:19 -0700 Subject: [PATCH 08/78] Fix assert --- src/main/scala/gemmini/PreloadFilter.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/scala/gemmini/PreloadFilter.scala b/src/main/scala/gemmini/PreloadFilter.scala index 57316900a..b4f4dd42a 100644 --- a/src/main/scala/gemmini/PreloadFilter.scala +++ b/src/main/scala/gemmini/PreloadFilter.scala @@ -129,7 +129,7 @@ class PreloadFilter[T <: Data : Arithmetic, U <: Data, V <: Data](config: Gemmin preloaded_address.make_this_garbage() } - assert(!(io.in_ex.valid && io.in_ld.valid && ex_preload_addr.overlaps(ld_addr))) + assert(!(io.in_ex.valid && io.in_ld.valid && !ld_is_config && ex_is_preload && ex_preload_addr.overlaps(ld_addr))) } object PreloadFilter{ From 6d2ded97381ef125be90a96fed6e9778713c6a9c Mon Sep 17 00:00:00 2001 From: Hasan Genc Date: Thu, 3 Jun 2021 04:45:59 -0700 Subject: [PATCH 09/78] Don't overwrite the preloaded address with garbage addresses --- src/main/scala/gemmini/PreloadFilter.scala | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/main/scala/gemmini/PreloadFilter.scala b/src/main/scala/gemmini/PreloadFilter.scala index b4f4dd42a..ce4323d04 100644 --- a/src/main/scala/gemmini/PreloadFilter.scala +++ b/src/main/scala/gemmini/PreloadFilter.scala @@ -40,6 +40,8 @@ class PreloadFilter[T <: Data : Arithmetic, U <: Data, V <: Data](config: Gemmin def make_this_garbage(dummy: Int=0): Unit = { start.make_this_garbage() } + + def is_garbage(dummy: Int=0): Bool = start.is_garbage() } val df = if (dataflow == Dataflow.BOTH) Reg(UInt(1.W)) else dataflow.id.U @@ -112,7 +114,7 @@ class PreloadFilter[T <: Data : Arithmetic, U <: Data, V <: Data](config: Gemmin df := ex_config_dataflow } b_transposed := ex_config_b_transposed - }.elsewhen(ex_is_preload) { + }.elsewhen(ex_is_preload && !ex_preload_addr.is_garbage()) { preloaded_address := ex_preload_addr } } From 64bd464fb8c09e6fab02c4971b11efe7863a6388 Mon Sep 17 00:00:00 2001 From: Hasan Genc Date: Thu, 3 Jun 2021 15:57:36 -0700 Subject: [PATCH 10/78] add new state to preload filter and turn of st ooo --- src/main/scala/gemmini/Configs.scala | 2 +- src/main/scala/gemmini/PreloadFilter.scala | 15 ++++++++++++++- 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/src/main/scala/gemmini/Configs.scala b/src/main/scala/gemmini/Configs.scala index 574c7d000..7e7f4fd6f 100644 --- a/src/main/scala/gemmini/Configs.scala +++ b/src/main/scala/gemmini/Configs.scala @@ -149,7 +149,7 @@ object GemminiConfigs { ld_ooo = false, ex_ooo = false, - st_ooo = true, + st_ooo = false, use_preload_filter = true, ) diff --git a/src/main/scala/gemmini/PreloadFilter.scala b/src/main/scala/gemmini/PreloadFilter.scala index ce4323d04..81bb4f41f 100644 --- a/src/main/scala/gemmini/PreloadFilter.scala +++ b/src/main/scala/gemmini/PreloadFilter.scala @@ -48,12 +48,14 @@ class PreloadFilter[T <: Data : Arithmetic, U <: Data, V <: Data](config: Gemmin val b_transposed = Reg(Bool()) val preloaded_address = Reg(new AddressRangeT) val ld_block_strides = Reg(Vec(load_states, UInt(block_stride_bits.W))) + val last_preload_was_filtered = RegInit(false.B) val ex_set_only_strides = io.in_ex.cmd.rs1(7) // TODO magic numbers val ex_is_config = io.in_ex.cmd.inst.funct === CONFIG_CMD && io.in_ex.cmd.rs1(1,0).asUInt() === CONFIG_EX && !ex_set_only_strides // TODO magic numbers val ex_config_dataflow = io.in_ex.cmd.rs1(2) // TODO magic numbers val ex_config_b_transposed = io.in_ex.cmd.rs1(9) // TODO magic numbers val ex_is_preload = io.in_ex.cmd.inst.funct === PRELOAD_CMD + val ex_is_compute = io.in_ex.cmd.inst.funct === COMPUTE_AND_STAY_CMD || io.in_ex.cmd.inst.funct === COMPUTE_AND_FLIP_CMD val ex_preload_rows = { val default_rows = io.in_ex.cmd.rs1(48 + log2Up(block_size) - 1, 48).asUInt() // TODO magic numbers val default_cols = io.in_ex.cmd.rs1(32 + log2Up(block_size) - 1, 32).asUInt() // TODO magic numbers @@ -75,6 +77,7 @@ class PreloadFilter[T <: Data : Arithmetic, U <: Data, V <: Data](config: Gemmin addr } + val should_filter_preload = ex_is_preload && df === Dataflow.WS.id.U && preloaded_address === ex_preload_addr val ld_is_config = io.in_ld.cmd.inst.funct === CONFIG_CMD val ld_id = MuxCase(0.U, Seq((io.in_ld.cmd.inst.funct === LOAD2_CMD) -> 1.U, @@ -119,12 +122,22 @@ class PreloadFilter[T <: Data : Arithmetic, U <: Data, V <: Data](config: Gemmin } } + when (io.in_ex.fire()) { + when (should_filter_preload) { + last_preload_was_filtered := true.B + }.elsewhen(ex_is_compute) { + last_preload_was_filtered := false.B + } + } + // Set outputs io.out_ld <> io.in_ld io.out_ex <> io.in_ex - when (ex_is_preload && df === Dataflow.WS.id.U && preloaded_address === ex_preload_addr) { + when (should_filter_preload) { io.out_ex.cmd.rs1 := (block_rows.U << 48) | (block_cols.U << 32) | GARBAGE_ADDR // TODO magic numbers + }.elsewhen(ex_is_compute && last_preload_was_filtered) { + io.out_ex.cmd.inst.funct := COMPUTE_AND_STAY_CMD } when (reset.toBool()) { From 6bc6c41cab34dd74ae5177d013edea0c1cca11c4 Mon Sep 17 00:00:00 2001 From: Hasan Genc Date: Thu, 3 Jun 2021 16:51:04 -0700 Subject: [PATCH 11/78] Fix equality check --- src/main/scala/gemmini/LocalAddr.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/scala/gemmini/LocalAddr.scala b/src/main/scala/gemmini/LocalAddr.scala index 668a30898..8651a191a 100644 --- a/src/main/scala/gemmini/LocalAddr.scala +++ b/src/main/scala/gemmini/LocalAddr.scala @@ -59,7 +59,7 @@ class LocalAddr(sp_banks: Int, sp_bank_entries: Int, acc_banks: Int, acc_bank_en def ===(other: LocalAddr) = is_acc_addr === other.is_acc_addr && - Mux(is_acc_addr, full_acc_addr() > other.full_acc_addr(), full_sp_addr() > other.full_sp_addr()) + Mux(is_acc_addr, full_acc_addr() === other.full_acc_addr(), full_sp_addr() === other.full_sp_addr()) def add_with_overflow(other: UInt): Tuple2[LocalAddr, Bool] = { require(isPow2(sp_bank_entries)) // TODO remove this requirement From 7d3066f97669608294c2e504600f053486db75f6 Mon Sep 17 00:00:00 2001 From: Hasan Genc Date: Thu, 3 Jun 2021 19:33:56 -0700 Subject: [PATCH 12/78] Fix b transpose error and io fire error --- src/main/scala/gemmini/PreloadFilter.scala | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/main/scala/gemmini/PreloadFilter.scala b/src/main/scala/gemmini/PreloadFilter.scala index 81bb4f41f..6bb695afc 100644 --- a/src/main/scala/gemmini/PreloadFilter.scala +++ b/src/main/scala/gemmini/PreloadFilter.scala @@ -59,7 +59,7 @@ class PreloadFilter[T <: Data : Arithmetic, U <: Data, V <: Data](config: Gemmin val ex_preload_rows = { val default_rows = io.in_ex.cmd.rs1(48 + log2Up(block_size) - 1, 48).asUInt() // TODO magic numbers val default_cols = io.in_ex.cmd.rs1(32 + log2Up(block_size) - 1, 32).asUInt() // TODO magic numbers - Mux(b_transposed, default_rows, default_cols) + Mux(b_transposed, default_cols, default_rows) } val ex_preload_addr = { val start = io.in_ex.cmd.rs1(31, 0).asTypeOf(local_addr_t) // TODO magic numbers @@ -103,7 +103,7 @@ class PreloadFilter[T <: Data : Arithmetic, U <: Data, V <: Data](config: Gemmin } // Set all state registers - when (io.in_ld.valid) { + when (io.in_ld.fire()) { when (ld_is_config) { ld_block_strides(ld_id) := ld_config_block_stride }.elsewhen(preloaded_address.overlaps(ld_addr)) { @@ -111,18 +111,20 @@ class PreloadFilter[T <: Data : Arithmetic, U <: Data, V <: Data](config: Gemmin } } - when (io.in_ex.valid) { + when (io.in_ex.fire()) { when (ex_is_config) { if (dataflow == Dataflow.BOTH) { df := ex_config_dataflow } b_transposed := ex_config_b_transposed + + when (b_transposed =/= ex_config_b_transposed) { + preloaded_address.make_this_garbage() + } }.elsewhen(ex_is_preload && !ex_preload_addr.is_garbage()) { preloaded_address := ex_preload_addr } - } - when (io.in_ex.fire()) { when (should_filter_preload) { last_preload_was_filtered := true.B }.elsewhen(ex_is_compute) { From 0df4b11eb123eea32f35dd9f97f3d7e504e64139 Mon Sep 17 00:00:00 2001 From: Hasan Genc Date: Fri, 4 Jun 2021 16:26:06 -0700 Subject: [PATCH 13/78] Add OoO ROB work correctly even when we preload garbage addresses --- src/main/scala/gemmini/PreloadFilter.scala | 2 +- src/main/scala/gemmini/ROB.scala | 44 +++++++++++++++++++--- 2 files changed, 39 insertions(+), 7 deletions(-) diff --git a/src/main/scala/gemmini/PreloadFilter.scala b/src/main/scala/gemmini/PreloadFilter.scala index 6bb695afc..db247da7a 100644 --- a/src/main/scala/gemmini/PreloadFilter.scala +++ b/src/main/scala/gemmini/PreloadFilter.scala @@ -44,7 +44,7 @@ class PreloadFilter[T <: Data : Arithmetic, U <: Data, V <: Data](config: Gemmin def is_garbage(dummy: Int=0): Bool = start.is_garbage() } - val df = if (dataflow == Dataflow.BOTH) Reg(UInt(1.W)) else dataflow.id.U + val df = if (dataflow == Dataflow.BOTH) Reg(UInt(1.W)) else dataflow.id.U // TODO magic numbers val b_transposed = Reg(Bool()) val preloaded_address = Reg(new AddressRangeT) val ld_block_strides = Reg(Vec(load_states, UInt(block_stride_bits.W))) diff --git a/src/main/scala/gemmini/ROB.scala b/src/main/scala/gemmini/ROB.scala index 2272d2be3..5070bcb46 100644 --- a/src/main/scala/gemmini/ROB.scala +++ b/src/main/scala/gemmini/ROB.scala @@ -116,9 +116,15 @@ class ROB[T <: Data : Arithmetic, U <: Data, V <: Data](config: GemminiArrayConf val ld_block_strides = Reg(Vec(load_states, UInt(block_stride_bits.W))) val st_block_stride = block_rows.U val pooling_is_enabled = Reg(Bool()) + val current_dataflow = if (dataflow == Dataflow.BOTH) Reg(UInt(1.W)) else dataflow.id.U // TODO magic number + + val ex_ooo_is_enabled = ex_ooo.B && current_dataflow === Dataflow.WS.id.U // Registers to help keep OOO execute working properly - val last_allocated_preload = Reg(UInt(log2Up(rob_entries).W)) + val last_allocated_preload = Reg(UDValid(UInt(log2Up(rob_entries).W))) + val last_allocated_garbage_preload = Reg(UDValid(UInt(log2Up(rob_entries).W))) + val last_allocated_preload_being_updated = WireInit(false.B) + val last_allocated_garbage_preload_being_updated = WireInit(false.B) val last_ex_issued_was_preload = RegInit(false.B) val new_entry = Wire(new Entry) @@ -308,14 +314,22 @@ class ROB[T <: Data : Arithmetic, U <: Data, V <: Data](config: GemminiArrayConf val older_in_same_q = VecInit(entries.zipWithIndex.map { case (e, i) => - val ooo_q = (ld_ooo.B && new_entry.q === ldq) || (ex_ooo.B && new_entry.q === exq) || (st_ooo.B && new_entry.q === stq) + val ooo_q = (ld_ooo.B && new_entry.q === ldq) || (ex_ooo_is_enabled && new_entry.q === exq) || (st_ooo.B && new_entry.q === stq) + + val is_last_preload = last_allocated_preload.valid && i.U === last_allocated_preload.bits + val is_last_garbage_preload = last_allocated_garbage_preload.valid && i.U === last_allocated_garbage_preload.bits - val is_last_preload = i.U === last_allocated_preload val new_entry_is_compute = new_entry.cmd.inst.funct === COMPUTE_AND_STAY_CMD || new_entry.cmd.inst.funct === COMPUTE_AND_FLIP_CMD + val new_entry_is_preload = new_entry.cmd.inst.funct === PRELOAD_CMD + val preload_addr = new_entry.cmd.rs1(31, 0).asTypeOf(local_addr_t) // TODO magic number + val preload_garbage = preload_addr.is_garbage() e.valid && e.bits.q === new_entry.q && !e.bits.issued && - (!ooo_q || e.bits.is_config || new_entry.is_config || (is_last_preload && new_entry_is_compute)) + (!ooo_q || e.bits.is_config || new_entry.is_config || + ((new_entry_is_compute && is_last_preload) || + (new_entry_is_preload && preload_garbage && is_last_preload) || + (new_entry_is_preload && !preload_garbage && is_last_garbage_preload))) }) val is_st_and_must_wait_for_prior_ex_config = VecInit(entries.map { e => @@ -365,6 +379,7 @@ class ROB[T <: Data : Arithmetic, U <: Data, V <: Data](config: GemminiArrayConf val set_only_strides = new_entry.cmd.rs1(7) // TODO magic numbers when (!set_only_strides) { a_transpose := new_entry.cmd.rs1(8) // TODO magic numbers + if (dataflow == Dataflow.BOTH) current_dataflow := new_entry.cmd.rs1(2) // TODO magic numbers } }.elsewhen(new_entry.is_config && new_entry.q === ldq) { val id = new_entry.cmd.rs1(4,3) // TODO magic numbers @@ -374,7 +389,14 @@ class ROB[T <: Data : Arithmetic, U <: Data, V <: Data](config: GemminiArrayConf val pool_stride = new_entry.cmd.rs1(5, 4) // TODO magic numbers pooling_is_enabled := pool_stride =/= 0.U }.elsewhen(new_entry.cmd.inst.funct === PRELOAD_CMD) { - last_allocated_preload := full_alloc_id + last_allocated_preload.push(full_alloc_id) + last_allocated_preload_being_updated := true.B + + val preload_addr = new_entry.cmd.rs1(31, 0).asTypeOf(local_addr_t) // TODO magic number + when (preload_addr.is_garbage()) { + last_allocated_preload.push(full_alloc_id) + last_allocated_garbage_preload_being_updated := true.B + } } } } @@ -427,6 +449,14 @@ class ROB[T <: Data : Arithmetic, U <: Data, V <: Data](config: GemminiArrayConf when (i.U === io.completed.bits) { e.valid := false.B assert(e.valid) + + when (last_allocated_preload.bits === i.U && !last_allocated_preload_being_updated) { + last_allocated_preload.pop() + } + + when (last_allocated_garbage_preload.bits === i.U && !last_allocated_garbage_preload_being_updated) { + last_allocated_garbage_preload.pop() + } } } } @@ -485,6 +515,8 @@ class ROB[T <: Data : Arithmetic, U <: Data, V <: Data](config: GemminiArrayConf } when (reset.asBool()) { - entries.foreach(_.valid := false.B) + entries.foreach(_.pop()) + last_allocated_preload.pop() + last_allocated_garbage_preload.pop() } } From 374a7da2e38b881d4aad8b959ee513a33dc621c3 Mon Sep 17 00:00:00 2001 From: Hasan Genc Date: Fri, 4 Jun 2021 16:34:59 -0700 Subject: [PATCH 14/78] Make sts ooo --- src/main/scala/gemmini/Configs.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/scala/gemmini/Configs.scala b/src/main/scala/gemmini/Configs.scala index 7e7f4fd6f..574c7d000 100644 --- a/src/main/scala/gemmini/Configs.scala +++ b/src/main/scala/gemmini/Configs.scala @@ -149,7 +149,7 @@ object GemminiConfigs { ld_ooo = false, ex_ooo = false, - st_ooo = false, + st_ooo = true, use_preload_filter = true, ) From 85b5b29980a82829e1027ae464fcbd7a4597b606 Mon Sep 17 00:00:00 2001 From: Hasan Genc Date: Fri, 4 Jun 2021 16:35:23 -0700 Subject: [PATCH 15/78] Make exs ooo --- src/main/scala/gemmini/Configs.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/scala/gemmini/Configs.scala b/src/main/scala/gemmini/Configs.scala index 574c7d000..96ca35193 100644 --- a/src/main/scala/gemmini/Configs.scala +++ b/src/main/scala/gemmini/Configs.scala @@ -148,7 +148,7 @@ object GemminiConfigs { mesh_output_delay = 1, ld_ooo = false, - ex_ooo = false, + ex_ooo = true, st_ooo = true, use_preload_filter = true, From d435b6e33eda90dc536601b44d414293f7f34dc0 Mon Sep 17 00:00:00 2001 From: Hasan Genc Date: Fri, 4 Jun 2021 18:38:13 -0700 Subject: [PATCH 16/78] Turn of ooo again --- src/main/scala/gemmini/Configs.scala | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/scala/gemmini/Configs.scala b/src/main/scala/gemmini/Configs.scala index 96ca35193..7e7f4fd6f 100644 --- a/src/main/scala/gemmini/Configs.scala +++ b/src/main/scala/gemmini/Configs.scala @@ -148,8 +148,8 @@ object GemminiConfigs { mesh_output_delay = 1, ld_ooo = false, - ex_ooo = true, - st_ooo = true, + ex_ooo = false, + st_ooo = false, use_preload_filter = true, ) From f506177c98d9a9754f0be13a30ef299dcc6bcdce Mon Sep 17 00:00:00 2001 From: Hasan Genc Date: Sun, 6 Jun 2021 05:39:42 -0700 Subject: [PATCH 17/78] Fix ld_id --- src/main/scala/gemmini/PreloadFilter.scala | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/main/scala/gemmini/PreloadFilter.scala b/src/main/scala/gemmini/PreloadFilter.scala index db247da7a..466198b85 100644 --- a/src/main/scala/gemmini/PreloadFilter.scala +++ b/src/main/scala/gemmini/PreloadFilter.scala @@ -80,8 +80,9 @@ class PreloadFilter[T <: Data : Arithmetic, U <: Data, V <: Data](config: Gemmin val should_filter_preload = ex_is_preload && df === Dataflow.WS.id.U && preloaded_address === ex_preload_addr val ld_is_config = io.in_ld.cmd.inst.funct === CONFIG_CMD - val ld_id = MuxCase(0.U, Seq((io.in_ld.cmd.inst.funct === LOAD2_CMD) -> 1.U, - (io.in_ld.cmd.inst.funct === LOAD3_CMD) -> 2.U)) + val ld_id = Mux(ld_is_config, io.in_ex.cmd.rs1(4,3).asUInt(), // TODO magic numbers + MuxCase(0.U, Seq((io.in_ld.cmd.inst.funct === LOAD2_CMD) -> 1.U, + (io.in_ld.cmd.inst.funct === LOAD3_CMD) -> 2.U))) val ld_config_block_stride = io.in_ld.cmd.rs1(31, 16).asUInt() // TODO magic numbers val ld_total_rows = { val block_stride = ld_block_strides(ld_id) From 9995263e08a7798ecabcf411099f7a017571395e Mon Sep 17 00:00:00 2001 From: Hasan Genc Date: Sun, 6 Jun 2021 05:42:31 -0700 Subject: [PATCH 18/78] Try making sts ooo --- src/main/scala/gemmini/Configs.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/scala/gemmini/Configs.scala b/src/main/scala/gemmini/Configs.scala index 7e7f4fd6f..574c7d000 100644 --- a/src/main/scala/gemmini/Configs.scala +++ b/src/main/scala/gemmini/Configs.scala @@ -149,7 +149,7 @@ object GemminiConfigs { ld_ooo = false, ex_ooo = false, - st_ooo = false, + st_ooo = true, use_preload_filter = true, ) From 7aeeae08bd62b3e225c5d33d3549d0a588c24748 Mon Sep 17 00:00:00 2001 From: Hasan Genc Date: Sun, 6 Jun 2021 06:29:14 -0700 Subject: [PATCH 19/78] Make ex ooo --- src/main/scala/gemmini/Configs.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/scala/gemmini/Configs.scala b/src/main/scala/gemmini/Configs.scala index 574c7d000..96ca35193 100644 --- a/src/main/scala/gemmini/Configs.scala +++ b/src/main/scala/gemmini/Configs.scala @@ -148,7 +148,7 @@ object GemminiConfigs { mesh_output_delay = 1, ld_ooo = false, - ex_ooo = false, + ex_ooo = true, st_ooo = true, use_preload_filter = true, From c562cde0fb1e68f00b28b4f3badb838da9b9075e Mon Sep 17 00:00:00 2001 From: Hasan Genc Date: Sun, 6 Jun 2021 06:51:52 -0700 Subject: [PATCH 20/78] Fix ld id again by using ld rs1 --- src/main/scala/gemmini/Configs.scala | 4 ++-- src/main/scala/gemmini/PreloadFilter.scala | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/scala/gemmini/Configs.scala b/src/main/scala/gemmini/Configs.scala index 96ca35193..7e7f4fd6f 100644 --- a/src/main/scala/gemmini/Configs.scala +++ b/src/main/scala/gemmini/Configs.scala @@ -148,8 +148,8 @@ object GemminiConfigs { mesh_output_delay = 1, ld_ooo = false, - ex_ooo = true, - st_ooo = true, + ex_ooo = false, + st_ooo = false, use_preload_filter = true, ) diff --git a/src/main/scala/gemmini/PreloadFilter.scala b/src/main/scala/gemmini/PreloadFilter.scala index 466198b85..129a4312d 100644 --- a/src/main/scala/gemmini/PreloadFilter.scala +++ b/src/main/scala/gemmini/PreloadFilter.scala @@ -80,7 +80,7 @@ class PreloadFilter[T <: Data : Arithmetic, U <: Data, V <: Data](config: Gemmin val should_filter_preload = ex_is_preload && df === Dataflow.WS.id.U && preloaded_address === ex_preload_addr val ld_is_config = io.in_ld.cmd.inst.funct === CONFIG_CMD - val ld_id = Mux(ld_is_config, io.in_ex.cmd.rs1(4,3).asUInt(), // TODO magic numbers + val ld_id = Mux(ld_is_config, io.in_ld.cmd.rs1(4,3).asUInt(), // TODO magic numbers MuxCase(0.U, Seq((io.in_ld.cmd.inst.funct === LOAD2_CMD) -> 1.U, (io.in_ld.cmd.inst.funct === LOAD3_CMD) -> 2.U))) val ld_config_block_stride = io.in_ld.cmd.rs1(31, 16).asUInt() // TODO magic numbers From 59e2cdcf48383d899f6cfa919decfd7b2053b174 Mon Sep 17 00:00:00 2001 From: Hasan Genc Date: Sun, 6 Jun 2021 06:52:40 -0700 Subject: [PATCH 21/78] make st ooo --- src/main/scala/gemmini/Configs.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/scala/gemmini/Configs.scala b/src/main/scala/gemmini/Configs.scala index 7e7f4fd6f..574c7d000 100644 --- a/src/main/scala/gemmini/Configs.scala +++ b/src/main/scala/gemmini/Configs.scala @@ -149,7 +149,7 @@ object GemminiConfigs { ld_ooo = false, ex_ooo = false, - st_ooo = false, + st_ooo = true, use_preload_filter = true, ) From 8240b6ce503daaa19f4ed84fa919bd8576d8142e Mon Sep 17 00:00:00 2001 From: Hasan Genc Date: Sun, 6 Jun 2021 06:52:55 -0700 Subject: [PATCH 22/78] make ex ooo --- src/main/scala/gemmini/Configs.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/scala/gemmini/Configs.scala b/src/main/scala/gemmini/Configs.scala index 574c7d000..96ca35193 100644 --- a/src/main/scala/gemmini/Configs.scala +++ b/src/main/scala/gemmini/Configs.scala @@ -148,7 +148,7 @@ object GemminiConfigs { mesh_output_delay = 1, ld_ooo = false, - ex_ooo = false, + ex_ooo = true, st_ooo = true, use_preload_filter = true, From a6d6617a2693f509dfe9e84925800fac503ec8ac Mon Sep 17 00:00:00 2001 From: Hasan Genc Date: Sun, 6 Jun 2021 07:16:25 -0700 Subject: [PATCH 23/78] Make only sts ooo --- src/main/scala/gemmini/Configs.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/scala/gemmini/Configs.scala b/src/main/scala/gemmini/Configs.scala index 96ca35193..574c7d000 100644 --- a/src/main/scala/gemmini/Configs.scala +++ b/src/main/scala/gemmini/Configs.scala @@ -148,7 +148,7 @@ object GemminiConfigs { mesh_output_delay = 1, ld_ooo = false, - ex_ooo = true, + ex_ooo = false, st_ooo = true, use_preload_filter = true, From 483d95760accbb48d065ed402aa1ee1f21444111 Mon Sep 17 00:00:00 2001 From: Hasan Genc Date: Sun, 6 Jun 2021 07:34:50 -0700 Subject: [PATCH 24/78] Fix last_allocated_garbage_preload typo --- src/main/scala/gemmini/ROB.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/scala/gemmini/ROB.scala b/src/main/scala/gemmini/ROB.scala index 5070bcb46..371a23fdf 100644 --- a/src/main/scala/gemmini/ROB.scala +++ b/src/main/scala/gemmini/ROB.scala @@ -394,7 +394,7 @@ class ROB[T <: Data : Arithmetic, U <: Data, V <: Data](config: GemminiArrayConf val preload_addr = new_entry.cmd.rs1(31, 0).asTypeOf(local_addr_t) // TODO magic number when (preload_addr.is_garbage()) { - last_allocated_preload.push(full_alloc_id) + last_allocated_garbage_preload.push(full_alloc_id) last_allocated_garbage_preload_being_updated := true.B } } From 83aaf793f3bf75b1dcc2a7501bc2f9897a07cb46 Mon Sep 17 00:00:00 2001 From: Hasan Genc Date: Sun, 6 Jun 2021 07:35:51 -0700 Subject: [PATCH 25/78] Make ex ooo --- src/main/scala/gemmini/Configs.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/scala/gemmini/Configs.scala b/src/main/scala/gemmini/Configs.scala index 574c7d000..96ca35193 100644 --- a/src/main/scala/gemmini/Configs.scala +++ b/src/main/scala/gemmini/Configs.scala @@ -148,7 +148,7 @@ object GemminiConfigs { mesh_output_delay = 1, ld_ooo = false, - ex_ooo = false, + ex_ooo = true, st_ooo = true, use_preload_filter = true, From 1da83f691a2989fd35817ff63e43cb4291ec2ae4 Mon Sep 17 00:00:00 2001 From: Hasan Genc Date: Sun, 6 Jun 2021 21:45:11 -0700 Subject: [PATCH 26/78] Added fused preload+comp instructions --- src/main/scala/gemmini/ROB.scala | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/src/main/scala/gemmini/ROB.scala b/src/main/scala/gemmini/ROB.scala index 371a23fdf..26a661169 100644 --- a/src/main/scala/gemmini/ROB.scala +++ b/src/main/scala/gemmini/ROB.scala @@ -92,6 +92,9 @@ class ROB[T <: Data : Arithmetic, U <: Data, V <: Data](config: GemminiArrayConf val deps = Vec(rob_entries, Bool()) def ready(dummy: Int = 0): Bool = !deps.reduce(_ || _) + // Signals that are necessary for OoO operation + val waiting_for_compute_inst = Bool() + // Debugging signals val allocated_at = UInt(instructions_allocated.getWidth.W) } @@ -354,6 +357,8 @@ class ROB[T <: Data : Arithmetic, U <: Data, V <: Data](config: GemminiArrayConf new_entry.complete_on_issue := new_entry.is_config && new_entry.q =/= exq + new_entry.waiting_for_compute_inst := ex_ooo.B && funct === PRELOAD_CMD + val is_full = PopCount(Seq(dst.valid, op1.valid, op2.valid)) > 1.U val full_alloc_id = MuxCase((rob_full_entries-1).U, full_entries.zipWithIndex.map { case (e, i) => !e.valid -> i.U }) val partial_alloc_id = MuxCase((rob_partial_entries-1).U, partial_entries.zipWithIndex.map { case (e, i) => !e.valid -> i.U }) @@ -397,6 +402,16 @@ class ROB[T <: Data : Arithmetic, U <: Data, V <: Data](config: GemminiArrayConf last_allocated_garbage_preload.push(full_alloc_id) last_allocated_garbage_preload_being_updated := true.B } + }.elsewhen(funct_is_compute) { + when (last_allocated_preload.valid) { + entries.zipWithIndex.foreach { case (e,i) => + when (i.U === last_allocated_preload.bits) { + e.bits.waiting_for_compute_inst := false.B + e.bits.deps := (e.bits.deps.asUInt() | new_entry.deps.asUInt()).asTypeOf(e.bits.deps) + assert(e.valid) + } + } + } } } } @@ -407,7 +422,8 @@ class ROB[T <: Data : Arithmetic, U <: Data, V <: Data](config: GemminiArrayConf val issue_valids = entries.map { e => val is_compute = e.bits.cmd.inst.funct === COMPUTE_AND_FLIP_CMD || e.bits.cmd.inst.funct === COMPUTE_AND_STAY_CMD - e.valid && e.bits.ready() && !e.bits.issued && e.bits.q === q && (!must_be_compute || is_compute) + e.valid && e.bits.ready() && !e.bits.issued && e.bits.q === q && (!must_be_compute || is_compute) && + (!ex_ooo.B || !e.bits.waiting_for_compute_inst) } val issue_sel = PriorityEncoderOH(issue_valids) val issue_id = OHToUInt(issue_sel) @@ -461,6 +477,11 @@ class ROB[T <: Data : Arithmetic, U <: Data, V <: Data](config: GemminiArrayConf } } + // Hardcode deps that point to the entry that owns the deps to 0 + entries.zipWithIndex.foreach { case (e,i) => + e.bits.deps(i) := false.B + } + // val utilization = PopCount(entries.map(e => e.valid)) val utilization_ld_q_unissued = PopCount(entries.map(e => e.valid && !e.bits.issued && e.bits.q === ldq)) val utilization_st_q_unissued = PopCount(entries.map(e => e.valid && !e.bits.issued && e.bits.q === stq)) From 4467508f18fef172e899c07f53e4a53af3a1ab24 Mon Sep 17 00:00:00 2001 From: Hasan Genc Date: Sun, 6 Jun 2021 22:34:55 -0700 Subject: [PATCH 27/78] Add LoopMatmul ooo option --- software/gemmini-rocc-tests | 2 +- src/main/scala/gemmini/LoopMatmul.scala | 8 ++++++-- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/software/gemmini-rocc-tests b/software/gemmini-rocc-tests index 000d2fd3e..b02e64b92 160000 --- a/software/gemmini-rocc-tests +++ b/software/gemmini-rocc-tests @@ -1 +1 @@ -Subproject commit 000d2fd3e472103cb2a2c91e3d0afedc85b3738b +Subproject commit b02e64b920937df2914a9edfbb0adf4abd288994 diff --git a/src/main/scala/gemmini/LoopMatmul.scala b/src/main/scala/gemmini/LoopMatmul.scala index af9e3061e..09451c49a 100644 --- a/src/main/scala/gemmini/LoopMatmul.scala +++ b/src/main/scala/gemmini/LoopMatmul.scala @@ -305,6 +305,7 @@ class LoopMatmulExecuteReq(val block_size: Int, val coreMaxAddrBits: Int, val it val pad_i = UInt(log2Up(block_size).W) val a_tranpose = Bool() val b_tranpose = Bool() + val ooo = Bool() val accumulate = Bool() val a_addr_start = UInt(log2Up(max_addr).W) val b_addr_end = UInt(log2Up(max_addr).W) @@ -374,7 +375,7 @@ class LoopMatmulExecute(block_size: Int, coreMaxAddrBits: Int, iterator_bitwidth val c_cols = block_size.U - Mux(j === req.max_j - 1.U, req.pad_j, 0.U) val c_rows = block_size.U - Mux(i === req.max_i - 1.U, req.pad_i, 0.U) - val pre_addr = Mux(i === 0.U, b_addr, GARBAGE_ADDR) + val pre_addr = Mux(i === 0.U || req.ooo, b_addr, GARBAGE_ADDR) val out_addr = Mux(req.accumulate || k =/= 0.U, c_addr, d_addr) val pre_cmd = Wire(new RoCCCommand) @@ -385,7 +386,7 @@ class LoopMatmulExecute(block_size: Int, coreMaxAddrBits: Int, iterator_bitwidth val comp_cmd = Wire(new RoCCCommand()) comp_cmd := DontCare - comp_cmd.inst.funct := Mux(i === 0.U, COMPUTE_AND_FLIP_CMD, COMPUTE_AND_STAY_CMD) + comp_cmd.inst.funct := Mux(i === 0.U || req.ooo, COMPUTE_AND_FLIP_CMD, COMPUTE_AND_STAY_CMD) comp_cmd.rs1 := a_addr | (a_cols << 32).asUInt() | (a_rows << 48).asUInt() comp_cmd.rs2 := GARBAGE_ADDR | (block_size.U << 32).asUInt() | (block_size.U << 48).asUInt() @@ -564,6 +565,7 @@ class LoopMatmulState(val iterator_bitwidth: Int, val coreMaxAddrBits: Int, val val ex_accumulate = Bool() val weightA = UInt(8.W) // TODO magic numbers + val ooo = Bool() val configured = Bool() @@ -741,6 +743,7 @@ class LoopMatmul(block_size: Int, coreMaxAddrBits: Int, rob_size: Int, max_lds: loop_being_configured.b_transpose := cmd.bits.rs2(1) loop_being_configured.weightA := cmd.bits.rs1(15, 8) // TODO magic numbers + loop_being_configured.ooo := cmd.bits.rs2(2) // TODO magic numbers loop_being_configured.configured := true.B @@ -805,6 +808,7 @@ class LoopMatmul(block_size: Int, coreMaxAddrBits: Int, rob_size: Int, max_lds: ex.io.req.bits.b_addr_end := loop_requesting_ex.b_addr_end ex.io.req.bits.a_tranpose := loop_requesting_ex.a_transpose ex.io.req.bits.b_tranpose := loop_requesting_ex.b_transpose + ex.io.req.bits.ooo := loop_requesting_ex.ooo ex.io.req.bits.c_addr_start := ex_c_addr_start ex.io.req.bits.loop_id := loop_requesting_ex_id From dd8c92cbe521a505a5361836d60b2010f3dc09a4 Mon Sep 17 00:00:00 2001 From: Hasan Genc Date: Sun, 6 Jun 2021 23:07:51 -0700 Subject: [PATCH 28/78] bump gemmini-rocc-tests --- software/gemmini-rocc-tests | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/software/gemmini-rocc-tests b/software/gemmini-rocc-tests index b02e64b92..7b7c21b83 160000 --- a/software/gemmini-rocc-tests +++ b/software/gemmini-rocc-tests @@ -1 +1 @@ -Subproject commit b02e64b920937df2914a9edfbb0adf4abd288994 +Subproject commit 7b7c21b837e2c005ab4581d708c82cacc97c13ac From d83a3a0c80df90a886e4c5a873d34f60168451ea Mon Sep 17 00:00:00 2001 From: Hasan Genc Date: Mon, 7 Jun 2021 01:50:24 -0700 Subject: [PATCH 29/78] Bump gemmini-rocc-tests --- software/gemmini-rocc-tests | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/software/gemmini-rocc-tests b/software/gemmini-rocc-tests index 7b7c21b83..a0fbc64e9 160000 --- a/software/gemmini-rocc-tests +++ b/software/gemmini-rocc-tests @@ -1 +1 @@ -Subproject commit 7b7c21b837e2c005ab4581d708c82cacc97c13ac +Subproject commit a0fbc64e9fde05d6c5991a31b82a7d791dc25239 From 34442b9bb2728eb41b605caedc0a42062fc78e8f Mon Sep 17 00:00:00 2001 From: Hasan Genc Date: Mon, 7 Jun 2021 02:29:14 -0700 Subject: [PATCH 30/78] Implement C-address accumulation checks for WAW --- src/main/scala/gemmini/ROB.scala | 29 +++++++++++++++++++++-------- 1 file changed, 21 insertions(+), 8 deletions(-) diff --git a/src/main/scala/gemmini/ROB.scala b/src/main/scala/gemmini/ROB.scala index 26a661169..f66fa98a3 100644 --- a/src/main/scala/gemmini/ROB.scala +++ b/src/main/scala/gemmini/ROB.scala @@ -56,9 +56,11 @@ class ROB[T <: Data : Arithmetic, U <: Data, V <: Data](config: GemminiArrayConf val end = local_addr_t.cloneType val wraps_around = Bool() - def overlaps(other: OpT): Bool = { + def overlaps(other: OpT, check_accumulates: Boolean=false): Bool = { ((other.start <= start && (start < other.end || other.wraps_around)) || (start <= other.start && (other.start < end || wraps_around))) && + (!check_accumulates.B || + !(start.is_acc_addr && start.accumulate && other.start.is_acc_addr && other.start.accumulate)) && !(start.is_garbage() || other.start.is_garbage()) // TODO the "is_garbage" check might not really be necessary } } @@ -274,8 +276,10 @@ class ROB[T <: Data : Arithmetic, U <: Data, V <: Data](config: GemminiArrayConf )) assert(is_load || is_store || is_ex) - // This can be RAW op1/op2 <- dst, or WAW dst <- dst + // This can be RAW op1/op2 <- dst val opa_matches_opa = VecInit(entries.map { e => e.valid && e.bits.opa.valid && new_entry.opa.bits.overlaps(e.bits.opa.bits) }) + // This can be WAW dst <- dst + val opa_matches_opa_for_waws = VecInit(entries.map { e => e.valid && e.bits.opa.valid && new_entry.opa.bits.overlaps(e.bits.opa.bits, check_accumulates=true) }) // This can be WAR dst <- op1/op2 val opa_matches_opb = VecInit(entries.map { e => e.valid && e.bits.opb.valid && new_entry.opa.bits.overlaps(e.bits.opb.bits) }) // This can be RAW op2 <- dst @@ -290,28 +294,37 @@ class ROB[T <: Data : Arithmetic, U <: Data, V <: Data](config: GemminiArrayConf val dst_matches_opa = VecInit((entries zip opa_matches_opa).map { case (e, a) => e.valid && dst.valid && a }) + val dst_matches_opa_for_waws = VecInit((entries zip opa_matches_opa_for_waws).map { case (e, a) => + e.valid && dst.valid && a + }) val dst_matches_opb = VecInit((entries zip opa_matches_opb).map { case (e, b) => e.valid && dst.valid && b }) + def compare_q(e: Entry, new_entry: Entry): Bool = { + // This function returns true if these entries are in different queues, or if they're in the + // same q, but "e" has not been issued yet. + e.q =/= new_entry.q || (e.q === new_entry.q && !e.issued) + } + val op1_raws_opa = VecInit((entries zip op1_matches_opa).map { case (e, m) => - m && op1.valid && e.bits.q =/= new_entry.q && e.bits.opa_is_dst + m && op1.valid && compare_q(e.bits, new_entry) && e.bits.opa_is_dst }) val op2_raws_opa = VecInit((entries zip op2_matches_opa).map { case (e, m) => - m && op2.valid && e.bits.q =/= new_entry.q && e.bits.opa_is_dst + m && op2.valid && compare_q(e.bits, new_entry) && e.bits.opa_is_dst }) val raws = VecInit((op1_raws_opa zip op2_raws_opa).map { case (a, b) => a || b }) val dst_wars_opa = VecInit((entries zip dst_matches_opa).map { case (e, m) => - m && dst.valid && e.bits.q =/= new_entry.q && !e.bits.opa_is_dst + m && dst.valid && compare_q(e.bits, new_entry) && !e.bits.opa_is_dst }) val dst_wars_opb = VecInit((entries zip dst_matches_opb).map { case (e, m) => - m && dst.valid && e.bits.q =/= new_entry.q + m && dst.valid && compare_q(e.bits, new_entry) }) val wars = VecInit((dst_wars_opa zip dst_wars_opb).map { case (a, b) => a || b }) - val dst_waws_opa = VecInit((entries zip dst_matches_opa).map { case (e, m) => - m && dst.valid && (e.bits.q =/= new_entry.q || new_entry.q === ldq) && e.bits.opa_is_dst + val dst_waws_opa = VecInit((entries zip dst_matches_opa_for_waws).map { case (e, m) => + m && dst.valid && (compare_q(e.bits, new_entry) || new_entry.q === ldq) && e.bits.opa_is_dst }) val waws = dst_waws_opa From 05a83c929db81db11fd4ad647353a0f9c16c4344 Mon Sep 17 00:00:00 2001 From: Hasan Genc Date: Wed, 9 Jun 2021 22:20:08 -0700 Subject: [PATCH 31/78] Add stall counter --- src/main/scala/gemmini/ROB.scala | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/main/scala/gemmini/ROB.scala b/src/main/scala/gemmini/ROB.scala index f66fa98a3..8fb2ff041 100644 --- a/src/main/scala/gemmini/ROB.scala +++ b/src/main/scala/gemmini/ROB.scala @@ -536,6 +536,16 @@ class ROB[T <: Data : Arithmetic, U <: Data, V <: Data](config: GemminiArrayConf dontTouch(e.bits.allocated_at) } + val first_preload_allocated = RegInit(false.B) + when (io.alloc.fire() && io.alloc.bits.inst.funct === PRELOAD_CMD) { + first_preload_allocated := true.B + } + val cycles_that_ex_stalls_due_to_dependencies = RegInit(0.U(32.W)) + when (first_preload_allocated && utilization_ex_q > 0.U && !io.issue.ex.valid) { + cycles_that_ex_stalls_due_to_dependencies := cycles_that_ex_stalls_due_to_dependencies + 1.U + } + dontTouch(cycles_that_ex_stalls_due_to_dependencies) + val cntr = Counter(10000000) when (cntr.inc()) { printf(p"Utilization: $utilization\n") From 7063b5a53596b4ab1face3b9466f2d2a97603821 Mon Sep 17 00:00:00 2001 From: Hasan Genc Date: Wed, 16 Jun 2021 03:20:24 +0300 Subject: [PATCH 32/78] Add I unrolling --- src/main/scala/gemmini/ExIUnroller.scala | 86 +++++++++++++++++++ .../scala/gemmini/ExecuteController.scala | 3 +- src/main/scala/gemmini/LoopMatmul.scala | 32 +++++-- src/main/scala/gemmini/ROB.scala | 9 +- 4 files changed, 121 insertions(+), 9 deletions(-) create mode 100644 src/main/scala/gemmini/ExIUnroller.scala diff --git a/src/main/scala/gemmini/ExIUnroller.scala b/src/main/scala/gemmini/ExIUnroller.scala new file mode 100644 index 000000000..a331d07bb --- /dev/null +++ b/src/main/scala/gemmini/ExIUnroller.scala @@ -0,0 +1,86 @@ +package gemmini + +import chisel3._ +import chisel3.util._ +import chisel3.experimental._ +import freechips.rocketchip.tile.RoCCCommand +import chipsalliance.rocketchip.config.Parameters +import GemminiISA._ +import Util._ + +class ExIUnroller[T <: Data : Arithmetic, U <: Data, V <: Data](config: GemminiArrayConfig[T, U, V])(implicit p: Parameters) extends Module { + import config._ + + val block_rows = meshRows * tileRows + val block_cols = meshColumns * tileColumns + + val io = IO(new Bundle { + val in = Flipped(Decoupled(new GemminiCmd(rob_entries))) + val out = Decoupled(new GemminiCmd(rob_entries)) + }) + + object State extends ChiselEnum { + val preload, compute = Value + } + import State._ + val state = RegInit(preload) + + val (q, len) = MultiHeadedQueue(io.in, entries=3, heads=2, maxpop=2) + + val first_cmd_is_preload = q.bits(0).cmd.inst.funct === PRELOAD_CMD + + val total_I = q.bits(0).cmd.rs1(63, 48).asUInt() // This is only valid if first_cmd_is_preload === true.B // TODO magic numbers + val I_sent = RegInit(0.U(16.W)) // TODO magic number + val last_send = total_I -& I_sent <= block_rows.U + + val must_unroll = first_cmd_is_preload && total_I > block_rows.U + + val J_blocks = Cat(q.bits(0).cmd.inst.opcode, q.bits(0).cmd.inst.rs1, q.bits(0).cmd.inst.rs2, q.bits(0).cmd.inst.rd) + val I_block = I_sent / block_rows.U + + val preload_cmd_with_bounded_i = WireInit(q.bits(0)) + preload_cmd_with_bounded_i.cmd.rs2 := (minOf(total_I -& I_sent, block_rows.U) << 48) | + (q.bits(0).cmd.rs2(47, 32) << 32) | + (q.bits(0).cmd.rs2(31, 0).asTypeOf(local_addr_t) + I_block * J_blocks).asUInt() + + val compute_cmd_with_bounded_i = WireInit(q.bits(1)) + compute_cmd_with_bounded_i.cmd.rs1 := (minOf(total_I -& I_sent, block_rows.U) << 48) | + (q.bits(1).cmd.rs1(47, 32) << 32) | + (q.bits(1).cmd.rs1(31, 0).asTypeOf(local_addr_t) + I_block * J_blocks).asUInt() + compute_cmd_with_bounded_i.cmd.rs2 := (minOf(total_I -& I_sent, block_rows.U) << 48) | + (q.bits(1).cmd.rs2(47, 32) << 32) | + (q.bits(1).cmd.rs2(31, 0).asTypeOf(local_addr_t) + I_block * J_blocks).asUInt() + + when (q.bits(0).cmd.rs2(31, 0).asTypeOf(local_addr_t).is_garbage()) { + preload_cmd_with_bounded_i.cmd.rs2 := (block_rows.U << 48) | (block_cols.U << 32) | GARBAGE_ADDR + } + when (q.bits(1).cmd.rs1(31, 0).asTypeOf(local_addr_t).is_garbage()) { + compute_cmd_with_bounded_i.cmd.rs1 := (block_rows.U << 48) | (block_cols.U << 32) | GARBAGE_ADDR + } + when (q.bits(1).cmd.rs2(31, 0).asTypeOf(local_addr_t).is_garbage()) { + compute_cmd_with_bounded_i.cmd.rs2 := (block_rows.U << 48) | (block_cols.U << 32) | GARBAGE_ADDR + } + + io.out.valid := Mux(must_unroll, (q.valid(0) && state === preload) || (q.valid(1) && state === compute), q.valid(0)) + io.out.bits := Mux(must_unroll, Mux(state === preload, preload_cmd_with_bounded_i, compute_cmd_with_bounded_i), q.bits(0)) + + q.pop := Mux(io.out.fire(), Mux(must_unroll, Mux(state === compute && last_send, 2.U, 0.U), 1.U), 0.U) + + // Control the state + when (io.out.fire() && must_unroll) { + state := state.next + } + + // Control I_sent + when (io.out.fire() && must_unroll && state === compute) { + I_sent := floorAdd(I_sent, total_I, block_rows.U) + } +} + +object ExIUnroller { + def apply[T <: Data : Arithmetic, U <: Data, V <: Data](in: ReadyValidIO[GemminiCmd], config: GemminiArrayConfig[T, U, V])(implicit p: Parameters) = { + val mod = Module(new ExIUnroller(config)) + mod.io.in <> in + mod.io.out + } +} diff --git a/src/main/scala/gemmini/ExecuteController.scala b/src/main/scala/gemmini/ExecuteController.scala index d8a1bac9f..37f80194a 100644 --- a/src/main/scala/gemmini/ExecuteController.scala +++ b/src/main/scala/gemmini/ExecuteController.scala @@ -59,7 +59,8 @@ class ExecuteController[T <: Data, U <: Data, V <: Data](xLen: Int, tagWidth: In } } - val unrolled_cmd = TransposePreloadUnroller(io.cmd, config) + val transpose_unrolled_cmd = TransposePreloadUnroller(io.cmd, config) + val unrolled_cmd = ExIUnroller(transpose_unrolled_cmd, config) val cmd_q_heads = 3 assert(ex_queue_length >= cmd_q_heads) diff --git a/src/main/scala/gemmini/LoopMatmul.scala b/src/main/scala/gemmini/LoopMatmul.scala index 09451c49a..abb73423f 100644 --- a/src/main/scala/gemmini/LoopMatmul.scala +++ b/src/main/scala/gemmini/LoopMatmul.scala @@ -313,10 +313,20 @@ class LoopMatmulExecuteReq(val block_size: Int, val coreMaxAddrBits: Int, val it val loop_id = UInt(log2Up(concurrent_loops).W) } -class LoopMatmulExecute(block_size: Int, coreMaxAddrBits: Int, iterator_bitwidth: Int, max_addr: Int, max_acc_addr: Int, concurrent_loops: Int) +class LoopMatmulExecute(block_size: Int, coreMaxAddrBits: Int, iterator_bitwidth: Int, max_addr: Int, max_acc_addr: Int, max_block_len: Int, concurrent_loops: Int) (implicit p: Parameters) extends Module { val GARBAGE_ADDR = (~0.U(32.W)).asUInt() + val cmd_t = new RoCCCommand + class j_blocks_holder_t extends Bundle { + val opcode = UInt(cmd_t.inst.opcode.getWidth.W) + val rs1 = UInt(cmd_t.inst.rs1.getWidth.W) + val rs2 = UInt(cmd_t.inst.rs2.getWidth.W) + val rd = UInt(cmd_t.inst.rd.getWidth.W) + + override def cloneType: j_blocks_holder_t.this.type = (new j_blocks_holder_t).asInstanceOf[this.type] + } + val io = IO(new Bundle { val req = Flipped(Decoupled(new LoopMatmulExecuteReq(block_size, coreMaxAddrBits, iterator_bitwidth, max_addr, max_acc_addr, concurrent_loops))) val cmd = Decoupled(Output(new RoCCCommand)) @@ -347,6 +357,8 @@ class LoopMatmulExecute(block_size: Int, coreMaxAddrBits: Int, iterator_bitwidth val req = Reg(new LoopMatmulExecuteReq(block_size, coreMaxAddrBits, iterator_bitwidth, max_addr, max_acc_addr, concurrent_loops)) + val max_i_blocks = Mux(req.a_tranpose, 1.U, Mux(req.max_i <= max_block_len.U, req.max_i, max_block_len.U)) + val d_addr_start = (BigInt(1) << 31).U | req.c_addr_start val c_addr_start = (BigInt(3) << 30).U | req.c_addr_start val b_addr_start = req.b_addr_end - req.max_k * req.max_j * block_size.U @@ -355,6 +367,8 @@ class LoopMatmulExecute(block_size: Int, coreMaxAddrBits: Int, iterator_bitwidth val j = Reg(UInt(iterator_bitwidth.W)) val i = Reg(UInt(iterator_bitwidth.W)) + val i_blocks = Mux(i + max_i_blocks <= req.max_i, max_i_blocks, req.max_i-i) + val a_row = Mux(req.a_tranpose, k, i) val a_col = Mux(req.a_tranpose, i, k) val b_row = Mux(req.b_tranpose, j, k) @@ -369,11 +383,11 @@ class LoopMatmulExecute(block_size: Int, coreMaxAddrBits: Int, iterator_bitwidth val c_addr = c_addr_start + (i * req.max_j + j) * block_size.U val a_cols = block_size.U - Mux(k === req.max_k - 1.U, req.pad_k, 0.U) - val a_rows = block_size.U - Mux(i === req.max_i - 1.U, req.pad_i, 0.U) + val a_rows = i_blocks * block_size.U - Mux(i + max_i_blocks >= req.max_i, req.pad_i, 0.U) val b_cols = block_size.U - Mux(j === req.max_j - 1.U, req.pad_j, 0.U) val b_rows = block_size.U - Mux(k === req.max_k - 1.U, req.pad_k, 0.U) val c_cols = block_size.U - Mux(j === req.max_j - 1.U, req.pad_j, 0.U) - val c_rows = block_size.U - Mux(i === req.max_i - 1.U, req.pad_i, 0.U) + val c_rows = i_blocks * block_size.U - Mux(i + max_i_blocks >= req.max_i, req.pad_i, 0.U) val pre_addr = Mux(i === 0.U || req.ooo, b_addr, GARBAGE_ADDR) val out_addr = Mux(req.accumulate || k =/= 0.U, c_addr, d_addr) @@ -397,7 +411,7 @@ class LoopMatmulExecute(block_size: Int, coreMaxAddrBits: Int, iterator_bitwidth io.idle := state === idle // The order here is k, j, i - val lda_ahead = io.lda_completed || io.ld_ka > k || (io.ld_ka === k && io.ld_i > i) + val lda_ahead = io.lda_completed || io.ld_ka > k || (io.ld_ka === k && io.ld_i >= i + i_blocks) val ldb_ahead = io.ldb_completed || io.ld_kb > k || (io.ld_ka === k && io.ld_j > j) val ldd_ahead = io.ldd_completed val ld_ahead = lda_ahead && ldb_ahead && ldd_ahead @@ -405,13 +419,19 @@ class LoopMatmulExecute(block_size: Int, coreMaxAddrBits: Int, iterator_bitwidth io.cmd.valid := state =/= idle && !io.rob_overloaded && ld_ahead io.cmd.bits := Mux(state === pre, pre_cmd, comp_cmd) + val j_blocks_holder = req.max_j.asTypeOf(new j_blocks_holder_t) + io.cmd.bits.inst.opcode := j_blocks_holder.opcode + io.cmd.bits.inst.rs1 := j_blocks_holder.rs1 + io.cmd.bits.inst.rs2 := j_blocks_holder.rs2 + io.cmd.bits.inst.rd := j_blocks_holder.rd + io.loop_id := req.loop_id when (io.cmd.fire()) { when (state === pre) { state := comp }.otherwise { - val next_i = floorAdd(i, 1.U, req.max_i) + val next_i = floorAdd(i, max_block_len.U, req.max_i) val next_j = floorAdd(j, 1.U, req.max_j, next_i === 0.U) val next_k = floorAdd(k, 1.U, req.max_k, next_j === 0.U && next_i === 0.U) @@ -640,7 +660,7 @@ class LoopMatmul(block_size: Int, coreMaxAddrBits: Int, rob_size: Int, max_lds: val ldA = Module(new LoopMatmulLdA(block_size, coreMaxAddrBits, iterator_bitwidth, max_addr, input_w, max_block_len, concurrent_loops)) val ldB = Module(new LoopMatmulLdB(block_size, coreMaxAddrBits, iterator_bitwidth, max_addr, input_w, max_block_len, concurrent_loops)) val ldD = Module(new LoopMatmulLdD(block_size, coreMaxAddrBits, iterator_bitwidth, max_acc_addr, input_w, acc_w, max_block_len, max_block_len_acc, concurrent_loops)) - val ex = Module(new LoopMatmulExecute(block_size, coreMaxAddrBits, iterator_bitwidth, max_addr, max_acc_addr, concurrent_loops)) + val ex = Module(new LoopMatmulExecute(block_size, coreMaxAddrBits, iterator_bitwidth, max_addr, max_acc_addr, max_block_len, concurrent_loops)) val stC = Module(new LoopMatmulStC(block_size, coreMaxAddrBits, iterator_bitwidth, max_acc_addr, input_w, acc_w, max_block_len, concurrent_loops)) // Create command queue diff --git a/src/main/scala/gemmini/ROB.scala b/src/main/scala/gemmini/ROB.scala index 8fb2ff041..1c50cab68 100644 --- a/src/main/scala/gemmini/ROB.scala +++ b/src/main/scala/gemmini/ROB.scala @@ -47,6 +47,11 @@ class ROB[T <: Data : Arithmetic, U <: Data, V <: Data](config: GemminiArrayConf val solitary_preload = Input(Bool()) // TODO very hacky. from ExecuteController, to prevent infinite fence stalls. remove later }) + println(s"\n\nio.alloc.bits.inst.rs1.getWidth = ${io.alloc.bits.inst.rs1.getWidth}") + println(s"io.alloc.bits.inst.rs2.getWidth = ${io.alloc.bits.inst.rs2.getWidth}") + println(s"io.alloc.bits.inst.rd.getWidth = ${io.alloc.bits.inst.rd.getWidth}") + println(s"io.alloc.bits.inst.opcode.getWidth = ${io.alloc.bits.inst.opcode.getWidth}\n\n") + // TODO make this a ChiselEnum val ldq :: stq :: exq :: Nil = Enum(3) val q_t = ldq.cloneType @@ -216,7 +221,7 @@ class ROB[T <: Data : Arithmetic, U <: Data, V <: Data](config: GemminiArrayConf op2.valid := funct_is_compute || funct === STORE_CMD op2.bits.start := cmd.rs2.asTypeOf(local_addr_t) when (funct_is_compute) { - val compute_rows = cmd.rs2(48 + log2Up(block_rows + 1) - 1, 48) + val compute_rows = cmd.rs2(48 + log2Up(mvin_cols_bits + 1) - 1, 48) op2.bits.end := op2.bits.start + compute_rows op2.bits.wraps_around := op2.bits.start.add_with_overflow(compute_rows)._2 }.elsewhen (pooling_is_enabled) { @@ -246,7 +251,7 @@ class ROB[T <: Data : Arithmetic, U <: Data, V <: Data](config: GemminiArrayConf dst.valid := funct === PRELOAD_CMD || funct === LOAD_CMD || funct === LOAD2_CMD || funct === LOAD3_CMD dst.bits.start := cmd.rs2(31, 0).asTypeOf(local_addr_t) when (funct === PRELOAD_CMD) { - val preload_rows = cmd.rs2(48 + log2Up(block_rows + 1) - 1, 48) * c_stride + val preload_rows = cmd.rs2(48 + log2Up(mvin_cols_bits + 1) - 1, 48) * c_stride dst.bits.end := dst.bits.start + preload_rows dst.bits.wraps_around := dst.bits.start.add_with_overflow(preload_rows)._2 }.otherwise { From 50981b079b67baca3a0d8ddabd94b0ae743188b9 Mon Sep 17 00:00:00 2001 From: Hasan Genc Date: Wed, 16 Jun 2021 03:57:07 +0300 Subject: [PATCH 33/78] Fix ROB --- src/main/scala/gemmini/ROB.scala | 30 ++++++++++++++++++++++++------ 1 file changed, 24 insertions(+), 6 deletions(-) diff --git a/src/main/scala/gemmini/ROB.scala b/src/main/scala/gemmini/ROB.scala index 1c50cab68..e61bb52bd 100644 --- a/src/main/scala/gemmini/ROB.scala +++ b/src/main/scala/gemmini/ROB.scala @@ -211,9 +211,15 @@ class ROB[T <: Data : Arithmetic, U <: Data, V <: Data](config: GemminiArrayConf op1.bits.end := op1.bits.start + preload_rows op1.bits.wraps_around := op1.bits.start.add_with_overflow(preload_rows)._2 }.otherwise { - val rows = cmd.rs1(48 + log2Up(block_rows + 1) - 1, 48) + val rows = cmd.rs1(48 + log2Up(mvin_cols_bits + 1) - 1, 48) + val j = Cat(cmd.inst.opcode, cmd.inst.rs1, cmd.inst.rs2, cmd.inst.rd) + + val mats = rows / block_rows.U + (rows % block_rows.U =/= 0.U) + val total_rows = ((mats - 1.U) * j) + Mux(rows % block_rows.U === 0.U, block_rows.U, rows % block_rows.U) + val cols = cmd.rs1(32 + log2Up(block_cols + 1) - 1, 32) - val compute_rows = Mux(a_transpose, cols, rows) * a_stride + val compute_rows = Mux(a_transpose, cols, total_rows) * a_stride + op1.bits.end := op1.bits.start + compute_rows op1.bits.wraps_around := op1.bits.start.add_with_overflow(compute_rows)._2 } @@ -221,9 +227,14 @@ class ROB[T <: Data : Arithmetic, U <: Data, V <: Data](config: GemminiArrayConf op2.valid := funct_is_compute || funct === STORE_CMD op2.bits.start := cmd.rs2.asTypeOf(local_addr_t) when (funct_is_compute) { - val compute_rows = cmd.rs2(48 + log2Up(mvin_cols_bits + 1) - 1, 48) - op2.bits.end := op2.bits.start + compute_rows - op2.bits.wraps_around := op2.bits.start.add_with_overflow(compute_rows)._2 + val rows = cmd.rs2(48 + log2Up(mvin_cols_bits + 1) - 1, 48) + val j = Cat(cmd.inst.opcode, cmd.inst.rs1, cmd.inst.rs2, cmd.inst.rd) + + val mats = rows / block_rows.U + (rows % block_rows.U =/= 0.U) + val total_rows = ((mats - 1.U) * j) + Mux(rows % block_rows.U === 0.U, block_rows.U, rows % block_rows.U) + + op2.bits.end := op2.bits.start + total_rows + op2.bits.wraps_around := op2.bits.start.add_with_overflow(total_rows)._2 }.elsewhen (pooling_is_enabled) { // If pooling is enabled, then we assume that this command simply mvouts everything in this accumulator bank from // start to the end of the bank // TODO this won't work when acc_banks =/= 2 @@ -251,7 +262,14 @@ class ROB[T <: Data : Arithmetic, U <: Data, V <: Data](config: GemminiArrayConf dst.valid := funct === PRELOAD_CMD || funct === LOAD_CMD || funct === LOAD2_CMD || funct === LOAD3_CMD dst.bits.start := cmd.rs2(31, 0).asTypeOf(local_addr_t) when (funct === PRELOAD_CMD) { - val preload_rows = cmd.rs2(48 + log2Up(mvin_cols_bits + 1) - 1, 48) * c_stride + val rows = cmd.rs2(48 + log2Up(mvin_cols_bits + 1) - 1, 48) + val j = Cat(cmd.inst.opcode, cmd.inst.rs1, cmd.inst.rs2, cmd.inst.rd) + + val mats = rows / block_rows.U + (rows % block_rows.U =/= 0.U) + val total_rows = ((mats - 1.U) * j) + Mux(rows % block_rows.U === 0.U, block_rows.U, rows % block_rows.U) + + val preload_rows = total_rows * c_stride + dst.bits.end := dst.bits.start + preload_rows dst.bits.wraps_around := dst.bits.start.add_with_overflow(preload_rows)._2 }.otherwise { From 7b188b3810f9d9366f27e169014be8021a206aee Mon Sep 17 00:00:00 2001 From: Hasan Genc Date: Wed, 16 Jun 2021 04:19:18 +0300 Subject: [PATCH 34/78] Fix rob-id in ExIUnroller --- src/main/scala/gemmini/ExIUnroller.scala | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main/scala/gemmini/ExIUnroller.scala b/src/main/scala/gemmini/ExIUnroller.scala index a331d07bb..db6487461 100644 --- a/src/main/scala/gemmini/ExIUnroller.scala +++ b/src/main/scala/gemmini/ExIUnroller.scala @@ -42,6 +42,7 @@ class ExIUnroller[T <: Data : Arithmetic, U <: Data, V <: Data](config: GemminiA preload_cmd_with_bounded_i.cmd.rs2 := (minOf(total_I -& I_sent, block_rows.U) << 48) | (q.bits(0).cmd.rs2(47, 32) << 32) | (q.bits(0).cmd.rs2(31, 0).asTypeOf(local_addr_t) + I_block * J_blocks).asUInt() + preload_cmd_with_bounded_i.rob_id.valid := last_send val compute_cmd_with_bounded_i = WireInit(q.bits(1)) compute_cmd_with_bounded_i.cmd.rs1 := (minOf(total_I -& I_sent, block_rows.U) << 48) | @@ -50,6 +51,7 @@ class ExIUnroller[T <: Data : Arithmetic, U <: Data, V <: Data](config: GemminiA compute_cmd_with_bounded_i.cmd.rs2 := (minOf(total_I -& I_sent, block_rows.U) << 48) | (q.bits(1).cmd.rs2(47, 32) << 32) | (q.bits(1).cmd.rs2(31, 0).asTypeOf(local_addr_t) + I_block * J_blocks).asUInt() + compute_cmd_with_bounded_i.rob_id.valid := last_send when (q.bits(0).cmd.rs2(31, 0).asTypeOf(local_addr_t).is_garbage()) { preload_cmd_with_bounded_i.cmd.rs2 := (block_rows.U << 48) | (block_cols.U << 32) | GARBAGE_ADDR From 95efa6a10daa1633cdf0bbd2bf317cd3fea241a4 Mon Sep 17 00:00:00 2001 From: Hasan Genc Date: Wed, 16 Jun 2021 04:32:29 +0300 Subject: [PATCH 35/78] Fix max_i_blocks addition --- src/main/scala/gemmini/LoopMatmul.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/scala/gemmini/LoopMatmul.scala b/src/main/scala/gemmini/LoopMatmul.scala index abb73423f..96d28f776 100644 --- a/src/main/scala/gemmini/LoopMatmul.scala +++ b/src/main/scala/gemmini/LoopMatmul.scala @@ -431,7 +431,7 @@ class LoopMatmulExecute(block_size: Int, coreMaxAddrBits: Int, iterator_bitwidth when (state === pre) { state := comp }.otherwise { - val next_i = floorAdd(i, max_block_len.U, req.max_i) + val next_i = floorAdd(i, max_i_blocks, req.max_i) val next_j = floorAdd(j, 1.U, req.max_j, next_i === 0.U) val next_k = floorAdd(k, 1.U, req.max_k, next_j === 0.U && next_i === 0.U) From 01db476c8b177f26e33c11f6f70edab4b9f5deb7 Mon Sep 17 00:00:00 2001 From: Hasan Genc Date: Wed, 16 Jun 2021 05:20:02 +0300 Subject: [PATCH 36/78] Fix ExIUnroller --- src/main/scala/gemmini/ExIUnroller.scala | 6 +++--- src/main/scala/gemmini/ExecuteController.scala | 3 +-- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/src/main/scala/gemmini/ExIUnroller.scala b/src/main/scala/gemmini/ExIUnroller.scala index db6487461..149d1a6c9 100644 --- a/src/main/scala/gemmini/ExIUnroller.scala +++ b/src/main/scala/gemmini/ExIUnroller.scala @@ -29,7 +29,7 @@ class ExIUnroller[T <: Data : Arithmetic, U <: Data, V <: Data](config: GemminiA val first_cmd_is_preload = q.bits(0).cmd.inst.funct === PRELOAD_CMD - val total_I = q.bits(0).cmd.rs1(63, 48).asUInt() // This is only valid if first_cmd_is_preload === true.B // TODO magic numbers + val total_I = q.bits(0).cmd.rs2(63, 48).asUInt() // This is only valid if first_cmd_is_preload === true.B // TODO magic numbers val I_sent = RegInit(0.U(16.W)) // TODO magic number val last_send = total_I -& I_sent <= block_rows.U @@ -42,7 +42,7 @@ class ExIUnroller[T <: Data : Arithmetic, U <: Data, V <: Data](config: GemminiA preload_cmd_with_bounded_i.cmd.rs2 := (minOf(total_I -& I_sent, block_rows.U) << 48) | (q.bits(0).cmd.rs2(47, 32) << 32) | (q.bits(0).cmd.rs2(31, 0).asTypeOf(local_addr_t) + I_block * J_blocks).asUInt() - preload_cmd_with_bounded_i.rob_id.valid := last_send + preload_cmd_with_bounded_i.rob_id.valid := last_send && q.bits(0).rob_id.valid val compute_cmd_with_bounded_i = WireInit(q.bits(1)) compute_cmd_with_bounded_i.cmd.rs1 := (minOf(total_I -& I_sent, block_rows.U) << 48) | @@ -51,7 +51,7 @@ class ExIUnroller[T <: Data : Arithmetic, U <: Data, V <: Data](config: GemminiA compute_cmd_with_bounded_i.cmd.rs2 := (minOf(total_I -& I_sent, block_rows.U) << 48) | (q.bits(1).cmd.rs2(47, 32) << 32) | (q.bits(1).cmd.rs2(31, 0).asTypeOf(local_addr_t) + I_block * J_blocks).asUInt() - compute_cmd_with_bounded_i.rob_id.valid := last_send + compute_cmd_with_bounded_i.rob_id.valid := last_send && q.bits(0).rob_id.valid when (q.bits(0).cmd.rs2(31, 0).asTypeOf(local_addr_t).is_garbage()) { preload_cmd_with_bounded_i.cmd.rs2 := (block_rows.U << 48) | (block_cols.U << 32) | GARBAGE_ADDR diff --git a/src/main/scala/gemmini/ExecuteController.scala b/src/main/scala/gemmini/ExecuteController.scala index 37f80194a..3552066c6 100644 --- a/src/main/scala/gemmini/ExecuteController.scala +++ b/src/main/scala/gemmini/ExecuteController.scala @@ -59,8 +59,7 @@ class ExecuteController[T <: Data, U <: Data, V <: Data](xLen: Int, tagWidth: In } } - val transpose_unrolled_cmd = TransposePreloadUnroller(io.cmd, config) - val unrolled_cmd = ExIUnroller(transpose_unrolled_cmd, config) + val unrolled_cmd = TransposePreloadUnroller(ExIUnroller(io.cmd, config), config) val cmd_q_heads = 3 assert(ex_queue_length >= cmd_q_heads) From 9faf839f1507807fdd309bbf0f0160f9291702e6 Mon Sep 17 00:00:00 2001 From: Hasan Genc Date: Wed, 16 Jun 2021 05:45:14 +0300 Subject: [PATCH 37/78] Fix flooradd --- src/main/scala/gemmini/ExIUnroller.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/scala/gemmini/ExIUnroller.scala b/src/main/scala/gemmini/ExIUnroller.scala index 149d1a6c9..7fa66f625 100644 --- a/src/main/scala/gemmini/ExIUnroller.scala +++ b/src/main/scala/gemmini/ExIUnroller.scala @@ -75,7 +75,7 @@ class ExIUnroller[T <: Data : Arithmetic, U <: Data, V <: Data](config: GemminiA // Control I_sent when (io.out.fire() && must_unroll && state === compute) { - I_sent := floorAdd(I_sent, total_I, block_rows.U) + I_sent := floorAdd(I_sent, block_rows.U, total_I) } } From c8cc2b19ec05e7620d8fd46e0ae4b3686d0b0ac1 Mon Sep 17 00:00:00 2001 From: Hasan Genc Date: Wed, 16 Jun 2021 05:49:10 +0300 Subject: [PATCH 38/78] Allow preload to have invalid rob id --- src/main/scala/gemmini/ExecuteController.scala | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/scala/gemmini/ExecuteController.scala b/src/main/scala/gemmini/ExecuteController.scala index 3552066c6..43b05b2f7 100644 --- a/src/main/scala/gemmini/ExecuteController.scala +++ b/src/main/scala/gemmini/ExecuteController.scala @@ -968,8 +968,8 @@ class ExecuteController[T <: Data, U <: Data, V <: Data](xLen: Int, tagWidth: In val last = mesh.io.resp.bits.last when(last) { - mesh_completed_rob_id_fire := true.B - io.completed.valid := true.B + mesh_completed_rob_id_fire := mesh.io.resp.bits.tag.rob_id.valid + io.completed.valid := mesh.io.resp.bits.tag.rob_id.valid io.completed.bits := mesh.io.resp.bits.tag.rob_id.bits } start_array_outputting := !is_garbage_addr From efa4fccaef7dc215f6350326bc53f1bbb896fb6e Mon Sep 17 00:00:00 2001 From: Hasan Genc Date: Wed, 16 Jun 2021 06:01:07 +0300 Subject: [PATCH 39/78] fix preload rob id valid again --- src/main/scala/gemmini/ExecuteController.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/scala/gemmini/ExecuteController.scala b/src/main/scala/gemmini/ExecuteController.scala index 43b05b2f7..10d08c988 100644 --- a/src/main/scala/gemmini/ExecuteController.scala +++ b/src/main/scala/gemmini/ExecuteController.scala @@ -784,7 +784,7 @@ class ExecuteController[T <: Data, U <: Data, V <: Data](xLen: Int, tagWidth: In mesh_cntl_signals_q.io.enq.bits.a_transpose := a_transpose mesh_cntl_signals_q.io.enq.bits.bd_transpose := bd_transpose - mesh_cntl_signals_q.io.enq.bits.rob_id.valid := !performing_single_mul && !c_address_rs2.is_garbage() + mesh_cntl_signals_q.io.enq.bits.rob_id.valid := cmd.bits(preload_cmd_place).rob_id.valid && !performing_single_mul && !c_address_rs2.is_garbage() mesh_cntl_signals_q.io.enq.bits.rob_id.bits := cmd.bits(preload_cmd_place).rob_id.bits mesh_cntl_signals_q.io.enq.bits.dataflow := current_dataflow From e14014a5b052e9beb23387e0115db7dbc9969202 Mon Sep 17 00:00:00 2001 From: Hasan Genc Date: Wed, 16 Jun 2021 06:02:41 +0300 Subject: [PATCH 40/78] Fix block addr calculation --- src/main/scala/gemmini/ExIUnroller.scala | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/scala/gemmini/ExIUnroller.scala b/src/main/scala/gemmini/ExIUnroller.scala index 7fa66f625..9c4d95bf3 100644 --- a/src/main/scala/gemmini/ExIUnroller.scala +++ b/src/main/scala/gemmini/ExIUnroller.scala @@ -41,16 +41,16 @@ class ExIUnroller[T <: Data : Arithmetic, U <: Data, V <: Data](config: GemminiA val preload_cmd_with_bounded_i = WireInit(q.bits(0)) preload_cmd_with_bounded_i.cmd.rs2 := (minOf(total_I -& I_sent, block_rows.U) << 48) | (q.bits(0).cmd.rs2(47, 32) << 32) | - (q.bits(0).cmd.rs2(31, 0).asTypeOf(local_addr_t) + I_block * J_blocks).asUInt() + (q.bits(0).cmd.rs2(31, 0).asTypeOf(local_addr_t) + I_block * J_blocks * block_rows.U).asUInt() preload_cmd_with_bounded_i.rob_id.valid := last_send && q.bits(0).rob_id.valid val compute_cmd_with_bounded_i = WireInit(q.bits(1)) compute_cmd_with_bounded_i.cmd.rs1 := (minOf(total_I -& I_sent, block_rows.U) << 48) | (q.bits(1).cmd.rs1(47, 32) << 32) | - (q.bits(1).cmd.rs1(31, 0).asTypeOf(local_addr_t) + I_block * J_blocks).asUInt() + (q.bits(1).cmd.rs1(31, 0).asTypeOf(local_addr_t) + I_block * J_blocks * block_rows.U).asUInt() compute_cmd_with_bounded_i.cmd.rs2 := (minOf(total_I -& I_sent, block_rows.U) << 48) | (q.bits(1).cmd.rs2(47, 32) << 32) | - (q.bits(1).cmd.rs2(31, 0).asTypeOf(local_addr_t) + I_block * J_blocks).asUInt() + (q.bits(1).cmd.rs2(31, 0).asTypeOf(local_addr_t) + I_block * J_blocks * block_rows.U).asUInt() compute_cmd_with_bounded_i.rob_id.valid := last_send && q.bits(0).rob_id.valid when (q.bits(0).cmd.rs2(31, 0).asTypeOf(local_addr_t).is_garbage()) { From e288e76d99ee60f0dc7c393fdc76fb12d4504ed9 Mon Sep 17 00:00:00 2001 From: Hasan Genc Date: Wed, 16 Jun 2021 06:33:24 +0300 Subject: [PATCH 41/78] Fix j block calc in ROB --- src/main/scala/gemmini/ROB.scala | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/scala/gemmini/ROB.scala b/src/main/scala/gemmini/ROB.scala index e61bb52bd..85c4b5abf 100644 --- a/src/main/scala/gemmini/ROB.scala +++ b/src/main/scala/gemmini/ROB.scala @@ -215,7 +215,7 @@ class ROB[T <: Data : Arithmetic, U <: Data, V <: Data](config: GemminiArrayConf val j = Cat(cmd.inst.opcode, cmd.inst.rs1, cmd.inst.rs2, cmd.inst.rd) val mats = rows / block_rows.U + (rows % block_rows.U =/= 0.U) - val total_rows = ((mats - 1.U) * j) + Mux(rows % block_rows.U === 0.U, block_rows.U, rows % block_rows.U) + val total_rows = ((mats - 1.U) * j * block_rows.U) + Mux(rows % block_rows.U === 0.U, block_rows.U, rows % block_rows.U) val cols = cmd.rs1(32 + log2Up(block_cols + 1) - 1, 32) val compute_rows = Mux(a_transpose, cols, total_rows) * a_stride @@ -231,7 +231,7 @@ class ROB[T <: Data : Arithmetic, U <: Data, V <: Data](config: GemminiArrayConf val j = Cat(cmd.inst.opcode, cmd.inst.rs1, cmd.inst.rs2, cmd.inst.rd) val mats = rows / block_rows.U + (rows % block_rows.U =/= 0.U) - val total_rows = ((mats - 1.U) * j) + Mux(rows % block_rows.U === 0.U, block_rows.U, rows % block_rows.U) + val total_rows = ((mats - 1.U) * j * block_rows.U) + Mux(rows % block_rows.U === 0.U, block_rows.U, rows % block_rows.U) op2.bits.end := op2.bits.start + total_rows op2.bits.wraps_around := op2.bits.start.add_with_overflow(total_rows)._2 @@ -266,7 +266,7 @@ class ROB[T <: Data : Arithmetic, U <: Data, V <: Data](config: GemminiArrayConf val j = Cat(cmd.inst.opcode, cmd.inst.rs1, cmd.inst.rs2, cmd.inst.rd) val mats = rows / block_rows.U + (rows % block_rows.U =/= 0.U) - val total_rows = ((mats - 1.U) * j) + Mux(rows % block_rows.U === 0.U, block_rows.U, rows % block_rows.U) + val total_rows = ((mats - 1.U) * j * block_rows.U) + Mux(rows % block_rows.U === 0.U, block_rows.U, rows % block_rows.U) val preload_rows = total_rows * c_stride From cba5afafcbed8d3122beaeca4fa9962a254fc750 Mon Sep 17 00:00:00 2001 From: Hasan Genc Date: Wed, 16 Jun 2021 06:45:13 +0300 Subject: [PATCH 42/78] fix preload rob id invalid again --- src/main/scala/gemmini/ExecuteController.scala | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/main/scala/gemmini/ExecuteController.scala b/src/main/scala/gemmini/ExecuteController.scala index 10d08c988..02d6075fb 100644 --- a/src/main/scala/gemmini/ExecuteController.scala +++ b/src/main/scala/gemmini/ExecuteController.scala @@ -963,15 +963,16 @@ class ExecuteController[T <: Data, U <: Data, V <: Data](xLen: Int, tagWidth: In //val complete_lock = RegInit(false.B) //Seah: added for WS accumulator - when(mesh.io.resp.fire() && mesh.io.resp.bits.tag.rob_id.valid) { + when(mesh.io.resp.fire()) { output_counter := wrappingAdd(output_counter, 1.U, w_total_output_rows) val last = mesh.io.resp.bits.last - when(last) { + when(last && mesh.io.resp.bits.tag.rob_id.valid) { mesh_completed_rob_id_fire := mesh.io.resp.bits.tag.rob_id.valid io.completed.valid := mesh.io.resp.bits.tag.rob_id.valid io.completed.bits := mesh.io.resp.bits.tag.rob_id.bits } + start_array_outputting := !is_garbage_addr } From 6dd6307214f72ccde32bdcddc81f73bcb5c0907f Mon Sep 17 00:00:00 2001 From: Hasan Genc Date: Wed, 16 Jun 2021 07:13:02 +0300 Subject: [PATCH 43/78] Fix ROB bitwidths --- src/main/scala/gemmini/ROB.scala | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/scala/gemmini/ROB.scala b/src/main/scala/gemmini/ROB.scala index 85c4b5abf..f21c02519 100644 --- a/src/main/scala/gemmini/ROB.scala +++ b/src/main/scala/gemmini/ROB.scala @@ -211,7 +211,7 @@ class ROB[T <: Data : Arithmetic, U <: Data, V <: Data](config: GemminiArrayConf op1.bits.end := op1.bits.start + preload_rows op1.bits.wraps_around := op1.bits.start.add_with_overflow(preload_rows)._2 }.otherwise { - val rows = cmd.rs1(48 + log2Up(mvin_cols_bits + 1) - 1, 48) + val rows = cmd.rs1(48 + mvin_cols_bits - 1, 48) val j = Cat(cmd.inst.opcode, cmd.inst.rs1, cmd.inst.rs2, cmd.inst.rd) val mats = rows / block_rows.U + (rows % block_rows.U =/= 0.U) @@ -227,7 +227,7 @@ class ROB[T <: Data : Arithmetic, U <: Data, V <: Data](config: GemminiArrayConf op2.valid := funct_is_compute || funct === STORE_CMD op2.bits.start := cmd.rs2.asTypeOf(local_addr_t) when (funct_is_compute) { - val rows = cmd.rs2(48 + log2Up(mvin_cols_bits + 1) - 1, 48) + val rows = cmd.rs2(48 + mvin_cols_bits - 1, 48) val j = Cat(cmd.inst.opcode, cmd.inst.rs1, cmd.inst.rs2, cmd.inst.rd) val mats = rows / block_rows.U + (rows % block_rows.U =/= 0.U) @@ -262,7 +262,7 @@ class ROB[T <: Data : Arithmetic, U <: Data, V <: Data](config: GemminiArrayConf dst.valid := funct === PRELOAD_CMD || funct === LOAD_CMD || funct === LOAD2_CMD || funct === LOAD3_CMD dst.bits.start := cmd.rs2(31, 0).asTypeOf(local_addr_t) when (funct === PRELOAD_CMD) { - val rows = cmd.rs2(48 + log2Up(mvin_cols_bits + 1) - 1, 48) + val rows = cmd.rs2(48 + mvin_cols_bits - 1, 48) val j = Cat(cmd.inst.opcode, cmd.inst.rs1, cmd.inst.rs2, cmd.inst.rd) val mats = rows / block_rows.U + (rows % block_rows.U =/= 0.U) From 42bd701bb38ad8ff36752ef26c8bb65d4823fe7c Mon Sep 17 00:00:00 2001 From: Hasan Genc Date: Wed, 16 Jun 2021 08:02:27 +0300 Subject: [PATCH 44/78] Fix rob-id in exiunroller --- src/main/scala/gemmini/ExIUnroller.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/scala/gemmini/ExIUnroller.scala b/src/main/scala/gemmini/ExIUnroller.scala index 9c4d95bf3..14610e659 100644 --- a/src/main/scala/gemmini/ExIUnroller.scala +++ b/src/main/scala/gemmini/ExIUnroller.scala @@ -51,7 +51,7 @@ class ExIUnroller[T <: Data : Arithmetic, U <: Data, V <: Data](config: GemminiA compute_cmd_with_bounded_i.cmd.rs2 := (minOf(total_I -& I_sent, block_rows.U) << 48) | (q.bits(1).cmd.rs2(47, 32) << 32) | (q.bits(1).cmd.rs2(31, 0).asTypeOf(local_addr_t) + I_block * J_blocks * block_rows.U).asUInt() - compute_cmd_with_bounded_i.rob_id.valid := last_send && q.bits(0).rob_id.valid + compute_cmd_with_bounded_i.rob_id.valid := last_send && q.bits(1).rob_id.valid when (q.bits(0).cmd.rs2(31, 0).asTypeOf(local_addr_t).is_garbage()) { preload_cmd_with_bounded_i.cmd.rs2 := (block_rows.U << 48) | (block_cols.U << 32) | GARBAGE_ADDR From 3ff5bbc7f57771ad0c85043077b388379fdf2ea5 Mon Sep 17 00:00:00 2001 From: Hasan Genc Date: Thu, 17 Jun 2021 01:03:19 +0300 Subject: [PATCH 45/78] Add max-k rather than just max-i --- src/main/scala/gemmini/ExIUnroller.scala | 8 ++++++-- src/main/scala/gemmini/LoopMatmul.scala | 21 +++++++++++++-------- src/main/scala/gemmini/ROB.scala | 8 ++++---- 3 files changed, 23 insertions(+), 14 deletions(-) diff --git a/src/main/scala/gemmini/ExIUnroller.scala b/src/main/scala/gemmini/ExIUnroller.scala index 14610e659..b1577cd9b 100644 --- a/src/main/scala/gemmini/ExIUnroller.scala +++ b/src/main/scala/gemmini/ExIUnroller.scala @@ -36,6 +36,7 @@ class ExIUnroller[T <: Data : Arithmetic, U <: Data, V <: Data](config: GemminiA val must_unroll = first_cmd_is_preload && total_I > block_rows.U val J_blocks = Cat(q.bits(0).cmd.inst.opcode, q.bits(0).cmd.inst.rs1, q.bits(0).cmd.inst.rs2, q.bits(0).cmd.inst.rd) + val K_blocks = Cat(q.bits(1).cmd.inst.opcode, q.bits(1).cmd.inst.rs1, q.bits(1).cmd.inst.rs2, q.bits(1).cmd.inst.rd) val I_block = I_sent / block_rows.U val preload_cmd_with_bounded_i = WireInit(q.bits(0)) @@ -47,19 +48,22 @@ class ExIUnroller[T <: Data : Arithmetic, U <: Data, V <: Data](config: GemminiA val compute_cmd_with_bounded_i = WireInit(q.bits(1)) compute_cmd_with_bounded_i.cmd.rs1 := (minOf(total_I -& I_sent, block_rows.U) << 48) | (q.bits(1).cmd.rs1(47, 32) << 32) | - (q.bits(1).cmd.rs1(31, 0).asTypeOf(local_addr_t) + I_block * J_blocks * block_rows.U).asUInt() + (q.bits(1).cmd.rs1(31, 0).asTypeOf(local_addr_t) + I_block * K_blocks * block_rows.U).asUInt() compute_cmd_with_bounded_i.cmd.rs2 := (minOf(total_I -& I_sent, block_rows.U) << 48) | (q.bits(1).cmd.rs2(47, 32) << 32) | (q.bits(1).cmd.rs2(31, 0).asTypeOf(local_addr_t) + I_block * J_blocks * block_rows.U).asUInt() compute_cmd_with_bounded_i.rob_id.valid := last_send && q.bits(1).rob_id.valid + when (I_sent > 0.U) { + preload_cmd_with_bounded_i.cmd.rs1 := (block_rows.U << 48) | (block_cols.U << 32) | GARBAGE_ADDR + } when (q.bits(0).cmd.rs2(31, 0).asTypeOf(local_addr_t).is_garbage()) { preload_cmd_with_bounded_i.cmd.rs2 := (block_rows.U << 48) | (block_cols.U << 32) | GARBAGE_ADDR } when (q.bits(1).cmd.rs1(31, 0).asTypeOf(local_addr_t).is_garbage()) { compute_cmd_with_bounded_i.cmd.rs1 := (block_rows.U << 48) | (block_cols.U << 32) | GARBAGE_ADDR } - when (q.bits(1).cmd.rs2(31, 0).asTypeOf(local_addr_t).is_garbage()) { + when (q.bits(1).cmd.rs2(31, 0).asTypeOf(local_addr_t).is_garbage() || (dataflow == Dataflow.WS && hardcode_d_to_garbage_addr).B) { compute_cmd_with_bounded_i.cmd.rs2 := (block_rows.U << 48) | (block_cols.U << 32) | GARBAGE_ADDR } diff --git a/src/main/scala/gemmini/LoopMatmul.scala b/src/main/scala/gemmini/LoopMatmul.scala index 96d28f776..fe6b778d0 100644 --- a/src/main/scala/gemmini/LoopMatmul.scala +++ b/src/main/scala/gemmini/LoopMatmul.scala @@ -318,13 +318,13 @@ class LoopMatmulExecute(block_size: Int, coreMaxAddrBits: Int, iterator_bitwidth val GARBAGE_ADDR = (~0.U(32.W)).asUInt() val cmd_t = new RoCCCommand - class j_blocks_holder_t extends Bundle { + class blocks_holder_t extends Bundle { val opcode = UInt(cmd_t.inst.opcode.getWidth.W) val rs1 = UInt(cmd_t.inst.rs1.getWidth.W) val rs2 = UInt(cmd_t.inst.rs2.getWidth.W) val rd = UInt(cmd_t.inst.rd.getWidth.W) - override def cloneType: j_blocks_holder_t.this.type = (new j_blocks_holder_t).asInstanceOf[this.type] + override def cloneType: blocks_holder_t.this.type = (new blocks_holder_t).asInstanceOf[this.type] } val io = IO(new Bundle { @@ -392,17 +392,28 @@ class LoopMatmulExecute(block_size: Int, coreMaxAddrBits: Int, iterator_bitwidth val pre_addr = Mux(i === 0.U || req.ooo, b_addr, GARBAGE_ADDR) val out_addr = Mux(req.accumulate || k =/= 0.U, c_addr, d_addr) + val j_blocks_holder = req.max_j.asTypeOf(new blocks_holder_t) + val k_blocks_holder = req.max_k.asTypeOf(new blocks_holder_t) + val pre_cmd = Wire(new RoCCCommand) pre_cmd := DontCare pre_cmd.inst.funct := PRELOAD_CMD pre_cmd.rs1 := pre_addr | (b_cols << 32).asUInt() | (b_rows << 48).asUInt() pre_cmd.rs2 := out_addr | (c_cols << 32).asUInt() | (c_rows << 48).asUInt() + pre_cmd.inst.opcode := j_blocks_holder.opcode + pre_cmd.inst.rs1 := j_blocks_holder.rs1 + pre_cmd.inst.rs2 := j_blocks_holder.rs2 + pre_cmd.inst.rd := j_blocks_holder.rd val comp_cmd = Wire(new RoCCCommand()) comp_cmd := DontCare comp_cmd.inst.funct := Mux(i === 0.U || req.ooo, COMPUTE_AND_FLIP_CMD, COMPUTE_AND_STAY_CMD) comp_cmd.rs1 := a_addr | (a_cols << 32).asUInt() | (a_rows << 48).asUInt() comp_cmd.rs2 := GARBAGE_ADDR | (block_size.U << 32).asUInt() | (block_size.U << 48).asUInt() + comp_cmd.inst.opcode := k_blocks_holder.opcode + comp_cmd.inst.rs1 := k_blocks_holder.rs1 + comp_cmd.inst.rs2 := k_blocks_holder.rs2 + comp_cmd.inst.rd := k_blocks_holder.rd io.req.ready := state === idle io.k := k @@ -419,12 +430,6 @@ class LoopMatmulExecute(block_size: Int, coreMaxAddrBits: Int, iterator_bitwidth io.cmd.valid := state =/= idle && !io.rob_overloaded && ld_ahead io.cmd.bits := Mux(state === pre, pre_cmd, comp_cmd) - val j_blocks_holder = req.max_j.asTypeOf(new j_blocks_holder_t) - io.cmd.bits.inst.opcode := j_blocks_holder.opcode - io.cmd.bits.inst.rs1 := j_blocks_holder.rs1 - io.cmd.bits.inst.rs2 := j_blocks_holder.rs2 - io.cmd.bits.inst.rd := j_blocks_holder.rd - io.loop_id := req.loop_id when (io.cmd.fire()) { diff --git a/src/main/scala/gemmini/ROB.scala b/src/main/scala/gemmini/ROB.scala index f21c02519..70711854d 100644 --- a/src/main/scala/gemmini/ROB.scala +++ b/src/main/scala/gemmini/ROB.scala @@ -212,10 +212,10 @@ class ROB[T <: Data : Arithmetic, U <: Data, V <: Data](config: GemminiArrayConf op1.bits.wraps_around := op1.bits.start.add_with_overflow(preload_rows)._2 }.otherwise { val rows = cmd.rs1(48 + mvin_cols_bits - 1, 48) - val j = Cat(cmd.inst.opcode, cmd.inst.rs1, cmd.inst.rs2, cmd.inst.rd) + val k = Cat(cmd.inst.opcode, cmd.inst.rs1, cmd.inst.rs2, cmd.inst.rd) val mats = rows / block_rows.U + (rows % block_rows.U =/= 0.U) - val total_rows = ((mats - 1.U) * j * block_rows.U) + Mux(rows % block_rows.U === 0.U, block_rows.U, rows % block_rows.U) + val total_rows = ((mats - 1.U) * k * block_rows.U) + Mux(rows % block_rows.U === 0.U, block_rows.U, rows % block_rows.U) val cols = cmd.rs1(32 + log2Up(block_cols + 1) - 1, 32) val compute_rows = Mux(a_transpose, cols, total_rows) * a_stride @@ -228,10 +228,10 @@ class ROB[T <: Data : Arithmetic, U <: Data, V <: Data](config: GemminiArrayConf op2.bits.start := cmd.rs2.asTypeOf(local_addr_t) when (funct_is_compute) { val rows = cmd.rs2(48 + mvin_cols_bits - 1, 48) - val j = Cat(cmd.inst.opcode, cmd.inst.rs1, cmd.inst.rs2, cmd.inst.rd) + val k = Cat(cmd.inst.opcode, cmd.inst.rs1, cmd.inst.rs2, cmd.inst.rd) // TODO this needs to use J rather than K val mats = rows / block_rows.U + (rows % block_rows.U =/= 0.U) - val total_rows = ((mats - 1.U) * j * block_rows.U) + Mux(rows % block_rows.U === 0.U, block_rows.U, rows % block_rows.U) + val total_rows = ((mats - 1.U) * k * block_rows.U) + Mux(rows % block_rows.U === 0.U, block_rows.U, rows % block_rows.U) op2.bits.end := op2.bits.start + total_rows op2.bits.wraps_around := op2.bits.start.add_with_overflow(total_rows)._2 From d05a637d67bbaa15a181c3d49e54a422b5d28216 Mon Sep 17 00:00:00 2001 From: Hasan Genc Date: Thu, 17 Jun 2021 08:26:09 +0300 Subject: [PATCH 46/78] Comment out ExIUnroller garbage preload --- src/main/scala/gemmini/ExIUnroller.scala | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/scala/gemmini/ExIUnroller.scala b/src/main/scala/gemmini/ExIUnroller.scala index b1577cd9b..8368a2aa6 100644 --- a/src/main/scala/gemmini/ExIUnroller.scala +++ b/src/main/scala/gemmini/ExIUnroller.scala @@ -54,9 +54,9 @@ class ExIUnroller[T <: Data : Arithmetic, U <: Data, V <: Data](config: GemminiA (q.bits(1).cmd.rs2(31, 0).asTypeOf(local_addr_t) + I_block * J_blocks * block_rows.U).asUInt() compute_cmd_with_bounded_i.rob_id.valid := last_send && q.bits(1).rob_id.valid - when (I_sent > 0.U) { + /*when (I_sent > 0.U) { preload_cmd_with_bounded_i.cmd.rs1 := (block_rows.U << 48) | (block_cols.U << 32) | GARBAGE_ADDR - } + }*/ when (q.bits(0).cmd.rs2(31, 0).asTypeOf(local_addr_t).is_garbage()) { preload_cmd_with_bounded_i.cmd.rs2 := (block_rows.U << 48) | (block_cols.U << 32) | GARBAGE_ADDR } From 9a255656722a2fd56f59a9efba83f7ba141267fd Mon Sep 17 00:00:00 2001 From: Hasan Genc Date: Thu, 17 Jun 2021 08:27:16 +0300 Subject: [PATCH 47/78] Add COMPUTE_AND_STAY to ExIUnroller --- src/main/scala/gemmini/ExIUnroller.scala | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/main/scala/gemmini/ExIUnroller.scala b/src/main/scala/gemmini/ExIUnroller.scala index 8368a2aa6..657bcc166 100644 --- a/src/main/scala/gemmini/ExIUnroller.scala +++ b/src/main/scala/gemmini/ExIUnroller.scala @@ -54,9 +54,10 @@ class ExIUnroller[T <: Data : Arithmetic, U <: Data, V <: Data](config: GemminiA (q.bits(1).cmd.rs2(31, 0).asTypeOf(local_addr_t) + I_block * J_blocks * block_rows.U).asUInt() compute_cmd_with_bounded_i.rob_id.valid := last_send && q.bits(1).rob_id.valid - /*when (I_sent > 0.U) { + when (I_sent > 0.U) { preload_cmd_with_bounded_i.cmd.rs1 := (block_rows.U << 48) | (block_cols.U << 32) | GARBAGE_ADDR - }*/ + compute_cmd_with_bounded_i.cmd.inst.funct := COMPUTE_AND_STAY_CMD + } when (q.bits(0).cmd.rs2(31, 0).asTypeOf(local_addr_t).is_garbage()) { preload_cmd_with_bounded_i.cmd.rs2 := (block_rows.U << 48) | (block_cols.U << 32) | GARBAGE_ADDR } From eab4f24d1428ea082eb41bff72a760b670e3000d Mon Sep 17 00:00:00 2001 From: Hasan Genc Date: Wed, 23 Jun 2021 10:21:04 +0300 Subject: [PATCH 48/78] Add new_entry_is_ld_and_other_is_ex to ROB --- src/main/scala/gemmini/ROB.scala | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/main/scala/gemmini/ROB.scala b/src/main/scala/gemmini/ROB.scala index 70711854d..a2b549550 100644 --- a/src/main/scala/gemmini/ROB.scala +++ b/src/main/scala/gemmini/ROB.scala @@ -330,6 +330,10 @@ class ROB[T <: Data : Arithmetic, U <: Data, V <: Data](config: GemminiArrayConf e.q =/= new_entry.q || (e.q === new_entry.q && !e.issued) } + val new_entry_is_ld_and_other_is_ex = entries.map { e => + e.valid && e.bits.q === exq && new_entry.q === ldq + } + val op1_raws_opa = VecInit((entries zip op1_matches_opa).map { case (e, m) => m && op1.valid && compare_q(e.bits, new_entry) && e.bits.opa_is_dst }) @@ -344,7 +348,7 @@ class ROB[T <: Data : Arithmetic, U <: Data, V <: Data](config: GemminiArrayConf val dst_wars_opb = VecInit((entries zip dst_matches_opb).map { case (e, m) => m && dst.valid && compare_q(e.bits, new_entry) }) - val wars = VecInit((dst_wars_opa zip dst_wars_opb).map { case (a, b) => a || b }) + val wars = VecInit((dst_wars_opa, dst_wars_opb, new_entry_is_ld_and_other_is_ex).zipped.map { case (a, b, c) => (a || b) && !c }) val dst_waws_opa = VecInit((entries zip dst_matches_opa_for_waws).map { case (e, m) => m && dst.valid && (compare_q(e.bits, new_entry) || new_entry.q === ldq) && e.bits.opa_is_dst From e8cccc3857b379d2683f431fe805c35a3bb341b5 Mon Sep 17 00:00:00 2001 From: Hasan Genc Date: Thu, 24 Jun 2021 16:58:21 +0300 Subject: [PATCH 49/78] Make it so that compute A only marks the last submatrix as being in-use --- src/main/scala/gemmini/ROB.scala | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/src/main/scala/gemmini/ROB.scala b/src/main/scala/gemmini/ROB.scala index a2b549550..932cb1550 100644 --- a/src/main/scala/gemmini/ROB.scala +++ b/src/main/scala/gemmini/ROB.scala @@ -211,6 +211,8 @@ class ROB[T <: Data : Arithmetic, U <: Data, V <: Data](config: GemminiArrayConf op1.bits.end := op1.bits.start + preload_rows op1.bits.wraps_around := op1.bits.start.add_with_overflow(preload_rows)._2 }.otherwise { + val start = cmd.rs1.asTypeOf(local_addr_t) + val rows = cmd.rs1(48 + mvin_cols_bits - 1, 48) val k = Cat(cmd.inst.opcode, cmd.inst.rs1, cmd.inst.rs2, cmd.inst.rd) @@ -220,13 +222,15 @@ class ROB[T <: Data : Arithmetic, U <: Data, V <: Data](config: GemminiArrayConf val cols = cmd.rs1(32 + log2Up(block_cols + 1) - 1, 32) val compute_rows = Mux(a_transpose, cols, total_rows) * a_stride - op1.bits.end := op1.bits.start + compute_rows - op1.bits.wraps_around := op1.bits.start.add_with_overflow(compute_rows)._2 + op1.bits.start := start + (mats - 1.U) * k * block_rows.U + op1.bits.end := start + compute_rows + op1.bits.wraps_around := start.add_with_overflow(compute_rows)._2 } op2.valid := funct_is_compute || funct === STORE_CMD op2.bits.start := cmd.rs2.asTypeOf(local_addr_t) when (funct_is_compute) { + /* val rows = cmd.rs2(48 + mvin_cols_bits - 1, 48) val k = Cat(cmd.inst.opcode, cmd.inst.rs1, cmd.inst.rs2, cmd.inst.rd) // TODO this needs to use J rather than K @@ -235,6 +239,9 @@ class ROB[T <: Data : Arithmetic, U <: Data, V <: Data](config: GemminiArrayConf op2.bits.end := op2.bits.start + total_rows op2.bits.wraps_around := op2.bits.start.add_with_overflow(total_rows)._2 + */ + op2.bits.end := GARBAGE_ADDR.asTypeOf(local_addr_t) + op2.bits.wraps_around := false.B }.elsewhen (pooling_is_enabled) { // If pooling is enabled, then we assume that this command simply mvouts everything in this accumulator bank from // start to the end of the bank // TODO this won't work when acc_banks =/= 2 @@ -303,6 +310,7 @@ class ROB[T <: Data : Arithmetic, U <: Data, V <: Data](config: GemminiArrayConf val opa_matches_opa = VecInit(entries.map { e => e.valid && e.bits.opa.valid && new_entry.opa.bits.overlaps(e.bits.opa.bits) }) // This can be WAW dst <- dst val opa_matches_opa_for_waws = VecInit(entries.map { e => e.valid && e.bits.opa.valid && new_entry.opa.bits.overlaps(e.bits.opa.bits, check_accumulates=true) }) + val opa_matches_opa_for_waws_for_ex = VecInit(entries.map { e => e.valid && e.bits.opa.valid && new_entry.opa.bits.start === e.bits.opa.bits.start }) // This can be WAR dst <- op1/op2 val opa_matches_opb = VecInit(entries.map { e => e.valid && e.bits.opb.valid && new_entry.opa.bits.overlaps(e.bits.opb.bits) }) // This can be RAW op2 <- dst @@ -317,9 +325,14 @@ class ROB[T <: Data : Arithmetic, U <: Data, V <: Data](config: GemminiArrayConf val dst_matches_opa = VecInit((entries zip opa_matches_opa).map { case (e, a) => e.valid && dst.valid && a }) + /* val dst_matches_opa_for_waws = VecInit((entries zip opa_matches_opa_for_waws).map { case (e, a) => e.valid && dst.valid && a }) + */ + val dst_matches_opa_for_waws = VecInit((entries, opa_matches_opa_for_waws, opa_matches_opa_for_waws_for_ex).zipped.map { case (e, a, b) => + e.valid && dst.valid && Mux(new_entry.q === exq && e.bits.q === exq, b, a) + }) val dst_matches_opb = VecInit((entries zip opa_matches_opb).map { case (e, b) => e.valid && dst.valid && b }) From 185aa09e3d380e6e4f98cc3eb2a5f58f1fe86d92 Mon Sep 17 00:00:00 2001 From: Hasan Genc Date: Thu, 24 Jun 2021 20:20:58 +0300 Subject: [PATCH 50/78] Revert "Make it so that compute A only marks the last submatrix as being in-use" This reverts commit e8cccc3857b379d2683f431fe805c35a3bb341b5. --- src/main/scala/gemmini/ROB.scala | 17 ++--------------- 1 file changed, 2 insertions(+), 15 deletions(-) diff --git a/src/main/scala/gemmini/ROB.scala b/src/main/scala/gemmini/ROB.scala index 932cb1550..a2b549550 100644 --- a/src/main/scala/gemmini/ROB.scala +++ b/src/main/scala/gemmini/ROB.scala @@ -211,8 +211,6 @@ class ROB[T <: Data : Arithmetic, U <: Data, V <: Data](config: GemminiArrayConf op1.bits.end := op1.bits.start + preload_rows op1.bits.wraps_around := op1.bits.start.add_with_overflow(preload_rows)._2 }.otherwise { - val start = cmd.rs1.asTypeOf(local_addr_t) - val rows = cmd.rs1(48 + mvin_cols_bits - 1, 48) val k = Cat(cmd.inst.opcode, cmd.inst.rs1, cmd.inst.rs2, cmd.inst.rd) @@ -222,15 +220,13 @@ class ROB[T <: Data : Arithmetic, U <: Data, V <: Data](config: GemminiArrayConf val cols = cmd.rs1(32 + log2Up(block_cols + 1) - 1, 32) val compute_rows = Mux(a_transpose, cols, total_rows) * a_stride - op1.bits.start := start + (mats - 1.U) * k * block_rows.U - op1.bits.end := start + compute_rows - op1.bits.wraps_around := start.add_with_overflow(compute_rows)._2 + op1.bits.end := op1.bits.start + compute_rows + op1.bits.wraps_around := op1.bits.start.add_with_overflow(compute_rows)._2 } op2.valid := funct_is_compute || funct === STORE_CMD op2.bits.start := cmd.rs2.asTypeOf(local_addr_t) when (funct_is_compute) { - /* val rows = cmd.rs2(48 + mvin_cols_bits - 1, 48) val k = Cat(cmd.inst.opcode, cmd.inst.rs1, cmd.inst.rs2, cmd.inst.rd) // TODO this needs to use J rather than K @@ -239,9 +235,6 @@ class ROB[T <: Data : Arithmetic, U <: Data, V <: Data](config: GemminiArrayConf op2.bits.end := op2.bits.start + total_rows op2.bits.wraps_around := op2.bits.start.add_with_overflow(total_rows)._2 - */ - op2.bits.end := GARBAGE_ADDR.asTypeOf(local_addr_t) - op2.bits.wraps_around := false.B }.elsewhen (pooling_is_enabled) { // If pooling is enabled, then we assume that this command simply mvouts everything in this accumulator bank from // start to the end of the bank // TODO this won't work when acc_banks =/= 2 @@ -310,7 +303,6 @@ class ROB[T <: Data : Arithmetic, U <: Data, V <: Data](config: GemminiArrayConf val opa_matches_opa = VecInit(entries.map { e => e.valid && e.bits.opa.valid && new_entry.opa.bits.overlaps(e.bits.opa.bits) }) // This can be WAW dst <- dst val opa_matches_opa_for_waws = VecInit(entries.map { e => e.valid && e.bits.opa.valid && new_entry.opa.bits.overlaps(e.bits.opa.bits, check_accumulates=true) }) - val opa_matches_opa_for_waws_for_ex = VecInit(entries.map { e => e.valid && e.bits.opa.valid && new_entry.opa.bits.start === e.bits.opa.bits.start }) // This can be WAR dst <- op1/op2 val opa_matches_opb = VecInit(entries.map { e => e.valid && e.bits.opb.valid && new_entry.opa.bits.overlaps(e.bits.opb.bits) }) // This can be RAW op2 <- dst @@ -325,14 +317,9 @@ class ROB[T <: Data : Arithmetic, U <: Data, V <: Data](config: GemminiArrayConf val dst_matches_opa = VecInit((entries zip opa_matches_opa).map { case (e, a) => e.valid && dst.valid && a }) - /* val dst_matches_opa_for_waws = VecInit((entries zip opa_matches_opa_for_waws).map { case (e, a) => e.valid && dst.valid && a }) - */ - val dst_matches_opa_for_waws = VecInit((entries, opa_matches_opa_for_waws, opa_matches_opa_for_waws_for_ex).zipped.map { case (e, a, b) => - e.valid && dst.valid && Mux(new_entry.q === exq && e.bits.q === exq, b, a) - }) val dst_matches_opb = VecInit((entries zip opa_matches_opb).map { case (e, b) => e.valid && dst.valid && b }) From c996a3881b79e65baef98b1e7fb60d4ac139a878 Mon Sep 17 00:00:00 2001 From: Hasan Genc Date: Fri, 25 Jun 2021 02:09:17 +0300 Subject: [PATCH 51/78] Add 2 dimensions to ROB overlap checks --- src/main/scala/gemmini/Controller.scala | 19 +++- src/main/scala/gemmini/LoopMatmul.scala | 115 +++++++++++++++++------- src/main/scala/gemmini/ROB.scala | 95 ++++++++++++++++---- 3 files changed, 173 insertions(+), 56 deletions(-) diff --git a/src/main/scala/gemmini/Controller.scala b/src/main/scala/gemmini/Controller.scala index e732cf844..cc06e9758 100644 --- a/src/main/scala/gemmini/Controller.scala +++ b/src/main/scala/gemmini/Controller.scala @@ -17,6 +17,14 @@ class GemminiCmd(rob_entries: Int)(implicit p: Parameters) extends Bundle { val cmd = new RoCCCommand val rob_id = UDValid(UInt(log2Up(rob_entries).W)) + val i = UInt(16.W) // TODO magic numbers + val j = UInt(16.W) // TODO magic numbers + val k = UInt(16.W) // TODO magic numbers + val max_i = UInt(16.W) // TODO magic numbers + val max_j = UInt(16.W) // TODO magic numbers + val max_k = UInt(16.W) // TODO magic numbers + val use_iterators = Bool() + override def cloneType: this.type = new GemminiCmd(rob_entries).asInstanceOf[this.type] } @@ -105,7 +113,7 @@ class GemminiModule[T <: Data: Arithmetic, U <: Data, V <: Data] */ // Incoming commands and ROB - val rob = Module(new ROB(outer.config, new RoCCCommand)) + val rob = Module(new ROB(outer.config, new RoCCCommand, new GemminiCmd(rob_entries))) val raw_cmd = Queue(io.cmd) @@ -125,7 +133,7 @@ class GemminiModule[T <: Data: Arithmetic, U <: Data, V <: Data] val (loop_cmd, loop_matmul_unroller_busy) = LoopMatmul(conv_cmd, rob.io.ld_utilization, rob.io.st_utilization, rob.io.ex_utilization, meshRows*tileRows, coreMaxAddrBits, rob_entries, max_lds, max_exs, max_sts, sp_banks * sp_bank_entries, acc_banks * acc_bank_entries, - inputType.getWidth, accType.getWidth, dma_maxbytes) + inputType.getWidth, accType.getWidth, dma_maxbytes, new GemminiCmd(rob_entries)) val unrolled_cmd = Queue(loop_cmd) unrolled_cmd.ready := false.B @@ -205,18 +213,21 @@ class GemminiModule[T <: Data: Arithmetic, U <: Data, V <: Data] load_controller.io.cmd.valid := rob_issue_ld.valid rob_issue_ld.ready := load_controller.io.cmd.ready + load_controller.io.cmd.bits := DontCare load_controller.io.cmd.bits.cmd := rob_issue_ld.cmd load_controller.io.cmd.bits.cmd.inst.funct := rob_issue_ld.cmd.inst.funct load_controller.io.cmd.bits.rob_id.push(rob_issue_ld.rob_id) store_controller.io.cmd.valid := rob.io.issue.st.valid rob.io.issue.st.ready := store_controller.io.cmd.ready + store_controller.io.cmd.bits := DontCare store_controller.io.cmd.bits.cmd := rob.io.issue.st.cmd store_controller.io.cmd.bits.cmd.inst.funct := rob.io.issue.st.cmd.inst.funct store_controller.io.cmd.bits.rob_id.push(rob.io.issue.st.rob_id) ex_controller.io.cmd.valid := rob_issue_ex.valid rob_issue_ex.ready := ex_controller.io.cmd.ready + ex_controller.io.cmd.bits := DontCare ex_controller.io.cmd.bits.cmd := rob_issue_ex.cmd ex_controller.io.cmd.bits.cmd.inst.funct := rob_issue_ex.cmd.inst.funct ex_controller.io.cmd.bits.rob_id.push(rob_issue_ex.rob_id) @@ -353,7 +364,7 @@ class GemminiModule[T <: Data: Arithmetic, U <: Data, V <: Data] // val config_cmd_type = cmd.bits.rs1(1,0) // TODO magic numbers //val funct = unrolled_cmd.bits.inst.funct - val risc_funct = unrolled_cmd.bits.inst.funct + val risc_funct = unrolled_cmd.bits.cmd.inst.funct val is_flush = risc_funct === FLUSH_CMD /* @@ -365,7 +376,7 @@ class GemminiModule[T <: Data: Arithmetic, U <: Data, V <: Data] when (is_flush) { // val skip = compressed_cmd.bits.rs1(0) - val skip = unrolled_cmd.bits.rs1(0) + val skip = unrolled_cmd.bits.cmd.rs1(0) tlb.io.exp.flush_skip := skip tlb.io.exp.flush_retry := !skip diff --git a/src/main/scala/gemmini/LoopMatmul.scala b/src/main/scala/gemmini/LoopMatmul.scala index fe6b778d0..e15f38bc4 100644 --- a/src/main/scala/gemmini/LoopMatmul.scala +++ b/src/main/scala/gemmini/LoopMatmul.scala @@ -23,11 +23,11 @@ class LoopMatmulLdAReq(val block_size: Int, val coreMaxAddrBits: Int, val iterat } class LoopMatmulLdA(block_size: Int, coreMaxAddrBits: Int, iterator_bitwidth: Int, max_addr: Int, input_w: Int, - max_block_len: Int, concurrent_loops: Int) + max_block_len: Int, concurrent_loops: Int, cmd_t: GemminiCmd) (implicit p: Parameters) extends Module { val io = IO(new Bundle { val req = Flipped(Decoupled(new LoopMatmulLdAReq(block_size, coreMaxAddrBits, iterator_bitwidth, max_addr, concurrent_loops))) - val cmd = Decoupled(Output(new RoCCCommand)) + val cmd = Decoupled(Output(cmd_t)) val i = Output(UInt(iterator_bitwidth.W)) val k = Output(UInt(iterator_bitwidth.W)) val idle = Output(Bool()) @@ -78,7 +78,15 @@ class LoopMatmulLdA(block_size: Int, coreMaxAddrBits: Int, iterator_bitwidth: In io.idle := state === idle io.cmd.valid := state =/= idle && !io.rob_overloaded - io.cmd.bits := mvin_cmd + io.cmd.bits.cmd := mvin_cmd + io.cmd.bits.rob_id := DontCare + io.cmd.bits.i := i + io.cmd.bits.j := DontCare + io.cmd.bits.k := k + io.cmd.bits.max_i := req.max_i + io.cmd.bits.max_j := DontCare + io.cmd.bits.max_k := req.max_k + io.cmd.bits.use_iterators := true.B io.loop_id := req.loop_id @@ -121,11 +129,11 @@ class LoopMatmulLdBReq(val block_size: Int, val coreMaxAddrBits: Int, val iterat } class LoopMatmulLdB(block_size: Int, coreMaxAddrBits: Int, iterator_bitwidth: Int, max_addr: Int, input_w: Int, - max_block_len: Int, concurrent_loops: Int) + max_block_len: Int, concurrent_loops: Int, cmd_t: GemminiCmd) (implicit p: Parameters) extends Module { val io = IO(new Bundle { val req = Flipped(Decoupled(new LoopMatmulLdBReq(block_size, coreMaxAddrBits, iterator_bitwidth, max_addr, concurrent_loops))) - val cmd = Decoupled(Output(new RoCCCommand)) + val cmd = Decoupled(Output(cmd_t)) val k = Output(UInt(iterator_bitwidth.W)) val j = Output(UInt(iterator_bitwidth.W)) @@ -179,7 +187,15 @@ class LoopMatmulLdB(block_size: Int, coreMaxAddrBits: Int, iterator_bitwidth: In io.idle := state === idle io.cmd.valid := state =/= idle && !io.rob_overloaded - io.cmd.bits := mvin_cmd + io.cmd.bits.cmd := mvin_cmd + io.cmd.bits.rob_id := DontCare + io.cmd.bits.i := DontCare + io.cmd.bits.j := j + io.cmd.bits.k := k + io.cmd.bits.max_i := DontCare + io.cmd.bits.max_j := req.max_j + io.cmd.bits.max_k := req.max_k + io.cmd.bits.use_iterators := true.B io.loop_id := req.loop_id @@ -222,11 +238,11 @@ class LoopMatmulLdDReq(val block_size: Int, val coreMaxAddrBits: Int, val iterat } class LoopMatmulLdD(block_size: Int, coreMaxAddrBits: Int, iterator_bitwidth: Int, max_acc_addr: Int, input_w: Int, - acc_w: Int, max_block_len: Int, max_block_len_acc: Int, concurrent_loops: Int) + acc_w: Int, max_block_len: Int, max_block_len_acc: Int, concurrent_loops: Int, cmd_t: GemminiCmd) (implicit p: Parameters) extends Module { val io = IO(new Bundle { val req = Flipped(Decoupled(new LoopMatmulLdDReq(block_size, coreMaxAddrBits, iterator_bitwidth, max_acc_addr, concurrent_loops))) - val cmd = Decoupled(Output(new RoCCCommand)) + val cmd = Decoupled(Output(cmd_t)) val idle = Output(Bool()) val rob_overloaded = Input(Bool()) @@ -268,7 +284,15 @@ class LoopMatmulLdD(block_size: Int, coreMaxAddrBits: Int, iterator_bitwidth: In // The order here is k, j, i io.cmd.valid := state =/= idle && !io.rob_overloaded && req.dram_addr =/= 0.U - io.cmd.bits := mvin_cmd + io.cmd.bits.cmd := mvin_cmd + io.cmd.bits.rob_id := DontCare + io.cmd.bits.i := i + io.cmd.bits.j := j + io.cmd.bits.k := DontCare + io.cmd.bits.max_i := req.max_i + io.cmd.bits.max_j := req.max_j + io.cmd.bits.max_k := DontCare + io.cmd.bits.use_iterators := true.B io.loop_id := req.loop_id @@ -313,23 +337,23 @@ class LoopMatmulExecuteReq(val block_size: Int, val coreMaxAddrBits: Int, val it val loop_id = UInt(log2Up(concurrent_loops).W) } -class LoopMatmulExecute(block_size: Int, coreMaxAddrBits: Int, iterator_bitwidth: Int, max_addr: Int, max_acc_addr: Int, max_block_len: Int, concurrent_loops: Int) +class LoopMatmulExecute(block_size: Int, coreMaxAddrBits: Int, iterator_bitwidth: Int, max_addr: Int, max_acc_addr: Int, max_block_len: Int, concurrent_loops: Int, cmd_t: GemminiCmd) (implicit p: Parameters) extends Module { val GARBAGE_ADDR = (~0.U(32.W)).asUInt() - val cmd_t = new RoCCCommand + val rocc_cmd_t = new RoCCCommand class blocks_holder_t extends Bundle { - val opcode = UInt(cmd_t.inst.opcode.getWidth.W) - val rs1 = UInt(cmd_t.inst.rs1.getWidth.W) - val rs2 = UInt(cmd_t.inst.rs2.getWidth.W) - val rd = UInt(cmd_t.inst.rd.getWidth.W) + val opcode = UInt(rocc_cmd_t.inst.opcode.getWidth.W) + val rs1 = UInt(rocc_cmd_t.inst.rs1.getWidth.W) + val rs2 = UInt(rocc_cmd_t.inst.rs2.getWidth.W) + val rd = UInt(rocc_cmd_t.inst.rd.getWidth.W) override def cloneType: blocks_holder_t.this.type = (new blocks_holder_t).asInstanceOf[this.type] } val io = IO(new Bundle { val req = Flipped(Decoupled(new LoopMatmulExecuteReq(block_size, coreMaxAddrBits, iterator_bitwidth, max_addr, max_acc_addr, concurrent_loops))) - val cmd = Decoupled(Output(new RoCCCommand)) + val cmd = Decoupled(Output(cmd_t)) val k = Output(UInt(iterator_bitwidth.W)) val j = Output(UInt(iterator_bitwidth.W)) @@ -428,7 +452,15 @@ class LoopMatmulExecute(block_size: Int, coreMaxAddrBits: Int, iterator_bitwidth val ld_ahead = lda_ahead && ldb_ahead && ldd_ahead io.cmd.valid := state =/= idle && !io.rob_overloaded && ld_ahead - io.cmd.bits := Mux(state === pre, pre_cmd, comp_cmd) + io.cmd.bits.cmd := Mux(state === pre, pre_cmd, comp_cmd) + io.cmd.bits.rob_id := DontCare + io.cmd.bits.i := i + io.cmd.bits.j := j + io.cmd.bits.k := k + io.cmd.bits.max_i := req.max_i + io.cmd.bits.max_j := req.max_j + io.cmd.bits.max_k := req.max_k + io.cmd.bits.use_iterators := true.B io.loop_id := req.loop_id @@ -474,11 +506,11 @@ class LoopMatmulStCReq(val block_size: Int, val coreMaxAddrBits: Int, val iterat val loop_id = UInt(log2Up(concurrent_loops).W) } -class LoopMatmulStC(block_size: Int, coreMaxAddrBits: Int, iterator_bitwidth: Int, max_acc_addr: Int, input_w: Int, acc_w: Int, max_block_len: Int, concurrent_loops: Int) +class LoopMatmulStC(block_size: Int, coreMaxAddrBits: Int, iterator_bitwidth: Int, max_acc_addr: Int, input_w: Int, acc_w: Int, max_block_len: Int, concurrent_loops: Int, cmd_t: GemminiCmd) (implicit p: Parameters) extends Module { val io = IO(new Bundle { val req = Flipped(Decoupled(new LoopMatmulStCReq(block_size, coreMaxAddrBits, iterator_bitwidth, max_acc_addr, concurrent_loops))) - val cmd = Decoupled(Output(new RoCCCommand)) + val cmd = Decoupled(Output(cmd_t)) val ex_k = Input(UInt(iterator_bitwidth.W)) val ex_j = Input(UInt(iterator_bitwidth.W)) @@ -535,7 +567,15 @@ class LoopMatmulStC(block_size: Int, coreMaxAddrBits: Int, iterator_bitwidth: In ((io.ex_j === j + blocks - 1.U) && io.ex_i > i))) io.cmd.valid := state =/= idle && !io.rob_overloaded && ex_ahead && req.dram_addr =/= 0.U - io.cmd.bits := mvout_cmd + io.cmd.bits.cmd := mvout_cmd + io.cmd.bits.rob_id := DontCare + io.cmd.bits.i := i + io.cmd.bits.j := j + io.cmd.bits.k := DontCare + io.cmd.bits.max_i := req.max_i + io.cmd.bits.max_j := req.max_j + io.cmd.bits.max_k := DontCare + io.cmd.bits.use_iterators := true.B io.loop_id := req.loop_id @@ -633,7 +673,7 @@ class LoopMatmulState(val iterator_bitwidth: Int, val coreMaxAddrBits: Int, val } class LoopMatmul(block_size: Int, coreMaxAddrBits: Int, rob_size: Int, max_lds: Int, max_exs: Int, max_sts: Int, - max_addr: Int, max_acc_addr: Int, input_w: Int, acc_w: Int, dma_max_bytes: Int) + max_addr: Int, max_acc_addr: Int, input_w: Int, acc_w: Int, dma_max_bytes: Int, cmd_t: GemminiCmd) (implicit p: Parameters) extends Module { val iterator_bitwidth = 16 val max_block_len = (dma_max_bytes / (block_size * input_w / 8)) max 1 @@ -641,7 +681,7 @@ class LoopMatmul(block_size: Int, coreMaxAddrBits: Int, rob_size: Int, max_lds: val io = IO(new Bundle { val in = Flipped(Decoupled(new RoCCCommand)) - val out = Decoupled(new RoCCCommand) + val out = Decoupled(cmd_t) val ld_utilization = Input(UInt(log2Up(rob_size+1).W)) val st_utilization = Input(UInt(log2Up(rob_size+1).W)) val ex_utilization = Input(UInt(log2Up(rob_size+1).W)) @@ -662,11 +702,11 @@ class LoopMatmul(block_size: Int, coreMaxAddrBits: Int, rob_size: Int, max_lds: val loop_being_configured = loops(loop_being_configured_id) // Create inner modules - val ldA = Module(new LoopMatmulLdA(block_size, coreMaxAddrBits, iterator_bitwidth, max_addr, input_w, max_block_len, concurrent_loops)) - val ldB = Module(new LoopMatmulLdB(block_size, coreMaxAddrBits, iterator_bitwidth, max_addr, input_w, max_block_len, concurrent_loops)) - val ldD = Module(new LoopMatmulLdD(block_size, coreMaxAddrBits, iterator_bitwidth, max_acc_addr, input_w, acc_w, max_block_len, max_block_len_acc, concurrent_loops)) - val ex = Module(new LoopMatmulExecute(block_size, coreMaxAddrBits, iterator_bitwidth, max_addr, max_acc_addr, max_block_len, concurrent_loops)) - val stC = Module(new LoopMatmulStC(block_size, coreMaxAddrBits, iterator_bitwidth, max_acc_addr, input_w, acc_w, max_block_len, concurrent_loops)) + val ldA = Module(new LoopMatmulLdA(block_size, coreMaxAddrBits, iterator_bitwidth, max_addr, input_w, max_block_len, concurrent_loops, cmd_t)) + val ldB = Module(new LoopMatmulLdB(block_size, coreMaxAddrBits, iterator_bitwidth, max_addr, input_w, max_block_len, concurrent_loops, cmd_t)) + val ldD = Module(new LoopMatmulLdD(block_size, coreMaxAddrBits, iterator_bitwidth, max_acc_addr, input_w, acc_w, max_block_len, max_block_len_acc, concurrent_loops, cmd_t)) + val ex = Module(new LoopMatmulExecute(block_size, coreMaxAddrBits, iterator_bitwidth, max_addr, max_acc_addr, max_block_len, concurrent_loops, cmd_t)) + val stC = Module(new LoopMatmulStC(block_size, coreMaxAddrBits, iterator_bitwidth, max_acc_addr, input_w, acc_w, max_block_len, concurrent_loops, cmd_t)) // Create command queue val cmd = Queue(io.in) @@ -674,7 +714,7 @@ class LoopMatmul(block_size: Int, coreMaxAddrBits: Int, rob_size: Int, max_lds: io.busy := cmd.valid || loop_configured // Create ld arbiters - val ldab_arb = Module(new WeightedArbiter(new RoCCCommand(), maxWeightA=255)) // TODO magic numbers + val ldab_arb = Module(new WeightedArbiter(cmd_t, maxWeightA=255)) // TODO magic numbers ldab_arb.io.inA <> ldA.io.cmd ldab_arb.io.inB <> ldB.io.cmd val ab_loads_on_same_loop = ldA.io.loop_id === ldB.io.loop_id @@ -683,7 +723,7 @@ class LoopMatmul(block_size: Int, coreMaxAddrBits: Int, rob_size: Int, max_lds: ldab_arb.io.weightA := head_loop.weightA // Create global arbiter - val arb = Module(new Arbiter(new RoCCCommand(), 4)) + val arb = Module(new Arbiter(cmd_t, 4)) arb.io.in(0) <> stC.io.cmd arb.io.in(1) <> ex.io.cmd arb.io.in(2) <> ldD.io.cmd @@ -695,8 +735,15 @@ class LoopMatmul(block_size: Int, coreMaxAddrBits: Int, rob_size: Int, max_lds: val is_loop_config_cmd = cmd.bits.inst.funct >= LOOP_WS_CONFIG_BOUNDS && cmd.bits.inst.funct <= LOOP_WS_CONFIG_STRIDES_DC val is_loop_cmd = is_loop_run_cmd || is_loop_config_cmd - io.out.bits := Mux(loop_configured, unrolled_cmd.bits, cmd.bits) - io.out.bits.status := cmd.bits.status // TODO This is not guaranteed to be the correct fix! We must fix this + // io.out.bits := Mux(loop_configured, unrolled_cmd.bits, cmd.bits) + when (loop_configured) { + io.out.bits := unrolled_cmd.bits + }.otherwise { + io.out.bits := DontCare + io.out.bits.cmd := cmd.bits + io.out.bits.use_iterators := false.B + } + io.out.bits.cmd.status := cmd.bits.status // TODO This is not guaranteed to be the correct fix! We must fix this io.out.valid := Mux(loop_configured, unrolled_cmd.valid, cmd.valid && !is_loop_config_cmd && !is_loop_run_cmd) cmd.ready := Mux(is_loop_cmd, !loop_being_configured.configured, !loop_configured && io.out.ready) @@ -935,10 +982,10 @@ class LoopMatmul(block_size: Int, coreMaxAddrBits: Int, rob_size: Int, max_lds: object LoopMatmul { def apply(in: DecoupledIO[RoCCCommand], ld_utilization: UInt, st_utilization: UInt, ex_utilization: UInt, block_size: Int, coreMaxAddrBits: Int, rob_size: Int, max_lds: Int, max_exs: Int, max_sts: Int, - max_addr: Int, max_acc_addr: Int, input_w: Int, acc_w: Int, dma_max_bytes: Int) - (implicit p: Parameters): Tuple2[DecoupledIO[RoCCCommand], Bool] = { + max_addr: Int, max_acc_addr: Int, input_w: Int, acc_w: Int, dma_max_bytes: Int, cmd_t: GemminiCmd) + (implicit p: Parameters): Tuple2[DecoupledIO[GemminiCmd], Bool] = { val mod = Module(new LoopMatmul(block_size, coreMaxAddrBits, rob_size, max_lds, max_exs, max_sts, - max_addr, max_acc_addr, input_w, acc_w, dma_max_bytes)) + max_addr, max_acc_addr, input_w, acc_w, dma_max_bytes, cmd_t)) mod.io.in <> in mod.io.ld_utilization := ld_utilization mod.io.st_utilization := st_utilization diff --git a/src/main/scala/gemmini/ROB.scala b/src/main/scala/gemmini/ROB.scala index a2b549550..84326a46f 100644 --- a/src/main/scala/gemmini/ROB.scala +++ b/src/main/scala/gemmini/ROB.scala @@ -21,14 +21,14 @@ class ROBIssue[T <: Data](cmd_t: T, rob_entries: Int) extends Bundle { } // TODO we don't need to store the full command in here. We should be able to release the command directly into the relevant controller and only store the associated metadata in the ROB. This would reduce the size considerably -class ROB[T <: Data : Arithmetic, U <: Data, V <: Data](config: GemminiArrayConfig[T, U, V], cmd_t: RoCCCommand) extends Module { +class ROB[T <: Data : Arithmetic, U <: Data, V <: Data](config: GemminiArrayConfig[T, U, V], cmd_t: RoCCCommand, gemmini_cmd_t: GemminiCmd) extends Module { import config._ val block_rows = tileRows * meshRows val block_cols = tileColumns * meshColumns val io = IO(new Bundle { - val alloc = Flipped(Decoupled(cmd_t.cloneType)) + val alloc = Flipped(Decoupled(gemmini_cmd_t.cloneType)) val completed = Flipped(Valid(UInt(log2Up(rob_entries).W))) @@ -47,11 +47,6 @@ class ROB[T <: Data : Arithmetic, U <: Data, V <: Data](config: GemminiArrayConf val solitary_preload = Input(Bool()) // TODO very hacky. from ExecuteController, to prevent infinite fence stalls. remove later }) - println(s"\n\nio.alloc.bits.inst.rs1.getWidth = ${io.alloc.bits.inst.rs1.getWidth}") - println(s"io.alloc.bits.inst.rs2.getWidth = ${io.alloc.bits.inst.rs2.getWidth}") - println(s"io.alloc.bits.inst.rd.getWidth = ${io.alloc.bits.inst.rd.getWidth}") - println(s"io.alloc.bits.inst.opcode.getWidth = ${io.alloc.bits.inst.opcode.getWidth}\n\n") - // TODO make this a ChiselEnum val ldq :: stq :: exq :: Nil = Enum(3) val q_t = ldq.cloneType @@ -61,12 +56,41 @@ class ROB[T <: Data : Arithmetic, U <: Data, V <: Data](config: GemminiArrayConf val end = local_addr_t.cloneType val wraps_around = Bool() - def overlaps(other: OpT, check_accumulates: Boolean=false): Bool = { - ((other.start <= start && (start < other.end || other.wraps_around)) || + val i = UInt(16.W) + val j = UInt(16.W) + val k = UInt(16.W) + val i_len = UInt(16.W) + val j_len = UInt(16.W) + val k_len = UInt(16.W) + val use_iterators = Bool() + + def overlaps(other: OpT, check_accumulates: Boolean=false, compare_i_and_k: Bool=false.B, compare_i_and_j: Bool=false.B): Bool = { + val without_iterators = ((other.start <= start && (start < other.end || other.wraps_around)) || (start <= other.start && (other.start < end || wraps_around))) && (!check_accumulates.B || !(start.is_acc_addr && start.accumulate && other.start.is_acc_addr && other.start.accumulate)) && !(start.is_garbage() || other.start.is_garbage()) // TODO the "is_garbage" check might not really be necessary + + val with_iterators_ik = ((other.i <= i && (i < other.i + other.i_len)) || + (i <= other.i && other.i < i + i_len)) && + ((other.k <= k && (k < other.k + other.k_len)) || + (k <= other.k && other.k < k + k_len)) && + (!check_accumulates.B || + !(start.is_acc_addr && start.accumulate && other.start.is_acc_addr && other.start.accumulate)) && + !(start.is_garbage() || other.start.is_garbage()) // TODO the "is_garbage" check might not really be necessary + + val with_iterators_ij = ((other.i <= i && (i < other.i + other.i_len)) || + (i <= other.i && other.i < i + i_len)) && + ((other.j <= j && (j < other.j + other.j_len)) || + (j <= other.j && other.j < j + j_len)) && + (!check_accumulates.B || + !(start.is_acc_addr && start.accumulate && other.start.is_acc_addr && other.start.accumulate)) && + !(start.is_garbage() || other.start.is_garbage()) // TODO the "is_garbage" check might not really be necessary + + assert(!(compare_i_and_j && compare_i_and_k)) + assert(!compare_i_and_j || !compare_i_and_k || (use_iterators && other.use_iterators)) + + Mux(compare_i_and_k, with_iterators_ik, Mux(compare_i_and_j, with_iterators_ij, without_iterators)) } } @@ -173,7 +197,8 @@ class ROB[T <: Data : Arithmetic, U <: Data, V <: Data](config: GemminiArrayConf io.alloc.ready := false.B when (io.alloc.valid) { val spAddrBits = 32 - val cmd = io.alloc.bits + val gemmini_cmd = io.alloc.bits + val cmd = io.alloc.bits.cmd val funct = cmd.inst.funct val funct_is_compute = funct === COMPUTE_AND_STAY_CMD || funct === COMPUTE_AND_FLIP_CMD val config_cmd_type = cmd.rs1(1,0) // TODO magic numbers @@ -186,12 +211,33 @@ class ROB[T <: Data : Arithmetic, U <: Data, V <: Data](config: GemminiArrayConf val op1 = Wire(UDValid(new OpT)) op1.valid := false.B op1.bits := DontCare + op1.bits.i := gemmini_cmd.i + op1.bits.j := gemmini_cmd.j + op1.bits.k := gemmini_cmd.k + op1.bits.i_len := 1.U + op1.bits.j_len := 1.U + op1.bits.k_len := 1.U + op1.bits.use_iterators := gemmini_cmd.use_iterators val op2 = Wire(UDValid(new OpT)) op2.valid := false.B op2.bits := DontCare + op2.bits.i := gemmini_cmd.i + op2.bits.j := gemmini_cmd.j + op2.bits.k := gemmini_cmd.k + op2.bits.i_len := 1.U + op2.bits.j_len := 1.U + op2.bits.k_len := 1.U + op2.bits.use_iterators := gemmini_cmd.use_iterators val dst = Wire(UDValid(new OpT)) dst.valid := false.B dst.bits := DontCare + dst.bits.i := gemmini_cmd.i + dst.bits.j := gemmini_cmd.j + dst.bits.k := gemmini_cmd.k + dst.bits.i_len := 1.U + dst.bits.j_len := 1.U + dst.bits.k_len := 1.U + dst.bits.use_iterators := gemmini_cmd.use_iterators assert(!(op1.valid && op2.valid && dst.valid)) new_entry.opa_is_dst := dst.valid @@ -212,7 +258,7 @@ class ROB[T <: Data : Arithmetic, U <: Data, V <: Data](config: GemminiArrayConf op1.bits.wraps_around := op1.bits.start.add_with_overflow(preload_rows)._2 }.otherwise { val rows = cmd.rs1(48 + mvin_cols_bits - 1, 48) - val k = Cat(cmd.inst.opcode, cmd.inst.rs1, cmd.inst.rs2, cmd.inst.rd) + val k = gemmini_cmd.max_k val mats = rows / block_rows.U + (rows % block_rows.U =/= 0.U) val total_rows = ((mats - 1.U) * k * block_rows.U) + Mux(rows % block_rows.U === 0.U, block_rows.U, rows % block_rows.U) @@ -222,19 +268,26 @@ class ROB[T <: Data : Arithmetic, U <: Data, V <: Data](config: GemminiArrayConf op1.bits.end := op1.bits.start + compute_rows op1.bits.wraps_around := op1.bits.start.add_with_overflow(compute_rows)._2 + + op1.bits.i_len := mats } op2.valid := funct_is_compute || funct === STORE_CMD op2.bits.start := cmd.rs2.asTypeOf(local_addr_t) when (funct_is_compute) { + /* val rows = cmd.rs2(48 + mvin_cols_bits - 1, 48) - val k = Cat(cmd.inst.opcode, cmd.inst.rs1, cmd.inst.rs2, cmd.inst.rd) // TODO this needs to use J rather than K + val j = gemmini_cmd.max_j val mats = rows / block_rows.U + (rows % block_rows.U =/= 0.U) - val total_rows = ((mats - 1.U) * k * block_rows.U) + Mux(rows % block_rows.U === 0.U, block_rows.U, rows % block_rows.U) + val total_rows = ((mats - 1.U) * j * block_rows.U) + Mux(rows % block_rows.U === 0.U, block_rows.U, rows % block_rows.U) op2.bits.end := op2.bits.start + total_rows op2.bits.wraps_around := op2.bits.start.add_with_overflow(total_rows)._2 + */ + + op2.bits.end := GARBAGE_ADDR.asTypeOf(local_addr_t) + op2.bits.wraps_around := false.B }.elsewhen (pooling_is_enabled) { // If pooling is enabled, then we assume that this command simply mvouts everything in this accumulator bank from // start to the end of the bank // TODO this won't work when acc_banks =/= 2 @@ -257,13 +310,15 @@ class ROB[T <: Data : Arithmetic, U <: Data, V <: Data](config: GemminiArrayConf op2.bits.end := op2.bits.start + total_mvout_rows op2.bits.wraps_around := pooling_is_enabled || op2.bits.start.add_with_overflow(total_mvout_rows)._2 + + op2.bits.j_len := mvout_mats } dst.valid := funct === PRELOAD_CMD || funct === LOAD_CMD || funct === LOAD2_CMD || funct === LOAD3_CMD dst.bits.start := cmd.rs2(31, 0).asTypeOf(local_addr_t) when (funct === PRELOAD_CMD) { val rows = cmd.rs2(48 + mvin_cols_bits - 1, 48) - val j = Cat(cmd.inst.opcode, cmd.inst.rs1, cmd.inst.rs2, cmd.inst.rd) + val j = gemmini_cmd.max_j val mats = rows / block_rows.U + (rows % block_rows.U =/= 0.U) val total_rows = ((mats - 1.U) * j * block_rows.U) + Mux(rows % block_rows.U === 0.U, block_rows.U, rows % block_rows.U) @@ -272,6 +327,8 @@ class ROB[T <: Data : Arithmetic, U <: Data, V <: Data](config: GemminiArrayConf dst.bits.end := dst.bits.start + preload_rows dst.bits.wraps_around := dst.bits.start.add_with_overflow(preload_rows)._2 + + dst.bits.i_len := mats }.otherwise { val id = MuxCase(0.U, Seq((new_entry.cmd.inst.funct === LOAD2_CMD) -> 1.U, (new_entry.cmd.inst.funct === LOAD3_CMD) -> 2.U)) @@ -285,6 +342,8 @@ class ROB[T <: Data : Arithmetic, U <: Data, V <: Data](config: GemminiArrayConf dst.bits.end := dst.bits.start + total_mvin_rows dst.bits.wraps_around := dst.bits.start.add_with_overflow(total_mvin_rows)._2 + + dst.bits.k_len := mvin_mats } val is_load = funct === LOAD_CMD || funct === LOAD2_CMD || funct === LOAD3_CMD || (funct === CONFIG_CMD && config_cmd_type === CONFIG_LOAD) @@ -300,13 +359,13 @@ class ROB[T <: Data : Arithmetic, U <: Data, V <: Data](config: GemminiArrayConf assert(is_load || is_store || is_ex) // This can be RAW op1/op2 <- dst - val opa_matches_opa = VecInit(entries.map { e => e.valid && e.bits.opa.valid && new_entry.opa.bits.overlaps(e.bits.opa.bits) }) + val opa_matches_opa = VecInit(entries.map { e => e.valid && e.bits.opa.valid && new_entry.opa.bits.overlaps(e.bits.opa.bits, compare_i_and_k=(new_entry.q === exq && e.bits.q === ldq && new_entry.opa.bits.use_iterators)) }) // This can be WAW dst <- dst - val opa_matches_opa_for_waws = VecInit(entries.map { e => e.valid && e.bits.opa.valid && new_entry.opa.bits.overlaps(e.bits.opa.bits, check_accumulates=true) }) + val opa_matches_opa_for_waws = VecInit(entries.map { e => e.valid && e.bits.opa.valid && new_entry.opa.bits.overlaps(e.bits.opa.bits, check_accumulates=true, compare_i_and_j=(new_entry.q === exq && e.bits.q === exq && new_entry.opa.bits.use_iterators)) }) // This can be WAR dst <- op1/op2 val opa_matches_opb = VecInit(entries.map { e => e.valid && e.bits.opb.valid && new_entry.opa.bits.overlaps(e.bits.opb.bits) }) // This can be RAW op2 <- dst - val opb_matches_opa = VecInit(entries.map { e => e.valid && e.bits.opa.valid && new_entry.opb.bits.overlaps(e.bits.opa.bits) }) + val opb_matches_opa = VecInit(entries.map { e => e.valid && e.bits.opa.valid && new_entry.opb.bits.overlaps(e.bits.opa.bits, compare_i_and_k=(new_entry.q === exq && e.bits.q === ldq && new_entry.opa.bits.use_iterators)) }) val op1_matches_opa = VecInit((entries zip (opa_matches_opa zip opb_matches_opa)).map { case (e, (a, b)) => e.valid && op1.valid && Mux(dst.valid, b, a) @@ -564,7 +623,7 @@ class ROB[T <: Data : Arithmetic, U <: Data, V <: Data](config: GemminiArrayConf } val first_preload_allocated = RegInit(false.B) - when (io.alloc.fire() && io.alloc.bits.inst.funct === PRELOAD_CMD) { + when (io.alloc.fire() && io.alloc.bits.cmd.inst.funct === PRELOAD_CMD) { first_preload_allocated := true.B } val cycles_that_ex_stalls_due_to_dependencies = RegInit(0.U(32.W)) From cb7d5c635c20b25aa16e40c2b20af9fc0284c53b Mon Sep 17 00:00:00 2001 From: Hasan Genc Date: Fri, 25 Jun 2021 22:42:08 +0300 Subject: [PATCH 52/78] Tighten requirements for iterator-checking in ROB --- src/main/scala/gemmini/ROB.scala | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/scala/gemmini/ROB.scala b/src/main/scala/gemmini/ROB.scala index 84326a46f..4dc76b29b 100644 --- a/src/main/scala/gemmini/ROB.scala +++ b/src/main/scala/gemmini/ROB.scala @@ -359,13 +359,13 @@ class ROB[T <: Data : Arithmetic, U <: Data, V <: Data](config: GemminiArrayConf assert(is_load || is_store || is_ex) // This can be RAW op1/op2 <- dst - val opa_matches_opa = VecInit(entries.map { e => e.valid && e.bits.opa.valid && new_entry.opa.bits.overlaps(e.bits.opa.bits, compare_i_and_k=(new_entry.q === exq && e.bits.q === ldq && new_entry.opa.bits.use_iterators)) }) + val opa_matches_opa = VecInit(entries.map { e => e.valid && e.bits.opa.valid && new_entry.opa.bits.overlaps(e.bits.opa.bits, compare_i_and_k=(funct_is_compute && e.bits.cmd.inst.funct === LOAD_CMD && new_entry.opa.bits.use_iterators)) }) // This can be WAW dst <- dst - val opa_matches_opa_for_waws = VecInit(entries.map { e => e.valid && e.bits.opa.valid && new_entry.opa.bits.overlaps(e.bits.opa.bits, check_accumulates=true, compare_i_and_j=(new_entry.q === exq && e.bits.q === exq && new_entry.opa.bits.use_iterators)) }) + val opa_matches_opa_for_waws = VecInit(entries.map { e => e.valid && e.bits.opa.valid && new_entry.opa.bits.overlaps(e.bits.opa.bits, check_accumulates=true, compare_i_and_j=(funct === PRELOAD_CMD && e.bits.cmd.inst.funct === PRELOAD_CMD && new_entry.opa.bits.use_iterators)) }) // This can be WAR dst <- op1/op2 val opa_matches_opb = VecInit(entries.map { e => e.valid && e.bits.opb.valid && new_entry.opa.bits.overlaps(e.bits.opb.bits) }) // This can be RAW op2 <- dst - val opb_matches_opa = VecInit(entries.map { e => e.valid && e.bits.opa.valid && new_entry.opb.bits.overlaps(e.bits.opa.bits, compare_i_and_k=(new_entry.q === exq && e.bits.q === ldq && new_entry.opa.bits.use_iterators)) }) + val opb_matches_opa = VecInit(entries.map { e => e.valid && e.bits.opa.valid && new_entry.opb.bits.overlaps(e.bits.opa.bits, compare_i_and_k=(funct_is_compute && e.bits.cmd.inst.funct === LOAD_CMD && new_entry.opa.bits.use_iterators)) }) val op1_matches_opa = VecInit((entries zip (opa_matches_opa zip opb_matches_opa)).map { case (e, (a, b)) => e.valid && op1.valid && Mux(dst.valid, b, a) From 0713f83e29775f68fac4c586c8565d14e74d3844 Mon Sep 17 00:00:00 2001 From: Hasan Genc Date: Sat, 26 Jun 2021 22:14:51 +0300 Subject: [PATCH 53/78] Add dynamic interleaving for K --- src/main/scala/gemmini/Controller.scala | 6 +- .../scala/gemmini/ExecuteController.scala | 3 +- src/main/scala/gemmini/GemminiConfigs.scala | 2 + src/main/scala/gemmini/LoopMatmul.scala | 107 ++++++++++++++++-- src/main/scala/gemmini/ROB.scala | 10 ++ src/main/scala/gemmini/Util.scala | 4 +- 6 files changed, 116 insertions(+), 16 deletions(-) diff --git a/src/main/scala/gemmini/Controller.scala b/src/main/scala/gemmini/Controller.scala index cc06e9758..fe6ee88d9 100644 --- a/src/main/scala/gemmini/Controller.scala +++ b/src/main/scala/gemmini/Controller.scala @@ -25,6 +25,8 @@ class GemminiCmd(rob_entries: Int)(implicit p: Parameters) extends Bundle { val max_k = UInt(16.W) // TODO magic numbers val use_iterators = Bool() + val ex_k_portion = UInt(8.W) // TODO magic numbers + override def cloneType: this.type = new GemminiCmd(rob_entries).asInstanceOf[this.type] } @@ -131,9 +133,9 @@ class GemminiModule[T <: Data: Arithmetic, U <: Data, V <: Data] // val (unrolled_cmd, loop_matmul_unroller_busy) = LoopMatmul(unrolled_cmd_after_conv, rob.io.ld_utilization, rob.io.st_utilization, rob.io.ex_utilization, - val (loop_cmd, loop_matmul_unroller_busy) = LoopMatmul(conv_cmd, rob.io.ld_utilization, rob.io.st_utilization, rob.io.ex_utilization, + val (loop_cmd, loop_matmul_unroller_busy) = LoopMatmul(conv_cmd, rob.io.ld_utilization, rob.io.st_utilization, rob.io.ex_utilization, rob.io.ex_k_portion_utilizations, meshRows*tileRows, coreMaxAddrBits, rob_entries, max_lds, max_exs, max_sts, sp_banks * sp_bank_entries, acc_banks * acc_bank_entries, - inputType.getWidth, accType.getWidth, dma_maxbytes, new GemminiCmd(rob_entries)) + inputType.getWidth, accType.getWidth, dma_maxbytes, new GemminiCmd(rob_entries), ex_total_k_portions) val unrolled_cmd = Queue(loop_cmd) unrolled_cmd.ready := false.B diff --git a/src/main/scala/gemmini/ExecuteController.scala b/src/main/scala/gemmini/ExecuteController.scala index 02d6075fb..1744422d6 100644 --- a/src/main/scala/gemmini/ExecuteController.scala +++ b/src/main/scala/gemmini/ExecuteController.scala @@ -64,7 +64,8 @@ class ExecuteController[T <: Data, U <: Data, V <: Data](xLen: Int, tagWidth: In val cmd_q_heads = 3 assert(ex_queue_length >= cmd_q_heads) // val (cmd, _) = MultiHeadedQueue(io.cmd, ex_queue_length, cmd_q_heads) - val (cmd, _) = MultiHeadedQueue(unrolled_cmd, ex_queue_length, cmd_q_heads) + // val (cmd, _) = MultiHeadedQueue(unrolled_cmd, ex_queue_length, cmd_q_heads) + val (cmd, _) = MultiHeadedQueue(unrolled_cmd, rob_full_entries, cmd_q_heads) // TODO this should be ex_queue_length cmd.pop := 0.U io.solitary_preload := cmd.valid(0) && cmd.bits(0).cmd.inst.funct === PRELOAD_CMD && !cmd.valid(1) diff --git a/src/main/scala/gemmini/GemminiConfigs.scala b/src/main/scala/gemmini/GemminiConfigs.scala index a467bbcea..cfb5de9ad 100644 --- a/src/main/scala/gemmini/GemminiConfigs.scala +++ b/src/main/scala/gemmini/GemminiConfigs.scala @@ -112,6 +112,8 @@ case class GemminiArrayConfig[T <: Data : Arithmetic, U <: Data, V <: Data]( val load_states = 3 val block_stride_bits = 16 + val ex_total_k_portions = 2 + //========================================================================== // sanity check mesh size //========================================================================== diff --git a/src/main/scala/gemmini/LoopMatmul.scala b/src/main/scala/gemmini/LoopMatmul.scala index e15f38bc4..f4f423f55 100644 --- a/src/main/scala/gemmini/LoopMatmul.scala +++ b/src/main/scala/gemmini/LoopMatmul.scala @@ -87,6 +87,7 @@ class LoopMatmulLdA(block_size: Int, coreMaxAddrBits: Int, iterator_bitwidth: In io.cmd.bits.max_j := DontCare io.cmd.bits.max_k := req.max_k io.cmd.bits.use_iterators := true.B + io.cmd.bits.ex_k_portion := DontCare io.loop_id := req.loop_id @@ -196,6 +197,7 @@ class LoopMatmulLdB(block_size: Int, coreMaxAddrBits: Int, iterator_bitwidth: In io.cmd.bits.max_j := req.max_j io.cmd.bits.max_k := req.max_k io.cmd.bits.use_iterators := true.B + io.cmd.bits.ex_k_portion := DontCare io.loop_id := req.loop_id @@ -293,6 +295,7 @@ class LoopMatmulLdD(block_size: Int, coreMaxAddrBits: Int, iterator_bitwidth: In io.cmd.bits.max_j := req.max_j io.cmd.bits.max_k := DontCare io.cmd.bits.use_iterators := true.B + io.cmd.bits.ex_k_portion := DontCare io.loop_id := req.loop_id @@ -337,7 +340,7 @@ class LoopMatmulExecuteReq(val block_size: Int, val coreMaxAddrBits: Int, val it val loop_id = UInt(log2Up(concurrent_loops).W) } -class LoopMatmulExecute(block_size: Int, coreMaxAddrBits: Int, iterator_bitwidth: Int, max_addr: Int, max_acc_addr: Int, max_block_len: Int, concurrent_loops: Int, cmd_t: GemminiCmd) +class LoopMatmulExecute(block_size: Int, coreMaxAddrBits: Int, iterator_bitwidth: Int, max_addr: Int, max_acc_addr: Int, max_block_len: Int, concurrent_loops: Int, cmd_t: GemminiCmd, total_k_portions: Int, k_portion: Int) (implicit p: Parameters) extends Module { val GARBAGE_ADDR = (~0.U(32.W)).asUInt() @@ -370,6 +373,8 @@ class LoopMatmulExecute(block_size: Int, coreMaxAddrBits: Int, iterator_bitwidth val idle = Output(Bool()) val rob_overloaded = Input(Bool()) + val must_send_compute = Output(Bool()) + val loop_id = Output(UInt(log2Up(concurrent_loops).W)) }) @@ -383,6 +388,9 @@ class LoopMatmulExecute(block_size: Int, coreMaxAddrBits: Int, iterator_bitwidth val max_i_blocks = Mux(req.a_tranpose, 1.U, Mux(req.max_i <= max_block_len.U, req.max_i, max_block_len.U)) + val lower_k_bound = (req.max_k / total_k_portions.U) * k_portion.U + val upper_k_bound = if (k_portion == total_k_portions - 1) { req.max_k } else { (req.max_k / total_k_portions.U) * (k_portion + 1).U } + val d_addr_start = (BigInt(1) << 31).U | req.c_addr_start val c_addr_start = (BigInt(3) << 30).U | req.c_addr_start val b_addr_start = req.b_addr_end - req.max_k * req.max_j * block_size.U @@ -444,6 +452,7 @@ class LoopMatmulExecute(block_size: Int, coreMaxAddrBits: Int, iterator_bitwidth io.j := j io.i := i io.idle := state === idle + io.must_send_compute := state === comp // The order here is k, j, i val lda_ahead = io.lda_completed || io.ld_ka > k || (io.ld_ka === k && io.ld_i >= i + i_blocks) @@ -461,6 +470,7 @@ class LoopMatmulExecute(block_size: Int, coreMaxAddrBits: Int, iterator_bitwidth io.cmd.bits.max_j := req.max_j io.cmd.bits.max_k := req.max_k io.cmd.bits.use_iterators := true.B + io.cmd.bits.ex_k_portion := k_portion.U io.loop_id := req.loop_id @@ -470,13 +480,15 @@ class LoopMatmulExecute(block_size: Int, coreMaxAddrBits: Int, iterator_bitwidth }.otherwise { val next_i = floorAdd(i, max_i_blocks, req.max_i) val next_j = floorAdd(j, 1.U, req.max_j, next_i === 0.U) - val next_k = floorAdd(k, 1.U, req.max_k, next_j === 0.U && next_i === 0.U) + // val next_k = floorAdd(k, 1.U, req.max_k, next_j === 0.U && next_i === 0.U) + val next_k = floorAdd(k, 1.U, upper_k_bound, next_j === 0.U && next_i === 0.U, min=lower_k_bound) k := next_k j := next_j i := next_i - state := Mux(next_k === 0.U && next_j === 0.U && next_i === 0.U, idle, pre) + // state := Mux(next_k === 0.U && next_j === 0.U && next_i === 0.U, idle, pre) + state := Mux(next_k === lower_k_bound && next_j === 0.U && next_i === 0.U, idle, pre) } } @@ -484,7 +496,8 @@ class LoopMatmulExecute(block_size: Int, coreMaxAddrBits: Int, iterator_bitwidth req := io.req.bits state := pre j := 0.U - k := 0.U + // k := 0.U + k := (io.req.bits.max_k / total_k_portions.U) * k_portion.U i := 0.U } @@ -576,6 +589,7 @@ class LoopMatmulStC(block_size: Int, coreMaxAddrBits: Int, iterator_bitwidth: In io.cmd.bits.max_j := req.max_j io.cmd.bits.max_k := DontCare io.cmd.bits.use_iterators := true.B + io.cmd.bits.ex_k_portion := DontCare io.loop_id := req.loop_id @@ -673,7 +687,7 @@ class LoopMatmulState(val iterator_bitwidth: Int, val coreMaxAddrBits: Int, val } class LoopMatmul(block_size: Int, coreMaxAddrBits: Int, rob_size: Int, max_lds: Int, max_exs: Int, max_sts: Int, - max_addr: Int, max_acc_addr: Int, input_w: Int, acc_w: Int, dma_max_bytes: Int, cmd_t: GemminiCmd) + max_addr: Int, max_acc_addr: Int, input_w: Int, acc_w: Int, dma_max_bytes: Int, cmd_t: GemminiCmd, ex_total_k_portions: Int) (implicit p: Parameters) extends Module { val iterator_bitwidth = 16 val max_block_len = (dma_max_bytes / (block_size * input_w / 8)) max 1 @@ -685,6 +699,7 @@ class LoopMatmul(block_size: Int, coreMaxAddrBits: Int, rob_size: Int, max_lds: val ld_utilization = Input(UInt(log2Up(rob_size+1).W)) val st_utilization = Input(UInt(log2Up(rob_size+1).W)) val ex_utilization = Input(UInt(log2Up(rob_size+1).W)) + val ex_k_portion_utilizations = Input(Vec(ex_total_k_portions, UInt(log2Up(rob_size+1).W))) val busy = Output(Bool()) }) @@ -705,7 +720,10 @@ class LoopMatmul(block_size: Int, coreMaxAddrBits: Int, rob_size: Int, max_lds: val ldA = Module(new LoopMatmulLdA(block_size, coreMaxAddrBits, iterator_bitwidth, max_addr, input_w, max_block_len, concurrent_loops, cmd_t)) val ldB = Module(new LoopMatmulLdB(block_size, coreMaxAddrBits, iterator_bitwidth, max_addr, input_w, max_block_len, concurrent_loops, cmd_t)) val ldD = Module(new LoopMatmulLdD(block_size, coreMaxAddrBits, iterator_bitwidth, max_acc_addr, input_w, acc_w, max_block_len, max_block_len_acc, concurrent_loops, cmd_t)) - val ex = Module(new LoopMatmulExecute(block_size, coreMaxAddrBits, iterator_bitwidth, max_addr, max_acc_addr, max_block_len, concurrent_loops, cmd_t)) + // val ex = Module(new LoopMatmulExecute(block_size, coreMaxAddrBits, iterator_bitwidth, max_addr, max_acc_addr, max_block_len, concurrent_loops, cmd_t)) + val exs = (0 until ex_total_k_portions).map { i => + Module(new LoopMatmulExecute(block_size, coreMaxAddrBits, iterator_bitwidth, max_addr, max_acc_addr, max_block_len, concurrent_loops, cmd_t, total_k_portions = ex_total_k_portions, k_portion = i)) + } val stC = Module(new LoopMatmulStC(block_size, coreMaxAddrBits, iterator_bitwidth, max_acc_addr, input_w, acc_w, max_block_len, concurrent_loops, cmd_t)) // Create command queue @@ -722,10 +740,17 @@ class LoopMatmul(block_size: Int, coreMaxAddrBits: Int, rob_size: Int, max_lds: ldab_arb.io.forceB := !ab_loads_on_same_loop && ldB.io.loop_id === head_loop_id ldab_arb.io.weightA := head_loop.weightA + // Create ex arbiters + val ex_arb = Module(new Arbiter(cmd_t, ex_total_k_portions)) + (ex_arb.io.in zip exs).foreach { case (in, ex) => + in <> ex.io.cmd + } + // Create global arbiter val arb = Module(new Arbiter(cmd_t, 4)) arb.io.in(0) <> stC.io.cmd - arb.io.in(1) <> ex.io.cmd + // arb.io.in(1) <> ex.io.cmd + arb.io.in(1) <> ex_arb.io.out arb.io.in(2) <> ldD.io.cmd arb.io.in(3) <> ldab_arb.io.out val unrolled_cmd = arb.io.out @@ -752,11 +777,17 @@ class LoopMatmul(block_size: Int, coreMaxAddrBits: Int, rob_size: Int, max_lds: // Wire up overloaded signals ldA.io.rob_overloaded := io.ld_utilization >= max_lds.U ldB.io.rob_overloaded := io.ld_utilization >= max_lds.U - ex.io.rob_overloaded := io.ex_utilization >= max_exs.U + // ex.io.rob_overloaded := io.ex_utilization >= max_exs.U + (exs zip io.ex_k_portion_utilizations).foreach { case (ex, k_util) => + val other_exs = exs.filter(_ != ex) + val must_wait_for_other_compute = other_exs.map(_.io.must_send_compute).reduce(_ || _) + ex.io.rob_overloaded := io.ex_utilization >= max_exs.U || k_util >= 12.U || must_wait_for_other_compute + } ldD.io.rob_overloaded := io.ld_utilization >= max_lds.U stC.io.rob_overloaded := io.st_utilization >= max_sts.U // Wire up iterator inputs + /* ex.io.lda_completed := (ldA.io.loop_id =/= ex.io.loop_id) || ldA.io.idle ex.io.ldb_completed := (ldB.io.loop_id =/= ex.io.loop_id) || ldB.io.idle ex.io.ldd_completed := (ldD.io.loop_id =/= ex.io.loop_id) || ldD.io.idle @@ -764,11 +795,28 @@ class LoopMatmul(block_size: Int, coreMaxAddrBits: Int, rob_size: Int, max_lds: ex.io.ld_kb := ldB.io.k ex.io.ld_j := ldB.io.j ex.io.ld_i := ldA.io.i + */ + exs.foreach { ex => + ex.io.lda_completed := (ldA.io.loop_id =/= ex.io.loop_id) || ldA.io.idle + ex.io.ldb_completed := (ldB.io.loop_id =/= ex.io.loop_id) || ldB.io.idle + ex.io.ldd_completed := (ldD.io.loop_id =/= ex.io.loop_id) || ldD.io.idle + ex.io.ld_ka := ldA.io.k + ex.io.ld_kb := ldB.io.k + ex.io.ld_j := ldB.io.j + ex.io.ld_i := ldA.io.i + } + /* stC.io.ex_completed := (ex.io.loop_id =/= stC.io.loop_id) || ex.io.idle stC.io.ex_k := ex.io.k stC.io.ex_j := ex.io.j stC.io.ex_i := ex.io.i + */ + val exs_completed = exs.map(ex => (ex.io.loop_id =/= stC.io.loop_id) || ex.io.idle) + stC.io.ex_completed := exs_completed.reduce(_ && _) + stC.io.ex_k := MuxCase(exs.last.io.k, (exs_completed zip exs).init.map { case (ex_completed, ex) => (!ex_completed) -> ex.io.k }) + stC.io.ex_j := MuxCase(exs.last.io.j, (exs_completed zip exs).init.map { case (ex_completed, ex) => (!ex_completed) -> ex.io.j }) + stC.io.ex_i := MuxCase(exs.last.io.i, (exs_completed zip exs).init.map { case (ex_completed, ex) => (!ex_completed) -> ex.io.i }) val loops_configured = RegInit(0.U(16.W)) dontTouch(loops_configured) @@ -869,6 +917,7 @@ class LoopMatmul(block_size: Int, coreMaxAddrBits: Int, rob_size: Int, max_lds: val loop_requesting_ex_id = Mux(head_loop.ex_started, tail_loop_id, head_loop_id) val loop_requesting_ex = loops(loop_requesting_ex_id) + /* ex.io.req.bits.max_j := loop_requesting_ex.max_j ex.io.req.bits.max_k := loop_requesting_ex.max_k ex.io.req.bits.max_i := loop_requesting_ex.max_i @@ -895,6 +944,36 @@ class LoopMatmul(block_size: Int, coreMaxAddrBits: Int, rob_size: Int, max_lds: ex_c_addr_start := floorAdd(ex_c_addr_start, (max_acc_addr / concurrent_loops).U, max_acc_addr.U) } } + */ + exs.foreach { ex => + ex.io.req.bits.max_j := loop_requesting_ex.max_j + ex.io.req.bits.max_k := loop_requesting_ex.max_k + ex.io.req.bits.max_i := loop_requesting_ex.max_i + ex.io.req.bits.pad_j := loop_requesting_ex.pad_j + ex.io.req.bits.pad_k := loop_requesting_ex.pad_k + ex.io.req.bits.pad_i := loop_requesting_ex.pad_i + ex.io.req.bits.accumulate := loop_requesting_ex.ex_accumulate + ex.io.req.bits.a_addr_start := loop_requesting_ex.a_addr_start + ex.io.req.bits.b_addr_end := loop_requesting_ex.b_addr_end + ex.io.req.bits.a_tranpose := loop_requesting_ex.a_transpose + ex.io.req.bits.b_tranpose := loop_requesting_ex.b_transpose + ex.io.req.bits.ooo := loop_requesting_ex.ooo + ex.io.req.bits.c_addr_start := ex_c_addr_start + ex.io.req.bits.loop_id := loop_requesting_ex_id + + ex.io.req.valid := !loop_requesting_ex.ex_started && loop_requesting_ex.lda_started && + loop_requesting_ex.ldb_started && loop_requesting_ex.ldd_started && loop_requesting_ex.configured && + exs.map(_.io.req.ready).reduce(_ && _) // TODO ready-valid loop + + when (ex.io.req.fire()) { + loop_requesting_ex.running := true.B + loop_requesting_ex.ex_started := true.B + + when (loop_requesting_ex.c_dram_addr =/= 0.U) { + ex_c_addr_start := floorAdd(ex_c_addr_start, (max_acc_addr / concurrent_loops).U, max_acc_addr.U) + } + } + } val loop_requesting_ldD_id = Mux(head_loop.ldd_started, tail_loop_id, head_loop_id) val loop_requesting_ldD = loops(loop_requesting_ldD_id) @@ -952,9 +1031,14 @@ class LoopMatmul(block_size: Int, coreMaxAddrBits: Int, rob_size: Int, max_lds: loops(ldB.io.loop_id).ldb_completed := true.B } + /* when (ex.io.idle && loops(ex.io.loop_id).running && loops(ex.io.loop_id).ex_started) { loops(ex.io.loop_id).ex_completed := true.B } + */ + when (exs.map(_.io.idle).reduce(_ && _) && loops(exs.head.io.loop_id).running && loops(exs.head.io.loop_id).ex_started) { + loops(exs.head.io.loop_id).ex_completed := true.B + } when (ldD.io.idle && loops(ldD.io.loop_id).running && loops(ldD.io.loop_id).ldd_started) { loops(ldD.io.loop_id).ldd_completed := true.B @@ -980,16 +1064,17 @@ class LoopMatmul(block_size: Int, coreMaxAddrBits: Int, rob_size: Int, max_lds: } object LoopMatmul { - def apply(in: DecoupledIO[RoCCCommand], ld_utilization: UInt, st_utilization: UInt, ex_utilization: UInt, + def apply(in: DecoupledIO[RoCCCommand], ld_utilization: UInt, st_utilization: UInt, ex_utilization: UInt, ex_k_utilizations: Vec[UInt], block_size: Int, coreMaxAddrBits: Int, rob_size: Int, max_lds: Int, max_exs: Int, max_sts: Int, - max_addr: Int, max_acc_addr: Int, input_w: Int, acc_w: Int, dma_max_bytes: Int, cmd_t: GemminiCmd) + max_addr: Int, max_acc_addr: Int, input_w: Int, acc_w: Int, dma_max_bytes: Int, cmd_t: GemminiCmd, ex_total_k_portions: Int) (implicit p: Parameters): Tuple2[DecoupledIO[GemminiCmd], Bool] = { val mod = Module(new LoopMatmul(block_size, coreMaxAddrBits, rob_size, max_lds, max_exs, max_sts, - max_addr, max_acc_addr, input_w, acc_w, dma_max_bytes, cmd_t)) + max_addr, max_acc_addr, input_w, acc_w, dma_max_bytes, cmd_t, ex_total_k_portions)) mod.io.in <> in mod.io.ld_utilization := ld_utilization mod.io.st_utilization := st_utilization mod.io.ex_utilization := ex_utilization + mod.io.ex_k_portion_utilizations := ex_k_utilizations (mod.io.out, mod.io.busy) } } diff --git a/src/main/scala/gemmini/ROB.scala b/src/main/scala/gemmini/ROB.scala index 4dc76b29b..ffe677933 100644 --- a/src/main/scala/gemmini/ROB.scala +++ b/src/main/scala/gemmini/ROB.scala @@ -42,6 +42,8 @@ class ROB[T <: Data : Arithmetic, U <: Data, V <: Data](config: GemminiArrayConf val st_utilization = Output(UInt(log2Up(rob_entries+1).W)) val ex_utilization = Output(UInt(log2Up(rob_entries+1).W)) + val ex_k_portion_utilizations = Output(Vec(ex_total_k_portions, UInt(log2Up(rob_entries+1).W))) + val busy = Output(Bool()) val solitary_preload = Input(Bool()) // TODO very hacky. from ExecuteController, to prevent infinite fence stalls. remove later @@ -123,6 +125,8 @@ class ROB[T <: Data : Arithmetic, U <: Data, V <: Data](config: GemminiArrayConf val deps = Vec(rob_entries, Bool()) def ready(dummy: Int = 0): Bool = !deps.reduce(_ || _) + val ex_k_portion = UInt(log2Up(ex_total_k_portions).W) + // Signals that are necessary for OoO operation val waiting_for_compute_inst = Bool() @@ -208,6 +212,8 @@ class ROB[T <: Data : Arithmetic, U <: Data, V <: Data](config: GemminiArrayConf new_entry.is_config := funct === CONFIG_CMD + new_entry.ex_k_portion := io.alloc.bits.ex_k_portion + val op1 = Wire(UDValid(new OpT)) op1.valid := false.B op1.bits := DontCare @@ -593,6 +599,10 @@ class ROB[T <: Data : Arithmetic, U <: Data, V <: Data](config: GemminiArrayConf io.st_utilization := utilization_st_q io.ex_utilization := utilization_ex_q + io.ex_k_portion_utilizations.zipWithIndex.foreach { case (io, k) => + io := PopCount(entries.map(e => e.valid && e.bits.q === exq && !e.bits.issued && e.bits.ex_k_portion === k.U)) + } + val valids = VecInit(entries.map(_.valid)) val functs = VecInit(entries.map(_.bits.cmd.inst.funct)) val issueds = VecInit(entries.map(_.bits.issued)) diff --git a/src/main/scala/gemmini/Util.scala b/src/main/scala/gemmini/Util.scala index 511cfee28..5bc152f66 100644 --- a/src/main/scala/gemmini/Util.scala +++ b/src/main/scala/gemmini/Util.scala @@ -35,12 +35,12 @@ object Util { Mux(u +& v > max, max, u + v) } - def floorAdd(u: UInt, n: UInt, max_plus_one: UInt, en: Bool = true.B): UInt = { + def floorAdd(u: UInt, n: UInt, max_plus_one: UInt, en: Bool = true.B, min: UInt = 0.U): UInt = { val max = max_plus_one - 1.U MuxCase(u + n, Seq( (!en) -> u, - ((u +& n) > max) -> 0.U + ((u +& n) > max) -> min )) } From 07e72f9a7ca1c68578f4f435a1fce5d7321a64e2 Mon Sep 17 00:00:00 2001 From: Hasan Genc Date: Sun, 27 Jun 2021 13:36:44 +0300 Subject: [PATCH 54/78] Make k_util limit dynamic rather than static --- src/main/scala/gemmini/Controller.scala | 2 +- src/main/scala/gemmini/LoopMatmul.scala | 23 ++++++++++++++++++----- 2 files changed, 19 insertions(+), 6 deletions(-) diff --git a/src/main/scala/gemmini/Controller.scala b/src/main/scala/gemmini/Controller.scala index fe6ee88d9..cf02c63dc 100644 --- a/src/main/scala/gemmini/Controller.scala +++ b/src/main/scala/gemmini/Controller.scala @@ -134,7 +134,7 @@ class GemminiModule[T <: Data: Arithmetic, U <: Data, V <: Data] // val (unrolled_cmd, loop_matmul_unroller_busy) = LoopMatmul(unrolled_cmd_after_conv, rob.io.ld_utilization, rob.io.st_utilization, rob.io.ex_utilization, val (loop_cmd, loop_matmul_unroller_busy) = LoopMatmul(conv_cmd, rob.io.ld_utilization, rob.io.st_utilization, rob.io.ex_utilization, rob.io.ex_k_portion_utilizations, - meshRows*tileRows, coreMaxAddrBits, rob_entries, max_lds, max_exs, max_sts, sp_banks * sp_bank_entries, acc_banks * acc_bank_entries, + meshRows*tileRows, coreMaxAddrBits, rob_entries, rob_full_entries, max_lds, max_exs, max_sts, sp_banks * sp_bank_entries, acc_banks * acc_bank_entries, inputType.getWidth, accType.getWidth, dma_maxbytes, new GemminiCmd(rob_entries), ex_total_k_portions) val unrolled_cmd = Queue(loop_cmd) diff --git a/src/main/scala/gemmini/LoopMatmul.scala b/src/main/scala/gemmini/LoopMatmul.scala index f4f423f55..491ce12f4 100644 --- a/src/main/scala/gemmini/LoopMatmul.scala +++ b/src/main/scala/gemmini/LoopMatmul.scala @@ -686,7 +686,7 @@ class LoopMatmulState(val iterator_bitwidth: Int, val coreMaxAddrBits: Int, val } } -class LoopMatmul(block_size: Int, coreMaxAddrBits: Int, rob_size: Int, max_lds: Int, max_exs: Int, max_sts: Int, +class LoopMatmul(block_size: Int, coreMaxAddrBits: Int, rob_size: Int, rob_full_entries: Int, max_lds: Int, max_exs: Int, max_sts: Int, max_addr: Int, max_acc_addr: Int, input_w: Int, acc_w: Int, dma_max_bytes: Int, cmd_t: GemminiCmd, ex_total_k_portions: Int) (implicit p: Parameters) extends Module { val iterator_bitwidth = 16 @@ -778,10 +778,23 @@ class LoopMatmul(block_size: Int, coreMaxAddrBits: Int, rob_size: Int, max_lds: ldA.io.rob_overloaded := io.ld_utilization >= max_lds.U ldB.io.rob_overloaded := io.ld_utilization >= max_lds.U // ex.io.rob_overloaded := io.ex_utilization >= max_exs.U - (exs zip io.ex_k_portion_utilizations).foreach { case (ex, k_util) => + (exs zip io.ex_k_portion_utilizations).zipWithIndex.foreach { case ((ex, k_util), id) => val other_exs = exs.filter(_ != ex) val must_wait_for_other_compute = other_exs.map(_.io.must_send_compute).reduce(_ || _) - ex.io.rob_overloaded := io.ex_utilization >= max_exs.U || k_util >= 12.U || must_wait_for_other_compute + + val limits = (1 to ex_total_k_portions).map(i => rob_full_entries / i) + val limits_uint = VecInit(limits.map(_.U)) + val first_limits = VecInit(limits.map(l => (l * 1.5).toInt.U)) + + val active_exs = PopCount(exs.map(!_.io.idle)) + val earliest_k_portion = MuxCase((ex_total_k_portions - 1).U, (0 until ex_total_k_portions).map { i => + !exs(i).io.idle -> i.U + }) + + val current_limit = Mux(id.U === earliest_k_portion, first_limits(active_exs), limits_uint(active_exs)) + + // ex.io.rob_overloaded := io.ex_utilization >= max_exs.U || k_util >= 12.U || must_wait_for_other_compute + ex.io.rob_overloaded := io.ex_utilization >= max_exs.U || k_util >= current_limit || must_wait_for_other_compute } ldD.io.rob_overloaded := io.ld_utilization >= max_lds.U stC.io.rob_overloaded := io.st_utilization >= max_sts.U @@ -1065,10 +1078,10 @@ class LoopMatmul(block_size: Int, coreMaxAddrBits: Int, rob_size: Int, max_lds: object LoopMatmul { def apply(in: DecoupledIO[RoCCCommand], ld_utilization: UInt, st_utilization: UInt, ex_utilization: UInt, ex_k_utilizations: Vec[UInt], - block_size: Int, coreMaxAddrBits: Int, rob_size: Int, max_lds: Int, max_exs: Int, max_sts: Int, + block_size: Int, coreMaxAddrBits: Int, rob_size: Int, rob_full_entries: Int, max_lds: Int, max_exs: Int, max_sts: Int, max_addr: Int, max_acc_addr: Int, input_w: Int, acc_w: Int, dma_max_bytes: Int, cmd_t: GemminiCmd, ex_total_k_portions: Int) (implicit p: Parameters): Tuple2[DecoupledIO[GemminiCmd], Bool] = { - val mod = Module(new LoopMatmul(block_size, coreMaxAddrBits, rob_size, max_lds, max_exs, max_sts, + val mod = Module(new LoopMatmul(block_size, coreMaxAddrBits, rob_size, rob_full_entries, max_lds, max_exs, max_sts, max_addr, max_acc_addr, input_w, acc_w, dma_max_bytes, cmd_t, ex_total_k_portions)) mod.io.in <> in mod.io.ld_utilization := ld_utilization From c22a9f3db7ef108456e5cf04dfc80e7e46582452 Mon Sep 17 00:00:00 2001 From: Hasan Genc Date: Sun, 27 Jun 2021 14:11:41 +0300 Subject: [PATCH 55/78] Make the k_util limit look at whether or not a command could be sent, rather than at the idle signal --- src/main/scala/gemmini/LoopMatmul.scala | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/src/main/scala/gemmini/LoopMatmul.scala b/src/main/scala/gemmini/LoopMatmul.scala index 491ce12f4..2c8788005 100644 --- a/src/main/scala/gemmini/LoopMatmul.scala +++ b/src/main/scala/gemmini/LoopMatmul.scala @@ -375,6 +375,8 @@ class LoopMatmulExecute(block_size: Int, coreMaxAddrBits: Int, iterator_bitwidth val must_send_compute = Output(Bool()) + val can_send_command = Output(Bool()) + val loop_id = Output(UInt(log2Up(concurrent_loops).W)) }) @@ -460,6 +462,8 @@ class LoopMatmulExecute(block_size: Int, coreMaxAddrBits: Int, iterator_bitwidth val ldd_ahead = io.ldd_completed val ld_ahead = lda_ahead && ldb_ahead && ldd_ahead + io.can_send_command := state =/= idle && ld_ahead + io.cmd.valid := state =/= idle && !io.rob_overloaded && ld_ahead io.cmd.bits.cmd := Mux(state === pre, pre_cmd, comp_cmd) io.cmd.bits.rob_id := DontCare @@ -786,15 +790,16 @@ class LoopMatmul(block_size: Int, coreMaxAddrBits: Int, rob_size: Int, rob_full_ val limits_uint = VecInit(limits.map(_.U)) val first_limits = VecInit(limits.map(l => (l * 1.5).toInt.U)) - val active_exs = PopCount(exs.map(!_.io.idle)) + val active_exs = PopCount(exs.map(_.io.can_send_command)) val earliest_k_portion = MuxCase((ex_total_k_portions - 1).U, (0 until ex_total_k_portions).map { i => - !exs(i).io.idle -> i.U + exs(i).io.can_send_command -> i.U }) - val current_limit = Mux(id.U === earliest_k_portion, first_limits(active_exs), limits_uint(active_exs)) + val k_util_limit = Mux(ex.io.must_send_compute, rob_size.U, // If we've just send a preload, then we should just send the next compute, without worrying about k_util + Mux(id.U === earliest_k_portion, first_limits(active_exs), limits_uint(active_exs))) // ex.io.rob_overloaded := io.ex_utilization >= max_exs.U || k_util >= 12.U || must_wait_for_other_compute - ex.io.rob_overloaded := io.ex_utilization >= max_exs.U || k_util >= current_limit || must_wait_for_other_compute + ex.io.rob_overloaded := io.ex_utilization >= max_exs.U || k_util >= k_util_limit || must_wait_for_other_compute } ldD.io.rob_overloaded := io.ld_utilization >= max_lds.U stC.io.rob_overloaded := io.st_utilization >= max_sts.U From 8a57b2ee15dadddf67909b87b1b974bd0710cf0c Mon Sep 17 00:00:00 2001 From: Hasan Genc Date: Sun, 27 Jun 2021 14:15:28 +0300 Subject: [PATCH 56/78] Add k_util maximum --- src/main/scala/gemmini/LoopMatmul.scala | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/main/scala/gemmini/LoopMatmul.scala b/src/main/scala/gemmini/LoopMatmul.scala index 2c8788005..18fed533c 100644 --- a/src/main/scala/gemmini/LoopMatmul.scala +++ b/src/main/scala/gemmini/LoopMatmul.scala @@ -795,10 +795,14 @@ class LoopMatmul(block_size: Int, coreMaxAddrBits: Int, rob_size: Int, rob_full_ exs(i).io.can_send_command -> i.U }) - val k_util_limit = Mux(ex.io.must_send_compute, rob_size.U, // If we've just send a preload, then we should just send the next compute, without worrying about k_util - Mux(id.U === earliest_k_portion, first_limits(active_exs), limits_uint(active_exs))) + val k_util_limit = WireInit(Mux(id.U === earliest_k_portion, first_limits(active_exs), limits_uint(active_exs))) + val max_k_util_limit = (rob_full_entries - 2).U + + // If we've just send a preload, then we should just send the next compute, without worrying about k_util + when (ex.io.must_send_compute || k_util_limit > max_k_util_limit) { + k_util_limit := max_k_util_limit + } - // ex.io.rob_overloaded := io.ex_utilization >= max_exs.U || k_util >= 12.U || must_wait_for_other_compute ex.io.rob_overloaded := io.ex_utilization >= max_exs.U || k_util >= k_util_limit || must_wait_for_other_compute } ldD.io.rob_overloaded := io.ld_utilization >= max_lds.U From a4a8453cd5791db747409916fd5db60ba146f08a Mon Sep 17 00:00:00 2001 From: Hasan Genc Date: Sun, 27 Jun 2021 14:48:06 +0300 Subject: [PATCH 57/78] Fix combinational loop --- src/main/scala/gemmini/LoopMatmul.scala | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/main/scala/gemmini/LoopMatmul.scala b/src/main/scala/gemmini/LoopMatmul.scala index 18fed533c..8d7f000e4 100644 --- a/src/main/scala/gemmini/LoopMatmul.scala +++ b/src/main/scala/gemmini/LoopMatmul.scala @@ -795,13 +795,12 @@ class LoopMatmul(block_size: Int, coreMaxAddrBits: Int, rob_size: Int, rob_full_ exs(i).io.can_send_command -> i.U }) - val k_util_limit = WireInit(Mux(id.U === earliest_k_portion, first_limits(active_exs), limits_uint(active_exs))) + val default_k_util_limit = Mux(id.U === earliest_k_portion, first_limits(active_exs), limits_uint(active_exs)) val max_k_util_limit = (rob_full_entries - 2).U // If we've just send a preload, then we should just send the next compute, without worrying about k_util - when (ex.io.must_send_compute || k_util_limit > max_k_util_limit) { - k_util_limit := max_k_util_limit - } + val k_util_limit = Mux(ex.io.must_send_compute || default_k_util_limit > max_k_util_limit, max_k_util_limit, + default_k_util_limit) ex.io.rob_overloaded := io.ex_utilization >= max_exs.U || k_util >= k_util_limit || must_wait_for_other_compute } From ad4cdb2b585b487348e452b9bedfc0385d1b4888 Mon Sep 17 00:00:00 2001 From: Hasan Genc Date: Sun, 27 Jun 2021 19:27:57 +0300 Subject: [PATCH 58/78] Add more comments for Alon --- src/main/scala/gemmini/GemminiConfigs.scala | 2 +- src/main/scala/gemmini/LoopMatmul.scala | 9 ++++++++- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/src/main/scala/gemmini/GemminiConfigs.scala b/src/main/scala/gemmini/GemminiConfigs.scala index cfb5de9ad..2b9a22e58 100644 --- a/src/main/scala/gemmini/GemminiConfigs.scala +++ b/src/main/scala/gemmini/GemminiConfigs.scala @@ -112,7 +112,7 @@ case class GemminiArrayConfig[T <: Data : Arithmetic, U <: Data, V <: Data]( val load_states = 3 val block_stride_bits = 16 - val ex_total_k_portions = 2 + val ex_total_k_portions = 2 // ALON: You can change this to any number of k-portions that you would like //========================================================================== // sanity check mesh size diff --git a/src/main/scala/gemmini/LoopMatmul.scala b/src/main/scala/gemmini/LoopMatmul.scala index 8d7f000e4..3f2d9c8ef 100644 --- a/src/main/scala/gemmini/LoopMatmul.scala +++ b/src/main/scala/gemmini/LoopMatmul.scala @@ -745,6 +745,7 @@ class LoopMatmul(block_size: Int, coreMaxAddrBits: Int, rob_size: Int, rob_full_ ldab_arb.io.weightA := head_loop.weightA // Create ex arbiters + // ALON: This is the arbiter between the k-portions. You could try out an RR arbiter instead. Right now, we're using Chisel's default arbiter which is a priority arbiter that prioritizes the earliest k-portions val ex_arb = Module(new Arbiter(cmd_t, ex_total_k_portions)) (ex_arb.io.in zip exs).foreach { case (in, ex) => in <> ex.io.cmd @@ -783,12 +784,17 @@ class LoopMatmul(block_size: Int, coreMaxAddrBits: Int, rob_size: Int, rob_full_ ldB.io.rob_overloaded := io.ld_utilization >= max_lds.U // ex.io.rob_overloaded := io.ex_utilization >= max_exs.U (exs zip io.ex_k_portion_utilizations).zipWithIndex.foreach { case ((ex, k_util), id) => + /* + A k-portion is inactive iff it has finished sending all its matmul commands, or if it can't send any matmul commands + currently because the loads that it needs haven't been sent out yet + */ + val other_exs = exs.filter(_ != ex) val must_wait_for_other_compute = other_exs.map(_.io.must_send_compute).reduce(_ || _) val limits = (1 to ex_total_k_portions).map(i => rob_full_entries / i) val limits_uint = VecInit(limits.map(_.U)) - val first_limits = VecInit(limits.map(l => (l * 1.5).toInt.U)) + val first_limits = VecInit(limits.map(l => (l * 1.5).toInt.U)) // ALON: You can scale the earliest k-portion's limit by any scalar factor (e.g. 1.25) that you would like val active_exs = PopCount(exs.map(_.io.can_send_command)) val earliest_k_portion = MuxCase((ex_total_k_portions - 1).U, (0 until ex_total_k_portions).map { i => @@ -802,6 +808,7 @@ class LoopMatmul(block_size: Int, coreMaxAddrBits: Int, rob_size: Int, rob_full_ val k_util_limit = Mux(ex.io.must_send_compute || default_k_util_limit > max_k_util_limit, max_k_util_limit, default_k_util_limit) + // ALON: You can change "k_util_limit" to any limit (e.g. 12.U) that you would like ex.io.rob_overloaded := io.ex_utilization >= max_exs.U || k_util >= k_util_limit || must_wait_for_other_compute } ldD.io.rob_overloaded := io.ld_utilization >= max_lds.U From f7a2d789615e31269a660097a341f617747aa187 Mon Sep 17 00:00:00 2001 From: Hasan Genc Date: Wed, 7 Jul 2021 23:31:19 -0700 Subject: [PATCH 59/78] Print the k-portion of stalled commands --- src/main/scala/gemmini/ROB.scala | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/main/scala/gemmini/ROB.scala b/src/main/scala/gemmini/ROB.scala index ffe677933..209243d3a 100644 --- a/src/main/scala/gemmini/ROB.scala +++ b/src/main/scala/gemmini/ROB.scala @@ -132,6 +132,7 @@ class ROB[T <: Data : Arithmetic, U <: Data, V <: Data](config: GemminiArrayConf // Debugging signals val allocated_at = UInt(instructions_allocated.getWidth.W) + val stall_cycles_before_issue = UInt(32.W) // TODO magic number } val full_entries = Reg(Vec(rob_full_entries, UDValid(new Entry))) val partial_entries = Reg(Vec(rob_partial_entries, UDValid(new Entry))) @@ -214,6 +215,8 @@ class ROB[T <: Data : Arithmetic, U <: Data, V <: Data](config: GemminiArrayConf new_entry.ex_k_portion := io.alloc.bits.ex_k_portion + new_entry.stall_cycles_before_issue := 0.U + val op1 = Wire(UDValid(new OpT)) op1.valid := false.B op1.bits := DontCare @@ -555,6 +558,11 @@ class ROB[T <: Data : Arithmetic, U <: Data, V <: Data](config: GemminiArrayConf e.valid := !e.bits.complete_on_issue } } + + val stall_limit = 5000.U // ALON: This magic number defines when a command will be considered "stalled" + when (issue_entry.bits.stall_cycles_before_issue > stall_limit && q === exq) { + printf(p"command stalled: (funct: ${issue_entry.bits.cmd.inst.funct}) (k_portion: ${issue_entry.bits.ex_k_portion})\n") + } } } @@ -582,6 +590,13 @@ class ROB[T <: Data : Arithmetic, U <: Data, V <: Data](config: GemminiArrayConf } } + // Increment stall counters + entries.foreach { e => + when (e.valid && !e.bits.issued) { + e.bits.stall_cycles_before_issue := e.bits.stall_cycles_before_issue + 1.U + } + } + // Hardcode deps that point to the entry that owns the deps to 0 entries.zipWithIndex.foreach { case (e,i) => e.bits.deps(i) := false.B From a1df841afdab4476b68f5420279c711e82957c31 Mon Sep 17 00:00:00 2001 From: Hasan Genc Date: Thu, 8 Jul 2021 03:18:13 -0700 Subject: [PATCH 60/78] Add new stall config options --- .../scala/gemmini/DMACommandTracker.scala | 19 ++++++++++++++++--- src/main/scala/gemmini/GemminiConfigs.scala | 6 ++++++ src/main/scala/gemmini/LoadController.scala | 4 +++- src/main/scala/gemmini/StoreController.scala | 4 +++- 4 files changed, 28 insertions(+), 5 deletions(-) diff --git a/src/main/scala/gemmini/DMACommandTracker.scala b/src/main/scala/gemmini/DMACommandTracker.scala index a687e918e..2b85472ed 100644 --- a/src/main/scala/gemmini/DMACommandTracker.scala +++ b/src/main/scala/gemmini/DMACommandTracker.scala @@ -6,7 +6,7 @@ import chisel3.util._ // This module is meant to go inside the Load controller, where it can track which commands are currently // in flight and which are completed -class DMACommandTracker[T <: Data](val nCmds: Int, val maxBytes: Int, tag_t: => T) extends Module { +class DMACommandTracker[T <: Data](val nCmds: Int, val maxBytes: Int, tag_t: => T, prng_seed: Int, proportion_of_slow_accesses_out_of_128: Int, stall_delay: Int) extends Module { def cmd_id_t = UInt((log2Ceil(nCmds) max 1).W) val io = IO(new Bundle { @@ -56,6 +56,8 @@ class DMACommandTracker[T <: Data](val nCmds: Int, val maxBytes: Int, tag_t: => val tag = tag_t.cloneType val bytes_left = UInt(log2Up(maxBytes+1).W) + val stall_cycles = UInt(32.W) // TODO magic number + def init(dummy: Int = 0): Unit = { valid := false.B } @@ -73,9 +75,9 @@ class DMACommandTracker[T <: Data](val nCmds: Int, val maxBytes: Int, tag_t: => io.busy := cmd_valids.reduce(_ || _) val cmd_completed_id = MuxCase(0.U, cmds.zipWithIndex.map { case (cmd, i) => - (cmd.valid && cmd.bytes_left === 0.U) -> i.U + (cmd.valid && cmd.bytes_left === 0.U && cmd.stall_cycles === 0.U) -> i.U }) - io.cmd_completed.valid := cmds.map(cmd => cmd.valid && cmd.bytes_left === 0.U).reduce(_ || _) + io.cmd_completed.valid := cmds.map(cmd => cmd.valid && cmd.bytes_left === 0.U && cmd.stall_cycles === 0.U).reduce(_ || _) io.cmd_completed.bits.cmd_id := cmd_completed_id io.cmd_completed.bits.tag := cmds(cmd_completed_id).tag @@ -83,6 +85,11 @@ class DMACommandTracker[T <: Data](val nCmds: Int, val maxBytes: Int, tag_t: => cmds(next_empty_alloc).valid := true.B cmds(next_empty_alloc).tag := io.alloc.bits.tag cmds(next_empty_alloc).bytes_left := io.alloc.bits.bytes_to_read + + val random_number = random.GaloisLFSR.maxPeriod(width=8, seed=Some(prng_seed)) + + cmds(next_empty_alloc).stall_cycles := Mux(random_number < proportion_of_slow_accesses_out_of_128.U, + stall_delay.U, 0.U) } when (io.request_returned.fire()) { @@ -97,6 +104,12 @@ class DMACommandTracker[T <: Data](val nCmds: Int, val maxBytes: Int, tag_t: => cmds(io.cmd_completed.bits.cmd_id).valid := false.B } + cmds.foreach { cmd => + when (cmd.valid && cmd.bytes_left === 0.U && cmd.stall_cycles > 0.U) { + cmd.stall_cycles := cmd.stall_cycles - 1.U + } + } + when (reset.asBool()) { cmds.foreach(_.init()) } diff --git a/src/main/scala/gemmini/GemminiConfigs.scala b/src/main/scala/gemmini/GemminiConfigs.scala index 2b9a22e58..d7ca3f9e6 100644 --- a/src/main/scala/gemmini/GemminiConfigs.scala +++ b/src/main/scala/gemmini/GemminiConfigs.scala @@ -72,6 +72,12 @@ case class GemminiArrayConfig[T <: Data : Arithmetic, U <: Data, V <: Data]( use_preload_filter: Boolean, + val prng_seed: Int = 1, // ALON: You can change the PRNG seed here + val proportion_of_slow_accesses_out_of_128: Int = 10, // ALON: The number of memory accesses (out of 128) that are slow. You can also make this 0 + val stall_delay: Int = 1000, // ALON: How many cycles should we wait for a slow memory access? You can also make this 0 + val delay_lds: Boolean = true, // ALON: Should loads be stalled? + val delay_sts: Boolean = true, // ALON: Should stores be stalled? + headerFileName: String = "gemmini_params.h" ) { val sp_width = meshColumns * tileColumns * inputType.getWidth diff --git a/src/main/scala/gemmini/LoadController.scala b/src/main/scala/gemmini/LoadController.scala index a89a219eb..db2d9df6b 100644 --- a/src/main/scala/gemmini/LoadController.scala +++ b/src/main/scala/gemmini/LoadController.scala @@ -77,7 +77,9 @@ class LoadController[T <: Data, U <: Data, V <: Data](config: GemminiArrayConfig (block_cols * config.accType.getWidth / 8) val maxBytesInMatRequest = block_rows * maxBytesInRowRequest - val cmd_tracker = Module(new DMACommandTracker(nCmds, maxBytesInMatRequest, deps_t)) + val cmd_tracker = Module(new DMACommandTracker(nCmds, maxBytesInMatRequest, deps_t, prng_seed = prng_seed, + proportion_of_slow_accesses_out_of_128 = if (delay_lds) proportion_of_slow_accesses_out_of_128 else 0, + stall_delay = stall_delay)) io.busy := cmd.valid || cmd_tracker.io.busy diff --git a/src/main/scala/gemmini/StoreController.scala b/src/main/scala/gemmini/StoreController.scala index 98584bca8..bbf2b8989 100644 --- a/src/main/scala/gemmini/StoreController.scala +++ b/src/main/scala/gemmini/StoreController.scala @@ -118,7 +118,9 @@ class StoreController[T <: Data : Arithmetic, U <: Data, V <: Data](config: Gemm ((config.sp_banks * config.sp_bank_entries) max (config.acc_banks * config.acc_bank_entries)) - val cmd_tracker = Module(new DMACommandTracker(nCmds, cmd_tracker_max_rows, deps_t)) + val cmd_tracker = Module(new DMACommandTracker(nCmds, cmd_tracker_max_rows, deps_t, prng_seed = prng_seed, + proportion_of_slow_accesses_out_of_128 = if (delay_sts) proportion_of_slow_accesses_out_of_128 else 0, + stall_delay = stall_delay)) // DMA IO wiring io.dma.req.valid := (control_state === waiting_for_command && cmd.valid && DoStore && cmd_tracker.io.alloc.ready) || From 033f5ae70fbab75a8a4a9304c621c4d5bcc15328 Mon Sep 17 00:00:00 2001 From: Hasan Genc Date: Thu, 8 Jul 2021 03:21:23 -0700 Subject: [PATCH 61/78] Remove unnecessarry val modifiers --- src/main/scala/gemmini/GemminiConfigs.scala | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/main/scala/gemmini/GemminiConfigs.scala b/src/main/scala/gemmini/GemminiConfigs.scala index d7ca3f9e6..cddb8bc08 100644 --- a/src/main/scala/gemmini/GemminiConfigs.scala +++ b/src/main/scala/gemmini/GemminiConfigs.scala @@ -72,11 +72,11 @@ case class GemminiArrayConfig[T <: Data : Arithmetic, U <: Data, V <: Data]( use_preload_filter: Boolean, - val prng_seed: Int = 1, // ALON: You can change the PRNG seed here - val proportion_of_slow_accesses_out_of_128: Int = 10, // ALON: The number of memory accesses (out of 128) that are slow. You can also make this 0 - val stall_delay: Int = 1000, // ALON: How many cycles should we wait for a slow memory access? You can also make this 0 - val delay_lds: Boolean = true, // ALON: Should loads be stalled? - val delay_sts: Boolean = true, // ALON: Should stores be stalled? + prng_seed: Int = 1, // ALON: You can change the PRNG seed here + proportion_of_slow_accesses_out_of_128: Int = 10, // ALON: The number of memory accesses (out of 128) that are slow. You can also make this 0 + stall_delay: Int = 1000, // ALON: How many cycles should we wait for a slow memory access? You can also make this 0 + delay_lds: Boolean = true, // ALON: Should loads be stalled? + delay_sts: Boolean = true, // ALON: Should stores be stalled? headerFileName: String = "gemmini_params.h" ) { From 4770ff9698d6c37309d3e82122eed4075751f20b Mon Sep 17 00:00:00 2001 From: Hasan Genc Date: Fri, 9 Jul 2021 23:04:16 -0700 Subject: [PATCH 62/78] Add fine-grained-interleaving --- src/main/scala/gemmini/Controller.scala | 2 +- src/main/scala/gemmini/GemminiConfigs.scala | 9 ++-- src/main/scala/gemmini/LoopMatmul.scala | 51 +++++++++++++++------ 3 files changed, 43 insertions(+), 19 deletions(-) diff --git a/src/main/scala/gemmini/Controller.scala b/src/main/scala/gemmini/Controller.scala index cf02c63dc..2c2ff0f46 100644 --- a/src/main/scala/gemmini/Controller.scala +++ b/src/main/scala/gemmini/Controller.scala @@ -135,7 +135,7 @@ class GemminiModule[T <: Data: Arithmetic, U <: Data, V <: Data] val (loop_cmd, loop_matmul_unroller_busy) = LoopMatmul(conv_cmd, rob.io.ld_utilization, rob.io.st_utilization, rob.io.ex_utilization, rob.io.ex_k_portion_utilizations, meshRows*tileRows, coreMaxAddrBits, rob_entries, rob_full_entries, max_lds, max_exs, max_sts, sp_banks * sp_bank_entries, acc_banks * acc_bank_entries, - inputType.getWidth, accType.getWidth, dma_maxbytes, new GemminiCmd(rob_entries), ex_total_k_portions) + inputType.getWidth, accType.getWidth, dma_maxbytes, new GemminiCmd(rob_entries), ex_total_k_portions, ex_fine_grained_interleaving) val unrolled_cmd = Queue(loop_cmd) unrolled_cmd.ready := false.B diff --git a/src/main/scala/gemmini/GemminiConfigs.scala b/src/main/scala/gemmini/GemminiConfigs.scala index cddb8bc08..ae69ec702 100644 --- a/src/main/scala/gemmini/GemminiConfigs.scala +++ b/src/main/scala/gemmini/GemminiConfigs.scala @@ -75,8 +75,11 @@ case class GemminiArrayConfig[T <: Data : Arithmetic, U <: Data, V <: Data]( prng_seed: Int = 1, // ALON: You can change the PRNG seed here proportion_of_slow_accesses_out_of_128: Int = 10, // ALON: The number of memory accesses (out of 128) that are slow. You can also make this 0 stall_delay: Int = 1000, // ALON: How many cycles should we wait for a slow memory access? You can also make this 0 - delay_lds: Boolean = true, // ALON: Should loads be stalled? - delay_sts: Boolean = true, // ALON: Should stores be stalled? + delay_lds: Boolean = false, // ALON: Should loads be stalled? + delay_sts: Boolean = false, // ALON: Should stores be stalled? + + ex_total_k_portions: Int = 2, // ALON: You can change this to any number of k-portions that you would like + ex_fine_grained_interleaving: Boolean = true, // ALON: If this is true, then we use the newer ("finer") intervleaving strategy headerFileName: String = "gemmini_params.h" ) { @@ -118,8 +121,6 @@ case class GemminiArrayConfig[T <: Data : Arithmetic, U <: Data, V <: Data]( val load_states = 3 val block_stride_bits = 16 - val ex_total_k_portions = 2 // ALON: You can change this to any number of k-portions that you would like - //========================================================================== // sanity check mesh size //========================================================================== diff --git a/src/main/scala/gemmini/LoopMatmul.scala b/src/main/scala/gemmini/LoopMatmul.scala index 3f2d9c8ef..036a84c32 100644 --- a/src/main/scala/gemmini/LoopMatmul.scala +++ b/src/main/scala/gemmini/LoopMatmul.scala @@ -340,7 +340,7 @@ class LoopMatmulExecuteReq(val block_size: Int, val coreMaxAddrBits: Int, val it val loop_id = UInt(log2Up(concurrent_loops).W) } -class LoopMatmulExecute(block_size: Int, coreMaxAddrBits: Int, iterator_bitwidth: Int, max_addr: Int, max_acc_addr: Int, max_block_len: Int, concurrent_loops: Int, cmd_t: GemminiCmd, total_k_portions: Int, k_portion: Int) +class LoopMatmulExecute(block_size: Int, coreMaxAddrBits: Int, iterator_bitwidth: Int, max_addr: Int, max_acc_addr: Int, max_block_len: Int, concurrent_loops: Int, cmd_t: GemminiCmd, total_k_portions: Int, k_portion: Int, fine_grained_interleaving: Boolean) (implicit p: Parameters) extends Module { val GARBAGE_ADDR = (~0.U(32.W)).asUInt() @@ -390,8 +390,8 @@ class LoopMatmulExecute(block_size: Int, coreMaxAddrBits: Int, iterator_bitwidth val max_i_blocks = Mux(req.a_tranpose, 1.U, Mux(req.max_i <= max_block_len.U, req.max_i, max_block_len.U)) - val lower_k_bound = (req.max_k / total_k_portions.U) * k_portion.U - val upper_k_bound = if (k_portion == total_k_portions - 1) { req.max_k } else { (req.max_k / total_k_portions.U) * (k_portion + 1).U } + val lower_k_bound = if (fine_grained_interleaving) { (max_block_len * k_portion).U } else { (req.max_k / total_k_portions.U) * k_portion.U } + val upper_k_bound = if (fine_grained_interleaving || k_portion == total_k_portions - 1) { req.max_k } else { (req.max_k / total_k_portions.U) * (k_portion + 1).U } val d_addr_start = (BigInt(1) << 31).U | req.c_addr_start val c_addr_start = (BigInt(3) << 30).U | req.c_addr_start @@ -482,10 +482,13 @@ class LoopMatmulExecute(block_size: Int, coreMaxAddrBits: Int, iterator_bitwidth when (state === pre) { state := comp }.otherwise { + val jump_k = fine_grained_interleaving.B && (k +& 1.U) % max_block_len.U === 0.U + val k_it = Mux(jump_k, (total_k_portions * max_block_len - max_block_len + 1).U, 1.U) + val next_i = floorAdd(i, max_i_blocks, req.max_i) val next_j = floorAdd(j, 1.U, req.max_j, next_i === 0.U) // val next_k = floorAdd(k, 1.U, req.max_k, next_j === 0.U && next_i === 0.U) - val next_k = floorAdd(k, 1.U, upper_k_bound, next_j === 0.U && next_i === 0.U, min=lower_k_bound) + val next_k = floorAdd(k, k_it, upper_k_bound, next_j === 0.U && next_i === 0.U, min=lower_k_bound) k := next_k j := next_j @@ -498,11 +501,14 @@ class LoopMatmulExecute(block_size: Int, coreMaxAddrBits: Int, iterator_bitwidth when (io.req.fire()) { req := io.req.bits - state := pre j := 0.U // k := 0.U - k := (io.req.bits.max_k / total_k_portions.U) * k_portion.U + k := (if (fine_grained_interleaving) { lower_k_bound } else { (io.req.bits.max_k / total_k_portions.U) * k_portion.U }) i := 0.U + + when (!fine_grained_interleaving.B || lower_k_bound < io.req.bits.max_k) { + state := pre + } } assert(!(state =/= idle && req.a_tranpose && req.b_tranpose)) @@ -691,7 +697,7 @@ class LoopMatmulState(val iterator_bitwidth: Int, val coreMaxAddrBits: Int, val } class LoopMatmul(block_size: Int, coreMaxAddrBits: Int, rob_size: Int, rob_full_entries: Int, max_lds: Int, max_exs: Int, max_sts: Int, - max_addr: Int, max_acc_addr: Int, input_w: Int, acc_w: Int, dma_max_bytes: Int, cmd_t: GemminiCmd, ex_total_k_portions: Int) + max_addr: Int, max_acc_addr: Int, input_w: Int, acc_w: Int, dma_max_bytes: Int, cmd_t: GemminiCmd, ex_total_k_portions: Int, ex_fine_grained_interleaving: Boolean) (implicit p: Parameters) extends Module { val iterator_bitwidth = 16 val max_block_len = (dma_max_bytes / (block_size * input_w / 8)) max 1 @@ -726,7 +732,7 @@ class LoopMatmul(block_size: Int, coreMaxAddrBits: Int, rob_size: Int, rob_full_ val ldD = Module(new LoopMatmulLdD(block_size, coreMaxAddrBits, iterator_bitwidth, max_acc_addr, input_w, acc_w, max_block_len, max_block_len_acc, concurrent_loops, cmd_t)) // val ex = Module(new LoopMatmulExecute(block_size, coreMaxAddrBits, iterator_bitwidth, max_addr, max_acc_addr, max_block_len, concurrent_loops, cmd_t)) val exs = (0 until ex_total_k_portions).map { i => - Module(new LoopMatmulExecute(block_size, coreMaxAddrBits, iterator_bitwidth, max_addr, max_acc_addr, max_block_len, concurrent_loops, cmd_t, total_k_portions = ex_total_k_portions, k_portion = i)) + Module(new LoopMatmulExecute(block_size, coreMaxAddrBits, iterator_bitwidth, max_addr, max_acc_addr, max_block_len, concurrent_loops, cmd_t, total_k_portions = ex_total_k_portions, k_portion = i, fine_grained_interleaving = ex_fine_grained_interleaving)) } val stC = Module(new LoopMatmulStC(block_size, coreMaxAddrBits, iterator_bitwidth, max_acc_addr, input_w, acc_w, max_block_len, concurrent_loops, cmd_t)) @@ -746,9 +752,10 @@ class LoopMatmul(block_size: Int, coreMaxAddrBits: Int, rob_size: Int, rob_full_ // Create ex arbiters // ALON: This is the arbiter between the k-portions. You could try out an RR arbiter instead. Right now, we're using Chisel's default arbiter which is a priority arbiter that prioritizes the earliest k-portions - val ex_arb = Module(new Arbiter(cmd_t, ex_total_k_portions)) - (ex_arb.io.in zip exs).foreach { case (in, ex) => + val ex_arb = Module(new ExArbiter(cmd_t, ex_total_k_portions, ex_fine_grained_interleaving)) + (ex_arb.io.in, ex_arb.io.k, exs).zipped.foreach { case (in, k, ex) => in <> ex.io.cmd + k := ex.io.k } // Create global arbiter @@ -792,9 +799,9 @@ class LoopMatmul(block_size: Int, coreMaxAddrBits: Int, rob_size: Int, rob_full_ val other_exs = exs.filter(_ != ex) val must_wait_for_other_compute = other_exs.map(_.io.must_send_compute).reduce(_ || _) - val limits = (1 to ex_total_k_portions).map(i => rob_full_entries / i) + val limits = if (ex_total_k_portions == 1) { Seq(rob_full_entries) } else { (1 to ex_total_k_portions).map(i => rob_full_entries / i) } val limits_uint = VecInit(limits.map(_.U)) - val first_limits = VecInit(limits.map(l => (l * 1.5).toInt.U)) // ALON: You can scale the earliest k-portion's limit by any scalar factor (e.g. 1.25) that you would like + val first_limits = VecInit(limits.map(l => if (ex_fine_grained_interleaving) l.U else (l * 1.5).toInt.U)) // ALON: You can scale the earliest k-portion's limit by any scalar factor (e.g. 1.25) that you would like val active_exs = PopCount(exs.map(_.io.can_send_command)) val earliest_k_portion = MuxCase((ex_total_k_portions - 1).U, (0 until ex_total_k_portions).map { i => @@ -1094,10 +1101,10 @@ class LoopMatmul(block_size: Int, coreMaxAddrBits: Int, rob_size: Int, rob_full_ object LoopMatmul { def apply(in: DecoupledIO[RoCCCommand], ld_utilization: UInt, st_utilization: UInt, ex_utilization: UInt, ex_k_utilizations: Vec[UInt], block_size: Int, coreMaxAddrBits: Int, rob_size: Int, rob_full_entries: Int, max_lds: Int, max_exs: Int, max_sts: Int, - max_addr: Int, max_acc_addr: Int, input_w: Int, acc_w: Int, dma_max_bytes: Int, cmd_t: GemminiCmd, ex_total_k_portions: Int) + max_addr: Int, max_acc_addr: Int, input_w: Int, acc_w: Int, dma_max_bytes: Int, cmd_t: GemminiCmd, ex_total_k_portions: Int, ex_fine_grained_interleaving: Boolean) (implicit p: Parameters): Tuple2[DecoupledIO[GemminiCmd], Bool] = { val mod = Module(new LoopMatmul(block_size, coreMaxAddrBits, rob_size, rob_full_entries, max_lds, max_exs, max_sts, - max_addr, max_acc_addr, input_w, acc_w, dma_max_bytes, cmd_t, ex_total_k_portions)) + max_addr, max_acc_addr, input_w, acc_w, dma_max_bytes, cmd_t, ex_total_k_portions, ex_fine_grained_interleaving)) mod.io.in <> in mod.io.ld_utilization := ld_utilization mod.io.st_utilization := st_utilization @@ -1106,3 +1113,19 @@ object LoopMatmul { (mod.io.out, mod.io.busy) } } + +class ExArbiter[T <: Data](gen: T, n: Int, ex_fine_grained: Boolean) extends Module { + val io = IO(new Bundle { + val in = Flipped(Vec(n, Decoupled(gen))) + val out = Decoupled(gen) + val k = Input(Vec(n, UInt(16.W))) // TODO magic number + }) + + val chosen = (io.in zip io.k).zipWithIndex.foldLeft(0.U) { case (acc, ((in, k), i)) => + if (ex_fine_grained) Mux(io.in(acc).valid, Mux(in.valid && k < io.k(acc), i.U, acc), i.U) + else Mux(io.in(acc).valid, acc, i.U) + } + + io.in.foreach(_.ready := false.B) + io.out <> io.in(chosen) +} From 963bf65e2d6430f2fa806a1b60027735cfa48420 Mon Sep 17 00:00:00 2001 From: Hasan Genc Date: Tue, 13 Jul 2021 02:11:18 -0700 Subject: [PATCH 63/78] Reduce size of matmul fsm --- src/main/scala/gemmini/Controller.scala | 2 +- src/main/scala/gemmini/GemminiISA.scala | 93 ++++++++++++++++ src/main/scala/gemmini/LocalAddr.scala | 12 +- src/main/scala/gemmini/LoopMatmul.scala | 142 ++++++++++++++++++------ 4 files changed, 209 insertions(+), 40 deletions(-) diff --git a/src/main/scala/gemmini/Controller.scala b/src/main/scala/gemmini/Controller.scala index 2c2ff0f46..9c0857f3f 100644 --- a/src/main/scala/gemmini/Controller.scala +++ b/src/main/scala/gemmini/Controller.scala @@ -135,7 +135,7 @@ class GemminiModule[T <: Data: Arithmetic, U <: Data, V <: Data] val (loop_cmd, loop_matmul_unroller_busy) = LoopMatmul(conv_cmd, rob.io.ld_utilization, rob.io.st_utilization, rob.io.ex_utilization, rob.io.ex_k_portion_utilizations, meshRows*tileRows, coreMaxAddrBits, rob_entries, rob_full_entries, max_lds, max_exs, max_sts, sp_banks * sp_bank_entries, acc_banks * acc_bank_entries, - inputType.getWidth, accType.getWidth, dma_maxbytes, new GemminiCmd(rob_entries), ex_total_k_portions, ex_fine_grained_interleaving) + inputType.getWidth, accType.getWidth, dma_maxbytes, new GemminiCmd(rob_entries), ex_total_k_portions, ex_fine_grained_interleaving, local_addr_t) val unrolled_cmd = Queue(loop_cmd) unrolled_cmd.ready := false.B diff --git a/src/main/scala/gemmini/GemminiISA.scala b/src/main/scala/gemmini/GemminiISA.scala index 46a23010c..f6b6520b0 100644 --- a/src/main/scala/gemmini/GemminiISA.scala +++ b/src/main/scala/gemmini/GemminiISA.scala @@ -1,6 +1,7 @@ package gemmini import chisel3._ +import chisel3.util._ object GemminiISA { // funct values @@ -54,4 +55,96 @@ object GemminiISA { // dataflow configuration //========================================================================== val GARBAGE_ADDR = "hffffffff".U(32.W) + + private val register_len = 64 + + object LoadCmd { + class Rs1(val coreMaxAddrBits: Int) extends Bundle { + val garbage = UInt((register_len - coreMaxAddrBits).W) + val dram_addr = UInt(coreMaxAddrBits.W) + } + + class Rs2(local_addr_t: LocalAddr) extends Bundle { + private val maxLocalAddrBits = local_addr_t.maxLocalAddrBits + + val garbage1 = UInt(((16 - maxLocalAddrBits) max 0).W) + val rows = UInt((16 min maxLocalAddrBits).W) + val garbage2 = UInt(((16 - maxLocalAddrBits) max 0).W) + val cols = UInt((16 min maxLocalAddrBits).W) + val spad_addr = local_addr_t + + override def cloneType: Rs2.this.type = new Rs2(local_addr_t).asInstanceOf[this.type] + } + } + + object StoreCmd { + class Rs1(val coreMaxAddrBits: Int) extends Bundle { + val garbage = UInt((register_len - coreMaxAddrBits).W) + val dram_addr = UInt(coreMaxAddrBits.W) + } + + class Rs2(local_addr_t: LocalAddr) extends Bundle { + private val maxLocalAddrBits = local_addr_t.maxLocalAddrBits + + val garbage1 = UInt(((16 - maxLocalAddrBits) max 0).W) + val rows = UInt((16 min maxLocalAddrBits).W) + val garbage2 = UInt(((16 - maxLocalAddrBits) max 0).W) + val cols = UInt((16 min maxLocalAddrBits).W) + val spad_addr = local_addr_t + + override def cloneType: Rs2.this.type = new Rs2(local_addr_t).asInstanceOf[this.type] + } + } + + object PreloadCmd { + class Rs1(local_addr_t: LocalAddr, block_size: Int) extends Bundle { + private val maxLocalAddrBits = local_addr_t.maxLocalAddrBits + + val garbage1 = UInt((16 - log2Up(block_size+1)).W) + val bd_rows = UInt(log2Up(block_size+1).W) + val garbage2 = UInt((16 - log2Up(block_size+1)).W) + val bd_cols = UInt(log2Up(block_size+1).W) + val bd = local_addr_t + + override def cloneType: Rs1.this.type = new Rs1(local_addr_t, block_size).asInstanceOf[this.type] + } + + class Rs2(local_addr_t: LocalAddr, block_size: Int, max_block_len: Int) extends Bundle { + private val maxLocalAddrBits = local_addr_t.maxLocalAddrBits + + val garbage1 = UInt((16 - log2Up(max_block_len*block_size+1)).W) + val c_rows = UInt(log2Up(max_block_len*block_size+1).W) + val garbage2 = UInt((16 - log2Up(max_block_len*block_size+1)).W) + val c_cols = UInt(log2Up(max_block_len*block_size+1).W) + val c = local_addr_t + + override def cloneType: Rs2.this.type = new Rs2(local_addr_t, block_size, max_block_len).asInstanceOf[this.type] + } + } + + object ComputeCmd { + class Rs1(local_addr_t: LocalAddr, block_size: Int, max_block_len: Int) extends Bundle { + private val maxLocalAddrBits = local_addr_t.maxLocalAddrBits + + val garbage1 = UInt((16 - log2Up(max_block_len*block_size+1)).W) + val a_rows = UInt(log2Up(max_block_len*block_size+1).W) + val garbage2 = UInt((16 - log2Up(max_block_len*block_size+1)).W) + val a_cols = UInt(log2Up(max_block_len*block_size+1).W) + val a = local_addr_t + + override def cloneType: Rs1.this.type = new Rs1(local_addr_t, block_size, max_block_len).asInstanceOf[this.type] + } + + class Rs2(local_addr_t: LocalAddr, block_size: Int) extends Bundle { + private val maxLocalAddrBits = local_addr_t.maxLocalAddrBits + + val garbage1 = UInt((16 - log2Up(block_size+1)).W) + val bd_rows = UInt(log2Up(block_size+1).W) + val garbage2 = UInt((16 - log2Up(block_size+1)).W) + val bd_cols = UInt(log2Up(block_size+1).W) + val bd = local_addr_t + + override def cloneType: Rs2.this.type = new Rs2(local_addr_t, block_size).asInstanceOf[this.type] + } + } } diff --git a/src/main/scala/gemmini/LocalAddr.scala b/src/main/scala/gemmini/LocalAddr.scala index 8651a191a..e62334934 100644 --- a/src/main/scala/gemmini/LocalAddr.scala +++ b/src/main/scala/gemmini/LocalAddr.scala @@ -8,7 +8,7 @@ class LocalAddr(sp_banks: Int, sp_bank_entries: Int, acc_banks: Int, acc_bank_en private val spAddrBits = log2Ceil(sp_banks * sp_bank_entries) private val accAddrBits = log2Ceil(acc_banks * acc_bank_entries) - private val maxAddrBits = spAddrBits max accAddrBits + val maxLocalAddrBits = spAddrBits max accAddrBits private val spBankBits = log2Up(sp_banks) private val spBankRowBits = log2Up(sp_bank_entries) @@ -19,9 +19,9 @@ class LocalAddr(sp_banks: Int, sp_bank_entries: Int, acc_banks: Int, acc_bank_en val is_acc_addr = Bool() val accumulate = Bool() val read_full_acc_row = Bool() - val garbage = UInt(((localAddrBits - maxAddrBits - 4) max 0).W) - val garbage_bit = if (localAddrBits - maxAddrBits >= 4) UInt(1.W) else UInt(0.W) - val data = UInt(maxAddrBits.W) + val garbage = UInt(((localAddrBits - maxLocalAddrBits - 4) max 0).W) + val garbage_bit = if (localAddrBits - maxLocalAddrBits >= 4) UInt(1.W) else UInt(0.W) + val data = UInt(maxLocalAddrBits.W) def sp_bank(dummy: Int = 0) = if (spAddrBits == spBankRowBits) 0.U else data(spAddrBits - 1, spBankRowBits) def sp_row(dummy: Int = 0) = data(spBankRowBits - 1, 0) @@ -70,7 +70,7 @@ class LocalAddr(sp_banks: Int, sp_bank_entries: Int, acc_banks: Int, acc_bank_en val overflow = Mux(is_acc_addr, sum(accAddrBits), sum(spAddrBits)) val result = WireInit(this) - result.data := sum(maxAddrBits - 1, 0) + result.data := sum(maxLocalAddrBits - 1, 0) (result, overflow) } @@ -80,7 +80,7 @@ class LocalAddr(sp_banks: Int, sp_bank_entries: Int, acc_banks: Int, acc_bank_en accumulate := true.B read_full_acc_row := true.B garbage_bit := 1.U - data := ~(0.U(maxAddrBits.W)) + data := ~(0.U(maxLocalAddrBits.W)) } override def cloneType: LocalAddr.this.type = new LocalAddr(sp_banks, sp_bank_entries, acc_banks, acc_bank_entries).asInstanceOf[this.type] diff --git a/src/main/scala/gemmini/LoopMatmul.scala b/src/main/scala/gemmini/LoopMatmul.scala index 036a84c32..232c0de5c 100644 --- a/src/main/scala/gemmini/LoopMatmul.scala +++ b/src/main/scala/gemmini/LoopMatmul.scala @@ -23,7 +23,7 @@ class LoopMatmulLdAReq(val block_size: Int, val coreMaxAddrBits: Int, val iterat } class LoopMatmulLdA(block_size: Int, coreMaxAddrBits: Int, iterator_bitwidth: Int, max_addr: Int, input_w: Int, - max_block_len: Int, concurrent_loops: Int, cmd_t: GemminiCmd) + max_block_len: Int, concurrent_loops: Int, cmd_t: GemminiCmd, local_addr_t: LocalAddr) (implicit p: Parameters) extends Module { val io = IO(new Bundle { val req = Flipped(Decoupled(new LoopMatmulLdAReq(block_size, coreMaxAddrBits, iterator_bitwidth, max_addr, concurrent_loops))) @@ -66,11 +66,22 @@ class LoopMatmulLdA(block_size: Int, coreMaxAddrBits: Int, iterator_bitwidth: In val cols = (blocks * block_size.U) - Mux(col_iterator + blocks >= max_col_iterator, col_pad, 0.U) val rows = block_size.U - Mux(row_iterator === max_row_iterator-1.U, row_pad, 0.U) + val mvin_cmd_rs1 = Wire(new GemminiISA.LoadCmd.Rs1(coreMaxAddrBits)) + mvin_cmd_rs1 := DontCare + mvin_cmd_rs1.dram_addr := dram_addr + + val mvin_cmd_rs2 = Wire(new GemminiISA.LoadCmd.Rs2(local_addr_t)) + mvin_cmd_rs2 := DontCare + mvin_cmd_rs2.rows := rows + mvin_cmd_rs2.cols := cols + mvin_cmd_rs2.spad_addr := 0.U.asTypeOf(local_addr_t) + mvin_cmd_rs2.spad_addr.data := sp_addr + val mvin_cmd = Wire(new RoCCCommand) mvin_cmd := DontCare mvin_cmd.inst.funct := LOAD_CMD - mvin_cmd.rs1 := dram_addr - mvin_cmd.rs2 := (rows << 48).asUInt() | (cols << 32).asUInt() | sp_addr + mvin_cmd.rs1 := mvin_cmd_rs1.asUInt() + mvin_cmd.rs2 := mvin_cmd_rs2.asUInt() io.req.ready := state === idle io.i := i @@ -130,7 +141,7 @@ class LoopMatmulLdBReq(val block_size: Int, val coreMaxAddrBits: Int, val iterat } class LoopMatmulLdB(block_size: Int, coreMaxAddrBits: Int, iterator_bitwidth: Int, max_addr: Int, input_w: Int, - max_block_len: Int, concurrent_loops: Int, cmd_t: GemminiCmd) + max_block_len: Int, concurrent_loops: Int, cmd_t: GemminiCmd, local_addr_t: LocalAddr) (implicit p: Parameters) extends Module { val io = IO(new Bundle { val req = Flipped(Decoupled(new LoopMatmulLdBReq(block_size, coreMaxAddrBits, iterator_bitwidth, max_addr, concurrent_loops))) @@ -176,11 +187,22 @@ class LoopMatmulLdB(block_size: Int, coreMaxAddrBits: Int, iterator_bitwidth: In val cols = (blocks * block_size.U) - Mux(col_iterator + blocks >= max_col_iterator, col_pad, 0.U) val rows = block_size.U - Mux(max_row_iterator === max_row_iterator-1.U, row_pad, 0.U) + val mvin_cmd_rs1 = Wire(new GemminiISA.LoadCmd.Rs1(coreMaxAddrBits)) + mvin_cmd_rs1 := DontCare + mvin_cmd_rs1.dram_addr := dram_addr + + val mvin_cmd_rs2 = Wire(new GemminiISA.LoadCmd.Rs2(local_addr_t)) + mvin_cmd_rs2 := DontCare + mvin_cmd_rs2.rows := rows + mvin_cmd_rs2.cols := cols + mvin_cmd_rs2.spad_addr := 0.U.asTypeOf(local_addr_t) + mvin_cmd_rs2.spad_addr.data := sp_addr + val mvin_cmd = Wire(new RoCCCommand) mvin_cmd := DontCare mvin_cmd.inst.funct := LOAD2_CMD - mvin_cmd.rs1 := dram_addr - mvin_cmd.rs2 := (rows << 48).asUInt() | (cols << 32).asUInt() | sp_addr + mvin_cmd.rs1 := mvin_cmd_rs1.asUInt() + mvin_cmd.rs2 := mvin_cmd_rs2.asUInt() io.req.ready := state === idle io.k := k @@ -240,7 +262,8 @@ class LoopMatmulLdDReq(val block_size: Int, val coreMaxAddrBits: Int, val iterat } class LoopMatmulLdD(block_size: Int, coreMaxAddrBits: Int, iterator_bitwidth: Int, max_acc_addr: Int, input_w: Int, - acc_w: Int, max_block_len: Int, max_block_len_acc: Int, concurrent_loops: Int, cmd_t: GemminiCmd) + acc_w: Int, max_block_len: Int, max_block_len_acc: Int, concurrent_loops: Int, cmd_t: GemminiCmd, + local_addr_t: LocalAddr) (implicit p: Parameters) extends Module { val io = IO(new Bundle { val req = Flipped(Decoupled(new LoopMatmulLdDReq(block_size, coreMaxAddrBits, iterator_bitwidth, max_acc_addr, concurrent_loops))) @@ -266,20 +289,30 @@ class LoopMatmulLdD(block_size: Int, coreMaxAddrBits: Int, iterator_bitwidth: In val j = Reg(UInt(iterator_bitwidth.W)) val i = Reg(UInt(iterator_bitwidth.W)) - val acc_addr_start = (BigInt(1) << 31).U | req.addr_start - val dram_addr = Mux(req.low_d, req.dram_addr + (i * req.dram_stride + j) * block_size.U * (input_w/8).U, req.dram_addr + (i * req.dram_stride + j) * block_size.U * (acc_w/8).U) - val sp_addr = acc_addr_start + (i * req.max_j + j) * block_size.U + val sp_addr = req.addr_start + (i * req.max_j + j) * block_size.U val blocks = Mux(j + max_blocks <= req.max_j, max_blocks, req.max_j-j) val cols = (blocks * block_size.U) - Mux(j + blocks >= req.max_j, req.pad_j, 0.U) val rows = block_size.U - Mux(i === req.max_i-1.U, req.pad_i, 0.U) + val mvin_cmd_rs1 = Wire(new GemminiISA.LoadCmd.Rs1(coreMaxAddrBits)) + mvin_cmd_rs1 := DontCare + mvin_cmd_rs1.dram_addr := dram_addr + + val mvin_cmd_rs2 = Wire(new GemminiISA.LoadCmd.Rs2(local_addr_t)) + mvin_cmd_rs2 := DontCare + mvin_cmd_rs2.rows := rows + mvin_cmd_rs2.cols := cols + mvin_cmd_rs2.spad_addr := 0.U.asTypeOf(local_addr_t) + mvin_cmd_rs2.spad_addr.is_acc_addr := true.B + mvin_cmd_rs2.spad_addr.data := sp_addr + val mvin_cmd = Wire(new RoCCCommand) mvin_cmd := DontCare mvin_cmd.inst.funct := LOAD3_CMD - mvin_cmd.rs1 := dram_addr - mvin_cmd.rs2 := (rows << 48).asUInt() | (cols << 32).asUInt() | sp_addr + mvin_cmd.rs1 := mvin_cmd_rs1.asUInt() + mvin_cmd.rs2 := mvin_cmd_rs2.asUInt() io.req.ready := state === idle io.idle := state === idle @@ -340,7 +373,7 @@ class LoopMatmulExecuteReq(val block_size: Int, val coreMaxAddrBits: Int, val it val loop_id = UInt(log2Up(concurrent_loops).W) } -class LoopMatmulExecute(block_size: Int, coreMaxAddrBits: Int, iterator_bitwidth: Int, max_addr: Int, max_acc_addr: Int, max_block_len: Int, concurrent_loops: Int, cmd_t: GemminiCmd, total_k_portions: Int, k_portion: Int, fine_grained_interleaving: Boolean) +class LoopMatmulExecute(block_size: Int, coreMaxAddrBits: Int, iterator_bitwidth: Int, max_addr: Int, max_acc_addr: Int, max_block_len: Int, concurrent_loops: Int, cmd_t: GemminiCmd, total_k_portions: Int, k_portion: Int, fine_grained_interleaving: Boolean, local_addr_t: LocalAddr) (implicit p: Parameters) extends Module { val GARBAGE_ADDR = (~0.U(32.W)).asUInt() @@ -423,26 +456,56 @@ class LoopMatmulExecute(block_size: Int, coreMaxAddrBits: Int, iterator_bitwidth val c_cols = block_size.U - Mux(j === req.max_j - 1.U, req.pad_j, 0.U) val c_rows = i_blocks * block_size.U - Mux(i + max_i_blocks >= req.max_i, req.pad_i, 0.U) - val pre_addr = Mux(i === 0.U || req.ooo, b_addr, GARBAGE_ADDR) - val out_addr = Mux(req.accumulate || k =/= 0.U, c_addr, d_addr) + val pre_addr_is_garbage = i === 0.U || req.ooo + val out_addr_accumulates = req.accumulate || k =/= 0.U + + val pre_addr = Mux(pre_addr_is_garbage, b_addr, GARBAGE_ADDR) + val out_addr = Mux(out_addr_accumulates, c_addr, d_addr) val j_blocks_holder = req.max_j.asTypeOf(new blocks_holder_t) val k_blocks_holder = req.max_k.asTypeOf(new blocks_holder_t) + val pre_cmd_rs1 = Wire(new GemminiISA.PreloadCmd.Rs1(local_addr_t, block_size)) + pre_cmd_rs1 := DontCare + pre_cmd_rs1.bd_rows := b_rows + pre_cmd_rs1.bd_cols := b_cols + pre_cmd_rs1.bd := 0.U.asTypeOf(local_addr_t) + pre_cmd_rs1.bd.data := pre_addr + + when (pre_addr_is_garbage) { + pre_cmd_rs1.bd.make_this_garbage() + } + + val pre_cmd_rs2 = Wire(new GemminiISA.PreloadCmd.Rs2(local_addr_t, block_size, max_block_len)) + pre_cmd_rs2 := DontCare + pre_cmd_rs2.c_rows := c_rows + pre_cmd_rs2.c_cols := c_cols + pre_cmd_rs2.c := 0.U.asTypeOf(local_addr_t) + pre_cmd_rs2.c.is_acc_addr := true.B + pre_cmd_rs2.c.accumulate := out_addr_accumulates + pre_cmd_rs2.c.data := out_addr + val pre_cmd = Wire(new RoCCCommand) pre_cmd := DontCare pre_cmd.inst.funct := PRELOAD_CMD - pre_cmd.rs1 := pre_addr | (b_cols << 32).asUInt() | (b_rows << 48).asUInt() - pre_cmd.rs2 := out_addr | (c_cols << 32).asUInt() | (c_rows << 48).asUInt() + pre_cmd.rs1 := pre_cmd_rs1.asUInt() + pre_cmd.rs2 := pre_cmd_rs2.asUInt() pre_cmd.inst.opcode := j_blocks_holder.opcode pre_cmd.inst.rs1 := j_blocks_holder.rs1 pre_cmd.inst.rs2 := j_blocks_holder.rs2 pre_cmd.inst.rd := j_blocks_holder.rd + val comp_cmd_rs1 = Wire(new GemminiISA.ComputeCmd.Rs1(local_addr_t, block_size, max_block_len)) + comp_cmd_rs1 := DontCare + comp_cmd_rs1.a_rows := a_rows + comp_cmd_rs1.a_cols := a_cols + comp_cmd_rs1.a := 0.U.asTypeOf(local_addr_t) + comp_cmd_rs1.a.data := a_addr + val comp_cmd = Wire(new RoCCCommand()) comp_cmd := DontCare comp_cmd.inst.funct := Mux(i === 0.U || req.ooo, COMPUTE_AND_FLIP_CMD, COMPUTE_AND_STAY_CMD) - comp_cmd.rs1 := a_addr | (a_cols << 32).asUInt() | (a_rows << 48).asUInt() + comp_cmd.rs1 := comp_cmd_rs1.asUInt() comp_cmd.rs2 := GARBAGE_ADDR | (block_size.U << 32).asUInt() | (block_size.U << 48).asUInt() comp_cmd.inst.opcode := k_blocks_holder.opcode comp_cmd.inst.rs1 := k_blocks_holder.rs1 @@ -529,7 +592,7 @@ class LoopMatmulStCReq(val block_size: Int, val coreMaxAddrBits: Int, val iterat val loop_id = UInt(log2Up(concurrent_loops).W) } -class LoopMatmulStC(block_size: Int, coreMaxAddrBits: Int, iterator_bitwidth: Int, max_acc_addr: Int, input_w: Int, acc_w: Int, max_block_len: Int, concurrent_loops: Int, cmd_t: GemminiCmd) +class LoopMatmulStC(block_size: Int, coreMaxAddrBits: Int, iterator_bitwidth: Int, max_acc_addr: Int, input_w: Int, acc_w: Int, max_block_len: Int, concurrent_loops: Int, cmd_t: GemminiCmd, local_addr_t: LocalAddr) (implicit p: Parameters) extends Module { val io = IO(new Bundle { val req = Flipped(Decoupled(new LoopMatmulStCReq(block_size, coreMaxAddrBits, iterator_bitwidth, max_acc_addr, concurrent_loops))) @@ -562,20 +625,31 @@ class LoopMatmulStC(block_size: Int, coreMaxAddrBits: Int, iterator_bitwidth: In val j = Reg(UInt(iterator_bitwidth.W)) val i = Reg(UInt(iterator_bitwidth.W)) - val acc_addr_start = (BigInt(1) << 31).U | (req.full_c << 29.U).asUInt() | req.addr_start - val dram_addr = Mux(req.full_c, req.dram_addr + (i * req.dram_stride + j) * block_size.U * (acc_w/8).U, req.dram_addr + (i * req.dram_stride + j) * block_size.U * (input_w/8).U) - val sp_addr = acc_addr_start + (i * req.max_j + j) * block_size.U + val sp_addr = req.addr_start + (i * req.max_j + j) * block_size.U val blocks = Mux(j + max_blocks <= req.max_j, max_blocks, req.max_j-j) val cols = (blocks * block_size.U) - Mux(j + blocks >= req.max_j, req.pad_j, 0.U) val rows = block_size.U - Mux(i === req.max_i-1.U, req.pad_i, 0.U) + val mvout_cmd_rs1 = Wire(new GemminiISA.LoadCmd.Rs1(coreMaxAddrBits)) + mvout_cmd_rs1 := DontCare + mvout_cmd_rs1.dram_addr := dram_addr + + val mvout_cmd_rs2 = Wire(new GemminiISA.LoadCmd.Rs2(local_addr_t)) + mvout_cmd_rs2 := DontCare + mvout_cmd_rs2.rows := rows + mvout_cmd_rs2.cols := cols + mvout_cmd_rs2.spad_addr := 0.U.asTypeOf(local_addr_t) + mvout_cmd_rs2.spad_addr.is_acc_addr := true.B + mvout_cmd_rs2.spad_addr.read_full_acc_row := req.full_c + mvout_cmd_rs2.spad_addr.data := sp_addr + val mvout_cmd = Wire(new RoCCCommand) mvout_cmd := DontCare mvout_cmd.inst.funct := STORE_CMD - mvout_cmd.rs1 := dram_addr - mvout_cmd.rs2 := (rows << 48).asUInt() | (cols << 32).asUInt() | sp_addr + mvout_cmd.rs1 := mvout_cmd_rs1.asUInt() + mvout_cmd.rs2 := mvout_cmd_rs2.asUInt() io.req.ready := state === idle io.j := j @@ -697,7 +771,7 @@ class LoopMatmulState(val iterator_bitwidth: Int, val coreMaxAddrBits: Int, val } class LoopMatmul(block_size: Int, coreMaxAddrBits: Int, rob_size: Int, rob_full_entries: Int, max_lds: Int, max_exs: Int, max_sts: Int, - max_addr: Int, max_acc_addr: Int, input_w: Int, acc_w: Int, dma_max_bytes: Int, cmd_t: GemminiCmd, ex_total_k_portions: Int, ex_fine_grained_interleaving: Boolean) + max_addr: Int, max_acc_addr: Int, input_w: Int, acc_w: Int, dma_max_bytes: Int, cmd_t: GemminiCmd, ex_total_k_portions: Int, ex_fine_grained_interleaving: Boolean, local_addr_t: LocalAddr) (implicit p: Parameters) extends Module { val iterator_bitwidth = 16 val max_block_len = (dma_max_bytes / (block_size * input_w / 8)) max 1 @@ -727,14 +801,14 @@ class LoopMatmul(block_size: Int, coreMaxAddrBits: Int, rob_size: Int, rob_full_ val loop_being_configured = loops(loop_being_configured_id) // Create inner modules - val ldA = Module(new LoopMatmulLdA(block_size, coreMaxAddrBits, iterator_bitwidth, max_addr, input_w, max_block_len, concurrent_loops, cmd_t)) - val ldB = Module(new LoopMatmulLdB(block_size, coreMaxAddrBits, iterator_bitwidth, max_addr, input_w, max_block_len, concurrent_loops, cmd_t)) - val ldD = Module(new LoopMatmulLdD(block_size, coreMaxAddrBits, iterator_bitwidth, max_acc_addr, input_w, acc_w, max_block_len, max_block_len_acc, concurrent_loops, cmd_t)) + val ldA = Module(new LoopMatmulLdA(block_size, coreMaxAddrBits, iterator_bitwidth, max_addr, input_w, max_block_len, concurrent_loops, cmd_t, local_addr_t)) + val ldB = Module(new LoopMatmulLdB(block_size, coreMaxAddrBits, iterator_bitwidth, max_addr, input_w, max_block_len, concurrent_loops, cmd_t, local_addr_t)) + val ldD = Module(new LoopMatmulLdD(block_size, coreMaxAddrBits, iterator_bitwidth, max_acc_addr, input_w, acc_w, max_block_len, max_block_len_acc, concurrent_loops, cmd_t, local_addr_t)) // val ex = Module(new LoopMatmulExecute(block_size, coreMaxAddrBits, iterator_bitwidth, max_addr, max_acc_addr, max_block_len, concurrent_loops, cmd_t)) val exs = (0 until ex_total_k_portions).map { i => - Module(new LoopMatmulExecute(block_size, coreMaxAddrBits, iterator_bitwidth, max_addr, max_acc_addr, max_block_len, concurrent_loops, cmd_t, total_k_portions = ex_total_k_portions, k_portion = i, fine_grained_interleaving = ex_fine_grained_interleaving)) + Module(new LoopMatmulExecute(block_size, coreMaxAddrBits, iterator_bitwidth, max_addr, max_acc_addr, max_block_len, concurrent_loops, cmd_t, total_k_portions = ex_total_k_portions, k_portion = i, fine_grained_interleaving = ex_fine_grained_interleaving, local_addr_t)) } - val stC = Module(new LoopMatmulStC(block_size, coreMaxAddrBits, iterator_bitwidth, max_acc_addr, input_w, acc_w, max_block_len, concurrent_loops, cmd_t)) + val stC = Module(new LoopMatmulStC(block_size, coreMaxAddrBits, iterator_bitwidth, max_acc_addr, input_w, acc_w, max_block_len, concurrent_loops, cmd_t, local_addr_t)) // Create command queue val cmd = Queue(io.in) @@ -797,7 +871,7 @@ class LoopMatmul(block_size: Int, coreMaxAddrBits: Int, rob_size: Int, rob_full_ */ val other_exs = exs.filter(_ != ex) - val must_wait_for_other_compute = other_exs.map(_.io.must_send_compute).reduce(_ || _) + val must_wait_for_other_compute = if (ex_total_k_portions == 1) { false.B } else { other_exs.map(_.io.must_send_compute).reduce(_ || _) } val limits = if (ex_total_k_portions == 1) { Seq(rob_full_entries) } else { (1 to ex_total_k_portions).map(i => rob_full_entries / i) } val limits_uint = VecInit(limits.map(_.U)) @@ -1101,10 +1175,12 @@ class LoopMatmul(block_size: Int, coreMaxAddrBits: Int, rob_size: Int, rob_full_ object LoopMatmul { def apply(in: DecoupledIO[RoCCCommand], ld_utilization: UInt, st_utilization: UInt, ex_utilization: UInt, ex_k_utilizations: Vec[UInt], block_size: Int, coreMaxAddrBits: Int, rob_size: Int, rob_full_entries: Int, max_lds: Int, max_exs: Int, max_sts: Int, - max_addr: Int, max_acc_addr: Int, input_w: Int, acc_w: Int, dma_max_bytes: Int, cmd_t: GemminiCmd, ex_total_k_portions: Int, ex_fine_grained_interleaving: Boolean) + max_addr: Int, max_acc_addr: Int, input_w: Int, acc_w: Int, dma_max_bytes: Int, cmd_t: GemminiCmd, ex_total_k_portions: Int, ex_fine_grained_interleaving: Boolean, + local_addr_t: LocalAddr) (implicit p: Parameters): Tuple2[DecoupledIO[GemminiCmd], Bool] = { val mod = Module(new LoopMatmul(block_size, coreMaxAddrBits, rob_size, rob_full_entries, max_lds, max_exs, max_sts, - max_addr, max_acc_addr, input_w, acc_w, dma_max_bytes, cmd_t, ex_total_k_portions, ex_fine_grained_interleaving)) + max_addr, max_acc_addr, input_w, acc_w, dma_max_bytes, cmd_t, ex_total_k_portions, ex_fine_grained_interleaving, + local_addr_t)) mod.io.in <> in mod.io.ld_utilization := ld_utilization mod.io.st_utilization := st_utilization From 6b2b9b5b9dd01a307932e834a777ae5f2fc737d6 Mon Sep 17 00:00:00 2001 From: Hasan Genc Date: Tue, 13 Jul 2021 02:20:20 -0700 Subject: [PATCH 64/78] Add cloneTypes to Bundle elements --- src/main/scala/gemmini/GemminiISA.scala | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/main/scala/gemmini/GemminiISA.scala b/src/main/scala/gemmini/GemminiISA.scala index f6b6520b0..3d08e83ae 100644 --- a/src/main/scala/gemmini/GemminiISA.scala +++ b/src/main/scala/gemmini/GemminiISA.scala @@ -71,7 +71,7 @@ object GemminiISA { val rows = UInt((16 min maxLocalAddrBits).W) val garbage2 = UInt(((16 - maxLocalAddrBits) max 0).W) val cols = UInt((16 min maxLocalAddrBits).W) - val spad_addr = local_addr_t + val spad_addr = local_addr_t.cloneType override def cloneType: Rs2.this.type = new Rs2(local_addr_t).asInstanceOf[this.type] } @@ -90,7 +90,7 @@ object GemminiISA { val rows = UInt((16 min maxLocalAddrBits).W) val garbage2 = UInt(((16 - maxLocalAddrBits) max 0).W) val cols = UInt((16 min maxLocalAddrBits).W) - val spad_addr = local_addr_t + val spad_addr = local_addr_t.cloneType override def cloneType: Rs2.this.type = new Rs2(local_addr_t).asInstanceOf[this.type] } @@ -104,7 +104,7 @@ object GemminiISA { val bd_rows = UInt(log2Up(block_size+1).W) val garbage2 = UInt((16 - log2Up(block_size+1)).W) val bd_cols = UInt(log2Up(block_size+1).W) - val bd = local_addr_t + val bd = local_addr_t.cloneType override def cloneType: Rs1.this.type = new Rs1(local_addr_t, block_size).asInstanceOf[this.type] } @@ -116,7 +116,7 @@ object GemminiISA { val c_rows = UInt(log2Up(max_block_len*block_size+1).W) val garbage2 = UInt((16 - log2Up(max_block_len*block_size+1)).W) val c_cols = UInt(log2Up(max_block_len*block_size+1).W) - val c = local_addr_t + val c = local_addr_t.cloneType override def cloneType: Rs2.this.type = new Rs2(local_addr_t, block_size, max_block_len).asInstanceOf[this.type] } @@ -130,7 +130,7 @@ object GemminiISA { val a_rows = UInt(log2Up(max_block_len*block_size+1).W) val garbage2 = UInt((16 - log2Up(max_block_len*block_size+1)).W) val a_cols = UInt(log2Up(max_block_len*block_size+1).W) - val a = local_addr_t + val a = local_addr_t.cloneType override def cloneType: Rs1.this.type = new Rs1(local_addr_t, block_size, max_block_len).asInstanceOf[this.type] } @@ -142,7 +142,7 @@ object GemminiISA { val bd_rows = UInt(log2Up(block_size+1).W) val garbage2 = UInt((16 - log2Up(block_size+1)).W) val bd_cols = UInt(log2Up(block_size+1).W) - val bd = local_addr_t + val bd = local_addr_t.cloneType override def cloneType: Rs2.this.type = new Rs2(local_addr_t, block_size).asInstanceOf[this.type] } From 598d8edfc75e3a2eef5e99acb834e4116a1cb7d0 Mon Sep 17 00:00:00 2001 From: Hasan Genc Date: Wed, 14 Jul 2021 10:31:36 -0700 Subject: [PATCH 65/78] Fix pre_addr garbage calculation --- src/main/scala/gemmini/LoopMatmul.scala | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/scala/gemmini/LoopMatmul.scala b/src/main/scala/gemmini/LoopMatmul.scala index 232c0de5c..01ac596dd 100644 --- a/src/main/scala/gemmini/LoopMatmul.scala +++ b/src/main/scala/gemmini/LoopMatmul.scala @@ -456,10 +456,10 @@ class LoopMatmulExecute(block_size: Int, coreMaxAddrBits: Int, iterator_bitwidth val c_cols = block_size.U - Mux(j === req.max_j - 1.U, req.pad_j, 0.U) val c_rows = i_blocks * block_size.U - Mux(i + max_i_blocks >= req.max_i, req.pad_i, 0.U) - val pre_addr_is_garbage = i === 0.U || req.ooo + val pre_addr_is_not_garbage = i === 0.U || req.ooo val out_addr_accumulates = req.accumulate || k =/= 0.U - val pre_addr = Mux(pre_addr_is_garbage, b_addr, GARBAGE_ADDR) + val pre_addr = Mux(pre_addr_is_not_garbage, b_addr, GARBAGE_ADDR) val out_addr = Mux(out_addr_accumulates, c_addr, d_addr) val j_blocks_holder = req.max_j.asTypeOf(new blocks_holder_t) @@ -472,7 +472,7 @@ class LoopMatmulExecute(block_size: Int, coreMaxAddrBits: Int, iterator_bitwidth pre_cmd_rs1.bd := 0.U.asTypeOf(local_addr_t) pre_cmd_rs1.bd.data := pre_addr - when (pre_addr_is_garbage) { + when (!pre_addr_is_not_garbage) { pre_cmd_rs1.bd.make_this_garbage() } From 5ee1c7e224fc82d7072b6312d0eb0dd00fedc329 Mon Sep 17 00:00:00 2001 From: Hasan Genc Date: Wed, 14 Jul 2021 11:29:21 -0700 Subject: [PATCH 66/78] Turn off k portions by default --- src/main/scala/gemmini/GemminiConfigs.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/scala/gemmini/GemminiConfigs.scala b/src/main/scala/gemmini/GemminiConfigs.scala index ae69ec702..ed577d923 100644 --- a/src/main/scala/gemmini/GemminiConfigs.scala +++ b/src/main/scala/gemmini/GemminiConfigs.scala @@ -78,7 +78,7 @@ case class GemminiArrayConfig[T <: Data : Arithmetic, U <: Data, V <: Data]( delay_lds: Boolean = false, // ALON: Should loads be stalled? delay_sts: Boolean = false, // ALON: Should stores be stalled? - ex_total_k_portions: Int = 2, // ALON: You can change this to any number of k-portions that you would like + ex_total_k_portions: Int = 1, // ALON: You can change this to any number of k-portions that you would like ex_fine_grained_interleaving: Boolean = true, // ALON: If this is true, then we use the newer ("finer") intervleaving strategy headerFileName: String = "gemmini_params.h" From 294d4e2b5f366a6ce5c0a3246154daa2ad8d6b55 Mon Sep 17 00:00:00 2001 From: Hasan Genc Date: Sat, 17 Jul 2021 11:17:23 -0700 Subject: [PATCH 67/78] Add lean ROB option --- src/main/scala/gemmini/GemminiConfigs.scala | 2 ++ src/main/scala/gemmini/ROB.scala | 8 ++++++-- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/src/main/scala/gemmini/GemminiConfigs.scala b/src/main/scala/gemmini/GemminiConfigs.scala index ed577d923..69204bdd2 100644 --- a/src/main/scala/gemmini/GemminiConfigs.scala +++ b/src/main/scala/gemmini/GemminiConfigs.scala @@ -81,6 +81,8 @@ case class GemminiArrayConfig[T <: Data : Arithmetic, U <: Data, V <: Data]( ex_total_k_portions: Int = 1, // ALON: You can change this to any number of k-portions that you would like ex_fine_grained_interleaving: Boolean = true, // ALON: If this is true, then we use the newer ("finer") intervleaving strategy + lean_ooo_rob: Boolean = true, // No garbage preloads + headerFileName: String = "gemmini_params.h" ) { val sp_width = meshColumns * tileColumns * inputType.getWidth diff --git a/src/main/scala/gemmini/ROB.scala b/src/main/scala/gemmini/ROB.scala index 209243d3a..1c7873b0f 100644 --- a/src/main/scala/gemmini/ROB.scala +++ b/src/main/scala/gemmini/ROB.scala @@ -428,13 +428,13 @@ class ROB[T <: Data : Arithmetic, U <: Data, V <: Data](config: GemminiArrayConf val ooo_q = (ld_ooo.B && new_entry.q === ldq) || (ex_ooo_is_enabled && new_entry.q === exq) || (st_ooo.B && new_entry.q === stq) val is_last_preload = last_allocated_preload.valid && i.U === last_allocated_preload.bits - val is_last_garbage_preload = last_allocated_garbage_preload.valid && i.U === last_allocated_garbage_preload.bits + val is_last_garbage_preload = !lean_ooo_rob.B && last_allocated_garbage_preload.valid && i.U === last_allocated_garbage_preload.bits val new_entry_is_compute = new_entry.cmd.inst.funct === COMPUTE_AND_STAY_CMD || new_entry.cmd.inst.funct === COMPUTE_AND_FLIP_CMD val new_entry_is_preload = new_entry.cmd.inst.funct === PRELOAD_CMD val preload_addr = new_entry.cmd.rs1(31, 0).asTypeOf(local_addr_t) // TODO magic number - val preload_garbage = preload_addr.is_garbage() + val preload_garbage = !lean_ooo_rob.B && preload_addr.is_garbage() e.valid && e.bits.q === new_entry.q && !e.bits.issued && (!ooo_q || e.bits.is_config || new_entry.is_config || @@ -669,6 +669,10 @@ class ROB[T <: Data : Arithmetic, U <: Data, V <: Data](config: GemminiArrayConf printf(p"Packed deps: $packed_deps\n") } + if (lean_ooo_rob) { + last_allocated_garbage_preload.pop() + } + when (reset.asBool()) { entries.foreach(_.pop()) last_allocated_preload.pop() From 41aa2d42bd55173339178884efabf0c8bf2bb166 Mon Sep 17 00:00:00 2001 From: Hasan Genc Date: Sat, 17 Jul 2021 12:34:59 -0700 Subject: [PATCH 68/78] Fix weightA arbiter --- src/main/scala/gemmini/LoopMatmul.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/scala/gemmini/LoopMatmul.scala b/src/main/scala/gemmini/LoopMatmul.scala index af8a84c73..12c499959 100644 --- a/src/main/scala/gemmini/LoopMatmul.scala +++ b/src/main/scala/gemmini/LoopMatmul.scala @@ -816,7 +816,7 @@ class LoopMatmul(block_size: Int, coreMaxAddrBits: Int, rob_size: Int, rob_full_ io.busy := cmd.valid || loop_configured // Create ld arbiters - val ldab_arb = Module(new WeightedArbiter(new RoCCCommand(), maxWeightA=255, staticWeightAEnabled=true, onlyStaticWeightA=lean_weightA)) // TODO magic numbers + val ldab_arb = Module(new WeightedArbiter(cmd_t, maxWeightA=255, staticWeightAEnabled=true, onlyStaticWeightA=lean_weightA)) // TODO magic numbers ldab_arb.io.inA <> ldA.io.cmd ldab_arb.io.inB <> ldB.io.cmd val ab_loads_on_same_loop = ldA.io.loop_id === ldB.io.loop_id From 60ad23d9df75616f24852d21ff5cba4d56e49a47 Mon Sep 17 00:00:00 2001 From: Hasan Genc Date: Sat, 17 Jul 2021 13:10:29 -0700 Subject: [PATCH 69/78] Consolidate ex-k-portion multipliers --- src/main/scala/gemmini/LoopMatmul.scala | 175 +++++++++++++++++++++++- 1 file changed, 174 insertions(+), 1 deletion(-) diff --git a/src/main/scala/gemmini/LoopMatmul.scala b/src/main/scala/gemmini/LoopMatmul.scala index 12c499959..3b0ced7ee 100644 --- a/src/main/scala/gemmini/LoopMatmul.scala +++ b/src/main/scala/gemmini/LoopMatmul.scala @@ -391,6 +391,9 @@ class LoopMatmulExecute(block_size: Int, coreMaxAddrBits: Int, iterator_bitwidth val req = Flipped(Decoupled(new LoopMatmulExecuteReq(block_size, coreMaxAddrBits, iterator_bitwidth, max_addr, max_acc_addr, concurrent_loops))) val cmd = Decoupled(Output(cmd_t)) + val req_out = Output(new LoopMatmulExecuteReq(block_size, coreMaxAddrBits, iterator_bitwidth, max_addr, max_acc_addr, concurrent_loops)) + val is_pre = Output(Bool()) + val k = Output(UInt(iterator_bitwidth.W)) val j = Output(UInt(iterator_bitwidth.W)) val i = Output(UInt(iterator_bitwidth.W)) @@ -420,6 +423,7 @@ class LoopMatmulExecute(block_size: Int, coreMaxAddrBits: Int, iterator_bitwidth val state = RegInit(idle) val req = Reg(new LoopMatmulExecuteReq(block_size, coreMaxAddrBits, iterator_bitwidth, max_addr, max_acc_addr, concurrent_loops)) + io.req_out := req val max_i_blocks = Mux(req.a_tranpose, 1.U, Mux(req.max_i <= max_block_len.U, req.max_i, max_block_len.U)) @@ -528,6 +532,8 @@ class LoopMatmulExecute(block_size: Int, coreMaxAddrBits: Int, iterator_bitwidth io.can_send_command := state =/= idle && ld_ahead io.cmd.valid := state =/= idle && !io.rob_overloaded && ld_ahead + io.cmd.bits := DontCare + /* io.cmd.bits.cmd := Mux(state === pre, pre_cmd, comp_cmd) io.cmd.bits.rob_id := DontCare io.cmd.bits.i := i @@ -537,10 +543,13 @@ class LoopMatmulExecute(block_size: Int, coreMaxAddrBits: Int, iterator_bitwidth io.cmd.bits.max_j := req.max_j io.cmd.bits.max_k := req.max_k io.cmd.bits.use_iterators := true.B + */ io.cmd.bits.ex_k_portion := k_portion.U io.loop_id := req.loop_id + io.is_pre := state === pre + when (io.cmd.fire()) { when (state === pre) { state := comp @@ -577,6 +586,136 @@ class LoopMatmulExecute(block_size: Int, coreMaxAddrBits: Int, iterator_bitwidth assert(!(state =/= idle && req.a_tranpose && req.b_tranpose)) } +class LoopMatmulExecuteAddrGenerator(block_size: Int, coreMaxAddrBits: Int, iterator_bitwidth: Int, max_addr: Int, max_acc_addr: Int, max_block_len: Int, concurrent_loops: Int, cmd_t: GemminiCmd, total_k_portions: Int, fine_grained_interleaving: Boolean, local_addr_t: LocalAddr) + (implicit p: Parameters) extends Module { + val GARBAGE_ADDR = (~0.U(32.W)).asUInt() + + val rocc_cmd_t = new RoCCCommand + class blocks_holder_t extends Bundle { + val opcode = UInt(rocc_cmd_t.inst.opcode.getWidth.W) + val rs1 = UInt(rocc_cmd_t.inst.rs1.getWidth.W) + val rs2 = UInt(rocc_cmd_t.inst.rs2.getWidth.W) + val rd = UInt(rocc_cmd_t.inst.rd.getWidth.W) + + override def cloneType: blocks_holder_t.this.type = (new blocks_holder_t).asInstanceOf[this.type] + } + + val io = IO(new Bundle { + val req = Input(new LoopMatmulExecuteReq(block_size, coreMaxAddrBits, iterator_bitwidth, max_addr, max_acc_addr, concurrent_loops)) + val k = Input(UInt(iterator_bitwidth.W)) + val j = Input(UInt(iterator_bitwidth.W)) + val i = Input(UInt(iterator_bitwidth.W)) + val is_pre = Input(Bool()) + val k_portion = Input(UInt(log2Up(total_k_portions).W)) + + val cmd = Output(cmd_t) + }) + + val req = io.req + val is_pre = io.is_pre + val k_portion = io.k_portion + + val max_i_blocks = Mux(req.a_tranpose, 1.U, Mux(req.max_i <= max_block_len.U, req.max_i, max_block_len.U)) + + val d_addr_start = (BigInt(1) << 31).U | req.c_addr_start + val c_addr_start = (BigInt(3) << 30).U | req.c_addr_start + val b_addr_start = req.b_addr_end - req.max_k * req.max_j * block_size.U + + val k = io.k + val j = io.j + val i = io.i + + val i_blocks = Mux(i + max_i_blocks <= req.max_i, max_i_blocks, req.max_i-i) + + val a_row = Mux(req.a_tranpose, k, i) + val a_col = Mux(req.a_tranpose, i, k) + val b_row = Mux(req.b_tranpose, j, k) + val b_col = Mux(req.b_tranpose, k, j) + + val a_max_col = Mux(req.a_tranpose, req.max_i, req.max_k) + val b_max_col = Mux(req.b_tranpose, req.max_k, req.max_j) + + val a_addr = req.a_addr_start + (a_row * a_max_col + a_col) * block_size.U + val b_addr = b_addr_start + (b_row * b_max_col + b_col) * block_size.U + val d_addr = d_addr_start + (i * req.max_j + j) * block_size.U + val c_addr = c_addr_start + (i * req.max_j + j) * block_size.U + + val a_cols = block_size.U - Mux(k === req.max_k - 1.U, req.pad_k, 0.U) + val a_rows = i_blocks * block_size.U - Mux(i + max_i_blocks >= req.max_i, req.pad_i, 0.U) + val b_cols = block_size.U - Mux(j === req.max_j - 1.U, req.pad_j, 0.U) + val b_rows = block_size.U - Mux(k === req.max_k - 1.U, req.pad_k, 0.U) + val c_cols = block_size.U - Mux(j === req.max_j - 1.U, req.pad_j, 0.U) + val c_rows = i_blocks * block_size.U - Mux(i + max_i_blocks >= req.max_i, req.pad_i, 0.U) + + val pre_addr_is_not_garbage = i === 0.U || req.ooo + val out_addr_accumulates = req.accumulate || k =/= 0.U + + val pre_addr = Mux(pre_addr_is_not_garbage, b_addr, GARBAGE_ADDR) + val out_addr = Mux(out_addr_accumulates, c_addr, d_addr) + + val j_blocks_holder = req.max_j.asTypeOf(new blocks_holder_t) + val k_blocks_holder = req.max_k.asTypeOf(new blocks_holder_t) + + val pre_cmd_rs1 = Wire(new GemminiISA.PreloadCmd.Rs1(local_addr_t, block_size)) + pre_cmd_rs1 := DontCare + pre_cmd_rs1.bd_rows := b_rows + pre_cmd_rs1.bd_cols := b_cols + pre_cmd_rs1.bd := 0.U.asTypeOf(local_addr_t) + pre_cmd_rs1.bd.data := pre_addr + + when (!pre_addr_is_not_garbage) { + pre_cmd_rs1.bd.make_this_garbage() + } + + val pre_cmd_rs2 = Wire(new GemminiISA.PreloadCmd.Rs2(local_addr_t, block_size, max_block_len)) + pre_cmd_rs2 := DontCare + pre_cmd_rs2.c_rows := c_rows + pre_cmd_rs2.c_cols := c_cols + pre_cmd_rs2.c := 0.U.asTypeOf(local_addr_t) + pre_cmd_rs2.c.is_acc_addr := true.B + pre_cmd_rs2.c.accumulate := out_addr_accumulates + pre_cmd_rs2.c.data := out_addr + + val pre_cmd = Wire(new RoCCCommand) + pre_cmd := DontCare + pre_cmd.inst.funct := PRELOAD_CMD + pre_cmd.rs1 := pre_cmd_rs1.asUInt() + pre_cmd.rs2 := pre_cmd_rs2.asUInt() + pre_cmd.inst.opcode := j_blocks_holder.opcode + pre_cmd.inst.rs1 := j_blocks_holder.rs1 + pre_cmd.inst.rs2 := j_blocks_holder.rs2 + pre_cmd.inst.rd := j_blocks_holder.rd + + val comp_cmd_rs1 = Wire(new GemminiISA.ComputeCmd.Rs1(local_addr_t, block_size, max_block_len)) + comp_cmd_rs1 := DontCare + comp_cmd_rs1.a_rows := a_rows + comp_cmd_rs1.a_cols := a_cols + comp_cmd_rs1.a := 0.U.asTypeOf(local_addr_t) + comp_cmd_rs1.a.data := a_addr + + val comp_cmd = Wire(new RoCCCommand()) + comp_cmd := DontCare + comp_cmd.inst.funct := Mux(i === 0.U || req.ooo, COMPUTE_AND_FLIP_CMD, COMPUTE_AND_STAY_CMD) + comp_cmd.rs1 := comp_cmd_rs1.asUInt() + comp_cmd.rs2 := GARBAGE_ADDR | (block_size.U << 32).asUInt() | (block_size.U << 48).asUInt() + comp_cmd.inst.opcode := k_blocks_holder.opcode + comp_cmd.inst.rs1 := k_blocks_holder.rs1 + comp_cmd.inst.rs2 := k_blocks_holder.rs2 + comp_cmd.inst.rd := k_blocks_holder.rd + + io.cmd.cmd := Mux(is_pre, pre_cmd, comp_cmd) + io.cmd.rob_id := DontCare + io.cmd.i := i + io.cmd.j := j + io.cmd.k := k + io.cmd.max_i := req.max_i + io.cmd.max_j := req.max_j + io.cmd.max_k := req.max_k + io.cmd.use_iterators := true.B + io.cmd.ex_k_portion := k_portion +} + + // StC class LoopMatmulStCReq(val block_size: Int, val coreMaxAddrBits: Int, val iterator_bitwidth: Int, val max_acc_addr: Int, val concurrent_loops: Int) extends Bundle { @@ -832,17 +971,51 @@ class LoopMatmul(block_size: Int, coreMaxAddrBits: Int, rob_size: Int, rob_full_ // Create ex arbiters // ALON: This is the arbiter between the k-portions. You could try out an RR arbiter instead. Right now, we're using Chisel's default arbiter which is a priority arbiter that prioritizes the earliest k-portions + class ExAddrGeneratorInput extends Bundle { + val req = exs.head.io.req_out.cloneType + val k = exs.head.io.k.cloneType + val j = exs.head.io.j.cloneType + val i = exs.head.io.i.cloneType + val is_pre = Bool() + val k_portion = UInt(log2Up(ex_total_k_portions).W) + + override def cloneType: ExAddrGeneratorInput.this.type = new ExAddrGeneratorInput().asInstanceOf[this.type] + } + val ex_arb = Module(new ExArbiter(new ExAddrGeneratorInput, ex_total_k_portions, ex_fine_grained_interleaving)) + (ex_arb.io.in, ex_arb.io.k, exs).zipped.foreach { case (in, k, ex) => + in.valid := ex.io.cmd.valid + ex.io.cmd.ready := in.ready + in.bits.req := ex.io.req_out + in.bits.k := ex.io.k + in.bits.j := ex.io.j + in.bits.i := ex.io.i + in.bits.is_pre := ex.io.is_pre + in.bits.k_portion := ex.io.cmd.bits.ex_k_portion + k := ex.io.k + } + val ex_addr_generator = Module(new LoopMatmulExecuteAddrGenerator(block_size, coreMaxAddrBits, iterator_bitwidth, max_addr, max_acc_addr, max_block_len, concurrent_loops, cmd_t, total_k_portions = ex_total_k_portions, fine_grained_interleaving = ex_fine_grained_interleaving, local_addr_t)) + ex_addr_generator.io.req := ex_arb.io.out.bits.req + ex_addr_generator.io.k := ex_arb.io.out.bits.k + ex_addr_generator.io.j := ex_arb.io.out.bits.j + ex_addr_generator.io.i := ex_arb.io.out.bits.i + ex_addr_generator.io.is_pre := ex_arb.io.out.bits.is_pre + ex_addr_generator.io.k_portion := ex_arb.io.out.bits.k_portion + /* val ex_arb = Module(new ExArbiter(cmd_t, ex_total_k_portions, ex_fine_grained_interleaving)) (ex_arb.io.in, ex_arb.io.k, exs).zipped.foreach { case (in, k, ex) => in <> ex.io.cmd k := ex.io.k } + */ // Create global arbiter val arb = Module(new Arbiter(cmd_t, 4)) arb.io.in(0) <> stC.io.cmd // arb.io.in(1) <> ex.io.cmd - arb.io.in(1) <> ex_arb.io.out + // arb.io.in(1) <> ex_arb.io.out + arb.io.in(1).valid := ex_arb.io.out.valid + arb.io.in(1).bits := ex_addr_generator.io.cmd + ex_arb.io.out.ready := arb.io.in(1).ready arb.io.in(2) <> ldD.io.cmd arb.io.in(3) <> ldab_arb.io.out val unrolled_cmd = arb.io.out From 1e182233df4f3a73756163f79817807e936cf8b4 Mon Sep 17 00:00:00 2001 From: Hasan Genc Date: Sat, 17 Jul 2021 13:40:16 -0700 Subject: [PATCH 70/78] Add configs for synthesis --- src/main/scala/gemmini/Configs.scala | 14 ++++++++++++++ src/main/scala/gemmini/Controller.scala | 3 ++- src/main/scala/gemmini/GemminiConfigs.scala | 2 ++ src/main/scala/gemmini/LoopMatmul.scala | 16 ++++++++-------- 4 files changed, 26 insertions(+), 9 deletions(-) diff --git a/src/main/scala/gemmini/Configs.scala b/src/main/scala/gemmini/Configs.scala index 96ca35193..8a75daf17 100644 --- a/src/main/scala/gemmini/Configs.scala +++ b/src/main/scala/gemmini/Configs.scala @@ -166,6 +166,20 @@ object GemminiConfigs { ) val leanConfig = defaultConfig.copy(dataflow=Dataflow.WS, max_in_flight_reqs = 64, acc_read_full_width = false, ex_read_from_acc = false, ex_write_to_spad = false, hardcode_d_to_garbage_addr = true) + + val synthesize_for_rob_ooo = leanConfig.copy(ld_ooo = false, ex_ooo = true, st_ooo = true, lean_ooo_rob = true) + val synthesize_for_rob_in_order = leanConfig.copy(ld_ooo = false, ex_ooo = false, st_ooo = false) + + val synthesize_for_microthreads_coarse_4_ooo = leanConfig.copy(ld_ooo = false, ex_ooo = true, st_ooo = true, lean_ooo_rob = true, ex_total_k_portions = 4, ex_fine_grained_interleaving = false) + val synthesize_for_microthreads_coarse_2_ooo = leanConfig.copy(ld_ooo = false, ex_ooo = true, st_ooo = true, lean_ooo_rob = true, ex_total_k_portions = 2, ex_fine_grained_interleaving = false) + + val synthesize_for_microthreads_fine_4_ooo = leanConfig.copy(ld_ooo = false, ex_ooo = true, st_ooo = true, lean_ooo_rob = true, ex_total_k_portions = 4, ex_fine_grained_interleaving = true) + val synthesize_for_microthreads_fine_2_ooo = leanConfig.copy(ld_ooo = false, ex_ooo = true, st_ooo = true, lean_ooo_rob = true, ex_total_k_portions = 2, ex_fine_grained_interleaving = true) + + val synthesize_for_microthreads_1_in_order = leanConfig.copy(ld_ooo = false, ex_ooo = false, st_ooo = false, ex_total_k_portions = 1, ex_fine_grained_interleaving = false) + + val synthesize_for_weightA_ooo = leanConfig.copy(ld_ooo = false, ex_ooo = true, st_ooo = true, staticWeightAEnabled = true, lean_weightA = true) + val synthesize_for_weightA_in_order = leanConfig.copy(ld_ooo = false, ex_ooo = false, st_ooo = false, staticWeightAEnabled = false, lean_weightA = false) } /** diff --git a/src/main/scala/gemmini/Controller.scala b/src/main/scala/gemmini/Controller.scala index 6291416ab..46b3ff797 100644 --- a/src/main/scala/gemmini/Controller.scala +++ b/src/main/scala/gemmini/Controller.scala @@ -135,7 +135,8 @@ class GemminiModule[T <: Data: Arithmetic, U <: Data, V <: Data] val (loop_cmd, loop_matmul_unroller_busy) = LoopMatmul(conv_cmd, rob.io.ld_utilization, rob.io.st_utilization, rob.io.ex_utilization, rob.io.ex_k_portion_utilizations, meshRows*tileRows, coreMaxAddrBits, rob_entries, rob_full_entries, max_lds, max_exs, max_sts, sp_banks * sp_bank_entries, acc_banks * acc_bank_entries, - inputType.getWidth, accType.getWidth, dma_maxbytes, new GemminiCmd(rob_entries), ex_total_k_portions, ex_fine_grained_interleaving, local_addr_t, lean_weightA) + inputType.getWidth, accType.getWidth, dma_maxbytes, new GemminiCmd(rob_entries), ex_total_k_portions, ex_fine_grained_interleaving, local_addr_t, lean_weightA, lean_ooo_rob, + staticWeightAEnabled) val unrolled_cmd = Queue(loop_cmd) unrolled_cmd.ready := false.B diff --git a/src/main/scala/gemmini/GemminiConfigs.scala b/src/main/scala/gemmini/GemminiConfigs.scala index b750550e1..aea78e480 100644 --- a/src/main/scala/gemmini/GemminiConfigs.scala +++ b/src/main/scala/gemmini/GemminiConfigs.scala @@ -84,6 +84,8 @@ case class GemminiArrayConfig[T <: Data : Arithmetic, U <: Data, V <: Data]( lean_ooo_rob: Boolean = true, // No garbage preloads lean_weightA: Boolean = true, // Only static weightA supported + staticWeightAEnabled: Boolean = true, + headerFileName: String = "gemmini_params.h" ) { val sp_width = meshColumns * tileColumns * inputType.getWidth diff --git a/src/main/scala/gemmini/LoopMatmul.scala b/src/main/scala/gemmini/LoopMatmul.scala index 3b0ced7ee..adff9ac2a 100644 --- a/src/main/scala/gemmini/LoopMatmul.scala +++ b/src/main/scala/gemmini/LoopMatmul.scala @@ -586,7 +586,7 @@ class LoopMatmulExecute(block_size: Int, coreMaxAddrBits: Int, iterator_bitwidth assert(!(state =/= idle && req.a_tranpose && req.b_tranpose)) } -class LoopMatmulExecuteAddrGenerator(block_size: Int, coreMaxAddrBits: Int, iterator_bitwidth: Int, max_addr: Int, max_acc_addr: Int, max_block_len: Int, concurrent_loops: Int, cmd_t: GemminiCmd, total_k_portions: Int, fine_grained_interleaving: Boolean, local_addr_t: LocalAddr) +class LoopMatmulExecuteAddrGenerator(block_size: Int, coreMaxAddrBits: Int, iterator_bitwidth: Int, max_addr: Int, max_acc_addr: Int, max_block_len: Int, concurrent_loops: Int, cmd_t: GemminiCmd, total_k_portions: Int, fine_grained_interleaving: Boolean, local_addr_t: LocalAddr, no_garbage_preload: Boolean) (implicit p: Parameters) extends Module { val GARBAGE_ADDR = (~0.U(32.W)).asUInt() @@ -647,7 +647,7 @@ class LoopMatmulExecuteAddrGenerator(block_size: Int, coreMaxAddrBits: Int, iter val c_cols = block_size.U - Mux(j === req.max_j - 1.U, req.pad_j, 0.U) val c_rows = i_blocks * block_size.U - Mux(i + max_i_blocks >= req.max_i, req.pad_i, 0.U) - val pre_addr_is_not_garbage = i === 0.U || req.ooo + val pre_addr_is_not_garbage = i === 0.U || req.ooo || no_garbage_preload.B val out_addr_accumulates = req.accumulate || k =/= 0.U val pre_addr = Mux(pre_addr_is_not_garbage, b_addr, GARBAGE_ADDR) @@ -910,7 +910,7 @@ class LoopMatmulState(val iterator_bitwidth: Int, val coreMaxAddrBits: Int, val } class LoopMatmul(block_size: Int, coreMaxAddrBits: Int, rob_size: Int, rob_full_entries: Int, max_lds: Int, max_exs: Int, max_sts: Int, - max_addr: Int, max_acc_addr: Int, input_w: Int, acc_w: Int, dma_max_bytes: Int, cmd_t: GemminiCmd, ex_total_k_portions: Int, ex_fine_grained_interleaving: Boolean, local_addr_t: LocalAddr, lean_weightA: Boolean) + max_addr: Int, max_acc_addr: Int, input_w: Int, acc_w: Int, dma_max_bytes: Int, cmd_t: GemminiCmd, ex_total_k_portions: Int, ex_fine_grained_interleaving: Boolean, local_addr_t: LocalAddr, lean_weightA: Boolean, lean_ooo_rob: Boolean, staticWeightAEnabled: Boolean) (implicit p: Parameters) extends Module { val iterator_bitwidth = 16 val max_block_len = (dma_max_bytes / (block_size * input_w / 8)) max 1 @@ -955,7 +955,7 @@ class LoopMatmul(block_size: Int, coreMaxAddrBits: Int, rob_size: Int, rob_full_ io.busy := cmd.valid || loop_configured // Create ld arbiters - val ldab_arb = Module(new WeightedArbiter(cmd_t, maxWeightA=255, staticWeightAEnabled=true, onlyStaticWeightA=lean_weightA)) // TODO magic numbers + val ldab_arb = Module(new WeightedArbiter(cmd_t, maxWeightA=255, staticWeightAEnabled=staticWeightAEnabled, onlyStaticWeightA=lean_weightA)) // TODO magic numbers ldab_arb.io.inA <> ldA.io.cmd ldab_arb.io.inB <> ldB.io.cmd val ab_loads_on_same_loop = ldA.io.loop_id === ldB.io.loop_id @@ -993,7 +993,7 @@ class LoopMatmul(block_size: Int, coreMaxAddrBits: Int, rob_size: Int, rob_full_ in.bits.k_portion := ex.io.cmd.bits.ex_k_portion k := ex.io.k } - val ex_addr_generator = Module(new LoopMatmulExecuteAddrGenerator(block_size, coreMaxAddrBits, iterator_bitwidth, max_addr, max_acc_addr, max_block_len, concurrent_loops, cmd_t, total_k_portions = ex_total_k_portions, fine_grained_interleaving = ex_fine_grained_interleaving, local_addr_t)) + val ex_addr_generator = Module(new LoopMatmulExecuteAddrGenerator(block_size, coreMaxAddrBits, iterator_bitwidth, max_addr, max_acc_addr, max_block_len, concurrent_loops, cmd_t, total_k_portions = ex_total_k_portions, fine_grained_interleaving = ex_fine_grained_interleaving, local_addr_t, lean_ooo_rob)) ex_addr_generator.io.req := ex_arb.io.out.bits.req ex_addr_generator.io.k := ex_arb.io.out.bits.k ex_addr_generator.io.j := ex_arb.io.out.bits.j @@ -1151,7 +1151,7 @@ class LoopMatmul(block_size: Int, coreMaxAddrBits: Int, rob_size: Int, rob_full_ loop_being_configured.b_transpose := cmd.bits.rs2(1) loop_being_configured.weightA := cmd.bits.rs1(15, 8) // TODO magic numbers - loop_being_configured.ooo := cmd.bits.rs2(2) // TODO magic numbers + loop_being_configured.ooo := lean_ooo_rob.B || cmd.bits.rs2(2) // TODO magic numbers loop_being_configured.configured := true.B @@ -1355,11 +1355,11 @@ object LoopMatmul { def apply(in: DecoupledIO[RoCCCommand], ld_utilization: UInt, st_utilization: UInt, ex_utilization: UInt, ex_k_utilizations: Vec[UInt], block_size: Int, coreMaxAddrBits: Int, rob_size: Int, rob_full_entries: Int, max_lds: Int, max_exs: Int, max_sts: Int, max_addr: Int, max_acc_addr: Int, input_w: Int, acc_w: Int, dma_max_bytes: Int, cmd_t: GemminiCmd, ex_total_k_portions: Int, ex_fine_grained_interleaving: Boolean, - local_addr_t: LocalAddr, lean_weightA: Boolean) + local_addr_t: LocalAddr, lean_weightA: Boolean, lean_ooo_rob: Boolean, staticWeightAEnabled: Boolean) (implicit p: Parameters): Tuple2[DecoupledIO[GemminiCmd], Bool] = { val mod = Module(new LoopMatmul(block_size, coreMaxAddrBits, rob_size, rob_full_entries, max_lds, max_exs, max_sts, max_addr, max_acc_addr, input_w, acc_w, dma_max_bytes, cmd_t, ex_total_k_portions, ex_fine_grained_interleaving, - local_addr_t, lean_weightA)) + local_addr_t, lean_weightA, lean_ooo_rob, staticWeightAEnabled)) mod.io.in <> in mod.io.ld_utilization := ld_utilization mod.io.st_utilization := st_utilization From a4e133ee1cfe39b54d6d93ddafa2b622ee218add Mon Sep 17 00:00:00 2001 From: Hasan Genc Date: Sat, 17 Jul 2021 13:49:38 -0700 Subject: [PATCH 71/78] Update configs --- src/main/scala/gemmini/Configs.scala | 4 ++-- src/main/scala/gemmini/GemminiConfigs.scala | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/main/scala/gemmini/Configs.scala b/src/main/scala/gemmini/Configs.scala index 8a75daf17..aa9fd2649 100644 --- a/src/main/scala/gemmini/Configs.scala +++ b/src/main/scala/gemmini/Configs.scala @@ -168,7 +168,7 @@ object GemminiConfigs { val leanConfig = defaultConfig.copy(dataflow=Dataflow.WS, max_in_flight_reqs = 64, acc_read_full_width = false, ex_read_from_acc = false, ex_write_to_spad = false, hardcode_d_to_garbage_addr = true) val synthesize_for_rob_ooo = leanConfig.copy(ld_ooo = false, ex_ooo = true, st_ooo = true, lean_ooo_rob = true) - val synthesize_for_rob_in_order = leanConfig.copy(ld_ooo = false, ex_ooo = false, st_ooo = false) + val synthesize_for_rob_in_order = leanConfig.copy(ld_ooo = false, ex_ooo = false, st_ooo = false, lean_ooo_rob = false) val synthesize_for_microthreads_coarse_4_ooo = leanConfig.copy(ld_ooo = false, ex_ooo = true, st_ooo = true, lean_ooo_rob = true, ex_total_k_portions = 4, ex_fine_grained_interleaving = false) val synthesize_for_microthreads_coarse_2_ooo = leanConfig.copy(ld_ooo = false, ex_ooo = true, st_ooo = true, lean_ooo_rob = true, ex_total_k_portions = 2, ex_fine_grained_interleaving = false) @@ -176,7 +176,7 @@ object GemminiConfigs { val synthesize_for_microthreads_fine_4_ooo = leanConfig.copy(ld_ooo = false, ex_ooo = true, st_ooo = true, lean_ooo_rob = true, ex_total_k_portions = 4, ex_fine_grained_interleaving = true) val synthesize_for_microthreads_fine_2_ooo = leanConfig.copy(ld_ooo = false, ex_ooo = true, st_ooo = true, lean_ooo_rob = true, ex_total_k_portions = 2, ex_fine_grained_interleaving = true) - val synthesize_for_microthreads_1_in_order = leanConfig.copy(ld_ooo = false, ex_ooo = false, st_ooo = false, ex_total_k_portions = 1, ex_fine_grained_interleaving = false) + val synthesize_for_microthreads_1_in_order = leanConfig.copy(ld_ooo = false, ex_ooo = false, st_ooo = false, lean_ooo_rob = true, ex_total_k_portions = 1, ex_fine_grained_interleaving = false) val synthesize_for_weightA_ooo = leanConfig.copy(ld_ooo = false, ex_ooo = true, st_ooo = true, staticWeightAEnabled = true, lean_weightA = true) val synthesize_for_weightA_in_order = leanConfig.copy(ld_ooo = false, ex_ooo = false, st_ooo = false, staticWeightAEnabled = false, lean_weightA = false) diff --git a/src/main/scala/gemmini/GemminiConfigs.scala b/src/main/scala/gemmini/GemminiConfigs.scala index aea78e480..fc9e75d7a 100644 --- a/src/main/scala/gemmini/GemminiConfigs.scala +++ b/src/main/scala/gemmini/GemminiConfigs.scala @@ -81,8 +81,8 @@ case class GemminiArrayConfig[T <: Data : Arithmetic, U <: Data, V <: Data]( ex_total_k_portions: Int = 1, // ALON: You can change this to any number of k-portions that you would like ex_fine_grained_interleaving: Boolean = true, // ALON: If this is true, then we use the newer ("finer") intervleaving strategy - lean_ooo_rob: Boolean = true, // No garbage preloads - lean_weightA: Boolean = true, // Only static weightA supported + lean_ooo_rob: Boolean = false, // No garbage preloads + lean_weightA: Boolean = false, // Only static weightA supported staticWeightAEnabled: Boolean = true, From 225edd608d017a3e1097e92f1955d5aa13b2580d Mon Sep 17 00:00:00 2001 From: Hasan Genc Date: Sat, 17 Jul 2021 13:52:52 -0700 Subject: [PATCH 72/78] Add comments --- src/main/scala/gemmini/Configs.scala | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/main/scala/gemmini/Configs.scala b/src/main/scala/gemmini/Configs.scala index aa9fd2649..9c25fe83f 100644 --- a/src/main/scala/gemmini/Configs.scala +++ b/src/main/scala/gemmini/Configs.scala @@ -167,19 +167,19 @@ object GemminiConfigs { val leanConfig = defaultConfig.copy(dataflow=Dataflow.WS, max_in_flight_reqs = 64, acc_read_full_width = false, ex_read_from_acc = false, ex_write_to_spad = false, hardcode_d_to_garbage_addr = true) - val synthesize_for_rob_ooo = leanConfig.copy(ld_ooo = false, ex_ooo = true, st_ooo = true, lean_ooo_rob = true) - val synthesize_for_rob_in_order = leanConfig.copy(ld_ooo = false, ex_ooo = false, st_ooo = false, lean_ooo_rob = false) + val synthesize_for_rob_ooo = leanConfig.copy(ld_ooo = false, ex_ooo = true, st_ooo = true, lean_ooo_rob = true) // Module ROB + val synthesize_for_rob_in_order = leanConfig.copy(ld_ooo = false, ex_ooo = false, st_ooo = false, lean_ooo_rob = false) // Module ROB - val synthesize_for_microthreads_coarse_4_ooo = leanConfig.copy(ld_ooo = false, ex_ooo = true, st_ooo = true, lean_ooo_rob = true, ex_total_k_portions = 4, ex_fine_grained_interleaving = false) - val synthesize_for_microthreads_coarse_2_ooo = leanConfig.copy(ld_ooo = false, ex_ooo = true, st_ooo = true, lean_ooo_rob = true, ex_total_k_portions = 2, ex_fine_grained_interleaving = false) + val synthesize_for_microthreads_coarse_4_ooo = leanConfig.copy(ld_ooo = false, ex_ooo = true, st_ooo = true, lean_ooo_rob = true, ex_total_k_portions = 4, ex_fine_grained_interleaving = false) // Module LoopMatmul + val synthesize_for_microthreads_coarse_2_ooo = leanConfig.copy(ld_ooo = false, ex_ooo = true, st_ooo = true, lean_ooo_rob = true, ex_total_k_portions = 2, ex_fine_grained_interleaving = false) // Module LoopMatmul - val synthesize_for_microthreads_fine_4_ooo = leanConfig.copy(ld_ooo = false, ex_ooo = true, st_ooo = true, lean_ooo_rob = true, ex_total_k_portions = 4, ex_fine_grained_interleaving = true) - val synthesize_for_microthreads_fine_2_ooo = leanConfig.copy(ld_ooo = false, ex_ooo = true, st_ooo = true, lean_ooo_rob = true, ex_total_k_portions = 2, ex_fine_grained_interleaving = true) + val synthesize_for_microthreads_fine_4_ooo = leanConfig.copy(ld_ooo = false, ex_ooo = true, st_ooo = true, lean_ooo_rob = true, ex_total_k_portions = 4, ex_fine_grained_interleaving = true) // Module LoopMatmul + val synthesize_for_microthreads_fine_2_ooo = leanConfig.copy(ld_ooo = false, ex_ooo = true, st_ooo = true, lean_ooo_rob = true, ex_total_k_portions = 2, ex_fine_grained_interleaving = true) // Module LoopMatmul - val synthesize_for_microthreads_1_in_order = leanConfig.copy(ld_ooo = false, ex_ooo = false, st_ooo = false, lean_ooo_rob = true, ex_total_k_portions = 1, ex_fine_grained_interleaving = false) + val synthesize_for_microthreads_1_in_order = leanConfig.copy(ld_ooo = false, ex_ooo = false, st_ooo = false, lean_ooo_rob = true, ex_total_k_portions = 1, ex_fine_grained_interleaving = false) // Module LoopMatmul - val synthesize_for_weightA_ooo = leanConfig.copy(ld_ooo = false, ex_ooo = true, st_ooo = true, staticWeightAEnabled = true, lean_weightA = true) - val synthesize_for_weightA_in_order = leanConfig.copy(ld_ooo = false, ex_ooo = false, st_ooo = false, staticWeightAEnabled = false, lean_weightA = false) + val synthesize_for_weightA_ooo = leanConfig.copy(ld_ooo = false, ex_ooo = true, st_ooo = true, staticWeightAEnabled = true, lean_weightA = true) // Module WeightedArbiter + val synthesize_for_weightA_in_order = leanConfig.copy(ld_ooo = false, ex_ooo = false, st_ooo = false, staticWeightAEnabled = false, lean_weightA = false) // Module WeightedArbiterr } /** From 4486bb4e2f9d43c409317a77029a04dd40926b6f Mon Sep 17 00:00:00 2001 From: Hasan Genc Date: Mon, 19 Jul 2021 00:49:14 -0700 Subject: [PATCH 73/78] Add 16-k-portion configs --- src/main/scala/gemmini/Configs.scala | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main/scala/gemmini/Configs.scala b/src/main/scala/gemmini/Configs.scala index 9c25fe83f..3da41d235 100644 --- a/src/main/scala/gemmini/Configs.scala +++ b/src/main/scala/gemmini/Configs.scala @@ -170,9 +170,11 @@ object GemminiConfigs { val synthesize_for_rob_ooo = leanConfig.copy(ld_ooo = false, ex_ooo = true, st_ooo = true, lean_ooo_rob = true) // Module ROB val synthesize_for_rob_in_order = leanConfig.copy(ld_ooo = false, ex_ooo = false, st_ooo = false, lean_ooo_rob = false) // Module ROB + val synthesize_for_microthreads_coarse_16_ooo = leanConfig.copy(ld_ooo = false, ex_ooo = true, st_ooo = true, lean_ooo_rob = true, ex_total_k_portions = 16, ex_fine_grained_interleaving = false) // Module LoopMatmul val synthesize_for_microthreads_coarse_4_ooo = leanConfig.copy(ld_ooo = false, ex_ooo = true, st_ooo = true, lean_ooo_rob = true, ex_total_k_portions = 4, ex_fine_grained_interleaving = false) // Module LoopMatmul val synthesize_for_microthreads_coarse_2_ooo = leanConfig.copy(ld_ooo = false, ex_ooo = true, st_ooo = true, lean_ooo_rob = true, ex_total_k_portions = 2, ex_fine_grained_interleaving = false) // Module LoopMatmul + val synthesize_for_microthreads_fine_16_ooo = leanConfig.copy(ld_ooo = false, ex_ooo = true, st_ooo = true, lean_ooo_rob = true, ex_total_k_portions = 16, ex_fine_grained_interleaving = true) // Module LoopMatmul val synthesize_for_microthreads_fine_4_ooo = leanConfig.copy(ld_ooo = false, ex_ooo = true, st_ooo = true, lean_ooo_rob = true, ex_total_k_portions = 4, ex_fine_grained_interleaving = true) // Module LoopMatmul val synthesize_for_microthreads_fine_2_ooo = leanConfig.copy(ld_ooo = false, ex_ooo = true, st_ooo = true, lean_ooo_rob = true, ex_total_k_portions = 2, ex_fine_grained_interleaving = true) // Module LoopMatmul From 2c747b16e5f6776cd4a478baaa3ad7df2da3c452 Mon Sep 17 00:00:00 2001 From: Hasan Genc Date: Thu, 22 Jul 2021 02:45:57 -0700 Subject: [PATCH 74/78] Simplify ExController a little bit --- src/main/scala/gemmini/Configs.scala | 2 ++ src/main/scala/gemmini/LoopMatmul.scala | 21 +++++++++++++++------ 2 files changed, 17 insertions(+), 6 deletions(-) diff --git a/src/main/scala/gemmini/Configs.scala b/src/main/scala/gemmini/Configs.scala index 3da41d235..6bdb6f6cf 100644 --- a/src/main/scala/gemmini/Configs.scala +++ b/src/main/scala/gemmini/Configs.scala @@ -171,10 +171,12 @@ object GemminiConfigs { val synthesize_for_rob_in_order = leanConfig.copy(ld_ooo = false, ex_ooo = false, st_ooo = false, lean_ooo_rob = false) // Module ROB val synthesize_for_microthreads_coarse_16_ooo = leanConfig.copy(ld_ooo = false, ex_ooo = true, st_ooo = true, lean_ooo_rob = true, ex_total_k_portions = 16, ex_fine_grained_interleaving = false) // Module LoopMatmul + val synthesize_for_microthreads_coarse_8_ooo = leanConfig.copy(ld_ooo = false, ex_ooo = true, st_ooo = true, lean_ooo_rob = true, ex_total_k_portions = 8, ex_fine_grained_interleaving = false) // Module LoopMatmul val synthesize_for_microthreads_coarse_4_ooo = leanConfig.copy(ld_ooo = false, ex_ooo = true, st_ooo = true, lean_ooo_rob = true, ex_total_k_portions = 4, ex_fine_grained_interleaving = false) // Module LoopMatmul val synthesize_for_microthreads_coarse_2_ooo = leanConfig.copy(ld_ooo = false, ex_ooo = true, st_ooo = true, lean_ooo_rob = true, ex_total_k_portions = 2, ex_fine_grained_interleaving = false) // Module LoopMatmul val synthesize_for_microthreads_fine_16_ooo = leanConfig.copy(ld_ooo = false, ex_ooo = true, st_ooo = true, lean_ooo_rob = true, ex_total_k_portions = 16, ex_fine_grained_interleaving = true) // Module LoopMatmul + val synthesize_for_microthreads_fine_8_ooo = leanConfig.copy(ld_ooo = false, ex_ooo = true, st_ooo = true, lean_ooo_rob = true, ex_total_k_portions = 8, ex_fine_grained_interleaving = true) // Module LoopMatmul val synthesize_for_microthreads_fine_4_ooo = leanConfig.copy(ld_ooo = false, ex_ooo = true, st_ooo = true, lean_ooo_rob = true, ex_total_k_portions = 4, ex_fine_grained_interleaving = true) // Module LoopMatmul val synthesize_for_microthreads_fine_2_ooo = leanConfig.copy(ld_ooo = false, ex_ooo = true, st_ooo = true, lean_ooo_rob = true, ex_total_k_portions = 2, ex_fine_grained_interleaving = true) // Module LoopMatmul diff --git a/src/main/scala/gemmini/LoopMatmul.scala b/src/main/scala/gemmini/LoopMatmul.scala index adff9ac2a..0eadbf2f1 100644 --- a/src/main/scala/gemmini/LoopMatmul.scala +++ b/src/main/scala/gemmini/LoopMatmul.scala @@ -425,14 +425,17 @@ class LoopMatmulExecute(block_size: Int, coreMaxAddrBits: Int, iterator_bitwidth val req = Reg(new LoopMatmulExecuteReq(block_size, coreMaxAddrBits, iterator_bitwidth, max_addr, max_acc_addr, concurrent_loops)) io.req_out := req - val max_i_blocks = Mux(req.a_tranpose, 1.U, Mux(req.max_i <= max_block_len.U, req.max_i, max_block_len.U)) + // val max_i_blocks = Mux(req.a_tranpose, 1.U, Mux(req.max_i <= max_block_len.U, req.max_i, max_block_len.U)) + val max_i_blocks = Mux(req.max_i <= max_block_len.U, req.max_i, max_block_len.U) val lower_k_bound = if (fine_grained_interleaving) { (max_block_len * k_portion).U } else { (req.max_k / total_k_portions.U) * k_portion.U } val upper_k_bound = if (fine_grained_interleaving || k_portion == total_k_portions - 1) { req.max_k } else { (req.max_k / total_k_portions.U) * (k_portion + 1).U } + /* val d_addr_start = (BigInt(1) << 31).U | req.c_addr_start val c_addr_start = (BigInt(3) << 30).U | req.c_addr_start val b_addr_start = req.b_addr_end - req.max_k * req.max_j * block_size.U + */ val k = Reg(UInt(iterator_bitwidth.W)) val j = Reg(UInt(iterator_bitwidth.W)) @@ -440,6 +443,7 @@ class LoopMatmulExecute(block_size: Int, coreMaxAddrBits: Int, iterator_bitwidth val i_blocks = Mux(i + max_i_blocks <= req.max_i, max_i_blocks, req.max_i-i) + /* val a_row = Mux(req.a_tranpose, k, i) val a_col = Mux(req.a_tranpose, i, k) val b_row = Mux(req.b_tranpose, j, k) @@ -465,7 +469,9 @@ class LoopMatmulExecute(block_size: Int, coreMaxAddrBits: Int, iterator_bitwidth val pre_addr = Mux(pre_addr_is_not_garbage, b_addr, GARBAGE_ADDR) val out_addr = Mux(out_addr_accumulates, c_addr, d_addr) + */ + /* val j_blocks_holder = req.max_j.asTypeOf(new blocks_holder_t) val k_blocks_holder = req.max_k.asTypeOf(new blocks_holder_t) @@ -515,6 +521,7 @@ class LoopMatmulExecute(block_size: Int, coreMaxAddrBits: Int, iterator_bitwidth comp_cmd.inst.rs1 := k_blocks_holder.rs1 comp_cmd.inst.rs2 := k_blocks_holder.rs2 comp_cmd.inst.rd := k_blocks_holder.rd + */ io.req.ready := state === idle io.k := k @@ -532,7 +539,7 @@ class LoopMatmulExecute(block_size: Int, coreMaxAddrBits: Int, iterator_bitwidth io.can_send_command := state =/= idle && ld_ahead io.cmd.valid := state =/= idle && !io.rob_overloaded && ld_ahead - io.cmd.bits := DontCare + io.cmd.bits := 0.U.asTypeOf(io.cmd.bits) /* io.cmd.bits.cmd := Mux(state === pre, pre_cmd, comp_cmd) io.cmd.bits.rob_id := DontCare @@ -560,14 +567,15 @@ class LoopMatmulExecute(block_size: Int, coreMaxAddrBits: Int, iterator_bitwidth val next_i = floorAdd(i, max_i_blocks, req.max_i) val next_j = floorAdd(j, 1.U, req.max_j, next_i === 0.U) // val next_k = floorAdd(k, 1.U, req.max_k, next_j === 0.U && next_i === 0.U) - val next_k = floorAdd(k, k_it, upper_k_bound, next_j === 0.U && next_i === 0.U, min=lower_k_bound) + // val next_k = floorAdd(k, k_it, upper_k_bound, next_j === 0.U && next_i === 0.U, min=lower_k_bound) + val next_k = floorAdd(k, k_it, upper_k_bound, next_j === 0.U && next_i === 0.U) k := next_k j := next_j i := next_i - // state := Mux(next_k === 0.U && next_j === 0.U && next_i === 0.U, idle, pre) - state := Mux(next_k === lower_k_bound && next_j === 0.U && next_i === 0.U, idle, pre) + state := Mux(next_k === 0.U && next_j === 0.U && next_i === 0.U, idle, pre) + // state := Mux(next_k === lower_k_bound && next_j === 0.U && next_i === 0.U, idle, pre) } } @@ -912,7 +920,8 @@ class LoopMatmulState(val iterator_bitwidth: Int, val coreMaxAddrBits: Int, val class LoopMatmul(block_size: Int, coreMaxAddrBits: Int, rob_size: Int, rob_full_entries: Int, max_lds: Int, max_exs: Int, max_sts: Int, max_addr: Int, max_acc_addr: Int, input_w: Int, acc_w: Int, dma_max_bytes: Int, cmd_t: GemminiCmd, ex_total_k_portions: Int, ex_fine_grained_interleaving: Boolean, local_addr_t: LocalAddr, lean_weightA: Boolean, lean_ooo_rob: Boolean, staticWeightAEnabled: Boolean) (implicit p: Parameters) extends Module { - val iterator_bitwidth = 16 + // val iterator_bitwidth = 16 + val iterator_bitwidth = 16 min (local_addr_t.maxLocalAddrBits - log2Up(block_size) + 1) val max_block_len = (dma_max_bytes / (block_size * input_w / 8)) max 1 val max_block_len_acc = (dma_max_bytes / (block_size * acc_w / 8)) max 1 From f2d35ed3c53e2c829157c0cfb0d0ec0b04b7b107 Mon Sep 17 00:00:00 2001 From: Hasan Genc Date: Thu, 22 Jul 2021 03:33:11 -0700 Subject: [PATCH 75/78] Fix bitwidths issue --- src/main/scala/gemmini/LoopMatmul.scala | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/main/scala/gemmini/LoopMatmul.scala b/src/main/scala/gemmini/LoopMatmul.scala index 0eadbf2f1..72af97ead 100644 --- a/src/main/scala/gemmini/LoopMatmul.scala +++ b/src/main/scala/gemmini/LoopMatmul.scala @@ -920,8 +920,8 @@ class LoopMatmulState(val iterator_bitwidth: Int, val coreMaxAddrBits: Int, val class LoopMatmul(block_size: Int, coreMaxAddrBits: Int, rob_size: Int, rob_full_entries: Int, max_lds: Int, max_exs: Int, max_sts: Int, max_addr: Int, max_acc_addr: Int, input_w: Int, acc_w: Int, dma_max_bytes: Int, cmd_t: GemminiCmd, ex_total_k_portions: Int, ex_fine_grained_interleaving: Boolean, local_addr_t: LocalAddr, lean_weightA: Boolean, lean_ooo_rob: Boolean, staticWeightAEnabled: Boolean) (implicit p: Parameters) extends Module { - // val iterator_bitwidth = 16 - val iterator_bitwidth = 16 min (local_addr_t.maxLocalAddrBits - log2Up(block_size) + 1) + val iterator_bitwidth = 16 + val iterator_bitwidth_ceiled = 16 min (local_addr_t.maxLocalAddrBits - log2Up(block_size) + 1) val max_block_len = (dma_max_bytes / (block_size * input_w / 8)) max 1 val max_block_len_acc = (dma_max_bytes / (block_size * acc_w / 8)) max 1 @@ -954,7 +954,7 @@ class LoopMatmul(block_size: Int, coreMaxAddrBits: Int, rob_size: Int, rob_full_ val ldD = Module(new LoopMatmulLdD(block_size, coreMaxAddrBits, iterator_bitwidth, max_acc_addr, input_w, acc_w, max_block_len, max_block_len_acc, concurrent_loops, cmd_t, local_addr_t)) // val ex = Module(new LoopMatmulExecute(block_size, coreMaxAddrBits, iterator_bitwidth, max_addr, max_acc_addr, max_block_len, concurrent_loops, cmd_t)) val exs = (0 until ex_total_k_portions).map { i => - Module(new LoopMatmulExecute(block_size, coreMaxAddrBits, iterator_bitwidth, max_addr, max_acc_addr, max_block_len, concurrent_loops, cmd_t, total_k_portions = ex_total_k_portions, k_portion = i, fine_grained_interleaving = ex_fine_grained_interleaving, local_addr_t)) + Module(new LoopMatmulExecute(block_size, coreMaxAddrBits, iterator_bitwidth_ceiled, max_addr, max_acc_addr, max_block_len, concurrent_loops, cmd_t, total_k_portions = ex_total_k_portions, k_portion = i, fine_grained_interleaving = ex_fine_grained_interleaving, local_addr_t)) } val stC = Module(new LoopMatmulStC(block_size, coreMaxAddrBits, iterator_bitwidth, max_acc_addr, input_w, acc_w, max_block_len, concurrent_loops, cmd_t, local_addr_t)) @@ -1002,7 +1002,7 @@ class LoopMatmul(block_size: Int, coreMaxAddrBits: Int, rob_size: Int, rob_full_ in.bits.k_portion := ex.io.cmd.bits.ex_k_portion k := ex.io.k } - val ex_addr_generator = Module(new LoopMatmulExecuteAddrGenerator(block_size, coreMaxAddrBits, iterator_bitwidth, max_addr, max_acc_addr, max_block_len, concurrent_loops, cmd_t, total_k_portions = ex_total_k_portions, fine_grained_interleaving = ex_fine_grained_interleaving, local_addr_t, lean_ooo_rob)) + val ex_addr_generator = Module(new LoopMatmulExecuteAddrGenerator(block_size, coreMaxAddrBits, iterator_bitwidth_ceiled, max_addr, max_acc_addr, max_block_len, concurrent_loops, cmd_t, total_k_portions = ex_total_k_portions, fine_grained_interleaving = ex_fine_grained_interleaving, local_addr_t, lean_ooo_rob)) ex_addr_generator.io.req := ex_arb.io.out.bits.req ex_addr_generator.io.k := ex_arb.io.out.bits.k ex_addr_generator.io.j := ex_arb.io.out.bits.j From 1c020b136bc11c2c718f11e82bd14532d47203c6 Mon Sep 17 00:00:00 2001 From: Hasan Genc Date: Sat, 24 Jul 2021 01:52:19 -0700 Subject: [PATCH 76/78] Remove transposes from LoopMatmul FSM to save area --- src/main/scala/gemmini/LoopMatmul.scala | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/src/main/scala/gemmini/LoopMatmul.scala b/src/main/scala/gemmini/LoopMatmul.scala index 72af97ead..00328faf1 100644 --- a/src/main/scala/gemmini/LoopMatmul.scala +++ b/src/main/scala/gemmini/LoopMatmul.scala @@ -426,7 +426,8 @@ class LoopMatmulExecute(block_size: Int, coreMaxAddrBits: Int, iterator_bitwidth io.req_out := req // val max_i_blocks = Mux(req.a_tranpose, 1.U, Mux(req.max_i <= max_block_len.U, req.max_i, max_block_len.U)) - val max_i_blocks = Mux(req.max_i <= max_block_len.U, req.max_i, max_block_len.U) + // val max_i_blocks = Mux(req.max_i <= max_block_len.U, req.max_i, max_block_len.U) + val max_i_blocks = max_block_len.U val lower_k_bound = if (fine_grained_interleaving) { (max_block_len * k_portion).U } else { (req.max_k / total_k_portions.U) * k_portion.U } val upper_k_bound = if (fine_grained_interleaving || k_portion == total_k_portions - 1) { req.max_k } else { (req.max_k / total_k_portions.U) * (k_portion + 1).U } @@ -531,7 +532,8 @@ class LoopMatmulExecute(block_size: Int, coreMaxAddrBits: Int, iterator_bitwidth io.must_send_compute := state === comp // The order here is k, j, i - val lda_ahead = io.lda_completed || io.ld_ka > k || (io.ld_ka === k && io.ld_i >= i + i_blocks) + // val lda_ahead = io.lda_completed || io.ld_ka > k || (io.ld_ka === k && io.ld_i >= i + i_blocks) + val lda_ahead = io.lda_completed || io.ld_ka > k || (io.ld_ka === k && io.ld_i >= i + max_i_blocks) val ldb_ahead = io.ldb_completed || io.ld_kb > k || (io.ld_ka === k && io.ld_j > j) val ldd_ahead = io.ldd_completed val ld_ahead = lda_ahead && ldb_ahead && ldd_ahead @@ -561,7 +563,8 @@ class LoopMatmulExecute(block_size: Int, coreMaxAddrBits: Int, iterator_bitwidth when (state === pre) { state := comp }.otherwise { - val jump_k = fine_grained_interleaving.B && (k +& 1.U) % max_block_len.U === 0.U + // val jump_k = fine_grained_interleaving.B && (k +& 1.U) % max_block_len.U === 0.U + val jump_k = fine_grained_interleaving.B && (k % max_block_len.U) === (max_block_len-1).U val k_it = Mux(jump_k, (total_k_portions * max_block_len - max_block_len + 1).U, 1.U) val next_i = floorAdd(i, max_i_blocks, req.max_i) @@ -623,7 +626,8 @@ class LoopMatmulExecuteAddrGenerator(block_size: Int, coreMaxAddrBits: Int, iter val is_pre = io.is_pre val k_portion = io.k_portion - val max_i_blocks = Mux(req.a_tranpose, 1.U, Mux(req.max_i <= max_block_len.U, req.max_i, max_block_len.U)) + // val max_i_blocks = Mux(req.a_tranpose, 1.U, Mux(req.max_i <= max_block_len.U, req.max_i, max_block_len.U)) + val max_i_blocks = max_block_len.U val d_addr_start = (BigInt(1) << 31).U | req.c_addr_start val c_addr_start = (BigInt(3) << 30).U | req.c_addr_start @@ -635,6 +639,7 @@ class LoopMatmulExecuteAddrGenerator(block_size: Int, coreMaxAddrBits: Int, iter val i_blocks = Mux(i + max_i_blocks <= req.max_i, max_i_blocks, req.max_i-i) + /* val a_row = Mux(req.a_tranpose, k, i) val a_col = Mux(req.a_tranpose, i, k) val b_row = Mux(req.b_tranpose, j, k) @@ -642,6 +647,15 @@ class LoopMatmulExecuteAddrGenerator(block_size: Int, coreMaxAddrBits: Int, iter val a_max_col = Mux(req.a_tranpose, req.max_i, req.max_k) val b_max_col = Mux(req.b_tranpose, req.max_k, req.max_j) + */ + + val a_row = i + val a_col = k + val b_row = k + val b_col = j + + val a_max_col = req.max_k + val b_max_col = req.max_j val a_addr = req.a_addr_start + (a_row * a_max_col + a_col) * block_size.U val b_addr = b_addr_start + (b_row * b_max_col + b_col) * block_size.U From 29edd8e740d26c82efd15ef924fb2c41c4689bdd Mon Sep 17 00:00:00 2001 From: Hasan Genc Date: Sat, 24 Jul 2021 02:25:43 -0700 Subject: [PATCH 77/78] Reduced bitwidth of ExArbiter --- src/main/scala/gemmini/LoopMatmul.scala | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/scala/gemmini/LoopMatmul.scala b/src/main/scala/gemmini/LoopMatmul.scala index 00328faf1..23ddd3eb0 100644 --- a/src/main/scala/gemmini/LoopMatmul.scala +++ b/src/main/scala/gemmini/LoopMatmul.scala @@ -1004,7 +1004,7 @@ class LoopMatmul(block_size: Int, coreMaxAddrBits: Int, rob_size: Int, rob_full_ override def cloneType: ExAddrGeneratorInput.this.type = new ExAddrGeneratorInput().asInstanceOf[this.type] } - val ex_arb = Module(new ExArbiter(new ExAddrGeneratorInput, ex_total_k_portions, ex_fine_grained_interleaving)) + val ex_arb = Module(new ExArbiter(new ExAddrGeneratorInput, ex_total_k_portions, ex_fine_grained_interleaving, iterator_bitwidth_ceiled)) (ex_arb.io.in, ex_arb.io.k, exs).zipped.foreach { case (in, k, ex) => in.valid := ex.io.cmd.valid ex.io.cmd.ready := in.ready @@ -1392,11 +1392,11 @@ object LoopMatmul { } } -class ExArbiter[T <: Data](gen: T, n: Int, ex_fine_grained: Boolean) extends Module { +class ExArbiter[T <: Data](gen: T, n: Int, ex_fine_grained: Boolean, iterator_bitwidth: Int) extends Module { val io = IO(new Bundle { val in = Flipped(Vec(n, Decoupled(gen))) val out = Decoupled(gen) - val k = Input(Vec(n, UInt(16.W))) // TODO magic number + val k = Input(Vec(n, UInt(iterator_bitwidth.W))) }) val chosen = (io.in zip io.k).zipWithIndex.foldLeft(0.U) { case (acc, ((in, k), i)) => From 9ebbfec900c288093ffb0a23752d7a803a45f62c Mon Sep 17 00:00:00 2001 From: Hasan Genc Date: Sat, 11 Sep 2021 14:54:08 -0700 Subject: [PATCH 78/78] Fix ooo fine-grained-interleaving st.io.ex_ijk connections --- src/main/scala/gemmini/LoopMatmul.scala | 27 ++++++++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) diff --git a/src/main/scala/gemmini/LoopMatmul.scala b/src/main/scala/gemmini/LoopMatmul.scala index 23ddd3eb0..1a85a7fa8 100644 --- a/src/main/scala/gemmini/LoopMatmul.scala +++ b/src/main/scala/gemmini/LoopMatmul.scala @@ -1125,9 +1125,30 @@ class LoopMatmul(block_size: Int, coreMaxAddrBits: Int, rob_size: Int, rob_full_ */ val exs_completed = exs.map(ex => (ex.io.loop_id =/= stC.io.loop_id) || ex.io.idle) stC.io.ex_completed := exs_completed.reduce(_ && _) - stC.io.ex_k := MuxCase(exs.last.io.k, (exs_completed zip exs).init.map { case (ex_completed, ex) => (!ex_completed) -> ex.io.k }) - stC.io.ex_j := MuxCase(exs.last.io.j, (exs_completed zip exs).init.map { case (ex_completed, ex) => (!ex_completed) -> ex.io.j }) - stC.io.ex_i := MuxCase(exs.last.io.i, (exs_completed zip exs).init.map { case (ex_completed, ex) => (!ex_completed) -> ex.io.i }) + if (ex_fine_grained_interleaving) { + // TODO getting the index here is very inefficient + val max_k = exs.map(_.io.k).reduce(maxOf) + val ks_maxed = (exs zip exs_completed).map { case (ex, completed) => Mux(completed, max_k, ex.io.k) } + val min_k = ks_maxed.reduce(minOf) + val min_k_index = WireInit(0.U(log2Up(ex_total_k_portions).W)) + ks_maxed.zipWithIndex.foreach { case (k, i) => + when (k === min_k) { + min_k_index := i.U + } + } + + val ks = VecInit(exs.map(_.io.k)) + val js = VecInit(exs.map(_.io.j)) + val is = VecInit(exs.map(_.io.i)) + + stC.io.ex_k := ks(min_k_index) + stC.io.ex_j := js(min_k_index) + stC.io.ex_i := is(min_k_index) + } else { + stC.io.ex_k := MuxCase(exs.last.io.k, (exs_completed zip exs).init.map { case (ex_completed, ex) => (!ex_completed) -> ex.io.k }) + stC.io.ex_j := MuxCase(exs.last.io.j, (exs_completed zip exs).init.map { case (ex_completed, ex) => (!ex_completed) -> ex.io.j }) + stC.io.ex_i := MuxCase(exs.last.io.i, (exs_completed zip exs).init.map { case (ex_completed, ex) => (!ex_completed) -> ex.io.i }) + } val loops_configured = RegInit(0.U(16.W)) dontTouch(loops_configured)