From 2adbe7711bec6c228e9cb6ffb7c7ef30b1621c8f Mon Sep 17 00:00:00 2001 From: Luke Kenneth Casson Leighton Date: Sun, 27 Feb 2022 19:16:35 +0000 Subject: [PATCH] fix up Logical pipeline to produce HDL with XLEN=32 fix Logical test_pipe_caller.py to use new regspeckls style --- src/soc/fu/logical/bpermd.py | 11 ++++---- src/soc/fu/logical/main_stage.py | 17 +++++++----- src/soc/fu/logical/pipe_data.py | 29 +++++++++++++-------- src/soc/fu/logical/popcount.py | 29 +++++++++++++-------- src/soc/fu/logical/test/test_pipe_caller.py | 29 ++++++++++----------- 5 files changed, 67 insertions(+), 48 deletions(-) diff --git a/src/soc/fu/logical/bpermd.py b/src/soc/fu/logical/bpermd.py index dc086fae..83eaf989 100644 --- a/src/soc/fu/logical/bpermd.py +++ b/src/soc/fu/logical/bpermd.py @@ -58,15 +58,16 @@ class Bpermd(Elaboratable): def elaborate(self, platform): m = Module() perm = Signal(self.width, reset_less=True) - rb64 = [Signal(1, reset_less=True, name=f"rb64_{i}") for i in range(64)] - for i in range(64): - m.d.comb += rb64[i].eq(self.rb[63-i]) + rb64 = [Signal(1, reset_less=True, name=f"rb64_{i}") + for i in range(self.width)] + for i in range(self.width): + m.d.comb += rb64[i].eq(self.rb[self.width-1-i]) rb64 = Array(rb64) - for i in range(8): + for i in range(self.width//8): index = self.rs[8*i:8*i+8] idx = Signal(8, name=f"idx_{i}", reset_less=True) m.d.comb += idx.eq(index) - with m.If(idx < 64): + with m.If(idx < self.width): m.d.comb += perm[i].eq(rb64[idx]) m.d.comb += self.ra[0:8].eq(perm) return m diff --git a/src/soc/fu/logical/main_stage.py b/src/soc/fu/logical/main_stage.py index 25366403..6a903957 100644 --- a/src/soc/fu/logical/main_stage.py +++ b/src/soc/fu/logical/main_stage.py @@ -6,6 +6,8 @@ # to the output stage # Copyright (C) 2020 Michael Nolan +# Copyright (C) 2020, 2021 Luke Kenneth Casson Leighton + from nmigen import (Module, Signal, Cat, Repl, Mux, Const, Array) from nmutil.pipemodbase import PipeModBase from nmutil.clz import CLZ @@ -33,14 +35,15 @@ class LogicalMainStage(PipeModBase): return LogicalOutputData(self.pspec) def elaborate(self, platform): + XLEN = self.pspec.XLEN m = Module() comb = m.d.comb op, a, b, o = self.i.ctx.op, self.i.a, self.i.b, self.o.o comb += o.ok.eq(1) # overridden if no op activates - m.submodules.bpermd = bpermd = Bpermd(64) - m.submodules.popcount = popcount = Popcount() + m.submodules.bpermd = bpermd = Bpermd(XLEN) + m.submodules.popcount = popcount = Popcount(XLEN) ########################## # main switch for logic ops AND, OR and XOR, cmpb, parity, and popcount @@ -84,12 +87,14 @@ class LogicalMainStage(PipeModBase): par0 = Signal(reset_less=True) par1 = Signal(reset_less=True) comb += par0.eq(Cat(a[0], a[8], a[16], a[24]).xor()) - comb += par1.eq(Cat(a[32], a[40], a[48], a[56]).xor()) + if XLEN == 64: + comb += par1.eq(Cat(a[32], a[40], a[48], a[56]).xor()) with m.If(op.data_len[3] == 1): comb += o.data.eq(par0 ^ par1) with m.Else(): comb += o[0].eq(par0) - comb += o[32].eq(par1) + if XLEN == 64: + comb += o[32].eq(par1) ################### ###### cntlz v3.0B p99 @@ -99,7 +104,7 @@ class LogicalMainStage(PipeModBase): count_right = Signal(reset_less=True) comb += count_right.eq(XO[-1]) - cntz_i = Signal(64, reset_less=True) + cntz_i = Signal(XLEN, reset_less=True) a32 = Signal(32, reset_less=True) comb += a32.eq(a[0:32]) @@ -108,7 +113,7 @@ class LogicalMainStage(PipeModBase): with m.Else(): comb += cntz_i.eq(Mux(count_right, a[::-1], a)) - m.submodules.clz = clz = CLZ(64) + m.submodules.clz = clz = CLZ(XLEN) comb += clz.sig_in.eq(cntz_i) comb += o.data.eq(Mux(op.is_32bit, clz.lz-32, clz.lz)) diff --git a/src/soc/fu/logical/pipe_data.py b/src/soc/fu/logical/pipe_data.py index 40a18bc2..359a2a59 100644 --- a/src/soc/fu/logical/pipe_data.py +++ b/src/soc/fu/logical/pipe_data.py @@ -5,38 +5,45 @@ from soc.fu.logical.logical_input_record import CompLogicalOpSubset # input (and output) for logical initial stage (common input) class LogicalInputData(FUBaseData): - regspec = [('INT', 'ra', '0:63'), # RA - ('INT', 'rb', '0:63'), # RB/immediate - ('XER', 'xer_so', '32'), # bit0: so - ] def __init__(self, pspec): super().__init__(pspec, False) # convenience self.a, self.b = self.ra, self.rb + @property + def regspec(self): + return [('INT', 'ra', self.intrange), # RA + ('INT', 'rb', self.intrange), # RB/immediate + ('XER', 'xer_so', '32'), # bit0: so + ] # input to logical final stage (common output) class LogicalOutputData(FUBaseData): - regspec = [('INT', 'o', '0:63'), # RT - ('CR', 'cr_a', '0:3'), - ('XER', 'xer_so', '32'), # bit0: so - ] def __init__(self, pspec): super().__init__(pspec, True) # convenience self.cr0 = self.cr_a + @property + def regspec(self): + return [('INT', 'o', self.intrange), + ('CR', 'cr_a', '0:3'), + ('XER', 'xer_so', '32'), # bit0: so + ] + # output from logical final stage (common output) - note that XER.so # is *not* included (the only reason it's in the input is because of CR0) class LogicalOutputDataFinal(FUBaseData): - regspec = [('INT', 'o', '0:63'), # RT - ('CR', 'cr_a', '0:3'), - ] def __init__(self, pspec): super().__init__(pspec, True) # convenience self.cr0 = self.cr_a + @property + def regspec(self): + return [('INT', 'o', self.intrange), + ('CR', 'cr_a', '0:3'), + ] class LogicalPipeSpec(CommonPipeSpec): diff --git a/src/soc/fu/logical/popcount.py b/src/soc/fu/logical/popcount.py index ca90112d..5975149d 100644 --- a/src/soc/fu/logical/popcount.py +++ b/src/soc/fu/logical/popcount.py @@ -23,11 +23,13 @@ def array_of(count, bitwidth): class Popcount(Elaboratable): - def __init__(self): - self.a = Signal(64, reset_less=True) - self.b = Signal(64, reset_less=True) + def __init__(self, width=64): + self.width = width + self.a = Signal(width, reset_less=True) + self.b = Signal(width, reset_less=True) self.data_len = Signal(4, reset_less=True) # data len up to... err.. 8? - self.o = Signal(64, reset_less=True) + self.o = Signal(width, reset_less=True) + assert width in [32, 64], "only 32 or 64 bit supported for now" def elaborate(self, platform): m = Module() @@ -38,11 +40,13 @@ class Popcount(Elaboratable): # creating arrays big enough to store the sum, each time pc = [a] # QTY32 2-bit (to take 2x 1-bit sums) etc. - work = [(32, 2), (16, 3), (8, 4), (4, 5), (2, 6), (1, 7)] + work = [(16, 3), (8, 4), (4, 5), (2, 6), (1, 7)] + if self.width == 64: + work = [(32, 2)] + work for l, bw in work: # l=number of add-reductions, bw=bitwidth pc.append(array_of(l, bw)) - pc8 = pc[3] # array of 8 8-bit counts (popcntb) - pc32 = pc[5] # array of 2 32-bit counts (popcntw) + pc8 = pc[-4] # array of 8 8-bit counts (popcntb) + pc32 = pc[-2] # array of 2 32-bit counts (popcntw) popcnt = pc[-1] # array of 1 64-bit count (popcntd) # cascade-tree of adds for idx, (l, bw) in enumerate(work): @@ -54,12 +58,15 @@ class Popcount(Elaboratable): # decode operation length (1-hot) with m.If(data_len == 1): # popcntb - pack 8x 4-bit answers into 8x 8-bit output fields - for i in range(8): + for i in range(self.width//8): comb += o[i*8:(i+1)*8].eq(pc8[i]) with m.Elif(data_len == 4): - # popcntw - pack 2x 5-bit answers into 2x 32-bit output fields - for i in range(2): - comb += o[i*32:(i+1)*32].eq(pc32[i]) + if self.width == 64: + # popcntw - pack 2x 5-bit answers into 2x 32-bit output fields + for i in range(2): + comb += o[i*32:(i+1)*32].eq(pc32[i]) + else: + comb += o.eq(popcnt[0]) with m.Else(): # popcntd - put 1x 6-bit answer into 64-bit output comb += o.eq(popcnt[0]) diff --git a/src/soc/fu/logical/test/test_pipe_caller.py b/src/soc/fu/logical/test/test_pipe_caller.py index 5ecbe230..5df6effc 100644 --- a/src/soc/fu/logical/test/test_pipe_caller.py +++ b/src/soc/fu/logical/test/test_pipe_caller.py @@ -51,17 +51,17 @@ def set_alu_inputs(alu, dec2, sim): class LogicalIlangCase(TestAccumulatorBase): def case_ilang(self): - pspec = LogicalPipeSpec(id_wid=2, parent_pspec=None) + class PPspec: + XLEN = 64 + pps = PPspec() + pspec = LogicalPipeSpec(id_wid=2, parent_pspec=pps) alu = LogicalBasePipe(pspec) vl = rtlil.convert(alu, ports=alu.ports()) with open("logical_pipeline.il", "w") as f: f.write(vl) -class TestRunner(FHDLTestCase): - def __init__(self, test_data): - super().__init__("run_all") - self.test_data = test_data +class TestRunner(unittest.TestCase): def execute(self, alu, instruction, pdecode2, test): print(test.name) @@ -107,7 +107,9 @@ class TestRunner(FHDLTestCase): simulator, code) yield Settle() - def run_all(self): + def test_it(self): + test_data = LogicalIlangCase().test_data + \ + LogicalTestCase().test_data m = Module() comb = m.d.comb instruction = Signal(32) @@ -116,7 +118,10 @@ class TestRunner(FHDLTestCase): m.submodules.pdecode2 = pdecode2 = PowerDecode2(pdecode) - pspec = LogicalPipeSpec(id_wid=2, parent_pspec=None) + class PPspec: + XLEN = 64 + pps = PPspec() + pspec = LogicalPipeSpec(id_wid=2, parent_pspec=pps) m.submodules.alu = alu = LogicalBasePipe(pspec) comb += alu.p.i_data.ctx.op.eq_from_execute1(pdecode2.do) @@ -127,7 +132,7 @@ class TestRunner(FHDLTestCase): sim.add_clock(1e-6) def process(): - for test in self.test_data: + for test in test_data: print(test.name) program = test.program with self.subTest(test.name): @@ -163,10 +168,4 @@ class TestRunner(FHDLTestCase): if __name__ == "__main__": - unittest.main(exit=False) - suite = unittest.TestSuite() - suite.addTest(TestRunner(LogicalIlangCase().test_data)) - suite.addTest(TestRunner(LogicalTestCase().test_data)) - - runner = unittest.TextTestRunner() - runner.run(suite) + unittest.main() -- 2.30.2