2019-06-23 17:56:50 -04:00
|
|
|
# This file is Copyright (c) 2018-2019 Florent Kermarrec <florent@enjoy-digital.fr>
|
|
|
|
# License: BSD
|
|
|
|
|
2018-09-15 17:36:12 -04:00
|
|
|
import unittest
|
|
|
|
import random
|
|
|
|
|
|
|
|
from migen import *
|
|
|
|
|
2018-09-15 18:39:33 -04:00
|
|
|
from litedram.common import *
|
2018-09-15 17:36:12 -04:00
|
|
|
from litedram.frontend.ecc import *
|
|
|
|
|
|
|
|
from litex.gen.sim import *
|
|
|
|
|
|
|
|
|
|
|
|
class TestECC(unittest.TestCase):
|
|
|
|
def test_m_n(self):
|
|
|
|
m, n = compute_m_n(15)
|
|
|
|
self.assertEqual(m, 5)
|
|
|
|
self.assertEqual(n, 20)
|
|
|
|
|
|
|
|
def test_syndrome_positions(self):
|
|
|
|
p_pos = compute_syndrome_positions(20)
|
|
|
|
p_pos_ref = [1, 2, 4, 8, 16]
|
|
|
|
self.assertEqual(p_pos, p_pos_ref)
|
|
|
|
|
|
|
|
def test_data_positions(self):
|
|
|
|
d_pos = compute_data_positions(20)
|
|
|
|
d_pos_ref = [3, 5, 6, 7, 9, 10, 11, 12, 13, 14, 15, 17, 18, 19, 20]
|
|
|
|
self.assertEqual(d_pos, d_pos_ref)
|
|
|
|
|
|
|
|
def test_cover_positions(self):
|
|
|
|
c_pos_ref = {
|
|
|
|
0 : [1, 3, 5, 7, 9, 11, 13, 15, 17, 19],
|
|
|
|
1 : [2, 3, 6, 7, 10, 11, 14, 15, 18, 19],
|
|
|
|
2 : [4, 5, 6, 7, 12, 13, 14, 15, 20],
|
|
|
|
3 : [8, 9, 10, 11, 12, 13, 14, 15],
|
|
|
|
4 : [16, 17, 18, 19, 20]
|
|
|
|
}
|
|
|
|
for i in range(5):
|
|
|
|
c_pos = compute_cover_positions(20, 2**i)
|
|
|
|
self.assertEqual(c_pos, c_pos_ref[i])
|
|
|
|
|
|
|
|
def test_ecc(self, k=15):
|
|
|
|
class DUT(Module):
|
|
|
|
def __init__(self, k):
|
|
|
|
m, n = compute_m_n(k)
|
|
|
|
self.flip = Signal(n + 1)
|
|
|
|
|
|
|
|
# # #
|
|
|
|
|
|
|
|
self.submodules.encoder = ECCEncoder(k)
|
|
|
|
self.submodules.decoder = ECCDecoder(k)
|
|
|
|
|
|
|
|
self.comb += self.decoder.i.eq(self.encoder.o ^ self.flip)
|
|
|
|
|
|
|
|
def generator(dut, k, nvalues, nerrors):
|
|
|
|
dut.errors = 0
|
|
|
|
prng = random.Random(42)
|
2018-10-12 11:13:53 -04:00
|
|
|
yield dut.decoder.enable.eq(1)
|
2018-09-15 17:36:12 -04:00
|
|
|
for i in range(nvalues):
|
|
|
|
data = prng.randrange(2**k-1)
|
|
|
|
yield dut.encoder.i.eq(data)
|
|
|
|
# FIXME: error when fliping parity bit
|
|
|
|
if nerrors == 1:
|
|
|
|
flip_bit1 = (prng.randrange(len(dut.flip)-2) + 1)
|
|
|
|
yield dut.flip.eq(1<<flip_bit1)
|
|
|
|
elif nerrors == 2:
|
|
|
|
flip_bit1 = (prng.randrange(len(dut.flip)-2) + 1)
|
|
|
|
flip_bit2 = flip_bit1
|
|
|
|
while flip_bit2 == flip_bit1:
|
|
|
|
flip_bit2 = (prng.randrange(len(dut.flip)-2) + 1)
|
|
|
|
yield dut.flip.eq((1<<flip_bit1) | (1<<flip_bit2))
|
|
|
|
yield
|
|
|
|
# if less than 2 errors, check data
|
|
|
|
if nerrors < 2:
|
|
|
|
if (yield dut.decoder.o) != data:
|
|
|
|
dut.errors += 1
|
2019-01-04 04:43:57 -05:00
|
|
|
# if 0 error, verify sec == 0 / ded == 0
|
2018-09-15 17:36:12 -04:00
|
|
|
if nerrors == 0:
|
|
|
|
if (yield dut.decoder.sec) != 0:
|
|
|
|
dut.errors += 1
|
2019-01-04 04:43:57 -05:00
|
|
|
if (yield dut.decoder.ded) != 0:
|
2018-09-15 17:36:12 -04:00
|
|
|
dut.errors += 1
|
|
|
|
# if 1 error, verify sec == 1 / dec == 0
|
|
|
|
elif nerrors == 1:
|
|
|
|
if (yield dut.decoder.sec) != 1:
|
|
|
|
dut.errors += 1
|
2019-01-04 04:43:57 -05:00
|
|
|
if (yield dut.decoder.ded) != 0:
|
2018-09-15 17:36:12 -04:00
|
|
|
dut.errors += 1
|
2019-01-04 04:43:57 -05:00
|
|
|
# if 2 errors, verify sec == 0 / ded == 1
|
2018-09-15 17:36:12 -04:00
|
|
|
elif nerrors == 2:
|
|
|
|
if (yield dut.decoder.sec) != 0:
|
|
|
|
dut.errors += 1
|
2019-01-04 04:43:57 -05:00
|
|
|
if (yield dut.decoder.ded) != 1:
|
2018-09-15 17:36:12 -04:00
|
|
|
dut.errors += 1
|
|
|
|
|
|
|
|
for i in range(3):
|
|
|
|
dut = DUT(k)
|
|
|
|
run_simulation(dut, generator(dut, k, 128, i))
|
|
|
|
self.assertEqual(dut.errors, 0)
|
2018-09-15 18:39:33 -04:00
|
|
|
|
|
|
|
def test_ecc_wrapper(self):
|
|
|
|
# 32 bits + 8 bits ecc
|
|
|
|
port_from = LiteDRAMNativePort("both", 24, 32*8)
|
|
|
|
port_to = LiteDRAMNativePort("both", 24, 40*8)
|
|
|
|
ecc = LiteDRAMNativePortECC(port_from, port_to)
|
|
|
|
|
|
|
|
# 64 bits + 8 bits ecc
|
|
|
|
port_from = LiteDRAMNativePort("both", 24, 64*8)
|
|
|
|
port_to = LiteDRAMNativePort("both", 24, 72*8)
|
|
|
|
ecc = LiteDRAMNativePortECC(port_from, port_to)
|