hw/vendor/lowrisc_ibex/rtl/ibex_compressed_decoder.sv Cov: 100%
1: // Copyright lowRISC contributors.
2: // Copyright 2018 ETH Zurich and University of Bologna, see also CREDITS.md.
3: // Licensed under the Apache License, Version 2.0, see LICENSE for details.
4: // SPDX-License-Identifier: Apache-2.0
5:
6: /**
7: * Compressed instruction decoder
8: *
9: * Decodes RISC-V compressed instructions into their RV32 equivalent.
10: * This module is fully combinatorial, clock and reset are used for
11: * assertions only.
12: */
13: module ibex_compressed_decoder (
14: input logic clk_i,
15: input logic rst_ni,
16: input logic valid_i,
17: input logic [31:0] instr_i,
18: output logic [31:0] instr_o,
19: output logic is_compressed_o,
20: output logic illegal_instr_o
21: );
22: import ibex_pkg::*;
23:
24: // valid_i indicates if instr_i is valid and is used for assertions only.
25: // The following signal is used to avoid possible lint errors.
26: logic unused_valid;
27: assign unused_valid = valid_i;
28:
29: ////////////////////////
30: // Compressed decoder //
31: ////////////////////////
32:
33: always_comb begin
34: // By default, forward incoming instruction, mark it as legal.
35: instr_o = instr_i;
36: illegal_instr_o = 1'b0;
37:
38: // Check if incoming instruction is compressed.
39: unique case (instr_i[1:0])
40: // C0
41: 2'b00: begin
42: unique case (instr_i[15:13])
43: 3'b000: begin
44: // c.addi4spn -> addi rd', x2, imm
45: instr_o = {2'b0, instr_i[10:7], instr_i[12:11], instr_i[5],
46: instr_i[6], 2'b00, 5'h02, 3'b000, 2'b01, instr_i[4:2], {OPCODE_OP_IMM}};
47: if (instr_i[12:5] == 8'b0) illegal_instr_o = 1'b1;
48: end
49:
50: 3'b010: begin
51: // c.lw -> lw rd', imm(rs1')
52: instr_o = {5'b0, instr_i[5], instr_i[12:10], instr_i[6],
53: 2'b00, 2'b01, instr_i[9:7], 3'b010, 2'b01, instr_i[4:2], {OPCODE_LOAD}};
54: end
55:
56: 3'b110: begin
57: // c.sw -> sw rs2', imm(rs1')
58: instr_o = {5'b0, instr_i[5], instr_i[12], 2'b01, instr_i[4:2],
59: 2'b01, instr_i[9:7], 3'b010, instr_i[11:10], instr_i[6],
60: 2'b00, {OPCODE_STORE}};
61: end
62:
63: 3'b001,
64: 3'b011,
65: 3'b100,
66: 3'b101,
67: 3'b111: begin
68: illegal_instr_o = 1'b1;
69: end
70:
71: default: begin
72: illegal_instr_o = 1'b1;
73: end
74: endcase
75: end
76:
77: // C1
78: //
79: // Register address checks for RV32E are performed in the regular instruction decoder.
80: // If this check fails, an illegal instruction exception is triggered and the controller
81: // writes the actual faulting instruction to mtval.
82: 2'b01: begin
83: unique case (instr_i[15:13])
84: 3'b000: begin
85: // c.addi -> addi rd, rd, nzimm
86: // c.nop
87: instr_o = {{6 {instr_i[12]}}, instr_i[12], instr_i[6:2],
88: instr_i[11:7], 3'b0, instr_i[11:7], {OPCODE_OP_IMM}};
89: end
90:
91: 3'b001, 3'b101: begin
92: // 001: c.jal -> jal x1, imm
93: // 101: c.j -> jal x0, imm
94: instr_o = {instr_i[12], instr_i[8], instr_i[10:9], instr_i[6],
95: instr_i[7], instr_i[2], instr_i[11], instr_i[5:3],
96: {9 {instr_i[12]}}, 4'b0, ~instr_i[15], {OPCODE_JAL}};
97: end
98:
99: 3'b010: begin
100: // c.li -> addi rd, x0, nzimm
101: // (c.li hints are translated into an addi hint)
102: instr_o = {{6 {instr_i[12]}}, instr_i[12], instr_i[6:2], 5'b0,
103: 3'b0, instr_i[11:7], {OPCODE_OP_IMM}};
104: end
105:
106: 3'b011: begin
107: // c.lui -> lui rd, imm
108: // (c.lui hints are translated into a lui hint)
109: instr_o = {{15 {instr_i[12]}}, instr_i[6:2], instr_i[11:7], {OPCODE_LUI}};
110:
111: if (instr_i[11:7] == 5'h02) begin
112: // c.addi16sp -> addi x2, x2, nzimm
113: instr_o = {{3 {instr_i[12]}}, instr_i[4:3], instr_i[5], instr_i[2],
114: instr_i[6], 4'b0, 5'h02, 3'b000, 5'h02, {OPCODE_OP_IMM}};
115: end
116:
117: if ({instr_i[12], instr_i[6:2]} == 6'b0) illegal_instr_o = 1'b1;
118: end
119:
120: 3'b100: begin
121: unique case (instr_i[11:10])
122: 2'b00,
123: 2'b01: begin
124: // 00: c.srli -> srli rd, rd, shamt
125: // 01: c.srai -> srai rd, rd, shamt
126: // (c.srli/c.srai hints are translated into a srli/srai hint)
127: instr_o = {1'b0, instr_i[10], 5'b0, instr_i[6:2], 2'b01, instr_i[9:7],
128: 3'b101, 2'b01, instr_i[9:7], {OPCODE_OP_IMM}};
129: if (instr_i[12] == 1'b1) illegal_instr_o = 1'b1;
130: end
131:
132: 2'b10: begin
133: // c.andi -> andi rd, rd, imm
134: instr_o = {{6 {instr_i[12]}}, instr_i[12], instr_i[6:2], 2'b01, instr_i[9:7],
135: 3'b111, 2'b01, instr_i[9:7], {OPCODE_OP_IMM}};
136: end
137:
138: 2'b11: begin
139: unique case ({instr_i[12], instr_i[6:5]})
140: 3'b000: begin
141: // c.sub -> sub rd', rd', rs2'
142: instr_o = {2'b01, 5'b0, 2'b01, instr_i[4:2], 2'b01, instr_i[9:7],
143: 3'b000, 2'b01, instr_i[9:7], {OPCODE_OP}};
144: end
145:
146: 3'b001: begin
147: // c.xor -> xor rd', rd', rs2'
148: instr_o = {7'b0, 2'b01, instr_i[4:2], 2'b01, instr_i[9:7], 3'b100,
149: 2'b01, instr_i[9:7], {OPCODE_OP}};
150: end
151:
152: 3'b010: begin
153: // c.or -> or rd', rd', rs2'
154: instr_o = {7'b0, 2'b01, instr_i[4:2], 2'b01, instr_i[9:7], 3'b110,
155: 2'b01, instr_i[9:7], {OPCODE_OP}};
156: end
157:
158: 3'b011: begin
159: // c.and -> and rd', rd', rs2'
160: instr_o = {7'b0, 2'b01, instr_i[4:2], 2'b01, instr_i[9:7], 3'b111,
161: 2'b01, instr_i[9:7], {OPCODE_OP}};
162: end
163:
164: 3'b100,
165: 3'b101,
166: 3'b110,
167: 3'b111: begin
168: // 100: c.subw
169: // 101: c.addw
170: illegal_instr_o = 1'b1;
171: end
172:
173: default: begin
174: illegal_instr_o = 1'b1;
175: end
176: endcase
177: end
178:
179: default: begin
180: illegal_instr_o = 1'b1;
181: end
182: endcase
183: end
184:
185: 3'b110, 3'b111: begin
186: // 0: c.beqz -> beq rs1', x0, imm
187: // 1: c.bnez -> bne rs1', x0, imm
188: instr_o = {{4 {instr_i[12]}}, instr_i[6:5], instr_i[2], 5'b0, 2'b01,
189: instr_i[9:7], 2'b00, instr_i[13], instr_i[11:10], instr_i[4:3],
190: instr_i[12], {OPCODE_BRANCH}};
191: end
192:
193: default: begin
194: illegal_instr_o = 1'b1;
195: end
196: endcase
197: end
198:
199: // C2
200: //
201: // Register address checks for RV32E are performed in the regular instruction decoder.
202: // If this check fails, an illegal instruction exception is triggered and the controller
203: // writes the actual faulting instruction to mtval.
204: 2'b10: begin
205: unique case (instr_i[15:13])
206: 3'b000: begin
207: // c.slli -> slli rd, rd, shamt
208: // (c.ssli hints are translated into a slli hint)
209: instr_o = {7'b0, instr_i[6:2], instr_i[11:7], 3'b001, instr_i[11:7], {OPCODE_OP_IMM}};
210: if (instr_i[12] == 1'b1) illegal_instr_o = 1'b1; // reserved for custom extensions
211: end
212:
213: 3'b010: begin
214: // c.lwsp -> lw rd, imm(x2)
215: instr_o = {4'b0, instr_i[3:2], instr_i[12], instr_i[6:4], 2'b00, 5'h02,
216: 3'b010, instr_i[11:7], OPCODE_LOAD};
217: if (instr_i[11:7] == 5'b0) illegal_instr_o = 1'b1;
218: end
219:
220: 3'b100: begin
221: if (instr_i[12] == 1'b0) begin
222: if (instr_i[6:2] != 5'b0) begin
223: // c.mv -> add rd/rs1, x0, rs2
224: // (c.mv hints are translated into an add hint)
225: instr_o = {7'b0, instr_i[6:2], 5'b0, 3'b0, instr_i[11:7], {OPCODE_OP}};
226: end else begin
227: // c.jr -> jalr x0, rd/rs1, 0
228: instr_o = {12'b0, instr_i[11:7], 3'b0, 5'b0, {OPCODE_JALR}};
229: if (instr_i[11:7] == 5'b0) illegal_instr_o = 1'b1;
230: end
231: end else begin
232: if (instr_i[6:2] != 5'b0) begin
233: // c.add -> add rd, rd, rs2
234: // (c.add hints are translated into an add hint)
235: instr_o = {7'b0, instr_i[6:2], instr_i[11:7], 3'b0, instr_i[11:7], {OPCODE_OP}};
236: end else begin
237: if (instr_i[11:7] == 5'b0) begin
238: // c.ebreak -> ebreak
239: instr_o = {32'h00_10_00_73};
240: end else begin
241: // c.jalr -> jalr x1, rs1, 0
242: instr_o = {12'b0, instr_i[11:7], 3'b000, 5'b00001, {OPCODE_JALR}};
243: end
244: end
245: end
246: end
247:
248: 3'b110: begin
249: // c.swsp -> sw rs2, imm(x2)
250: instr_o = {4'b0, instr_i[8:7], instr_i[12], instr_i[6:2], 5'h02, 3'b010,
251: instr_i[11:9], 2'b00, {OPCODE_STORE}};
252: end
253:
254: 3'b001,
255: 3'b011,
256: 3'b101,
257: 3'b111: begin
258: illegal_instr_o = 1'b1;
259: end
260:
261: default: begin
262: illegal_instr_o = 1'b1;
263: end
264: endcase
265: end
266:
267: // Incoming instruction is not compressed.
268: 2'b11:;
269:
270: default: begin
271: illegal_instr_o = 1'b1;
272: end
273: endcase
274: end
275:
276: assign is_compressed_o = (instr_i[1:0] != 2'b11);
277:
278: ////////////////
279: // Assertions //
280: ////////////////
281:
282: // Selectors must be known/valid.
283: `ASSERT(IbexInstrLSBsKnown, valid_i |->
284: !$isunknown(instr_i[1:0]), clk_i, !rst_ni)
285: `ASSERT(IbexC0Known1, (valid_i && (instr_i[1:0] == 2'b00)) |->
286: !$isunknown(instr_i[15:13]), clk_i, !rst_ni)
287: `ASSERT(IbexC1Known1, (valid_i && (instr_i[1:0] == 2'b01)) |->
288: !$isunknown(instr_i[15:13]), clk_i, !rst_ni)
289: `ASSERT(IbexC1Known2, (valid_i && (instr_i[1:0] == 2'b01) && (instr_i[15:13] == 3'b100)) |->
290: !$isunknown(instr_i[11:10]), clk_i, !rst_ni)
291: `ASSERT(IbexC1Known3, (valid_i &&
292: (instr_i[1:0] == 2'b01) && (instr_i[15:13] == 3'b100) && (instr_i[11:10] == 2'b11)) |->
293: !$isunknown({instr_i[12], instr_i[6:5]}), clk_i, !rst_ni)
294: `ASSERT(IbexC2Known1, (valid_i && (instr_i[1:0] == 2'b10)) |->
295: !$isunknown(instr_i[15:13]), clk_i, !rst_ni)
296:
297: endmodule
298: