1/*************************************************************************************** 2 * Copyright (c) 2020-2022 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 device 17 18import org.chipsalliance.cde.config.Parameters 19import chisel3._ 20import chisel3.experimental.{ExtModule, prefix} 21import chisel3.util._ 22import difftest.common.DifftestMem 23import freechips.rocketchip.amba.axi4.{AXI4MasterNode, AXI4Parameters, AXI4SlaveNode} 24import freechips.rocketchip.diplomacy.{AddressSet, InModuleBody, LazyModule, LazyModuleImp} 25import utils._ 26 27class MemoryRequestHelper(requestType: Int) 28 extends ExtModule(Map("REQUEST_TYPE" -> requestType)) 29 with HasExtModuleInline 30{ 31 val clock = IO(Input(Clock())) 32 val reset = IO(Input(Reset())) 33 val io = IO(new Bundle { 34 val req = Flipped(ValidIO(new Bundle { 35 val addr = UInt(64.W) 36 val id = UInt(32.W) 37 })) 38 val response = Output(Bool()) 39 }) 40 41 val verilogLines = Seq( 42 "import \"DPI-C\" function bit memory_request (", 43 " input longint address,", 44 " input int id,", 45 " input bit isWrite", 46 ");", 47 "", 48 "module MemoryRequestHelper #(", 49 " parameter REQUEST_TYPE", 50 ")(", 51 " input clock,", 52 " input reset,", 53 " input io_req_valid,", 54 " input [63:0] io_req_bits_addr,", 55 " input [31:0] io_req_bits_id,", 56 " output reg io_response", 57 ");", 58 "", 59 "always @(posedge clock or posedge reset) begin", 60 " if (reset) begin", 61 " io_response <= 1'b0;", 62 " end", 63 " else if (io_req_valid) begin", 64 " io_response <= memory_request(io_req_bits_addr, io_req_bits_id, REQUEST_TYPE);", 65 " end" + 66 " else begin", 67 " io_response <= 1'b0;", 68 " end", 69 "end", 70 "", 71 "endmodule" 72 ) 73 setInline(s"$desiredName.v", verilogLines.mkString("\n")) 74} 75 76class MemoryResponseHelper(requestType: Int) 77 extends ExtModule(Map("REQUEST_TYPE" -> requestType)) 78 with HasExtModuleInline 79{ 80 val clock = IO(Input(Clock())) 81 val reset = IO(Input(Reset())) 82 val enable = IO(Input(Bool())) 83 val response = IO(Output(UInt(64.W))) 84 85 val verilogLines = Seq( 86 "import \"DPI-C\" function longint memory_response (", 87 " input bit isWrite", 88 ");", 89 "", 90 "module MemoryResponseHelper #(", 91 " parameter REQUEST_TYPE", 92 ")(", 93 " input clock,", 94 " input reset,", 95 " input enable,", 96 " output reg [63:0] response", 97 ");", 98 "", 99 "always @(posedge clock or posedge reset) begin", 100 " if (reset) begin", 101 " response <= 64'b0;", 102 " end", 103 " else if (!reset && enable) begin", 104 " response <= memory_response(REQUEST_TYPE);", 105 " end", 106 " else begin", 107 " response <= 64'b0;", 108 " end", 109 "end", 110 "", 111 "endmodule" 112 ) 113 setInline(s"$desiredName.v", verilogLines.mkString("\n")) 114} 115 116trait MemoryHelper { this: Module => 117 private def requestType(isWrite: Boolean): Int = if (isWrite) 1 else 0 118 private def request(valid: Bool, addr: UInt, id: UInt, isWrite: Boolean): Bool = { 119 val helper = Module(new MemoryRequestHelper(requestType(isWrite))) 120 helper.clock := clock 121 helper.reset := reset 122 helper.io.req.valid := valid 123 helper.io.req.bits.addr := addr 124 helper.io.req.bits.id := id 125 helper.io.response 126 } 127 protected def readRequest(valid: Bool, addr: UInt, id: UInt): Bool = 128 request(valid, addr, id, false) 129 protected def writeRequest(valid: Bool, addr: UInt, id: UInt): Bool = 130 request(valid, addr, id, true) 131 private def response(enable: Bool, isWrite: Boolean): (Bool, UInt) = { 132 val helper = Module(new MemoryResponseHelper(requestType(isWrite))) 133 helper.clock := clock 134 helper.reset := reset 135 helper.enable := enable 136 (helper.response(32), helper.response(31, 0)) 137 } 138 protected def readResponse(enable: Bool): (Bool, UInt) = 139 response(enable, false) 140 protected def writeResponse(enable: Bool): (Bool, UInt) = 141 response(enable, true) 142} 143 144class AXI4MemoryImp[T <: Data](outer: AXI4Memory) extends AXI4SlaveModuleImp(outer) with MemoryHelper { 145 val ramBaseAddr = outer.address.head.base 146 val (ramIndexBits, ramOffsetBits) = (log2Ceil(outer.beatBytes), log2Ceil(outer.memByte)) 147 def ramIndex(addr: UInt) = ((addr - ramBaseAddr.U)(ramOffsetBits - 1, 0) >> ramIndexBits).asUInt 148 val ramHelper = DifftestMem(outer.memByte, outer.beatBytes, 8, singlePort = false) 149 150 val numOutstanding = 1 << in.ar.bits.id.getWidth 151 // Note: we are using in.ar.bits.addr.getWidth insead of ramOffsetBits here. 152 // Why: the CPU may access out-of-range addresses. Let the RAM helper deal with it. 153 val addressMem = Mem(numOutstanding, UInt((in.ar.bits.addr.getWidth - ramIndexBits).W)) 154 val arlenMem = Mem(numOutstanding, UInt(in.ar.bits.len.getWidth.W)) 155 156 // accept a read request and send it to the external model 157 val pending_read_req_valid = RegInit(false.B) 158 val pending_read_req_bits = RegEnable(in.ar.bits, in.ar.fire) 159 val pending_read_req_ready = Wire(Bool()) 160 val pending_read_need_req = pending_read_req_valid && !pending_read_req_ready 161 val read_req_valid = pending_read_need_req || in.ar.valid 162 val read_req_bits = Mux(pending_read_need_req, pending_read_req_bits, in.ar.bits) 163 pending_read_req_ready := readRequest(read_req_valid, read_req_bits.addr, read_req_bits.id) 164 165 when (in.ar.fire) { 166 pending_read_req_valid := true.B 167 addressMem.write(read_req_bits.id, ramIndex(read_req_bits.addr)) 168 arlenMem.write(read_req_bits.id, read_req_bits.len) 169 }.elsewhen (pending_read_req_ready) { 170 pending_read_req_valid := false.B 171 } 172 in.ar.ready := !pending_read_req_valid || pending_read_req_ready 173 174 // accept a write request (including address and data) and send it to the external model 175 val pending_write_req_valid = RegInit(VecInit.fill(2)(false.B)) 176 val pending_write_req_bits = RegEnable(in.aw.bits, in.aw.fire) 177 val pending_write_req_data = RegEnable(in.w.bits, in.w.fire) 178 XSError(in.aw.fire && in.aw.bits.len === 0.U, "data must have more than one beat now") 179 val pending_write_req_ready = Wire(Bool()) 180 val pending_write_need_req = pending_write_req_valid.last && !pending_write_req_ready 181 val write_req_valid = pending_write_req_valid.head && (pending_write_need_req || in.w.valid && in.w.bits.last) 182 pending_write_req_ready := writeRequest(write_req_valid, pending_write_req_bits.addr, pending_write_req_bits.id) 183 184 when (in.aw.fire) { 185 pending_write_req_valid.head := true.B 186 }.elsewhen (pending_write_req_ready) { 187 pending_write_req_valid.head := false.B 188 } 189 val write_req_last = in.w.fire && in.w.bits.last 190 when (write_req_last) { 191 pending_write_req_valid.last := true.B 192 }.elsewhen (pending_write_req_ready) { 193 pending_write_req_valid.last := false.B 194 } 195 in.aw.ready := !pending_write_req_valid.head || pending_write_req_ready 196 in.w.ready := in.aw.ready || !pending_write_req_valid.last 197 198 // ram is written when write data fire 199 val wdata_cnt = Counter(outer.burstLen) 200 val write_req_addr = Mux(in.aw.fire, in.aw.bits.addr, pending_write_req_bits.addr) 201 val write_req_index = ramIndex(write_req_addr) + wdata_cnt.value 202 when (in.w.fire) { 203 ramHelper.write( 204 addr = write_req_index, 205 data = in.w.bits.data.asTypeOf(Vec(outer.beatBytes, UInt(8.W))), 206 mask = in.w.bits.strb.asBools 207 ) 208 } 209 when (write_req_last) { 210 wdata_cnt.reset() 211 }.elsewhen (in.w.fire) { 212 wdata_cnt.inc() 213 } 214 215 // read data response: resp from DRAMsim3; read data and response to in.r 216 // This is the output of the last pipeline before in.r. This is not the pipeline registers. 217 val r_resp = Wire(Decoupled(chiselTypeOf(in.r.bits))) 218 219 val pending_read_resp_valid = RegInit(false.B) 220 val pending_read_resp_id = Reg(UInt(r_resp.bits.id.getWidth.W)) 221 val has_read_resp = Wire(Bool()) 222 val read_resp_last = r_resp.fire && r_resp.bits.last 223 val (read_resp_valid, read_resp_id) = readResponse(!has_read_resp || read_resp_last) 224 has_read_resp := (read_resp_valid && !read_resp_last) || pending_read_resp_valid 225 val rdata_cnt = Counter(outer.burstLen) 226 val read_resp_addr = addressMem(r_resp.bits.id) + rdata_cnt.value 227 val read_resp_len = arlenMem(r_resp.bits.id) 228 r_resp.valid := read_resp_valid || pending_read_resp_valid 229 r_resp.bits.id := Mux(pending_read_resp_valid, pending_read_resp_id, read_resp_id) 230 // We cannot get the read data this cycle because the RAM helper has one-cycle latency. 231 r_resp.bits.data := DontCare 232 r_resp.bits.resp := AXI4Parameters.RESP_OKAY 233 r_resp.bits.last := (rdata_cnt.value === read_resp_len) 234 235 when (!pending_read_resp_valid && read_resp_valid && !read_resp_last) { 236 pending_read_resp_valid := true.B 237 pending_read_resp_id := read_resp_id 238 }.elsewhen (pending_read_resp_valid && !read_resp_valid && read_resp_last) { 239 pending_read_resp_valid := false.B 240 } 241 when (read_resp_last) { 242 rdata_cnt.reset() 243 }.elsewhen (r_resp.fire) { 244 rdata_cnt.inc() 245 } 246 247 // `r_pipe`: the extra pipeline registers for the read response `in.r` 248 prefix("r_pipe") { 249 val valid = RegInit(false.B) 250 when (r_resp.valid && in.r.ready) { 251 valid := true.B 252 }.elsewhen (in.r.ready) { 253 valid := false.B 254 } 255 in.r.valid := valid 256 in.r.bits := RegEnable(r_resp.bits, r_resp.valid && in.r.ready) 257 r_resp.ready := !valid || in.r.ready 258 259 // the data should be auto-hold 260 in.r.bits.data := ramHelper.readAndHold(read_resp_addr, r_resp.fire).asUInt 261 } 262 263 // write response 264 val pending_write_resp_valid = RegInit(false.B) 265 val pending_write_resp_id = Reg(UInt(in.b.bits.id.getWidth.W)) 266 val has_write_resp = Wire(Bool()) 267 val (write_resp_valid, write_resp_id) = writeResponse(!has_write_resp || in.b.fire) 268 has_write_resp := write_resp_valid || pending_write_resp_valid 269 in.b.valid := write_resp_valid || pending_write_resp_valid 270 in.b.bits.id := Mux(pending_write_resp_valid, pending_write_resp_id, write_resp_id) 271 in.b.bits.resp := AXI4Parameters.RESP_OKAY 272 273 when (!pending_write_resp_valid && write_resp_valid && !in.b.ready) { 274 pending_write_resp_valid := true.B 275 pending_write_resp_id := write_resp_id 276 }.elsewhen (pending_write_resp_valid && !write_resp_valid && in.b.ready) { 277 pending_write_resp_valid := false.B 278 } 279} 280 281class AXI4Memory 282( 283 val address: Seq[AddressSet], 284 val memByte: Long, 285 val useBlackBox: Boolean = false, 286 val executable: Boolean = true, 287 val beatBytes: Int, 288 val burstLen: Int, 289)(implicit p: Parameters) 290 extends AXI4SlaveModule(address, executable, beatBytes, burstLen) 291{ 292 override lazy val module = new AXI4MemoryImp(this) 293} 294 295class AXI4MemoryWrapper ( 296 slave: AXI4SlaveNode, 297 memByte: Long, 298 useBlackBox: Boolean = false 299)(implicit p: Parameters) extends AXI4MemorySlave(slave, memByte, useBlackBox) { 300 val ram = LazyModule(new AXI4Memory( 301 slaveParam.address, 302 memByte, 303 useBlackBox, 304 slaveParam.executable, 305 portParam.beatBytes, 306 burstLen 307 )) 308 ram.node := master 309} 310 311abstract class AXI4MemorySlave ( 312 slave: AXI4SlaveNode, 313 memByte: Long, 314 useBlackBox: Boolean = false 315)(implicit p: Parameters) extends LazyModule { 316 val master = AXI4MasterNode(List(slave.in.head._2.master)) 317 318 val portParam = slave.portParams.head 319 val slaveParam = portParam.slaves.head 320 val burstLen = portParam.maxTransfer / portParam.beatBytes 321 322 val io_axi4 = InModuleBody{ master.makeIOs() } 323 324 lazy val module = new LazyModuleImp(this) { } 325} 326 327object AXI4MemorySlave { 328 def apply( 329 slave: AXI4SlaveNode, 330 memByte: Long, 331 useBlackBox: Boolean = false, 332 dynamicLatency: Boolean = false 333 )(implicit p: Parameters): AXI4MemorySlave = { 334 val memory = if (dynamicLatency) { 335 LazyModule(new AXI4MemoryWrapper(slave, memByte, useBlackBox)) 336 } else { 337 LazyModule(new AXI4RAMWrapper(slave, memByte, useBlackBox)) 338 } 339 memory 340 } 341} 342