xref: /XiangShan/src/main/scala/device/AXI4Memory.scala (revision 8891a219bbc84f568e1d134854d8d5ed86d6d560)
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