3 * Copyright 2018 Jacob Lifshay
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:
12 * The above copyright notice and this permission notice shall be included in all
13 * copies or substantial portions of the Software.
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
24 `timescale 1ns / 100ps
27 from migen
.fhdl
import verilog
29 from riscvdefs
import *
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.
40 self
.instruction
= Signal(32)
41 self
.funct7
= Signal(7)
42 self
.funct3
= Signal(3)
46 self
.immediate
= Signal(32)
47 self
.opcode
= Signal(7)
48 self
.decode_action
= Signal(decode_action
)
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])
58 # add combinatorial decode opcode case statements for immed and action
59 self
.comb
+= self
.calculate_immediate()
60 self
.comb
+= self
.calculate_action()
62 def calculate_immediate(self
):
63 """ calculate immediate
66 no_imm
= Constant(0x0, 32)
68 # R-type: no immediate
69 for op
in [OP
.amo
, OP
.op
, OP
.op_32
, OP
.op_fp
]:
70 ci
[op
] = self
.immediate
.eq(no_imm
)
72 # I-type: sign-extended bits 20-31
73 im
= Cat(self
.instruction
[20:], Replicate(self
.instruction
[31], 20))
74 for op
in [OP
.load
, OP
.load_fp
, OP
.misc_mem
,
75 OP
.op_imm
, OP
.op_imm_32
, OP
.jalr
,
77 ci
[op
] = self
.immediate
.eq(im
)
80 im
= Cat(self
.instruction
[7:12], self
.instruction
[25:31],
81 Replicate(self
.instruction
[31], 21))
82 for op
in [OP
.store
, OP
.store_fp
]:
83 ci
[op
] = self
.immediate
.eq(im
)
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 [OP
.branch
, ]:
90 ci
[op
] = self
.immediate
.eq(im
)
93 im
= Cat(Constant(0, 1), self
.instruction
[12:], )
94 for op
in [OP
.auipc
, OP
.lui
]:
95 ci
[op
] = self
.immediate
.eq(im
)
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 [OP
.jal
, ]:
103 ci
[op
] = self
.immediate
.eq(im
)
105 # R4-type: no immediate
106 for op
in [OP
.madd
, OP
.msub
, OP
.nmsub
, OP
.nmadd
]:
107 ci
[op
] = self
.immediate
.eq(no_imm
)
110 for op
in [ OP
.custom_0
, OP
.op_48b_escape_0
, OP
.custom_1
,
111 OP
.op_64b_escape
, OP
.reserved_10101
, OP
.rv128_0
,
112 OP
.op_48b_escape_1
, OP
.reserved_11010
,
113 OP
.reserved_11101
, OP
.rv128_1
, OP
.op_80b_escape
]:
114 ci
[op
] = self
.immediate
.eq(no_imm
)
117 for op
in [ "default", ]:
118 ci
[op
] = self
.immediate
.eq(no_imm
)
120 return Case(self
.opcode
, ci
)
122 def _decode_funct3(self
, action
, options
):
123 """ decode by list of cases
128 c
[op
] = self
.decode_action
.eq(action
)
130 c
["default"] = self
.decode_action
.eq(DA
.trap_illegal_instruction
)
132 return Case(self
.funct3
, c
)
134 def calculate_store_action(self
):
135 """ decode store action
137 return self
._decode
_funct
3(DA
.store
, [F3
.sb
, F3
.sh
, F3
.sw
, ])
139 def calculate_load_action(self
):
140 """ decode load action
142 return self
._decode
_funct
3(DA
.load
, [F3
.lb
, F3
.lbu
, F3
.lh
,
145 def calculate_branch_action(self
):
146 """ decode branch action
148 return self
._decode
_funct
3(DA
.branch
, [F3
.beq
, F3
.bne
, F3
.blt
,
149 F3
.bge
, F3
.bltu
, F3
.bgeu
])
151 def calculate_jalr_action(self
):
152 """ decode jalr action
154 return self
._decode
_funct
3(DA
.jalr
, [F3
.jalr
, ])
156 def calculate_op_action(self
):
157 """ decode op action: the arith ops, and, or, add, xor, sr/sl etc.
160 immz
= Constant(0, 12)
161 regz
= Constant(0, 5)
164 If((self
.funct7
== Constant(0, 7)),
165 self
.decode_action
.eq(DA
.op_op_imm
)
167 self
.decode_action
.eq(DA
.trap_illegal_instruction
))
170 If((self
.funct7
== Constant(0, 7) | \
171 (self
.funct7
== Constant(0x20, 7))),
172 self
.decode_action
.eq(DA
.op_op_imm
)
174 self
.decode_action
.eq(DA
.trap_illegal_instruction
))
176 c
["default"] = self
.decode_action
.eq(DA
.op_op_imm
)
178 return Case(self
.funct3
, c
)
180 def calculate_misc_action(self
):
181 """ decode misc mem action: fence and fence_i
184 immz
= Constant(0, 12)
185 regz
= Constant(0, 5)
188 If((self
.immediate
[8:12] == immz
) & (self
.rs1
== regz
) & \
190 self
.decode_action
.eq(DA
.fence
)
192 self
.decode_action
.eq(DA
.trap_illegal_instruction
))
195 If((self
.immediate
[0:12] == immz
) & (self
.rs1
== regz
) & \
197 self
.decode_action
.eq(DA
.fence_i
)
199 self
.decode_action
.eq(DA
.trap_illegal_instruction
))
201 c
["default"] = self
.decode_action
.eq(DA
.trap_illegal_instruction
)
203 return Case(self
.funct3
, c
)
205 def calculate_system_action(self
):
206 """ decode opcode system: ebreak and csrs
210 regz
= Constant(0, 5)
212 c
[F3
.ecall_ebreak
] = \
213 If((self
.immediate
== ~b1
) & (self
.rs1
== regz
) & \
215 self
.decode_action
.eq(DA
.trap_ecall_ebreak
)
217 self
.decode_action
.eq(DA
.trap_illegal_instruction
))
219 for op
in [ F3
.csrrw
, F3
.csrrs
, F3
.csrrc
,
220 F3
.csrrwi
, F3
.csrrsi
, F3
.csrrci
]:
221 c
[op
] = self
.decode_action
.eq(DA
.csr
)
223 c
["default"] = self
.decode_action
.eq(DA
.trap_illegal_instruction
)
225 return Case(self
.funct3
, c
)
227 def calculate_action(self
):
228 """ calculate action based on opcode.
230 this is a first level case statement that calls down to 2nd
231 level case (and in some cases if logic) mostly using funct3
232 (funct7 in the case of arith ops).
235 c
[OP
.load
] = self
.calculate_load_action()
236 c
[OP
.misc_mem
] = self
.calculate_misc_action()
237 c
[OP
.op_imm
] = self
.calculate_op_action()
238 c
[OP
.op
] = self
.calculate_op_action()
239 c
[OP
.lui
] = self
.decode_action
.eq(DA
.lui_auipc
)
240 c
[OP
.auipc
] = self
.decode_action
.eq(DA
.lui_auipc
)
241 c
[OP
.store
] = self
.calculate_store_action()
242 c
[OP
.branch
] = self
.calculate_branch_action()
243 c
[OP
.jalr
] = self
.calculate_jalr_action()
244 c
[OP
.jal
] = self
.decode_action
.eq(DA
.jal
)
245 c
[OP
.system
] = self
.calculate_system_action()
247 # big batch of unrecognised opcodes: throw trap.
248 for o
in [ OP
.load_fp
, OP
.custom_0
, OP
.op_imm_32
,
249 OP
.op_48b_escape_0
, OP
.store_fp
, OP
.custom_1
,
250 OP
.amo
, OP
.op_32
, OP
.op_64b_escape
,
251 OP
.madd
, OP
.msub
, OP
.nmsub
,
252 OP
.nmadd
, OP
.op_fp
, OP
.reserved_10101
,
253 OP
.rv128_0
, OP
.op_48b_escape_1
, OP
.reserved_11010
,
254 OP
.reserved_11101
, OP
.rv128_1
, OP
.op_80b_escape
,
256 c
[o
] = self
.decode_action
.eq(DA
.trap_illegal_instruction
)
258 return Case(self
.opcode
, c
)
260 if __name__
== "__main__":
261 example
= CPUDecoder()
262 print(verilog
.convert(example
,
272 example
.decode_action
,