Fix address & data handling in memtrace driver and logger
* TileLink doesn't alter the `address` field from what we originally used in the Get/Put call. * Same goes for the `data` field. * The only thing TL generates by itself is `mask`. This means we have to align data to the beatBytes boundary ourselves when Putting, and also taking the right sublanes using the mask when Getting.
This commit is contained in:
@@ -649,7 +649,7 @@ class MemTraceDriverImp(outer: MemTraceDriver, numLanes: Int, traceFile: String)
|
|||||||
// In default setting, all mem-req for program data must be within
|
// In default setting, all mem-req for program data must be within
|
||||||
// 0X80000000 -> 0X90000000
|
// 0X80000000 -> 0X90000000
|
||||||
def hashToValidPhyAddr(addr: UInt): UInt = {
|
def hashToValidPhyAddr(addr: UInt): UInt = {
|
||||||
Cat(8.U(4.W), addr(27, 3), 0.U(3.W))
|
Cat(8.U(4.W), addr(27, 0))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Generate TL requests according to the trace line.
|
// Generate TL requests according to the trace line.
|
||||||
@@ -660,7 +660,8 @@ class MemTraceDriverImp(outer: MemTraceDriver, numLanes: Int, traceFile: String)
|
|||||||
fromSource = sourceIdCounter,
|
fromSource = sourceIdCounter,
|
||||||
toAddress = hashToValidPhyAddr(req.address),
|
toAddress = hashToValidPhyAddr(req.address),
|
||||||
lgSize = req.size, // trace line already holds log2(size)
|
lgSize = req.size, // trace line already holds log2(size)
|
||||||
data = req.data
|
// Need to construct data that is correctly aligned to beatBytes
|
||||||
|
data = (req.data << (8.U * (req.address % edge.manager.beatBytes.U)))
|
||||||
)
|
)
|
||||||
val (glegal, gbits) = edge.Get(
|
val (glegal, gbits) = edge.Get(
|
||||||
fromSource = sourceIdCounter,
|
fromSource = sourceIdCounter,
|
||||||
@@ -672,10 +673,13 @@ class MemTraceDriverImp(outer: MemTraceDriver, numLanes: Int, traceFile: String)
|
|||||||
|
|
||||||
when(tlOut.a.valid) {
|
when(tlOut.a.valid) {
|
||||||
printf(
|
printf(
|
||||||
"Get(): addr=%x, size=%x, mask=%x\n",
|
"MemTraceDriver: TL addr=%x, size=%d, mask=%x, store=%d, tlData=%x, reqData=%x\n",
|
||||||
tlOut.a.bits.address,
|
tlOut.a.bits.address,
|
||||||
tlOut.a.bits.size,
|
tlOut.a.bits.size,
|
||||||
tlOut.a.bits.mask
|
tlOut.a.bits.mask,
|
||||||
|
req.is_store,
|
||||||
|
tlOut.a.bits.data,
|
||||||
|
req.data
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -757,6 +761,12 @@ class MemTraceLogger(numLanes: Int = 4, filename: String = "vecadd.core1.thread4
|
|||||||
// )
|
// )
|
||||||
// })
|
// })
|
||||||
|
|
||||||
|
// Copied from freechips.rocketchip.trailingZeros which only supports Scala
|
||||||
|
// integers
|
||||||
|
def trailingZeros(x: UInt): UInt = {
|
||||||
|
Mux(x === 0.U, x.widthOption.get.U, Log2(x & -x))
|
||||||
|
}
|
||||||
|
|
||||||
lazy val module = new Impl
|
lazy val module = new Impl
|
||||||
class Impl extends LazyModuleImp(this) {
|
class Impl extends LazyModuleImp(this) {
|
||||||
val sim = Module(new SimMemTraceLogger(filename, numLanes))
|
val sim = Module(new SimMemTraceLogger(filename, numLanes))
|
||||||
@@ -776,21 +786,48 @@ class MemTraceLogger(numLanes: Int = 4, filename: String = "vecadd.core1.thread4
|
|||||||
tlIn.d <> tlOut.d
|
tlIn.d <> tlOut.d
|
||||||
|
|
||||||
// requests on TL A channel
|
// requests on TL A channel
|
||||||
|
//
|
||||||
req.valid := tlIn.a.valid
|
req.valid := tlIn.a.valid
|
||||||
req.address := tlIn.a.bits.address
|
|
||||||
req.data := tlIn.a.bits.data
|
|
||||||
req.is_store := false.B
|
|
||||||
when(tlIn.a.bits.opcode === 0.U) {
|
|
||||||
// 0: PutFullData, 1: PutPartialData but we don't support it
|
|
||||||
req.is_store := true.B
|
|
||||||
}.elsewhen(tlIn.a.bits.opcode === 4.U) {
|
|
||||||
// 4: Get
|
|
||||||
req.is_store := false.B
|
|
||||||
}.elsewhen(true.B) {
|
|
||||||
// that's all I know
|
|
||||||
assert(false.B, "unhandled TL opcode found in MemTraceLogger")
|
|
||||||
}
|
|
||||||
req.size := tlIn.a.bits.size
|
req.size := tlIn.a.bits.size
|
||||||
|
def tlOpcodeIsStore(opcode: UInt): Bool = {
|
||||||
|
// 0: PutFullData, 1: PutPartialData but we don't support it
|
||||||
|
// 4: Get
|
||||||
|
assert(opcode === 0.U || opcode === 4.U, "unhandled TL opcode found in MemTraceLogger")
|
||||||
|
tlIn.a.bits.opcode === 0.U
|
||||||
|
}
|
||||||
|
req.is_store := tlOpcodeIsStore(tlIn.a.bits.opcode)
|
||||||
|
// TL always carries the exact unaligned address that the client
|
||||||
|
// originally requested, so no postprocessing required
|
||||||
|
req.address := tlIn.a.bits.address
|
||||||
|
|
||||||
|
// TL data
|
||||||
|
//
|
||||||
|
// When tlIn.a.bits.size is smaller than the data bus width, need to
|
||||||
|
// figure out which byte lanes we actually accessed so that
|
||||||
|
// we can write that to the memory trace.
|
||||||
|
// See Section 4.5 Byte Lanes in spec 1.8.1
|
||||||
|
|
||||||
|
// This assert only holds true for PutFullData and not PutPartialData,
|
||||||
|
// where HIGH bits in the mask may not be contiguous.
|
||||||
|
assert(
|
||||||
|
PopCount(tlIn.a.bits.mask) === (1.U << tlIn.a.bits.size),
|
||||||
|
"mask HIGH bits do not match the TL size. This should have been handled by the TL generator logic"
|
||||||
|
)
|
||||||
|
val trailingZerosInMask = trailingZeros(tlIn.a.bits.mask)
|
||||||
|
val mask = ~((~0.U) << (trailingZerosInMask * 8.U))
|
||||||
|
req.data := mask & (tlIn.a.bits.data >> (trailingZerosInMask * 8.U))
|
||||||
|
|
||||||
|
when(req.valid) {
|
||||||
|
printf(
|
||||||
|
"MemTraceLogger: TL addr=%x, size=%d, mask=%x, store=%d, tlData=%x, reqData=%x\n",
|
||||||
|
tlIn.a.bits.address,
|
||||||
|
tlIn.a.bits.size,
|
||||||
|
tlIn.a.bits.mask,
|
||||||
|
req.is_store,
|
||||||
|
tlIn.a.bits.data,
|
||||||
|
req.data
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
// responses on TL D channel
|
// responses on TL D channel
|
||||||
// TODO
|
// TODO
|
||||||
|
|||||||
Reference in New Issue
Block a user