Skip to content

Commit

Permalink
support of nifs
Browse files Browse the repository at this point in the history
  • Loading branch information
fritzthekid committed Apr 19, 2024
1 parent 89465dd commit 8ea7fee
Show file tree
Hide file tree
Showing 10 changed files with 382 additions and 2 deletions.
7 changes: 6 additions & 1 deletion csrc/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,20 @@ SRCS = $(wildcard *.c)
INCS = $(wildcard include/*.h)
ASDIR=../_build/obj
ASFILES=$(patsubst %.c,$(ASDIR)/%.s,$(SRCS))
OBJFILES=$(ASDIR)/test2.o
# $(patsubst %.c,$(ASDIR)/%.o,$(SRCS))

all: $(ASFILES)
all: $(ASFILES) $(OBJFILES)

INCLUDES= -Iinclude
CCOPTIONS= -g -O2 -march=rv32imac -mabi=ilp32

$(ASDIR)/%.s: %.c ${INCS} Makefile
$(CC) -S ${CCOPTIONS} ${INCLUDES} -o $@ $<

$(ASDIR)/%.o: %.c ${INCS} Makefile
$(CC) -c ${CCOPTIONS} ${INCLUDES} -DWITHMAIN -o $@ $<

main: main.c test2.c
gcc -o main -D'__NOTRISCV__' main.c test2.c

3 changes: 3 additions & 0 deletions csrc/include/stdlib.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
#define __STDLIB__H

float atof(char *);

#ifndef WITHMAIN
int32_t __attribute__ ((noinline)) rvs_strtol_extern(char *);
int32_t __attribute__ ((noinline)) strtol(char *str) {
int32_t ret;
Expand All @@ -17,6 +19,7 @@ int32_t __attribute__ ((noinline)) strtol(char *str) {
asm ( "\n\t" );
return ret;
}
#endif

static inline int32_t atoi(char * arg) {
return strtol(arg);
Expand Down
2 changes: 2 additions & 0 deletions csrc/test2.c
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
#include <stdint-gcc.h>
#include <stdlib.h>

#ifndef WITHMAIN
#include "__startup__.h"
#endif

extern int32_t buffer[];

Expand Down
1 change: 0 additions & 1 deletion csrc/test5.c
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,5 @@ int32_t main(int32_t argc, char **argv) {
int32_t start = rvs_itoa(strtol(argv[1]),&buffer[100],9);
//rvsstrcpy(&buffer[len],&buffer[100+start]);
rvs_sendmessage(&buffer[100+start],rvsstrlen(&buffer[100+start]));
rvs_sendmessage(argv[2],rvsstrlen(argv[2]));
return len;
}
Binary file added docs/instruction_set_rv_i.pdf
Binary file not shown.
3 changes: 3 additions & 0 deletions docs/links.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,4 +44,7 @@ Here the best thing is how he/she spawns a local function.

[RISC-V Assembler Reference](https://michaeljclark.github.io/asm.html)

opcodes (bitgenau)
[RISC-V Reference](https://www.cs.sfu.ca/~ashriram/Courses/CS295/assets/notebooks/RISCV/RISCV_CARD.pdf)


287 changes: 287 additions & 0 deletions nifs/rvsops.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,287 @@
/*
* A minimal RISC-V RV32I dissassembler
* source: github.com:andportnoy/riscv-disassembler
* under: MIT License
*/

#include <erl_nif.h>
#include "rvsops.h"

enum das_format {R, I, S, B, U, J};

struct {
u8 opcode; /* 7-bit */
enum das_format fmt;
} opcodefmt[] = {
{0x37, U},
{0x17, U},
{0x6f, J},
{0x67, I},
{0x63, B},
{0x03, I},
{0x23, S},
{0x13, I},
{0x33, R},
{0x0f, I},
{0x73, I},
};

union encoding {
u32 insn;
struct { /* generic */
u32 opcode :7;
u32 rd :5;
u32 funct3 :3;
u32 rs1 :5;
u32 rs2 :5;
u32 funct7 :7;
};
struct {
u32 opcode :7;
u32 rd :5;
u32 funct3 :3;
u32 rs1 :5;
u32 rs2 :5;
u32 funct7 :7;
} r;
struct {
u32 opcode :7;
u32 rd :5;
u32 funct3 :3;
u32 rs1 :5;
s32 i11_0 :12; /* sign extension */
} i;
struct {
u32 opcode :7;
u32 i4_0 :5;
u32 funct3 :3;
u32 rs1 :5;
u32 rs2 :5;
s32 i11_5 :7; /* sign extension */
} s;
struct {
u32 opcode :7;
u32 i11 :1;
u32 i4_1 :4;
u32 funct3 :3;
u32 rs1 :5;
u32 rs2 :5;
u32 i10_5 :6;
s32 i12 :1; /* sign extension */
} b;
struct {
u32 opcode :7;
u32 rd :5;
u32 i31_12 :20;
} u;
struct {
u32 opcode :7;
u32 rd :5;
u32 i19_12 :8;
u32 i11 :1;
u32 i10_1 :10;
s32 i20 :1; /* sign extension */
} j;
};

int das_format(u8 opcode) {
#ifdef DEBUG
printf("%d\r\n",__LINE__);
#endif
for (int i=0, n=sizeof opcodefmt/sizeof opcodefmt[0]; i<n; ++i)
if (opcode == opcodefmt[i].opcode)
return opcodefmt[i].fmt;
return -1;
}

char *name(u32 insn) {
#ifdef DEBUG
printf("%d\r\n",__LINE__);
#endif
union encoding e = {insn};
switch (das_format(e.opcode)) {
case R: switch (e.funct3) {
case 0: return e.funct7? "sub": "add";
case 1: return "sll";
case 2: return "slt";
case 3: return "sltu";
case 4: return "xor";
case 5: return e.funct7? "sra": "srl";
case 6: return "or";
case 7: return "and";
} break;
case I: switch(e.opcode) {
case 0x67: return "jalr";
case 0x03: switch (e.funct3) {
case 0: return "lb";
case 1: return "lh";
case 2: return "lw";
case 4: return "lbu";
case 5: return "lhu";
} break;
case 0x13: switch (e.funct3) {
case 0: return "addi";
case 1: return "slli";
case 2: return "slti";
case 3: return "sltiu";
case 4: return "xori";
case 5: return e.funct7? "srai": "srli";
case 6: return "ori";
case 7: return "andi";
} break;
case 0x0f: switch (e.funct3) {
case 0: return "fence";
case 1: return "fence.i";
} break;
case 0x73: switch (e.funct3) {
case 0: return e.rs2? "ebreak": "ecall";
case 1: return "csrrw";
case 2: return "csrrs";
case 3: return "csrrc";
case 5: return "csrrwi";
case 6: return "csrrsi";
case 7: return "csrrci";
} break;
} break;
case S: switch(e.funct3) {
case 0: return "sb";
case 1: return "sh";
case 2: return "sw";
} break;
case B: switch(e.funct3) {
case 0: return "beq";
case 1: return "bne";
case 4: return "blt";
case 5: return "bge";
case 6: return "bltu";
case 7: return "bgeu";
} break;
case U: switch(e.opcode) {
case 0x37: return "lui";
case 0x17: return "auipc";
} break;
case J: return "jal";
}

return NULL;
}

char *op0(u32 insn) {
#ifdef DEBUG
printf("%d\r\n",__LINE__);
#endif
union encoding e = {insn};
char *name = calloc(16+1, sizeof *name);
switch (das_format(e.opcode)) {
case R:
case I: sprintf(name, "x%d", e.rd); break;
case S: sprintf(name, "x%d", e.rs2); break;
case B: sprintf(name, "x%d", e.rs1); break;
case U:
case J: sprintf(name, "x%d", e.rd); break;
}
return name;
}

char *op1(u32 insn) {
#ifdef DEBUG
printf("%d\r\n",__LINE__);
#endif
union encoding e = {insn};
char *name = calloc(16+1, sizeof *name);
switch (das_format(e.opcode)) {
case R:
case I:
case S: sprintf(name, "x%d", e.rs1); break;
case B: sprintf(name, "x%d", e.rs2); break;
case U: sprintf(name, "0x%x", e.u.i31_12); break;
case J: sprintf(name, "%d", (e.j.i20 <<20) |
(e.j.i19_12 <<12) |
(e.j.i11 <<11) |
(e.j.i10_1 << 1)); break;
}
return name;
}

char *op2(u32 insn) {
#ifdef DEBUG
printf("%d\r\n",__LINE__);
#endif
union encoding e = {insn};
char *name = calloc(16+1, sizeof *name);
switch (das_format(e.opcode)) {
case R: sprintf(name, "x%d", e.rs2); break;
case I: sprintf(name, "%d", e.i.i11_0); break;
case S: sprintf(name, "%d", (e.s.i11_5<<5) | e.s.i4_0); break;
case B: sprintf(name, "%d", (e.b.i12 <<12) |
(e.b.i11 <<11) |
(e.b.i10_5 << 5) |
(e.b.i4_1 << 1)); break;
case U: break;
case J: break;
}
if ( strlen(name) == 0 ) {
return NULL;
}
return name;
}

/*
int main(int argc, char **argv) {
struct progbits pb = loadbits(argv[1]);
for (u32 i=0, n=pb.size, insn=pb.data[i]; i<n; ++i, insn=pb.data[i])
printf("%4x: %08x %-8s %3s %3s %3s\n",
4*i, insn, name(insn), op0(insn), op1(insn), op2(insn));
}
*/

static ERL_NIF_TERM disassemble(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{
uint32_t insn;
uint32_t op;
#ifdef DEBUG
printf("%d\r\n",__LINE__);
#endif
int retval = enif_get_int(env, argv[0], &insn);
#ifdef DEBUG
printf("%d\r\n",__LINE__);
#endif
char *name_val = name(insn);
#ifdef DEBUG
printf("%d\r\n",__LINE__);
#endif
char *op0_val = op0(insn);
char *op1_val = op1(insn);
char *op2_val = op2(insn);
if ( name_val == NULL ) {
return enif_make_badarg(env);
} else if ( op0_val == NULL ) {
return enif_make_list(env,2,
enif_make_string(env, name_val, ERL_NIF_LATIN1)
);
} else if ( op1_val == NULL ) {
return enif_make_list(env,2,
enif_make_string(env, name_val, ERL_NIF_LATIN1),
enif_make_string(env, op0_val, ERL_NIF_LATIN1)
);
} else if ( op2_val == NULL ) {
return enif_make_list(env,3,
enif_make_string(env, name_val, ERL_NIF_LATIN1),
enif_make_string(env, op0_val, ERL_NIF_LATIN1),
enif_make_string(env, op1_val, ERL_NIF_LATIN1)
);
}
return enif_make_list(env,4,
enif_make_string(env, name_val, ERL_NIF_LATIN1),
enif_make_string(env, op0_val, ERL_NIF_LATIN1),
enif_make_string(env, op1_val, ERL_NIF_LATIN1),
enif_make_string(env, op2_val, ERL_NIF_LATIN1)
);
}

static ErlNifFunc nif_funcs[] =
{
{"disassemble", 1, disassemble}
};

ERL_NIF_INIT(rvsops,nif_funcs,NULL,NULL,NULL,NULL)
20 changes: 20 additions & 0 deletions nifs/rvsops.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <assert.h>

typedef uint8_t u8;
typedef uint16_t u16;
typedef uint32_t u32;
typedef uint64_t u64;

typedef int32_t s32;

/* stream of 32 bit fixed length instructions */
struct progbits {
u32 size;
u32 *data;
};

struct progbits loadbits(char *filename);
Loading

0 comments on commit 8ea7fee

Please sign in to comment.