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