split out sig set from sig setup
[soc.git] / src / soc / decoder / power_decoder.py
1 """Cascading Power ISA Decoder
2
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.
7
8 This is based on Anton Blanchard's excellent microwatt work:
9 https://github.com/antonblanchard/microwatt/blob/master/decode1.vhdl
10
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.
14
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".
19
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.
24
25 Top Level:
26
27 [ (extra.csv: bit-fields entire 32-bit range
28 opcode -> matches
29 000000---------------01000000000 -> ILLEGAL instruction
30 01100000000000000000000000000000 -> SIM_CONFIG instruction
31 ................................ ->
32 ),
33 (major.csv: first 6 bits ONLY
34 opcode -> matches
35 001100 -> ALU,OP_ADD (add)
36 001101 -> ALU,OP_ADD (another type of add)
37 ...... -> ...
38 ...... -> ...
39 subdecoders:
40 001011 this must match *MAJOR*.CSV
41 [ (minor_19.csv: bits 21 through 30 inclusive:
42 opcode -> matches
43 0b0000000000 -> ALU,OP_MCRF
44 ............ -> ....
45 ),
46 (minor_19_00000.csv: bits 21 through 25 inclusive:
47 opcode -> matches
48 0b00010 -> ALU,add_pcis
49 )
50 ]
51 ),
52 ]
53
54 """
55
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
66
67
68 Subdecoder = namedtuple("Subdecoder", ["pattern", "opcodes", "opint",
69 "bitsel", "suffix", "subdecoders"])
70
71
72 class PowerOp:
73 """PowerOp: spec for execution. op type (ADD etc.) reg specs etc.
74 """
75
76 def __init__(self):
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))
90
91 def _eq(self, row=None):
92 if row is None:
93 row = default_values
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']]),
104 ]
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))))
108 return res
109
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))))
124 return res
125
126 def ports(self):
127 regular = [self.function_unit,
128 self.in1_sel,
129 self.in2_sel,
130 self.in3_sel,
131 self.out_sel,
132 self.ldst_len,
133 self.rc_sel,
134 self.internal_op,
135 self.form]
136 single_bit_ports = [getattr(self, get_signal_name(x))
137 for x in single_bit_flags]
138 return regular + single_bit_ports
139
140
141 class PowerDecoder(Elaboratable):
142 """PowerDecoder - decodes an incoming opcode into the type of operation
143 """
144
145 def __init__(self, width, dec):
146 if not isinstance(dec, list):
147 dec = [dec]
148 self.dec = dec
149 self.opcode_in = Signal(width, reset_less=True)
150
151 self.op = PowerOp()
152 for d in dec:
153 if d.suffix is not None and d.suffix >= width:
154 d.suffix = None
155 self.width = width
156
157 def suffix_mask(self, d):
158 return ((1 << d.suffix) - 1)
159
160 def divide_opcodes(self, d):
161 divided = {}
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)
168 key = opcode & mask
169 opcode = opcode >> d.suffix
170 if key not in divided:
171 divided[key] = []
172 r = row.copy()
173 r['opcode'] = opcode
174 divided[key].append(r)
175 return divided
176
177 def elaborate(self, platform):
178 m = Module()
179 comb = m.d.comb
180
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
183
184 # go through the list of CSV decoders first
185 for d in self.dec:
186 opcode_switch = Signal(d.bitsel[1] - d.bitsel[0],
187 reset_less=True)
188 comb += opcode_switch.eq(self.opcode_in[d.bitsel[0]:d.bitsel[1]])
189 if d.suffix:
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)
202 with m.Case(key):
203 comb += self.op.eq(subdecoder.op)
204 else:
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)
213 if not row['unit']:
214 continue
215 with m.Case(opcode):
216 comb += self.op._eq(row)
217 return m
218
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
223 dec = dec[0]
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)
228
229 def ports(self):
230 return [self.opcode_in] + self.op.ports()
231
232
233 class TopPowerDecoder(PowerDecoder):
234 """TopPowerDecoder
235
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
239 """
240
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)
247
248 for name, value in self.fields.common_fields.items():
249 sig = Signal(value[0:-1].shape(), reset_less=True, name=name)
250 setattr(self, name, sig)
251
252 # create signals for all field forms
253 self.form_names = forms = self.fields.instrs.keys()
254 self.sigforms = {}
255 for form in forms:
256 fields = self.fields.instrs[form]
257 fk = fields.keys()
258 Fields = namedtuple("Fields", fk)
259 sf = {}
260 for k, value in fields.items():
261 name = "%s_%s" % (form, k)
262 sig = Signal(value[0:-1].shape(), reset_less=True, name=name)
263 sf[k] = sig
264 instr = Fields(**sf)
265 setattr(self, "Form%s" % form, instr)
266 self.sigforms[form] = instr
267
268 def elaborate(self, platform):
269 m = PowerDecoder.elaborate(self, platform)
270 comb = m.d.comb
271 raw_be = self.raw_opcode_in
272 l = []
273 for i in range(0, self.width, 8):
274 l.append(raw_be[i:i+8])
275 l.reverse()
276 raw_le = Cat(*l)
277 comb += self.opcode_in.eq(Mux(self.bigendian, raw_be, raw_le))
278
279 # add all signal from commonly-used fields
280 for name, value in self.fields.common_fields.items():
281 sig = getattr(self, name)
282 comb += sig.eq(value[0:-1])
283
284 # link signals for all field forms
285 forms = self.form_names
286 for form in forms:
287 sf = self.sigforms[form]
288 fields = self.fields.instrs[form]
289 for k, value in fields.items():
290 sig = getattr(sf, k)
291 comb += sig.eq(value[0:-1])
292
293 return m
294
295 def ports(self):
296 return [self.raw_opcode_in, self.bigendian] + PowerDecoder.ports(self)
297
298
299 def create_pdecode():
300
301 # minor 19 has extra patterns
302 m19 = []
303 m19.append(Subdecoder(pattern=19, opcodes=get_csv("minor_19.csv"),
304 opint=True, bitsel=(1, 11), suffix=None, subdecoders=[]))
305 m19.append(Subdecoder(pattern=19, opcodes=get_csv("minor_19_00000.csv"),
306 opint=True, bitsel=(1, 6), suffix=None, subdecoders=[]))
307
308 # minor opcodes.
309 pminor = [
310 m19,
311 Subdecoder(pattern=30, opcodes=get_csv("minor_30.csv"),
312 opint=True, bitsel=(1, 6), suffix=None, subdecoders=[]),
313 Subdecoder(pattern=31, opcodes=get_csv("minor_31.csv"),
314 opint=True, bitsel=(1, 11), suffix=0b00101, subdecoders=[]),
315 Subdecoder(pattern=58, opcodes=get_csv("minor_58.csv"),
316 opint=True, bitsel=(0, 2), suffix=None, subdecoders=[]),
317 Subdecoder(pattern=62, opcodes=get_csv("minor_62.csv"),
318 opint=True, bitsel=(0, 2), suffix=None, subdecoders=[]),
319 ]
320
321 # top level: extra merged with major
322 dec = []
323 opcodes = get_csv("major.csv")
324 dec.append(Subdecoder(pattern=None, opint=True, opcodes=opcodes,
325 bitsel=(26, 32), suffix=None, subdecoders=pminor))
326 opcodes = get_csv("extra.csv")
327 dec.append(Subdecoder(pattern=None, opint=False, opcodes=opcodes,
328 bitsel=(0, 32), suffix=None, subdecoders=[]))
329
330 return TopPowerDecoder(32, dec)
331
332
333 if __name__ == '__main__':
334 pdecode = create_pdecode()
335 vl = rtlil.convert(pdecode, ports=pdecode.ports())
336 with open("decoder.il", "w") as f:
337 f.write(vl)