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
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)
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
#### 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 #####
+++ /dev/null
-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<<x) - 1)
- comb += mask_b.eq((1<<y) - 1)
-
- with m.If(x > 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]
+++ /dev/null
-# 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
-
+++ /dev/null
-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
+++ /dev/null
-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()
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"]