-
Notifications
You must be signed in to change notification settings - Fork 23
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[t1rocket] implement t1rocket Testbench
- Loading branch information
Showing
3 changed files
with
596 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,205 @@ | ||
// SPDX-License-Identifier: Apache-2.0 | ||
// SPDX-FileCopyrightText: 2022-2024 Jiuyang Liu <[email protected]> | ||
|
||
package org.chipsalliance.t1.t1rocketemu.dpi | ||
|
||
// TODO: upstream to AMBA as VIP | ||
import chisel3._ | ||
import chisel3.util.circt.dpi.{RawClockedVoidFunctionCall, RawUnclockedNonVoidFunctionCall} | ||
import chisel3.util.{isPow2, log2Ceil} | ||
import org.chipsalliance.amba.axi4.bundle.{ARChannel, ARFlowControl, AWChannel, AWFlowControl, AXI4BundleParameter, AXI4ROIrrevocableVerilog, AXI4RWIrrevocableVerilog, AXI4WOIrrevocableVerilog, BChannel, BFlowControl, RChannel, RFlowControl, WChannel, WFlowControl} | ||
|
||
case class AXI4SlaveAgentParameter(name: String, axiParameter: AXI4BundleParameter, outstanding: Int, readPayloadSize: Int, writePayloadSize: Int) | ||
|
||
class AXI4SlaveAgentInterface(parameter: AXI4SlaveAgentParameter) extends Bundle { | ||
val clock: Clock = Input(Clock()) | ||
val reset: Reset = Input(Reset()) | ||
val channelId: UInt = Input(Const(UInt(64.W))) | ||
// don't issue read DPI | ||
val gateRead: Bool = Input(Bool()) | ||
// don't issue write DPI | ||
val gateWrite: Bool = Input(Bool()) | ||
val channel = Flipped( | ||
org.chipsalliance.amba.axi4.bundle.verilog.irrevocable(parameter.axiParameter) | ||
) | ||
} | ||
|
||
class WritePayload(length: Int, dataWidth: Int) extends Bundle { | ||
val data = Vec(length, UInt(dataWidth.W)) | ||
// For dataWidth <= 8, align strb to u8 for a simple C-API | ||
val strb = Vec(length, UInt(math.max(8, dataWidth / 8).W)) | ||
} | ||
|
||
class ReadPayload(length: Int,dataWidth: Int) extends Bundle { | ||
val data = Vec(length, UInt(dataWidth.W)) | ||
} | ||
|
||
// consume transaction from DPI, drive RTL signal | ||
class AXI4SlaveAgent(parameter: AXI4SlaveAgentParameter) | ||
extends FixedIORawModule[AXI4SlaveAgentInterface](new AXI4SlaveAgentInterface(parameter)) { | ||
dontTouch(io) | ||
io.channel match { | ||
case channel: AXI4RWIrrevocableVerilog => | ||
new WriteManager(channel) | ||
new ReadManager(channel) | ||
case channel: AXI4ROIrrevocableVerilog => | ||
new ReadManager(channel) | ||
case channel: AXI4WOIrrevocableVerilog => | ||
new WriteManager(channel) | ||
} | ||
|
||
private class WriteManager( | ||
channel: AWChannel with AWFlowControl with WChannel with WFlowControl with BChannel with BFlowControl) { | ||
withClockAndReset(io.clock, io.reset) { | ||
/** There is an aw in the register. */ | ||
val awIssued = RegInit(false.B) | ||
/** There is a w in the register. */ | ||
val last = RegInit(false.B) | ||
|
||
/** memory to store the write payload | ||
* @todo limit the payload size based on the RTL configuration. | ||
*/ | ||
val writePayload = RegInit(0.U.asTypeOf(new WritePayload(parameter.writePayloadSize, parameter.axiParameter.dataWidth))) | ||
/** AWID, latch at AW fire, used at B fire. */ | ||
val awid = RegInit(0.U.asTypeOf(chiselTypeOf(channel.AWID))) | ||
val awaddr = RegInit(0.U.asTypeOf(chiselTypeOf(channel.AWADDR))) | ||
val awlen = RegInit(0.U.asTypeOf(chiselTypeOf(channel.AWLEN))) | ||
val awsize = RegInit(0.U.asTypeOf(chiselTypeOf(channel.AWSIZE))) | ||
val awburst = RegInit(0.U.asTypeOf(chiselTypeOf(channel.AWBURST))) | ||
val awlock = RegInit(0.U.asTypeOf(chiselTypeOf(channel.AWLOCK))) | ||
val awcache = RegInit(0.U.asTypeOf(chiselTypeOf(channel.AWCACHE))) | ||
val awprot = RegInit(0.U.asTypeOf(chiselTypeOf(channel.AWPROT))) | ||
val awqos = RegInit(0.U.asTypeOf(chiselTypeOf(channel.AWQOS))) | ||
val awregion = RegInit(0.U.asTypeOf(chiselTypeOf(channel.AWREGION))) | ||
val awuser = RegInit(0.U.asTypeOf(chiselTypeOf(channel.AWUSER))) | ||
|
||
/** index the payload, used to write [[writePayload]] */ | ||
val writeIdx = RegInit(0.U.asTypeOf(UInt(8.W))) | ||
val bFire = channel.BREADY && channel.BVALID | ||
val awFire = channel.AWREADY && channel.AWVALID | ||
val wLastFire = channel.WVALID && channel.WREADY && channel.WLAST | ||
val awExist = channel.AWVALID || awIssued | ||
val wExist = channel.WVALID && channel.WLAST || last | ||
|
||
// AW | ||
channel.AWREADY := !awIssued || (wExist && channel.BREADY) | ||
when(channel.AWREADY && channel.AWVALID) { | ||
awid := channel.AWID | ||
awaddr := channel.AWADDR | ||
awlen := channel.AWLEN | ||
awsize := channel.AWSIZE | ||
awburst := channel.AWBURST | ||
awlock := channel.AWLOCK | ||
awcache := channel.AWCACHE | ||
awprot := channel.AWPROT | ||
awqos := channel.AWQOS | ||
awregion := channel.AWREGION | ||
awuser := channel.AWUSER | ||
} | ||
when(awFire ^ bFire) { | ||
awIssued := awFire | ||
} | ||
|
||
// W | ||
val writePayloadUpdate = WireDefault(writePayload) | ||
channel.WREADY := !last || (awExist && channel.BREADY) | ||
when(channel.WVALID && channel.WREADY) { | ||
writePayload.data(writeIdx) := channel.WDATA | ||
writePayloadUpdate.data(writeIdx) := channel.WDATA | ||
writePayload.strb(writeIdx) := channel.WSTRB.pad(writePayload.strb.getWidth) | ||
writePayloadUpdate.strb(writeIdx) := channel.WSTRB.pad(writePayload.strb.getWidth) | ||
writeIdx := writeIdx + 1.U | ||
when(channel.WLAST) { | ||
writeIdx := 0.U | ||
} | ||
} | ||
when(wLastFire ^ bFire) { | ||
last := wLastFire | ||
} | ||
|
||
// B | ||
channel.BVALID := awExist && wExist | ||
channel.BID := Mux(awIssued, awid, channel.AWID) | ||
channel.BRESP := 0.U(2.W) // OK | ||
channel.BUSER := Mux(awIssued, awuser, channel.AWUSER) | ||
when(channel.BVALID && channel.BREADY) { | ||
RawClockedVoidFunctionCall(s"axi_write_${parameter.name}")( | ||
io.clock, | ||
when.cond && !io.gateWrite, | ||
io.channelId, | ||
// handle AW and W at same beat. | ||
Mux(awIssued, awid.asTypeOf(UInt(64.W)), channel.AWID), | ||
Mux(awIssued, awaddr.asTypeOf(UInt(64.W)), channel.AWADDR), | ||
Mux(awIssued, awlen.asTypeOf(UInt(64.W)), channel.AWLEN), | ||
Mux(awIssued, awsize.asTypeOf(UInt(64.W)), channel.AWSIZE), | ||
Mux(awIssued, awburst.asTypeOf(UInt(64.W)), channel.AWBURST), | ||
Mux(awIssued, awlock.asTypeOf(UInt(64.W)), channel.AWLOCK), | ||
Mux(awIssued, awcache.asTypeOf(UInt(64.W)), channel.AWCACHE), | ||
Mux(awIssued, awprot.asTypeOf(UInt(64.W)), channel.AWPROT), | ||
Mux(awIssued, awqos.asTypeOf(UInt(64.W)), channel.AWQOS), | ||
Mux(awIssued, awregion.asTypeOf(UInt(64.W)), channel.AWREGION), | ||
writePayloadUpdate | ||
) | ||
} | ||
} | ||
} | ||
|
||
private class ReadManager(channel: ARChannel with ARFlowControl with RChannel with RFlowControl) { | ||
withClockAndReset(io.clock, io.reset) { | ||
class CAMValue extends Bundle { | ||
val arid = UInt(16.W) | ||
val arlen = UInt(8.W) | ||
val readPayload = new ReadPayload(parameter.readPayloadSize, parameter.axiParameter.dataWidth) | ||
val readPayloadIndex = UInt(8.W) | ||
val valid = Bool() | ||
val user: UInt = UInt(channel.ARUSER.getWidth.W) | ||
} | ||
/** CAM to maintain order of read requests. This is maintained as FIFO. */ | ||
val cam: Vec[CAMValue] = RegInit(0.U.asTypeOf(Vec(parameter.outstanding, new CAMValue))) | ||
require(isPow2(parameter.outstanding), "Need to handle pointers") | ||
val arPtr = RegInit(0.U.asTypeOf(UInt(log2Ceil(parameter.outstanding).W))) | ||
val rPtr = RegInit(0.U.asTypeOf(UInt(log2Ceil(parameter.outstanding).W))) | ||
|
||
// AR | ||
channel.ARREADY := !cam(arPtr).valid | ||
when(channel.ARREADY && channel.ARVALID) { | ||
cam(arPtr).arid := channel.ARID | ||
cam(arPtr).arlen := channel.ARLEN | ||
cam(arPtr).user := channel.ARUSER | ||
cam(arPtr).readPayload := RawUnclockedNonVoidFunctionCall(s"axi_read_${parameter.name}", new ReadPayload(parameter.readPayloadSize, parameter.axiParameter.dataWidth))( | ||
when.cond && !io.gateRead, | ||
io.channelId, | ||
channel.ARID.asTypeOf(UInt(64.W)), | ||
channel.ARADDR.asTypeOf(UInt(64.W)), | ||
channel.ARLEN.asTypeOf(UInt(64.W)), | ||
channel.ARSIZE.asTypeOf(UInt(64.W)), | ||
channel.ARBURST.asTypeOf(UInt(64.W)), | ||
channel.ARLOCK.asTypeOf(UInt(64.W)), | ||
channel.ARCACHE.asTypeOf(UInt(64.W)), | ||
channel.ARPROT.asTypeOf(UInt(64.W)), | ||
channel.ARQOS.asTypeOf(UInt(64.W)), | ||
channel.ARREGION.asTypeOf(UInt(64.W)) | ||
) | ||
cam(arPtr).readPayloadIndex := 0.U | ||
cam(arPtr).valid := true.B | ||
arPtr := arPtr + 1.U | ||
} | ||
|
||
// R | ||
channel.RVALID := cam(rPtr).valid | ||
channel.RID := cam(rPtr).arid | ||
channel.RDATA := cam(rPtr).readPayload.data(cam(rPtr).readPayloadIndex) | ||
channel.RRESP := 0.U // OK | ||
channel.RLAST := (cam(rPtr).arlen === cam(rPtr).readPayloadIndex) && cam(rPtr).valid | ||
channel.RUSER := cam(rPtr).user | ||
when(channel.RREADY && channel.RVALID) { | ||
// increase index | ||
cam(rPtr).readPayloadIndex := cam(rPtr).readPayloadIndex + 1.U | ||
when(channel.RLAST) { | ||
cam(rPtr).valid := false.B | ||
rPtr := rPtr + 1.U | ||
} | ||
} | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,74 @@ | ||
// SPDX-License-Identifier: Apache-2.0 | ||
// SPDX-FileCopyrightText: 2012-2014 The Regents of the University of California | ||
// SPDX-FileCopyrightText: 2016-2017 SiFive, Inc | ||
// SPDX-FileCopyrightText: 2024 Jiuyang Liu <[email protected]> | ||
package org.chipsalliance.t1.t1rocketemu | ||
|
||
import chisel3._ | ||
import chisel3.experimental.hierarchy.instantiable | ||
import chisel3.experimental.{SerializableModule, SerializableModuleParameter} | ||
import chisel3.util._ | ||
import org.chipsalliance.rocketv.{FPUHelper, FType} | ||
|
||
object FPToIEEEParameter { | ||
implicit def rwP: upickle.default.ReadWriter[FPToIEEEParameter] = upickle.default.macroRW[FPToIEEEParameter] | ||
} | ||
|
||
class FPToIEEEInput(fLen: Int) extends Bundle { | ||
val typeTag = UInt(2.W) | ||
val data = UInt((fLen + 1).W) | ||
} | ||
|
||
case class FPToIEEEParameter( | ||
useAsyncReset: Boolean, | ||
xLen: Int, | ||
fLen: Int, | ||
minFLen: Int) | ||
extends SerializableModuleParameter | ||
class FPToIEEEInterface(parameter: FPToIEEEParameter) extends Bundle { | ||
val clock = Input(Clock()) | ||
val reset = Input(if (parameter.useAsyncReset) AsyncReset() else Bool()) | ||
val in = Flipped(Valid(new FPToIEEEInput(parameter.fLen))) | ||
val out = Valid(UInt(parameter.fLen.W)) | ||
} | ||
|
||
@instantiable | ||
class FPToIEEE(val parameter: FPToIEEEParameter) | ||
extends FixedIORawModule(new FPToIEEEInterface(parameter)) | ||
with SerializableModule[FPToIEEEParameter] | ||
with ImplicitClock | ||
with ImplicitReset { | ||
override protected def implicitClock: Clock = io.clock | ||
override protected def implicitReset: Reset = io.reset | ||
|
||
val minFLen: Int = parameter.minFLen | ||
val fLen: Int = parameter.fLen | ||
val xLen: Int = parameter.xLen | ||
val helper = new FPUHelper(minFLen, fLen, xLen) | ||
val maxExpWidth = helper.maxExpWidth | ||
val maxSigWidth = helper.maxSigWidth | ||
val floatTypes = helper.floatTypes | ||
val maxType = helper.maxType | ||
val minXLen = helper.minXLen | ||
val nIntTypes = helper.nIntTypes | ||
def ieee(x: UInt, t: FType = maxType) = helper.ieee(x, t) | ||
|
||
val in = io.in.bits | ||
val valid = io.in.valid | ||
|
||
def sextTo(x: UInt, n: Int): UInt = { | ||
require(x.getWidth <= n) | ||
if (x.getWidth == n) x | ||
else Cat(Fill(n - x.getWidth, x(x.getWidth - 1)), x) | ||
} | ||
|
||
val store = VecInit( | ||
floatTypes.map(t => | ||
if (t == FType.H) Fill(maxType.ieeeWidth / minXLen, sextTo(ieee(in.data)(15, 0), minXLen)) | ||
else Fill(maxType.ieeeWidth / t.ieeeWidth, ieee(in.data)(t.ieeeWidth - 1, 0)) | ||
) | ||
)(in.typeTag) | ||
|
||
io.out.valid := valid | ||
io.out.bits := store | ||
} |
Oops, something went wrong.