xref: /XiangShan/src/main/scala/device/AXI4RAM.scala (revision 708ceed4afe43fb0ea3a52407e46b2794c573634)
1/***************************************************************************************
2* Copyright (c) 2020-2021 Institute of Computing Technology, Chinese Academy of Sciences
3* Copyright (c) 2020-2021 Peng Cheng Laboratory
4*
5* XiangShan is licensed under Mulan PSL v2.
6* You can use this software according to the terms and conditions of the Mulan PSL v2.
7* You may obtain a copy of Mulan PSL v2 at:
8*          http://license.coscl.org.cn/MulanPSL2
9*
10* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
11* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
12* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
13*
14* See the Mulan PSL v2 for more details.
15***************************************************************************************/
16
17package device
18
19import chipsalliance.rocketchip.config.Parameters
20import chisel3._
21import chisel3.util._
22import chisel3.experimental.ExtModule
23import freechips.rocketchip.amba.axi4.{AXI4EdgeParameters, AXI4MasterNode, AXI4SlaveNode}
24import freechips.rocketchip.diplomacy.{AddressSet, InModuleBody, LazyModule, LazyModuleImp, RegionType}
25import top.HaveAXI4MemPort
26import xiangshan.HasXSParameter
27import utils.MaskExpand
28
29class RAMHelper(memByte: BigInt) extends ExtModule {
30  val DataBits = 64
31
32  val clk   = IO(Input(Clock()))
33  val en    = IO(Input(Bool()))
34  val rIdx  = IO(Input(UInt(DataBits.W)))
35  val rdata = IO(Output(UInt(DataBits.W)))
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  val wen   = IO(Input(Bool()))
40}
41
42class AXI4RAM
43(
44  address: Seq[AddressSet],
45  memByte: Long,
46  useBlackBox: Boolean = false,
47  executable: Boolean = true,
48  beatBytes: Int = 8,
49  burstLen: Int = 16,
50)(implicit p: Parameters)
51  extends AXI4SlaveModule(address, executable, beatBytes, burstLen)
52{
53  override lazy val module = new AXI4SlaveModuleImp(this){
54
55    val split = beatBytes / 8
56    val bankByte = memByte / split
57    val offsetBits = log2Up(memByte)
58
59    require(address.length >= 1)
60    val baseAddress = address(0).base
61
62    def index(addr: UInt) = ((addr - baseAddress.U)(offsetBits - 1, 0) >> log2Ceil(beatBytes)).asUInt()
63
64    def inRange(idx: UInt) = idx < (memByte / beatBytes).U
65
66    val wIdx = index(waddr) + writeBeatCnt
67    val rIdx = index(raddr) + readBeatCnt
68    val wen = in.w.fire() && inRange(wIdx)
69    require(beatBytes >= 8)
70
71    val rdata = if (useBlackBox) {
72      val mems = (0 until split).map {_ => Module(new RAMHelper(bankByte))}
73      mems.zipWithIndex map { case (mem, i) =>
74        mem.clk   := clock
75        mem.en    := !reset.asBool() && ((state === s_rdata) || (state === s_wdata))
76        mem.rIdx  := (rIdx << log2Up(split)) + i.U
77        mem.wIdx  := (wIdx << log2Up(split)) + i.U
78        mem.wdata := in.w.bits.data((i + 1) * 64 - 1, i * 64)
79        mem.wmask := MaskExpand(in.w.bits.strb((i + 1) * 8 - 1, i * 8))
80        mem.wen   := wen
81      }
82      val rdata = mems.map {mem => mem.rdata}
83      Cat(rdata.reverse)
84    } else {
85      val mem = Mem(memByte / beatBytes, Vec(beatBytes, UInt(8.W)))
86
87      val wdata = VecInit.tabulate(beatBytes) { i => in.w.bits.data(8 * (i + 1) - 1, 8 * i) }
88      when(wen) {
89        mem.write(wIdx, wdata, in.w.bits.strb.asBools())
90      }
91
92      Cat(mem.read(rIdx).reverse)
93    }
94    in.r.bits.data := rdata
95  }
96}
97
98class AXI4RAMWrapper
99(snode: AXI4SlaveNode, memByte: Long, useBlackBox: Boolean = false)
100(implicit p: Parameters)
101  extends LazyModule {
102
103  val mnode = AXI4MasterNode(List(snode.in.head._2.master))
104
105  val portParam = snode.portParams.head
106  val slaveParam = portParam.slaves.head
107  val burstLen = portParam.maxTransfer / portParam.beatBytes
108  val ram = LazyModule(new AXI4RAM(
109    slaveParam.address, memByte, useBlackBox,
110    slaveParam.executable, portParam.beatBytes, burstLen
111  ))
112  ram.node := mnode
113
114  val io_axi4 = InModuleBody{ mnode.makeIOs() }
115  def connectToSoC(soc: HaveAXI4MemPort) = {
116    io_axi4 <> soc.memory
117  }
118
119  lazy val module = new LazyModuleImp(this){}
120}
121