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