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