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 nmigen
import Module
, Elaboratable
, Signal
, Cat
, Mux
57 from nmigen
.cli
import rtlil
58 from soc
.decoder
.power_enums
import (Function
, Form
, InternalOp
,
59 In1Sel
, In2Sel
, In3Sel
, OutSel
, RC
, LdstLen
,
60 CryIn
, get_csv
, single_bit_flags
,
61 get_signal_name
, default_values
)
62 from collections
import namedtuple
63 from soc
.decoder
.power_fields
import DecodeFields
64 from soc
.decoder
.power_fieldsn
import SigDecode
, SignalBitRange
67 Subdecoder
= namedtuple("Subdecoder", ["pattern", "opcodes", "opint",
68 "bitsel", "suffix", "subdecoders"])
72 """PowerOp: spec for execution. op type (ADD etc.) reg specs etc.
76 self
.function_unit
= Signal(Function
, reset_less
=True)
77 self
.internal_op
= Signal(InternalOp
, reset_less
=True)
78 self
.form
= Signal(Form
, reset_less
=True)
79 self
.in1_sel
= Signal(In1Sel
, reset_less
=True)
80 self
.in2_sel
= Signal(In2Sel
, reset_less
=True)
81 self
.in3_sel
= Signal(In3Sel
, reset_less
=True)
82 self
.out_sel
= Signal(OutSel
, reset_less
=True)
83 self
.ldst_len
= Signal(LdstLen
, reset_less
=True)
84 self
.rc_sel
= Signal(RC
, reset_less
=True)
85 self
.cry_in
= Signal(CryIn
, reset_less
=True)
86 for bit
in single_bit_flags
:
87 name
= get_signal_name(bit
)
88 setattr(self
, name
, Signal(reset_less
=True, name
=name
))
90 def _eq(self
, row
=None):
93 res
= [self
.function_unit
.eq(Function
[row
['unit']]),
94 self
.form
.eq(Form
[row
['form']]),
95 self
.internal_op
.eq(InternalOp
[row
['internal op']]),
96 self
.in1_sel
.eq(In1Sel
[row
['in1']]),
97 self
.in2_sel
.eq(In2Sel
[row
['in2']]),
98 self
.in3_sel
.eq(In3Sel
[row
['in3']]),
99 self
.out_sel
.eq(OutSel
[row
['out']]),
100 self
.ldst_len
.eq(LdstLen
[row
['ldst len']]),
101 self
.rc_sel
.eq(RC
[row
['rc']]),
102 self
.cry_in
.eq(CryIn
[row
['cry in']]),
104 for bit
in single_bit_flags
:
105 sig
= getattr(self
, get_signal_name(bit
))
106 res
.append(sig
.eq(int(row
.get(bit
, 0))))
109 def eq(self
, otherop
):
110 res
= [self
.function_unit
.eq(otherop
.function_unit
),
111 self
.form
.eq(otherop
.form
),
112 self
.internal_op
.eq(otherop
.internal_op
),
113 self
.in1_sel
.eq(otherop
.in1_sel
),
114 self
.in2_sel
.eq(otherop
.in2_sel
),
115 self
.in3_sel
.eq(otherop
.in3_sel
),
116 self
.out_sel
.eq(otherop
.out_sel
),
117 self
.rc_sel
.eq(otherop
.rc_sel
),
118 self
.ldst_len
.eq(otherop
.ldst_len
),
119 self
.cry_in
.eq(otherop
.cry_in
)]
120 for bit
in single_bit_flags
:
121 sig
= getattr(self
, get_signal_name(bit
))
122 res
.append(sig
.eq(getattr(otherop
, get_signal_name(bit
))))
126 regular
= [self
.function_unit
,
135 single_bit_ports
= [getattr(self
, get_signal_name(x
))
136 for x
in single_bit_flags
]
137 return regular
+ single_bit_ports
140 class PowerDecoder(Elaboratable
):
141 """PowerDecoder - decodes an incoming opcode into the type of operation
144 def __init__(self
, width
, dec
):
145 if not isinstance(dec
, list):
148 self
.opcode_in
= Signal(width
, reset_less
=True)
152 if d
.suffix
is not None and d
.suffix
>= width
:
156 def suffix_mask(self
, d
):
157 return ((1 << d
.suffix
) - 1)
159 def divide_opcodes(self
, d
):
161 mask
= self
.suffix_mask(d
)
162 print("mask", hex(mask
))
163 for row
in d
.opcodes
:
164 opcode
= row
['opcode']
165 if d
.opint
and '-' not in opcode
:
166 opcode
= int(opcode
, 0)
168 opcode
= opcode
>> d
.suffix
169 if key
not in divided
:
173 divided
[key
].append(r
)
176 def elaborate(self
, platform
):
180 # note: default opcode is "illegal" as this is a combinatorial block
181 # this only works because OP_ILLEGAL=0 and the default (unset) is 0
183 # go through the list of CSV decoders first
185 opcode_switch
= Signal(d
.bitsel
[1] - d
.bitsel
[0],
187 comb
+= opcode_switch
.eq(self
.opcode_in
[d
.bitsel
[0]:d
.bitsel
[1]])
189 opcodes
= self
.divide_opcodes(d
)
190 opc_in
= Signal(d
.suffix
, reset_less
=True)
191 comb
+= opc_in
.eq(opcode_switch
[:d
.suffix
])
192 with m
.Switch(opc_in
):
193 for key
, row
in opcodes
.items():
194 bitsel
= (d
.suffix
+d
.bitsel
[0], d
.bitsel
[1])
195 sd
= Subdecoder(pattern
=None, opcodes
=row
,
196 bitsel
=bitsel
, suffix
=None,
197 opint
=False, subdecoders
=[])
198 subdecoder
= PowerDecoder(width
=32, dec
=sd
)
199 setattr(m
.submodules
, "dec_sub%d" % key
, subdecoder
)
200 comb
+= subdecoder
.opcode_in
.eq(self
.opcode_in
)
202 comb
+= self
.op
.eq(subdecoder
.op
)
204 # TODO: arguments, here (all of them) need to be a list.
205 # a for-loop around the *list* of decoder args.
206 with m
.Switch(opcode_switch
):
207 self
.handle_subdecoders(m
, d
)
208 for row
in d
.opcodes
:
209 opcode
= row
['opcode']
210 if d
.opint
and '-' not in opcode
:
211 opcode
= int(opcode
, 0)
215 comb
+= self
.op
._eq
(row
)
218 def handle_subdecoders(self
, m
, d
):
219 for dec
in d
.subdecoders
:
220 subdecoder
= PowerDecoder(self
.width
, dec
)
221 if isinstance(dec
, list): # XXX HACK: take first pattern
223 setattr(m
.submodules
, "dec%d" % dec
.pattern
, subdecoder
)
224 m
.d
.comb
+= subdecoder
.opcode_in
.eq(self
.opcode_in
)
225 with m
.Case(dec
.pattern
):
226 m
.d
.comb
+= self
.op
.eq(subdecoder
.op
)
229 return [self
.opcode_in
] + self
.op
.ports()
232 class TopPowerDecoder(PowerDecoder
, DecodeFields
):
235 top-level hierarchical decoder for POWER ISA
236 bigendian dynamically switches between big and little endian decoding
237 (reverses byte order)
240 def __init__(self
, width
, dec
):
241 PowerDecoder
.__init
__(self
, width
, dec
)
242 DecodeFields
.__init
__(self
, SignalBitRange
, [self
.opcode_in
])
244 self
.raw_opcode_in
= Signal
.like(self
.opcode_in
, reset_less
=True)
245 self
.bigendian
= Signal(reset_less
=True)
247 def elaborate(self
, platform
):
248 m
= PowerDecoder
.elaborate(self
, platform
)
250 raw_be
= self
.raw_opcode_in
252 for i
in range(0, self
.width
, 8):
253 l
.append(raw_be
[i
:i
+8])
256 comb
+= self
.opcode_in
.eq(Mux(self
.bigendian
, raw_be
, raw_le
))
260 return [self
.raw_opcode_in
, self
.bigendian
] + PowerDecoder
.ports(self
)
263 def create_pdecode():
265 # minor 19 has extra patterns
267 m19
.append(Subdecoder(pattern
=19, opcodes
=get_csv("minor_19.csv"),
268 opint
=True, bitsel
=(1, 11), suffix
=None, subdecoders
=[]))
269 m19
.append(Subdecoder(pattern
=19, opcodes
=get_csv("minor_19_00000.csv"),
270 opint
=True, bitsel
=(1, 6), suffix
=None, subdecoders
=[]))
275 Subdecoder(pattern
=30, opcodes
=get_csv("minor_30.csv"),
276 opint
=True, bitsel
=(1, 6), suffix
=None, subdecoders
=[]),
277 Subdecoder(pattern
=31, opcodes
=get_csv("minor_31.csv"),
278 opint
=True, bitsel
=(1, 11), suffix
=0b00101, subdecoders
=[]),
279 Subdecoder(pattern
=58, opcodes
=get_csv("minor_58.csv"),
280 opint
=True, bitsel
=(0, 2), suffix
=None, subdecoders
=[]),
281 Subdecoder(pattern
=62, opcodes
=get_csv("minor_62.csv"),
282 opint
=True, bitsel
=(0, 2), suffix
=None, subdecoders
=[]),
285 # top level: extra merged with major
287 opcodes
= get_csv("major.csv")
288 dec
.append(Subdecoder(pattern
=None, opint
=True, opcodes
=opcodes
,
289 bitsel
=(26, 32), suffix
=None, subdecoders
=pminor
))
290 opcodes
= get_csv("extra.csv")
291 dec
.append(Subdecoder(pattern
=None, opint
=False, opcodes
=opcodes
,
292 bitsel
=(0, 32), suffix
=None, subdecoders
=[]))
294 return TopPowerDecoder(32, dec
)
297 if __name__
== '__main__':
298 pdecode
= create_pdecode()
299 vl
= rtlil
.convert(pdecode
, ports
=pdecode
.ports())
300 with
open("decoder.il", "w") as f
: