171784e68SYinan Xu/*************************************************************************************** 271784e68SYinan Xu * Copyright (c) 2020-2022 Institute of Computing Technology, Chinese Academy of Sciences 371784e68SYinan Xu * 471784e68SYinan Xu * XiangShan is licensed under Mulan PSL v2. 571784e68SYinan Xu * You can use this software according to the terms and conditions of the Mulan PSL v2. 671784e68SYinan Xu * You may obtain a copy of Mulan PSL v2 at: 771784e68SYinan Xu * http://license.coscl.org.cn/MulanPSL2 871784e68SYinan Xu * 971784e68SYinan Xu * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, 1071784e68SYinan Xu * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, 1171784e68SYinan Xu * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. 1271784e68SYinan Xu * 1371784e68SYinan Xu * See the Mulan PSL v2 for more details. 1471784e68SYinan Xu ***************************************************************************************/ 1571784e68SYinan Xu 1671784e68SYinan Xupackage device 1771784e68SYinan Xu 188891a219SYinan Xuimport org.chipsalliance.cde.config.Parameters 1971784e68SYinan Xuimport chisel3._ 20*9f659d72SKamimiaoimport chisel3.experimental.{ExtModule, prefix} 2171784e68SYinan Xuimport chisel3.util._ 22*9f659d72SKamimiaoimport difftest.common.DifftestMem 2371784e68SYinan Xuimport freechips.rocketchip.amba.axi4.{AXI4MasterNode, AXI4Parameters, AXI4SlaveNode} 2471784e68SYinan Xuimport freechips.rocketchip.diplomacy.{AddressSet, InModuleBody, LazyModule, LazyModuleImp} 2571784e68SYinan Xuimport utils._ 2671784e68SYinan Xu 2771784e68SYinan Xuclass MemoryRequestHelper(requestType: Int) 2871784e68SYinan Xu extends ExtModule(Map("REQUEST_TYPE" -> requestType)) 2971784e68SYinan Xu with HasExtModuleInline 3071784e68SYinan Xu{ 3171784e68SYinan Xu val clock = IO(Input(Clock())) 3271784e68SYinan Xu val reset = IO(Input(Reset())) 3371784e68SYinan Xu val io = IO(new Bundle { 3471784e68SYinan Xu val req = Flipped(ValidIO(new Bundle { 3571784e68SYinan Xu val addr = UInt(64.W) 3671784e68SYinan Xu val id = UInt(32.W) 3771784e68SYinan Xu })) 3871784e68SYinan Xu val response = Output(Bool()) 3971784e68SYinan Xu }) 4071784e68SYinan Xu 4171784e68SYinan Xu val verilogLines = Seq( 4271784e68SYinan Xu "import \"DPI-C\" function bit memory_request (", 4371784e68SYinan Xu " input longint address,", 4471784e68SYinan Xu " input int id,", 4571784e68SYinan Xu " input bit isWrite", 4671784e68SYinan Xu ");", 4771784e68SYinan Xu "", 4871784e68SYinan Xu "module MemoryRequestHelper #(", 4971784e68SYinan Xu " parameter REQUEST_TYPE", 5071784e68SYinan Xu ")(", 5171784e68SYinan Xu " input clock,", 5271784e68SYinan Xu " input reset,", 5371784e68SYinan Xu " input io_req_valid,", 5471784e68SYinan Xu " input [63:0] io_req_bits_addr,", 5571784e68SYinan Xu " input [31:0] io_req_bits_id,", 5671784e68SYinan Xu " output reg io_response", 5771784e68SYinan Xu ");", 5871784e68SYinan Xu "", 5971784e68SYinan Xu "always @(posedge clock or posedge reset) begin", 6071784e68SYinan Xu " if (reset) begin", 6171784e68SYinan Xu " io_response <= 1'b0;", 6271784e68SYinan Xu " end", 6371784e68SYinan Xu " else if (io_req_valid) begin", 6471784e68SYinan Xu " io_response <= memory_request(io_req_bits_addr, io_req_bits_id, REQUEST_TYPE);", 6571784e68SYinan Xu " end" + 6671784e68SYinan Xu " else begin", 6771784e68SYinan Xu " io_response <= 1'b0;", 6871784e68SYinan Xu " end", 6971784e68SYinan Xu "end", 7071784e68SYinan Xu "", 7171784e68SYinan Xu "endmodule" 7271784e68SYinan Xu ) 7371784e68SYinan Xu setInline(s"$desiredName.v", verilogLines.mkString("\n")) 7471784e68SYinan Xu} 7571784e68SYinan Xu 7671784e68SYinan Xuclass MemoryResponseHelper(requestType: Int) 7771784e68SYinan Xu extends ExtModule(Map("REQUEST_TYPE" -> requestType)) 7871784e68SYinan Xu with HasExtModuleInline 7971784e68SYinan Xu{ 8071784e68SYinan Xu val clock = IO(Input(Clock())) 8171784e68SYinan Xu val reset = IO(Input(Reset())) 8271784e68SYinan Xu val enable = IO(Input(Bool())) 8371784e68SYinan Xu val response = IO(Output(UInt(64.W))) 8471784e68SYinan Xu 8571784e68SYinan Xu val verilogLines = Seq( 8671784e68SYinan Xu "import \"DPI-C\" function longint memory_response (", 8771784e68SYinan Xu " input bit isWrite", 8871784e68SYinan Xu ");", 8971784e68SYinan Xu "", 9071784e68SYinan Xu "module MemoryResponseHelper #(", 9171784e68SYinan Xu " parameter REQUEST_TYPE", 9271784e68SYinan Xu ")(", 9371784e68SYinan Xu " input clock,", 9471784e68SYinan Xu " input reset,", 9571784e68SYinan Xu " input enable,", 9671784e68SYinan Xu " output reg [63:0] response", 9771784e68SYinan Xu ");", 9871784e68SYinan Xu "", 9971784e68SYinan Xu "always @(posedge clock or posedge reset) begin", 10071784e68SYinan Xu " if (reset) begin", 10171784e68SYinan Xu " response <= 64'b0;", 10271784e68SYinan Xu " end", 10371784e68SYinan Xu " else if (!reset && enable) begin", 10471784e68SYinan Xu " response <= memory_response(REQUEST_TYPE);", 10571784e68SYinan Xu " end", 10671784e68SYinan Xu " else begin", 10771784e68SYinan Xu " response <= 64'b0;", 10871784e68SYinan Xu " end", 10971784e68SYinan Xu "end", 11071784e68SYinan Xu "", 11171784e68SYinan Xu "endmodule" 11271784e68SYinan Xu ) 11371784e68SYinan Xu setInline(s"$desiredName.v", verilogLines.mkString("\n")) 11471784e68SYinan Xu} 11571784e68SYinan Xu 11671784e68SYinan Xutrait MemoryHelper { this: Module => 11771784e68SYinan Xu private def requestType(isWrite: Boolean): Int = if (isWrite) 1 else 0 11871784e68SYinan Xu private def request(valid: Bool, addr: UInt, id: UInt, isWrite: Boolean): Bool = { 11971784e68SYinan Xu val helper = Module(new MemoryRequestHelper(requestType(isWrite))) 12071784e68SYinan Xu helper.clock := clock 12171784e68SYinan Xu helper.reset := reset 12271784e68SYinan Xu helper.io.req.valid := valid 12371784e68SYinan Xu helper.io.req.bits.addr := addr 12471784e68SYinan Xu helper.io.req.bits.id := id 12571784e68SYinan Xu helper.io.response 12671784e68SYinan Xu } 12771784e68SYinan Xu protected def readRequest(valid: Bool, addr: UInt, id: UInt): Bool = 12871784e68SYinan Xu request(valid, addr, id, false) 12971784e68SYinan Xu protected def writeRequest(valid: Bool, addr: UInt, id: UInt): Bool = 13071784e68SYinan Xu request(valid, addr, id, true) 13171784e68SYinan Xu private def response(enable: Bool, isWrite: Boolean): (Bool, UInt) = { 13271784e68SYinan Xu val helper = Module(new MemoryResponseHelper(requestType(isWrite))) 13371784e68SYinan Xu helper.clock := clock 13471784e68SYinan Xu helper.reset := reset 13571784e68SYinan Xu helper.enable := enable 13671784e68SYinan Xu (helper.response(32), helper.response(31, 0)) 13771784e68SYinan Xu } 13871784e68SYinan Xu protected def readResponse(enable: Bool): (Bool, UInt) = 13971784e68SYinan Xu response(enable, false) 14071784e68SYinan Xu protected def writeResponse(enable: Bool): (Bool, UInt) = 14171784e68SYinan Xu response(enable, true) 14271784e68SYinan Xu} 14371784e68SYinan Xu 14471784e68SYinan Xuclass AXI4MemoryImp[T <: Data](outer: AXI4Memory) extends AXI4SlaveModuleImp(outer) with MemoryHelper { 14571784e68SYinan Xu val ramBaseAddr = outer.address.head.base 146*9f659d72SKamimiao val (ramIndexBits, ramOffsetBits) = (log2Ceil(outer.beatBytes), log2Ceil(outer.memByte)) 147*9f659d72SKamimiao def ramIndex(addr: UInt) = ((addr - ramBaseAddr.U)(ramOffsetBits - 1, 0) >> ramIndexBits).asUInt 148*9f659d72SKamimiao val ramHelper = DifftestMem(outer.memByte, outer.beatBytes, 8, singlePort = false) 14971784e68SYinan Xu 15071784e68SYinan Xu val numOutstanding = 1 << in.ar.bits.id.getWidth 151*9f659d72SKamimiao // Note: we are using in.ar.bits.addr.getWidth insead of ramOffsetBits here. 152*9f659d72SKamimiao // Why: the CPU may access out-of-range addresses. Let the RAM helper deal with it. 153*9f659d72SKamimiao val addressMem = Mem(numOutstanding, UInt((in.ar.bits.addr.getWidth - ramIndexBits).W)) 15471784e68SYinan Xu val arlenMem = Mem(numOutstanding, UInt(in.ar.bits.len.getWidth.W)) 15571784e68SYinan Xu 15671784e68SYinan Xu // accept a read request and send it to the external model 15771784e68SYinan Xu val pending_read_req_valid = RegInit(false.B) 15871784e68SYinan Xu val pending_read_req_bits = RegEnable(in.ar.bits, in.ar.fire) 15971784e68SYinan Xu val pending_read_req_ready = Wire(Bool()) 16071784e68SYinan Xu val pending_read_need_req = pending_read_req_valid && !pending_read_req_ready 16171784e68SYinan Xu val read_req_valid = pending_read_need_req || in.ar.valid 16271784e68SYinan Xu val read_req_bits = Mux(pending_read_need_req, pending_read_req_bits, in.ar.bits) 16371784e68SYinan Xu pending_read_req_ready := readRequest(read_req_valid, read_req_bits.addr, read_req_bits.id) 16471784e68SYinan Xu 16571784e68SYinan Xu when (in.ar.fire) { 16671784e68SYinan Xu pending_read_req_valid := true.B 16771784e68SYinan Xu addressMem.write(read_req_bits.id, ramIndex(read_req_bits.addr)) 16871784e68SYinan Xu arlenMem.write(read_req_bits.id, read_req_bits.len) 16971784e68SYinan Xu }.elsewhen (pending_read_req_ready) { 17071784e68SYinan Xu pending_read_req_valid := false.B 17171784e68SYinan Xu } 17271784e68SYinan Xu in.ar.ready := !pending_read_req_valid || pending_read_req_ready 17371784e68SYinan Xu 17471784e68SYinan Xu // accept a write request (including address and data) and send it to the external model 17571784e68SYinan Xu val pending_write_req_valid = RegInit(VecInit.fill(2)(false.B)) 17671784e68SYinan Xu val pending_write_req_bits = RegEnable(in.aw.bits, in.aw.fire) 17771784e68SYinan Xu val pending_write_req_data = RegEnable(in.w.bits, in.w.fire) 17871784e68SYinan Xu XSError(in.aw.fire && in.aw.bits.len === 0.U, "data must have more than one beat now") 17971784e68SYinan Xu val pending_write_req_ready = Wire(Bool()) 18071784e68SYinan Xu val pending_write_need_req = pending_write_req_valid.last && !pending_write_req_ready 18171784e68SYinan Xu val write_req_valid = pending_write_req_valid.head && (pending_write_need_req || in.w.valid && in.w.bits.last) 18271784e68SYinan Xu pending_write_req_ready := writeRequest(write_req_valid, pending_write_req_bits.addr, pending_write_req_bits.id) 18371784e68SYinan Xu 18471784e68SYinan Xu when (in.aw.fire) { 18571784e68SYinan Xu pending_write_req_valid.head := true.B 18671784e68SYinan Xu }.elsewhen (pending_write_req_ready) { 18771784e68SYinan Xu pending_write_req_valid.head := false.B 18871784e68SYinan Xu } 18971784e68SYinan Xu val write_req_last = in.w.fire && in.w.bits.last 19071784e68SYinan Xu when (write_req_last) { 19171784e68SYinan Xu pending_write_req_valid.last := true.B 19271784e68SYinan Xu }.elsewhen (pending_write_req_ready) { 19371784e68SYinan Xu pending_write_req_valid.last := false.B 19471784e68SYinan Xu } 19571784e68SYinan Xu in.aw.ready := !pending_write_req_valid.head || pending_write_req_ready 19671784e68SYinan Xu in.w.ready := in.aw.ready || !pending_write_req_valid.last 19771784e68SYinan Xu 19871784e68SYinan Xu // ram is written when write data fire 19971784e68SYinan Xu val wdata_cnt = Counter(outer.burstLen) 20071784e68SYinan Xu val write_req_addr = Mux(in.aw.fire, in.aw.bits.addr, pending_write_req_bits.addr) 201*9f659d72SKamimiao val write_req_index = ramIndex(write_req_addr) + wdata_cnt.value 202*9f659d72SKamimiao when (in.w.fire) { 203*9f659d72SKamimiao ramHelper.write( 204*9f659d72SKamimiao addr = write_req_index, 205*9f659d72SKamimiao data = in.w.bits.data.asTypeOf(Vec(outer.beatBytes, UInt(8.W))), 206*9f659d72SKamimiao mask = in.w.bits.strb.asBools 207*9f659d72SKamimiao ) 20871784e68SYinan Xu } 20971784e68SYinan Xu when (write_req_last) { 21071784e68SYinan Xu wdata_cnt.reset() 21171784e68SYinan Xu }.elsewhen (in.w.fire) { 21271784e68SYinan Xu wdata_cnt.inc() 21371784e68SYinan Xu } 21471784e68SYinan Xu 215*9f659d72SKamimiao // read data response: resp from DRAMsim3; read data and response to in.r 216*9f659d72SKamimiao // This is the output of the last pipeline before in.r. This is not the pipeline registers. 217*9f659d72SKamimiao val r_resp = Wire(Decoupled(chiselTypeOf(in.r.bits))) 218*9f659d72SKamimiao 21971784e68SYinan Xu val pending_read_resp_valid = RegInit(false.B) 220*9f659d72SKamimiao val pending_read_resp_id = Reg(UInt(r_resp.bits.id.getWidth.W)) 22171784e68SYinan Xu val has_read_resp = Wire(Bool()) 222*9f659d72SKamimiao val read_resp_last = r_resp.fire && r_resp.bits.last 22371784e68SYinan Xu val (read_resp_valid, read_resp_id) = readResponse(!has_read_resp || read_resp_last) 22471784e68SYinan Xu has_read_resp := (read_resp_valid && !read_resp_last) || pending_read_resp_valid 22571784e68SYinan Xu val rdata_cnt = Counter(outer.burstLen) 226*9f659d72SKamimiao val read_resp_addr = addressMem(r_resp.bits.id) + rdata_cnt.value 227*9f659d72SKamimiao val read_resp_len = arlenMem(r_resp.bits.id) 228*9f659d72SKamimiao r_resp.valid := read_resp_valid || pending_read_resp_valid 229*9f659d72SKamimiao r_resp.bits.id := Mux(pending_read_resp_valid, pending_read_resp_id, read_resp_id) 230*9f659d72SKamimiao // We cannot get the read data this cycle because the RAM helper has one-cycle latency. 231*9f659d72SKamimiao r_resp.bits.data := DontCare 232*9f659d72SKamimiao r_resp.bits.resp := AXI4Parameters.RESP_OKAY 233*9f659d72SKamimiao r_resp.bits.last := (rdata_cnt.value === read_resp_len) 23471784e68SYinan Xu 23571784e68SYinan Xu when (!pending_read_resp_valid && read_resp_valid && !read_resp_last) { 23671784e68SYinan Xu pending_read_resp_valid := true.B 23771784e68SYinan Xu pending_read_resp_id := read_resp_id 23871784e68SYinan Xu }.elsewhen (pending_read_resp_valid && !read_resp_valid && read_resp_last) { 23971784e68SYinan Xu pending_read_resp_valid := false.B 24071784e68SYinan Xu } 24171784e68SYinan Xu when (read_resp_last) { 24271784e68SYinan Xu rdata_cnt.reset() 243*9f659d72SKamimiao }.elsewhen (r_resp.fire) { 24471784e68SYinan Xu rdata_cnt.inc() 24571784e68SYinan Xu } 24671784e68SYinan Xu 247*9f659d72SKamimiao // `r_pipe`: the extra pipeline registers for the read response `in.r` 248*9f659d72SKamimiao prefix("r_pipe") { 249*9f659d72SKamimiao val valid = RegInit(false.B) 250*9f659d72SKamimiao when (r_resp.valid && in.r.ready) { 251*9f659d72SKamimiao valid := true.B 252*9f659d72SKamimiao }.elsewhen (in.r.ready) { 253*9f659d72SKamimiao valid := false.B 254*9f659d72SKamimiao } 255*9f659d72SKamimiao in.r.valid := valid 256*9f659d72SKamimiao in.r.bits := RegEnable(r_resp.bits, r_resp.valid && in.r.ready) 257*9f659d72SKamimiao r_resp.ready := !valid || in.r.ready 258*9f659d72SKamimiao 259*9f659d72SKamimiao // the data should be auto-hold 260*9f659d72SKamimiao in.r.bits.data := ramHelper.readAndHold(read_resp_addr, r_resp.fire).asUInt 261*9f659d72SKamimiao } 262*9f659d72SKamimiao 26371784e68SYinan Xu // write response 26471784e68SYinan Xu val pending_write_resp_valid = RegInit(false.B) 26571784e68SYinan Xu val pending_write_resp_id = Reg(UInt(in.b.bits.id.getWidth.W)) 26671784e68SYinan Xu val has_write_resp = Wire(Bool()) 26771784e68SYinan Xu val (write_resp_valid, write_resp_id) = writeResponse(!has_write_resp || in.b.fire) 26804ac809eSYinan Xu has_write_resp := write_resp_valid || pending_write_resp_valid 26971784e68SYinan Xu in.b.valid := write_resp_valid || pending_write_resp_valid 27071784e68SYinan Xu in.b.bits.id := Mux(pending_write_resp_valid, pending_write_resp_id, write_resp_id) 27171784e68SYinan Xu in.b.bits.resp := AXI4Parameters.RESP_OKAY 27271784e68SYinan Xu 27371784e68SYinan Xu when (!pending_write_resp_valid && write_resp_valid && !in.b.ready) { 27471784e68SYinan Xu pending_write_resp_valid := true.B 27504ac809eSYinan Xu pending_write_resp_id := write_resp_id 27671784e68SYinan Xu }.elsewhen (pending_write_resp_valid && !write_resp_valid && in.b.ready) { 27771784e68SYinan Xu pending_write_resp_valid := false.B 27871784e68SYinan Xu } 27971784e68SYinan Xu} 28071784e68SYinan Xu 28171784e68SYinan Xuclass AXI4Memory 28271784e68SYinan Xu( 28371784e68SYinan Xu val address: Seq[AddressSet], 28471784e68SYinan Xu val memByte: Long, 28571784e68SYinan Xu val useBlackBox: Boolean = false, 28671784e68SYinan Xu val executable: Boolean = true, 28771784e68SYinan Xu val beatBytes: Int, 28871784e68SYinan Xu val burstLen: Int, 28971784e68SYinan Xu)(implicit p: Parameters) 29071784e68SYinan Xu extends AXI4SlaveModule(address, executable, beatBytes, burstLen) 29171784e68SYinan Xu{ 29271784e68SYinan Xu override lazy val module = new AXI4MemoryImp(this) 29371784e68SYinan Xu} 29471784e68SYinan Xu 29571784e68SYinan Xuclass AXI4MemoryWrapper ( 29671784e68SYinan Xu slave: AXI4SlaveNode, 29771784e68SYinan Xu memByte: Long, 29871784e68SYinan Xu useBlackBox: Boolean = false 29971784e68SYinan Xu)(implicit p: Parameters) extends AXI4MemorySlave(slave, memByte, useBlackBox) { 30071784e68SYinan Xu val ram = LazyModule(new AXI4Memory( 30171784e68SYinan Xu slaveParam.address, 30271784e68SYinan Xu memByte, 30371784e68SYinan Xu useBlackBox, 30471784e68SYinan Xu slaveParam.executable, 30571784e68SYinan Xu portParam.beatBytes, 30671784e68SYinan Xu burstLen 30771784e68SYinan Xu )) 30871784e68SYinan Xu ram.node := master 30971784e68SYinan Xu} 31071784e68SYinan Xu 31171784e68SYinan Xuabstract class AXI4MemorySlave ( 31271784e68SYinan Xu slave: AXI4SlaveNode, 31371784e68SYinan Xu memByte: Long, 31471784e68SYinan Xu useBlackBox: Boolean = false 31571784e68SYinan Xu)(implicit p: Parameters) extends LazyModule { 31671784e68SYinan Xu val master = AXI4MasterNode(List(slave.in.head._2.master)) 31771784e68SYinan Xu 31871784e68SYinan Xu val portParam = slave.portParams.head 31971784e68SYinan Xu val slaveParam = portParam.slaves.head 32071784e68SYinan Xu val burstLen = portParam.maxTransfer / portParam.beatBytes 32171784e68SYinan Xu 32271784e68SYinan Xu val io_axi4 = InModuleBody{ master.makeIOs() } 32371784e68SYinan Xu 32471784e68SYinan Xu lazy val module = new LazyModuleImp(this) { } 32571784e68SYinan Xu} 32671784e68SYinan Xu 32771784e68SYinan Xuobject AXI4MemorySlave { 32871784e68SYinan Xu def apply( 32971784e68SYinan Xu slave: AXI4SlaveNode, 33071784e68SYinan Xu memByte: Long, 33171784e68SYinan Xu useBlackBox: Boolean = false, 33271784e68SYinan Xu dynamicLatency: Boolean = false 33371784e68SYinan Xu )(implicit p: Parameters): AXI4MemorySlave = { 33471784e68SYinan Xu val memory = if (dynamicLatency) { 33571784e68SYinan Xu LazyModule(new AXI4MemoryWrapper(slave, memByte, useBlackBox)) 33671784e68SYinan Xu } else { 33771784e68SYinan Xu LazyModule(new AXI4RAMWrapper(slave, memByte, useBlackBox)) 33871784e68SYinan Xu } 33971784e68SYinan Xu memory 34071784e68SYinan Xu } 34171784e68SYinan Xu} 342