940 lines
18 KiB
C
940 lines
18 KiB
C
#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
|