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 wide, flattened (1-level) series of bitfields,
6 suitable 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 Where "normal" HDL would do this, in laborious excruciating detail:
17 switch (opcode & major_mask_bits):
18 case opcode_2: decode_opcode_2()
20 switch (opcode & minor_19_mask_bits)
21 case minor_opcode_19_operation_X:
22 case minor_opcode_19_operation_y:
24 we take *full* advantage of the decoupling between python and the
25 nmigen AST data structure, to do this:
27 with m.Switch(opcode & self.mask):
28 for case_bitmask in subcases:
29 with m.If(opcode & case_bitmask): {do_something}
31 this includes specifying the information sufficient to perform subdecoding.
35 the full hierarchical tree for decoding POWER9 is specified here
39 takes a *list* of CSV files with an associated bit-range that it
40 is requested to match against the "opcode" row of the CSV file.
41 This pattern can be either an integer, a binary number, *or* a
42 wildcard nmigen Case pattern of the form "001--1-100".
46 these are *additional* cases with further decoding. The "pattern"
47 argument is specified as one of the Case statements (a peer of the
48 opcode row in the CSV file), and thus further fields of the opcode
49 may be decoded giving increasing levels of detail.
53 [ (extra.csv: bit-fields entire 32-bit range
55 000000---------------01000000000 -> ILLEGAL instruction
56 01100000000000000000000000000000 -> SIM_CONFIG instruction
57 ................................ ->
59 (major.csv: first 6 bits ONLY
61 001100 -> ALU,OP_ADD (add)
62 001101 -> ALU,OP_ADD (another type of add)
66 001011 this must match *MAJOR*.CSV
67 [ (minor_19.csv: bits 21 through 30 inclusive:
69 0b0000000000 -> ALU,OP_MCRF
72 (minor_19_00000.csv: bits 21 through 25 inclusive:
74 0b00010 -> ALU,add_pcis
82 from collections
import namedtuple
83 from nmigen
import Module
, Elaboratable
, Signal
, Cat
, Mux
84 from nmigen
.cli
import rtlil
85 from soc
.decoder
.power_enums
import (Function
, Form
, InternalOp
,
86 In1Sel
, In2Sel
, In3Sel
, OutSel
, RC
, LdstLen
,
87 CryIn
, get_csv
, single_bit_flags
,
88 get_signal_name
, default_values
)
89 from soc
.decoder
.power_fields
import DecodeFields
90 from soc
.decoder
.power_fieldsn
import SigDecode
, SignalBitRange
93 # key data structure in which the POWER decoder is specified,
94 # in a hierarchical fashion
95 Subdecoder
= namedtuple("Subdecoder",
96 ["pattern", # the major pattern to search for (e.g. major opcode)
97 "opcodes", # a dictionary of minor patterns to find
98 "opint", # true => the pattern must not be in "10----11" format
99 "bitsel", # the bits (as a range) against which "pattern" matches
100 "suffix", # shift the opcode down before decoding
101 "subdecoders" # list of further subdecoders for *additional* matches,
102 # *ONLY* after "pattern" has *ALSO* been matched against.
107 """PowerOp: spec for execution. op type (ADD etc.) reg specs etc.
111 self
.function_unit
= Signal(Function
, reset_less
=True)
112 self
.internal_op
= Signal(InternalOp
, reset_less
=True)
113 self
.form
= Signal(Form
, reset_less
=True)
114 self
.in1_sel
= Signal(In1Sel
, reset_less
=True)
115 self
.in2_sel
= Signal(In2Sel
, reset_less
=True)
116 self
.in3_sel
= Signal(In3Sel
, reset_less
=True)
117 self
.out_sel
= Signal(OutSel
, reset_less
=True)
118 self
.ldst_len
= Signal(LdstLen
, reset_less
=True)
119 self
.rc_sel
= Signal(RC
, reset_less
=True)
120 self
.cry_in
= Signal(CryIn
, reset_less
=True)
121 for bit
in single_bit_flags
:
122 name
= get_signal_name(bit
)
123 setattr(self
, name
, Signal(reset_less
=True, name
=name
))
125 def _eq(self
, row
=None):
128 res
= [self
.function_unit
.eq(Function
[row
['unit']]),
129 self
.form
.eq(Form
[row
['form']]),
130 self
.internal_op
.eq(InternalOp
[row
['internal op']]),
131 self
.in1_sel
.eq(In1Sel
[row
['in1']]),
132 self
.in2_sel
.eq(In2Sel
[row
['in2']]),
133 self
.in3_sel
.eq(In3Sel
[row
['in3']]),
134 self
.out_sel
.eq(OutSel
[row
['out']]),
135 self
.ldst_len
.eq(LdstLen
[row
['ldst len']]),
136 self
.rc_sel
.eq(RC
[row
['rc']]),
137 self
.cry_in
.eq(CryIn
[row
['cry in']]),
139 for bit
in single_bit_flags
:
140 sig
= getattr(self
, get_signal_name(bit
))
141 res
.append(sig
.eq(int(row
.get(bit
, 0))))
144 def eq(self
, otherop
):
145 res
= [self
.function_unit
.eq(otherop
.function_unit
),
146 self
.form
.eq(otherop
.form
),
147 self
.internal_op
.eq(otherop
.internal_op
),
148 self
.in1_sel
.eq(otherop
.in1_sel
),
149 self
.in2_sel
.eq(otherop
.in2_sel
),
150 self
.in3_sel
.eq(otherop
.in3_sel
),
151 self
.out_sel
.eq(otherop
.out_sel
),
152 self
.rc_sel
.eq(otherop
.rc_sel
),
153 self
.ldst_len
.eq(otherop
.ldst_len
),
154 self
.cry_in
.eq(otherop
.cry_in
)]
155 for bit
in single_bit_flags
:
156 sig
= getattr(self
, get_signal_name(bit
))
157 res
.append(sig
.eq(getattr(otherop
, get_signal_name(bit
))))
161 regular
= [self
.function_unit
,
170 single_bit_ports
= [getattr(self
, get_signal_name(x
))
171 for x
in single_bit_flags
]
172 return regular
+ single_bit_ports
175 class PowerDecoder(Elaboratable
):
176 """PowerDecoder - decodes an incoming opcode into the type of operation
179 def __init__(self
, width
, dec
):
180 if not isinstance(dec
, list):
183 self
.opcode_in
= Signal(width
, reset_less
=True)
187 if d
.suffix
is not None and d
.suffix
>= width
:
191 def suffix_mask(self
, d
):
192 return ((1 << d
.suffix
) - 1)
194 def divide_opcodes(self
, d
):
196 mask
= self
.suffix_mask(d
)
197 print("mask", hex(mask
))
198 for row
in d
.opcodes
:
199 opcode
= row
['opcode']
200 if d
.opint
and '-' not in opcode
:
201 opcode
= int(opcode
, 0)
203 opcode
= opcode
>> d
.suffix
204 if key
not in divided
:
208 divided
[key
].append(r
)
211 def elaborate(self
, platform
):
215 # note: default opcode is "illegal" as this is a combinatorial block
216 # this only works because OP_ILLEGAL=0 and the default (unset) is 0
218 # go through the list of CSV decoders first
220 opcode_switch
= Signal(d
.bitsel
[1] - d
.bitsel
[0],
222 comb
+= opcode_switch
.eq(self
.opcode_in
[d
.bitsel
[0]:d
.bitsel
[1]])
224 opcodes
= self
.divide_opcodes(d
)
225 opc_in
= Signal(d
.suffix
, reset_less
=True)
226 comb
+= opc_in
.eq(opcode_switch
[:d
.suffix
])
227 # begin the dynamic Switch statement here
228 with m
.Switch(opc_in
):
229 for key
, row
in opcodes
.items():
230 bitsel
= (d
.suffix
+d
.bitsel
[0], d
.bitsel
[1])
231 sd
= Subdecoder(pattern
=None, opcodes
=row
,
232 bitsel
=bitsel
, suffix
=None,
233 opint
=False, subdecoders
=[])
234 subdecoder
= PowerDecoder(width
=32, dec
=sd
)
235 setattr(m
.submodules
, "dec_sub%d" % key
, subdecoder
)
236 comb
+= subdecoder
.opcode_in
.eq(self
.opcode_in
)
237 # add in the dynamic Case statement here
239 comb
+= self
.op
.eq(subdecoder
.op
)
241 # TODO: arguments, here (all of them) need to be a list.
242 # a for-loop around the *list* of decoder args.
243 with m
.Switch(opcode_switch
):
244 self
.handle_subdecoders(m
, d
)
245 for row
in d
.opcodes
:
246 opcode
= row
['opcode']
247 if d
.opint
and '-' not in opcode
:
248 opcode
= int(opcode
, 0)
251 # add in the dynamic Case statement here
253 comb
+= self
.op
._eq
(row
)
256 def handle_subdecoders(self
, m
, d
):
257 for dec
in d
.subdecoders
:
258 subdecoder
= PowerDecoder(self
.width
, dec
)
259 if isinstance(dec
, list): # XXX HACK: take first pattern
261 setattr(m
.submodules
, "dec%d" % dec
.pattern
, subdecoder
)
262 m
.d
.comb
+= subdecoder
.opcode_in
.eq(self
.opcode_in
)
263 with m
.Case(dec
.pattern
):
264 m
.d
.comb
+= self
.op
.eq(subdecoder
.op
)
267 return [self
.opcode_in
] + self
.op
.ports()
270 class TopPowerDecoder(PowerDecoder
):
273 top-level hierarchical decoder for POWER ISA
274 bigendian dynamically switches between big and little endian decoding
275 (reverses byte order). See V3.0B p44 1.11.2
278 def __init__(self
, width
, dec
):
279 PowerDecoder
.__init
__(self
, width
, dec
)
280 self
.fields
= df
= DecodeFields(SignalBitRange
, [self
.opcode_in
])
281 self
.fields
.create_specs()
282 self
.raw_opcode_in
= Signal
.like(self
.opcode_in
, reset_less
=True)
283 self
.bigendian
= Signal(reset_less
=True)
285 for name
, value
in self
.fields
.common_fields
.items():
286 sig
= Signal(value
[0:-1].shape(), reset_less
=True, name
=name
)
287 setattr(self
, name
, sig
)
289 # create signals for all field forms
290 self
.form_names
= forms
= self
.fields
.instrs
.keys()
293 fields
= self
.fields
.instrs
[form
]
295 Fields
= namedtuple("Fields", fk
)
297 for k
, value
in fields
.items():
298 name
= "%s_%s" % (form
, k
)
299 sig
= Signal(value
[0:-1].shape(), reset_less
=True, name
=name
)
302 setattr(self
, "Form%s" % form
, instr
)
303 self
.sigforms
[form
] = instr
305 def elaborate(self
, platform
):
306 m
= PowerDecoder
.elaborate(self
, platform
)
308 raw_be
= self
.raw_opcode_in
310 for i
in range(0, self
.width
, 8):
311 l
.append(raw_be
[i
:i
+8])
314 comb
+= self
.opcode_in
.eq(Mux(self
.bigendian
, raw_be
, raw_le
))
316 # add all signal from commonly-used fields
317 for name
, value
in self
.fields
.common_fields
.items():
318 sig
= getattr(self
, name
)
319 comb
+= sig
.eq(value
[0:-1])
321 # link signals for all field forms
322 forms
= self
.form_names
324 sf
= self
.sigforms
[form
]
325 fields
= self
.fields
.instrs
[form
]
326 for k
, value
in fields
.items():
328 comb
+= sig
.eq(value
[0:-1])
333 return [self
.raw_opcode_in
, self
.bigendian
] + PowerDecoder
.ports(self
)
336 ####################################################
337 # PRIMARY FUNCTION SPECIFYING THE FULL POWER DECODER
339 def create_pdecode():
340 """create_pdecode - creates a cascading hierarchical POWER ISA decoder
343 # minor 19 has extra patterns
345 m19
.append(Subdecoder(pattern
=19, opcodes
=get_csv("minor_19.csv"),
346 opint
=True, bitsel
=(1, 11), suffix
=None, subdecoders
=[]))
347 m19
.append(Subdecoder(pattern
=19, opcodes
=get_csv("minor_19_00000.csv"),
348 opint
=True, bitsel
=(1, 6), suffix
=None, subdecoders
=[]))
353 Subdecoder(pattern
=30, opcodes
=get_csv("minor_30.csv"),
354 opint
=True, bitsel
=(1, 6), suffix
=None, subdecoders
=[]),
355 Subdecoder(pattern
=31, opcodes
=get_csv("minor_31.csv"),
356 opint
=True, bitsel
=(1, 11), suffix
=0b00101, subdecoders
=[]),
357 Subdecoder(pattern
=58, opcodes
=get_csv("minor_58.csv"),
358 opint
=True, bitsel
=(0, 2), suffix
=None, subdecoders
=[]),
359 Subdecoder(pattern
=62, opcodes
=get_csv("minor_62.csv"),
360 opint
=True, bitsel
=(0, 2), suffix
=None, subdecoders
=[]),
363 # top level: extra merged with major
365 opcodes
= get_csv("major.csv")
366 dec
.append(Subdecoder(pattern
=None, opint
=True, opcodes
=opcodes
,
367 bitsel
=(26, 32), suffix
=None, subdecoders
=pminor
))
368 opcodes
= get_csv("extra.csv")
369 dec
.append(Subdecoder(pattern
=None, opint
=False, opcodes
=opcodes
,
370 bitsel
=(0, 32), suffix
=None, subdecoders
=[]))
372 return TopPowerDecoder(32, dec
)
375 if __name__
== '__main__':
376 pdecode
= create_pdecode()
377 vl
= rtlil
.convert(pdecode
, ports
=pdecode
.ports())
378 with
open("decoder.il", "w") as f
: