#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