Merge pull request #1091 from freechipsproject/atomic-automata-errors
tilelink: AtomicAutomata should OR the Get error with the Put error
This commit is contained in:
commit
1f5fb5d643
@ -273,12 +273,13 @@ class ICacheModule(outer: ICache) extends LazyModuleImp(outer)
|
||||
val s1_scratchpad_hit = Mux(s1_slaveValid, lineInScratchpad(scratchpadLine(s1s3_slaveAddr)), addrInScratchpad(io.s1_paddr))
|
||||
val s2_scratchpad_hit = RegEnable(s1_scratchpad_hit, s1_clk_en)
|
||||
io.errors.correctable.foreach { c =>
|
||||
c.valid := s2_valid && Mux(s2_scratchpad_hit, s2_data_decoded.correctable, s2_disparity)
|
||||
c.bits := 0.U
|
||||
c.valid := ((s2_valid || s2_slaveValid) && (s2_scratchpad_hit && s2_data_decoded.correctable)) || (s2_valid && !s2_scratchpad_hit && s2_disparity)
|
||||
c.bits := Mux(s2_scratchpad_hit, scratchpadBase.get + s2_scratchpad_word_addr, 0.U)
|
||||
}
|
||||
io.errors.uncorrectable.foreach { u =>
|
||||
u.valid := s2_valid && s2_scratchpad_hit && s2_data_decoded.uncorrectable
|
||||
u.bits := scratchpadBase.get + s2_scratchpad_word_addr
|
||||
u.valid := (s2_valid || s2_slaveValid) && (s2_scratchpad_hit && s2_data_decoded.uncorrectable)
|
||||
// the Mux is not necessary, but saves HW in BusErrorUnit because it matches c.bits above
|
||||
u.bits := Mux(s2_scratchpad_hit, scratchpadBase.get + s2_scratchpad_word_addr, 0.U)
|
||||
}
|
||||
|
||||
tl_in.map { tl =>
|
||||
@ -312,6 +313,7 @@ class ICacheModule(outer: ICache) extends LazyModuleImp(outer)
|
||||
}
|
||||
|
||||
respValid := s2_slaveValid || (respValid && !tl.d.ready)
|
||||
val respError = RegEnable(s2_scratchpad_hit && s2_data_decoded.uncorrectable, s2_slaveValid)
|
||||
when (s2_slaveValid) {
|
||||
when (edge_in.get.hasData(s1_a) || s2_data_decoded.correctable) { s3_slaveValid := true }
|
||||
def byteEn(i: Int) = !(edge_in.get.hasData(s1_a) && s1_a.mask(i))
|
||||
@ -323,6 +325,7 @@ class ICacheModule(outer: ICache) extends LazyModuleImp(outer)
|
||||
edge_in.get.AccessAck(s1_a),
|
||||
edge_in.get.AccessAck(s1_a, UInt(0)))
|
||||
tl.d.bits.data := s1s3_slaveData
|
||||
tl.d.bits.error := respError
|
||||
|
||||
// Tie off unused channels
|
||||
tl.b.valid := false
|
||||
|
@ -188,6 +188,7 @@ class TLAtomicAutomata(logical: Boolean = true, arithmetic: Boolean = true, conc
|
||||
val d_cam_sel_raw = cam_a.map(_.bits.source === in.d.bits.source)
|
||||
val d_cam_sel_match = (d_cam_sel_raw zip cam_dmatch) map { case (a,b) => a&&b }
|
||||
val d_cam_data = Mux1H(d_cam_sel_match, cam_d.map(_.data))
|
||||
val d_cam_error = Mux1H(d_cam_sel_match, cam_d.map(_.error))
|
||||
val d_cam_sel_bypass = if (edgeOut.manager.minLatency > 0) Bool(false) else
|
||||
out.d.bits.source === in.a.bits.source && in.a.valid && !a_isSupported
|
||||
val d_cam_sel = (a_cam_sel_free zip d_cam_sel_match) map { case (a,d) => Mux(d_cam_sel_bypass, a, d) }
|
||||
@ -199,6 +200,7 @@ class TLAtomicAutomata(logical: Boolean = true, arithmetic: Boolean = true, conc
|
||||
(d_cam_sel zip cam_d) foreach { case (en, r) =>
|
||||
when (en && d_ackd) {
|
||||
r.data := out.d.bits.data
|
||||
r.error := out.d.bits.error
|
||||
}
|
||||
}
|
||||
(d_cam_sel zip cam_s) foreach { case (en, r) =>
|
||||
@ -219,6 +221,7 @@ class TLAtomicAutomata(logical: Boolean = true, arithmetic: Boolean = true, conc
|
||||
when (d_replace) { // minimal muxes
|
||||
in.d.bits.opcode := TLMessages.AccessAckData
|
||||
in.d.bits.data := d_cam_data
|
||||
in.d.bits.error := d_cam_error || out.d.bits.error
|
||||
}
|
||||
} else {
|
||||
out.a.valid := in.a.valid
|
||||
@ -270,25 +273,36 @@ object TLAtomicAutomata
|
||||
val lut = UInt(width = 4)
|
||||
}
|
||||
class CAM_D(params: CAMParams) extends GenericParameterizedBundle(params) {
|
||||
val data = UInt(width = params.a.dataBits)
|
||||
val data = UInt(width = params.a.dataBits)
|
||||
val error = Bool()
|
||||
}
|
||||
}
|
||||
|
||||
/** Synthesizeable unit tests */
|
||||
import freechips.rocketchip.unittest._
|
||||
|
||||
//TODO ensure handler will pass through operations to clients that can handle them themselves
|
||||
|
||||
class TLRAMAtomicAutomata(txns: Int)(implicit p: Parameters) extends LazyModule {
|
||||
val fuzz = LazyModule(new TLFuzzer(txns))
|
||||
val model = LazyModule(new TLRAMModel("AtomicAutomata"))
|
||||
val ram = LazyModule(new TLRAM(AddressSet(0x0, 0x3ff)))
|
||||
|
||||
// Confirm that the AtomicAutomata combines read + write errors
|
||||
import TLMessages._
|
||||
val test = new RequestPattern({a: TLBundleA =>
|
||||
val doesA = a.opcode === ArithmeticData || a.opcode === LogicalData
|
||||
val doesR = a.opcode === Get || doesA
|
||||
val doesW = a.opcode === PutFullData || a.opcode === PutPartialData || doesA
|
||||
(doesR && RequestPattern.overlaps(Seq(AddressSet(0x08, ~0x08)))(a)) ||
|
||||
(doesW && RequestPattern.overlaps(Seq(AddressSet(0x10, ~0x10)))(a))
|
||||
})
|
||||
|
||||
(ram.node
|
||||
:= TLErrorEvaluator(test)
|
||||
:= TLFragmenter(4, 256)
|
||||
:= TLDelayer(0.1)
|
||||
:= TLAtomicAutomata()
|
||||
:= TLDelayer(0.1)
|
||||
:= TLErrorEvaluator(test, testOn=true, testOff=true)
|
||||
:= model.node
|
||||
:= fuzz.node)
|
||||
|
||||
|
@ -7,34 +7,50 @@ import freechips.rocketchip.config.Parameters
|
||||
import freechips.rocketchip.diplomacy._
|
||||
import freechips.rocketchip.util._
|
||||
|
||||
// Check if a request satisfies some interesting property
|
||||
class RequestPattern(test: TLBundleA => Bool)
|
||||
{
|
||||
def apply(a: TLBundleA) = test(a)
|
||||
}
|
||||
|
||||
object RequestPattern
|
||||
{
|
||||
// Does the request address range overlap a particular pattern of addresses?
|
||||
def overlaps(pattern: Seq[AddressSet])(a: TLBundleA) = {
|
||||
val amask = UIntToOH1(a.size, a.params.addressBits)
|
||||
val abase = a.address
|
||||
pattern.map { case p =>
|
||||
val pbase = UInt(p.base)
|
||||
val pmask = UInt(p.mask & ((BigInt(1) << a.params.addressBits) - 1))
|
||||
(amask | pmask | ~(abase ^ pbase)).andR
|
||||
}.reduce(_ || _)
|
||||
}
|
||||
|
||||
implicit def apply(pattern: Seq[AddressSet]): RequestPattern = new RequestPattern(overlaps(pattern) _)
|
||||
}
|
||||
|
||||
// An ErrorEvaluator is used for test harnesses.
|
||||
// It creates errors in transactions which overlap an address in pattern.
|
||||
// It creates errors in transactions which match the provided test function.
|
||||
// If testOn is true, it will assert fail if these transactions do not already error.
|
||||
// If testOff is true, it will assert fail if these transactions otherwise error.
|
||||
// This helps when building unit tests to confirm that errors are propagated correctly.
|
||||
class TLErrorEvaluator(pattern: Seq[AddressSet], testOn: Boolean, testOff: Boolean)(implicit p: Parameters) extends LazyModule
|
||||
class TLErrorEvaluator(test: RequestPattern, testOn: Boolean, testOff: Boolean)(implicit p: Parameters) extends LazyModule
|
||||
{
|
||||
val node = TLAdapterNode()
|
||||
lazy val module = new LazyModuleImp(this) {
|
||||
(node.in zip node.out) foreach { case ((in, edgeIn), (out, edgeOut)) =>
|
||||
out <> in
|
||||
|
||||
// Does the request overlap the pattern ?
|
||||
val abase = in.a.bits.address
|
||||
val amask = UIntToOH1(in.a.bits.size, log2Up(edgeIn.maxTransfer))
|
||||
val overlaps = pattern.map { case a =>
|
||||
val pbase = UInt(a.base)
|
||||
val pmask = UInt(a.mask & ((BigInt(1) << edgeIn.bundle.addressBits) - 1))
|
||||
(amask | pmask | ~(abase ^ pbase)).andR
|
||||
}.reduce(_ || _)
|
||||
// Should the request receive an error ?
|
||||
val inject_map = Mem(edgeIn.client.endSourceId, Bool())
|
||||
val inject_now = test(in.a.bits)
|
||||
|
||||
val (d_first, d_last, _) = edgeOut.firstlast(out.d)
|
||||
|
||||
val inject = Mem(edgeIn.client.endSourceId, Bool())
|
||||
when (in.a.fire()) { inject.write(in.a.bits.source, overlaps) }
|
||||
when (in.a.fire()) { inject_map.write(in.a.bits.source, inject_now) }
|
||||
|
||||
val bypass = in.a.fire() && in.a.bits.source === in.d.bits.source
|
||||
val d_inject = Mux(bypass, overlaps, inject.read(in.d.bits.source)) holdUnless d_first
|
||||
val d_inject = Mux(bypass, inject_now, inject_map.read(in.d.bits.source)) holdUnless d_first
|
||||
in.d.bits.error := out.d.bits.error || (d_last && d_inject)
|
||||
|
||||
assert (Bool(!testOn) || !out.d.fire() || !d_last || !d_inject || out.d.bits.error, "Error flag was not set!")
|
||||
@ -45,6 +61,6 @@ class TLErrorEvaluator(pattern: Seq[AddressSet], testOn: Boolean, testOff: Boole
|
||||
|
||||
object TLErrorEvaluator
|
||||
{
|
||||
def apply(pattern: Seq[AddressSet], testOn: Boolean = false, testOff: Boolean = false)(implicit p: Parameters): TLNode =
|
||||
LazyModule(new TLErrorEvaluator(pattern, testOn, testOff)).node
|
||||
def apply(test: RequestPattern, testOn: Boolean = false, testOff: Boolean = false)(implicit p: Parameters): TLNode =
|
||||
LazyModule(new TLErrorEvaluator(test, testOn, testOff)).node
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user