class TestCaseData:
+ __test__ = False # make pytest ignore class
+
def __init__(self,
dividend,
divisor_radicand,
core_config)
+def shifted_ints(total_bits, int_bits):
+ """ Generate a sequence like a generalized binary version of A037124.
+
+ See https://oeis.org/A037124
+
+ Generates the sequence of all non-negative integers ``n`` in ascending
+ order with no repeats where ``n < (1 << total_bits) and n == (v << i)``
+ where ``i`` is a non-negative integer and ``v`` is a non-negative
+ integer less than ``1 << int_bits``.
+ """
+ n = 0
+ while n < (1 << total_bits):
+ yield n
+ if n < (1 << int_bits):
+ n += 1
+ else:
+ n += 1 << (n.bit_length() - int_bits)
+
+
+def partitioned_ints(bit_width):
+ """ Get ints with all 1s on one side and 0s on the other. """
+ for i in range(bit_width):
+ yield (-1 << i) & ((1 << bit_width) - 1)
+ yield (1 << (i + 1)) - 1
+
+
+class TestShiftedInts(unittest.TestCase):
+ def test(self):
+ expected = [0x000,
+ 0x001,
+ 0x002, 0x003,
+ 0x004, 0x005, 0x006, 0x007,
+ 0x008, 0x009, 0x00A, 0x00B, 0x00C, 0x00D, 0x00E, 0x00F,
+ 0x010, 0x012, 0x014, 0x016, 0x018, 0x01A, 0x01C, 0x01E,
+ 0x020, 0x024, 0x028, 0x02C, 0x030, 0x034, 0x038, 0x03C,
+ 0x040, 0x048, 0x050, 0x058, 0x060, 0x068, 0x070, 0x078,
+ 0x080, 0x090, 0x0A0, 0x0B0, 0x0C0, 0x0D0, 0x0E0, 0x0F0,
+ 0x100, 0x120, 0x140, 0x160, 0x180, 0x1A0, 0x1C0, 0x1E0,
+ 0x200, 0x240, 0x280, 0x2C0, 0x300, 0x340, 0x380, 0x3C0,
+ 0x400, 0x480, 0x500, 0x580, 0x600, 0x680, 0x700, 0x780,
+ 0x800, 0x900, 0xA00, 0xB00, 0xC00, 0xD00, 0xE00, 0xF00]
+ self.assertEqual(list(shifted_ints(12, 4)), expected)
+
+
def get_test_cases(core_config,
dividends=None,
divisors=None,
radicands=None):
if dividends is None:
- dividends = range(1 << (core_config.bit_width
- + core_config.fract_width))
+ dividend_width = core_config.bit_width + core_config.fract_width
+ dividends = [*shifted_ints(dividend_width,
+ max(3, core_config.log2_radix)),
+ *partitioned_ints(dividend_width)]
else:
assert isinstance(dividends, list)
if divisors is None:
- divisors = range(1 << core_config.bit_width)
+ divisors = [*shifted_ints(core_config.bit_width,
+ max(3, core_config.log2_radix)),
+ *partitioned_ints(core_config.bit_width)]
else:
assert isinstance(divisors, list)
if radicands is None:
- radicands = range(1 << core_config.bit_width)
+ radicands = [*shifted_ints(core_config.bit_width, 5),
+ *partitioned_ints(core_config.bit_width)]
else:
assert isinstance(radicands, list)
- for alg_op in Operation:
+ for alg_op in reversed(Operation): # put UDivRem at end
if alg_op is Operation.UDivRem:
for dividend in dividends:
for divisor in divisors:
class TestDivPipeCore(unittest.TestCase):
- def handle_case(self,
- core_config,
- dividends=None,
- divisors=None,
- radicands=None,
- sync=True):
- if dividends is not None:
- dividends = list(dividends)
- if divisors is not None:
- divisors = list(divisors)
- if radicands is not None:
- radicands = list(radicands)
-
- def gen_test_cases():
- yield from get_test_cases(core_config,
- dividends,
- divisors,
- radicands)
- base_name = f"div_pipe_core_bit_width_{core_config.bit_width}"
+ def handle_config(self,
+ core_config,
+ test_cases=None,
+ sync=True):
+ if test_cases is None:
+ test_cases = get_test_cases(core_config)
+ test_cases = list(test_cases)
+ base_name = f"test_div_pipe_core_bit_width_{core_config.bit_width}"
base_name += f"_fract_width_{core_config.fract_width}"
base_name += f"_radix_{1 << core_config.log2_radix}"
+ if not sync:
+ base_name += "_comb"
with self.subTest(part="synthesize"):
dut = DivPipeCoreTestPipeline(core_config, sync)
vl = rtlil.convert(dut, ports=[*dut.i, *dut.o])
gtkw_file=open(f"{base_name}.gtkw", "w"),
traces=[*dut.traces()]) as sim:
def generate_process():
- for test_case in gen_test_cases():
+ for test_case in test_cases:
yield Tick()
yield dut.i.dividend.eq(test_case.dividend)
yield dut.i.divisor_radicand.eq(test_case.divisor_radicand)
yield
# now synched with generator
- for test_case in gen_test_cases():
+ for test_case in test_cases:
yield Tick()
yield Delay(0.9e-6)
quotient_root = (yield dut.o.quotient_root)
sim.add_sync_process(check_process)
sim.run()
- def test_bit_width_8_fract_width_4_radix_2(self):
- self.handle_case(DivPipeCoreConfig(bit_width=8,
- fract_width=4,
- log2_radix=1),
- dividends=[*range(1 << 8),
- *range(1 << 8, 1 << 12, 1 << 4)],
- sync=False)
+ def test_bit_width_2_fract_width_1_radix_2_comb(self):
+ self.handle_config(DivPipeCoreConfig(bit_width=2,
+ fract_width=1,
+ log2_radix=1),
+ sync=False)
def test_bit_width_2_fract_width_1_radix_2(self):
- self.handle_case(DivPipeCoreConfig(bit_width=2,
- fract_width=1,
- log2_radix=1),
- sync=False)
+ self.handle_config(DivPipeCoreConfig(bit_width=2,
+ fract_width=1,
+ log2_radix=1))
+
+ def test_bit_width_8_fract_width_4_radix_2_comb(self):
+ self.handle_config(DivPipeCoreConfig(bit_width=8,
+ fract_width=4,
+ log2_radix=1),
+ sync=False)
+
+ def test_bit_width_8_fract_width_4_radix_2(self):
+ self.handle_config(DivPipeCoreConfig(bit_width=8,
+ fract_width=4,
+ log2_radix=1))
+
+ def test_bit_width_32_fract_width_24_radix_8_comb(self):
+ self.handle_config(DivPipeCoreConfig(bit_width=32,
+ fract_width=24,
+ log2_radix=3),
+ sync=False)
+
+ def test_bit_width_32_fract_width_24_radix_8(self):
+ self.handle_config(DivPipeCoreConfig(bit_width=32,
+ fract_width=24,
+ log2_radix=3))
+
+ def test_bit_width_32_fract_width_28_radix_8_comb(self):
+ self.handle_config(DivPipeCoreConfig(bit_width=32,
+ fract_width=28,
+ log2_radix=3),
+ sync=False)
+
+ def test_bit_width_32_fract_width_28_radix_8(self):
+ self.handle_config(DivPipeCoreConfig(bit_width=32,
+ fract_width=28,
+ log2_radix=3))
# FIXME: add more test_* functions