1package xiangshan.mem 2 3import chisel3._ 4import chisel3.util._ 5import utils._ 6import xiangshan._ 7import xiangshan.cache._ 8import xiangshan.cache.{DCacheWordIO, DCacheLineIO, TlbRequestIO, MemoryOpConstants} 9import xiangshan.backend.LSUOpType 10import xiangshan.mem._ 11import xiangshan.backend.roq.RoqPtr 12 13 14// Data module define 15// These data modules are like SyncDataModuleTemplate, but support cam-like ops 16class SQPaddrModule(numEntries: Int, numRead: Int, numWrite: Int, numForward: Int) extends XSModule with HasDCacheParameters { 17 val io = IO(new Bundle { 18 val raddr = Input(Vec(numRead, UInt(log2Up(numEntries).W))) 19 val rdata = Output(Vec(numRead, UInt((PAddrBits).W))) 20 val wen = Input(Vec(numWrite, Bool())) 21 val waddr = Input(Vec(numWrite, UInt(log2Up(numEntries).W))) 22 val wdata = Input(Vec(numWrite, UInt((PAddrBits).W))) 23 val forwardMdata = Input(Vec(numForward, UInt((PAddrBits).W))) 24 val forwardMmask = Output(Vec(numForward, Vec(numEntries, Bool()))) 25 }) 26 27 val data = Reg(Vec(numEntries, UInt((PAddrBits).W))) 28 29 // read ports 30 for (i <- 0 until numRead) { 31 io.rdata(i) := data(RegNext(io.raddr(i))) 32 } 33 34 // below is the write ports (with priorities) 35 for (i <- 0 until numWrite) { 36 when (io.wen(i)) { 37 data(io.waddr(i)) := io.wdata(i) 38 } 39 } 40 41 // content addressed match 42 for (i <- 0 until numForward) { 43 for (j <- 0 until numEntries) { 44 io.forwardMmask(i)(j) := io.forwardMdata(i)(PAddrBits-1, 3) === data(j)(PAddrBits-1, 3) 45 } 46 } 47 48 // DataModuleTemplate should not be used when there're any write conflicts 49 for (i <- 0 until numWrite) { 50 for (j <- i+1 until numWrite) { 51 assert(!(io.wen(i) && io.wen(j) && io.waddr(i) === io.waddr(j))) 52 } 53 } 54} 55 56class SQData8Entry extends XSBundle { 57 // val paddr = UInt(PAddrBits.W) 58 val valid = Bool() 59 val data = UInt((XLEN/8).W) 60} 61 62class SQData8Module(size: Int, numRead: Int, numWrite: Int, numForward: Int) extends XSModule with HasDCacheParameters with HasCircularQueuePtrHelper { 63 val io = IO(new Bundle() { 64 val raddr = Vec(numRead, Input(UInt(log2Up(size).W))) 65 val rdata = Vec(numRead, Output(new SQData8Entry)) 66 val wen = Vec(numWrite, Input(Bool())) 67 val waddr = Vec(numWrite, Input(UInt(log2Up(size).W))) 68 val wdata = Vec(numWrite, Input(new SQData8Entry)) 69 70 val needForward = Input(Vec(numForward, Vec(2, UInt(size.W)))) 71 val forwardValid = Vec(numForward, Output(Bool())) 72 val forwardData = Vec(numForward, Output(UInt(8.W))) 73 }) 74 75 io := DontCare 76 77 val data = Reg(Vec(size, new SQData8Entry)) 78 79 // writeback to lq/sq 80 (0 until numWrite).map(i => { 81 when(io.wen(i)){ 82 data(io.waddr(i)) := io.wdata(i) 83 } 84 }) 85 86 // destorequeue read data 87 (0 until numRead).map(i => { 88 io.rdata(i) := data(RegNext(io.raddr(i))) 89 }) 90 91 // DataModuleTemplate should not be used when there're any write conflicts 92 for (i <- 0 until numWrite) { 93 for (j <- i+1 until numWrite) { 94 assert(!(io.wen(i) && io.wen(j) && io.waddr(i) === io.waddr(j))) 95 } 96 } 97 98 // forwarding 99 // Compare ringBufferTail (deqPtr) and forward.sqIdx, we have two cases: 100 // (1) if they have the same flag, we need to check range(tail, sqIdx) 101 // (2) if they have different flags, we need to check range(tail, LoadQueueSize) and range(0, sqIdx) 102 // Forward1: Mux(same_flag, range(tail, sqIdx), range(tail, LoadQueueSize)) 103 // Forward2: Mux(same_flag, 0.U, range(0, sqIdx) ) 104 // i.e. forward1 is the target entries with the same flag bits and forward2 otherwise 105 106 // entry with larger index should have higher priority since it's data is younger 107 108 (0 until numForward).map(i => { 109 // parallel fwd logic 110 val matchResultVec = Wire(Vec(size * 2, new FwdEntry)) 111 112 def parallelFwd(xs: Seq[Data]): Data = { 113 ParallelOperation(xs, (a: Data, b: Data) => { 114 val l = a.asTypeOf(new FwdEntry) 115 val r = b.asTypeOf(new FwdEntry) 116 val res = Wire(new FwdEntry) 117 res.valid := l.valid || r.valid 118 res.data := Mux(r.valid, r.data, l.data) 119 res 120 }) 121 } 122 123 // paddrMatch is now included in io.needForward 124 // for (j <- 0 until size) { 125 // paddrMatch(j) := io.forward(i).paddr(PAddrBits - 1, 3) === data(j).paddr(PAddrBits - 1, 3) 126 // } 127 128 for (j <- 0 until size) { 129 val needCheck0 = RegNext(io.needForward(i)(0)(j)) 130 val needCheck1 = RegNext(io.needForward(i)(1)(j)) 131 (0 until XLEN / 8).foreach(k => { 132 matchResultVec(j).valid := needCheck0 && data(j).valid 133 matchResultVec(j).data := data(j).data 134 matchResultVec(size + j).valid := needCheck1 && data(j).valid 135 matchResultVec(size + j).data := data(j).data 136 }) 137 } 138 139 val parallelFwdResult = parallelFwd(matchResultVec).asTypeOf(new FwdEntry) 140 141 io.forwardValid(i) := parallelFwdResult.valid 142 io.forwardData(i) := parallelFwdResult.data 143 144 }) 145} 146 147class SQDataEntry extends XSBundle { 148 // val paddr = UInt(PAddrBits.W) 149 val mask = UInt(8.W) 150 val data = UInt(XLEN.W) 151} 152 153class StoreQueueData(size: Int, numRead: Int, numWrite: Int, numForward: Int) extends XSModule with HasDCacheParameters with HasCircularQueuePtrHelper { 154 val io = IO(new Bundle() { 155 val raddr = Vec(numRead, Input(UInt(log2Up(size).W))) 156 val rdata = Vec(numRead, Output(new SQDataEntry)) 157 val wen = Vec(numWrite, Input(Bool())) 158 val waddr = Vec(numWrite, Input(UInt(log2Up(size).W))) 159 val wdata = Vec(numWrite, Input(new SQDataEntry)) 160 161 val needForward = Input(Vec(numForward, Vec(2, UInt(size.W)))) 162 val forwardMask = Vec(numForward, Output(Vec(8, Bool()))) 163 val forwardData = Vec(numForward, Output(Vec(8, UInt(8.W)))) 164 }) 165 166 val data8 = Seq.fill(8)(Module(new SQData8Module(size, numRead, numWrite, numForward))) 167 168 // writeback to lq/sq 169 for (i <- 0 until numWrite) { 170 // write to data8 171 for (j <- 0 until 8) { 172 data8(j).io.waddr(i) := io.waddr(i) 173 data8(j).io.wdata(i).valid := io.wdata(i).mask(j) 174 data8(j).io.wdata(i).data := io.wdata(i).data(8*(j+1)-1, 8*j) 175 data8(j).io.wen(i) := io.wen(i) 176 } 177 } 178 179 // destorequeue read data 180 for (i <- 0 until numRead) { 181 for (j <- 0 until 8) { 182 data8(j).io.raddr(i) := io.raddr(i) 183 } 184 io.rdata(i).mask := VecInit((0 until 8).map(j => data8(j).io.rdata(i).valid)).asUInt 185 io.rdata(i).data := VecInit((0 until 8).map(j => data8(j).io.rdata(i).data)).asUInt 186 } 187 188 // DataModuleTemplate should not be used when there're any write conflicts 189 for (i <- 0 until numWrite) { 190 for (j <- i+1 until numWrite) { 191 assert(!(io.wen(i) && io.wen(j) && io.waddr(i) === io.waddr(j))) 192 } 193 } 194 195 (0 until numForward).map(i => { 196 // parallel fwd logic 197 for (j <- 0 until 8) { 198 data8(j).io.needForward(i) <> io.needForward(i) 199 io.forwardMask(i) := VecInit((0 until 8).map(j => data8(j).io.forwardValid(i))) 200 io.forwardData(i) := VecInit((0 until 8).map(j => data8(j).io.forwardData(i))) 201 } 202 }) 203}