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
57 from nmigen
.cli
import rtlil
58 from power_enums
import (Function
, Form
, InternalOp
, In1Sel
, In2Sel
, In3Sel
,
59 OutSel
, RC
, LdstLen
, CryIn
, get_csv
, single_bit_flags
,
60 get_signal_name
, default_values
)
61 from collections
import namedtuple
63 Subdecoder
= namedtuple("Subdecoder", ["pattern", "opcodes", "opint",
64 "bitsel", "suffix", "subdecoders"])
68 """PowerOp: spec for execution. op type (ADD etc.) reg specs etc.
72 self
.function_unit
= Signal(Function
, reset_less
=True)
73 self
.internal_op
= Signal(InternalOp
, reset_less
=True)
74 self
.form
= Signal(Form
, reset_less
=True)
75 self
.in1_sel
= Signal(In1Sel
, reset_less
=True)
76 self
.in2_sel
= Signal(In2Sel
, reset_less
=True)
77 self
.in3_sel
= Signal(In3Sel
, reset_less
=True)
78 self
.out_sel
= Signal(OutSel
, reset_less
=True)
79 self
.ldst_len
= Signal(LdstLen
, reset_less
=True)
80 self
.rc_sel
= Signal(RC
, reset_less
=True)
81 self
.cry_in
= Signal(CryIn
, reset_less
=True)
82 for bit
in single_bit_flags
:
83 name
= get_signal_name(bit
)
84 setattr(self
, name
, Signal(reset_less
=True, name
=name
))
86 def _eq(self
, row
=None):
89 res
= [self
.function_unit
.eq(Function
[row
['unit']]),
90 self
.form
.eq(Form
[row
['form']]),
91 self
.internal_op
.eq(InternalOp
[row
['internal op']]),
92 self
.in1_sel
.eq(In1Sel
[row
['in1']]),
93 self
.in2_sel
.eq(In2Sel
[row
['in2']]),
94 self
.in3_sel
.eq(In3Sel
[row
['in3']]),
95 self
.out_sel
.eq(OutSel
[row
['out']]),
96 self
.ldst_len
.eq(LdstLen
[row
['ldst len']]),
97 self
.rc_sel
.eq(RC
[row
['rc']]),
98 self
.cry_in
.eq(CryIn
[row
['cry in']]),
100 for bit
in single_bit_flags
:
101 sig
= getattr(self
, get_signal_name(bit
))
102 res
.append(sig
.eq(int(row
.get(bit
, 0))))
105 def eq(self
, otherop
):
106 res
= [self
.function_unit
.eq(otherop
.function_unit
),
107 self
.form
.eq(otherop
.form
),
108 self
.internal_op
.eq(otherop
.internal_op
),
109 self
.in1_sel
.eq(otherop
.in1_sel
),
110 self
.in2_sel
.eq(otherop
.in2_sel
),
111 self
.in3_sel
.eq(otherop
.in3_sel
),
112 self
.out_sel
.eq(otherop
.out_sel
),
113 self
.rc_sel
.eq(otherop
.rc_sel
),
114 self
.ldst_len
.eq(otherop
.ldst_len
),
115 self
.cry_in
.eq(otherop
.cry_in
)]
116 for bit
in single_bit_flags
:
117 sig
= getattr(self
, get_signal_name(bit
))
118 res
.append(sig
.eq(getattr(otherop
, get_signal_name(bit
))))
122 regular
= [self
.function_unit
,
131 single_bit_ports
= [getattr(self
, get_signal_name(x
))
132 for x
in single_bit_flags
]
133 return regular
+ single_bit_ports
136 class PowerDecoder(Elaboratable
):
137 """PowerDecoder - decodes an incoming opcode into the type of operation
140 def __init__(self
, width
, dec
):
141 if not isinstance(dec
, list):
144 self
.opcode_in
= Signal(width
, reset_less
=True)
148 if d
.suffix
is not None and d
.suffix
>= width
:
152 def suffix_mask(self
, d
):
153 return ((1 << d
.suffix
) - 1)
155 def divide_opcodes(self
, d
):
157 mask
= self
.suffix_mask(d
)
158 print("mask", hex(mask
))
159 for row
in d
.opcodes
:
160 opcode
= row
['opcode']
161 if d
.opint
and '-' not in opcode
:
162 opcode
= int(opcode
, 0)
164 opcode
= opcode
>> d
.suffix
165 if key
not in divided
:
169 divided
[key
].append(r
)
172 def elaborate(self
, platform
):
176 # note: default opcode is "illegal" as this is a combinatorial block
178 # go through the list of CSV decoders first
180 opcode_switch
= Signal(d
.bitsel
[1] - d
.bitsel
[0],
182 comb
+= opcode_switch
.eq(self
.opcode_in
[d
.bitsel
[0]:d
.bitsel
[1]])
184 opcodes
= self
.divide_opcodes(d
)
185 opc_in
= Signal(d
.suffix
, reset_less
=True)
186 comb
+= opc_in
.eq(opcode_switch
[:d
.suffix
])
187 with m
.Switch(opc_in
):
188 for key
, row
in opcodes
.items():
189 bitsel
= (d
.suffix
+d
.bitsel
[0], d
.bitsel
[1])
190 sd
= Subdecoder(pattern
=None, opcodes
=row
,
191 bitsel
=bitsel
, suffix
=None,
192 opint
=False, subdecoders
=[])
193 subdecoder
= PowerDecoder(width
=32, dec
=sd
)
194 setattr(m
.submodules
, "dec_sub%d" % key
, subdecoder
)
195 comb
+= subdecoder
.opcode_in
.eq(self
.opcode_in
)
197 comb
+= self
.op
.eq(subdecoder
.op
)
199 # TODO: arguments, here (all of them) need to be a list.
200 # a for-loop around the *list* of decoder args.
201 with m
.Switch(opcode_switch
):
202 self
.handle_subdecoders(m
, d
)
203 for row
in d
.opcodes
:
204 opcode
= row
['opcode']
205 if d
.opint
and '-' not in opcode
:
206 opcode
= int(opcode
, 0)
210 comb
+= self
.op
._eq
(row
)
213 def handle_subdecoders(self
, m
, d
):
214 for dec
in d
.subdecoders
:
215 subdecoder
= PowerDecoder(self
.width
, dec
)
216 if isinstance(dec
, list): # XXX HACK: take first pattern
218 setattr(m
.submodules
, "dec%d" % dec
.pattern
, subdecoder
)
219 m
.d
.comb
+= subdecoder
.opcode_in
.eq(self
.opcode_in
)
220 with m
.Case(dec
.pattern
):
221 m
.d
.comb
+= self
.op
.eq(subdecoder
.op
)
224 return [self
.opcode_in
] + self
.op
.ports()
227 def create_pdecode():
229 # minor 19 has extra patterns
231 m19
.append(Subdecoder(pattern
=19, opcodes
=get_csv("minor_19.csv"),
232 opint
=True, bitsel
=(1, 11), suffix
=None, subdecoders
=[]))
233 m19
.append(Subdecoder(pattern
=19, opcodes
=get_csv("minor_19_00000.csv"),
234 opint
=True, bitsel
=(1, 6), suffix
=None, subdecoders
=[]))
239 Subdecoder(pattern
=30, opcodes
=get_csv("minor_30.csv"),
240 opint
=True, bitsel
=(1, 6), suffix
=None, subdecoders
=[]),
241 Subdecoder(pattern
=31, opcodes
=get_csv("minor_31.csv"),
242 opint
=True, bitsel
=(1, 11), suffix
=0b00101, subdecoders
=[]),
243 Subdecoder(pattern
=58, opcodes
=get_csv("minor_58.csv"),
244 opint
=True, bitsel
=(0, 2), suffix
=None, subdecoders
=[]),
245 Subdecoder(pattern
=62, opcodes
=get_csv("minor_62.csv"),
246 opint
=True, bitsel
=(0, 2), suffix
=None, subdecoders
=[]),
249 # top level: extra merged with major
251 opcodes
= get_csv("major.csv")
252 dec
.append(Subdecoder(pattern
=None, opint
=True, opcodes
=opcodes
,
253 bitsel
=(26, 32), suffix
=None, subdecoders
=pminor
))
254 opcodes
= get_csv("extra.csv")
255 dec
.append(Subdecoder(pattern
=None, opint
=False, opcodes
=opcodes
,
256 bitsel
=(0, 32), suffix
=None, subdecoders
=[]))
258 return PowerDecoder(32, dec
)
261 if __name__
== '__main__':
262 pdecode
= create_pdecode()
263 vl
= rtlil
.convert(pdecode
, ports
=pdecode
.ports())
264 with
open("decoder.il", "w") as f
: