xref: /XiangShan/src/main/scala/device/AXI4RAM.scala (revision c6d439803a044ea209139672b25e35fe8d7f4aa0)
1/***************************************************************************************
2* Copyright (c) 2020-2021 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.util._
21import freechips.rocketchip.amba.axi4.{AXI4SlaveNode, AXI4EdgeParameters, AXI4MasterNode}
22import freechips.rocketchip.diplomacy.{AddressSet, InModuleBody, LazyModule, LazyModuleImp, RegionType}
23import top.HaveAXI4MemPort
24import xiangshan.HasXSParameter
25import utils.MaskExpand
26
27class RAMHelper(memByte: BigInt) extends BlackBox {
28  val DataBits = 64
29  val io = IO(new Bundle {
30    val clk   = Input(Clock())
31    val en    = Input(Bool())
32    val rIdx  = Input(UInt(DataBits.W))
33    val rdata = Output(UInt(DataBits.W))
34    val wIdx  = Input(UInt(DataBits.W))
35    val wdata = Input(UInt(DataBits.W))
36    val wmask = Input(UInt(DataBits.W))
37    val wen   = Input(Bool())
38  })
39}
40
41class AXI4RAM
42(
43  address: Seq[AddressSet],
44  memByte: Long,
45  useBlackBox: Boolean = false,
46  executable: Boolean = true,
47  beatBytes: Int = 8,
48  burstLen: Int = 16,
49)(implicit p: Parameters)
50  extends AXI4SlaveModule(address, executable, beatBytes, burstLen)
51{
52  override lazy val module = new AXI4SlaveModuleImp(this){
53
54    val split = beatBytes / 8
55    val bankByte = memByte / split
56    val offsetBits = log2Up(memByte)
57
58    require(address.length >= 1)
59    val baseAddress = address(0).base
60
61    def index(addr: UInt) = ((addr - baseAddress.U)(offsetBits - 1, 0) >> log2Ceil(beatBytes)).asUInt()
62
63    def inRange(idx: UInt) = idx < (memByte / beatBytes).U
64
65    val wIdx = index(waddr) + writeBeatCnt
66    val rIdx = index(raddr) + readBeatCnt
67    val wen = in.w.fire() && inRange(wIdx)
68    require(beatBytes >= 8)
69
70    val rdata = if (useBlackBox) {
71      val mems = (0 until split).map {_ => Module(new RAMHelper(bankByte))}
72      mems.zipWithIndex map { case (mem, i) =>
73        mem.io.clk   := clock
74        mem.io.en    := !reset.asBool() && ((state === s_rdata) || (state === s_wdata))
75        mem.io.rIdx  := (rIdx << log2Up(split)) + i.U
76        mem.io.wIdx  := (wIdx << log2Up(split)) + i.U
77        mem.io.wdata := in.w.bits.data((i + 1) * 64 - 1, i * 64)
78        mem.io.wmask := MaskExpand(in.w.bits.strb((i + 1) * 8 - 1, i * 8))
79        mem.io.wen   := wen
80      }
81      val rdata = mems.map {mem => mem.io.rdata}
82      Cat(rdata.reverse)
83    } else {
84      val mem = Mem(memByte / beatBytes, Vec(beatBytes, UInt(8.W)))
85
86      val wdata = VecInit.tabulate(beatBytes) { i => in.w.bits.data(8 * (i + 1) - 1, 8 * i) }
87      when(wen) {
88        mem.write(wIdx, wdata, in.w.bits.strb.asBools())
89      }
90
91      Cat(mem.read(rIdx).reverse)
92    }
93    in.r.bits.data := rdata
94  }
95}
96
97class AXI4RAMWrapper
98(snode: AXI4SlaveNode, memByte: Long, useBlackBox: Boolean = false)
99(implicit p: Parameters)
100  extends LazyModule {
101
102  val mnode = AXI4MasterNode(List(snode.in.head._2.master))
103
104  val portParam = snode.portParams.head
105  val slaveParam = portParam.slaves.head
106  val burstLen = portParam.maxTransfer / portParam.beatBytes
107  val ram = LazyModule(new AXI4RAM(
108    slaveParam.address, memByte, useBlackBox,
109    slaveParam.executable, portParam.beatBytes, burstLen
110  ))
111  ram.node := mnode
112
113  val io_axi4 = InModuleBody{ mnode.makeIOs() }
114  def connectToSoC(soc: HaveAXI4MemPort) = {
115    io_axi4 <> soc.memory
116  }
117
118  lazy val module = new LazyModuleImp(this){}
119}
120