2 # Copyright (C) 2020 Michael Nolan <mtnolan2640@gmail.com>
3 # Copyright (C) 2020 Luke Kenneth Casson Leighton <lkcl@lkcl.net>
5 # This stage is intended to do most of the work of executing shift
6 # instructions, as well as carry and overflow generation. This module
7 # however should not gate the carry or overflow, that's up to the
9 from nmigen
import (Module
, Signal
, Cat
, Repl
, Mux
, Const
)
10 from nmutil
.pipemodbase
import PipeModBase
11 from soc
.fu
.pipe_data
import get_pspec_draft_bitmanip
12 from soc
.fu
.shift_rot
.pipe_data
import (ShiftRotOutputData
,
14 from nmutil
.lut
import BitwiseLut
15 from nmutil
.grev
import GRev
16 from openpower
.decoder
.power_enums
import MicrOp
17 from soc
.fu
.shift_rot
.rotator
import Rotator
19 from openpower
.decoder
.power_fields
import DecodeFields
20 from openpower
.decoder
.power_fieldsn
import SignalBitRange
23 class ShiftRotMainStage(PipeModBase
):
24 def __init__(self
, pspec
):
25 super().__init
__(pspec
, "main")
26 self
.draft_bitmanip
= get_pspec_draft_bitmanip(pspec
)
27 self
.fields
= DecodeFields(SignalBitRange
, [self
.i
.ctx
.op
.insn
])
28 self
.fields
.create_specs()
31 return ShiftRotInputData(self
.pspec
)
34 return ShiftRotOutputData(self
.pspec
)
36 def elaborate(self
, platform
):
37 XLEN
= self
.pspec
.XLEN
45 if self
.draft_bitmanip
:
46 bitwise_lut
= BitwiseLut(input_count
=3, width
=XLEN
)
47 m
.submodules
.bitwise_lut
= bitwise_lut
48 comb
+= bitwise_lut
.inputs
[0].eq(self
.i
.rb
)
49 comb
+= bitwise_lut
.inputs
[1].eq(self
.i
.ra
)
50 comb
+= bitwise_lut
.inputs
[2].eq(self
.i
.rc
)
51 # 6 == log2(64) because we have 64-bit values
52 grev
= GRev(log2_width
=(XLEN
-1).bit_length())
53 m
.submodules
.grev
= grev
54 with m
.If(op
.is_32bit
):
55 # 32-bit, so input is lower 32-bits zero-extended
56 comb
+= grev
.input.eq(self
.i
.ra
[0:32])
57 # 32-bit, so we only feed in log2(32) == 5 bits
58 comb
+= grev
.chunk_sizes
.eq(self
.i
.rb
[0:5])
60 comb
+= grev
.input.eq(self
.i
.ra
)
61 comb
+= grev
.chunk_sizes
.eq(self
.i
.rb
)
63 # NOTE: the sh field immediate is read in by PowerDecode2
64 # (actually DecodeRB), whereupon by way of rb "immediate" mode
65 # it ends up in self.i.rb.
67 # obtain me and mb fields from instruction.
68 m_fields
= self
.fields
.instrs
['M']
69 md_fields
= self
.fields
.instrs
['MD']
70 mb
= Signal(m_fields
['MB'][0:-1].shape())
71 me
= Signal(m_fields
['ME'][0:-1].shape())
72 mb_extra
= Signal(1, reset_less
=True)
73 comb
+= mb
.eq(m_fields
['MB'][0:-1])
74 comb
+= me
.eq(m_fields
['ME'][0:-1])
75 comb
+= mb_extra
.eq(md_fields
['mb'][0:-1][0])
77 # set up microwatt rotator module
78 m
.submodules
.rotator
= rotator
= Rotator(XLEN
)
82 rotator
.mb_extra
.eq(mb_extra
),
83 rotator
.rs
.eq(self
.i
.rs
),
84 rotator
.ra
.eq(self
.i
.a
),
85 rotator
.shift
.eq(self
.i
.rb
), # can also be sh (in immediate mode)
86 rotator
.is_32bit
.eq(op
.is_32bit
),
87 rotator
.arith
.eq(op
.is_signed
),
90 comb
+= o
.ok
.eq(1) # defaults to enabled
92 # instruction rotate type
93 mode
= Signal(4, reset_less
=True)
94 comb
+= Cat(rotator
.right_shift
,
97 rotator
.sign_ext_rs
).eq(mode
)
99 # outputs from the microwatt rotator module
100 comb
+= [o
.data
.eq(rotator
.result_o
),
101 self
.o
.xer_ca
.data
.eq(Repl(rotator
.carry_out_o
, 2))]
103 with m
.Switch(op
.insn_type
):
104 with m
.Case(MicrOp
.OP_SHL
):
105 comb
+= mode
.eq(0b0000) # L-shift
106 with m
.Case(MicrOp
.OP_SHR
):
107 comb
+= mode
.eq(0b0001) # R-shift
108 with m
.Case(MicrOp
.OP_RLC
):
109 comb
+= mode
.eq(0b0110) # clear LR
110 with m
.Case(MicrOp
.OP_RLCL
):
111 comb
+= mode
.eq(0b0010) # clear L
112 with m
.Case(MicrOp
.OP_RLCR
):
113 comb
+= mode
.eq(0b0100) # clear R
114 with m
.Case(MicrOp
.OP_EXTSWSLI
):
115 comb
+= mode
.eq(0b1000) # L-ext
116 if self
.draft_bitmanip
:
117 with m
.Case(MicrOp
.OP_TERNLOG
):
118 # TODO: this only works for ternlogi, change to get lut
119 # value from register when we implement other variants
120 comb
+= bitwise_lut
.lut
.eq(self
.fields
.FormTLI
.TLI
[:])
121 comb
+= o
.data
.eq(bitwise_lut
.output
)
122 comb
+= self
.o
.xer_ca
.data
.eq(0)
123 with m
.Case(MicrOp
.OP_GREV
):
124 comb
+= o
.data
.eq(grev
.output
)
125 comb
+= self
.o
.xer_ca
.data
.eq(0)
127 comb
+= o
.ok
.eq(0) # otherwise disable
129 ###### sticky overflow and context, both pass-through #####
131 comb
+= self
.o
.xer_so
.data
.eq(self
.i
.xer_so
)
132 comb
+= self
.o
.ctx
.eq(self
.i
.ctx
)