1
0

ECC: support poison during encode (#1166)

This makes it possible to update an ECC-protected word while
retaining the fact that the value has an ECC error.
This commit is contained in:
Wesley W. Terpstra 2018-03-21 16:29:24 -07:00 committed by GitHub
parent 7593baf2aa
commit 7f96da2288
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -19,7 +19,12 @@ abstract class Code
def canCorrect: Boolean def canCorrect: Boolean
def width(w0: Int): Int def width(w0: Int): Int
def encode(x: UInt): UInt
/** Encode x to a codeword suitable for decode.
* If poison is true, the decoded value will report uncorrectable
* error despite decoding to the supplied value 'x'.
*/
def encode(x: UInt, poison: Bool = Bool(false)): UInt
def decode(x: UInt): Decoding def decode(x: UInt): Decoding
/** Copy the bits in x to the right bit positions in an encoded word, /** Copy the bits in x to the right bit positions in an encoded word,
@ -36,7 +41,10 @@ class IdentityCode extends Code
def canCorrect = false def canCorrect = false
def width(w0: Int) = w0 def width(w0: Int) = w0
def encode(x: UInt) = x def encode(x: UInt, poison: Bool = Bool(false)) = {
require (poison.isLit && poison.litValue == 0, "IdentityCode can not be poisoned")
x
}
def swizzle(x: UInt) = x def swizzle(x: UInt) = x
def decode(y: UInt) = new Decoding { def decode(y: UInt) = new Decoding {
def uncorrected = y def uncorrected = y
@ -52,7 +60,7 @@ class ParityCode extends Code
def canCorrect = false def canCorrect = false
def width(w0: Int) = w0+1 def width(w0: Int) = w0+1
def encode(x: UInt) = Cat(x.xorR, x) def encode(x: UInt, poison: Bool = Bool(false)) = Cat(x.xorR ^ poison, x)
def swizzle(x: UInt) = Cat(false.B, x) def swizzle(x: UInt) = Cat(false.B, x)
def decode(y: UInt) = new Decoding { def decode(y: UInt) = new Decoding {
val uncorrected = y(y.getWidth-2,0) val uncorrected = y(y.getWidth-2,0)
@ -67,20 +75,26 @@ class SECCode extends Code
def canDetect = true def canDetect = true
def canCorrect = true def canCorrect = true
// SEC codes may or may not be poisonous depending on the length
// If the code is perfect, every non-codeword is correctable
def poisonous(n: Int) = !isPow2(n+1)
def width(k: Int) = { def width(k: Int) = {
val m = log2Floor(k) + 1 val m = log2Floor(k) + 1
k + m + (if((1 << m) < m+k+1) 1 else 0) k + m + (if((1 << m) < m+k+1) 1 else 0)
} }
def encode(x: UInt) = { def encode(x: UInt, poison: Bool = Bool(false)) = {
val k = x.getWidth val k = x.getWidth
require(k > 0) require(k > 0)
val n = width(k) val n = width(k)
require ((poison.isLit && poison.litValue == 0) || poisonous(n), s"SEC code of length ${n} cannot be poisoned")
val y = for (i <- 1 to n) yield { val y = for (i <- 1 to n) yield {
if (isPow2(i)) { if (isPow2(i)) {
val r = for (j <- 1 to n; if j != i && (j & i) != 0) val r = for (j <- 1 to n; if j != i && (j & i) != 0)
yield x(mapping(j)) yield x(mapping(j))
r reduce (_^_) r.reduce(_^_) ^ poison
} else } else
x(mapping(i)) x(mapping(i))
} }
@ -106,7 +120,7 @@ class SECCode extends Code
val uncorrected = swizzle(y) val uncorrected = swizzle(y)
val corrected = swizzle(((y << 1) ^ UIntToOH(syndrome)) >> 1) val corrected = swizzle(((y << 1) ^ UIntToOH(syndrome)) >> 1)
val correctable = syndrome.orR val correctable = syndrome.orR
val uncorrectable = syndrome > UInt(n) val uncorrectable = if (poisonous(n)) { syndrome > UInt(n) } else { Bool(false) }
} }
private def mapping(i: Int) = i-1-log2Up(i) private def mapping(i: Int) = i-1-log2Up(i)
} }
@ -120,7 +134,12 @@ class SECDEDCode extends Code
private val par = new ParityCode private val par = new ParityCode
def width(k: Int) = sec.width(k)+1 def width(k: Int) = sec.width(k)+1
def encode(x: UInt) = par.encode(sec.encode(x)) def encode(x: UInt, poison: Bool = Bool(false)) = {
// toggling two bits ensures the error is uncorrectable
val toggle_lo = poison.asUInt // a non-data bit in SEC
val toggle_hi = toggle_lo << sec.width(x.getWidth) // the parity bit
par.encode(sec.encode(x)) ^ toggle_lo ^ toggle_hi
}
def swizzle(x: UInt) = par.swizzle(sec.swizzle(x)) def swizzle(x: UInt) = par.swizzle(sec.swizzle(x))
def decode(x: UInt) = new Decoding { def decode(x: UInt) = new Decoding {
val secdec = sec.decode(x(x.getWidth-2,0)) val secdec = sec.decode(x(x.getWidth-2,0))