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 collections
import namedtuple
90 from soc
.decoder
.power_fields
import DecodeFields
91 from soc
.decoder
.power_fieldsn
import SigDecode
, SignalBitRange
94 # key data structure in which the POWER decoder is specified,
95 # in a hierarchical fashion
96 Subdecoder
= namedtuple("Subdecoder",
97 ["pattern", # the major pattern to search for (e.g. major opcode)
98 "opcodes", # a dictionary of minor patterns to find
99 "opint", # true => the pattern must not be in "10----11" format
100 "bitsel", # the bits (as a range) against which "pattern" matches
101 "suffix", # shift the opcode down before decoding
102 "subdecoders" # list of further subdecoders for *additional* matches,
103 # *ONLY* after "pattern" has *ALSO* been matched against.
108 """PowerOp: spec for execution. op type (ADD etc.) reg specs etc.
112 self
.function_unit
= Signal(Function
, reset_less
=True)
113 self
.internal_op
= Signal(InternalOp
, reset_less
=True)
114 self
.form
= Signal(Form
, reset_less
=True)
115 self
.in1_sel
= Signal(In1Sel
, reset_less
=True)
116 self
.in2_sel
= Signal(In2Sel
, reset_less
=True)
117 self
.in3_sel
= Signal(In3Sel
, reset_less
=True)
118 self
.out_sel
= Signal(OutSel
, reset_less
=True)
119 self
.ldst_len
= Signal(LdstLen
, reset_less
=True)
120 self
.rc_sel
= Signal(RC
, reset_less
=True)
121 self
.cry_in
= Signal(CryIn
, reset_less
=True)
122 for bit
in single_bit_flags
:
123 name
= get_signal_name(bit
)
124 setattr(self
, name
, Signal(reset_less
=True, name
=name
))
126 def _eq(self
, row
=None):
129 res
= [self
.function_unit
.eq(Function
[row
['unit']]),
130 self
.form
.eq(Form
[row
['form']]),
131 self
.internal_op
.eq(InternalOp
[row
['internal op']]),
132 self
.in1_sel
.eq(In1Sel
[row
['in1']]),
133 self
.in2_sel
.eq(In2Sel
[row
['in2']]),
134 self
.in3_sel
.eq(In3Sel
[row
['in3']]),
135 self
.out_sel
.eq(OutSel
[row
['out']]),
136 self
.ldst_len
.eq(LdstLen
[row
['ldst len']]),
137 self
.rc_sel
.eq(RC
[row
['rc']]),
138 self
.cry_in
.eq(CryIn
[row
['cry in']]),
140 for bit
in single_bit_flags
:
141 sig
= getattr(self
, get_signal_name(bit
))
142 res
.append(sig
.eq(int(row
.get(bit
, 0))))
145 def eq(self
, otherop
):
146 res
= [self
.function_unit
.eq(otherop
.function_unit
),
147 self
.form
.eq(otherop
.form
),
148 self
.internal_op
.eq(otherop
.internal_op
),
149 self
.in1_sel
.eq(otherop
.in1_sel
),
150 self
.in2_sel
.eq(otherop
.in2_sel
),
151 self
.in3_sel
.eq(otherop
.in3_sel
),
152 self
.out_sel
.eq(otherop
.out_sel
),
153 self
.rc_sel
.eq(otherop
.rc_sel
),
154 self
.ldst_len
.eq(otherop
.ldst_len
),
155 self
.cry_in
.eq(otherop
.cry_in
)]
156 for bit
in single_bit_flags
:
157 sig
= getattr(self
, get_signal_name(bit
))
158 res
.append(sig
.eq(getattr(otherop
, get_signal_name(bit
))))
162 regular
= [self
.function_unit
,
171 single_bit_ports
= [getattr(self
, get_signal_name(x
))
172 for x
in single_bit_flags
]
173 return regular
+ single_bit_ports
176 class PowerDecoder(Elaboratable
):
177 """PowerDecoder - decodes an incoming opcode into the type of operation
180 def __init__(self
, width
, dec
):
181 if not isinstance(dec
, list):
184 self
.opcode_in
= Signal(width
, reset_less
=True)
188 if d
.suffix
is not None and d
.suffix
>= width
:
192 def suffix_mask(self
, d
):
193 return ((1 << d
.suffix
) - 1)
195 def divide_opcodes(self
, d
):
197 mask
= self
.suffix_mask(d
)
198 print("mask", hex(mask
))
199 for row
in d
.opcodes
:
200 opcode
= row
['opcode']
201 if d
.opint
and '-' not in opcode
:
202 opcode
= int(opcode
, 0)
204 opcode
= opcode
>> d
.suffix
205 if key
not in divided
:
209 divided
[key
].append(r
)
212 def elaborate(self
, platform
):
216 # note: default opcode is "illegal" as this is a combinatorial block
217 # this only works because OP_ILLEGAL=0 and the default (unset) is 0
219 # go through the list of CSV decoders first
221 opcode_switch
= Signal(d
.bitsel
[1] - d
.bitsel
[0],
223 comb
+= opcode_switch
.eq(self
.opcode_in
[d
.bitsel
[0]:d
.bitsel
[1]])
225 opcodes
= self
.divide_opcodes(d
)
226 opc_in
= Signal(d
.suffix
, reset_less
=True)
227 comb
+= opc_in
.eq(opcode_switch
[:d
.suffix
])
228 # begin the dynamic Switch statement here
229 with m
.Switch(opc_in
):
230 for key
, row
in opcodes
.items():
231 bitsel
= (d
.suffix
+d
.bitsel
[0], d
.bitsel
[1])
232 sd
= Subdecoder(pattern
=None, opcodes
=row
,
233 bitsel
=bitsel
, suffix
=None,
234 opint
=False, subdecoders
=[])
235 subdecoder
= PowerDecoder(width
=32, dec
=sd
)
236 setattr(m
.submodules
, "dec_sub%d" % key
, subdecoder
)
237 comb
+= subdecoder
.opcode_in
.eq(self
.opcode_in
)
238 # add in the dynamic Case statement here
240 comb
+= self
.op
.eq(subdecoder
.op
)
242 # TODO: arguments, here (all of them) need to be a list.
243 # a for-loop around the *list* of decoder args.
244 with m
.Switch(opcode_switch
):
245 self
.handle_subdecoders(m
, d
)
246 for row
in d
.opcodes
:
247 opcode
= row
['opcode']
248 if d
.opint
and '-' not in opcode
:
249 opcode
= int(opcode
, 0)
252 # add in the dynamic Case statement here
254 comb
+= self
.op
._eq
(row
)
257 def handle_subdecoders(self
, m
, d
):
258 for dec
in d
.subdecoders
:
259 subdecoder
= PowerDecoder(self
.width
, dec
)
260 if isinstance(dec
, list): # XXX HACK: take first pattern
262 setattr(m
.submodules
, "dec%d" % dec
.pattern
, subdecoder
)
263 m
.d
.comb
+= subdecoder
.opcode_in
.eq(self
.opcode_in
)
264 with m
.Case(dec
.pattern
):
265 m
.d
.comb
+= self
.op
.eq(subdecoder
.op
)
268 return [self
.opcode_in
] + self
.op
.ports()
271 class TopPowerDecoder(PowerDecoder
):
274 top-level hierarchical decoder for POWER ISA
275 bigendian dynamically switches between big and little endian decoding
276 (reverses byte order). See V3.0B p44 1.11.2
279 def __init__(self
, width
, dec
):
280 PowerDecoder
.__init
__(self
, width
, dec
)
281 self
.fields
= df
= DecodeFields(SignalBitRange
, [self
.opcode_in
])
282 self
.fields
.create_specs()
283 self
.raw_opcode_in
= Signal
.like(self
.opcode_in
, reset_less
=True)
284 self
.bigendian
= Signal(reset_less
=True)
286 for name
, value
in self
.fields
.common_fields
.items():
287 sig
= Signal(value
[0:-1].shape(), reset_less
=True, name
=name
)
288 setattr(self
, name
, sig
)
290 # create signals for all field forms
291 self
.form_names
= forms
= self
.fields
.instrs
.keys()
294 fields
= self
.fields
.instrs
[form
]
296 Fields
= namedtuple("Fields", fk
)
298 for k
, value
in fields
.items():
299 name
= "%s_%s" % (form
, k
)
300 sig
= Signal(value
[0:-1].shape(), reset_less
=True, name
=name
)
303 setattr(self
, "Form%s" % form
, instr
)
304 self
.sigforms
[form
] = instr
306 def elaborate(self
, platform
):
307 m
= PowerDecoder
.elaborate(self
, platform
)
309 raw_be
= self
.raw_opcode_in
311 for i
in range(0, self
.width
, 8):
312 l
.append(raw_be
[i
:i
+8])
315 comb
+= self
.opcode_in
.eq(Mux(self
.bigendian
, raw_be
, raw_le
))
317 # add all signal from commonly-used fields
318 for name
, value
in self
.fields
.common_fields
.items():
319 sig
= getattr(self
, name
)
320 comb
+= sig
.eq(value
[0:-1])
322 # link signals for all field forms
323 forms
= self
.form_names
325 sf
= self
.sigforms
[form
]
326 fields
= self
.fields
.instrs
[form
]
327 for k
, value
in fields
.items():
329 comb
+= sig
.eq(value
[0:-1])
334 return [self
.raw_opcode_in
, self
.bigendian
] + PowerDecoder
.ports(self
)
337 ####################################################
338 # PRIMARY FUNCTION SPECIFYING THE FULL POWER DECODER
340 def create_pdecode():
341 """create_pdecode - creates a cascading hierarchical POWER ISA decoder
344 # minor 19 has extra patterns
346 m19
.append(Subdecoder(pattern
=19, opcodes
=get_csv("minor_19.csv"),
347 opint
=True, bitsel
=(1, 11), suffix
=None, subdecoders
=[]))
348 m19
.append(Subdecoder(pattern
=19, opcodes
=get_csv("minor_19_00000.csv"),
349 opint
=True, bitsel
=(1, 6), suffix
=None, subdecoders
=[]))
354 Subdecoder(pattern
=30, opcodes
=get_csv("minor_30.csv"),
355 opint
=True, bitsel
=(1, 6), suffix
=None, subdecoders
=[]),
356 Subdecoder(pattern
=31, opcodes
=get_csv("minor_31.csv"),
357 opint
=True, bitsel
=(1, 11), suffix
=0b00101, subdecoders
=[]),
358 Subdecoder(pattern
=58, opcodes
=get_csv("minor_58.csv"),
359 opint
=True, bitsel
=(0, 2), suffix
=None, subdecoders
=[]),
360 Subdecoder(pattern
=62, opcodes
=get_csv("minor_62.csv"),
361 opint
=True, bitsel
=(0, 2), suffix
=None, subdecoders
=[]),
364 # top level: extra merged with major
366 opcodes
= get_csv("major.csv")
367 dec
.append(Subdecoder(pattern
=None, opint
=True, opcodes
=opcodes
,
368 bitsel
=(26, 32), suffix
=None, subdecoders
=pminor
))
369 opcodes
= get_csv("extra.csv")
370 dec
.append(Subdecoder(pattern
=None, opint
=False, opcodes
=opcodes
,
371 bitsel
=(0, 32), suffix
=None, subdecoders
=[]))
373 return TopPowerDecoder(32, dec
)
376 if __name__
== '__main__':
377 pdecode
= create_pdecode()
378 vl
= rtlil
.convert(pdecode
, ports
=pdecode
.ports())
379 with
open("decoder.il", "w") as f
: