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