cleanup cpu_decode.py
[rv32.git] / cpu_decoder.py
1 """
2 /*
3 * Copyright 2018 Jacob Lifshay
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining a copy
6 * of this software and associated documentation files (the "Software"), to deal
7 * in the Software without restriction, including without limitation the rights
8 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 * copies of the Software, and to permit persons to whom the Software is
10 * furnished to do so, subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice shall be included in all
13 * copies or substantial portions of the Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 * SOFTWARE.
22 *
23 */
24 `timescale 1ns / 100ps
25 """
26 from migen import *
27 from migen.fhdl import verilog
28
29 from riscvdefs import *
30 from cpudefs import *
31
32 class CPUDecoder(Module):
33 """ decodes a 32-bit instruction into an immediate and other constituent
34 parts, including the opcode and funct3 and funct7, followed by
35 a further (hierarchical) breakdown of the action required to be taken.
36 unidentified actions are decoded as an illegal instruction trap.
37 """
38
39 def __init__(self):
40 self.instruction = Signal(32)
41 self.funct7 = Signal(7)
42 self.funct3 = Signal(3)
43 self.rd = Signal(5)
44 self.rs1 = Signal(5)
45 self.rs2 = Signal(5)
46 self.immediate = Signal(32)
47 self.opcode = Signal(7)
48 self.decode_action = Signal(decode_action)
49
50 # decode bits of instruction
51 self.comb += self.funct7.eq(self.instruction[25:32])
52 self.comb += self.funct3.eq(self.instruction[12:15])
53 self.comb += self.rd.eq (self.instruction[7:12])
54 self.comb += self.rs1.eq (self.instruction[15:20])
55 self.comb += self.rs2.eq (self.instruction[20:25])
56 self.comb += self.opcode.eq(self.instruction[0:7])
57
58 # add combinatorial decode opcode case statements for immed and action
59 self.comb += self.calculate_immediate()
60 self.comb += self.calculate_action()
61
62 def calculate_immediate(self):
63 """ calculate immediate
64 """
65 ci = {}
66 no_imm = 0x0
67
68 # R-type: no immediate
69 for op in [opcode_amo, opcode_op, opcode_op_32, opcode_op_fp]:
70 ci[op] = self.immediate.eq(no_imm)
71
72 # I-type
73 im = Cat(self.instruction[20:], Replicate(self.instruction[31], 20))
74 for op in [opcode_load, opcode_load_fp, opcode_misc_mem,
75 opcode_op_imm, opcode_op_imm_32, opcode_jalr,
76 opcode_system]:
77 ci[op] = self.immediate.eq(im)
78
79 # S-type
80 im = Cat(self.instruction[7:12], self.instruction[25:31],
81 Replicate(self.instruction[31], 21))
82 for op in [opcode_store, opcode_store_fp]:
83 ci[op] = self.immediate.eq(im)
84
85 # B-type
86 im = Cat(Constant(0, 1),
87 self.instruction[8:12], self.instruction[25:31],
88 self.instruction[7], Replicate(self.instruction[31], 20))
89 for op in [opcode_branch, ]:
90 ci[op] = self.immediate.eq(im)
91
92 # U-type
93 im = Cat(Constant(0, 1), self.instruction[12:], )
94 for op in [opcode_auipc, opcode_lui]:
95 ci[op] = self.immediate.eq(im)
96
97 # J-type
98 im = Cat(Constant(0, 1),
99 self.instruction[21:25], self.instruction[25:31],
100 self.instruction[20], self.instruction[12:20],
101 Replicate(self.instruction[31], 12))
102 for op in [opcode_jal, ]:
103 ci[op] = self.immediate.eq(im)
104
105 # R4-type: no immediate
106 for op in [opcode_madd, opcode_msub, opcode_nmsub, opcode_nmadd]:
107 ci[op] = self.immediate.eq(no_imm)
108
109 # unknown
110 for op in [ opcode_custom_0, opcode_48b_escape_0, opcode_custom_1,
111 opcode_64b_escape, opcode_reserved_10101, opcode_rv128_0,
112 opcode_48b_escape_1, opcode_reserved_11010,
113 opcode_reserved_11101, opcode_rv128_1, opcode_80b_escape]:
114 ci[op] = self.immediate.eq(no_imm)
115
116 # default
117 for op in [ "default", ]:
118 ci[op] = self.immediate.eq(no_imm)
119
120 return Case(self.opcode, ci)
121
122 def _decode_funct3(self, options, action):
123 """ decode by list of cases
124 """
125 c = {}
126 # load opcode
127 for op in options:
128 c[op] = self.decode_action.eq(action)
129 # default
130 c["default"] = \
131 self.decode_action.eq(decode_action_trap_illegal_instruction)
132
133 return Case(self.funct3, c)
134
135 def calculate_store_action(self):
136 """ decode store action
137 """
138 return self._decode_funct3([ funct3_sb, funct3_sh, funct3_sw, ],
139 decode_action_store)
140
141 def calculate_load_action(self):
142 """ decode load action
143 """
144 return self._decode_funct3([ funct3_lb, funct3_lbu, funct3_lh,
145 funct3_lhu, funct3_lw, ],
146 decode_action_load)
147
148 def calculate_branch_action(self):
149 """ decode branch action
150 """
151 return self._decode_funct3([ funct3_beq, funct3_bne, funct3_blt,
152 funct3_bge, funct3_bltu, funct3_bgeu ],
153 decode_action_branch)
154
155 def calculate_jalr_action(self):
156 """ decode jalr action
157 """
158 return self._decode_funct3([ funct3_jalr, ],
159 decode_action_jalr)
160
161 def calculate_op_action(self):
162 """ decode op action
163 """
164 c = {}
165 immz = Constant(0, 12)
166 regz = Constant(0, 5)
167 # fence
168 c[funct3_slli] = \
169 If((self.funct7 == Constant(0, 7)),
170 self.decode_action.eq(decode_action_op_op_imm)).\
171 Else(
172 self.decode_action.eq(decode_action_trap_illegal_instruction))
173 # fence.i
174 c[funct3_srli_srai] = \
175 If((self.funct7 == Constant(0, 7) | \
176 (self.funct7 == Constant(0x20, 7))),
177 self.decode_action.eq(decode_action_op_op_imm)).\
178 Else(
179 self.decode_action.eq(decode_action_trap_illegal_instruction))
180 # default
181 c["default"] = \
182 self.decode_action.eq(decode_action_op_op_imm)
183
184 return Case(self.funct3, c)
185
186 def calculate_misc_action(self):
187 """ decode misc mem action
188 """
189 c = {}
190 immz = Constant(0, 12)
191 regz = Constant(0, 5)
192 # fence
193 c[funct3_fence] = \
194 If((self.immediate[8:12] == immz) & (self.rs1 == regz) & \
195 (self.rd == regz),
196 self.decode_action.eq(decode_action_fence)).\
197 Else(
198 self.decode_action.eq(decode_action_trap_illegal_instruction))
199 # fence.i
200 c[funct3_fence_i] = \
201 If((self.immediate[0:12] == immz) & (self.rs1 == regz) & \
202 (self.rd == regz),
203 self.decode_action.eq(decode_action_fence_i)).\
204 Else(
205 self.decode_action.eq(decode_action_trap_illegal_instruction))
206 # default
207 c["default"] = \
208 self.decode_action.eq(decode_action_trap_illegal_instruction)
209
210 return Case(self.funct3, c)
211
212 def calculate_system_action(self):
213 """ decode system action
214 """
215 c = {}
216 b1 = Constant(1, 32)
217 regz = Constant(0, 5)
218 # ebreak
219 c[funct3_ecall_ebreak] = \
220 If((self.immediate != ~b1) | (self.rs1 != regz) | \
221 (self.rd != regz),
222 self.decode_action.eq(decode_action_trap_illegal_instruction)).\
223 Else(
224 self.decode_action.eq(decode_action_trap_ecall_ebreak))
225 # csrs
226 for op in [ funct3_csrrw, funct3_csrrs, funct3_csrrc,
227 funct3_csrrwi, funct3_csrrsi, funct3_csrrci]:
228 c[op] = self.decode_action.eq(decode_action_csr)
229 # default
230 c["default"] = \
231 self.decode_action.eq(decode_action_trap_illegal_instruction)
232
233 return Case(self.funct3, c)
234
235 def calculate_action(self):
236 """ calculate action based on opcode.
237
238 this is a first level case statement that calls down to 2nd
239 level case (and in some cases if logic) mostly using funct3
240 (funct7 in the case of arith ops).
241 """
242 c = {}
243 c[opcode_load] = self.calculate_load_action()
244 c[opcode_misc_mem] = self.calculate_misc_action()
245 c[opcode_op_imm] = self.calculate_op_action()
246 c[opcode_op] = self.calculate_op_action()
247 c[opcode_lui] = self.decode_action.eq(decode_action_lui_auipc)
248 c[opcode_auipc] = self.decode_action.eq(decode_action_lui_auipc)
249 c[opcode_store] = self.calculate_store_action()
250 c[opcode_branch] = self.calculate_branch_action()
251 c[opcode_jalr] = self.calculate_jalr_action()
252 c[opcode_jal] = self.decode_action.eq(decode_action_jal)
253 c[opcode_system] = self.calculate_system_action()
254
255 # big batch of unrecognised opcodes: throw trap.
256 for o in [ opcode_load_fp, opcode_custom_0, opcode_op_imm_32,
257 opcode_48b_escape_0, opcode_store_fp, opcode_custom_1,
258 opcode_amo, opcode_op_32, opcode_64b_escape,
259 opcode_madd, opcode_msub, opcode_nmsub,
260 opcode_nmadd, opcode_op_fp, opcode_reserved_10101,
261 opcode_rv128_0, opcode_48b_escape_1, opcode_reserved_11010,
262 opcode_reserved_11101, opcode_rv128_1, opcode_80b_escape,
263 "default", ]:
264 c[o] = self.decode_action.eq(decode_action_trap_illegal_instruction)
265
266 return Case(self.opcode, c)
267
268 if __name__ == "__main__":
269 example = CPUDecoder()
270 print(verilog.convert(example,
271 {
272 example.instruction,
273 example.funct7,
274 example.funct3,
275 example.rd,
276 example.rs1,
277 example.rs2,
278 example.immediate,
279 example.opcode,
280 example.decode_action,
281 }))