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