WIP: Replace fields in power_decoder with signals of the same name
[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 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
65
66
67 Subdecoder = namedtuple("Subdecoder", ["pattern", "opcodes", "opint",
68 "bitsel", "suffix", "subdecoders"])
69
70
71 class PowerOp:
72 """PowerOp: spec for execution. op type (ADD etc.) reg specs etc.
73 """
74
75 def __init__(self):
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))
89
90 def _eq(self, row=None):
91 if row is None:
92 row = default_values
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']]),
103 ]
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))))
107 return res
108
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))))
123 return res
124
125 def ports(self):
126 regular = [self.function_unit,
127 self.in1_sel,
128 self.in2_sel,
129 self.in3_sel,
130 self.out_sel,
131 self.ldst_len,
132 self.rc_sel,
133 self.internal_op,
134 self.form]
135 single_bit_ports = [getattr(self, get_signal_name(x))
136 for x in single_bit_flags]
137 return regular + single_bit_ports
138
139
140 class PowerDecoder(Elaboratable):
141 """PowerDecoder - decodes an incoming opcode into the type of operation
142 """
143
144 def __init__(self, width, dec):
145 if not isinstance(dec, list):
146 dec = [dec]
147 self.dec = dec
148 self.opcode_in = Signal(width, reset_less=True)
149
150 self.op = PowerOp()
151 for d in dec:
152 if d.suffix is not None and d.suffix >= width:
153 d.suffix = None
154 self.width = width
155
156 def suffix_mask(self, d):
157 return ((1 << d.suffix) - 1)
158
159 def divide_opcodes(self, d):
160 divided = {}
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)
167 key = opcode & mask
168 opcode = opcode >> d.suffix
169 if key not in divided:
170 divided[key] = []
171 r = row.copy()
172 r['opcode'] = opcode
173 divided[key].append(r)
174 return divided
175
176 def elaborate(self, platform):
177 m = Module()
178 comb = m.d.comb
179
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
182
183 # go through the list of CSV decoders first
184 for d in self.dec:
185 opcode_switch = Signal(d.bitsel[1] - d.bitsel[0],
186 reset_less=True)
187 comb += opcode_switch.eq(self.opcode_in[d.bitsel[0]:d.bitsel[1]])
188 if d.suffix:
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)
201 with m.Case(key):
202 comb += self.op.eq(subdecoder.op)
203 else:
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)
212 if not row['unit']:
213 continue
214 with m.Case(opcode):
215 comb += self.op._eq(row)
216 return m
217
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
222 dec = dec[0]
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)
227
228 def ports(self):
229 return [self.opcode_in] + self.op.ports()
230
231
232 class TopPowerDecoder(PowerDecoder):
233 """TopPowerDecoder
234
235 top-level hierarchical decoder for POWER ISA
236 bigendian dynamically switches between big and little endian decoding
237 (reverses byte order). See V3.0B p44 1.11.2
238 """
239
240 def __init__(self, width, dec):
241 PowerDecoder.__init__(self, width, dec)
242 self.fields = DecodeFields(SignalBitRange, [self.opcode_in])
243 self.fields.create_specs()
244 self.raw_opcode_in = Signal.like(self.opcode_in, reset_less=True)
245 self.bigendian = Signal(reset_less=True)
246
247 for name in self.fields.common_fields:
248 value = getattr(self.fields, name)
249 sig = Signal(value[0:-1].shape(), reset_less=True, name=name)
250 setattr(self, name, sig)
251
252 def elaborate(self, platform):
253 m = PowerDecoder.elaborate(self, platform)
254 comb = m.d.comb
255 raw_be = self.raw_opcode_in
256 l = []
257 for i in range(0, self.width, 8):
258 l.append(raw_be[i:i+8])
259 l.reverse()
260 raw_le = Cat(*l)
261 comb += self.opcode_in.eq(Mux(self.bigendian, raw_be, raw_le))
262 for name in self.fields.common_fields:
263 value = getattr(self.fields, name)
264 sig = getattr(self, name)
265 comb += sig.eq(value[0:-1])
266 return m
267
268 def ports(self):
269 return [self.raw_opcode_in, self.bigendian] + PowerDecoder.ports(self)
270
271
272 def create_pdecode():
273
274 # minor 19 has extra patterns
275 m19 = []
276 m19.append(Subdecoder(pattern=19, opcodes=get_csv("minor_19.csv"),
277 opint=True, bitsel=(1, 11), suffix=None, subdecoders=[]))
278 m19.append(Subdecoder(pattern=19, opcodes=get_csv("minor_19_00000.csv"),
279 opint=True, bitsel=(1, 6), suffix=None, subdecoders=[]))
280
281 # minor opcodes.
282 pminor = [
283 m19,
284 Subdecoder(pattern=30, opcodes=get_csv("minor_30.csv"),
285 opint=True, bitsel=(1, 6), suffix=None, subdecoders=[]),
286 Subdecoder(pattern=31, opcodes=get_csv("minor_31.csv"),
287 opint=True, bitsel=(1, 11), suffix=0b00101, subdecoders=[]),
288 Subdecoder(pattern=58, opcodes=get_csv("minor_58.csv"),
289 opint=True, bitsel=(0, 2), suffix=None, subdecoders=[]),
290 Subdecoder(pattern=62, opcodes=get_csv("minor_62.csv"),
291 opint=True, bitsel=(0, 2), suffix=None, subdecoders=[]),
292 ]
293
294 # top level: extra merged with major
295 dec = []
296 opcodes = get_csv("major.csv")
297 dec.append(Subdecoder(pattern=None, opint=True, opcodes=opcodes,
298 bitsel=(26, 32), suffix=None, subdecoders=pminor))
299 opcodes = get_csv("extra.csv")
300 dec.append(Subdecoder(pattern=None, opint=False, opcodes=opcodes,
301 bitsel=(0, 32), suffix=None, subdecoders=[]))
302
303 return TopPowerDecoder(32, dec)
304
305
306 if __name__ == '__main__':
307 pdecode = create_pdecode()
308 vl = rtlil.convert(pdecode, ports=pdecode.ports())
309 with open("decoder.il", "w") as f:
310 f.write(vl)