#ifndef __SMCC_RISCV32_INSTR_H__ #define __SMCC_RISCV32_INSTR_H__ #include "riscv32_mcode.h" #include "riscv32_def.h" #define EMIT_PUSH_BACK (-1) /* base integer instruction */ /** * ADD * * add rd, rs1, rs2 * * rd = rs1 + rs2 */ static inline int rv32_add(mcode_rv32_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(mcode_rv32_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(mcode_rv32_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(mcode_rv32_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(mcode_rv32_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(mcode_rv32_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(mcode_rv32_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(mcode_rv32_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(mcode_rv32_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(mcode_rv32_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(mcode_rv32_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(mcode_rv32_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(mcode_rv32_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(mcode_rv32_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(mcode_rv32_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(mcode_rv32_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(mcode_rv32_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(mcode_rv32_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(mcode_rv32_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(mcode_rv32_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(mcode_rv32_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(mcode_rv32_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(mcode_rv32_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(mcode_rv32_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(mcode_rv32_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(mcode_rv32_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(mcode_rv32_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(mcode_rv32_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(mcode_rv32_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(mcode_rv32_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(mcode_rv32_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(mcode_rv32_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(mcode_rv32_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(mcode_rv32_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(mcode_rv32_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(mcode_rv32_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(mcode_rv32_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(mcode_rv32_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(mcode_rv32_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(mcode_rv32_t* prog, u32_t imm) { // TODO return rv32_jal(prog, REG_X0, imm); } /** * jump register * * jr rs1 * * PC = rs1 */ static inline int rv32_jr(mcode_rv32_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(mcode_rv32_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(mcode_rv32_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(mcode_rv32_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(mcode_rv32_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(mcode_rv32_t* prog) { return rv32_addi(prog, REG_X0, REG_X0, 0); } /** * not * * not rd, rs1 * * rd = ~rs1 */ static inline int rv32_not(mcode_rv32_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(mcode_rv32_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(mcode_rv32_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(mcode_rv32_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(mcode_rv32_t* prog, rv_reg_t rs1, rv_reg_t rs2, void* 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(mcode_rv32_t* prog, rv_reg_t rd, void* 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(mcode_rv32_t* prog, void* 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; } #endif