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