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