diff --git a/rocket/src/main/scala/ecc.scala b/rocket/src/main/scala/ecc.scala index cc1e00a6..179315d6 100644 --- a/rocket/src/main/scala/ecc.scala +++ b/rocket/src/main/scala/ecc.scala @@ -14,26 +14,38 @@ abstract class Decoding def error = correctable || uncorrectable } -abstract class Encoding +abstract class Code { def width(w0: Int): Int def encode(x: Bits): Bits def decode(x: Bits): Decoding } -class Parity extends Encoding +class IdentityCode extends Code +{ + def width(w0: Int) = w0 + def encode(x: Bits) = x + def decode(y: Bits) = new Decoding { + def uncorrected = y + def corrected = y + def correctable = Bool(false) + def uncorrectable = Bool(false) + } +} + +class ParityCode extends Code { def width(w0: Int) = w0+1 def encode(x: Bits) = Cat(x.xorR, x) def decode(y: Bits) = new Decoding { def uncorrected = y(y.getWidth-2,0) def corrected = uncorrected - def correctable = y.xorR - def uncorrectable = Bool(false) + def correctable = Bool(false) + def uncorrectable = y.xorR } } -class SEC extends Encoding +class SECCode extends Code { def width(k: Int) = { val m = log2Up(k) + 1 - !isPow2(k) @@ -75,30 +87,37 @@ class SEC extends Encoding private def mapping(i: Int) = i-1-log2Up(i) } -class SECDED extends Encoding +class SECDEDCode extends Code { - def width(k: Int) = new SEC().width(k)+1 - def encode(x: Bits) = new Parity().encode(new SEC().encode(x)) + private val sec = new SECCode + private val par = new ParityCode + + def width(k: Int) = sec.width(k)+1 + def encode(x: Bits) = par.encode(sec.encode(x)) def decode(x: Bits) = new Decoding { - val sec = new SEC().decode(x(x.getWidth-2,0)) - val par = new Parity().decode(x) - def uncorrected = sec.uncorrected - def corrected = sec.corrected - def correctable = par.correctable - def uncorrectable = !par.correctable && sec.correctable + val secdec = sec.decode(x(x.getWidth-2,0)) + val pardec = par.decode(x) + + def uncorrected = secdec.uncorrected + def corrected = secdec.corrected + def correctable = pardec.uncorrectable + def uncorrectable = !pardec.uncorrectable && secdec.correctable } } +object ErrGen +{ + // generate a 1-bit error with approximate probability 2^-f + def apply(width: Int, f: Int): Bits = { + require(width > 0 && f >= 0 && log2Up(width) + f <= 16) + UFixToOH(LFSR16()(log2Up(width)+f-1,0))(width-1,0) + } + def apply(x: Bits, f: Int): Bits = x ^ apply(x.getWidth, f) +} + class SECDEDTest extends Component { - def inject(x: Bits, n: UFix) = { - val r = LFSR16() - val r1 = UFixToOH(r(log2Up(x.getWidth)-1,0))(x.getWidth-1,0) - val r2 = UFixToOH(r(log2Up(x.getWidth)*2-1,log2Up(x.getWidth)))(x.getWidth-1,0) - x ^ Mux(n < UFix(1), UFix(0), r1) ^ Mux(n < UFix(2), UFix(0), r2) - } - - val code = new SECDED + val code = new SECDEDCode val k = 4 val n = code.width(k) @@ -115,7 +134,7 @@ class SECDEDTest extends Component val c = Counter(Bool(true), 1 << k) val numErrors = Counter(c._2, 3)._1 val e = code.encode(c._1) - val i = inject(e, numErrors) + val i = e ^ Mux(numErrors < 1, 0, ErrGen(n, 1)) ^ Mux(numErrors < 2, 0, ErrGen(n, 1)) val d = code.decode(i) io.original := c._1 diff --git a/rocket/src/main/scala/icache.scala b/rocket/src/main/scala/icache.scala index 8845f5ee..1fc33696 100644 --- a/rocket/src/main/scala/icache.scala +++ b/rocket/src/main/scala/icache.scala @@ -7,7 +7,7 @@ import uncore._ import Util._ case class ICacheConfig(sets: Int, assoc: Int, co: CoherencePolicyWithUncached, - parity: Boolean = false) + code: Code = new IdentityCode) { val w = 1 val ibytes = 4 @@ -15,12 +15,10 @@ case class ICacheConfig(sets: Int, assoc: Int, co: CoherencePolicyWithUncached, val dm = assoc == 1 val lines = sets * assoc val databits = MEM_DATA_BITS - val datawidth = databits + (if (parity) 1 else 0) val idxbits = log2Up(sets) val offbits = OFFSET_BITS val untagbits = idxbits + offbits val tagbits = PADDR_BITS - untagbits - val tagwidth = tagbits + (if (parity) 1 else 0) require(isPow2(sets) && isPow2(assoc)) require(isPow2(w) && isPow2(ibytes)) @@ -176,11 +174,12 @@ class ICache(implicit c: ICacheConfig) extends Component val (rf_cnt, refill_done) = Counter(io.mem.xact_rep.valid, REFILL_CYCLES) val repl_way = if (c.dm) UFix(0) else LFSR16(s2_miss)(log2Up(c.assoc)-1,0) - val tag_array = Mem(c.sets, seqRead = true) { Bits(width = c.tagwidth*c.assoc) } + val enc_tagbits = c.code.width(c.tagbits) + val tag_array = Mem(c.sets, seqRead = true) { Bits(width = enc_tagbits*c.assoc) } val tag_rdata = Reg() { Bits() } when (refill_done) { - val wmask = FillInterleaved(c.tagwidth, if (c.dm) Bits(1) else UFixToOH(repl_way)) - val tag = Cat(if (c.parity) s2_tag.xorR else null, s2_tag) + val wmask = FillInterleaved(enc_tagbits, if (c.dm) Bits(1) else UFixToOH(repl_way)) + val tag = c.code.encode(s2_tag) tag_array.write(s2_idx, Fill(c.assoc, tag), wmask) } /*.else*/when (s0_valid) { // uncomment ".else" to infer 6T SRAM @@ -201,39 +200,37 @@ class ICache(implicit c: ICacheConfig) extends Component val s1_tag_match = Vec(c.assoc) { Bool() } val s2_tag_hit = Vec(c.assoc) { Bool() } - val s2_data_disparity = Vec(c.assoc) { Bool() } + val s2_dout = Vec(c.assoc){Reg{Bits()}} + for (i <- 0 until c.assoc) { val s1_vb = vb_array(Cat(UFix(i), s1_pgoff(c.untagbits-1,c.offbits))).toBool val s2_vb = Reg() { Bool() } val s2_tag_disparity = Reg() { Bool() } val s2_tag_match = Reg() { Bool() } - val tag_out = tag_rdata(c.tagwidth*(i+1)-1, c.tagwidth*i) + val tag_out = tag_rdata(enc_tagbits*(i+1)-1, enc_tagbits*i) when (s1_valid && rdy && !stall) { s2_vb := s1_vb - s2_tag_disparity := tag_out.xorR + s2_tag_disparity := c.code.decode(tag_out).error s2_tag_match := s1_tag_match(i) } s1_tag_match(i) := tag_out(c.tagbits-1,0) === s1_tag s2_tag_hit(i) := s2_vb && s2_tag_match - s2_disparity(i) := Bool(c.parity) && s2_vb && (s2_tag_disparity || s2_data_disparity(i)) + s2_disparity(i) := s2_vb && (s2_tag_disparity || c.code.decode(s2_dout(i)).error) } s2_any_tag_hit := s2_tag_hit.reduceLeft(_||_) && !s2_disparity.reduceLeft(_||_) - val s2_dout = Vec(c.assoc) { Reg() { Bits(width = c.databits) } } for (i <- 0 until c.assoc) { - val data_array = Mem(c.sets*REFILL_CYCLES, seqRead = true){ Bits(width = c.datawidth) } + val data_array = Mem(c.sets*REFILL_CYCLES, seqRead = true){ Bits(width = c.code.width(c.databits)) } val s1_dout = Reg(){ Bits() } when (io.mem.xact_rep.valid && repl_way === UFix(i)) { val d = io.mem.xact_rep.bits.data - val wdata = if (c.parity) Cat(d.xorR, d) else d - data_array(Cat(s2_idx,rf_cnt)) := wdata + data_array(Cat(s2_idx,rf_cnt)) := c.code.encode(d) } /*.else*/when (s0_valid) { // uncomment ".else" to infer 6T SRAM s1_dout := data_array(s0_pgoff(c.untagbits-1,c.offbits-rf_cnt.getWidth)) } // if s1_tag_match is critical, replace with partial tag check when (s1_valid && rdy && !stall && (Bool(c.dm) || s1_tag_match(i))) { s2_dout(i) := s1_dout } - s2_data_disparity(i) := s2_dout(i).xorR } val s2_dout_word = s2_dout.map(x => (x >> (s2_offset(log2Up(c.databits/8)-1,log2Up(c.ibytes)) << log2Up(c.ibytes*8)))(c.ibytes*8-1,0)) io.resp.bits.data := Mux1H(s2_tag_hit, s2_dout_word)