virtual-machine 0.0.4 → 0.0.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/src/decoder.rs DELETED
@@ -1,789 +0,0 @@
1
- use crate::Trap;
2
-
3
- #[derive(Debug, Clone, Copy, PartialEq)]
4
- pub enum Register {
5
- X0,
6
- X1,
7
- X2,
8
- X3,
9
- X4,
10
- X5,
11
- X6,
12
- X7,
13
- X8,
14
- X9,
15
- X10,
16
- X11,
17
- X12,
18
- X13,
19
- X14,
20
- X15,
21
- X16,
22
- X17,
23
- X18,
24
- X19,
25
- X20,
26
- X21,
27
- X22,
28
- X23,
29
- X24,
30
- X25,
31
- X26,
32
- X27,
33
- X28,
34
- X29,
35
- X30,
36
- X31,
37
- }
38
-
39
- impl Register {
40
- pub fn from_u32(v: u32) -> Self {
41
- match v & 0x1F {
42
- 0 => Register::X0,
43
- 1 => Register::X1,
44
- 2 => Register::X2,
45
- 3 => Register::X3,
46
- 4 => Register::X4,
47
- 5 => Register::X5,
48
- 6 => Register::X6,
49
- 7 => Register::X7,
50
- 8 => Register::X8,
51
- 9 => Register::X9,
52
- 10 => Register::X10,
53
- 11 => Register::X11,
54
- 12 => Register::X12,
55
- 13 => Register::X13,
56
- 14 => Register::X14,
57
- 15 => Register::X15,
58
- 16 => Register::X16,
59
- 17 => Register::X17,
60
- 18 => Register::X18,
61
- 19 => Register::X19,
62
- 20 => Register::X20,
63
- 21 => Register::X21,
64
- 22 => Register::X22,
65
- 23 => Register::X23,
66
- 24 => Register::X24,
67
- 25 => Register::X25,
68
- 26 => Register::X26,
69
- 27 => Register::X27,
70
- 28 => Register::X28,
71
- 29 => Register::X29,
72
- 30 => Register::X30,
73
- 31 => Register::X31,
74
- _ => unreachable!(),
75
- }
76
- }
77
-
78
- pub fn to_usize(&self) -> usize {
79
- *self as usize
80
- }
81
- }
82
-
83
- #[derive(Debug, Clone, PartialEq)]
84
- pub enum Op {
85
- Lui {
86
- rd: Register,
87
- imm: i64,
88
- },
89
- Auipc {
90
- rd: Register,
91
- imm: i64,
92
- },
93
- Jal {
94
- rd: Register,
95
- imm: i64,
96
- },
97
- Jalr {
98
- rd: Register,
99
- rs1: Register,
100
- imm: i64,
101
- },
102
- Branch {
103
- rs1: Register,
104
- rs2: Register,
105
- imm: i64,
106
- funct3: u32,
107
- },
108
- Load {
109
- rd: Register,
110
- rs1: Register,
111
- imm: i64,
112
- funct3: u32,
113
- },
114
- Store {
115
- rs1: Register,
116
- rs2: Register,
117
- imm: i64,
118
- funct3: u32,
119
- },
120
- OpImm {
121
- rd: Register,
122
- rs1: Register,
123
- imm: i64,
124
- funct3: u32,
125
- funct7: u32,
126
- }, // I-type ALU (ADDI etc)
127
- Op {
128
- rd: Register,
129
- rs1: Register,
130
- rs2: Register,
131
- funct3: u32,
132
- funct7: u32,
133
- }, // R-type ALU
134
- OpImm32 {
135
- rd: Register,
136
- rs1: Register,
137
- imm: i64,
138
- funct3: u32,
139
- funct7: u32,
140
- }, // ADDIW etc
141
- Op32 {
142
- rd: Register,
143
- rs1: Register,
144
- rs2: Register,
145
- funct3: u32,
146
- funct7: u32,
147
- }, // ADDW etc
148
- System {
149
- rd: Register,
150
- rs1: Register,
151
- funct3: u32,
152
- imm: u32,
153
- }, // CSRs / Ecall (imm used for csr addr usually)
154
- Amo {
155
- rd: Register,
156
- rs1: Register,
157
- rs2: Register,
158
- funct3: u32,
159
- funct5: u32,
160
- aq: bool,
161
- rl: bool,
162
- }, // RV64A atomics (LR/SC/AMO*)
163
- Fence, // FENCE / FENCE.I
164
- }
165
-
166
- pub fn decode(insn: u32) -> Result<Op, Trap> {
167
- let opcode = insn & 0x7F;
168
- let rd = Register::from_u32((insn >> 7) & 0x1F);
169
- let funct3 = (insn >> 12) & 0x7;
170
- let rs1 = Register::from_u32((insn >> 15) & 0x1F);
171
- let rs2 = Register::from_u32((insn >> 20) & 0x1F);
172
- let funct7 = (insn >> 25) & 0x7F;
173
-
174
- // Sign extension helpers
175
- let imm_i = ((insn as i32) >> 20) as i64;
176
- let imm_s = (((insn as i32) >> 25) << 5) as i64 | (((insn >> 7) & 0x1F) as i64);
177
- // B-type: imm[12|10:5|4:1|11]
178
- let imm_b = {
179
- let bit31 = (insn >> 31) & 1;
180
- let bit30_25 = (insn >> 25) & 0x3F;
181
- let bit11_8 = (insn >> 8) & 0xF;
182
- let bit7 = (insn >> 7) & 1;
183
- let val = (bit31 << 12) | (bit7 << 11) | (bit30_25 << 5) | (bit11_8 << 1);
184
- // Sign extend from bit 12
185
- ((val as i32) << 19 >> 19) as i64
186
- };
187
- // U-type: imm[31:12]
188
- let imm_u = ((insn as i32) & 0xFFFFF000u32 as i32) as i64;
189
- // J-type: imm[20|10:1|11|19:12]
190
- let imm_j = {
191
- let bit31 = (insn >> 31) & 1;
192
- let bit30_21 = (insn >> 21) & 0x3FF;
193
- let bit20 = (insn >> 20) & 1;
194
- let bit19_12 = (insn >> 12) & 0xFF;
195
- let val = (bit31 << 20) | (bit19_12 << 12) | (bit20 << 11) | (bit30_21 << 1);
196
- ((val as i32) << 11 >> 11) as i64
197
- };
198
-
199
- match opcode {
200
- 0x37 => Ok(Op::Lui { rd, imm: imm_u }),
201
- 0x17 => Ok(Op::Auipc { rd, imm: imm_u }),
202
- 0x6F => Ok(Op::Jal { rd, imm: imm_j }),
203
- 0x67 => Ok(Op::Jalr {
204
- rd,
205
- rs1,
206
- imm: imm_i,
207
- }),
208
- 0x63 => Ok(Op::Branch {
209
- rs1,
210
- rs2,
211
- imm: imm_b,
212
- funct3,
213
- }),
214
- 0x03 => Ok(Op::Load {
215
- rd,
216
- rs1,
217
- imm: imm_i,
218
- funct3,
219
- }),
220
- 0x23 => Ok(Op::Store {
221
- rs1,
222
- rs2,
223
- imm: imm_s,
224
- funct3,
225
- }),
226
- 0x13 => Ok(Op::OpImm {
227
- rd,
228
- rs1,
229
- imm: imm_i,
230
- funct3,
231
- funct7,
232
- }),
233
- 0x33 => Ok(Op::Op {
234
- rd,
235
- rs1,
236
- rs2,
237
- funct3,
238
- funct7,
239
- }),
240
- 0x1B => Ok(Op::OpImm32 {
241
- rd,
242
- rs1,
243
- imm: imm_i,
244
- funct3,
245
- funct7,
246
- }),
247
- 0x3B => Ok(Op::Op32 {
248
- rd,
249
- rs1,
250
- rs2,
251
- funct3,
252
- funct7,
253
- }),
254
- 0x2F => {
255
- // A-extension (atomics)
256
- let funct5 = (insn >> 27) & 0x1F;
257
- let aq = ((insn >> 26) & 1) != 0;
258
- let rl = ((insn >> 25) & 1) != 0;
259
- Ok(Op::Amo {
260
- rd,
261
- rs1,
262
- rs2,
263
- funct3,
264
- funct5,
265
- aq,
266
- rl,
267
- })
268
- }
269
- 0x73 => {
270
- let i_imm = (insn >> 20) & 0xFFF;
271
- Ok(Op::System {
272
- rd,
273
- rs1,
274
- funct3,
275
- imm: i_imm,
276
- })
277
- }
278
- 0x0F => Ok(Op::Fence),
279
-
280
- _ => Err(Trap::IllegalInstruction(insn as u64)),
281
- }
282
- }
283
-
284
- // -------- Compressed (C) extension expansion ---------------------------------
285
- //
286
- // These helpers expand 16-bit compressed instructions into canonical 32-bit
287
- // encodings, which are then fed through the normal `decode()` function.
288
-
289
- fn encode_i(imm: i32, rs1: u32, funct3: u32, rd: u32, opcode: u32) -> u32 {
290
- let imm12 = (imm as u32) & 0xFFF;
291
- (imm12 << 20) | (rs1 << 15) | (funct3 << 12) | (rd << 7) | opcode
292
- }
293
-
294
- fn encode_u(imm: i32, rd: u32, opcode: u32) -> u32 {
295
- // U-type: imm[31:12] in bits[31:12], low 12 bits zero.
296
- let imm20 = ((imm as u32) >> 12) & 0xFFFFF;
297
- (imm20 << 12) | (rd << 7) | opcode
298
- }
299
-
300
- fn encode_r(funct7: u32, rs2: u32, rs1: u32, funct3: u32, rd: u32, opcode: u32) -> u32 {
301
- (funct7 << 25) | (rs2 << 20) | (rs1 << 15) | (funct3 << 12) | (rd << 7) | opcode
302
- }
303
-
304
- fn encode_s(imm: i32, rs2: u32, rs1: u32, funct3: u32, opcode: u32) -> u32 {
305
- let imm12 = (imm as u32) & 0xFFF;
306
- let imm11_5 = (imm12 >> 5) & 0x7F;
307
- let imm4_0 = imm12 & 0x1F;
308
- (imm11_5 << 25)
309
- | (rs2 << 20)
310
- | (rs1 << 15)
311
- | (funct3 << 12)
312
- | (imm4_0 << 7)
313
- | opcode
314
- }
315
-
316
- fn encode_j(imm: i32, rd: u32) -> u32 {
317
- // J-type immediate, imm is already the signed byte offset.
318
- let imm20 = ((imm >> 20) & 0x1) as u32;
319
- let imm10_1 = ((imm >> 1) & 0x3FF) as u32;
320
- let imm11 = ((imm >> 11) & 0x1) as u32;
321
- let imm19_12 = ((imm >> 12) & 0xFF) as u32;
322
- (imm20 << 31) | (imm19_12 << 12) | (imm11 << 20) | (imm10_1 << 21) | (rd << 7) | 0x6F
323
- }
324
-
325
- fn encode_b(imm: i32, rs2: u32, rs1: u32, funct3: u32, opcode: u32) -> u32 {
326
- // B-type immediate, imm is signed byte offset (multiple of 2).
327
- let imm13 = (imm as u32) & 0x1FFF;
328
- let imm12 = (imm13 >> 12) & 0x1;
329
- let imm10_5 = (imm13 >> 5) & 0x3F;
330
- let imm4_1 = (imm13 >> 1) & 0xF;
331
- let imm11 = (imm13 >> 11) & 0x1;
332
- (imm12 << 31)
333
- | (imm10_5 << 25)
334
- | (rs2 << 20)
335
- | (rs1 << 15)
336
- | (funct3 << 12)
337
- | (imm4_1 << 8)
338
- | (imm11 << 7)
339
- | opcode
340
- }
341
-
342
- fn sext(value: u32, bits: u8) -> i32 {
343
- let shift = 32 - bits as i32;
344
- ((value << shift) as i32) >> shift
345
- }
346
-
347
- pub fn expand_compressed(insn: u16) -> Result<u32, Trap> {
348
- let opcode = insn & 0x3;
349
- let funct3 = (insn >> 13) & 0x7;
350
-
351
- match opcode {
352
- 0b00 => expand_q0(insn, funct3),
353
- 0b01 => expand_q1(insn, funct3),
354
- 0b10 => expand_q2(insn, funct3),
355
- _ => Err(Trap::IllegalInstruction(insn as u64)),
356
- }
357
- }
358
-
359
- fn expand_q0(insn: u16, funct3: u16) -> Result<u32, Trap> {
360
- let insn_u = insn as u32;
361
- match funct3 {
362
- // C.ADDI4SPN -> ADDI rd', x2, nzuimm
363
- 0b000 => {
364
- let nzuimm = (((insn_u >> 6) & 0x1) << 2)
365
- | (((insn_u >> 5) & 0x1) << 3)
366
- | (((insn_u >> 11) & 0x3) << 4)
367
- | (((insn_u >> 7) & 0xF) << 6);
368
- if nzuimm == 0 {
369
- return Err(Trap::IllegalInstruction(insn as u64));
370
- }
371
- let rd_prime = 8 + ((insn_u >> 2) & 0x7);
372
- Ok(encode_i(nzuimm as i32, 2, 0x0, rd_prime, 0x13))
373
- }
374
- // C.LW -> LW rd', uimm(rs1')
375
- 0b010 => {
376
- let uimm =
377
- (((insn_u >> 6) & 0x1) << 2) | (((insn_u >> 10) & 0x7) << 3) | (((insn_u >> 5) & 0x1) << 6);
378
- let rd_prime = 8 + ((insn_u >> 2) & 0x7);
379
- let rs1_prime = 8 + ((insn_u >> 7) & 0x7);
380
- Ok(encode_i(uimm as i32, rs1_prime, 0x2, rd_prime, 0x03))
381
- }
382
- // C.LD -> LD rd', uimm(rs1')
383
- 0b011 => {
384
- let uimm = (((insn_u >> 10) & 0x7) << 3) | (((insn_u >> 5) & 0x3) << 6);
385
- let rd_prime = 8 + ((insn_u >> 2) & 0x7);
386
- let rs1_prime = 8 + ((insn_u >> 7) & 0x7);
387
- Ok(encode_i(uimm as i32, rs1_prime, 0x3, rd_prime, 0x03))
388
- }
389
- // C.SW -> SW rs2', uimm(rs1')
390
- 0b110 => {
391
- let uimm =
392
- (((insn_u >> 6) & 0x1) << 2) | (((insn_u >> 10) & 0x7) << 3) | (((insn_u >> 5) & 0x1) << 6);
393
- let rs2_prime = 8 + ((insn_u >> 2) & 0x7);
394
- let rs1_prime = 8 + ((insn_u >> 7) & 0x7);
395
- Ok(encode_s(uimm as i32, rs2_prime, rs1_prime, 0x2, 0x23))
396
- }
397
- // C.SD -> SD rs2', uimm(rs1')
398
- 0b111 => {
399
- let uimm = (((insn_u >> 10) & 0x7) << 3) | (((insn_u >> 5) & 0x3) << 6);
400
- let rs2_prime = 8 + ((insn_u >> 2) & 0x7);
401
- let rs1_prime = 8 + ((insn_u >> 7) & 0x7);
402
- Ok(encode_s(uimm as i32, rs2_prime, rs1_prime, 0x3, 0x23))
403
- }
404
- _ => Err(Trap::IllegalInstruction(insn as u64)),
405
- }
406
- }
407
-
408
- fn expand_q1(insn: u16, funct3: u16) -> Result<u32, Trap> {
409
- let insn_u = insn as u32;
410
- match funct3 {
411
- // C.NOP / C.ADDI
412
- 0b000 => {
413
- let rd = (insn_u >> 7) & 0x1F;
414
- let imm_bits = ((insn_u >> 2) & 0x1F) | (((insn_u >> 12) & 0x1) << 5);
415
- let imm = sext(imm_bits, 6);
416
- if rd == 0 {
417
- if imm == 0 {
418
- // C.NOP
419
- return Ok(encode_i(0, 0, 0x0, 0, 0x13));
420
- } else {
421
- return Err(Trap::IllegalInstruction(insn as u64));
422
- }
423
- }
424
- Ok(encode_i(imm, rd, 0x0, rd, 0x13)) // ADDI rd, rd, imm
425
- }
426
- // RV64: C.ADDIW
427
- 0b001 => {
428
- let rd = (insn_u >> 7) & 0x1F;
429
- let imm_bits = ((insn_u >> 2) & 0x1F) | (((insn_u >> 12) & 0x1) << 5);
430
- let imm = sext(imm_bits, 6);
431
- if rd == 0 {
432
- return Err(Trap::IllegalInstruction(insn as u64));
433
- }
434
- Ok(encode_i(imm, rd, 0x0, rd, 0x1B)) // ADDIW rd, rd, imm
435
- }
436
- // C.LI -> ADDI rd, x0, imm
437
- 0b010 => {
438
- let rd = (insn_u >> 7) & 0x1F;
439
- let imm_bits = ((insn_u >> 2) & 0x1F) | (((insn_u >> 12) & 0x1) << 5);
440
- let imm = sext(imm_bits, 6);
441
- if rd == 0 {
442
- return Err(Trap::IllegalInstruction(insn as u64));
443
- }
444
- Ok(encode_i(imm, 0, 0x0, rd, 0x13))
445
- }
446
- // C.ADDI16SP / C.LUI
447
- 0b011 => {
448
- let rd = (insn_u >> 7) & 0x1F;
449
- if rd == 2 {
450
- // C.ADDI16SP
451
- let mut nz = 0u32;
452
- nz |= ((insn_u >> 12) & 0x1) << 9;
453
- nz |= ((insn_u >> 3) & 0x3) << 7;
454
- nz |= ((insn_u >> 5) & 0x1) << 6;
455
- nz |= ((insn_u >> 2) & 0x1) << 5;
456
- nz |= ((insn_u >> 6) & 0x1) << 4;
457
- if nz == 0 {
458
- return Err(Trap::IllegalInstruction(insn as u64));
459
- }
460
- let imm = sext(nz, 10);
461
- Ok(encode_i(imm, 2, 0x0, 2, 0x13)) // ADDI x2,x2,imm
462
- } else {
463
- // C.LUI -> LUI rd, imm
464
- let imm_bits = ((insn_u >> 2) & 0x1F) | (((insn_u >> 12) & 0x1) << 5);
465
- if rd == 0 || imm_bits == 0 {
466
- return Err(Trap::IllegalInstruction(insn as u64));
467
- }
468
- let imm = sext(imm_bits, 6);
469
- Ok(encode_u(imm << 12, rd, 0x37))
470
- }
471
- }
472
- // C.SRLI / C.SRAI / C.ANDI / C.SUB/XOR/OR/AND
473
- 0b100 => {
474
- let rs1_prime = 8 + ((insn_u >> 7) & 0x7);
475
- let rs2_prime = 8 + ((insn_u >> 2) & 0x7);
476
- let op = (insn_u >> 10) & 0x3;
477
- match op {
478
- // C.SRLI
479
- 0b00 => {
480
- let shamt_bits = ((insn_u >> 2) & 0x1F) | (((insn_u >> 12) & 0x1) << 5);
481
- let shamt = shamt_bits & 0x3F; // RV64: 6-bit shamt
482
- Ok(encode_i(shamt as i32, rs1_prime, 0x5, rs1_prime, 0x13)) // SRLI
483
- }
484
- // C.SRAI
485
- 0b01 => {
486
- let shamt_bits = ((insn_u >> 2) & 0x1F) | (((insn_u >> 12) & 0x1) << 5);
487
- let shamt = shamt_bits & 0x3F;
488
- // SRAI encoding: funct7=0b0100000, funct3=101
489
- Ok(encode_i((0x20 << 6) | (shamt as i32), rs1_prime, 0x5, rs1_prime, 0x13))
490
- }
491
- // C.ANDI
492
- 0b10 => {
493
- let imm_bits = ((insn_u >> 2) & 0x1F) | (((insn_u >> 12) & 0x1) << 5);
494
- let imm = sext(imm_bits, 6);
495
- Ok(encode_i(imm, rs1_prime, 0x7, rs1_prime, 0x13))
496
- }
497
- // C.SUB / C.XOR / C.OR / C.AND (bit12=0) or C.SUBW / C.ADDW (bit12=1, RV64)
498
- 0b11 => {
499
- let bit12 = (insn_u >> 12) & 0x1;
500
- let funct2 = (insn_u >> 5) & 0x3;
501
-
502
- if bit12 == 0 {
503
- // C.SUB / C.XOR / C.OR / C.AND -> R-type with opcode 0x33
504
- let (funct3, funct7) = match funct2 {
505
- 0b00 => (0x0, 0x20), // SUB
506
- 0b01 => (0x4, 0x00), // XOR
507
- 0b10 => (0x6, 0x00), // OR
508
- 0b11 => (0x7, 0x00), // AND
509
- _ => unreachable!(),
510
- };
511
- Ok(
512
- (funct7 << 25)
513
- | (rs2_prime << 20)
514
- | (rs1_prime << 15)
515
- | (funct3 << 12)
516
- | (rs1_prime << 7)
517
- | 0x33,
518
- )
519
- } else {
520
- // RV64C: C.SUBW / C.ADDW -> R-type with opcode 0x3B (Op32)
521
- match funct2 {
522
- 0b00 => {
523
- // C.SUBW -> SUBW rd', rd', rs2'
524
- Ok(encode_r(0x20, rs2_prime, rs1_prime, 0x0, rs1_prime, 0x3B))
525
- }
526
- 0b01 => {
527
- // C.ADDW -> ADDW rd', rd', rs2'
528
- Ok(encode_r(0x00, rs2_prime, rs1_prime, 0x0, rs1_prime, 0x3B))
529
- }
530
- // funct2 = 0b10, 0b11 are reserved in RV64C
531
- _ => Err(Trap::IllegalInstruction(insn as u64)),
532
- }
533
- }
534
- }
535
- _ => Err(Trap::IllegalInstruction(insn as u64)),
536
- }
537
- }
538
- // C.J (unconditional jump)
539
- 0b101 => {
540
- // C.J immediate: imm[11|4|9:8|10|6|7|3:1|5] with bit 0 implicitly 0
541
- let mut off = 0u32;
542
- off |= ((insn_u >> 12) & 0x1) << 11;
543
- off |= ((insn_u >> 11) & 0x1) << 4;
544
- off |= ((insn_u >> 9) & 0x3) << 8;
545
- off |= ((insn_u >> 8) & 0x1) << 10;
546
- off |= ((insn_u >> 7) & 0x1) << 6;
547
- off |= ((insn_u >> 6) & 0x1) << 7;
548
- off |= ((insn_u >> 3) & 0x7) << 1;
549
- off |= ((insn_u >> 2) & 0x1) << 5;
550
- // off already has bit 0 = 0 implicitly; sign-extend from bit 11
551
- let imm = sext(off, 12);
552
- Ok(encode_j(imm, 0)) // JAL x0, imm
553
- }
554
- // C.BEQZ
555
- 0b110 => {
556
- let rs1_prime = 8 + ((insn_u >> 7) & 0x7);
557
- // C.BEQZ immediate: imm[8|4:3|7:6|2:1|5] with bit 0 implicitly 0
558
- let mut off = 0u32;
559
- off |= ((insn_u >> 12) & 0x1) << 8;
560
- off |= ((insn_u >> 10) & 0x3) << 3;
561
- off |= ((insn_u >> 5) & 0x3) << 6;
562
- off |= ((insn_u >> 3) & 0x3) << 1;
563
- off |= ((insn_u >> 2) & 0x1) << 5;
564
- // off already has bit 0 = 0 implicitly; sign-extend from bit 8
565
- let imm = sext(off, 9);
566
- Ok(encode_b(imm, 0, rs1_prime, 0x0, 0x63)) // BEQ rs1', x0, imm
567
- }
568
- // C.BNEZ
569
- 0b111 => {
570
- let rs1_prime = 8 + ((insn_u >> 7) & 0x7);
571
- // C.BNEZ immediate: imm[8|4:3|7:6|2:1|5] with bit 0 implicitly 0
572
- let mut off = 0u32;
573
- off |= ((insn_u >> 12) & 0x1) << 8;
574
- off |= ((insn_u >> 10) & 0x3) << 3;
575
- off |= ((insn_u >> 5) & 0x3) << 6;
576
- off |= ((insn_u >> 3) & 0x3) << 1;
577
- off |= ((insn_u >> 2) & 0x1) << 5;
578
- // off already has bit 0 = 0 implicitly; sign-extend from bit 8
579
- let imm = sext(off, 9);
580
- Ok(encode_b(imm, 0, rs1_prime, 0x1, 0x63)) // BNE rs1', x0, imm
581
- }
582
- _ => Err(Trap::IllegalInstruction(insn as u64)),
583
- }
584
- }
585
-
586
- fn expand_q2(insn: u16, funct3: u16) -> Result<u32, Trap> {
587
- let insn_u = insn as u32;
588
- match funct3 {
589
- // C.SLLI
590
- 0b000 => {
591
- let rd = (insn_u >> 7) & 0x1F;
592
- let imm_bits = ((insn_u >> 2) & 0x1F) | (((insn_u >> 12) & 0x1) << 5);
593
- let imm = imm_bits & 0x3F; // RV64: 6-bit shamt
594
- if rd == 0 {
595
- return Err(Trap::IllegalInstruction(insn as u64));
596
- }
597
- Ok(encode_i(imm as i32, rd, 0x1, rd, 0x13))
598
- }
599
- // C.LWSP
600
- 0b010 => {
601
- let rd = (insn_u >> 7) & 0x1F;
602
- if rd == 0 {
603
- return Err(Trap::IllegalInstruction(insn as u64));
604
- }
605
- let uimm = (((insn_u >> 4) & 0x7) << 2)
606
- | (((insn_u >> 12) & 0x1) << 5)
607
- | (((insn_u >> 2) & 0x3) << 6);
608
- Ok(encode_i(uimm as i32, 2, 0x2, rd, 0x03))
609
- }
610
- // C.LDSP: LD rd, uimm(sp) - uimm[5|4:3|8:6] scaled by 8
611
- 0b011 => {
612
- let rd = (insn_u >> 7) & 0x1F;
613
- if rd == 0 {
614
- return Err(Trap::IllegalInstruction(insn as u64));
615
- }
616
- // bit 12 -> uimm[5], bits [6:5] -> uimm[4:3], bits [4:2] -> uimm[8:6]
617
- let uimm = (((insn_u >> 12) & 0x1) << 5)
618
- | (((insn_u >> 5) & 0x3) << 3)
619
- | (((insn_u >> 2) & 0x7) << 6);
620
- Ok(encode_i(uimm as i32, 2, 0x3, rd, 0x03))
621
- }
622
- // C.JR / C.MV / C.EBREAK / C.JALR / C.ADD
623
- 0b100 => {
624
- let rd = (insn_u >> 7) & 0x1F;
625
- let rs2 = (insn_u >> 2) & 0x1F;
626
- let bit12 = (insn_u >> 12) & 0x1;
627
- match (bit12, rs2, rd) {
628
- // C.JR: rs2=0, bit12=0, rd!=0
629
- (0, 0, rd) if rd != 0 => {
630
- Ok(encode_i(0, rd, 0x0, 0, 0x67)) // JALR x0, rd, 0
631
- }
632
- // C.MV: bit12=0, rs2!=0, rd!=0
633
- (0, rs2, rd) if rs2 != 0 && rd != 0 => {
634
- Ok(encode_r(0x00, rs2, 0, 0x0, rd, 0x33)) // ADD rd, x0, rs2
635
- }
636
- // C.EBREAK: bit12=1, rd=0, rs2=0
637
- (1, 0, 0) => Ok(0x0010_0073),
638
- // C.JALR: bit12=1, rs2=0, rd!=0
639
- (1, 0, rd) if rd != 0 => {
640
- Ok(encode_i(0, rd, 0x0, 1, 0x67)) // JALR x1, rd, 0
641
- }
642
- // C.ADD: bit12=1, rs2!=0, rd!=0
643
- (1, rs2, rd) if rs2 != 0 && rd != 0 => {
644
- Ok(encode_r(0x00, rs2, rd, 0x0, rd, 0x33)) // ADD rd, rd, rs2
645
- }
646
- _ => Err(Trap::IllegalInstruction(insn as u64)),
647
- }
648
- }
649
- // C.SWSP: SW rs2, uimm(sp) - uimm[5:2|7:6] scaled by 4
650
- 0b110 => {
651
- let rs2 = (insn_u >> 2) & 0x1F;
652
- // bits [12:9] -> uimm[5:2], bits [8:7] -> uimm[7:6]
653
- let uimm = (((insn_u >> 9) & 0xF) << 2) | (((insn_u >> 7) & 0x3) << 6);
654
- Ok(encode_s(uimm as i32, rs2, 2, 0x2, 0x23))
655
- }
656
- // C.SDSP: SD rs2, uimm(sp) - uimm[5:3|8:6] scaled by 8
657
- 0b111 => {
658
- let rs2 = (insn_u >> 2) & 0x1F;
659
- // bits [12:10] -> uimm[5:3], bits [9:7] -> uimm[8:6]
660
- let uimm = (((insn_u >> 10) & 0x7) << 3) | (((insn_u >> 7) & 0x7) << 6);
661
- Ok(encode_s(uimm as i32, rs2, 2, 0x3, 0x23))
662
- }
663
- _ => Err(Trap::IllegalInstruction(insn as u64)),
664
- }
665
- }
666
-
667
- #[cfg(test)]
668
- mod tests {
669
- use super::*;
670
-
671
- #[test]
672
- fn decode_lui_and_jal() {
673
- // LUI x2, 0x12345
674
- let lui_insn: u32 = 0x12345137;
675
- let op = decode(lui_insn).unwrap();
676
- match op {
677
- Op::Lui { rd, imm } => {
678
- assert_eq!(rd, Register::X2);
679
- assert_eq!(imm, 0x0000_0000_1234_5000);
680
- }
681
- _ => panic!("Expected LUI op"),
682
- }
683
-
684
- // JAL x1, 8 (matches cpu::tests::test_jal)
685
- let jal_insn: u32 = (4 << 21) | (1 << 7) | 0x6F;
686
- let op = decode(jal_insn).unwrap();
687
- match op {
688
- Op::Jal { rd, imm } => {
689
- assert_eq!(rd, Register::X1);
690
- assert_eq!(imm, 8);
691
- }
692
- _ => panic!("Expected JAL op"),
693
- }
694
- }
695
-
696
- #[test]
697
- fn decode_illegal_opcode() {
698
- // Opcode with bits[6:0] not matching any valid RV64I opcode we implement.
699
- let bad: u32 = 0x0000_0000;
700
- let res = decode(bad);
701
- match res {
702
- Err(Trap::IllegalInstruction(bits)) => assert_eq!(bits, bad as u64),
703
- _ => panic!("Expected IllegalInstruction trap"),
704
- }
705
- }
706
-
707
- #[test]
708
- fn expand_compressed_basic_integer_ops() {
709
- // These 16-bit encodings come from assembling with rv64imac:
710
- // addi x8, x2, 16 # C.ADDI4SPN
711
- // addi x11,x11,1 # C.ADDI
712
- // addiw x12,x12,1 # C.ADDIW
713
- // addi x13,x0,-1 # C.LI
714
- // addi x2, x2, 16 # C.ADDI16SP
715
- // lui x14,1 # C.LUI
716
- let c_addi4spn: u16 = 0x0800;
717
- let c_addi: u16 = 0x0585;
718
- let c_addiw: u16 = 0x2605;
719
- let c_li: u16 = 0x56FD;
720
- let c_addi16sp: u16 = 0x0141;
721
- let c_lui: u16 = 0x6705;
722
-
723
- // C.ADDI4SPN -> ADDI x8, x2, 16
724
- let op = decode(expand_compressed(c_addi4spn).unwrap()).unwrap();
725
- match op {
726
- Op::OpImm { rd, rs1, imm, funct3, .. } => {
727
- assert_eq!(rd, Register::X8);
728
- assert_eq!(rs1, Register::X2);
729
- assert_eq!(imm, 16);
730
- assert_eq!(funct3, 0);
731
- }
732
- _ => panic!("Expected OpImm from C.ADDI4SPN"),
733
- }
734
-
735
- // C.ADDI -> ADDI x11, x11, 1
736
- let op = decode(expand_compressed(c_addi).unwrap()).unwrap();
737
- match op {
738
- Op::OpImm { rd, rs1, imm, .. } => {
739
- assert_eq!(rd, Register::X11);
740
- assert_eq!(rs1, Register::X11);
741
- assert_eq!(imm, 1);
742
- }
743
- _ => panic!("Expected OpImm from C.ADDI"),
744
- }
745
-
746
- // C.ADDIW -> ADDIW x12, x12, 1
747
- let op = decode(expand_compressed(c_addiw).unwrap()).unwrap();
748
- match op {
749
- Op::OpImm32 { rd, rs1, imm, .. } => {
750
- assert_eq!(rd, Register::X12);
751
- assert_eq!(rs1, Register::X12);
752
- assert_eq!(imm, 1);
753
- }
754
- _ => panic!("Expected OpImm32 from C.ADDIW"),
755
- }
756
-
757
- // C.LI -> ADDI x13, x0, -1
758
- let op = decode(expand_compressed(c_li).unwrap()).unwrap();
759
- match op {
760
- Op::OpImm { rd, rs1, imm, .. } => {
761
- assert_eq!(rd, Register::X13);
762
- assert_eq!(rs1, Register::X0);
763
- assert_eq!(imm, -1);
764
- }
765
- _ => panic!("Expected OpImm from C.LI"),
766
- }
767
-
768
- // C.ADDI16SP -> ADDI x2, x2, 16
769
- let op = decode(expand_compressed(c_addi16sp).unwrap()).unwrap();
770
- match op {
771
- Op::OpImm { rd, rs1, imm, .. } => {
772
- assert_eq!(rd, Register::X2);
773
- assert_eq!(rs1, Register::X2);
774
- assert_eq!(imm, 16);
775
- }
776
- _ => panic!("Expected OpImm from C.ADDI16SP"),
777
- }
778
-
779
- // C.LUI -> LUI x14, 1
780
- let op = decode(expand_compressed(c_lui).unwrap()).unwrap();
781
- match op {
782
- Op::Lui { rd, imm } => {
783
- assert_eq!(rd, Register::X14);
784
- assert_eq!(imm, 0x0000_0000_0000_1000);
785
- }
786
- _ => panic!("Expected Lui from C.LUI"),
787
- }
788
- }
789
- }