add decoder on power fields
[soc.git] / src / 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 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
62
63 Subdecoder = namedtuple("Subdecoder", ["pattern", "opcodes", "opint",
64 "bitsel", "suffix", "subdecoders"])
65
66
67 class PowerOp:
68 """PowerOp: spec for execution. op type (ADD etc.) reg specs etc.
69 """
70
71 def __init__(self):
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))
85
86 def _eq(self, row=None):
87 if row is None:
88 row = default_values
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']]),
99 ]
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))))
103 return res
104
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))))
119 return res
120
121 def ports(self):
122 regular = [self.function_unit,
123 self.in1_sel,
124 self.in2_sel,
125 self.in3_sel,
126 self.out_sel,
127 self.ldst_len,
128 self.rc_sel,
129 self.internal_op,
130 self.form]
131 single_bit_ports = [getattr(self, get_signal_name(x))
132 for x in single_bit_flags]
133 return regular + single_bit_ports
134
135
136 class PowerDecoder(Elaboratable):
137 """PowerDecoder - decodes an incoming opcode into the type of operation
138 """
139
140 def __init__(self, width, dec):
141 if not isinstance(dec, list):
142 dec = [dec]
143 self.dec = dec
144 self.opcode_in = Signal(width, reset_less=True)
145
146 self.op = PowerOp()
147 for d in dec:
148 if d.suffix is not None and d.suffix >= width:
149 d.suffix = None
150 self.width = width
151
152 def suffix_mask(self, d):
153 return ((1 << d.suffix) - 1)
154
155 def divide_opcodes(self, d):
156 divided = {}
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)
163 key = opcode & mask
164 opcode = opcode >> d.suffix
165 if key not in divided:
166 divided[key] = []
167 r = row.copy()
168 r['opcode'] = opcode
169 divided[key].append(r)
170 return divided
171
172 def elaborate(self, platform):
173 m = Module()
174 comb = m.d.comb
175
176 # note: default opcode is "illegal" as this is a combinatorial block
177
178 # go through the list of CSV decoders first
179 for d in self.dec:
180 opcode_switch = Signal(d.bitsel[1] - d.bitsel[0],
181 reset_less=True)
182 comb += opcode_switch.eq(self.opcode_in[d.bitsel[0]:d.bitsel[1]])
183 if d.suffix:
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)
196 with m.Case(key):
197 comb += self.op.eq(subdecoder.op)
198 else:
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)
207 if not row['unit']:
208 continue
209 with m.Case(opcode):
210 comb += self.op._eq(row)
211 return m
212
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
217 dec = dec[0]
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)
222
223 def ports(self):
224 return [self.opcode_in] + self.op.ports()
225
226
227 def create_pdecode():
228
229 # minor 19 has extra patterns
230 m19 = []
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=[]))
235
236 # minor opcodes.
237 pminor = [
238 m19,
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=[]),
247 ]
248
249 # top level: extra merged with major
250 dec = []
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=[]))
257
258 return PowerDecoder(32, dec)
259
260
261 if __name__ == '__main__':
262 pdecode = create_pdecode()
263 vl = rtlil.convert(pdecode, ports=pdecode.ports())
264 with open("decoder.il", "w") as f:
265 f.write(vl)