From 7f06a0a7162bed084387b2391619912fe22b251e Mon Sep 17 00:00:00 2001 From: Michael Nolan Date: Tue, 12 May 2020 13:29:02 -0400 Subject: [PATCH] Remove rotates and shifts from alu --- src/soc/alu/formal/proof_main_stage.py | 19 --- src/soc/alu/main_stage.py | 81 ------------- src/soc/alu/maskgen.py | 47 -------- src/soc/alu/rotator.py | 154 ------------------------- src/soc/alu/rotl.py | 24 ---- src/soc/alu/test/test_maskgen.py | 41 ------- src/soc/alu/test/test_pipe_caller.py | 44 ------- 7 files changed, 410 deletions(-) delete mode 100644 src/soc/alu/maskgen.py delete mode 100644 src/soc/alu/rotator.py delete mode 100644 src/soc/alu/rotl.py delete mode 100644 src/soc/alu/test/test_maskgen.py diff --git a/src/soc/alu/formal/proof_main_stage.py b/src/soc/alu/formal/proof_main_stage.py index 3ce8f19a..e25b1c51 100644 --- a/src/soc/alu/formal/proof_main_stage.py +++ b/src/soc/alu/formal/proof_main_stage.py @@ -74,25 +74,6 @@ class Driver(Elaboratable): comb += Assert(dut.o.o == a | b) with m.Case(InternalOp.OP_XOR): comb += Assert(dut.o.o == a ^ b) - with m.Case(InternalOp.OP_SHL): - with m.If(rec.is_32bit): - comb += Assert(o[0:32] == ((a << b[0:6]) & 0xffffffff)) - comb += Assert(o[32:64] == 0) - with m.Else(): - comb += Assert(o == ((a << b[0:7]) & ((1 << 64)-1))) - with m.Case(InternalOp.OP_SHR): - with m.If(~rec.is_signed): - with m.If(rec.is_32bit): - comb += Assert(o[0:32] == (a[0:32] >> b[0:6])) - comb += Assert(o[32:64] == 0) - with m.Else(): - comb += Assert(o == (a >> b[0:7])) - with m.Else(): - with m.If(rec.is_32bit): - comb += Assert(o[0:32] == (a_signed_32 >> b[0:6])) - comb += Assert(o[32:64] == Repl(a[31], 32)) - with m.Else(): - comb += Assert(o == (a_signed >> b[0:7])) return m diff --git a/src/soc/alu/main_stage.py b/src/soc/alu/main_stage.py index 9d8133f1..b2851015 100644 --- a/src/soc/alu/main_stage.py +++ b/src/soc/alu/main_stage.py @@ -8,18 +8,12 @@ from nmutil.pipemodbase import PipeModBase from soc.alu.pipe_data import ALUInputData, ALUOutputData from ieee754.part.partsig import PartitionedSignal from soc.decoder.power_enums import InternalOp -from soc.alu.maskgen import MaskGen -from soc.alu.rotl import ROTL -from soc.decoder.power_fields import DecodeFields -from soc.decoder.power_fieldsn import SignalBitRange class ALUMainStage(PipeModBase): def __init__(self, pspec): super().__init__(pspec, "main") - self.fields = DecodeFields(SignalBitRange, [self.i.ctx.op.insn]) - self.fields.create_specs() def ispec(self): return ALUInputData(self.pspec) @@ -32,37 +26,12 @@ class ALUMainStage(PipeModBase): comb = m.d.comb - fields = self.fields.instrs['M'] - mb = Signal(fields['MB'][0:-1].shape()) - comb += mb.eq(fields['MB'][0:-1]) - me = Signal(fields['ME'][0:-1].shape()) - comb += me.eq(fields['ME'][0:-1]) - # check if op is 32-bit, and get sign bit from operand a is_32bit = Signal(reset_less=True) sign_bit = Signal(reset_less=True) comb += is_32bit.eq(self.i.ctx.op.is_32bit) comb += sign_bit.eq(Mux(is_32bit, self.i.a[31], self.i.a[63])) - # Signals for rotates and shifts - rotl_out = Signal.like(self.i.a) - mask = Signal.like(self.i.a) - m.submodules.maskgen = maskgen = MaskGen(64) - m.submodules.rotl = rotl = ROTL(64) - m.submodules.rotl32 = rotl32 = ROTL(32) - rotate_amt = Signal.like(rotl.b) - - comb += [ - rotl.a.eq(self.i.a), - rotl.b.eq(rotate_amt), - rotl32.a.eq(self.i.a[0:32]), - rotl32.b.eq(rotate_amt)] - - with m.If(is_32bit): - comb += rotl_out.eq(Cat(rotl32.o, Repl(0, 32))) - with m.Else(): - comb += rotl_out.eq(rotl.o) - ########################## # main switch-statement for handling arithmetic and logic operations @@ -92,56 +61,6 @@ class ALUMainStage(PipeModBase): #### xor #### with m.Case(InternalOp.OP_XOR): comb += self.o.o.eq(self.i.a ^ self.i.b) - - #### shift left #### - with m.Case(InternalOp.OP_SHL): - comb += maskgen.mb.eq(Mux(is_32bit, 32, 0)) - comb += maskgen.me.eq(63-self.i.b[0:6]) - comb += rotate_amt.eq(self.i.b[0:6]) - with m.If(is_32bit): - with m.If(self.i.b[5]): - comb += mask.eq(0) - with m.Else(): - comb += mask.eq(maskgen.o) - with m.Else(): - with m.If(self.i.b[6]): - comb += mask.eq(0) - with m.Else(): - comb += mask.eq(maskgen.o) - comb += self.o.o.eq(rotl_out & mask) - - #### shift right #### - with m.Case(InternalOp.OP_SHR): - comb += maskgen.mb.eq(Mux(is_32bit, 32, 0) + self.i.b[0:6]) - comb += maskgen.me.eq(63) - comb += rotate_amt.eq(64-self.i.b[0:6]) - with m.If(is_32bit): - with m.If(self.i.b[5]): - comb += mask.eq(0) - with m.Else(): - comb += mask.eq(maskgen.o) - with m.Else(): - with m.If(self.i.b[6]): - comb += mask.eq(0) - with m.Else(): - comb += mask.eq(maskgen.o) - with m.If(self.i.ctx.op.is_signed): - out = rotl_out & mask | Mux(sign_bit, ~mask, 0) - cout = sign_bit & ((rotl_out & mask) != 0) - comb += self.o.o.eq(out) - comb += self.o.carry_out.eq(cout) - with m.Else(): - comb += self.o.o.eq(rotl_out & mask) - - with m.Case(InternalOp.OP_RLC): - with m.If(self.i.ctx.op.imm_data.imm_ok): - comb += rotate_amt.eq(self.i.ctx.op.imm_data.imm[0:5]) - with m.Else(): - comb += rotate_amt.eq(self.i.b[0:5]) - comb += maskgen.mb.eq(mb+32) - comb += maskgen.me.eq(me+32) - comb += mask.eq(maskgen.o) - comb += self.o.o.eq((rotl_out & mask) | (self.i.b & ~mask)) ###### sticky overflow and context, both pass-through ##### diff --git a/src/soc/alu/maskgen.py b/src/soc/alu/maskgen.py deleted file mode 100644 index 89246e0b..00000000 --- a/src/soc/alu/maskgen.py +++ /dev/null @@ -1,47 +0,0 @@ -from nmigen import (Elaboratable, Signal, Module) -import math - -class MaskGen(Elaboratable): - """MaskGen - create a diff mask - - example: x=5 --> a=0b11111 - y=3 --> b=0b00111 - o: 0b11000 - x=2 --> a=0b00011 - y=4 --> b=0b01111 - o: 0b10011 - """ - def __init__(self, width): - self.width = width - self.shiftwidth = math.ceil(math.log2(width)) - self.mb = Signal(self.shiftwidth, reset_less=True) - self.me = Signal(self.shiftwidth, reset_less=True) - - self.o = Signal(width, reset_less=True) - - def elaborate(self, platform): - m = Module() - comb = m.d.comb - - x = Signal.like(self.mb) - y = Signal.like(self.mb) - - comb += x.eq(64 - self.mb) - comb += y.eq(63 - self.me) - - mask_a = Signal.like(self.o) - mask_b = Signal.like(self.o) - - comb += mask_a.eq((1< y): - comb += self.o.eq(mask_a ^ mask_b) - with m.Else(): - comb += self.o.eq(mask_a ^ ~mask_b) - - - return m - - def ports(self): - return [self.mb, self.me, self.o] diff --git a/src/soc/alu/rotator.py b/src/soc/alu/rotator.py deleted file mode 100644 index 7681692e..00000000 --- a/src/soc/alu/rotator.py +++ /dev/null @@ -1,154 +0,0 @@ -# Manual translation and adaptation of rotator.vhdl from microwatt into nmigen -# - -from nmigen import (Elaboratable, Signal, Module, Const, Cat) -from soc.alu.rotl import ROTL - -# note BE bit numbering -def right_mask(m, mask_begin): - """ this can be replaced by something like (mask_begin << 1) - 1""" - ret = Signal(64, name="right_mask", reset_less=True) - m.d.comb += ret.eq(0) - for i in range(64): - with m.If(i >= unsigned(mask_begin)): # set from i upwards - m.d.comb += ret[63 - i].eq(1) - return ret; - -def left_mask(m, mask_end): - """ this can be replaced by something like ~((mask_end << 1) - 1)""" - ret = Signal(64, name="left_mask", reset_less=True) - m.d.comb += ret.eq(0) - with m.If(mask_end[6] != 0): - return ret - for i in range(64): - with m.If(i <= unsigned(mask_end)): # set from i downwards - m.d.comb += ret[63 - i].eq(1) - return ret; - - -class Rotator(Elaboratable): - """Rotator: covers multiple POWER9 rotate functions - - supported modes: - - * sl[wd] - * rlw*, rldic, rldicr, rldimi - * rldicl, sr[wd] - * sra[wd][i] - - use as follows: - - * shift = RB[0:7] - * arith = 1 when is_signed - * right_shift = 1 when insn_type is OP_SHR - * clear_left = 1 when insn_type is OP_RLC or OP_RLCL - * clear_right = 1 when insn_type is OP_RLC or OP_RLCR - """ - def __init__(self): - # input - self.rs = Signal(64, reset_less=True) # RS - self.ra = Signal(64, reset_less=True) # RA - self.shift = Signal(7, reset_less=True) # RB[0:7] - self.insn = Signal(32, reset_less=True) # for mb and me fields - self.is_32bit = Signal(reset_less=True) - self.right_shift = Signal(reset_less=True) - self.arith = Signal(reset_less=True) - self.clear_left = Signal(reset_less=True) - self.clear_right = Signal(reset_less=True) - # output - self.result_o = Signal(64, reset_less=True) - self.carry_out_o = Signal(reset_less=True) - - def elaborate(self, platform): - m = Module() - comb = m.d.comb - ra, rs = self.ra, self.rs - - # temporaries - repl32 = Signal(64, reset_less=True) - rot_count = Signal(6, reset_less=True) - rot = Signal(64, reset_less=True) - sh = Signal(7, reset_less=True) - mb = Signal(7, reset_less=True) - me = Signal(7, reset_less=True) - mr = Signal(64, reset_less=True) - ml = Signal(64, reset_less=True) - output_mode = Signal(2, reset_less=True) - - # First replicate bottom 32 bits to both halves if 32-bit - comb += repl32[0:32].eq(rs[0:32]) - with m.If(self.is_32bit): - comb += repl32[32:64].eq(rs[0:32]) - - # Negate shift count for right shifts - with m.If(self.right_shift): - comb += rot_count.eq(-signed(self.shift[0:6])) - with m.Else(): - comb += rot_count.eq(self.shift[0:6]) - - # ROTL submodule - m.submodules.rotl = rotl = ROTL(64) - comb += rotl.a.eq(repl32) - comb += rotl.b.eq(rot_count) - comb += rot.eq(rotl.o) - - # Trim shift count to 6 bits for 32-bit shifts - comb += sh.eq(Cat(shift[0:6], shift[6] & ~self.is_32bit)) - - # XXX errr... we should already have these, in Fields? oh well - # Work out mask begin/end indexes (caution, big-endian bit numbering) - - # mask-begin (mb) - with m.If(self.clear_left): - with m.If(self.is_32bit): - comb += mb.eq(Cat(self.insn[6:11], Const(0b01, 2))) - with m.Else(): - comb += mb.eq(Cat(self.insn[6:11], self.insn[5], Const(0b0, 1))) - with m.Elif(self.right_shift): - # this is basically mb = sh + (is_32bit? 32: 0); - with m.If(self.is_32bit): - comb += mb.eq(Cat(sh[0:5], ~sh[5], sh[5])) - with m.Else(): - comb += mb.eq(sh) - with m.Else(): - comb += mb.eq(Cat(Const(0b0, 5), self.is_32bit, Const(0b0, 1))) - - # mask-end (me) - with m.If(self.clear_right & self.is_32bit): - comb += me.eq(Cat(self.insn[1:6], Const(0b01, 2))) - with m.Elif(self.clear_right & ~self.clear_left): - comb += me.eq(Cat(self.insn[6:11], self.insn[5], Const(0b0, 1))) - with m.Else(): - # effectively, 63 - sh - comb += me.eq(Cat(~shift[0:6], shift[6])) - - # Calculate left and right masks - comb += mr.eq(right_mask(m, mb)) - comb += ml.eq(left_mask(m, me)) - - # Work out output mode - # 00 for sl[wd] - # 0w for rlw*, rldic, rldicr, rldimi, where w = 1 iff mb > me - # 10 for rldicl, sr[wd] - # 1z for sra[wd][i], z = 1 if rs is negative - with m.If((self.clear_left & ~self.clear_right) | self.right_shift): - comb += output_mode.eq(Cat(self.arith & repl32[63], Const(1, 1)) - with m.Else(): - mbgt = self.clear_right & (unsigned(mb[0:6]) > unsigned(me[0:6])) - comb += output_mode.eq(Cat(mbgt, Const(0, 1)) - - # Generate output from rotated input and masks - with m.Switch(output_mode): - with m.Case(0b00): - comb += self.result_o.eq((rot & (mr & ml)) | (ra & ~(mr & ml))) - with m.Case(0b01): - comb += self.result_o.eq((rot & (mr | ml)) | (ra & ~(mr | ml))) - with m.Case(0b10): - comb += self.result_o.eq(rot & mr) - with m.Case(0b11): - comb += self.result_o.eq(rot | ~mr) - # Generate carry output for arithmetic shift right of -ve value - comb += self.carry_out_o.eq(rs & ~ml) - - return m - diff --git a/src/soc/alu/rotl.py b/src/soc/alu/rotl.py deleted file mode 100644 index d2ebfcf7..00000000 --- a/src/soc/alu/rotl.py +++ /dev/null @@ -1,24 +0,0 @@ -from nmigen import (Elaboratable, Signal, Module) -import math - -class ROTL(Elaboratable): - def __init__(self, width): - self.width = width - self.shiftwidth = math.ceil(math.log2(width)) - self.a = Signal(width, reset_less=True) - self.b = Signal(self.shiftwidth, reset_less=True) - - self.o = Signal(width, reset_less=True) - - def elaborate(self, platform): - m = Module() - comb = m.d.comb - - shl = Signal.like(self.a) - shr = Signal.like(self.a) - - comb += shl.eq(self.a << self.b) - comb += shr.eq(self.a >> (self.width - self.b)) - - comb += self.o.eq(shl | shr) - return m diff --git a/src/soc/alu/test/test_maskgen.py b/src/soc/alu/test/test_maskgen.py deleted file mode 100644 index f9d28d70..00000000 --- a/src/soc/alu/test/test_maskgen.py +++ /dev/null @@ -1,41 +0,0 @@ -from nmigen import Signal, Module -from nmigen.back.pysim import Simulator, Delay, Settle -from nmigen.test.utils import FHDLTestCase -from soc.alu.maskgen import MaskGen -from soc.decoder.helpers import MASK -import random -import unittest - -class MaskGenTestCase(FHDLTestCase): - def test_maskgen(self): - m = Module() - comb = m.d.comb - m.submodules.dut = dut = MaskGen(64) - mb = Signal.like(dut.mb) - me = Signal.like(dut.me) - o = Signal.like(dut.o) - - comb += [ - dut.mb.eq(mb), - dut.me.eq(me), - o.eq(dut.o)] - - sim = Simulator(m) - - def process(): - for x in range(0, 64): - for y in range(0, 64): - yield mb.eq(x) - yield me.eq(y) - yield Delay(1e-6) - - expected = MASK(x, y) - result = yield o - self.assertEqual(expected, result) - - sim.add_process(process) # or sim.add_sync_process(process), see below - with sim.write_vcd("maskgen.vcd", "maskgen.gtkw", traces=dut.ports()): - sim.run() - -if __name__ == '__main__': - unittest.main() diff --git a/src/soc/alu/test/test_pipe_caller.py b/src/soc/alu/test/test_pipe_caller.py index 3dcab75b..a31c5fe3 100644 --- a/src/soc/alu/test/test_pipe_caller.py +++ b/src/soc/alu/test/test_pipe_caller.py @@ -130,50 +130,6 @@ class ALUTestCase(FHDLTestCase): initial_regs = [0] * 32 initial_regs[1] = random.randint(0, (1<<64)-1) self.run_tst_program(Program(lst), initial_regs) - - def test_shift(self): - insns = ["slw", "sld", "srw", "srd", "sraw", "srad"] - for i in range(20): - choice = random.choice(insns) - lst = [f"{choice} 3, 1, 2"] - initial_regs = [0] * 32 - initial_regs[1] = random.randint(0, (1<<64)-1) - initial_regs[2] = random.randint(0, 63) - print(initial_regs[1], initial_regs[2]) - self.run_tst_program(Program(lst), initial_regs) - - - def test_shift_arith(self): - lst = ["sraw 3, 1, 2"] - initial_regs = [0] * 32 - initial_regs[1] = random.randint(0, (1<<64)-1) - initial_regs[2] = random.randint(0, 63) - print(initial_regs[1], initial_regs[2]) - self.run_tst_program(Program(lst), initial_regs) - - def test_rlwinm(self): - for i in range(10): - mb = random.randint(0,31) - me = random.randint(0,31) - sh = random.randint(0,31) - lst = [f"rlwinm 3, 1, {mb}, {me}, {sh}"] - initial_regs = [0] * 32 - initial_regs[1] = random.randint(0, (1<<64)-1) - self.run_tst_program(Program(lst), initial_regs) - - def test_rlwimi(self): - lst = ["rlwimi 3, 1, 5, 20, 6"] - initial_regs = [0] * 32 - initial_regs[1] = 0xdeadbeef - initial_regs[3] = 0x12345678 - self.run_tst_program(Program(lst), initial_regs) - - def test_rlwnm(self): - lst = ["rlwnm 3, 1, 2, 20, 6"] - initial_regs = [0] * 32 - initial_regs[1] = random.randint(0, (1<<64)-1) - initial_regs[2] = random.randint(0, 63) - self.run_tst_program(Program(lst), initial_regs) def test_adde(self): lst = ["adde. 5, 6, 7"] -- 2.30.2