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 utility._ 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 val pending_write_req_ready = Wire(Bool()) 179 val pending_write_need_req = pending_write_req_valid.last && !pending_write_req_ready 180 val aw_and_w_last_arrive_at_same_time = in.aw.fire && in.w.fire && in.w.bits.last 181 val w_last_arrive_before_aw = in.aw.fire && pending_write_need_req 182 val aw_arrive_before_w_last = pending_write_req_valid.head && in.w.fire && in.w.bits.last 183 val aw_arrive_before_w = pending_write_req_valid.head && pending_write_need_req 184 val write_req_enq_pending = aw_arrive_before_w || aw_arrive_before_w_last 185 val write_req_enq_no_pending = aw_and_w_last_arrive_at_same_time || w_last_arrive_before_aw 186 val write_req_valid = write_req_enq_pending || write_req_enq_no_pending 187 val write_req_enq_addr = Mux(write_req_enq_pending, pending_write_req_bits.addr, in.aw.bits.addr) 188 val write_req_enq_id = Mux(write_req_enq_pending, pending_write_req_bits.id, in.aw.bits.id) 189 pending_write_req_ready := writeRequest(write_req_valid, write_req_enq_addr, write_req_enq_id) 190 191 when (in.aw.fire && !write_req_enq_no_pending) { 192 pending_write_req_valid.head := true.B 193 }.elsewhen (pending_write_req_ready) { 194 pending_write_req_valid.head := false.B 195 } 196 val write_req_last = in.w.fire && in.w.bits.last 197 when (write_req_last) { 198 pending_write_req_valid.last := true.B 199 }.elsewhen (pending_write_req_ready) { 200 pending_write_req_valid.last := false.B 201 } 202 in.aw.ready := !pending_write_req_valid.head || pending_write_req_ready 203 in.w.ready := in.aw.ready || !pending_write_req_valid.last 204 205 // ram is written when write data fire 206 val wdata_cnt = Counter(outer.burstLen) 207 val write_req_addr = Mux(in.aw.fire, in.aw.bits.addr, pending_write_req_bits.addr) 208 val write_req_index = ramIndex(write_req_addr) + wdata_cnt.value 209 when (in.w.fire) { 210 ramHelper.write( 211 addr = write_req_index, 212 data = in.w.bits.data.asTypeOf(Vec(outer.beatBytes, UInt(8.W))), 213 mask = in.w.bits.strb.asBools 214 ) 215 } 216 when (write_req_last) { 217 wdata_cnt.reset() 218 }.elsewhen (in.w.fire) { 219 wdata_cnt.inc() 220 } 221 222 // read data response: resp from DRAMsim3; read data and response to in.r 223 // This is the output of the last pipeline before in.r. This is not the pipeline registers. 224 val r_resp = Wire(Decoupled(chiselTypeOf(in.r.bits))) 225 226 val pending_read_resp_valid = RegInit(false.B) 227 val pending_read_resp_id = Reg(UInt(r_resp.bits.id.getWidth.W)) 228 val has_read_resp = Wire(Bool()) 229 val read_resp_last = r_resp.fire && r_resp.bits.last 230 val read_request_cnt = RegInit(0.U(8.W)) 231 val read_have_req_cnt = read_request_cnt =/= 0.U 232 val (read_resp_valid, read_resp_id) = readResponse((!has_read_resp || read_resp_last) && read_have_req_cnt) 233 has_read_resp := (read_resp_valid && !read_resp_last) || pending_read_resp_valid 234 val rdata_cnt = Counter(outer.burstLen) 235 val read_resp_addr = addressMem(r_resp.bits.id) + rdata_cnt.value 236 val read_resp_len = arlenMem(r_resp.bits.id) 237 r_resp.valid := read_resp_valid || pending_read_resp_valid 238 r_resp.bits.id := Mux(pending_read_resp_valid, pending_read_resp_id, read_resp_id) 239 // We cannot get the read data this cycle because the RAM helper has one-cycle latency. 240 r_resp.bits.data := DontCare 241 r_resp.bits.resp := AXI4Parameters.RESP_OKAY 242 r_resp.bits.last := (rdata_cnt.value === read_resp_len) 243 244 // The return values of DPI-C are used to determine whether a request has been made or completed 245 // pending_read_req_ready ---> readRequest() 246 // read_resp_valid <--- readResponse() 247 when (pending_read_req_ready && !read_resp_valid) { 248 read_request_cnt := read_request_cnt + 1.U 249 }.elsewhen (read_resp_valid && !pending_read_req_ready) { 250 read_request_cnt := read_request_cnt - 1.U 251 } 252 when (!pending_read_resp_valid && read_resp_valid && !read_resp_last) { 253 pending_read_resp_valid := true.B 254 pending_read_resp_id := read_resp_id 255 }.elsewhen (pending_read_resp_valid && !read_resp_valid && read_resp_last) { 256 pending_read_resp_valid := false.B 257 } 258 when (read_resp_last) { 259 rdata_cnt.reset() 260 }.elsewhen (r_resp.fire) { 261 rdata_cnt.inc() 262 } 263 264 // `r_pipe`: the extra pipeline registers for the read response `in.r` 265 prefix("r_pipe") { 266 val valid = RegInit(false.B) 267 when (in.r.fire) { valid := false.B } 268 when (r_resp.fire) { valid := true.B } 269 in.r.valid := valid 270 in.r.bits := RegEnable(r_resp.bits, r_resp.fire) 271 r_resp.ready := !valid || in.r.ready 272 273 // the data should be auto-hold 274 in.r.bits.data := ramHelper.readAndHold(read_resp_addr, r_resp.fire).asUInt 275 } 276 277 // write response 278 val pending_write_resp_valid = RegInit(false.B) 279 val pending_write_resp_id = Reg(UInt(in.b.bits.id.getWidth.W)) 280 val has_write_resp = Wire(Bool()) 281 val write_request_cnt = RegInit(0.U(8.W)) 282 val write_have_req_cnt = write_request_cnt =/= 0.U 283 val (write_resp_valid, write_resp_id) = writeResponse((!has_write_resp || in.b.fire) && write_have_req_cnt) 284 has_write_resp := write_resp_valid || pending_write_resp_valid 285 in.b.valid := write_resp_valid || pending_write_resp_valid 286 in.b.bits.id := Mux(pending_write_resp_valid, pending_write_resp_id, write_resp_id) 287 in.b.bits.resp := AXI4Parameters.RESP_OKAY 288 289 // The return values of DPI-C are used to determine whether a request has been made or completed 290 // pending_write_req_ready ---> writeRequest() 291 // write_resp_valid <--- writeResponse() 292 when (pending_write_req_ready && !write_resp_valid) { 293 write_request_cnt := write_request_cnt + 1.U 294 }.elsewhen (write_resp_valid && !pending_write_req_ready) { 295 write_request_cnt := write_request_cnt - 1.U 296 } 297 when (!pending_write_resp_valid && write_resp_valid && !in.b.ready) { 298 pending_write_resp_valid := true.B 299 pending_write_resp_id := write_resp_id 300 }.elsewhen (pending_write_resp_valid && !write_resp_valid && in.b.ready) { 301 pending_write_resp_valid := false.B 302 } 303} 304 305class AXI4Memory 306( 307 val address: Seq[AddressSet], 308 val memByte: Long, 309 val useBlackBox: Boolean = false, 310 val executable: Boolean = true, 311 val beatBytes: Int, 312 val burstLen: Int, 313)(implicit p: Parameters) 314 extends AXI4SlaveModule(address, executable, beatBytes, burstLen) 315{ 316 override lazy val module = new AXI4MemoryImp(this) 317} 318 319class AXI4MemoryWrapper ( 320 slave: AXI4SlaveNode, 321 memByte: Long, 322 useBlackBox: Boolean = false 323)(implicit p: Parameters) extends AXI4MemorySlave(slave, memByte, useBlackBox) { 324 val ram = LazyModule(new AXI4Memory( 325 slaveParam.address, 326 memByte, 327 useBlackBox, 328 slaveParam.executable, 329 portParam.beatBytes, 330 burstLen 331 )) 332 ram.node := master 333} 334 335abstract class AXI4MemorySlave ( 336 slave: AXI4SlaveNode, 337 memByte: Long, 338 useBlackBox: Boolean = false 339)(implicit p: Parameters) extends LazyModule { 340 val master = AXI4MasterNode(List(slave.in.head._2.master)) 341 342 val portParam = slave.portParams.head 343 val slaveParam = portParam.slaves.head 344 val burstLen = portParam.maxTransfer / portParam.beatBytes 345 346 val io_axi4 = InModuleBody{ master.makeIOs() } 347 348 lazy val module = new LazyModuleImp(this) { } 349} 350 351object AXI4MemorySlave { 352 def apply( 353 slave: AXI4SlaveNode, 354 memByte: Long, 355 useBlackBox: Boolean = false, 356 dynamicLatency: Boolean = false 357 )(implicit p: Parameters): AXI4MemorySlave = { 358 val memory = if (dynamicLatency) { 359 LazyModule(new AXI4MemoryWrapper(slave, memByte, useBlackBox)) 360 } else { 361 LazyModule(new AXI4RAMWrapper(slave, memByte, useBlackBox)) 362 } 363 memory 364 } 365} 366