diff --git a/src/main/scala/amba/ahb/Test.scala b/src/main/scala/amba/ahb/Test.scala index a959f54c..f50a1d09 100644 --- a/src/main/scala/amba/ahb/Test.scala +++ b/src/main/scala/amba/ahb/Test.scala @@ -49,7 +49,7 @@ class AHBFuzzMaster(aFlow: Boolean, txns: Int)(implicit p: Parameters) extends L { val node = AHBIdentityNode() val fuzz = LazyModule(new TLFuzzer(txns, overrideAddress = Some(fuzzAddr))) - val model = LazyModule(new TLRAMModel("AHBFuzzMaster")) + val model = LazyModule(new TLRAMModel("AHBFuzzMaster", ignoreErrorData=true)) (node := TLToAHB(aFlow) diff --git a/src/main/scala/amba/ahb/ToTL.scala b/src/main/scala/amba/ahb/ToTL.scala index ec76044c..4b0484ba 100644 --- a/src/main/scala/amba/ahb/ToTL.scala +++ b/src/main/scala/amba/ahb/ToTL.scala @@ -106,7 +106,14 @@ class AHBToTL()(implicit p: Parameters) extends LazyModule out.a.bits.mask := MaskGen(d_addr, d_size, beatBytes) out.d.ready := d_recv // backpressure AccessAckData arriving faster than AHB beats - in.hrdata := out.d.bits.data + + // NOTE: on error, we present the read result on the hreadyout LOW cycle + // This means that if you latch hrdata from an error, the result is garbage. + // To fix this would require a bus-wide register, and the AHB spec says this: + // "A slave only has to provide valid data when a transfer completes with an OKAY + // response. ERROR responses do not require valid read data." + // Therefore, we choose to accept this slight TL-AHB infidelity. + in.hrdata := out.d.bits.data // In a perfect world, we'd use these signals val hresp = d_error || (out.d.valid && out.d.bits.error) diff --git a/src/main/scala/tilelink/RAMModel.scala b/src/main/scala/tilelink/RAMModel.scala index 21c5cf14..4ffbb2ef 100644 --- a/src/main/scala/tilelink/RAMModel.scala +++ b/src/main/scala/tilelink/RAMModel.scala @@ -22,7 +22,7 @@ import freechips.rocketchip.util._ // put, get, getAck, putAck => ok: detected by getAck (it sees busy>0) impossible for FIFO // If FIFO, the getAck should check data even if its validity was wiped -class TLRAMModel(log: String = "")(implicit p: Parameters) extends LazyModule +class TLRAMModel(log: String = "", ignoreErrorData: Boolean = false)(implicit p: Parameters) extends LazyModule { val node = TLAdapterNode() @@ -288,6 +288,8 @@ class TLRAMModel(log: String = "")(implicit p: Parameters) extends LazyModule printf(", undefined (concurrent incomplete puts #%d)\n", d_inc(i) - d_dec(i)) } .elsewhen (!d_fifo && !d_valid) { printf(", undefined (concurrent completed put)\n") + } .elsewhen (Bool(ignoreErrorData) && d.error) { + printf(", undefined (error result)\n") } .otherwise { printf("\n") when (shadow.value =/= got) { printf("EXPECTED: 0x%x\n", shadow.value) } @@ -303,8 +305,9 @@ class TLRAMModel(log: String = "")(implicit p: Parameters) extends LazyModule when ((Cat(race.reverse) & d_mask).orR) { d_no_race := Bool(false) } when (d_last) { val must_match = d_crc_valid && (d_fifo || (d_valid && d_no_race)) + val error = Bool(ignoreErrorData) && d.error printf(log + " crc = 0x%x %d\n", d_crc, must_match.asUInt) - when (must_match && d_crc =/= d_crc_check) { printf("EXPECTED: 0x%x\n", d_crc_check) } + when (!error && must_match && d_crc =/= d_crc_check) { printf("EXPECTED: 0x%x\n", d_crc_check) } assert (!must_match || d_crc === d_crc_check) } }