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) {
222
                return Instr::Atomic(atomic);
223
            }
224
            return Instr::Unknown { bits: instr };
225
        },
226
        case 0x0f => {
227
            if instr == 0x100f {
228
                return Instr::FenceI;
229
            }
230
            if (instr & 0xf00fffff) == 0x0f {
231
                return Instr::Fence { predecessor: (instr >> 24) & 15, successor: (instr >> 20) & 15 };
232
            }
233
            return Instr::Unknown { bits: instr };
234
        },
235
        case encode::OP_LUI => {
236
            return Instr::Lui { rd, imm: immU(instr) };
237
        },
238
        case encode::OP_AUIPC => {
239
            return Instr::Auipc { rd, imm: immU(instr) };
240
        },
241
        case encode::OP_JAL => {
242
            return Instr::Jal { rd, imm: immJ(instr) };
243
        },
244
        case encode::OP_JALR => {
245
            return Instr::Jalr { rd, rs1, imm: immI(instr) };
246
        },
247
        case encode::OP_BRANCH => {
248
            let imm = immB(instr);
249
            match f3 {
250
                case encode::F3_BEQ  => return Instr::Beq { rs1, rs2, imm },
251
                case encode::F3_BNE  => return Instr::Bne { rs1, rs2, imm },
252
                case encode::F3_BLT  => return Instr::Blt { rs1, rs2, imm },
253
                case encode::F3_BGE  => return Instr::Bge { rs1, rs2, imm },
254
                case encode::F3_BLTU => return Instr::Bltu { rs1, rs2, imm },
255
                case encode::F3_BGEU => return Instr::Bgeu { rs1, rs2, imm },
256
                else                 => return Instr::Unknown { bits: instr },
257
            }
258
        },
259
        case encode::OP_LOAD => {
260
            let imm = immI(instr);
261
            match f3 {
262
                case encode::F3_BYTE   => return Instr::Lb { rd, rs1, imm },
263
                case encode::F3_HALF   => return Instr::Lh { rd, rs1, imm },
264
                case encode::F3_WORD   => return Instr::Lw { rd, rs1, imm },
265
                case encode::F3_DWORD  => return Instr::Ld { rd, rs1, imm },
266
                case encode::F3_BYTE_U => return Instr::Lbu { rd, rs1, imm },
267
                case encode::F3_HALF_U => return Instr::Lhu { rd, rs1, imm },
268
                case encode::F3_WORD_U => return Instr::Lwu { rd, rs1, imm },
269
                else                   => return Instr::Unknown { bits: instr },
270
            }
271
        },
272
        case encode::OP_STORE => {
273
            let imm = immS(instr);
274
            match f3 {
275
                case encode::F3_BYTE  => return Instr::Sb { rs2, rs1, imm },
276
                case encode::F3_HALF  => return Instr::Sh { rs2, rs1, imm },
277
                case encode::F3_WORD  => return Instr::Sw { rs2, rs1, imm },
278
                case encode::F3_DWORD => return Instr::Sd { rs2, rs1, imm },
279
                else                  => return Instr::Unknown { bits: instr },
280
            }
281
        },
282
        case encode::OP_IMM => {
283
            let imm = immI(instr);
284
            match f3 {
285
                case encode::F3_ADD  => return Instr::Addi { rd, rs1, imm },
286
                case encode::F3_SLT  => return Instr::Slti { rd, rs1, imm },
287
                case encode::F3_SLTU => return Instr::Sltiu { rd, rs1, imm },
288
                case encode::F3_XOR  => return Instr::Xori { rd, rs1, imm },
289
                case encode::F3_OR   => return Instr::Ori { rd, rs1, imm },
290
                case encode::F3_AND  => return Instr::Andi { rd, rs1, imm },
291
                case encode::F3_SLL  => return Instr::Slli { rd, rs1, shamt: imm & 0x3F },
292
                case encode::F3_SRL  => {
293
                    let shamt = imm & 0x3F;
294
                    if (imm & 0x400) <> 0 {
295
                        return Instr::Srai { rd, rs1, shamt };
296
                    } else {
297
                        return Instr::Srli { rd, rs1, shamt };
298
                    }
299
                },
300
                else => return Instr::Unknown { bits: instr },
301
            }
302
        },
303
        case encode::OP_OP => {
304
            if f7 == encode::F7_MUL {
305
                match f3 {
306
                    case encode::F3_ADD  => return Instr::Mul { rd, rs1, rs2 },
307
                    case encode::F3_SLL  => return Instr::Mulh { rd, rs1, rs2 },
308
                    case encode::F3_SLT  => return Instr::Mulhsu { rd, rs1, rs2 },
309
                    case encode::F3_SLTU => return Instr::Mulhu { rd, rs1, rs2 },
310
                    case encode::F3_XOR  => return Instr::Div { rd, rs1, rs2 },
311
                    case encode::F3_SRL  => return Instr::Divu { rd, rs1, rs2 },
312
                    case encode::F3_OR   => return Instr::Rem { rd, rs1, rs2 },
313
                    case encode::F3_AND  => return Instr::Remu { rd, rs1, rs2 },
314
                    else                 => return Instr::Unknown { bits: instr },
315
                }
316
            } else {
317
                match f3 {
318
                    case encode::F3_ADD => {
319
                        if f7 == encode::F7_SUB {
320
                            return Instr::Sub { rd, rs1, rs2 };
321
                        } else {
322
                            return Instr::Add { rd, rs1, rs2 };
323
                        }
324
                    },
325
                    case encode::F3_SLL  => return Instr::Sll { rd, rs1, rs2 },
326
                    case encode::F3_SLT  => return Instr::Slt { rd, rs1, rs2 },
327
                    case encode::F3_SLTU => return Instr::Sltu { rd, rs1, rs2 },
328
                    case encode::F3_XOR  => return Instr::Xor { rd, rs1, rs2 },
329
                    case encode::F3_SRL  => {
330
                        if f7 == encode::F7_SRA {
331
                            return Instr::Sra { rd, rs1, rs2 };
332
                        } else {
333
                            return Instr::Srl { rd, rs1, rs2 };
334
                        }
335
                    },
336
                    case encode::F3_OR  => return Instr::Or { rd, rs1, rs2 },
337
                    case encode::F3_AND => return Instr::And { rd, rs1, rs2 },
338
                    else                => return Instr::Unknown { bits: instr },
339
                }
340
            }
341
        },
342
        case encode::OP_IMM32 => {
343
            let imm = immI(instr);
344
            match f3 {
345
                case encode::F3_ADD => return Instr::Addiw { rd, rs1, imm },
346
                case encode::F3_SLL => return Instr::Slliw { rd, rs1, shamt: imm & 0x1F },
347
                case encode::F3_SRL => {
348
                    let shamt = imm & 0x1F;
349
                    if (imm & 0x400) <> 0 {
350
                        return Instr::Sraiw { rd, rs1, shamt };
351
                    } else {
352
                        return Instr::Srliw { rd, rs1, shamt };
353
                    }
354
                },
355
                else => return Instr::Unknown { bits: instr },
356
            }
357
        },
358
        case encode::OP_OP32 => {
359
            if f7 == encode::F7_MUL {
360
                match f3 {
361
                    case encode::F3_ADD => return Instr::Mulw { rd, rs1, rs2 },
362
                    case encode::F3_XOR => return Instr::Divw { rd, rs1, rs2 },
363
                    case encode::F3_SRL => return Instr::Divuw { rd, rs1, rs2 },
364
                    case encode::F3_OR  => return Instr::Remw { rd, rs1, rs2 },
365
                    case encode::F3_AND => return Instr::Remuw { rd, rs1, rs2 },
366
                    else                => return Instr::Unknown { bits: instr },
367
                }
368
            } else {
369
                match f3 {
370
                    case encode::F3_ADD => {
371
                        if f7 == encode::F7_SUB {
372
                            return Instr::Subw { rd, rs1, rs2 };
373
                        } else {
374
                            return Instr::Addw { rd, rs1, rs2 };
375
                        }
376
                    },
377
                    case encode::F3_SLL => return Instr::Sllw { rd, rs1, rs2 },
378
                    case encode::F3_SRL => {
379
                        if f7 == encode::F7_SRA {
380
                            return Instr::Sraw { rd, rs1, rs2 };
381
                        } else {
382
                            return Instr::Srlw { rd, rs1, rs2 };
383
                        }
384
                    },
385
                    else => return Instr::Unknown { bits: instr },
386
                }
387
            }
388
        },
389
        case encode::OP_SYSTEM => {
390
            let imm = immI(instr);
391
            if imm == 0 {
392
                return Instr::Ecall;
393
            } else if imm == 1 {
394
                return Instr::Ebreak;
395
            } else {
396
                return Instr::Unknown { bits: instr };
397
            }
398
        },
399
        else => {
400
            return Instr::Unknown { bits: instr };
401
        }
402
    }
403
}