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.rob.RobPtr 28 29 30// Data module define 31// These data modules are like SyncDataModuleTemplate, but support cam-like ops 32class SQAddrModule(dataWidth: Int, numEntries: Int, numRead: Int, numWrite: Int, numForward: Int)(implicit p: Parameters) extends XSModule with HasDCacheParameters { 33 val io = IO(new Bundle { 34 // sync read 35 val raddr = Input(Vec(numRead, UInt(log2Up(numEntries).W))) 36 val rdata = Output(Vec(numRead, UInt(dataWidth.W))) // rdata: store addr 37 val rlineflag = Output(Vec(numRead, Bool())) // rdata: line op flag 38 // write 39 val wen = Input(Vec(numWrite, Bool())) 40 val waddr = Input(Vec(numWrite, UInt(log2Up(numEntries).W))) 41 val wdata = Input(Vec(numWrite, UInt(dataWidth.W))) // wdata: store addr 42 val wlineflag = Input(Vec(numWrite, Bool())) // wdata: line op flag 43 // forward addr cam 44 val forwardMdata = Input(Vec(numForward, UInt(dataWidth.W))) // addr 45 val forwardMmask = Output(Vec(numForward, Vec(numEntries, Bool()))) // cam result mask 46 // debug 47 val debug_data = Output(Vec(numEntries, UInt(dataWidth.W))) 48 }) 49 50 val data = Reg(Vec(numEntries, UInt(dataWidth.W))) 51 val lineflag = Reg(Vec(numEntries, Bool())) // cache line match flag 52 // if lineflag == true, this address points to a whole cacheline 53 io.debug_data := data 54 55 // read ports 56 for (i <- 0 until numRead) { 57 io.rdata(i) := data(RegNext(io.raddr(i))) 58 io.rlineflag(i) := lineflag(RegNext(io.raddr(i))) 59 } 60 61 // below is the write ports (with priorities) 62 for (i <- 0 until numWrite) { 63 when (io.wen(i)) { 64 data(io.waddr(i)) := io.wdata(i) 65 lineflag(io.waddr(i)) := io.wlineflag(i) 66 } 67 } 68 69 // content addressed match 70 for (i <- 0 until numForward) { 71 for (j <- 0 until numEntries) { 72 // io.forwardMmask(i)(j) := io.forwardMdata(i)(dataWidth-1, 3) === data(j)(dataWidth-1, 3) 73 val linehit = io.forwardMdata(i)(dataWidth-1, DCacheLineOffset) === data(j)(dataWidth-1, DCacheLineOffset) 74 val wordhit = io.forwardMdata(i)(DCacheLineOffset-1, DCacheWordOffset) === data(j)(DCacheLineOffset-1, DCacheWordOffset) 75 io.forwardMmask(i)(j) := linehit && (wordhit || lineflag(j)) 76 } 77 } 78 79 // DataModuleTemplate should not be used when there're any write conflicts 80 for (i <- 0 until numWrite) { 81 for (j <- i+1 until numWrite) { 82 assert(!(io.wen(i) && io.wen(j) && io.waddr(i) === io.waddr(j))) 83 } 84 } 85} 86 87class SQData8Entry(implicit p: Parameters) extends XSBundle { 88 val valid = Bool() // this byte is valid 89 val data = UInt((XLEN/8).W) 90} 91 92class SQData8Module(numEntries: Int, numRead: Int, numWrite: Int, numForward: Int)(implicit p: Parameters) extends XSModule with HasDCacheParameters with HasCircularQueuePtrHelper { 93 val io = IO(new Bundle() { 94 // sync read port 95 val raddr = Vec(numRead, Input(UInt(log2Up(numEntries).W))) 96 val rdata = Vec(numRead, Output(new SQData8Entry)) 97 // data write port 98 val data = new Bundle() { 99 val wen = Vec(numWrite, Input(Bool())) 100 val waddr = Vec(numWrite, Input(UInt(log2Up(numEntries).W))) 101 val wdata = Vec(numWrite, Input(UInt((XLEN/8).W))) 102 } 103 // mask (data valid) write port 104 val mask = new Bundle() { 105 val wen = Vec(numWrite, Input(Bool())) 106 val waddr = Vec(numWrite, Input(UInt(log2Up(numEntries).W))) 107 val wdata = Vec(numWrite, Input(Bool())) 108 } 109 110 // st-ld forward addr cam result input, used to select forward data 111 val needForward = Input(Vec(numForward, Vec(2, UInt(numEntries.W)))) 112 // forward result valid bit generated in current cycle 113 val forwardValidFast = Vec(numForward, Output(Bool())) 114 // forward result generated in the next cycle 115 val forwardValid = Vec(numForward, Output(Bool())) // forwardValid = RegNext(forwardValidFast) 116 val forwardData = Vec(numForward, Output(UInt(8.W))) 117 }) 118 119 io := DontCare 120 121 val data = Reg(Vec(numEntries, new SQData8Entry)) 122 123 // writeback to sq 124 (0 until numWrite).map(i => { 125 when(io.data.wen(i)){ 126 data(io.data.waddr(i)).data := io.data.wdata(i) 127 } 128 }) 129 (0 until numWrite).map(i => { 130 when(io.mask.wen(i)){ 131 data(io.mask.waddr(i)).valid := io.mask.wdata(i) 132 } 133 }) 134 135 // destorequeue read data 136 (0 until numRead).map(i => { 137 io.rdata(i) := data(RegNext(io.raddr(i))) 138 }) 139 140 // DataModuleTemplate should not be used when there're any write conflicts 141 for (i <- 0 until numWrite) { 142 for (j <- i+1 until numWrite) { 143 assert(!(io.data.wen(i) && io.data.wen(j) && io.data.waddr(i) === io.data.waddr(j))) 144 } 145 } 146 for (i <- 0 until numWrite) { 147 for (j <- i+1 until numWrite) { 148 assert(!(io.mask.wen(i) && io.mask.wen(j) && io.mask.waddr(i) === io.mask.waddr(j))) 149 } 150 } 151 152 // forwarding 153 // Compare ringBufferTail (deqPtr) and forward.sqIdx, we have two cases: 154 // (1) if they have the same flag, we need to check range(tail, sqIdx) 155 // (2) if they have different flags, we need to check range(tail, LoadQueueSize) and range(0, sqIdx) 156 // Forward1: Mux(same_flag, range(tail, sqIdx), range(tail, LoadQueueSize)) 157 // Forward2: Mux(same_flag, 0.U, range(0, sqIdx) ) 158 // i.e. forward1 is the target entries with the same flag bits and forward2 otherwise 159 160 // entry with larger index should have higher priority since it's data is younger 161 162 (0 until numForward).map(i => { 163 // parallel fwd logic 164 val matchResultVec = Wire(Vec(numEntries * 2, new FwdEntry)) 165 166 def parallelFwd(xs: Seq[Data]): Data = { 167 ParallelOperation(xs, (a: Data, b: Data) => { 168 val l = a.asTypeOf(new FwdEntry) 169 val r = b.asTypeOf(new FwdEntry) 170 val res = Wire(new FwdEntry) 171 res.validFast := l.validFast || r.validFast 172 res.valid := l.valid || r.valid 173 // res.valid := RegNext(res.validFast) 174 res.data := Mux(r.valid, r.data, l.data) 175 res 176 }) 177 } 178 179 for (j <- 0 until numEntries) { 180 val needCheck0 = io.needForward(i)(0)(j) 181 val needCheck1 = io.needForward(i)(1)(j) 182 val needCheck0Reg = RegNext(needCheck0) 183 val needCheck1Reg = RegNext(needCheck1) 184 (0 until XLEN / 8).foreach(k => { 185 matchResultVec(j).validFast := needCheck0 && data(j).valid 186 matchResultVec(j).valid := needCheck0Reg && data(j).valid 187 matchResultVec(j).data := data(j).data 188 matchResultVec(numEntries + j).validFast := needCheck1 && data(j).valid 189 matchResultVec(numEntries + j).valid := needCheck1Reg && data(j).valid 190 matchResultVec(numEntries + j).data := data(j).data 191 }) 192 } 193 194 val parallelFwdResult = parallelFwd(matchResultVec).asTypeOf(new FwdEntry) 195 196 // validFast is generated the same cycle with query 197 io.forwardValidFast(i) := parallelFwdResult.validFast 198 // valid is generated 1 cycle after query request 199 io.forwardValid(i) := parallelFwdResult.valid 200 // data is generated 1 cycle after query request 201 io.forwardData(i) := parallelFwdResult.data 202 203 }) 204} 205 206class SQDataEntry(implicit p: Parameters) extends XSBundle { 207 val mask = UInt(8.W) 208 val data = UInt(XLEN.W) 209} 210 211// SQDataModule is a wrapper of SQData8Modules 212class SQDataModule(numEntries: Int, numRead: Int, numWrite: Int, numForward: Int)(implicit p: Parameters) extends XSModule with HasDCacheParameters with HasCircularQueuePtrHelper { 213 val io = IO(new Bundle() { 214 // sync read port 215 val raddr = Vec(numRead, Input(UInt(log2Up(numEntries).W))) 216 val rdata = Vec(numRead, Output(new SQDataEntry)) 217 // data write port 218 val data = new Bundle() { 219 val wen = Vec(numWrite, Input(Bool())) 220 val waddr = Vec(numWrite, Input(UInt(log2Up(numEntries).W))) 221 val wdata = Vec(numWrite, Input(UInt(XLEN.W))) 222 } 223 // mask (data valid) write port 224 val mask = new Bundle() { 225 val wen = Vec(numWrite, Input(Bool())) 226 val waddr = Vec(numWrite, Input(UInt(log2Up(numEntries).W))) 227 val wdata = Vec(numWrite, Input(UInt(8.W))) 228 } 229 230 // st-ld forward addr cam result input, used to select forward data 231 val needForward = Input(Vec(numForward, Vec(2, UInt(numEntries.W)))) 232 // forward result valid bit generated in current cycle 233 val forwardMaskFast = Vec(numForward, Output(Vec(8, Bool()))) 234 // forward result generated in the next cycle 235 val forwardMask = Vec(numForward, Output(Vec(8, Bool()))) // forwardMask = RegNext(forwardMaskFast) 236 val forwardData = Vec(numForward, Output(Vec(8, UInt(8.W)))) 237 }) 238 239 val data8 = Seq.fill(8)(Module(new SQData8Module(numEntries, numRead, numWrite, numForward))) 240 241 // writeback to lq/sq 242 for (i <- 0 until numWrite) { 243 // write to data8 244 for (j <- 0 until 8) { 245 data8(j).io.mask.waddr(i) := io.mask.waddr(i) 246 data8(j).io.mask.wdata(i) := io.mask.wdata(i)(j) 247 data8(j).io.mask.wen(i) := io.mask.wen(i) 248 data8(j).io.data.waddr(i) := io.data.waddr(i) 249 data8(j).io.data.wdata(i) := io.data.wdata(i)(8*(j+1)-1, 8*j) 250 data8(j).io.data.wen(i) := io.data.wen(i) 251 } 252 } 253 254 // destorequeue read data 255 for (i <- 0 until numRead) { 256 for (j <- 0 until 8) { 257 data8(j).io.raddr(i) := io.raddr(i) 258 } 259 io.rdata(i).mask := VecInit((0 until 8).map(j => data8(j).io.rdata(i).valid)).asUInt 260 io.rdata(i).data := VecInit((0 until 8).map(j => data8(j).io.rdata(i).data)).asUInt 261 } 262 263 // DataModuleTemplate should not be used when there're any write conflicts 264 for (i <- 0 until numWrite) { 265 for (j <- i+1 until numWrite) { 266 assert(!(io.data.wen(i) && io.data.wen(j) && io.data.waddr(i) === io.data.waddr(j))) 267 } 268 } 269 for (i <- 0 until numWrite) { 270 for (j <- i+1 until numWrite) { 271 assert(!(io.mask.wen(i) && io.mask.wen(j) && io.mask.waddr(i) === io.mask.waddr(j))) 272 } 273 } 274 275 (0 until numForward).map(i => { 276 // parallel fwd logic 277 for (j <- 0 until 8) { 278 data8(j).io.needForward(i) <> io.needForward(i) 279 io.forwardMaskFast(i) := VecInit((0 until 8).map(j => data8(j).io.forwardValidFast(i))) 280 io.forwardMask(i) := VecInit((0 until 8).map(j => data8(j).io.forwardValid(i))) 281 io.forwardData(i) := VecInit((0 until 8).map(j => data8(j).io.forwardData(i))) 282 } 283 }) 284} 285