1 """Cascading Power ISA Decoder
3 This module uses CSV tables in a hierarchical/peer cascading fashion,
4 to create a multi-level instruction decoder by recognising appropriate
5 patterns. The output is a flattened (1-level) series of fields suitable
6 for a simple RISC engine.
8 This is based on Anton Blanchard's excellent microwatt work:
9 https://github.com/antonblanchard/microwatt/blob/master/decode1.vhdl
11 The basic principle is that the python code does the heavy lifting
12 (reading the CSV files, constructing the hierarchy), creating the HDL
13 AST with for-loops generating switch-case statements.
15 PowerDecoder takes a *list* of CSV files with an associated bit-range
16 that it is requested to match against the "opcode" row of the CSV file.
17 This pattern can be either an integer, a binary number, *or* a wildcard
18 nmigen Case pattern of the form "001--1-100".
20 Subdecoders are *additional* cases with further decoding. The "pattern"
21 argument is specified as one of the Case statements (a peer of the opcode
22 row in the CSV file), and thus further fields of the opcode may be decoded
23 giving increasing levels of detail.
27 [ (extra.csv: bit-fields entire 32-bit range
29 000000---------------01000000000 -> ILLEGAL instruction
30 01100000000000000000000000000000 -> SIM_CONFIG instruction
31 ................................ ->
33 (major.csv: first 6 bits ONLY
35 001100 -> ALU,OP_ADD (add)
36 001101 -> ALU,OP_ADD (another type of add)
40 001011 this must match *MAJOR*.CSV
41 [ (minor_19.csv: bits 21 through 30 inclusive:
43 0b0000000000 -> ALU,OP_MCRF
46 (minor_19_00000.csv: bits 21 through 25 inclusive:
48 0b00010 -> ALU,add_pcis
56 from collections
import namedtuple
57 from nmigen
import Module
, Elaboratable
, Signal
, Cat
, Mux
58 from nmigen
.cli
import rtlil
59 from soc
.decoder
.power_enums
import (Function
, Form
, InternalOp
,
60 In1Sel
, In2Sel
, In3Sel
, OutSel
, RC
, LdstLen
,
61 CryIn
, get_csv
, single_bit_flags
,
62 get_signal_name
, default_values
)
63 from collections
import namedtuple
64 from soc
.decoder
.power_fields
import DecodeFields
65 from soc
.decoder
.power_fieldsn
import SigDecode
, SignalBitRange
68 Subdecoder
= namedtuple("Subdecoder", ["pattern", "opcodes", "opint",
69 "bitsel", "suffix", "subdecoders"])
73 """PowerOp: spec for execution. op type (ADD etc.) reg specs etc.
77 self
.function_unit
= Signal(Function
, reset_less
=True)
78 self
.internal_op
= Signal(InternalOp
, reset_less
=True)
79 self
.form
= Signal(Form
, reset_less
=True)
80 self
.in1_sel
= Signal(In1Sel
, reset_less
=True)
81 self
.in2_sel
= Signal(In2Sel
, reset_less
=True)
82 self
.in3_sel
= Signal(In3Sel
, reset_less
=True)
83 self
.out_sel
= Signal(OutSel
, reset_less
=True)
84 self
.ldst_len
= Signal(LdstLen
, reset_less
=True)
85 self
.rc_sel
= Signal(RC
, reset_less
=True)
86 self
.cry_in
= Signal(CryIn
, reset_less
=True)
87 for bit
in single_bit_flags
:
88 name
= get_signal_name(bit
)
89 setattr(self
, name
, Signal(reset_less
=True, name
=name
))
91 def _eq(self
, row
=None):
94 res
= [self
.function_unit
.eq(Function
[row
['unit']]),
95 self
.form
.eq(Form
[row
['form']]),
96 self
.internal_op
.eq(InternalOp
[row
['internal op']]),
97 self
.in1_sel
.eq(In1Sel
[row
['in1']]),
98 self
.in2_sel
.eq(In2Sel
[row
['in2']]),
99 self
.in3_sel
.eq(In3Sel
[row
['in3']]),
100 self
.out_sel
.eq(OutSel
[row
['out']]),
101 self
.ldst_len
.eq(LdstLen
[row
['ldst len']]),
102 self
.rc_sel
.eq(RC
[row
['rc']]),
103 self
.cry_in
.eq(CryIn
[row
['cry in']]),
105 for bit
in single_bit_flags
:
106 sig
= getattr(self
, get_signal_name(bit
))
107 res
.append(sig
.eq(int(row
.get(bit
, 0))))
110 def eq(self
, otherop
):
111 res
= [self
.function_unit
.eq(otherop
.function_unit
),
112 self
.form
.eq(otherop
.form
),
113 self
.internal_op
.eq(otherop
.internal_op
),
114 self
.in1_sel
.eq(otherop
.in1_sel
),
115 self
.in2_sel
.eq(otherop
.in2_sel
),
116 self
.in3_sel
.eq(otherop
.in3_sel
),
117 self
.out_sel
.eq(otherop
.out_sel
),
118 self
.rc_sel
.eq(otherop
.rc_sel
),
119 self
.ldst_len
.eq(otherop
.ldst_len
),
120 self
.cry_in
.eq(otherop
.cry_in
)]
121 for bit
in single_bit_flags
:
122 sig
= getattr(self
, get_signal_name(bit
))
123 res
.append(sig
.eq(getattr(otherop
, get_signal_name(bit
))))
127 regular
= [self
.function_unit
,
136 single_bit_ports
= [getattr(self
, get_signal_name(x
))
137 for x
in single_bit_flags
]
138 return regular
+ single_bit_ports
141 class PowerDecoder(Elaboratable
):
142 """PowerDecoder - decodes an incoming opcode into the type of operation
145 def __init__(self
, width
, dec
):
146 if not isinstance(dec
, list):
149 self
.opcode_in
= Signal(width
, reset_less
=True)
153 if d
.suffix
is not None and d
.suffix
>= width
:
157 def suffix_mask(self
, d
):
158 return ((1 << d
.suffix
) - 1)
160 def divide_opcodes(self
, d
):
162 mask
= self
.suffix_mask(d
)
163 print("mask", hex(mask
))
164 for row
in d
.opcodes
:
165 opcode
= row
['opcode']
166 if d
.opint
and '-' not in opcode
:
167 opcode
= int(opcode
, 0)
169 opcode
= opcode
>> d
.suffix
170 if key
not in divided
:
174 divided
[key
].append(r
)
177 def elaborate(self
, platform
):
181 # note: default opcode is "illegal" as this is a combinatorial block
182 # this only works because OP_ILLEGAL=0 and the default (unset) is 0
184 # go through the list of CSV decoders first
186 opcode_switch
= Signal(d
.bitsel
[1] - d
.bitsel
[0],
188 comb
+= opcode_switch
.eq(self
.opcode_in
[d
.bitsel
[0]:d
.bitsel
[1]])
190 opcodes
= self
.divide_opcodes(d
)
191 opc_in
= Signal(d
.suffix
, reset_less
=True)
192 comb
+= opc_in
.eq(opcode_switch
[:d
.suffix
])
193 with m
.Switch(opc_in
):
194 for key
, row
in opcodes
.items():
195 bitsel
= (d
.suffix
+d
.bitsel
[0], d
.bitsel
[1])
196 sd
= Subdecoder(pattern
=None, opcodes
=row
,
197 bitsel
=bitsel
, suffix
=None,
198 opint
=False, subdecoders
=[])
199 subdecoder
= PowerDecoder(width
=32, dec
=sd
)
200 setattr(m
.submodules
, "dec_sub%d" % key
, subdecoder
)
201 comb
+= subdecoder
.opcode_in
.eq(self
.opcode_in
)
203 comb
+= self
.op
.eq(subdecoder
.op
)
205 # TODO: arguments, here (all of them) need to be a list.
206 # a for-loop around the *list* of decoder args.
207 with m
.Switch(opcode_switch
):
208 self
.handle_subdecoders(m
, d
)
209 for row
in d
.opcodes
:
210 opcode
= row
['opcode']
211 if d
.opint
and '-' not in opcode
:
212 opcode
= int(opcode
, 0)
216 comb
+= self
.op
._eq
(row
)
219 def handle_subdecoders(self
, m
, d
):
220 for dec
in d
.subdecoders
:
221 subdecoder
= PowerDecoder(self
.width
, dec
)
222 if isinstance(dec
, list): # XXX HACK: take first pattern
224 setattr(m
.submodules
, "dec%d" % dec
.pattern
, subdecoder
)
225 m
.d
.comb
+= subdecoder
.opcode_in
.eq(self
.opcode_in
)
226 with m
.Case(dec
.pattern
):
227 m
.d
.comb
+= self
.op
.eq(subdecoder
.op
)
230 return [self
.opcode_in
] + self
.op
.ports()
233 class TopPowerDecoder(PowerDecoder
):
236 top-level hierarchical decoder for POWER ISA
237 bigendian dynamically switches between big and little endian decoding
238 (reverses byte order). See V3.0B p44 1.11.2
241 def __init__(self
, width
, dec
):
242 PowerDecoder
.__init
__(self
, width
, dec
)
243 self
.fields
= df
= DecodeFields(SignalBitRange
, [self
.opcode_in
])
244 self
.fields
.create_specs()
245 self
.raw_opcode_in
= Signal
.like(self
.opcode_in
, reset_less
=True)
246 self
.bigendian
= Signal(reset_less
=True)
248 for name
in self
.fields
.common_fields
:
249 value
= getattr(self
.fields
, name
)
250 sig
= Signal(value
[0:-1].shape(), reset_less
=True, name
=name
)
251 setattr(self
, name
, sig
)
254 def elaborate(self
, platform
):
255 m
= PowerDecoder
.elaborate(self
, platform
)
257 raw_be
= self
.raw_opcode_in
259 for i
in range(0, self
.width
, 8):
260 l
.append(raw_be
[i
:i
+8])
263 comb
+= self
.opcode_in
.eq(Mux(self
.bigendian
, raw_be
, raw_le
))
265 # add all signal from commonly-used fields
266 for name
in self
.fields
.common_fields
:
267 value
= getattr(self
.fields
, name
)
268 sig
= getattr(self
, name
)
269 comb
+= sig
.eq(value
[0:-1])
271 # create signals for all field forms
272 self
.form_names
= forms
= self
.fields
.instrs
.keys()
275 fields
= self
.fields
.instrs
[form
]
277 Fields
= namedtuple("Fields", fk
)
279 for k
, value
in fields
.items():
280 name
= "%s_%s" % (form
, k
)
281 sig
= Signal(value
[0:-1].shape(), reset_less
=True, name
=name
)
283 comb
+= sig
.eq(value
[0:-1])
285 setattr(self
, "Form%s" % form
, instr
)
286 self
.sigforms
[form
] = instr
291 return [self
.raw_opcode_in
, self
.bigendian
] + PowerDecoder
.ports(self
)
294 def create_pdecode():
296 # minor 19 has extra patterns
298 m19
.append(Subdecoder(pattern
=19, opcodes
=get_csv("minor_19.csv"),
299 opint
=True, bitsel
=(1, 11), suffix
=None, subdecoders
=[]))
300 m19
.append(Subdecoder(pattern
=19, opcodes
=get_csv("minor_19_00000.csv"),
301 opint
=True, bitsel
=(1, 6), suffix
=None, subdecoders
=[]))
306 Subdecoder(pattern
=30, opcodes
=get_csv("minor_30.csv"),
307 opint
=True, bitsel
=(1, 6), suffix
=None, subdecoders
=[]),
308 Subdecoder(pattern
=31, opcodes
=get_csv("minor_31.csv"),
309 opint
=True, bitsel
=(1, 11), suffix
=0b00101, subdecoders
=[]),
310 Subdecoder(pattern
=58, opcodes
=get_csv("minor_58.csv"),
311 opint
=True, bitsel
=(0, 2), suffix
=None, subdecoders
=[]),
312 Subdecoder(pattern
=62, opcodes
=get_csv("minor_62.csv"),
313 opint
=True, bitsel
=(0, 2), suffix
=None, subdecoders
=[]),
316 # top level: extra merged with major
318 opcodes
= get_csv("major.csv")
319 dec
.append(Subdecoder(pattern
=None, opint
=True, opcodes
=opcodes
,
320 bitsel
=(26, 32), suffix
=None, subdecoders
=pminor
))
321 opcodes
= get_csv("extra.csv")
322 dec
.append(Subdecoder(pattern
=None, opint
=False, opcodes
=opcodes
,
323 bitsel
=(0, 32), suffix
=None, subdecoders
=[]))
325 return TopPowerDecoder(32, dec
)
328 if __name__
== '__main__':
329 pdecode
= create_pdecode()
330 vl
= rtlil
.convert(pdecode
, ports
=pdecode
.ports())
331 with
open("decoder.il", "w") as f
: