riscv.h 12.0 KiB raw
1
#ifndef OP_H
2
#define OP_H
3
4
#include "types.h"
5
6
/* Total number of registers. */
7
#define REGISTERS       32
8
/* Word size of target architecture (RISCV64). */
9
#define WORD_SIZE       8
10
/* Tag size for optional/union discriminants. */
11
#define TAG_SIZE        1
12
/* Instruction size in bytes (always 32-bit, even on RV64). */
13
#define INSTR_SIZE      4
14
/* Stack alignment requirement. */
15
#define STACK_ALIGNMENT 16
16
/* The frame pointer register is set as an alias of `S0`. */
17
#define FP              S0
18
19
/* Convenient macro wrappers for `instr`.
20
 * Some of these, such as BLE and BGT are implemented by swapping the operands
21
 * of other instructions. */
22
#define ADDI(rd, rs1, imm)   __instr(I_ADDI, rd, rs1, 0, imm)
23
#define SLTI(rd, rs1, imm)   __instr(I_SLTI, rd, rs1, 0, imm)
24
#define SLTIU(rd, rs1, imm)  __instr(I_SLTIU, rd, rs1, 0, imm)
25
#define XORI(rd, rs1, imm)   __instr(I_XORI, rd, rs1, 0, imm)
26
#define ORI(rd, rs1, imm)    __instr(I_ORI, rd, rs1, 0, imm)
27
#define ANDI(rd, rs1, imm)   __instr(I_ANDI, rd, rs1, 0, imm)
28
#define SLLI(rd, rs1, imm)   __instr(I_SLLI, rd, rs1, 0, imm)
29
#define SRLI(rd, rs1, imm)   __instr(I_SRLI, rd, rs1, 0, imm)
30
#define SRAI(rd, rs1, imm)   __instr(I_SRAI, rd, rs1, 0, imm)
31
#define JALR(rd, rs1, imm)   __instr(I_JALR, rd, rs1, 0, imm)
32
#define LB(rd, rs1, imm)     __instr(I_LB, rd, rs1, 0, imm)
33
#define LH(rd, rs1, imm)     __instr(I_LH, rd, rs1, 0, imm)
34
#define LW(rd, rs1, imm)     __instr(I_LW, rd, rs1, 0, imm)
35
#define LWU(rd, rs1, imm)    __instr(I_LWU, rd, rs1, 0, imm)
36
#define LD(rd, rs1, imm)     __instr(I_LD, rd, rs1, 0, imm)
37
#define LBU(rd, rs1, imm)    __instr(I_LBU, rd, rs1, 0, imm)
38
#define LHU(rd, rs1, imm)    __instr(I_LHU, rd, rs1, 0, imm)
39
#define SB(rs2, rs1, imm)    __instr(I_SB, 0, rs1, rs2, imm)
40
#define SH(rs2, rs1, imm)    __instr(I_SH, 0, rs1, rs2, imm)
41
#define SW(rs2, rs1, imm)    __instr(I_SW, 0, rs1, rs2, imm)
42
#define SD(rs2, rs1, imm)    __instr(I_SD, 0, rs1, rs2, imm)
43
#define BEQ(rs1, rs2, imm)   __instr(I_BEQ, 0, rs1, rs2, imm)
44
#define BNE(rs1, rs2, imm)   __instr(I_BNE, 0, rs1, rs2, imm)
45
#define BLT(rs1, rs2, imm)   __instr(I_BLT, 0, rs1, rs2, imm)
46
#define BGE(rs1, rs2, imm)   __instr(I_BGE, 0, rs1, rs2, imm)
47
#define BLTU(rs1, rs2, imm)  __instr(I_BLTU, 0, rs1, rs2, imm)
48
#define BGEU(rs1, rs2, imm)  __instr(I_BGEU, 0, rs1, rs2, imm)
49
#define BLE(rs1, rs2, imm)   __instr(I_BGE, 0, rs2, rs1, imm)
50
#define BGT(rs1, rs2, imm)   __instr(I_BLT, 0, rs2, rs1, imm)
51
#define ADD(rd, rs1, rs2)    __instr(I_ADD, rd, rs1, rs2, 0)
52
#define SUB(rd, rs1, rs2)    __instr(I_SUB, rd, rs1, rs2, 0)
53
#define DIV(rd, rs1, rs2)    __instr(I_DIV, rd, rs1, rs2, 0)
54
#define DIVU(rd, rs1, rs2)   __instr(I_DIVU, rd, rs1, rs2, 0)
55
#define REM(rd, rs1, rs2)    __instr(I_REM, rd, rs1, rs2, 0)
56
#define REMU(rd, rs1, rs2)   __instr(I_REMU, rd, rs1, rs2, 0)
57
#define MUL(rd, rs1, rs2)    __instr(I_MUL, rd, rs1, rs2, 0)
58
#define SLL(rd, rs1, rs2)    __instr(I_SLL, rd, rs1, rs2, 0)
59
#define SLT(rd, rs1, rs2)    __instr(I_SLT, rd, rs1, rs2, 0)
60
#define SLTU(rd, rs1, rs2)   __instr(I_SLTU, rd, rs1, rs2, 0)
61
#define XOR(rd, rs1, rs2)    __instr(I_XOR, rd, rs1, rs2, 0)
62
#define SRL(rd, rs1, rs2)    __instr(I_SRL, rd, rs1, rs2, 0)
63
#define AND(rd, rs1, rs2)    __instr(I_AND, rd, rs1, rs2, 0)
64
#define OR(rd, rs1, rs2)     __instr(I_OR, rd, rs1, rs2, 0)
65
#define LUI(rd, imm)         __instr(I_LUI, rd, 0, 0, imm)
66
#define AUIPC(rd, imm)       __instr(I_AUIPC, rd, 0, 0, imm)
67
#define JAL(rd, imm)         __instr(I_JAL, rd, 0, 0, imm)
68
#define JMP(imm)             __instr(I_JMP, 0, 0, 0, imm)
69
#define MV(rd, rs1)          __instr(I_MV, rd, rs1, 0, 0)
70
#define NOT(rd, rs1)         __instr(I_NOT, rd, rs1, 0, 0)
71
#define NEG(rd, rs1)         __instr(I_NEG, rd, rs1, 0, 0)
72
#define NOP                  __instr(I_NOP, 0, 0, 0, 0)
73
#define RET                  __instr(I_JALR, ZERO, RA, 0, 0)
74
#define EBREAK               __instr(I_EBREAK, 0, 0, 0, 0)
75
#define ECALL                __instr(I_ECALL, 0, 0, 0, 0)
76
/* RV64I word-width (32-bit) operations */
77
#define ADDIW(rd, rs1, imm)  __instr(I_ADDIW, rd, rs1, 0, imm)
78
#define ADDW(rd, rs1, rs2)   __instr(I_ADDW, rd, rs1, rs2, 0)
79
#define SUBW(rd, rs1, rs2)   __instr(I_SUBW, rd, rs1, rs2, 0)
80
#define MULW(rd, rs1, rs2)   __instr(I_MULW, rd, rs1, rs2, 0)
81
#define DIVW(rd, rs1, rs2)   __instr(I_DIVW, rd, rs1, rs2, 0)
82
#define DIVUW(rd, rs1, rs2)  __instr(I_DIVUW, rd, rs1, rs2, 0)
83
#define REMW(rd, rs1, rs2)   __instr(I_REMW, rd, rs1, rs2, 0)
84
#define REMUW(rd, rs1, rs2)  __instr(I_REMUW, rd, rs1, rs2, 0)
85
#define SLLIW(rd, rs1, imm)  __instr(I_SLLIW, rd, rs1, 0, imm)
86
#define SRLIW(rd, rs1, imm)  __instr(I_SRLIW, rd, rs1, 0, imm)
87
#define SRAIW(rd, rs1, imm)  __instr(I_SRAIW, rd, rs1, 0, imm)
88
#define SLLW(rd, rs1, rs2)   __instr(I_SLLW, rd, rs1, rs2, 0)
89
#define SRLW(rd, rs1, rs2)   __instr(I_SRLW, rd, rs1, rs2, 0)
90
#define SRAW(rd, rs1, rs2)   __instr(I_SRAW, rd, rs1, rs2, 0)
91
/* F Extension - Floating-point instructions */
92
#define FADD_S(rd, rs1, rs2) __instr(I_FADD_S, rd, rs1, rs2, 0)
93
#define FSUB_S(rd, rs1, rs2) __instr(I_FSUB_S, rd, rs1, rs2, 0)
94
#define FMUL_S(rd, rs1, rs2) __instr(I_FMUL_S, rd, rs1, rs2, 0)
95
#define FDIV_S(rd, rs1, rs2) __instr(I_FDIV_S, rd, rs1, rs2, 0)
96
#define FEQ_S(rd, rs1, rs2)  __instr(I_FEQ_S, rd, rs1, rs2, 0)
97
#define FLT_S(rd, rs1, rs2)  __instr(I_FLT_S, rd, rs1, rs2, 0)
98
#define FLE_S(rd, rs1, rs2)  __instr(I_FLE_S, rd, rs1, rs2, 0)
99
#define FLW(rd, rs1, imm)    __instr(I_FLW, rd, rs1, 0, imm)
100
#define FSW(rs2, rs1, imm)   __instr(I_FSW, 0, rs1, rs2, imm)
101
102
/* String representations of register names. */
103
extern const char *reg_names[];
104
105
/* Boolean map of caller-saved registers.
106
 * True for registers that need to be saved by the caller
107
 * before a function call. */
108
extern const bool caller_saved_registers[REGISTERS];
109
110
/* RISC-V register names. */
111
typedef enum {
112
    ZERO = 0,  /* Hard-wired zero */
113
    RA   = 1,  /* Return address */
114
    SP   = 2,  /* Stack pointer */
115
    GP   = 3,  /* Global pointer */
116
    TP   = 4,  /* Thread pointer */
117
    T0   = 5,  /* Temporary/alternate link register */
118
    T1   = 6,  /* Temporary */
119
    T2   = 7,  /* Temporary */
120
    S0   = 8,  /* Saved register/frame pointer */
121
    S1   = 9,  /* Saved register */
122
    A0   = 10, /* Function arguments/returns */
123
    A1   = 11,
124
    A2   = 12, /* Function arguments */
125
    A3   = 13,
126
    A4   = 14,
127
    A5   = 15,
128
    A6   = 16,
129
    A7   = 17,
130
    S2   = 18, /* Saved registers */
131
    S3   = 19,
132
    S4   = 20,
133
    S5   = 21,
134
    S6   = 22,
135
    S7   = 23,
136
    S8   = 24,
137
    S9   = 25,
138
    S10  = 26,
139
    S11  = 27,
140
    T3   = 28, /* Temporaries */
141
    T4   = 29,
142
    T5   = 30,
143
    T6   = 31
144
} reg_t;
145
146
/* Temporary registers (T1-T6) */
147
extern const reg_t temp_registers[6];
148
149
/* Opcodes for RISC-V base instruction set */
150
typedef enum {
151
    OP_LOAD   = 0x03,
152
    OP_STORE  = 0x23,
153
    OP_BRANCH = 0x63,
154
    OP_JALR   = 0x67,
155
    OP_JAL    = 0x6F,
156
    OP_OP     = 0x33,
157
    OP_IMM    = 0x13,
158
    OP_AUIPC  = 0x17,
159
    OP_IMM_32 = 0x1B, /* RV64I: ADDIW, SLLIW, SRLIW, SRAIW */
160
    OP_OP_32 = 0x3B, /* RV64I: ADDW, SUBW, SLLW, SRLW, SRAW, MULW, DIVW, REMW */
161
    OP_LUI   = 0x37,
162
    OP_SYSTEM = 0x73,
163
    OP_FENCE  = 0x0F,
164
    /* F Extension opcodes */
165
    OP_LOAD_FP  = 0x07,
166
    OP_STORE_FP = 0x27,
167
    OP_OP_FP    = 0x53
168
} opcode_t;
169
170
/* Function3 values */
171
typedef enum {
172
    /* Memory operations */
173
    FUNCT3_BYTE   = 0x0, /* LB/SB - Load/Store Byte */
174
    FUNCT3_HALF   = 0x1, /* LH/SH - Load/Store Halfword */
175
    FUNCT3_WORD   = 0x2, /* LW/SW - Load/Store Word */
176
    FUNCT3_DOUBLE = 0x3, /* LD/SD - Load/Store Doubleword */
177
    FUNCT3_BYTE_U = 0x4, /* LBU - Load Byte Unsigned */
178
    FUNCT3_HALF_U = 0x5, /* LHU - Load Halfword Unsigned */
179
    FUNCT3_WORD_U = 0x6, /* LWU - Load Word Unsigned */
180
181
    /* ALU operations */
182
    FUNCT3_ADD  = 0x0, /* ADD/SUB/ADDI */
183
    FUNCT3_SLL  = 0x1, /* SLL/SLLI */
184
    FUNCT3_SLT  = 0x2, /* SLT/SLTI */
185
    FUNCT3_SLTU = 0x3, /* SLTU/SLTIU */
186
    FUNCT3_XOR  = 0x4, /* XOR/XORI */
187
    FUNCT3_SRL  = 0x5, /* SRL/SRA/SRLI/SRAI */
188
    FUNCT3_OR   = 0x6, /* OR/ORI */
189
    FUNCT3_AND  = 0x7, /* AND/ANDI */
190
    /* F Extension function3 codes */
191
    FUNCT3_WORD_FP = 0x2, /* FLW/FSW - Load/Store Single */
192
    FUNCT3_FEQ     = 0x2, /* FEQ.S */
193
    FUNCT3_FLT     = 0x1, /* FLT.S */
194
    FUNCT3_FLE     = 0x0  /* FLE.S */
195
} funct3_t;
196
197
/* Function7 values */
198
typedef enum {
199
    FUNCT7_NORMAL = 0x00,
200
    FUNCT7_SUB    = 0x20,
201
    FUNCT7_SRA    = 0x20,
202
    FUNCT7_MUL    = 0x01,
203
    /* F Extension function codes */
204
    FUNCT7_FADD_S = 0x00,
205
    FUNCT7_FSUB_S = 0x04,
206
    FUNCT7_FMUL_S = 0x08,
207
    FUNCT7_FDIV_S = 0x0C,
208
    FUNCT7_FEQ_S  = 0x50,
209
    FUNCT7_FLT_S  = 0x50,
210
    FUNCT7_FLE_S  = 0x50
211
} funct7_t;
212
213
/* Represents a RISC-V instruction in its various formats */
214
typedef union {
215
    struct {
216
        u32 opcode : 7;
217
        u32 rd     : 5;
218
        u32 funct3 : 3;
219
        u32 rs1    : 5;
220
        u32 rs2    : 5;
221
        u32 funct7 : 7;
222
    } r; /* Register format */
223
224
    struct {
225
        u32 opcode   : 7;
226
        u32 rd       : 5;
227
        u32 funct3   : 3;
228
        u32 rs1      : 5;
229
        u32 imm_11_0 : 12;
230
    } i; /* Immediate format */
231
232
    struct {
233
        u32 opcode   : 7;
234
        u32 imm_4_0  : 5;
235
        u32 funct3   : 3;
236
        u32 rs1      : 5;
237
        u32 rs2      : 5;
238
        u32 imm_11_5 : 7;
239
    } s; /* Store format */
240
241
    struct {
242
        u32 opcode   : 7;
243
        u32 imm_11   : 1;
244
        u32 imm_4_1  : 4;
245
        u32 funct3   : 3;
246
        u32 rs1      : 5;
247
        u32 rs2      : 5;
248
        u32 imm_10_5 : 6;
249
        u32 imm_12   : 1;
250
    } b; /* Branch format */
251
252
    struct {
253
        u32 opcode    : 7;
254
        u32 rd        : 5;
255
        u32 imm_31_12 : 20;
256
    } u; /* Upper immediate format */
257
258
    struct {
259
        u32 opcode    : 7;
260
        u32 rd        : 5;
261
        u32 imm_19_12 : 8;
262
        u32 imm_11    : 1;
263
        u32 imm_10_1  : 10;
264
        u32 imm_20    : 1;
265
    } j; /* Jump format */
266
267
    u32 raw; /* Raw 32-bit instruction */
268
} instr_t;
269
270
/* Instruction type. */
271
typedef enum {
272
    IFMT_I, /* I-type (immediate) */
273
    IFMT_R, /* R-type (register) */
274
    IFMT_S, /* S-type (store) */
275
    IFMT_B, /* B-type (branch) */
276
    IFMT_U, /* U-type (upper immediate) */
277
    IFMT_J, /* J-type (jump) */
278
} ifmt_t;
279
280
/* RISC-V instruction name. */
281
typedef enum {
282
    I_LUI,
283
    I_AUIPC,
284
    I_JAL,
285
    I_JALR,
286
    I_BEQ,
287
    I_BNE,
288
    I_BLT,
289
    I_BGE,
290
    I_BLTU,
291
    I_BGEU,
292
    I_LB,
293
    I_LH,
294
    I_LW,
295
    I_LBU,
296
    I_LHU,
297
    I_SB,
298
    I_SH,
299
    I_SW,
300
    I_ADDI,
301
    I_SLTI,
302
    I_SLTIU,
303
    I_XORI,
304
    I_ORI,
305
    I_ANDI,
306
    I_SLLI,
307
    I_SRLI,
308
    I_SRAI,
309
    I_ADD,
310
    I_SUB,
311
    I_SLL,
312
    I_SLT,
313
    I_SLTU,
314
    I_XOR,
315
    I_SRL,
316
    I_SRA,
317
    I_OR,
318
    I_AND,
319
    I_MUL,
320
    I_MULH,
321
    I_MULHSU,
322
    I_MULHU,
323
    I_DIV,
324
    I_DIVU,
325
    I_REM,
326
    I_REMU,
327
    I_MV,
328
    I_JMP,
329
    I_NOP,
330
    I_NOT,
331
    I_NEG,
332
    I_EBREAK,
333
    I_ECALL,
334
    /* F Extension - Floating-point instructions */
335
    I_FADD_S,
336
    I_FSUB_S,
337
    I_FMUL_S,
338
    I_FDIV_S,
339
    I_FEQ_S,
340
    I_FLT_S,
341
    I_FLE_S,
342
    I_FLW,
343
    I_FSW,
344
    /* RV64I extensions */
345
    I_LWU,
346
    I_LD,
347
    I_SD,
348
    I_ADDIW,
349
    I_SLLIW,
350
    I_SRLIW,
351
    I_SRAIW,
352
    I_ADDW,
353
    I_SUBW,
354
    I_SLLW,
355
    I_SRLW,
356
    I_SRAW,
357
    I_MULW,
358
    I_DIVW,
359
    I_DIVUW,
360
    I_REMW,
361
    I_REMUW
362
} iname_t;
363
364
/* Returns a RISC-V instruction based on the instruction type. */
365
instr_t instr(iname_t op, reg_t rd, reg_t rs1, reg_t rs2, i32 imm);
366
367
static inline instr_t __instr(
368
    iname_t op, reg_t rd, reg_t rs1, reg_t rs2, i32 imm
369
) {
370
    return instr(op, rd, rs1, rs2, imm);
371
}
372
373
/* Return true when a signed 12-bit immediate can encode `value`. */
374
static inline bool is_small(i32 value) {
375
    return value >= -2048 && value <= 2047;
376
}
377
378
static inline bool is_branch_imm(i32 value) {
379
    return value >= -(1 << 12) && value <= ((1 << 12) - 2) && !(value & 1);
380
}
381
382
static inline bool is_jump_imm(i32 value) {
383
    return value >= -(1 << 20) && value <= ((1 << 20) - 2) && !(value & 1);
384
}
385
386
/* Helper function to sign-extend a value. */
387
i32 sign_extend(u32 value, int bit_width);
388
/* Aligns a size to the specified alignment boundary. */
389
i32 align(i32 size, i32 alignment);
390
/* Functions to get immediates out of instruction. */
391
i32 get_i_imm(instr_t instr);
392
i32 get_s_imm(instr_t instr);
393
i32 get_b_imm(instr_t instr);
394
i32 get_j_imm(instr_t instr);
395
396
#endif