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