stable
This commit is contained in:
18
assembler/riscv32/Makefile
Normal file
18
assembler/riscv32/Makefile
Normal file
@ -0,0 +1,18 @@
|
||||
CC = gcc
|
||||
AR = ar
|
||||
CFLAGS = -g -Wall -I../..
|
||||
|
||||
# 自动收集所有子模块源文件
|
||||
EXCLUDE = test*.c
|
||||
|
||||
SRCS = $(filter-out $(EXCLUDE), $(wildcard *.c))
|
||||
OBJS = $(SRCS:.c=.o)
|
||||
|
||||
libasm.a: $(OBJS)
|
||||
$(AR) rcs $@ $^
|
||||
|
||||
%.o: %.c
|
||||
$(CC) $(CFLAGS) -c -o $@ $<
|
||||
|
||||
clean:
|
||||
rm -f libasm.a $(OBJS)
|
204
assembler/riscv32/riscv32.c
Normal file
204
assembler/riscv32/riscv32.c
Normal file
@ -0,0 +1,204 @@
|
||||
#include "riscv32.h"
|
||||
#include "riscv32_def.h"
|
||||
#include <lib/core.h>
|
||||
|
||||
static const rv32_instr_t rv32_instrs[] = {
|
||||
[RV_LUI] = {RV32_I_EXT, RV_U_TYPE, RV_LUI, "lui", 0x37},
|
||||
[RV_AUIPC] = {RV32_I_EXT, RV_U_TYPE, RV_AUIPC, "auipc", 0x17},
|
||||
|
||||
[RV_JAL] = {RV32_I_EXT, RV_J_TYPE, RV_JAL, "jal", 0x6F},
|
||||
|
||||
[RV_JALR] = {RV32_I_EXT, RV_I_TYPE, RV_JALR, "jalr", 0x67},
|
||||
|
||||
[RV_LB] = {RV32_I_EXT, RV_I_TYPE, RV_LB, "lb", 0x03 | RV_F3(0x0)},
|
||||
[RV_LH] = {RV32_I_EXT, RV_I_TYPE, RV_LH, "lh", 0x03 | RV_F3(0x1)},
|
||||
[RV_LW] = {RV32_I_EXT, RV_I_TYPE, RV_LW, "lw", 0x03 | RV_F3(0x2)},
|
||||
[RV_LBU] = {RV32_I_EXT, RV_I_TYPE, RV_LBU, "lbu", 0x03 | RV_F3(0x4)},
|
||||
[RV_LHU] = {RV32_I_EXT, RV_I_TYPE, RV_LHU, "lhu", 0x03 | RV_F3(0x5)},
|
||||
|
||||
[RV_ADDI] = {RV32_I_EXT, RV_I_TYPE, RV_ADDI, "addi", 0x13 | RV_F3(0x0)},
|
||||
[RV_SLTI] = {RV32_I_EXT, RV_I_TYPE, RV_SLTI, "slti", 0x13 | RV_F3(0x2)},
|
||||
[RV_SLTIU] = {RV32_I_EXT, RV_I_TYPE, RV_SLTIU, "sltiu", 0x13 | RV_F3(0x3)},
|
||||
[RV_XORI] = {RV32_I_EXT, RV_I_TYPE, RV_XORI, "xori", 0x13 | RV_F3(0x4)},
|
||||
[RV_ORI] = {RV32_I_EXT, RV_I_TYPE, RV_ORI, "ori", 0x13 | RV_F3(0x6)},
|
||||
[RV_ANDI] = {RV32_I_EXT, RV_I_TYPE, RV_ANDI, "andi", 0x13 | RV_F3(0x7)},
|
||||
|
||||
[RV_SLLI] = {RV32_I_EXT, RV_I_TYPE, RV_SLLI, "slli", 0x13 | RV_F3(0x0)},
|
||||
[RV_SRLI] = {RV32_I_EXT, RV_I_TYPE, RV_SRLI, "srli", 0x13 | RV_F3(0x5)},
|
||||
[RV_SRAI] = {RV32_I_EXT, RV_I_TYPE, RV_SRAI, "srai", 0x13 | RV_F3(0x5)},
|
||||
|
||||
[RV_BEQ] = {RV32_I_EXT, RV_B_TYPE, RV_BEQ, "beq", 0x63 | RV_F3(0x0)},
|
||||
[RV_BNE] = {RV32_I_EXT, RV_B_TYPE, RV_BNE, "bne", 0x63 | RV_F3(0x1)},
|
||||
[RV_BLT] = {RV32_I_EXT, RV_B_TYPE, RV_BLT, "blt", 0x63 | RV_F3(0x4)},
|
||||
[RV_BGE] = {RV32_I_EXT, RV_B_TYPE, RV_BGE, "bge", 0x63 | RV_F3(0x5)},
|
||||
[RV_BLTU] = {RV32_I_EXT, RV_B_TYPE, RV_BLTU, "bltu", 0x63 | RV_F3(0x6)},
|
||||
[RV_BGEU] = {RV32_I_EXT, RV_B_TYPE, RV_BGEU, "bgeu", 0x63 | RV_F3(0x7)},
|
||||
|
||||
[RV_SB] = {RV32_I_EXT, RV_S_TYPE, RV_SB, "sb", 0x23 | RV_F3(0x0)},
|
||||
[RV_SH] = {RV32_I_EXT, RV_S_TYPE, RV_SH, "sh", 0x23 | RV_F3(0x1)},
|
||||
[RV_SW] = {RV32_I_EXT, RV_S_TYPE, RV_SW, "sw", 0x23 | RV_F3(0x2)},
|
||||
|
||||
[RV_ADD] = {RV32_I_EXT, RV_R_TYPE, RV_ADD, "add", 0x33 | RV_F3(0x0) | RV_F7(0x00)},
|
||||
[RV_SUB] = {RV32_I_EXT, RV_R_TYPE, RV_SUB, "sub", 0x33 | RV_F3(0x0) | RV_F7(0x20)},
|
||||
[RV_SLL] = {RV32_I_EXT, RV_R_TYPE, RV_SLL, "sll", 0x33 | RV_F3(0x1) | RV_F7(0x00)},
|
||||
[RV_SLT] = {RV32_I_EXT, RV_R_TYPE, RV_SLT, "slt", 0x33 | RV_F3(0x2) | RV_F7(0x00)},
|
||||
[RV_SLTU] = {RV32_I_EXT, RV_R_TYPE, RV_SLTU, "sltu", 0x33 | RV_F3(0x3) | RV_F7(0x00)},
|
||||
[RV_XOR] = {RV32_I_EXT, RV_R_TYPE, RV_XOR, "xor", 0x33 | RV_F3(0x4) | RV_F7(0x00)},
|
||||
[RV_SRL] = {RV32_I_EXT, RV_R_TYPE, RV_SRL, "srl", 0x33 | RV_F3(0x5) | RV_F7(0x00)},
|
||||
[RV_SRA] = {RV32_I_EXT, RV_R_TYPE, RV_SRA, "sra", 0x33 | RV_F3(0x5) | RV_F7(0x20)},
|
||||
[RV_OR] = {RV32_I_EXT, RV_R_TYPE, RV_OR, "or", 0x33 | RV_F3(0x6) | RV_F7(0x00)},
|
||||
[RV_AND] = {RV32_I_EXT, RV_R_TYPE, RV_AND, "and", 0x33 | RV_F3(0x7) | RV_F7(0x00)},
|
||||
|
||||
// {RV32_I_EXT, RV_I_TYPE, RV_FENCE, "fence", 0x0F},
|
||||
[RV_ECALL] = {RV32_I_EXT, RV_I_TYPE, RV_ECALL, "ecall", 0x73},
|
||||
[RV_EBREAK] = {RV32_I_EXT, RV_I_TYPE, RV_EBREAK,"ebreak",0x100073},
|
||||
|
||||
[RV_MUL] = {RV32_M_EXT, RV_R_TYPE, RV_MUL, "mul", 0x33 | RV_F3(0x0) | RV_F7(0x01)},
|
||||
[RV_DIV] = {RV32_M_EXT, RV_R_TYPE, RV_DIV, "div", 0x33 | RV_F3(0x0) | RV_F7(0x05)},
|
||||
[RV_REM] = {RV32_M_EXT, RV_R_TYPE, RV_REM, "rem", 0x33 | RV_F3(0x0) | RV_F7(0x07)},
|
||||
};
|
||||
|
||||
void init_rv32_prog(rv32_prog_t* prog, strpool_t* strpool) {
|
||||
if (strpool == NULL) {
|
||||
prog->strpool = salloc_alloc(sizeof(strpool_t));
|
||||
init_strpool(prog->strpool);
|
||||
} else {
|
||||
prog->strpool = strpool;
|
||||
}
|
||||
prog->data_base_address = 0;
|
||||
vector_init(prog->data);
|
||||
prog->text_base_address = 0;
|
||||
vector_init(prog->text);
|
||||
vector_init(prog->rinstrs);
|
||||
init_symtab_asm(&prog->symtab);
|
||||
}
|
||||
|
||||
static inline int valid_reg(rv_reg_t reg) {
|
||||
// return reg >= REG_X0 && reg <= REG_X31;
|
||||
return !(reg & ~0x1F);
|
||||
}
|
||||
|
||||
// static int valid_instr
|
||||
// (rv_instr_type_t type, u32_t imm, rv_reg_t rs1, rv_reg_t rs2, rv_reg_t rd) {
|
||||
// Assert(type >= 0 && type < RV_INSTR_TYPE_COUNT);
|
||||
// rv_fmt_t fmt = rv32_instrs[type].format;
|
||||
// switch (fmt) {
|
||||
// case RV_R_TYPE:
|
||||
// if (valid_reg(rd) && valid_reg(rs1) && valid_reg(rs2)) {
|
||||
// return 1;
|
||||
// }
|
||||
// break;
|
||||
// case RV_I_TYPE:
|
||||
// if (valid_reg(rd) && valid_reg(rs1) && rs2 == 0 && (imm & ~0xFFF) == 0) {
|
||||
// return 1;
|
||||
// }
|
||||
// break;
|
||||
// case RV_S_TYPE:
|
||||
// if (rd == 0 && valid_reg(rs1) && valid_reg(rs2) && (imm & ~0xFFF) == 0) {
|
||||
// return 1;
|
||||
// }
|
||||
// break;
|
||||
// case RV_B_TYPE:
|
||||
// if (rd == 0 && valid_reg(rs1) && valid_reg(rs2) && (imm & ~(0xFFF << 1)) == 0) {
|
||||
// return 1;
|
||||
// }
|
||||
// break;
|
||||
// case RV_U_TYPE:
|
||||
// if (valid_reg(rd) && rs1 == 0 && rs2 == 0 && (imm & ~(0xFFFFF << 12)) == 0) {
|
||||
// return 1;
|
||||
// }
|
||||
// break;
|
||||
// case RV_J_TYPE:
|
||||
// if (valid_reg(rd) && rs1 == 0 && rs2 == 0 && (imm & ~(0xFFFFF)) == 0) {
|
||||
// return 1;
|
||||
// }
|
||||
// break;
|
||||
// }
|
||||
// return 0;
|
||||
// }
|
||||
|
||||
int emit_rv32_instr(rv32_prog_t* prog, rv32_instr_t *instr, u32_t idx, symasm_entry_t *target) {
|
||||
// TODO check out input data
|
||||
instr->extention = rv32_instrs[instr->instr_type].extention;
|
||||
instr->format = rv32_instrs[instr->instr_type].format;
|
||||
instr->instr_name = rv32_instrs[instr->instr_type].instr_name;
|
||||
instr->instr = rv32_instrs[instr->instr_type].instr;
|
||||
|
||||
switch (instr->format) {
|
||||
case RV_R_TYPE:
|
||||
instr->instr |= (instr->rd << 7) | (instr->rs1 << 15) | (instr->rs2 << 20);
|
||||
break;
|
||||
case RV_I_TYPE:
|
||||
instr->instr |= (instr->rd << 7) | (instr->rs1 << 15) | (instr->imm << 20);
|
||||
break;
|
||||
case RV_S_TYPE:
|
||||
instr->instr |= (instr->rs1 << 15) | (instr->rs2 << 20) |
|
||||
((instr->imm & 0x1F) << 7) | ((instr->imm & 0xFE0) << 20);
|
||||
break;
|
||||
case RV_B_TYPE:
|
||||
instr->instr |= (instr->rs1 << 15) | (instr->rs2 << 20) |
|
||||
(((instr->imm) >> 12) & 0x1) << 31 | /* imm[12:12] -> instr[31:31] */ \
|
||||
(((instr->imm) >> 5) & 0x3F) << 25 | /* imm[10:5] -> instr[30:25] */ \
|
||||
(((instr->imm) >> 1) & 0xF) << 8 | /* imm[4:1] -> instr[11:8] */ \
|
||||
(((instr->imm) >> 11) & 0x1) << 7; /* imm[11:11] -> instr[7:7] */
|
||||
break;
|
||||
case RV_U_TYPE:
|
||||
instr->instr |= (instr->rd << 7) | (instr->imm & 0xFFFFF000);
|
||||
break;
|
||||
case RV_J_TYPE:
|
||||
instr->instr |= (instr->rd << 7) |
|
||||
(((instr->imm) >> 20) & 0x1) << 31 | /* imm[20:20] -> instr[31:31] */ \
|
||||
(((instr->imm) >> 1) & 0x3FF)<< 21 | /* imm[10:1] -> instr[30:21] */ \
|
||||
(((instr->imm) >> 11) & 0x1) << 20 | /* imm[11:11] -> instr[20:20] */ \
|
||||
(((instr->imm) >> 12) & 0xFF) << 12; /* imm[19:12] -> instr[19:12] */
|
||||
break;
|
||||
default:
|
||||
Panic("Invalid instruction format");
|
||||
}
|
||||
|
||||
if (target != NULL) {
|
||||
Assert(idx == -1);
|
||||
rotated_instr_t rinstr = {
|
||||
.instr = *instr,
|
||||
.address = prog->text.size,
|
||||
.target = *target,
|
||||
};
|
||||
vector_push(prog->rinstrs, rinstr);
|
||||
// GOTO idx == -1
|
||||
}
|
||||
|
||||
if (idx == -1) {
|
||||
vector_push(prog->text, instr->instr);
|
||||
return idx;
|
||||
} else if (idx >= 0 && idx < prog->text.size) {
|
||||
vector_at(prog->text, idx) = instr->instr;
|
||||
return prog->text.size - 1;
|
||||
} else {
|
||||
Panic("Invalid instruction index");
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
// int gen_rv32_instr(rv32_prog_t* prog) {
|
||||
// vector_header(rinstrs_g, rotated_instr_t);
|
||||
// vector_init(rinstrs_g);
|
||||
// for (int i = 0; i < prog->rinstrs.size; i++) {
|
||||
// rotated_instr_t* rinstr = &prog->rinstrs.data[i];
|
||||
// // FIXME address typedef needed
|
||||
// u32_t* ptr = symtab_get(&prog->symtab, &rinstr->target);
|
||||
// if (ptr == NULL) {
|
||||
// vector_push(rinstrs_g, *rinstr);
|
||||
// continue;
|
||||
// }
|
||||
// u32_t target_address = *ptr;
|
||||
|
||||
// rv32_instr_t *back_instr = &rinstr->instr;
|
||||
|
||||
// // FIXME 重定向类别
|
||||
// back_instr->imm = target_address;
|
||||
|
||||
// emit_rv32_instr(prog, back_instr, target_address, NULL);
|
||||
// }
|
||||
// vector_free(prog->rinstrs);
|
||||
// prog->rinstrs.cap = rinstrs_g.cap;
|
||||
// }
|
30
assembler/riscv32/riscv32.h
Normal file
30
assembler/riscv32/riscv32.h
Normal file
@ -0,0 +1,30 @@
|
||||
#ifndef __SMCC_ASM_RISCV32_H__
|
||||
#define __SMCC_ASM_RISCV32_H__
|
||||
|
||||
#include <lib/core.h>
|
||||
#include <lib/utils/ds/vector.h>
|
||||
#include <lib/utils/symtab/symtab.h>
|
||||
#include "riscv32_def.h"
|
||||
#include "symtab_asm.h"
|
||||
|
||||
typedef struct rotated_instr {
|
||||
u32_t address;
|
||||
symasm_entry_t target;
|
||||
rv32_instr_t instr;
|
||||
} rotated_instr_t;
|
||||
|
||||
typedef struct rv32_prog {
|
||||
strpool_t* strpool;
|
||||
symtab_asm_t symtab;
|
||||
u32_t text_base_address;
|
||||
vector_header(text, u32_t);
|
||||
u32_t data_base_address;
|
||||
vector_header(data, iptr_t);
|
||||
vector_header(rinstrs, rotated_instr_t);
|
||||
} rv32_prog_t;
|
||||
|
||||
void init_rv32_prog(rv32_prog_t* prog, strpool_t* strpool);
|
||||
int emit_rv32_instr(rv32_prog_t* prog, rv32_instr_t *instr, u32_t idx, symasm_entry_t *target);
|
||||
// int gen_rv32_instr(rv32_prog_t* prog);
|
||||
|
||||
#endif
|
119
assembler/riscv32/riscv32_def.h
Normal file
119
assembler/riscv32/riscv32_def.h
Normal file
@ -0,0 +1,119 @@
|
||||
#ifndef __SMCC_RISCV32_DEF_H__
|
||||
#define __SMCC_RISCV32_DEF_H__
|
||||
|
||||
#include <lib/core.h>
|
||||
|
||||
typedef enum rv_ext {
|
||||
RV32_I_EXT,
|
||||
RV32_M_EXT,
|
||||
} rv_ext_t;
|
||||
|
||||
typedef enum rv_fmt {
|
||||
RV_R_TYPE,
|
||||
RV_I_TYPE,
|
||||
RV_S_TYPE,
|
||||
RV_B_TYPE,
|
||||
RV_U_TYPE,
|
||||
RV_J_TYPE,
|
||||
} rv_fmt_t;
|
||||
|
||||
typedef enum rv_instr_type {
|
||||
/* U type */
|
||||
RV_AUIPC,
|
||||
RV_LUI,
|
||||
/* J type */
|
||||
RV_JAL,
|
||||
/* I type */
|
||||
RV_JALR,
|
||||
// Load
|
||||
RV_LB,
|
||||
RV_LH,
|
||||
RV_LW,
|
||||
RV_LBU,
|
||||
RV_LHU,
|
||||
// Imm arithmetic
|
||||
RV_ADDI,
|
||||
RV_SLTI,
|
||||
RV_SLTIU,
|
||||
RV_XORI,
|
||||
RV_ORI,
|
||||
RV_ANDI,
|
||||
// Imm shift
|
||||
RV_SLLI,
|
||||
RV_SRLI,
|
||||
RV_SRAI,
|
||||
/* B type */
|
||||
RV_BEQ,
|
||||
RV_BNE,
|
||||
RV_BLT,
|
||||
RV_BGE,
|
||||
RV_BLTU,
|
||||
RV_BGEU,
|
||||
/* S type */
|
||||
RV_SB,
|
||||
RV_SH,
|
||||
RV_SW,
|
||||
/* R type */
|
||||
RV_ADD,
|
||||
RV_SUB,
|
||||
RV_SLL,
|
||||
RV_SLT,
|
||||
RV_SLTU,
|
||||
RV_XOR,
|
||||
RV_SRL,
|
||||
RV_SRA,
|
||||
RV_OR,
|
||||
RV_AND,
|
||||
/* I type (system) */
|
||||
RV_FENCE,
|
||||
RV_ECALL,
|
||||
RV_EBREAK,
|
||||
|
||||
/* M-Extention */
|
||||
RV_MUL,
|
||||
RV_DIV,
|
||||
RV_REM,
|
||||
// RV_MULH,
|
||||
// RV_DIVU,
|
||||
// RV_REMU,
|
||||
// RV_MULHSU,
|
||||
// RV_MULHU,
|
||||
// RV_DIVU,
|
||||
// RV_REMU,
|
||||
// RV_MULHSU,
|
||||
// RV_MULHU,
|
||||
RV_INSTR_TYPE_COUNT,
|
||||
} rv_instr_type_t;
|
||||
|
||||
typedef enum rv_reg {
|
||||
REG_X0, REG_X1, REG_X2, REG_X3, REG_X4, REG_X5, REG_X6, REG_X7,
|
||||
REG_X8, REG_X9, REG_X10, REG_X11, REG_X12, REG_X13, REG_X14, REG_X15,
|
||||
REG_X16, REG_X17, REG_X18, REG_X19, REG_X20, REG_X21, REG_X22, REG_X23,
|
||||
REG_X24, REG_X25, REG_X26, REG_X27, REG_X28, REG_X29, REG_X30, REG_X31,
|
||||
REG_ZERO = REG_X0, REG_RA = REG_X1, REG_SP = REG_X2, REG_GP = REG_X3,
|
||||
REG_TP = REG_X4, REG_T0 = REG_X5, REG_T1 = REG_X6, REG_T2 = REG_X7,
|
||||
REG_S0 = REG_X8, REG_S1 = REG_X9, REG_A0 = REG_X10, REG_A1 = REG_X11,
|
||||
REG_A2 = REG_X12, REG_A3 = REG_X13, REG_A4 = REG_X14, REG_A5 = REG_X15,
|
||||
REG_A6 = REG_X16, REG_A7 = REG_X17, REG_S2 = REG_X18, REG_S3 = REG_X19,
|
||||
REG_S4 = REG_X20, REG_S5 = REG_X21, REG_S6 = REG_X22, REG_S7 = REG_X23,
|
||||
REG_S8 = REG_X24, REG_S9 = REG_X25, REG_S10 = REG_X26, REG_S11 = REG_X27,
|
||||
REG_T3 = REG_X28, REG_T4 = REG_X29, REG_T5 = REG_X30, REG_T6 = REG_X31,
|
||||
REG_NULL = 0,
|
||||
} rv_reg_t;
|
||||
|
||||
#define RV_F3(f3) (f3 << 12)
|
||||
#define RV_F7(f7) (f7 << 25)
|
||||
|
||||
typedef struct rv32_instr {
|
||||
rv_ext_t extention;
|
||||
rv_fmt_t format;
|
||||
rv_instr_type_t instr_type;
|
||||
const char* instr_name;
|
||||
u32_t instr;
|
||||
u32_t imm;
|
||||
rv_reg_t rd;
|
||||
rv_reg_t rs1;
|
||||
rv_reg_t rs2;
|
||||
} rv32_instr_t;
|
||||
|
||||
#endif
|
948
assembler/riscv32/riscv32_instr.h
Normal file
948
assembler/riscv32/riscv32_instr.h
Normal file
@ -0,0 +1,948 @@
|
||||
#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
|
40
assembler/riscv32/symtab_asm.c
Normal file
40
assembler/riscv32/symtab_asm.c
Normal file
@ -0,0 +1,40 @@
|
||||
#include "symtab_asm.h"
|
||||
|
||||
static u32_t hash_func(const symasm_entry_t* key) {
|
||||
return rt_strhash(key->name);
|
||||
}
|
||||
|
||||
static int cmp_func(const symasm_entry_t* k1, const symasm_entry_t* k2) {
|
||||
return rt_strcmp(k1->name, k2->name);
|
||||
}
|
||||
|
||||
void init_symtab_asm(symtab_asm_t* symtab) {
|
||||
init_hashtable(&symtab->symtab);
|
||||
symtab->symtab.hash_func = (u32_t(*)(const void*))hash_func;
|
||||
symtab->symtab.key_cmp = (int(*)(const void*, const void*))cmp_func;
|
||||
}
|
||||
|
||||
void symtab_asm_put(symtab_asm_t* symtab, symasm_entry_t* _entry, u32_t address) {
|
||||
// FIXME maybe memory leak
|
||||
u32_t* addr = salloc_alloc(sizeof(u32_t));
|
||||
if (addr == NULL) {
|
||||
LOG_FATAL("salloc_alloc failure");
|
||||
}
|
||||
symasm_entry_t* entry = salloc_alloc(sizeof(symasm_entry_t));
|
||||
if (entry == NULL) LOG_FATAL("malloc failure");
|
||||
*entry = *_entry;
|
||||
*addr = address;
|
||||
void* ret = hashtable_set(&symtab->symtab, entry, addr);
|
||||
if (ret != NULL) {
|
||||
LOG_ERROR("Symbol %s already exists", entry->name);
|
||||
}
|
||||
}
|
||||
|
||||
u32_t* symtab_asm_get(symtab_asm_t* symtab, symasm_entry_t* entry) {
|
||||
u32_t* addr = hashtable_get(&symtab->symtab, entry);
|
||||
return addr;
|
||||
}
|
||||
|
||||
void symtab_asm_destroy(symtab_asm_t* symtab) {
|
||||
hashtable_destory(&symtab->symtab);
|
||||
}
|
26
assembler/riscv32/symtab_asm.h
Normal file
26
assembler/riscv32/symtab_asm.h
Normal file
@ -0,0 +1,26 @@
|
||||
#ifndef __SMCC_SYMTAB_ASM_H__
|
||||
#define __SMCC_SYMTAB_ASM_H__
|
||||
|
||||
#include <lib/core.h>
|
||||
#include <lib/utils/ds/hashtable.h>
|
||||
|
||||
typedef enum symasm_attr {
|
||||
GLOBAL,
|
||||
LOCAL,
|
||||
} symasm_attr_t;
|
||||
|
||||
typedef struct symasm_entry {
|
||||
const char* name;
|
||||
symasm_attr_t attr;
|
||||
} symasm_entry_t;
|
||||
|
||||
typedef struct symtab_asm {
|
||||
hash_table_t symtab;
|
||||
} symtab_asm_t;
|
||||
|
||||
void init_symtab_asm(symtab_asm_t* symtab);
|
||||
void symtab_asm_put(symtab_asm_t* symtab, symasm_entry_t* entry, u32_t address);
|
||||
u32_t* symtab_asm_get(symtab_asm_t* symtab, symasm_entry_t* entry);
|
||||
void symtab_asm_destroy(symtab_asm_t* symtab);
|
||||
|
||||
#endif
|
Reference in New Issue
Block a user