Files
scc/assembler/riscv32/riscv32_instr.h
2025-04-01 00:13:21 +08:00

949 lines
18 KiB
C

#ifndef __SMCC_RISCV32_INSTR_H__
#define __SMCC_RISCV32_INSTR_H__
#include "riscv32.h"
#include "riscv32_def.h"
#include "symtab_asm.h"
#define EMIT_PUSH_BACK (-1)
/* base integer instruction */
/**
* ADD
*
* add rd, rs1, rs2
*
* rd = rs1 + rs2
*/
static inline int
rv32_add(rv32_prog_t* prog, rv_reg_t rd, rv_reg_t rs1, rv_reg_t rs2) {
rv32_instr_t instr = {
.instr_type = RV_ADD,
.rd = rd,
.rs1 = rs1,
.rs2 = rs2,
};
return emit_rv32_instr(prog, &instr, EMIT_PUSH_BACK, NULL);
}
/**
* ADD Immediate
*
* addi rd, rs1, imm
*
* rd = rs1 + imm (imm maybe cut)
*/
static inline int
rv32_addi(rv32_prog_t* prog, rv_reg_t rd, rv_reg_t rs1, u32_t imm) {
rv32_instr_t instr = {
.instr_type = RV_ADDI,
.rd = rd,
.rs1 = rs1,
.rs2 = REG_NULL,
.imm = imm,
};
return emit_rv32_instr(prog, &instr, EMIT_PUSH_BACK, NULL);
}
/**
* AND
*
* and rd, rs1, rs2
*
* rd = rs1 & rs2
*/
static inline int
rv32_and(rv32_prog_t* prog, rv_reg_t rd, rv_reg_t rs1, rv_reg_t rs2) {
rv32_instr_t instr = {
.instr_type = RV_AND,
.rd = rd,
.rs1 = rs1,
.rs2 = rs2,
.imm = 0,
};
return emit_rv32_instr(prog, &instr, EMIT_PUSH_BACK, NULL);
}
/**
* AND Immediate
*
* andi rd, rs1, imm
*
* rd = rs1 & imm (imm maybe cut)
*/
static inline int
rv32_andi(rv32_prog_t* prog, rv_reg_t rd, rv_reg_t rs1, u32_t imm) {
rv32_instr_t instr = {
.instr_type = RV_ANDI,
.rd = rd,
.rs1 = rs1,
.rs2 = REG_NULL,
.imm = imm,
};
return emit_rv32_instr(prog, &instr, EMIT_PUSH_BACK, NULL);
}
/**
* Add Upper Immediate to PC
*
* auipc rd, imm{12}
*
* rd = PC + imm{12}
*/
static inline int
rv32_auipc(rv32_prog_t* prog, rv_reg_t rd, u32_t imm) {
rv32_instr_t instr = {
.instr_type = RV_AUIPC,
.rd = rd,
.rs1 = REG_NULL,
.rs2 = REG_NULL,
.imm = imm,
};
return emit_rv32_instr(prog, &instr, EMIT_PUSH_BACK, NULL);
}
/**
* Branch EQual
*
* beq rs1, rs2, imm
*
* if (rs1 == rs2) PC += imm{alian2}
*/
static inline int
rv32_beq(rv32_prog_t* prog, rv_reg_t rs1, rv_reg_t rs2, u32_t imm) {
rv32_instr_t instr = {
.instr_type = RV_BEQ,
.rd = REG_NULL,
.rs1 = rs1,
.rs2 = rs2,
.imm = imm,
};
return emit_rv32_instr(prog, &instr, EMIT_PUSH_BACK, NULL);
}
/**
* Branch Greater than or Equal
*
* bge rs1, rs2, imm
*
* if (rs1 >= rs2) PC += imm{alian2}
*/
static inline int
rv32_bge(rv32_prog_t* prog, rv_reg_t rs1, rv_reg_t rs2, u32_t imm) {
rv32_instr_t instr = {
.instr_type = RV_BGE,
.rd = REG_NULL,
.rs1 = rs1,
.rs2 = rs2,
.imm = imm,
};
return emit_rv32_instr(prog, &instr, EMIT_PUSH_BACK, NULL);
}
/**
* Branch Greater than or Equal Unsigned
*
* bgeu rs1, rs2, imm
*
* if (rs1 >= u rs2) PC += imm{alian2}
*/
static inline int
rv32_bgeu(rv32_prog_t* prog, rv_reg_t rs1, rv_reg_t rs2, u32_t imm) {
rv32_instr_t instr = {
.instr_type = RV_BGEU,
.rd = REG_NULL,
.rs1 = rs1,
.rs2 = rs2,
.imm = imm,
};
return emit_rv32_instr(prog, &instr, EMIT_PUSH_BACK, NULL);
}
/**
* Branch Less Than
*
* blt rs1, rs2, imm
*
* if (rs1 < rs2) PC += imm{alian2}
*/
static inline int
rv32_blt(rv32_prog_t* prog, rv_reg_t rs1, rv_reg_t rs2, u32_t imm) {
rv32_instr_t instr = {
.instr_type = RV_BLT,
.rd = REG_NULL,
.rs1 = rs1,
.rs2 = rs2,
.imm = imm,
};
return emit_rv32_instr(prog, &instr, EMIT_PUSH_BACK, NULL);
}
/**
* Branch Less Than Unsigned
*
* bltu rs1, rs2, imm
*
* if (rs1 < u rs2) PC += imm{alian2}
*/
static inline int
rv32_bltu(rv32_prog_t* prog, rv_reg_t rs1, rv_reg_t rs2, u32_t imm) {
rv32_instr_t instr = {
.instr_type = RV_BLTU,
.rd = REG_NULL,
.rs1 = rs1,
.rs2 = rs2,
.imm = imm,
};
return emit_rv32_instr(prog, &instr, EMIT_PUSH_BACK, NULL);
}
/**
* Branch Not Equal
*
* bne rs1, rs2, imm
*
* if (rs1 != rs2) PC += imm{alian2}
*/
static inline int
rv32_bne(rv32_prog_t* prog, rv_reg_t rs1, rv_reg_t rs2, u32_t imm) {
rv32_instr_t instr = {
.instr_type = RV_BNE,
.rd = REG_NULL,
.rs1 = rs1,
.rs2 = rs2,
.imm = imm,
};
return emit_rv32_instr(prog, &instr, EMIT_PUSH_BACK, NULL);
}
/**
* Environment BREAK
*
* ebreak
*
* Transfer control to debugger
*/
static inline int
rv32_ebreak(rv32_prog_t* prog) {
rv32_instr_t instr = {
.instr_type = RV_EBREAK,
.rd = REG_NULL,
.rs1 = REG_NULL,
.rs2 = REG_NULL,
.imm = 1,
};
return emit_rv32_instr(prog, &instr, EMIT_PUSH_BACK, NULL);
}
/**
* Environment CALL
*
* ecall
*
* Transfer control to operating system
*/
static inline int
rv32_ecall(rv32_prog_t* prog) {
rv32_instr_t instr = {
.instr_type = RV_ECALL,
.rd = REG_NULL,
.rs1 = REG_NULL,
.rs2 = REG_NULL,
.imm = 0,
};
return emit_rv32_instr(prog, &instr, EMIT_PUSH_BACK, NULL);
}
/**
* Jump And Link
*
* jal rd, imm
*
* rd = PC + 4; PC += imm{alian2}
*/
static inline int
rv32_jal(rv32_prog_t* prog, rv_reg_t rd, u32_t imm) {
rv32_instr_t instr = {
.instr_type = RV_JAL,
.rd = rd,
.rs1 = REG_NULL,
.rs2 = REG_NULL,
.imm = imm,
};
return emit_rv32_instr(prog, &instr, EMIT_PUSH_BACK, NULL);
}
/**
* Jump And Link Register
*
* jalr rd, rs1, imm
*
* rd = PC + 4; PC = rs1 + imm
*/
static inline int
rv32_jalr(rv32_prog_t* prog, rv_reg_t rd, rv_reg_t rs1, u32_t imm) {
rv32_instr_t instr = {
.instr_type = RV_JALR,
.rd = rd,
.rs1 = rs1,
.rs2 = REG_NULL,
.imm = imm,
};
return emit_rv32_instr(prog, &instr, EMIT_PUSH_BACK, NULL);
}
/**
* Load Byte
*
* lb rd, rs1, imm
*
* rd = (8 bit) M[rs1+imm]
*/
static inline int
rv32_lb(rv32_prog_t* prog, rv_reg_t rd, rv_reg_t rs1, u32_t imm) {
rv32_instr_t instr = {
.instr_type = RV_LB,
.rd = rd,
.rs1 = rs1,
.rs2 = REG_NULL,
.imm = imm,
};
return emit_rv32_instr(prog, &instr, EMIT_PUSH_BACK, NULL);
}
/**
* Load Byte Unsigned
*
* lbu rd, rs1, imm
*
* rd = (8 bit) M[rs1+imm]
*/
static inline int
rv32_lbu(rv32_prog_t* prog, rv_reg_t rd, rv_reg_t rs1, u32_t imm) {
rv32_instr_t instr = {
.instr_type = RV_LBU,
.rd = rd,
.rs1 = rs1,
.rs2 = REG_NULL,
.imm = imm,
};
return emit_rv32_instr(prog, &instr, EMIT_PUSH_BACK, NULL);
}
/**
* ld
* lh
* lhu
*/
/**
* Load Upper Immediate
*
* lui rd, imm
*
* rd = (32 bit) imm
*/
static inline int
rv32_lui(rv32_prog_t* prog, rv_reg_t rd, u32_t imm) {
rv32_instr_t instr = {
.instr_type = RV_LUI,
.rd = rd,
.rs1 = REG_NULL,
.rs2 = REG_NULL,
.imm = imm,
};
return emit_rv32_instr(prog, &instr, EMIT_PUSH_BACK, NULL);
}
/**
* Load Word
*
* lw rd, rs1, imm
*
* rd = (32 bit) M[rs1+imm]
*/
static inline int
rv32_lw(rv32_prog_t* prog, rv_reg_t rd, rv_reg_t rs1, u32_t imm) {
rv32_instr_t instr = {
.instr_type = RV_LW,
.rd = rd,
.rs1 = rs1,
.rs2 = REG_NULL,
.imm = imm,
};
return emit_rv32_instr(prog, &instr, EMIT_PUSH_BACK, NULL);
}
/**
* Load Word Unsigned
*
* lwu rd, rs1, imm
*
* rd = (32 bit) u M[rs1+imm]
*/
// static inline int
// rv32_lwu(rv32_prog_t* prog, rv_reg_t rd, rv_reg_t rs1, u32_t imm) {
// return emit_rv32_instr(prog, RV_LWU, rd, rs1, REG_NULL, imm);
// }
/**
* OR
*
* or rd, rs1, rs2
*
* rd = rs1 | rs2
*/
static inline int
rv32_or(rv32_prog_t* prog, rv_reg_t rd, rv_reg_t rs1, rv_reg_t rs2) {
rv32_instr_t instr = {
.instr_type = RV_OR,
.rd = rd,
.rs1 = rs1,
.rs2 = rs2,
.imm = 0,
};
return emit_rv32_instr(prog, &instr, EMIT_PUSH_BACK, NULL);
}
/**
* OR Immediate
*
* ori rd, rs1, imm
*
* rd = rs1 | imm (imm maybe cut)
*/
static inline int
rv32_ori(rv32_prog_t* prog, rv_reg_t rd, rv_reg_t rs1, u32_t imm) {
rv32_instr_t instr = {
.instr_type = RV_ORI,
.rd = rd,
.rs1 = rs1,
.rs2 = REG_NULL,
.imm = imm,
};
return emit_rv32_instr(prog, &instr, EMIT_PUSH_BACK, NULL);
}
/**
* Store Byte
*
* sb rs2, rs1, imm
*
* M[rs1+imm] = rs2
*/
static inline int
rv32_sb(rv32_prog_t* prog, rv_reg_t rs2, rv_reg_t rs1, u32_t imm) {
rv32_instr_t instr = {
.instr_type = RV_SB,
.rd = REG_NULL,
.rs1 = rs1,
.rs2 = rs2,
.imm = imm,
};
return emit_rv32_instr(prog, &instr, EMIT_PUSH_BACK, NULL);
}
/**
* sd sh
*/
/**
* Shift Left
*
* sll rd, rs1, rs2
*
* rd = rs1 << rs2
*/
static inline int
rv32_sll(rv32_prog_t* prog, rv_reg_t rd, rv_reg_t rs1, rv_reg_t rs2) {
rv32_instr_t instr = {
.instr_type = RV_SLL,
.rd = rd,
.rs1 = rs1,
.rs2 = rs2,
.imm = 0,
};
return emit_rv32_instr(prog, &instr, EMIT_PUSH_BACK, NULL);
}
/**
* Shift Left Immediate
*
* slli rd, rs1, imm
*
* rd = rs1 << imm (maybe cut it)
*/
static inline int
rv32_slli(rv32_prog_t* prog, rv_reg_t rd, rv_reg_t rs1, u32_t imm) {
rv32_instr_t instr = {
.instr_type = RV_SLLI,
.rd = rd,
.rs1 = rs1,
.rs2 = REG_NULL,
.imm = imm,
};
return emit_rv32_instr(prog, &instr, EMIT_PUSH_BACK, NULL);
}
/**
* Set Less Than
*
* slt rd, rs1, rs2
*
* rd = (rs1 < rs2) ? 1 : 0
*/
static inline int
rv32_slt(rv32_prog_t* prog, rv_reg_t rd, rv_reg_t rs1, rv_reg_t rs2) {
rv32_instr_t instr = {
.instr_type = RV_SLT,
.rd = rd,
.rs1 = rs1,
.rs2 = rs2,
.imm = 0,
};
return emit_rv32_instr(prog, &instr, EMIT_PUSH_BACK, NULL);
}
/**
* Set Less Than Immediate
*
* slti rd, rs1, imm
*
* rd = (rs1 < imm) ? 1 : 0
*/
static inline int
rv32_slti(rv32_prog_t* prog, rv_reg_t rd, rv_reg_t rs1, u32_t imm) {
rv32_instr_t instr = {
.instr_type = RV_SLTI,
.rd = rd,
.rs1 = rs1,
.rs2 = REG_NULL,
.imm = imm,
};
return emit_rv32_instr(prog, &instr, EMIT_PUSH_BACK, NULL);
}
/**
* Set Less Than Immediate Unsigned
*
* sltiu rd, rs1, imm
*
* rd = (u rs1 < imm) ? 1 : 0
*/
static inline int
rv32_sltiu(rv32_prog_t* prog, rv_reg_t rd, rv_reg_t rs1, u32_t imm) {
rv32_instr_t instr = {
.instr_type = RV_SLTIU,
.rd = rd,
.rs1 = rs1,
.rs2 = REG_NULL,
.imm = imm,
};
return emit_rv32_instr(prog, &instr, EMIT_PUSH_BACK, NULL);
}
/**
* Set Less Than Unsigned
*
* sltu rd, rs1, rs2
*
* rd = (u rs1 < u rs2) ? 1 : 0
*/
static inline int
rv32_sltu(rv32_prog_t* prog, rv_reg_t rd, rv_reg_t rs1, rv_reg_t rs2) {
rv32_instr_t instr = {
.instr_type = RV_SLTU,
.rd = rd,
.rs1 = rs1,
.rs2 = rs2,
.imm = 0,
};
return emit_rv32_instr(prog, &instr, EMIT_PUSH_BACK, NULL);
}
/**
* Shift Right Arithmetic
*
* sra rd, rs1, rs2
*
* rd = rs1 >> rs2
*/
static inline int
rv32_sra(rv32_prog_t* prog, rv_reg_t rd, rv_reg_t rs1, rv_reg_t rs2) {
rv32_instr_t instr = {
.instr_type = RV_SRA,
.rd = rd,
.rs1 = rs1,
.rs2 = rs2,
.imm = 0,
};
return emit_rv32_instr(prog, &instr, EMIT_PUSH_BACK, NULL);
}
/**
* Shift Right Arithmetic Immediate
*
* srai rd, rs1, imm
*
* rd = rs1 >> imm (maybe cut it)
*/
static inline int
rv32_srai(rv32_prog_t* prog, rv_reg_t rd, rv_reg_t rs1, u32_t imm) {
rv32_instr_t instr = {
.instr_type = RV_SRAI,
.rd = rd,
.rs1 = rs1,
.rs2 = REG_NULL,
.imm = imm,
};
return emit_rv32_instr(prog, &instr, EMIT_PUSH_BACK, NULL);
}
/**
* Shift Right Logical
*
* srl rd, rs1, rs2
*
* rd = (u rs1) >> rs2
*/
static inline int
rv32_srl(rv32_prog_t* prog, rv_reg_t rd, rv_reg_t rs1, rv_reg_t rs2) {
rv32_instr_t instr = {
.instr_type = RV_SRL,
.rd = rd,
.rs1 = rs1,
.rs2 = rs2,
.imm = 0,
};
return emit_rv32_instr(prog, &instr, EMIT_PUSH_BACK, NULL);
}
/**
* Shift Right Logical Immediate
*
* srli rd, rs1, imm
*
* rd = (u rs1) >> imm (maybe cut it)
*/
static inline int
rv32_srli(rv32_prog_t* prog, rv_reg_t rd, rv_reg_t rs1, u32_t imm) {
rv32_instr_t instr = {
.instr_type = RV_SRLI,
.rd = rd,
.rs1 = rs1,
.rs2 = REG_NULL,
.imm = imm,
};
return emit_rv32_instr(prog, &instr, EMIT_PUSH_BACK, NULL);
}
/**
* SUBtract
*
* sub rd, rs1, rs2
*
* rd = rs1 - rs2
*/
static inline int
rv32_sub(rv32_prog_t* prog, rv_reg_t rd, rv_reg_t rs1, rv_reg_t rs2) {
rv32_instr_t instr = {
.instr_type = RV_SUB,
.rd = rd,
.rs1 = rs1,
.rs2 = rs2,
.imm = 0,
};
return emit_rv32_instr(prog, &instr, EMIT_PUSH_BACK, NULL);
}
/**
* Store Word
*
* sw rs2, rs1, imm
*
* M[rs1+imm] = rs2
*/
static inline int
rv32_sw(rv32_prog_t* prog, rv_reg_t rs2, rv_reg_t rs1, u32_t imm) {
rv32_instr_t instr = {
.instr_type = RV_SW,
.rd = REG_NULL,
.rs1 = rs1,
.rs2 = rs2,
.imm = imm,
};
return emit_rv32_instr(prog, &instr, EMIT_PUSH_BACK, NULL);
}
/**
* XOR
*
* xor rd, rs1, rs2
*
* rd = rs1 ^ rs2
*/
static inline int
rv32_xor(rv32_prog_t* prog, rv_reg_t rd, rv_reg_t rs1, rv_reg_t rs2) {
rv32_instr_t instr = {
.instr_type = RV_XOR,
.rd = rd,
.rs1 = rs1,
.rs2 = rs2,
.imm = 0,
};
return emit_rv32_instr(prog, &instr, EMIT_PUSH_BACK, NULL);
}
/**
* XOR Immediate
*
* xori rd, rs1, imm
*
* rd = rs1 ^ imm (maybe cut it)
*/
static inline int
rv32_xori(rv32_prog_t* prog, rv_reg_t rd, rv_reg_t rs1, u32_t imm) {
rv32_instr_t instr = {
.instr_type = RV_XORI,
.rd = rd,
.rs1 = rs1,
.rs2 = REG_NULL,
.imm = imm,
};
return emit_rv32_instr(prog, &instr, EMIT_PUSH_BACK, NULL);
}
/* pseudo instruction */
/**
* branch equal zero
*
* beqz rs1, imm
*
* if (rs1 == 0) PC += imm{alian2}
*/
static inline int
rv32_beqz(rv32_prog_t* prog, rv_reg_t rs1, u32_t imm) {
return rv32_beq(prog, rs1, REG_X0, imm);
}
/**
* branch not equal zero
*
* bnez rs1, imm
*
* if (rs1 != 0) PC += imm{alian2}
*/
static inline int
rv32_bnez(rv32_prog_t* prog, rv_reg_t rs1, u32_t imm) {
return rv32_bne(prog, rs1, REG_X0, imm);
}
/**
* fabs.s fabs.d
* fmv.s fmv.d
* fneg.s fneg.d
*/
/**
* jump
*
* j imm
*
* PC = imm{alian2}
*/
static inline int
rv32_j(rv32_prog_t* prog, u32_t imm) {
// TODO
return rv32_jal(prog, REG_X0, imm);
}
/**
* jump register
*
* jr rs1
*
* PC = rs1
*/
static inline int
rv32_jr(rv32_prog_t* prog, rv_reg_t rs1) {
// TODO
return rv32_jalr(prog, REG_X0, rs1, 0);
}
/**
* load address
*
* la rd
*
* rd = address
*/
static inline int
rv32_la(rv32_prog_t* prog, rv_reg_t rd, u32_t imm) {
// TODO
return rv32_auipc(prog, rd, imm);
}
/**
* load immediate
*
* li rd, imm
*
* rd = imm
*/
static inline int
rv32_li(rv32_prog_t* prog, rv_reg_t rd, i32_t imm) {
if (imm >= -2048 && imm <= 2047) {
return rv32_addi(prog, rd, REG_X0, imm);
} else {
int ret = rv32_lui(prog, rd, imm);
rv32_addi(prog, rd, rd, imm);
return ret;
}
}
/**
* move
*
* mv rd, rs1
*
* rd = rs1
*/
static inline int
rv32_mv(rv32_prog_t* prog, rv_reg_t rd, rv_reg_t rs1) {
return rv32_addi(prog, rd, rs1, 0);
}
/**
* negate
*
* neg rd, rs1
*
* rd = -rs1
*/
static inline int
rv32_neg(rv32_prog_t* prog, rv_reg_t rd, rv_reg_t rs1) {
return rv32_sub(prog, rd, REG_X0, rs1);
}
/**
* no opreation
*
* nop
*
* x0 = x0
*/
static inline int
rv32_nop(rv32_prog_t* prog) {
return rv32_addi(prog, REG_X0, REG_X0, 0);
}
/**
* not
*
* not rd, rs1
*
* rd = ~rs1
*/
static inline int
rv32_not(rv32_prog_t* prog, rv_reg_t rd, rv_reg_t rs1) {
return rv32_xori(prog, rd, rs1, ~0);
}
/**
* return
*
* ret
*
* PC = ra
*/
static inline int
rv32_ret(rv32_prog_t* prog) {
return rv32_jalr(prog, REG_X0, REG_RA, 0);
}
/**
* set equal zero
*
* seqz rd, rs1
*
* rd = (rs1 == 0) ? 1 : 0
*/
static inline int
rv32_seqz(rv32_prog_t* prog, rv_reg_t rd, rv_reg_t rs1) {
// TODO
return rv32_sltiu(prog, rd, rs1, 1);
}
/**
* set not equal zero
*
* snez rd, rs1
*
* rd = (rs1 != 0) ? 1 : 0
*/
static inline int
rv32_snez(rv32_prog_t* prog, rv_reg_t rd, rv_reg_t rs1) {
// TODO
return rv32_sltu(prog, rd, rs1, REG_X0);
}
/* instruction of rotated (using label) */
static inline int
rv32_bne_l(rv32_prog_t* prog, rv_reg_t rs1, rv_reg_t rs2, symasm_entry_t* label) {
rv32_instr_t instr = {
.instr_type = RV_BNE,
.rd = REG_NULL,
.rs1 = rs1,
.rs2 = rs2,
.imm = 0,
};
return emit_rv32_instr(prog, &instr, EMIT_PUSH_BACK, label);
}
static inline int
rv32_jal_l(rv32_prog_t* prog, rv_reg_t rd, symasm_entry_t* label) {
rv32_instr_t instr = {
.instr_type = RV_JAL,
.rd = rd,
.rs1 = REG_NULL,
.rs2 = REG_NULL,
.imm = 0,
};
return emit_rv32_instr(prog, &instr, EMIT_PUSH_BACK, label);
}
static inline int
rv32_call_l(rv32_prog_t* prog, symasm_entry_t* label) {
rv32_instr_t instr;
instr.instr_type = RV_JAL;
instr.rd = REG_NULL;
instr.rs1 = REG_NULL;
instr.rs2 = REG_NULL;
instr.imm = 0;
int ret = rv32_auipc(prog, REG_RA, REG_X0);
instr.instr_type = RV_JALR;
instr.rd = REG_RA;
instr.rs1 = REG_RA;
instr.rs2 = REG_NULL;
instr.imm = 4;
emit_rv32_instr(prog, &instr, EMIT_PUSH_BACK, label);
return ret;
}
/* append label */
static inline int
rv32_append_label(rv32_prog_t* prog, symasm_entry_t* label, u32_t offset) {
// prog->symtab
symtab_asm_put(&prog->symtab, label, offset);
return 0;
}
#endif