lib/std/arch/rv64/decode.rad 14.6 KiB raw
1
//! RV64 instruction decoder.
2
//!
3
//! Decodes 32-bit instruction words into structured representations.
4
5
use super::encode;
6
7
///////////////////////
8
// Field Extraction  //
9
///////////////////////
10
11
/// Extract opcode (bits 6:0).
12
pub fn opcode(instr: u32) -> u32 {
13
    return instr & 0x7F;
14
}
15
16
/// Extract rd (bits 11:7).
17
pub fn rd(instr: u32) -> u8 {
18
    return ((instr >> 7) & 0x1F) as u8;
19
}
20
21
/// Extract funct3 (bits 14:12).
22
pub fn funct3(instr: u32) -> u32 {
23
    return (instr >> 12) & 0x07;
24
}
25
26
/// Extract rs1 (bits 19:15).
27
pub fn rs1(instr: u32) -> u8 {
28
    return ((instr >> 15) & 0x1F) as u8;
29
}
30
31
/// Extract rs2 (bits 24:20).
32
pub fn rs2(instr: u32) -> u8 {
33
    return ((instr >> 20) & 0x1F) as u8;
34
}
35
36
/// Extract funct7 (bits 31:25).
37
pub fn funct7(instr: u32) -> u32 {
38
    return instr >> 25;
39
}
40
41
//////////////////////////
42
// Immediate Extraction //
43
//////////////////////////
44
45
/// Extract I-type immediate (sign-extended).
46
pub fn immI(instr: u32) -> i32 {
47
    let imm = instr >> 20;
48
    if (imm & 0x800) != 0 {
49
        return (imm | 0xFFFFF000) as i32;
50
    }
51
    return imm as i32;
52
}
53
54
/// Extract S-type immediate (sign-extended).
55
pub fn immS(instr: u32) -> i32 {
56
    let lo = (instr >> 7) & 0x1F;
57
    let hi = (instr >> 25) & 0x7F;
58
    let imm = (hi << 5) | lo;
59
    if (imm & 0x800) != 0 {
60
        return (imm | 0xFFFFF000) as i32;
61
    }
62
    return imm as i32;
63
}
64
65
/// Extract B-type immediate (sign-extended).
66
pub fn immB(instr: u32) -> i32 {
67
    let imm11 = (instr >> 7) & 0x1;
68
    let imm4_1 = (instr >> 8) & 0xF;
69
    let imm10_5 = (instr >> 25) & 0x3F;
70
    let imm12 = (instr >> 31) & 0x1;
71
    let imm = (imm12 << 12) | (imm11 << 11) | (imm10_5 << 5) | (imm4_1 << 1);
72
    if (imm & 0x1000) != 0 {
73
        return (imm | 0xFFFFE000) as i32;
74
    }
75
    return imm as i32;
76
}
77
78
/// Extract J-type immediate (sign-extended).
79
pub fn immJ(instr: u32) -> i32 {
80
    let imm19_12 = (instr >> 12) & 0xFF;
81
    let imm11 = (instr >> 20) & 0x1;
82
    let imm10_1 = (instr >> 21) & 0x3FF;
83
    let imm20 = (instr >> 31) & 0x1;
84
    let imm = (imm20 << 20) | (imm19_12 << 12) | (imm11 << 11) | (imm10_1 << 1);
85
    if (imm & 0x100000) != 0 {
86
        return (imm | 0xFFE00000) as i32;
87
    }
88
    return imm as i32;
89
}
90
91
/// Extract U-type immediate (upper 20 bits, sign-extended).
92
pub fn immU(instr: u32) -> i32 {
93
    let imm = instr >> 12;
94
    if (imm & 0x80000) != 0 {
95
        return (imm | 0xFFF00000) as i32;
96
    }
97
    return imm as i32;
98
}
99
100
/////////////////////////
101
// Decoded Instruction //
102
/////////////////////////
103
104
/// Decoded RV64 instruction.
105
pub union Instr {
106
    // R-type ALU.
107
    Add  { rd: super::Reg, rs1: super::Reg, rs2: super::Reg },
108
    Sub  { rd: super::Reg, rs1: super::Reg, rs2: super::Reg },
109
    Sll  { rd: super::Reg, rs1: super::Reg, rs2: super::Reg },
110
    Slt  { rd: super::Reg, rs1: super::Reg, rs2: super::Reg },
111
    Sltu { rd: super::Reg, rs1: super::Reg, rs2: super::Reg },
112
    Xor  { rd: super::Reg, rs1: super::Reg, rs2: super::Reg },
113
    Srl  { rd: super::Reg, rs1: super::Reg, rs2: super::Reg },
114
    Sra  { rd: super::Reg, rs1: super::Reg, rs2: super::Reg },
115
    Or   { rd: super::Reg, rs1: super::Reg, rs2: super::Reg },
116
    And  { rd: super::Reg, rs1: super::Reg, rs2: super::Reg },
117
118
    // R-type M extension.
119
    Mul    { rd: super::Reg, rs1: super::Reg, rs2: super::Reg },
120
    Mulh   { rd: super::Reg, rs1: super::Reg, rs2: super::Reg },
121
    Mulhsu { rd: super::Reg, rs1: super::Reg, rs2: super::Reg },
122
    Mulhu  { rd: super::Reg, rs1: super::Reg, rs2: super::Reg },
123
    Div    { rd: super::Reg, rs1: super::Reg, rs2: super::Reg },
124
    Divu   { rd: super::Reg, rs1: super::Reg, rs2: super::Reg },
125
    Rem    { rd: super::Reg, rs1: super::Reg, rs2: super::Reg },
126
    Remu   { rd: super::Reg, rs1: super::Reg, rs2: super::Reg },
127
128
    // R-type RV64 word operations.
129
    Addw  { rd: super::Reg, rs1: super::Reg, rs2: super::Reg },
130
    Subw  { rd: super::Reg, rs1: super::Reg, rs2: super::Reg },
131
    Sllw  { rd: super::Reg, rs1: super::Reg, rs2: super::Reg },
132
    Srlw  { rd: super::Reg, rs1: super::Reg, rs2: super::Reg },
133
    Sraw  { rd: super::Reg, rs1: super::Reg, rs2: super::Reg },
134
    Mulw  { rd: super::Reg, rs1: super::Reg, rs2: super::Reg },
135
    Divw  { rd: super::Reg, rs1: super::Reg, rs2: super::Reg },
136
    Divuw { rd: super::Reg, rs1: super::Reg, rs2: super::Reg },
137
    Remw  { rd: super::Reg, rs1: super::Reg, rs2: super::Reg },
138
    Remuw { rd: super::Reg, rs1: super::Reg, rs2: super::Reg },
139
140
    // I-type ALU.
141
    Addi  { rd: super::Reg, rs1: super::Reg, imm: i32 },
142
    Slti  { rd: super::Reg, rs1: super::Reg, imm: i32 },
143
    Sltiu { rd: super::Reg, rs1: super::Reg, imm: i32 },
144
    Xori  { rd: super::Reg, rs1: super::Reg, imm: i32 },
145
    Ori   { rd: super::Reg, rs1: super::Reg, imm: i32 },
146
    Andi  { rd: super::Reg, rs1: super::Reg, imm: i32 },
147
    Slli  { rd: super::Reg, rs1: super::Reg, shamt: i32 },
148
    Srli  { rd: super::Reg, rs1: super::Reg, shamt: i32 },
149
    Srai  { rd: super::Reg, rs1: super::Reg, shamt: i32 },
150
151
    // I-type RV64 word immediate operations.
152
    Addiw { rd: super::Reg, rs1: super::Reg, imm: i32 },
153
    Slliw { rd: super::Reg, rs1: super::Reg, shamt: i32 },
154
    Srliw { rd: super::Reg, rs1: super::Reg, shamt: i32 },
155
    Sraiw { rd: super::Reg, rs1: super::Reg, shamt: i32 },
156
157
    // Load instructions.
158
    Lb  { rd: super::Reg, rs1: super::Reg, imm: i32 },
159
    Lh  { rd: super::Reg, rs1: super::Reg, imm: i32 },
160
    Lw  { rd: super::Reg, rs1: super::Reg, imm: i32 },
161
    Ld  { rd: super::Reg, rs1: super::Reg, imm: i32 },
162
    Lbu { rd: super::Reg, rs1: super::Reg, imm: i32 },
163
    Lhu { rd: super::Reg, rs1: super::Reg, imm: i32 },
164
    Lwu { rd: super::Reg, rs1: super::Reg, imm: i32 },
165
166
    // Store instructions.
167
    Sb { rs2: super::Reg, rs1: super::Reg, imm: i32 },
168
    Sh { rs2: super::Reg, rs1: super::Reg, imm: i32 },
169
    Sw { rs2: super::Reg, rs1: super::Reg, imm: i32 },
170
    Sd { rs2: super::Reg, rs1: super::Reg, imm: i32 },
171
172
    // Branch instructions.
173
    Beq  { rs1: super::Reg, rs2: super::Reg, imm: i32 },
174
    Bne  { rs1: super::Reg, rs2: super::Reg, imm: i32 },
175
    Blt  { rs1: super::Reg, rs2: super::Reg, imm: i32 },
176
    Bge  { rs1: super::Reg, rs2: super::Reg, imm: i32 },
177
    Bltu { rs1: super::Reg, rs2: super::Reg, imm: i32 },
178
    Bgeu { rs1: super::Reg, rs2: super::Reg, imm: i32 },
179
180
    // Jump instructions.
181
    Jal  { rd: super::Reg, imm: i32 },
182
    Jalr { rd: super::Reg, rs1: super::Reg, imm: i32 },
183
184
    // Upper immediate.
185
    Lui   { rd: super::Reg, imm: i32 },
186
    Auipc { rd: super::Reg, imm: i32 },
187
188
    // System.
189
    Ecall,
190
    Ebreak,
191
192
    // Unknown/invalid instruction.
193
    Unknown { bits: u32 },
194
}
195
196
/// Decode a 32-bit instruction word into an [`Instr`].
197
pub fn decode(instr: u32) -> Instr {
198
    let op = opcode(instr);
199
    let f3 = funct3(instr);
200
    let f7 = funct7(instr);
201
    let rd = super::reg(rd(instr));
202
    let rs1 = super::reg(rs1(instr));
203
    let rs2 = super::reg(rs2(instr));
204
205
    match op {
206
        case encode::OP_LUI => {
207
            return Instr::Lui { rd, imm: immU(instr) };
208
        },
209
        case encode::OP_AUIPC => {
210
            return Instr::Auipc { rd, imm: immU(instr) };
211
        },
212
        case encode::OP_JAL => {
213
            return Instr::Jal { rd, imm: immJ(instr) };
214
        },
215
        case encode::OP_JALR => {
216
            return Instr::Jalr { rd, rs1, imm: immI(instr) };
217
        },
218
        case encode::OP_BRANCH => {
219
            let imm = immB(instr);
220
            match f3 {
221
                case encode::F3_BEQ  => return Instr::Beq { rs1, rs2, imm },
222
                case encode::F3_BNE  => return Instr::Bne { rs1, rs2, imm },
223
                case encode::F3_BLT  => return Instr::Blt { rs1, rs2, imm },
224
                case encode::F3_BGE  => return Instr::Bge { rs1, rs2, imm },
225
                case encode::F3_BLTU => return Instr::Bltu { rs1, rs2, imm },
226
                case encode::F3_BGEU => return Instr::Bgeu { rs1, rs2, imm },
227
                else                 => return Instr::Unknown { bits: instr },
228
            }
229
        },
230
        case encode::OP_LOAD => {
231
            let imm = immI(instr);
232
            match f3 {
233
                case encode::F3_BYTE   => return Instr::Lb { rd, rs1, imm },
234
                case encode::F3_HALF   => return Instr::Lh { rd, rs1, imm },
235
                case encode::F3_WORD   => return Instr::Lw { rd, rs1, imm },
236
                case encode::F3_DWORD  => return Instr::Ld { rd, rs1, imm },
237
                case encode::F3_BYTE_U => return Instr::Lbu { rd, rs1, imm },
238
                case encode::F3_HALF_U => return Instr::Lhu { rd, rs1, imm },
239
                case encode::F3_WORD_U => return Instr::Lwu { rd, rs1, imm },
240
                else                   => return Instr::Unknown { bits: instr },
241
            }
242
        },
243
        case encode::OP_STORE => {
244
            let imm = immS(instr);
245
            match f3 {
246
                case encode::F3_BYTE  => return Instr::Sb { rs2, rs1, imm },
247
                case encode::F3_HALF  => return Instr::Sh { rs2, rs1, imm },
248
                case encode::F3_WORD  => return Instr::Sw { rs2, rs1, imm },
249
                case encode::F3_DWORD => return Instr::Sd { rs2, rs1, imm },
250
                else                  => return Instr::Unknown { bits: instr },
251
            }
252
        },
253
        case encode::OP_IMM => {
254
            let imm = immI(instr);
255
            match f3 {
256
                case encode::F3_ADD  => return Instr::Addi { rd, rs1, imm },
257
                case encode::F3_SLT  => return Instr::Slti { rd, rs1, imm },
258
                case encode::F3_SLTU => return Instr::Sltiu { rd, rs1, imm },
259
                case encode::F3_XOR  => return Instr::Xori { rd, rs1, imm },
260
                case encode::F3_OR   => return Instr::Ori { rd, rs1, imm },
261
                case encode::F3_AND  => return Instr::Andi { rd, rs1, imm },
262
                case encode::F3_SLL  => return Instr::Slli { rd, rs1, shamt: imm & 0x3F },
263
                case encode::F3_SRL  => {
264
                    let shamt = imm & 0x3F;
265
                    if (imm & 0x400) != 0 {
266
                        return Instr::Srai { rd, rs1, shamt };
267
                    } else {
268
                        return Instr::Srli { rd, rs1, shamt };
269
                    }
270
                },
271
                else => return Instr::Unknown { bits: instr },
272
            }
273
        },
274
        case encode::OP_OP => {
275
            if f7 == encode::F7_MUL {
276
                match f3 {
277
                    case encode::F3_ADD  => return Instr::Mul { rd, rs1, rs2 },
278
                    case encode::F3_SLL  => return Instr::Mulh { rd, rs1, rs2 },
279
                    case encode::F3_SLT  => return Instr::Mulhsu { rd, rs1, rs2 },
280
                    case encode::F3_SLTU => return Instr::Mulhu { rd, rs1, rs2 },
281
                    case encode::F3_XOR  => return Instr::Div { rd, rs1, rs2 },
282
                    case encode::F3_SRL  => return Instr::Divu { rd, rs1, rs2 },
283
                    case encode::F3_OR   => return Instr::Rem { rd, rs1, rs2 },
284
                    case encode::F3_AND  => return Instr::Remu { rd, rs1, rs2 },
285
                    else                 => return Instr::Unknown { bits: instr },
286
                }
287
            } else {
288
                match f3 {
289
                    case encode::F3_ADD => {
290
                        if f7 == encode::F7_SUB {
291
                            return Instr::Sub { rd, rs1, rs2 };
292
                        } else {
293
                            return Instr::Add { rd, rs1, rs2 };
294
                        }
295
                    },
296
                    case encode::F3_SLL  => return Instr::Sll { rd, rs1, rs2 },
297
                    case encode::F3_SLT  => return Instr::Slt { rd, rs1, rs2 },
298
                    case encode::F3_SLTU => return Instr::Sltu { rd, rs1, rs2 },
299
                    case encode::F3_XOR  => return Instr::Xor { rd, rs1, rs2 },
300
                    case encode::F3_SRL  => {
301
                        if f7 == encode::F7_SRA {
302
                            return Instr::Sra { rd, rs1, rs2 };
303
                        } else {
304
                            return Instr::Srl { rd, rs1, rs2 };
305
                        }
306
                    },
307
                    case encode::F3_OR  => return Instr::Or { rd, rs1, rs2 },
308
                    case encode::F3_AND => return Instr::And { rd, rs1, rs2 },
309
                    else                => return Instr::Unknown { bits: instr },
310
                }
311
            }
312
        },
313
        case encode::OP_IMM32 => {
314
            let imm = immI(instr);
315
            match f3 {
316
                case encode::F3_ADD => return Instr::Addiw { rd, rs1, imm },
317
                case encode::F3_SLL => return Instr::Slliw { rd, rs1, shamt: imm & 0x1F },
318
                case encode::F3_SRL => {
319
                    let shamt = imm & 0x1F;
320
                    if (imm & 0x400) != 0 {
321
                        return Instr::Sraiw { rd, rs1, shamt };
322
                    } else {
323
                        return Instr::Srliw { rd, rs1, shamt };
324
                    }
325
                },
326
                else => return Instr::Unknown { bits: instr },
327
            }
328
        },
329
        case encode::OP_OP32 => {
330
            if f7 == encode::F7_MUL {
331
                match f3 {
332
                    case encode::F3_ADD => return Instr::Mulw { rd, rs1, rs2 },
333
                    case encode::F3_XOR => return Instr::Divw { rd, rs1, rs2 },
334
                    case encode::F3_SRL => return Instr::Divuw { rd, rs1, rs2 },
335
                    case encode::F3_OR  => return Instr::Remw { rd, rs1, rs2 },
336
                    case encode::F3_AND => return Instr::Remuw { rd, rs1, rs2 },
337
                    else                => return Instr::Unknown { bits: instr },
338
                }
339
            } else {
340
                match f3 {
341
                    case encode::F3_ADD => {
342
                        if f7 == encode::F7_SUB {
343
                            return Instr::Subw { rd, rs1, rs2 };
344
                        } else {
345
                            return Instr::Addw { rd, rs1, rs2 };
346
                        }
347
                    },
348
                    case encode::F3_SLL => return Instr::Sllw { rd, rs1, rs2 },
349
                    case encode::F3_SRL => {
350
                        if f7 == encode::F7_SRA {
351
                            return Instr::Sraw { rd, rs1, rs2 };
352
                        } else {
353
                            return Instr::Srlw { rd, rs1, rs2 };
354
                        }
355
                    },
356
                    else => return Instr::Unknown { bits: instr },
357
                }
358
            }
359
        },
360
        case encode::OP_SYSTEM => {
361
            let imm = immI(instr);
362
            if imm == 0 {
363
                return Instr::Ecall;
364
            } else if imm == 1 {
365
                return Instr::Ebreak;
366
            } else {
367
                return Instr::Unknown { bits: instr };
368
            }
369
        },
370
        else => {
371
            return Instr::Unknown { bits: instr };
372
        }
373
    }
374
}