virtual-machine 0.0.4 → 0.0.14
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/build/{chunk-V6I6APCK.mjs → chunk-H6WI4NRK.mjs} +122 -123
- package/build/cli.js +590 -610
- package/build/index.d.ts +5 -5
- package/build/index.js +117 -118
- package/build/index.mjs +4 -4
- package/build/{riscv_vm-QIJGD3E2.mjs → riscv_vm-MAZK3LFN.mjs} +1 -1
- package/package.json +12 -5
- package/.yarn/install-state.gz +0 -0
- package/.yarnrc.yml +0 -1
- package/Cargo.toml +0 -49
- package/build.sh +0 -25
- package/cli.ts +0 -268
- package/index.ts +0 -16
- package/src/bus.rs +0 -558
- package/src/clint.rs +0 -132
- package/src/console.rs +0 -83
- package/src/cpu.rs +0 -1913
- package/src/csr.rs +0 -67
- package/src/decoder.rs +0 -789
- package/src/dram.rs +0 -146
- package/src/emulator.rs +0 -603
- package/src/lib.rs +0 -249
- package/src/main.rs +0 -449
- package/src/mmu.rs +0 -331
- package/src/net.rs +0 -121
- package/src/net_webtransport.rs +0 -446
- package/src/plic.rs +0 -261
- package/src/uart.rs +0 -231
- package/src/virtio.rs +0 -1074
- package/tsconfig.json +0 -19
- package/tsup/index.ts +0 -79
- package/tsup/tsup.cli.ts +0 -8
- package/tsup/tsup.core.cjs.ts +0 -7
- package/tsup/tsup.core.esm.ts +0 -8
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
|
-
}
|