1/*************************************************************************************** 2* Copyright (c) 2020-2021 Institute of Computing Technology, Chinese Academy of Sciences 3* Copyright (c) 2020-2021 Peng Cheng Laboratory 4* 5* XiangShan is licensed under Mulan PSL v2. 6* You can use this software according to the terms and conditions of the Mulan PSL v2. 7* You may obtain a copy of Mulan PSL v2 at: 8* http://license.coscl.org.cn/MulanPSL2 9* 10* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, 11* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, 12* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. 13* 14* See the Mulan PSL v2 for more details. 15***************************************************************************************/ 16 17package xiangshan.mem 18 19import chipsalliance.rocketchip.config.Parameters 20import chisel3._ 21import chisel3.util._ 22import utils._ 23import xiangshan._ 24import xiangshan.cache._ 25import xiangshan.cache.{DCacheWordIO, DCacheLineIO, MemoryOpConstants} 26import xiangshan.mem._ 27import xiangshan.backend.roq.RoqPtr 28 29 30// Data module define 31// These data modules are like SyncDataModuleTemplate, but support cam-like ops 32class SQPaddrModule(numEntries: Int, numRead: Int, numWrite: Int, numForward: Int)(implicit p: Parameters) extends XSModule with HasDCacheParameters { 33 val io = IO(new Bundle { 34 val raddr = Input(Vec(numRead, UInt(log2Up(numEntries).W))) 35 val rdata = Output(Vec(numRead, UInt((PAddrBits).W))) 36 val wen = Input(Vec(numWrite, Bool())) 37 val waddr = Input(Vec(numWrite, UInt(log2Up(numEntries).W))) 38 val wdata = Input(Vec(numWrite, UInt((PAddrBits).W))) 39 val forwardMdata = Input(Vec(numForward, UInt((PAddrBits).W))) 40 val forwardMmask = Output(Vec(numForward, Vec(numEntries, Bool()))) 41 }) 42 43 val data = Reg(Vec(numEntries, UInt((PAddrBits).W))) 44 45 // read ports 46 for (i <- 0 until numRead) { 47 io.rdata(i) := data(RegNext(io.raddr(i))) 48 } 49 50 // below is the write ports (with priorities) 51 for (i <- 0 until numWrite) { 52 when (io.wen(i)) { 53 data(io.waddr(i)) := io.wdata(i) 54 } 55 } 56 57 // content addressed match 58 for (i <- 0 until numForward) { 59 for (j <- 0 until numEntries) { 60 io.forwardMmask(i)(j) := io.forwardMdata(i)(PAddrBits-1, 3) === data(j)(PAddrBits-1, 3) 61 } 62 } 63 64 // DataModuleTemplate should not be used when there're any write conflicts 65 for (i <- 0 until numWrite) { 66 for (j <- i+1 until numWrite) { 67 assert(!(io.wen(i) && io.wen(j) && io.waddr(i) === io.waddr(j))) 68 } 69 } 70} 71 72class SQData8Entry(implicit p: Parameters) extends XSBundle { 73 // val paddr = UInt(PAddrBits.W) 74 val valid = Bool() 75 val data = UInt((XLEN/8).W) 76} 77 78class SQData8Module(size: Int, numRead: Int, numWrite: Int, numForward: Int)(implicit p: Parameters) extends XSModule with HasDCacheParameters with HasCircularQueuePtrHelper { 79 val io = IO(new Bundle() { 80 val raddr = Vec(numRead, Input(UInt(log2Up(size).W))) 81 val rdata = Vec(numRead, Output(new SQData8Entry)) 82 val data = new Bundle() { 83 val wen = Vec(numWrite, Input(Bool())) 84 val waddr = Vec(numWrite, Input(UInt(log2Up(size).W))) 85 val wdata = Vec(numWrite, Input(UInt((XLEN/8).W))) 86 } 87 val mask = new Bundle() { 88 val wen = Vec(numWrite, Input(Bool())) 89 val waddr = Vec(numWrite, Input(UInt(log2Up(size).W))) 90 val wdata = Vec(numWrite, Input(Bool())) 91 } 92 93 val needForward = Input(Vec(numForward, Vec(2, UInt(size.W)))) 94 val forwardValid = Vec(numForward, Output(Bool())) 95 val forwardData = Vec(numForward, Output(UInt(8.W))) 96 }) 97 98 io := DontCare 99 100 val data = Reg(Vec(size, new SQData8Entry)) 101 102 // writeback to sq 103 (0 until numWrite).map(i => { 104 when(io.data.wen(i)){ 105 data(io.data.waddr(i)).data := io.data.wdata(i) 106 } 107 }) 108 (0 until numWrite).map(i => { 109 when(io.mask.wen(i)){ 110 data(io.mask.waddr(i)).valid := io.mask.wdata(i) 111 } 112 }) 113 114 // destorequeue read data 115 (0 until numRead).map(i => { 116 io.rdata(i) := data(RegNext(io.raddr(i))) 117 }) 118 119 // DataModuleTemplate should not be used when there're any write conflicts 120 for (i <- 0 until numWrite) { 121 for (j <- i+1 until numWrite) { 122 assert(!(io.data.wen(i) && io.data.wen(j) && io.data.waddr(i) === io.data.waddr(j))) 123 } 124 } 125 for (i <- 0 until numWrite) { 126 for (j <- i+1 until numWrite) { 127 assert(!(io.mask.wen(i) && io.mask.wen(j) && io.mask.waddr(i) === io.mask.waddr(j))) 128 } 129 } 130 131 // forwarding 132 // Compare ringBufferTail (deqPtr) and forward.sqIdx, we have two cases: 133 // (1) if they have the same flag, we need to check range(tail, sqIdx) 134 // (2) if they have different flags, we need to check range(tail, LoadQueueSize) and range(0, sqIdx) 135 // Forward1: Mux(same_flag, range(tail, sqIdx), range(tail, LoadQueueSize)) 136 // Forward2: Mux(same_flag, 0.U, range(0, sqIdx) ) 137 // i.e. forward1 is the target entries with the same flag bits and forward2 otherwise 138 139 // entry with larger index should have higher priority since it's data is younger 140 141 (0 until numForward).map(i => { 142 // parallel fwd logic 143 val matchResultVec = Wire(Vec(size * 2, new FwdEntry)) 144 145 def parallelFwd(xs: Seq[Data]): Data = { 146 ParallelOperation(xs, (a: Data, b: Data) => { 147 val l = a.asTypeOf(new FwdEntry) 148 val r = b.asTypeOf(new FwdEntry) 149 val res = Wire(new FwdEntry) 150 res.valid := l.valid || r.valid 151 res.data := Mux(r.valid, r.data, l.data) 152 res 153 }) 154 } 155 156 // paddrMatch is now included in io.needForward 157 // for (j <- 0 until size) { 158 // paddrMatch(j) := io.forward(i).paddr(PAddrBits - 1, 3) === data(j).paddr(PAddrBits - 1, 3) 159 // } 160 161 for (j <- 0 until size) { 162 val needCheck0 = RegNext(io.needForward(i)(0)(j)) 163 val needCheck1 = RegNext(io.needForward(i)(1)(j)) 164 (0 until XLEN / 8).foreach(k => { 165 matchResultVec(j).valid := needCheck0 && data(j).valid 166 matchResultVec(j).data := data(j).data 167 matchResultVec(size + j).valid := needCheck1 && data(j).valid 168 matchResultVec(size + j).data := data(j).data 169 }) 170 } 171 172 val parallelFwdResult = parallelFwd(matchResultVec).asTypeOf(new FwdEntry) 173 174 io.forwardValid(i) := parallelFwdResult.valid 175 io.forwardData(i) := parallelFwdResult.data 176 177 }) 178} 179 180class SQDataEntry(implicit p: Parameters) extends XSBundle { 181 // val paddr = UInt(PAddrBits.W) 182 val mask = UInt(8.W) 183 val data = UInt(XLEN.W) 184} 185 186class SQDataModule(size: Int, numRead: Int, numWrite: Int, numForward: Int)(implicit p: Parameters) extends XSModule with HasDCacheParameters with HasCircularQueuePtrHelper { 187 val io = IO(new Bundle() { 188 val raddr = Vec(numRead, Input(UInt(log2Up(size).W))) 189 val rdata = Vec(numRead, Output(new SQDataEntry)) 190 val data = new Bundle() { 191 val wen = Vec(numWrite, Input(Bool())) 192 val waddr = Vec(numWrite, Input(UInt(log2Up(size).W))) 193 val wdata = Vec(numWrite, Input(UInt(XLEN.W))) 194 } 195 val mask = new Bundle() { 196 val wen = Vec(numWrite, Input(Bool())) 197 val waddr = Vec(numWrite, Input(UInt(log2Up(size).W))) 198 val wdata = Vec(numWrite, Input(UInt(8.W))) 199 } 200 201 val needForward = Input(Vec(numForward, Vec(2, UInt(size.W)))) 202 val forwardMask = Vec(numForward, Output(Vec(8, Bool()))) 203 val forwardData = Vec(numForward, Output(Vec(8, UInt(8.W)))) 204 }) 205 206 val data8 = Seq.fill(8)(Module(new SQData8Module(size, numRead, numWrite, numForward))) 207 208 // writeback to lq/sq 209 for (i <- 0 until numWrite) { 210 // write to data8 211 for (j <- 0 until 8) { 212 data8(j).io.mask.waddr(i) := io.mask.waddr(i) 213 data8(j).io.mask.wdata(i) := io.mask.wdata(i)(j) 214 data8(j).io.mask.wen(i) := io.mask.wen(i) 215 data8(j).io.data.waddr(i) := io.data.waddr(i) 216 data8(j).io.data.wdata(i) := io.data.wdata(i)(8*(j+1)-1, 8*j) 217 data8(j).io.data.wen(i) := io.data.wen(i) 218 } 219 } 220 221 // destorequeue read data 222 for (i <- 0 until numRead) { 223 for (j <- 0 until 8) { 224 data8(j).io.raddr(i) := io.raddr(i) 225 } 226 io.rdata(i).mask := VecInit((0 until 8).map(j => data8(j).io.rdata(i).valid)).asUInt 227 io.rdata(i).data := VecInit((0 until 8).map(j => data8(j).io.rdata(i).data)).asUInt 228 } 229 230 // DataModuleTemplate should not be used when there're any write conflicts 231 for (i <- 0 until numWrite) { 232 for (j <- i+1 until numWrite) { 233 assert(!(io.data.wen(i) && io.data.wen(j) && io.data.waddr(i) === io.data.waddr(j))) 234 } 235 } 236 for (i <- 0 until numWrite) { 237 for (j <- i+1 until numWrite) { 238 assert(!(io.mask.wen(i) && io.mask.wen(j) && io.mask.waddr(i) === io.mask.waddr(j))) 239 } 240 } 241 242 (0 until numForward).map(i => { 243 // parallel fwd logic 244 for (j <- 0 until 8) { 245 data8(j).io.needForward(i) <> io.needForward(i) 246 io.forwardMask(i) := VecInit((0 until 8).map(j => data8(j).io.forwardValid(i))) 247 io.forwardData(i) := VecInit((0 until 8).map(j => data8(j).io.forwardData(i))) 248 } 249 }) 250} 251