lib/std/arch/rv64/encode.rad 22.0 KiB raw
1
//! RISC-V RV64I+M instruction encoding.
2
//!
3
//! Provides type-safe functions for encoding RV64 instructions.
4
5
use std::lang::gen;
6
7
//////////////////////
8
// Opcode Constants //
9
//////////////////////
10
11
export constant OP_LOAD:   u32 = 0x03;
12
export constant OP_STORE:  u32 = 0x23;
13
export constant OP_BRANCH: u32 = 0x63;
14
export constant OP_JALR:   u32 = 0x67;
15
export constant OP_JAL:    u32 = 0x6F;
16
export constant OP_OP:     u32 = 0x33;
17
export constant OP_IMM:    u32 = 0x13;
18
export constant OP_AUIPC:  u32 = 0x17;
19
export constant OP_LUI:    u32 = 0x37;
20
export constant OP_SYSTEM: u32 = 0x73;
21
export constant OP_OP32:   u32 = 0x3B;  // RV64: 32-bit operations
22
export constant OP_IMM32:  u32 = 0x1B;  // RV64: 32-bit immediate operations
23
24
//////////////////////
25
// Funct3 Constants //
26
//////////////////////
27
28
// Memory operations
29
30
export constant F3_BYTE:   u32 = 0x0;  // LB/SB
31
export constant F3_HALF:   u32 = 0x1;  // LH/SH
32
export constant F3_WORD:   u32 = 0x2;  // LW/SW
33
export constant F3_DWORD:  u32 = 0x3;  // LD/SD (RV64)
34
export constant F3_BYTE_U: u32 = 0x4;  // LBU
35
export constant F3_HALF_U: u32 = 0x5;  // LHU
36
export constant F3_WORD_U: u32 = 0x6;  // LWU (RV64)
37
38
// ALU operations
39
40
export constant F3_ADD:  u32 = 0x0;  // ADD/SUB/ADDI
41
export constant F3_SLL:  u32 = 0x1;  // SLL/SLLI
42
export constant F3_SLT:  u32 = 0x2;  // SLT/SLTI
43
export constant F3_SLTU: u32 = 0x3;  // SLTU/SLTIU
44
export constant F3_XOR:  u32 = 0x4;  // XOR/XORI
45
export constant F3_SRL:  u32 = 0x5;  // SRL/SRA/SRLI/SRAI
46
export constant F3_OR:   u32 = 0x6;  // OR/ORI
47
export constant F3_AND:  u32 = 0x7;  // AND/ANDI
48
49
// Branch operations
50
51
export constant F3_BEQ:  u32 = 0x0;
52
export constant F3_BNE:  u32 = 0x1;
53
export constant F3_BLT:  u32 = 0x4;
54
export constant F3_BGE:  u32 = 0x5;
55
export constant F3_BLTU: u32 = 0x6;
56
export constant F3_BGEU: u32 = 0x7;
57
58
// CSR/system operations
59
60
export constant F3_CSRRW: u32 = 0x1;
61
export constant F3_CSRRS: u32 = 0x2;
62
export constant F3_CSRRC: u32 = 0x3;
63
export constant F3_CSRRWI: u32 = 0x5;
64
export constant F3_CSRRSI: u32 = 0x6;
65
export constant F3_CSRRCI: u32 = 0x7;
66
67
//////////////////////
68
// Funct7 Constants //
69
//////////////////////
70
71
export constant F7_NORMAL: u32 = 0b0000000;
72
export constant F7_SUB:    u32 = 0b0100000;  // Bit 5 set
73
export constant F7_SRA:    u32 = 0b0100000;  // Bit 5 set
74
export constant F7_MUL:    u32 = 0b0000001;  // Bit 0 set
75
76
/////////////////////////
77
// Validation Helpers  //
78
/////////////////////////
79
80
/// Returns `true` if the value fits in a signed 12-bit immediate.
81
export fn isSmallImm(value: i32) -> bool {
82
    return value >= super::MIN_IMM and value <= super::MAX_IMM;
83
}
84
85
/// Returns `true` if a 64-bit value fits in a 12-bit signed immediate.
86
export fn isSmallImm64(value: i64) -> bool {
87
    return value >= (super::MIN_IMM as i64) and value <= (super::MAX_IMM as i64);
88
}
89
90
/// Returns `true` if the value is valid for branch immediates.
91
/// Branch immediates are 13-bit signed, even aligned.
92
export fn isBranchImm(value: i32) -> bool {
93
    return value >= -(1 << 12) and value <= ((1 << 12) - 2) and (value & 1) == 0;
94
}
95
96
/// Returns `true` if the value is valid for jump immediates (JAL).
97
/// Jump immediates are 21-bit signed, even aligned.
98
export fn isJumpImm(value: i32) -> bool {
99
    return value >= -(1 << 20) and value <= ((1 << 20) - 2) and (value & 1) == 0;
100
}
101
102
//////////////////////
103
// Format Encoders  //
104
//////////////////////
105
106
/// Encode an R-type instruction.
107
fn encodeR(opcode: u32, rd: gen::Reg, rs1: gen::Reg, rs2: gen::Reg, funct3: u32, funct7: u32) -> u32 {
108
    return (opcode        & 0x7F)
109
         | ((*rd  as u32  & 0x1F) << 7)
110
         | ((funct3       & 0x07) << 12)
111
         | ((*rs1 as u32  & 0x1F) << 15)
112
         | ((*rs2 as u32  & 0x1F) << 20)
113
         | ((funct7       & 0x7F) << 25);
114
}
115
116
/// Encode an I-type instruction.
117
fn encodeI(opcode: u32, rd: gen::Reg, rs1: gen::Reg, funct3: u32, imm: i32) -> u32 {
118
    assert isSmallImm(imm);
119
120
    return (opcode        & 0x7F)
121
         | ((*rd  as u32  & 0x1F)  << 7)
122
         | ((funct3       & 0x07)  << 12)
123
         | ((*rs1 as u32  & 0x1F)  << 15)
124
         | ((imm as u32   & 0xFFF) << 20);
125
}
126
127
/// Encode an S-type instruction.
128
fn encodeS(opcode: u32, rs1: gen::Reg, rs2: gen::Reg, funct3: u32, imm: i32) -> u32 {
129
    assert isSmallImm(imm);
130
131
    return (opcode  & 0x7F)
132
         | ((imm as u32       & 0x1F) << 7)
133
         | ((funct3           & 0x07) << 12)
134
         | ((*rs1 as u32      & 0x1F) << 15)
135
         | ((*rs2 as u32      & 0x1F) << 20)
136
         | ((imm as u32 >> 5  & 0x7F) << 25);
137
}
138
139
/// Encode a B-type (branch) instruction.
140
fn encodeB(opcode: u32, rs1: gen::Reg, rs2: gen::Reg, funct3: u32, imm: i32) -> u32 {
141
    assert isBranchImm(imm);
142
143
    let imm11   = (imm as u32 >> 11) & 0x1;
144
    let imm4_1  = (imm as u32 >> 1)  & 0xF;
145
    let imm10_5 = (imm as u32 >> 5)  & 0x3F;
146
    let imm12   = (imm as u32 >> 12) & 0x1;
147
148
    return (opcode        &  0x7F)
149
         | (imm11         << 7)
150
         | (imm4_1        << 8)
151
         | ((funct3       & 0x07) << 12)
152
         | ((*rs1 as u32  & 0x1F) << 15)
153
         | ((*rs2 as u32  & 0x1F) << 20)
154
         | (imm10_5       << 25)
155
         | (imm12         << 31);
156
}
157
158
/// Encode a U-type instruction.
159
fn encodeU(opcode: u32, rd: gen::Reg, imm: i32) -> u32 {
160
    return (opcode       & 0x7F)
161
         | ((*rd as u32  & 0x1F)    << 7)
162
         | ((imm as u32  & 0xFFFFF) << 12);
163
}
164
165
/// Encode a J-type (jump) instruction.
166
fn encodeJ(opcode: u32, rd: gen::Reg, imm: i32) -> u32 {
167
    assert isJumpImm(imm);
168
169
    let imm20    = (imm as u32 >> 20) & 0x1;
170
    let imm10_1  = (imm as u32 >> 1)  & 0x3FF;
171
    let imm11    = (imm as u32 >> 11) & 0x1;
172
    let imm19_12 = (imm as u32 >> 12) & 0xFF;
173
174
    return (opcode       & 0x7F)
175
         | ((*rd as u32  & 0x1F) << 7)
176
         | (imm19_12     << 12)
177
         | (imm11        << 20)
178
         | (imm10_1      << 21)
179
         | (imm20        << 31);
180
}
181
182
////////////////////////////
183
// ALU Immediate (I-type) //
184
////////////////////////////
185
186
/// Add immediate: `rd = rs1 + imm`.
187
export fn addi(rd: gen::Reg, rs1: gen::Reg, imm: i32) -> u32 {
188
    return encodeI(OP_IMM, rd, rs1, F3_ADD, imm);
189
}
190
191
/// Set less than immediate (signed): `rd = (rs1 < imm) ? 1 : 0`.
192
export fn slti(rd: gen::Reg, rs1: gen::Reg, imm: i32) -> u32 {
193
    return encodeI(OP_IMM, rd, rs1, F3_SLT, imm);
194
}
195
196
/// Set less than immediate unsigned: `rd = (rs1 < imm) ? 1 : 0`.
197
export fn sltiu(rd: gen::Reg, rs1: gen::Reg, imm: i32) -> u32 {
198
    return encodeI(OP_IMM, rd, rs1, F3_SLTU, imm);
199
}
200
201
/// XOR immediate: `rd = rs1 ^ imm`.
202
export fn xori(rd: gen::Reg, rs1: gen::Reg, imm: i32) -> u32 {
203
    return encodeI(OP_IMM, rd, rs1, F3_XOR, imm);
204
}
205
206
/// OR immediate: `rd = rs1 | imm`.
207
export fn ori(rd: gen::Reg, rs1: gen::Reg, imm: i32) -> u32 {
208
    return encodeI(OP_IMM, rd, rs1, F3_OR, imm);
209
}
210
211
/// AND immediate: `rd = rs1 & imm`.
212
export fn andi(rd: gen::Reg, rs1: gen::Reg, imm: i32) -> u32 {
213
    return encodeI(OP_IMM, rd, rs1, F3_AND, imm);
214
}
215
216
/// Shift left logical immediate: `rd = rs1 << shamt`.
217
export fn slli(rd: gen::Reg, rs1: gen::Reg, shamt: i32) -> u32 {
218
    assert shamt >= 0 and shamt < 64;
219
    return encodeI(OP_IMM, rd, rs1, F3_SLL, shamt & 0x3F);
220
}
221
222
/// Shift right logical immediate: `rd = rs1 >> shamt` (zero-extend).
223
export fn srli(rd: gen::Reg, rs1: gen::Reg, shamt: i32) -> u32 {
224
    assert shamt >= 0 and shamt < 64;
225
    return encodeI(OP_IMM, rd, rs1, F3_SRL, shamt & 0x3F);
226
}
227
228
/// Shift right arithmetic immediate: `rd = rs1 >> shamt` (sign-extend).
229
export fn srai(rd: gen::Reg, rs1: gen::Reg, shamt: i32) -> u32 {
230
    assert shamt >= 0 and shamt < 64;
231
    // SRAI has bit 10 set in immediate field (becomes bit 30 in instruction)
232
    return encodeI(OP_IMM, rd, rs1, F3_SRL, (shamt & 0x3F) | 0b10000000000);
233
}
234
235
///////////////////////////
236
// ALU Register (R-type) //
237
///////////////////////////
238
239
/// Add: `rd = rs1 + rs2`.
240
export fn add(rd: gen::Reg, rs1: gen::Reg, rs2: gen::Reg) -> u32 {
241
    return encodeR(OP_OP, rd, rs1, rs2, F3_ADD, F7_NORMAL);
242
}
243
244
/// Subtract: `rd = rs1 - rs2`.
245
export fn sub(rd: gen::Reg, rs1: gen::Reg, rs2: gen::Reg) -> u32 {
246
    return encodeR(OP_OP, rd, rs1, rs2, F3_ADD, F7_SUB);
247
}
248
249
/// Shift left logical: `rd = rs1 << rs2[5:0]`.
250
export fn sll(rd: gen::Reg, rs1: gen::Reg, rs2: gen::Reg) -> u32 {
251
    return encodeR(OP_OP, rd, rs1, rs2, F3_SLL, F7_NORMAL);
252
}
253
254
/// Set less than (signed): `rd = (rs1 < rs2) ? 1 : 0`.
255
export fn slt(rd: gen::Reg, rs1: gen::Reg, rs2: gen::Reg) -> u32 {
256
    return encodeR(OP_OP, rd, rs1, rs2, F3_SLT, F7_NORMAL);
257
}
258
259
/// Set less than unsigned: `rd = (rs1 < rs2) ? 1 : 0`.
260
export fn sltu(rd: gen::Reg, rs1: gen::Reg, rs2: gen::Reg) -> u32 {
261
    return encodeR(OP_OP, rd, rs1, rs2, F3_SLTU, F7_NORMAL);
262
}
263
264
/// XOR: `rd = rs1 ^ rs2`.
265
export fn xor(rd: gen::Reg, rs1: gen::Reg, rs2: gen::Reg) -> u32 {
266
    return encodeR(OP_OP, rd, rs1, rs2, F3_XOR, F7_NORMAL);
267
}
268
269
/// Shift right logical: `rd = rs1 >> rs2[5:0]` (zero-extend).
270
export fn srl(rd: gen::Reg, rs1: gen::Reg, rs2: gen::Reg) -> u32 {
271
    return encodeR(OP_OP, rd, rs1, rs2, F3_SRL, F7_NORMAL);
272
}
273
274
/// Shift right arithmetic: `rd = rs1 >> rs2[5:0]` (sign-extend).
275
export fn sra(rd: gen::Reg, rs1: gen::Reg, rs2: gen::Reg) -> u32 {
276
    return encodeR(OP_OP, rd, rs1, rs2, F3_SRL, F7_SRA);
277
}
278
279
/// OR: `rd = rs1 | rs2`.
280
export fn or_(rd: gen::Reg, rs1: gen::Reg, rs2: gen::Reg) -> u32 {
281
    return encodeR(OP_OP, rd, rs1, rs2, F3_OR, F7_NORMAL);
282
}
283
284
/// AND: `rd = rs1 & rs2`.
285
export fn and_(rd: gen::Reg, rs1: gen::Reg, rs2: gen::Reg) -> u32 {
286
    return encodeR(OP_OP, rd, rs1, rs2, F3_AND, F7_NORMAL);
287
}
288
289
/////////////////
290
// M Extension //
291
/////////////////
292
293
/// Multiply: `rd = (rs1 * rs2)[63:0]`.
294
export fn mul(rd: gen::Reg, rs1: gen::Reg, rs2: gen::Reg) -> u32 {
295
    return encodeR(OP_OP, rd, rs1, rs2, F3_ADD, F7_MUL);
296
}
297
298
/// Multiply high (signed x signed): `rd = (rs1 * rs2)[127:64]`.
299
export fn mulh(rd: gen::Reg, rs1: gen::Reg, rs2: gen::Reg) -> u32 {
300
    return encodeR(OP_OP, rd, rs1, rs2, F3_SLL, F7_MUL);
301
}
302
303
/// Multiply high (signed x unsigned): `rd = (rs1 * rs2)[127:64]`.
304
export fn mulhsu(rd: gen::Reg, rs1: gen::Reg, rs2: gen::Reg) -> u32 {
305
    return encodeR(OP_OP, rd, rs1, rs2, F3_SLT, F7_MUL);
306
}
307
308
/// Multiply high (unsigned x unsigned): `rd = (rs1 * rs2)[127:64]`.
309
export fn mulhu(rd: gen::Reg, rs1: gen::Reg, rs2: gen::Reg) -> u32 {
310
    return encodeR(OP_OP, rd, rs1, rs2, F3_SLTU, F7_MUL);
311
}
312
313
/// Divide (signed): `rd = rs1 / rs2`.
314
export fn div(rd: gen::Reg, rs1: gen::Reg, rs2: gen::Reg) -> u32 {
315
    return encodeR(OP_OP, rd, rs1, rs2, F3_XOR, F7_MUL);
316
}
317
318
/// Divide (unsigned): `rd = rs1 / rs2`.
319
export fn divu(rd: gen::Reg, rs1: gen::Reg, rs2: gen::Reg) -> u32 {
320
    return encodeR(OP_OP, rd, rs1, rs2, F3_SRL, F7_MUL);
321
}
322
323
/// Remainder (signed): `rd = rs1 % rs2`.
324
export fn rem(rd: gen::Reg, rs1: gen::Reg, rs2: gen::Reg) -> u32 {
325
    return encodeR(OP_OP, rd, rs1, rs2, F3_OR, F7_MUL);
326
}
327
328
/// Remainder (unsigned): `rd = rs1 % rs2`.
329
export fn remu(rd: gen::Reg, rs1: gen::Reg, rs2: gen::Reg) -> u32 {
330
    return encodeR(OP_OP, rd, rs1, rs2, F3_AND, F7_MUL);
331
}
332
333
//////////////////////////
334
// RV64 Word Operations //
335
//////////////////////////
336
337
/// Add immediate word (32-bit, sign-extended): `rd = sign_ext((rs1 + imm)[31:0])`.
338
export fn addiw(rd: gen::Reg, rs1: gen::Reg, imm: i32) -> u32 {
339
    return encodeI(OP_IMM32, rd, rs1, F3_ADD, imm);
340
}
341
342
/// Shift left logical immediate word: `rd = sign_ext((rs1 << shamt)[31:0])`.
343
export fn slliw(rd: gen::Reg, rs1: gen::Reg, shamt: i32) -> u32 {
344
    assert shamt >= 0 and shamt < 32;
345
    return encodeI(OP_IMM32, rd, rs1, F3_SLL, shamt & 0x1F);
346
}
347
348
/// Shift right logical immediate word: `rd = sign_ext((rs1[31:0] >> shamt))`.
349
export fn srliw(rd: gen::Reg, rs1: gen::Reg, shamt: i32) -> u32 {
350
    assert shamt >= 0 and shamt < 32;
351
    return encodeI(OP_IMM32, rd, rs1, F3_SRL, shamt & 0x1F);
352
}
353
354
/// Shift right arithmetic immediate word: `rd = sign_ext((rs1[31:0] >> shamt))` (sign-extended).
355
export fn sraiw(rd: gen::Reg, rs1: gen::Reg, shamt: i32) -> u32 {
356
    assert shamt >= 0 and shamt < 32;
357
    return encodeI(OP_IMM32, rd, rs1, F3_SRL, (shamt & 0x1F) | 0b10000000000);
358
}
359
360
/// Add word: `rd = sign_ext((rs1 + rs2)[31:0])`.
361
export fn addw(rd: gen::Reg, rs1: gen::Reg, rs2: gen::Reg) -> u32 {
362
    return encodeR(OP_OP32, rd, rs1, rs2, F3_ADD, F7_NORMAL);
363
}
364
365
/// Subtract word: `rd = sign_ext((rs1 - rs2)[31:0])`.
366
export fn subw(rd: gen::Reg, rs1: gen::Reg, rs2: gen::Reg) -> u32 {
367
    return encodeR(OP_OP32, rd, rs1, rs2, F3_ADD, F7_SUB);
368
}
369
370
/// Shift left logical word: `rd = sign_ext((rs1 << rs2[4:0])[31:0])`.
371
export fn sllw(rd: gen::Reg, rs1: gen::Reg, rs2: gen::Reg) -> u32 {
372
    return encodeR(OP_OP32, rd, rs1, rs2, F3_SLL, F7_NORMAL);
373
}
374
375
/// Shift right logical word: `rd = sign_ext((rs1[31:0] >> rs2[4:0]))`.
376
export fn srlw(rd: gen::Reg, rs1: gen::Reg, rs2: gen::Reg) -> u32 {
377
    return encodeR(OP_OP32, rd, rs1, rs2, F3_SRL, F7_NORMAL);
378
}
379
380
/// Shift right arithmetic word: `rd = sign_ext((rs1[31:0] >> rs2[4:0]))` (sign-extended).
381
export fn sraw(rd: gen::Reg, rs1: gen::Reg, rs2: gen::Reg) -> u32 {
382
    return encodeR(OP_OP32, rd, rs1, rs2, F3_SRL, F7_SRA);
383
}
384
385
/// Multiply word: `rd = sign_ext((rs1 * rs2)[31:0])`.
386
export fn mulw(rd: gen::Reg, rs1: gen::Reg, rs2: gen::Reg) -> u32 {
387
    return encodeR(OP_OP32, rd, rs1, rs2, F3_ADD, F7_MUL);
388
}
389
390
/// Divide word (signed): `rd = sign_ext(rs1[31:0] / rs2[31:0])`.
391
export fn divw(rd: gen::Reg, rs1: gen::Reg, rs2: gen::Reg) -> u32 {
392
    return encodeR(OP_OP32, rd, rs1, rs2, F3_XOR, F7_MUL);
393
}
394
395
/// Divide word (unsigned): `rd = sign_ext(rs1[31:0] / rs2[31:0])`.
396
export fn divuw(rd: gen::Reg, rs1: gen::Reg, rs2: gen::Reg) -> u32 {
397
    return encodeR(OP_OP32, rd, rs1, rs2, F3_SRL, F7_MUL);
398
}
399
400
/// Remainder word (signed): `rd = sign_ext(rs1[31:0] % rs2[31:0])`.
401
export fn remw(rd: gen::Reg, rs1: gen::Reg, rs2: gen::Reg) -> u32 {
402
    return encodeR(OP_OP32, rd, rs1, rs2, F3_OR, F7_MUL);
403
}
404
405
/// Remainder word (unsigned): `rd = sign_ext(rs1[31:0] % rs2[31:0])`.
406
export fn remuw(rd: gen::Reg, rs1: gen::Reg, rs2: gen::Reg) -> u32 {
407
    return encodeR(OP_OP32, rd, rs1, rs2, F3_AND, F7_MUL);
408
}
409
410
///////////////////
411
// Load (I-type) //
412
///////////////////
413
414
/// Load byte (sign-extend): `rd = mem[rs1 + imm][7:0]`.
415
export fn lb(rd: gen::Reg, rs1: gen::Reg, imm: i32) -> u32 {
416
    return encodeI(OP_LOAD, rd, rs1, F3_BYTE, imm);
417
}
418
419
/// Load halfword (sign-extend): `rd = mem[rs1 + imm][15:0]`.
420
export fn lh(rd: gen::Reg, rs1: gen::Reg, imm: i32) -> u32 {
421
    return encodeI(OP_LOAD, rd, rs1, F3_HALF, imm);
422
}
423
424
/// Load word (sign-extend to 64-bit): `rd = sign_ext(mem[rs1 + imm][31:0])`.
425
export fn lw(rd: gen::Reg, rs1: gen::Reg, imm: i32) -> u32 {
426
    return encodeI(OP_LOAD, rd, rs1, F3_WORD, imm);
427
}
428
429
/// Load byte unsigned (zero-extend): `rd = mem[rs1 + imm][7:0]`.
430
export fn lbu(rd: gen::Reg, rs1: gen::Reg, imm: i32) -> u32 {
431
    return encodeI(OP_LOAD, rd, rs1, F3_BYTE_U, imm);
432
}
433
434
/// Load halfword unsigned (zero-extend): `rd = mem[rs1 + imm][15:0]`.
435
export fn lhu(rd: gen::Reg, rs1: gen::Reg, imm: i32) -> u32 {
436
    return encodeI(OP_LOAD, rd, rs1, F3_HALF_U, imm);
437
}
438
439
/// Load word unsigned (zero-extend to 64-bit): `rd = mem[rs1 + imm][31:0]`.
440
export fn lwu(rd: gen::Reg, rs1: gen::Reg, imm: i32) -> u32 {
441
    return encodeI(OP_LOAD, rd, rs1, F3_WORD_U, imm);
442
}
443
444
/// Load doubleword: `rd = mem[rs1 + imm][63:0]`.
445
export fn ld(rd: gen::Reg, rs1: gen::Reg, imm: i32) -> u32 {
446
    return encodeI(OP_LOAD, rd, rs1, F3_DWORD, imm);
447
}
448
449
////////////////////
450
// Store (S-type) //
451
////////////////////
452
453
/// Store byte: `mem[rs1 + imm] = rs2[7:0]`.
454
export fn sb(rs2: gen::Reg, rs1: gen::Reg, imm: i32) -> u32 {
455
    return encodeS(OP_STORE, rs1, rs2, F3_BYTE, imm);
456
}
457
458
/// Store halfword: `mem[rs1 + imm] = rs2[15:0]`.
459
export fn sh(rs2: gen::Reg, rs1: gen::Reg, imm: i32) -> u32 {
460
    return encodeS(OP_STORE, rs1, rs2, F3_HALF, imm);
461
}
462
463
/// Store word: `mem[rs1 + imm] = rs2[31:0]`.
464
export fn sw(rs2: gen::Reg, rs1: gen::Reg, imm: i32) -> u32 {
465
    return encodeS(OP_STORE, rs1, rs2, F3_WORD, imm);
466
}
467
468
/// Store doubleword: `mem[rs1 + imm] = rs2[63:0]`.
469
export fn sd(rs2: gen::Reg, rs1: gen::Reg, imm: i32) -> u32 {
470
    return encodeS(OP_STORE, rs1, rs2, F3_DWORD, imm);
471
}
472
473
/////////////////////
474
// Branch (B-type) //
475
/////////////////////
476
477
/// Branch if equal: `if (rs1 == rs2) pc += imm`.
478
export fn beq(rs1: gen::Reg, rs2: gen::Reg, imm: i32) -> u32 {
479
    return encodeB(OP_BRANCH, rs1, rs2, F3_BEQ, imm);
480
}
481
482
/// Branch if not equal: `if (rs1 <> rs2) pc += imm`.
483
export fn bne(rs1: gen::Reg, rs2: gen::Reg, imm: i32) -> u32 {
484
    return encodeB(OP_BRANCH, rs1, rs2, F3_BNE, imm);
485
}
486
487
/// Branch if less than (signed): `if (rs1 < rs2) pc += imm`.
488
export fn blt(rs1: gen::Reg, rs2: gen::Reg, imm: i32) -> u32 {
489
    return encodeB(OP_BRANCH, rs1, rs2, F3_BLT, imm);
490
}
491
492
/// Branch if greater or equal (signed): `if (rs1 >= rs2) pc += imm`.
493
export fn bge(rs1: gen::Reg, rs2: gen::Reg, imm: i32) -> u32 {
494
    return encodeB(OP_BRANCH, rs1, rs2, F3_BGE, imm);
495
}
496
497
/// Branch if less than unsigned: `if (rs1 < rs2) pc += imm`.
498
export fn bltu(rs1: gen::Reg, rs2: gen::Reg, imm: i32) -> u32 {
499
    return encodeB(OP_BRANCH, rs1, rs2, F3_BLTU, imm);
500
}
501
502
/// Branch if greater or equal unsigned: `if (rs1 >= rs2) pc += imm`.
503
export fn bgeu(rs1: gen::Reg, rs2: gen::Reg, imm: i32) -> u32 {
504
    return encodeB(OP_BRANCH, rs1, rs2, F3_BGEU, imm);
505
}
506
507
//////////
508
// Jump //
509
//////////
510
511
/// Jump and link: `rd = pc + 4; pc += imm`.
512
export fn jal(rd: gen::Reg, imm: i32) -> u32 {
513
    return encodeJ(OP_JAL, rd, imm);
514
}
515
516
/// Jump and link register: `rd = pc + 4; pc = rs1 + imm`.
517
export fn jalr(rd: gen::Reg, rs1: gen::Reg, imm: i32) -> u32 {
518
    return encodeI(OP_JALR, rd, rs1, 0, imm);
519
}
520
521
/////////////////////
522
// Upper Immediate //
523
/////////////////////
524
525
/// Load upper immediate: `rd = imm << 12`.
526
export fn lui(rd: gen::Reg, imm: i32) -> u32 {
527
    return encodeU(OP_LUI, rd, imm);
528
}
529
530
/// Add upper immediate to PC: `rd = pc + (imm << 12)`.
531
export fn auipc(rd: gen::Reg, imm: i32) -> u32 {
532
    return encodeU(OP_AUIPC, rd, imm);
533
}
534
535
////////////
536
// System //
537
////////////
538
539
/// Environment call (system call).
540
export fn ecall() -> u32 {
541
    return encodeI(OP_SYSTEM, super::ZERO, super::ZERO, 0, 0);
542
}
543
544
/// Environment break (debugger breakpoint).
545
export fn ebreak() -> u32 {
546
    return encodeI(OP_SYSTEM, super::ZERO, super::ZERO, 0, 1);
547
}
548
549
/// Full predecessor/successor memory fence (`fence rw, rw`).
550
export fn fence() -> u32 {
551
    return fenceOrder(3, 3);
552
}
553
554
/// Encode a CSR instruction with a register source.
555
fn encodeCsr(op: u32, rd: gen::Reg, csr: u32, funct3: u32, rs1: gen::Reg) -> u32 {
556
    return (op             & 0x7F)
557
         | ((*rd as u32    & 0x1F) << 7)
558
         | ((funct3        & 0x07) << 12)
559
         | ((*rs1 as u32   & 0x1F) << 15)
560
         | ((csr           & 0xFFF) << 20);
561
}
562
563
/// Encode a CSR instruction with an immediate source.
564
fn encodeCsrImm(op: u32, rd: gen::Reg, csr: u32, funct3: u32, imm: u32) -> u32 {
565
    assert imm < 32;
566
    return (op             & 0x7F)
567
         | ((*rd as u32    & 0x1F) << 7)
568
         | ((funct3        & 0x07) << 12)
569
         | ((imm           & 0x1F) << 15)
570
         | ((csr           & 0xFFF) << 20);
571
}
572
573
/// Read CSR into `rd`.
574
export fn csrr(rd: gen::Reg, csr: u32) -> u32 {
575
    return encodeCsr(OP_SYSTEM, rd, csr, F3_CSRRS, super::ZERO);
576
}
577
578
/// Read/write CSR: old CSR to `rd`, write `rs1`.
579
export fn csrrw(rd: gen::Reg, csr: u32, rs1: gen::Reg) -> u32 {
580
    return encodeCsr(OP_SYSTEM, rd, csr, F3_CSRRW, rs1);
581
}
582
583
/// Write `rs1` into CSR and discard old value.
584
export fn csrw(csr: u32, rs1: gen::Reg) -> u32 {
585
    return encodeCsr(OP_SYSTEM, super::ZERO, csr, F3_CSRRW, rs1);
586
}
587
588
/// Clear CSR bits from `rs1` and discard old value.
589
export fn csrc(csr: u32, rs1: gen::Reg) -> u32 {
590
    return encodeCsr(OP_SYSTEM, super::ZERO, csr, F3_CSRRC, rs1);
591
}
592
593
/// Set CSR bits from a 5-bit immediate and discard old value.
594
export fn csrsi(csr: u32, imm: u32) -> u32 {
595
    return encodeCsrImm(OP_SYSTEM, super::ZERO, csr, F3_CSRRSI, imm);
596
}
597
598
/// Wait for interrupt.
599
export fn wfi() -> u32 {
600
    return 0x10500073;
601
}
602
603
/// Return from machine mode trap.
604
export fn mret() -> u32 {
605
    return 0x30200073;
606
}
607
608
/////////////////////////
609
// Pseudo-instructions //
610
/////////////////////////
611
612
/// No operation: `addi zero, zero, 0`.
613
export fn nop() -> u32 {
614
    return addi(super::ZERO, super::ZERO, 0);
615
}
616
617
/// Move: `rd = rs` (`addi rd, rs, 0`).
618
export fn mv(rd: gen::Reg, rs: gen::Reg) -> u32 {
619
    return addi(rd, rs, 0);
620
}
621
622
/// Bitwise NOT: `rd = ~rs` (`xori rd, rs, -1`).
623
export fn not_(rd: gen::Reg, rs: gen::Reg) -> u32 {
624
    return xori(rd, rs, -1);
625
}
626
627
/// Negate: `rd = -rs` (`sub rd, zero, rs`).
628
export fn neg(rd: gen::Reg, rs: gen::Reg) -> u32 {
629
    return sub(rd, super::ZERO, rs);
630
}
631
632
/// Return: `jalr zero, ra, 0`.
633
export fn ret() -> u32 {
634
    return jalr(super::ZERO, super::RA, 0);
635
}
636
637
/// Jump (unconditional): `jal zero, imm`.
638
export fn j(imm: i32) -> u32 {
639
    return jal(super::ZERO, imm);
640
}
641
642
/// Branch if less than or equal (signed): `if (rs1 <= rs2) pc += imm`.
643
/// Implemented as `bge rs2, rs1, imm` (swap operands).
644
export fn ble(rs1: gen::Reg, rs2: gen::Reg, imm: i32) -> u32 {
645
    return bge(rs2, rs1, imm);
646
}
647
648
/// Branch if greater than (signed): `if (rs1 > rs2) pc += imm`.
649
/// Implemented as `blt rs2, rs1, imm` (swap operands).
650
export fn bgt(rs1: gen::Reg, rs2: gen::Reg, imm: i32) -> u32 {
651
    return blt(rs2, rs1, imm);
652
}
653
654
/// Set if equal to zero: `rd = (rs == 0) ? 1 : 0`.
655
/// Implemented as `sltiu rd, rs, 1`.
656
export fn seqz(rd: gen::Reg, rs: gen::Reg) -> u32 {
657
    return sltiu(rd, rs, 1);
658
}
659
660
/// Set if not equal to zero: `rd = (rs <> 0) ? 1 : 0`.
661
/// Implemented as `sltu rd, zero, rs`.
662
export fn snez(rd: gen::Reg, rs: gen::Reg) -> u32 {
663
    return sltu(rd, super::ZERO, rs);
664
}
665
666
/// Branch if equal to zero: `if (rs == 0) pc += imm`.
667
export fn beqz(rs: gen::Reg, imm: i32) -> u32 {
668
    return beq(rs, super::ZERO, imm);
669
}
670
671
/// Branch if not equal to zero: `if (rs <> 0) pc += imm`.
672
export fn bnez(rs: gen::Reg, imm: i32) -> u32 {
673
    return bne(rs, super::ZERO, imm);
674
}
675
676
/// Call: `jal ra, imm`.
677
export fn call(imm: i32) -> u32 {
678
    return jal(super::RA, imm);
679
}
680
681
/// Order the specified predecessor and successor memory or I/O access classes.
682
/// Each mask uses I=8, O=4, R=2, W=1.
683
export fn fenceOrder(predecessor: u32, successor: u32) -> u32 {
684
    assert predecessor <= 15 and successor <= 15;
685
    return 0x0f | (predecessor << 24) | (successor << 20);
686
}
687
688
/// Synchronize subsequent instruction fetch on the executing hart.
689
export fn fenceI() -> u32 { return 0x0000100f; }