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