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