Fix bug in rotator preventing use of 64 bit rlcl/r
[soc.git] / src / soc / shift_rot / main_stage.py
1 # This stage is intended to do most of the work of executing the ALU
2 # instructions. This would be like the additions, logical operations,
3 # and shifting, as well as carry and overflow generation. This module
4 # however should not gate the carry or overflow, that's up to the
5 # output stage
6 from nmigen import (Module, Signal, Cat, Repl, Mux, Const)
7 from nmutil.pipemodbase import PipeModBase
8 from soc.alu.pipe_data import ALUOutputData
9 from soc.shift_rot.pipe_data import ShiftRotInputData
10 from ieee754.part.partsig import PartitionedSignal
11 from soc.decoder.power_enums import InternalOp
12 from soc.shift_rot.rotator import Rotator
13
14 from soc.decoder.power_fields import DecodeFields
15 from soc.decoder.power_fieldsn import SignalBitRange
16
17
18 class ShiftRotMainStage(PipeModBase):
19 def __init__(self, pspec):
20 super().__init__(pspec, "main")
21 self.fields = DecodeFields(SignalBitRange, [self.i.ctx.op.insn])
22 self.fields.create_specs()
23
24 def ispec(self):
25 return ShiftRotInputData(self.pspec)
26
27 def ospec(self):
28 return ALUOutputData(self.pspec) # TODO: ALUIntermediateData
29
30 def elaborate(self, platform):
31 m = Module()
32 comb = m.d.comb
33
34 # obtain me and mb fields from instruction.
35 m_fields = self.fields.instrs['M']
36 md_fields = self.fields.instrs['MD']
37 mb = Signal(m_fields['MB'][0:-1].shape())
38 me = Signal(m_fields['ME'][0:-1].shape())
39 mb_extra = Signal(1)
40 comb += mb.eq(m_fields['MB'][0:-1])
41 comb += me.eq(m_fields['ME'][0:-1])
42 comb += mb_extra.eq(md_fields['mb'][0:-1][0])
43
44 # set up microwatt rotator module
45 m.submodules.rotator = rotator = Rotator()
46 comb += [
47 rotator.me.eq(me),
48 rotator.mb.eq(mb),
49 rotator.mb_extra.eq(mb_extra),
50 rotator.rs.eq(self.i.rs),
51 rotator.ra.eq(self.i.ra),
52 rotator.shift.eq(self.i.rb),
53 rotator.is_32bit.eq(self.i.ctx.op.is_32bit),
54 rotator.arith.eq(self.i.ctx.op.is_signed),
55 ]
56
57 # instruction rotate type
58 with m.Switch(self.i.ctx.op.insn_type):
59 with m.Case(InternalOp.OP_SHL):
60 comb += [rotator.right_shift.eq(0),
61 rotator.clear_left.eq(0),
62 rotator.clear_right.eq(0)]
63 with m.Case(InternalOp.OP_SHR):
64 comb += [rotator.right_shift.eq(1),
65 rotator.clear_left.eq(0),
66 rotator.clear_right.eq(0)]
67 with m.Case(InternalOp.OP_RLC):
68 comb += [rotator.right_shift.eq(0),
69 rotator.clear_left.eq(1),
70 rotator.clear_right.eq(1)]
71 with m.Case(InternalOp.OP_RLCL):
72 comb += [rotator.right_shift.eq(0),
73 rotator.clear_left.eq(1),
74 rotator.clear_right.eq(0)]
75 with m.Case(InternalOp.OP_RLCR):
76 comb += [rotator.right_shift.eq(0),
77 rotator.clear_left.eq(0),
78 rotator.clear_right.eq(1)]
79
80 # outputs from the microwatt rotator module
81 comb += [self.o.o.eq(rotator.result_o),
82 self.o.carry_out.eq(rotator.carry_out_o)]
83
84 ###### sticky overflow and context, both pass-through #####
85
86 comb += self.o.so.eq(self.i.so)
87 comb += self.o.ctx.eq(self.i.ctx)
88
89 return m