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