Migrate imports to use absolute imports
[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
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 Subdecoder = namedtuple("Subdecoder", ["pattern", "opcodes", "opint",
67 "bitsel", "suffix", "subdecoders"])
68
69
70 class PowerOp:
71 """PowerOp: spec for execution. op type (ADD etc.) reg specs etc.
72 """
73
74 def __init__(self):
75 self.function_unit = Signal(Function, reset_less=True)
76 self.internal_op = Signal(InternalOp, reset_less=True)
77 self.form = Signal(Form, reset_less=True)
78 self.in1_sel = Signal(In1Sel, reset_less=True)
79 self.in2_sel = Signal(In2Sel, reset_less=True)
80 self.in3_sel = Signal(In3Sel, reset_less=True)
81 self.out_sel = Signal(OutSel, reset_less=True)
82 self.ldst_len = Signal(LdstLen, reset_less=True)
83 self.rc_sel = Signal(RC, reset_less=True)
84 self.cry_in = Signal(CryIn, reset_less=True)
85 for bit in single_bit_flags:
86 name = get_signal_name(bit)
87 setattr(self, name, Signal(reset_less=True, name=name))
88
89 def _eq(self, row=None):
90 if row is None:
91 row = default_values
92 res = [self.function_unit.eq(Function[row['unit']]),
93 self.form.eq(Form[row['form']]),
94 self.internal_op.eq(InternalOp[row['internal op']]),
95 self.in1_sel.eq(In1Sel[row['in1']]),
96 self.in2_sel.eq(In2Sel[row['in2']]),
97 self.in3_sel.eq(In3Sel[row['in3']]),
98 self.out_sel.eq(OutSel[row['out']]),
99 self.ldst_len.eq(LdstLen[row['ldst len']]),
100 self.rc_sel.eq(RC[row['rc']]),
101 self.cry_in.eq(CryIn[row['cry in']]),
102 ]
103 for bit in single_bit_flags:
104 sig = getattr(self, get_signal_name(bit))
105 res.append(sig.eq(int(row.get(bit, 0))))
106 return res
107
108 def eq(self, otherop):
109 res = [self.function_unit.eq(otherop.function_unit),
110 self.form.eq(otherop.form),
111 self.internal_op.eq(otherop.internal_op),
112 self.in1_sel.eq(otherop.in1_sel),
113 self.in2_sel.eq(otherop.in2_sel),
114 self.in3_sel.eq(otherop.in3_sel),
115 self.out_sel.eq(otherop.out_sel),
116 self.rc_sel.eq(otherop.rc_sel),
117 self.ldst_len.eq(otherop.ldst_len),
118 self.cry_in.eq(otherop.cry_in)]
119 for bit in single_bit_flags:
120 sig = getattr(self, get_signal_name(bit))
121 res.append(sig.eq(getattr(otherop, get_signal_name(bit))))
122 return res
123
124 def ports(self):
125 regular = [self.function_unit,
126 self.in1_sel,
127 self.in2_sel,
128 self.in3_sel,
129 self.out_sel,
130 self.ldst_len,
131 self.rc_sel,
132 self.internal_op,
133 self.form]
134 single_bit_ports = [getattr(self, get_signal_name(x))
135 for x in single_bit_flags]
136 return regular + single_bit_ports
137
138
139 class PowerDecoder(Elaboratable):
140 """PowerDecoder - decodes an incoming opcode into the type of operation
141 """
142
143 def __init__(self, width, dec):
144 if not isinstance(dec, list):
145 dec = [dec]
146 self.dec = dec
147 self.opcode_in = Signal(width, reset_less=True)
148
149 self.op = PowerOp()
150 for d in dec:
151 if d.suffix is not None and d.suffix >= width:
152 d.suffix = None
153 self.width = width
154
155 def suffix_mask(self, d):
156 return ((1 << d.suffix) - 1)
157
158 def divide_opcodes(self, d):
159 divided = {}
160 mask = self.suffix_mask(d)
161 print("mask", hex(mask))
162 for row in d.opcodes:
163 opcode = row['opcode']
164 if d.opint and '-' not in opcode:
165 opcode = int(opcode, 0)
166 key = opcode & mask
167 opcode = opcode >> d.suffix
168 if key not in divided:
169 divided[key] = []
170 r = row.copy()
171 r['opcode'] = opcode
172 divided[key].append(r)
173 return divided
174
175 def elaborate(self, platform):
176 m = Module()
177 comb = m.d.comb
178
179 # note: default opcode is "illegal" as this is a combinatorial block
180
181 # go through the list of CSV decoders first
182 for d in self.dec:
183 opcode_switch = Signal(d.bitsel[1] - d.bitsel[0],
184 reset_less=True)
185 comb += opcode_switch.eq(self.opcode_in[d.bitsel[0]:d.bitsel[1]])
186 if d.suffix:
187 opcodes = self.divide_opcodes(d)
188 opc_in = Signal(d.suffix, reset_less=True)
189 comb += opc_in.eq(opcode_switch[:d.suffix])
190 with m.Switch(opc_in):
191 for key, row in opcodes.items():
192 bitsel = (d.suffix+d.bitsel[0], d.bitsel[1])
193 sd = Subdecoder(pattern=None, opcodes=row,
194 bitsel=bitsel, suffix=None,
195 opint=False, subdecoders=[])
196 subdecoder = PowerDecoder(width=32, dec=sd)
197 setattr(m.submodules, "dec_sub%d" % key, subdecoder)
198 comb += subdecoder.opcode_in.eq(self.opcode_in)
199 with m.Case(key):
200 comb += self.op.eq(subdecoder.op)
201 else:
202 # TODO: arguments, here (all of them) need to be a list.
203 # a for-loop around the *list* of decoder args.
204 with m.Switch(opcode_switch):
205 self.handle_subdecoders(m, d)
206 for row in d.opcodes:
207 opcode = row['opcode']
208 if d.opint and '-' not in opcode:
209 opcode = int(opcode, 0)
210 if not row['unit']:
211 continue
212 with m.Case(opcode):
213 comb += self.op._eq(row)
214 return m
215
216 def handle_subdecoders(self, m, d):
217 for dec in d.subdecoders:
218 subdecoder = PowerDecoder(self.width, dec)
219 if isinstance(dec, list): # XXX HACK: take first pattern
220 dec = dec[0]
221 setattr(m.submodules, "dec%d" % dec.pattern, subdecoder)
222 m.d.comb += subdecoder.opcode_in.eq(self.opcode_in)
223 with m.Case(dec.pattern):
224 m.d.comb += self.op.eq(subdecoder.op)
225
226 def ports(self):
227 return [self.opcode_in] + self.op.ports()
228
229
230 class TopPowerDecoder(PowerDecoder, DecodeFields):
231
232 def __init__(self, width, dec):
233 PowerDecoder.__init__(self, width, dec)
234 DecodeFields.__init__(self, SignalBitRange, [self.opcode_in])
235 self.create_specs()
236
237
238 def create_pdecode():
239
240 # minor 19 has extra patterns
241 m19 = []
242 m19.append(Subdecoder(pattern=19, opcodes=get_csv("minor_19.csv"),
243 opint=True, bitsel=(1, 11), suffix=None, subdecoders=[]))
244 m19.append(Subdecoder(pattern=19, opcodes=get_csv("minor_19_00000.csv"),
245 opint=True, bitsel=(1, 6), suffix=None, subdecoders=[]))
246
247 # minor opcodes.
248 pminor = [
249 m19,
250 Subdecoder(pattern=30, opcodes=get_csv("minor_30.csv"),
251 opint=True, bitsel=(1, 6), suffix=None, subdecoders=[]),
252 Subdecoder(pattern=31, opcodes=get_csv("minor_31.csv"),
253 opint=True, bitsel=(1, 11), suffix=0b00101, subdecoders=[]),
254 Subdecoder(pattern=58, opcodes=get_csv("minor_58.csv"),
255 opint=True, bitsel=(0, 2), suffix=None, subdecoders=[]),
256 Subdecoder(pattern=62, opcodes=get_csv("minor_62.csv"),
257 opint=True, bitsel=(0, 2), suffix=None, subdecoders=[]),
258 ]
259
260 # top level: extra merged with major
261 dec = []
262 opcodes = get_csv("major.csv")
263 dec.append(Subdecoder(pattern=None, opint=True, opcodes=opcodes,
264 bitsel=(26, 32), suffix=None, subdecoders=pminor))
265 opcodes = get_csv("extra.csv")
266 dec.append(Subdecoder(pattern=None, opint=False, opcodes=opcodes,
267 bitsel=(0, 32), suffix=None, subdecoders=[]))
268
269 return TopPowerDecoder(32, dec)
270
271
272 if __name__ == '__main__':
273 pdecode = create_pdecode()
274 vl = rtlil.convert(pdecode, ports=pdecode.ports())
275 with open("decoder.il", "w") as f:
276 f.write(vl)