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