Skip to content

Commit

Permalink
Bind I/O handlers during emulator initialization
Browse files Browse the repository at this point in the history
It is not required to give an application the opportunity to bind I/O
handlers because I/O handlers are rarely altered during the
creation of an emulator.

With this commit, the application can now build a emulator much more
easier by only taking the emulator's attribute (vm_attr_t)
into consideration.

In order to facilitate further integration with the RISC-V system
emulator (semu), I have included a TODO inside the I/O interface.

Related: sysprog21#310
  • Loading branch information
ChinYikMing committed Feb 25, 2024
1 parent 9154976 commit ff8a1ab
Show file tree
Hide file tree
Showing 3 changed files with 52 additions and 52 deletions.
47 changes: 1 addition & 46 deletions src/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -49,31 +49,6 @@ static bool opt_misaligned = false;
static bool opt_prof_data = false;
static char *prof_out_file;

#define MEMIO(op) on_mem_##op
#define IO_HANDLER_IMPL(type, op, RW) \
static IIF(RW)( \
/* W */ void MEMIO(op)(riscv_word_t addr, riscv_##type##_t data), \
/* R */ riscv_##type##_t MEMIO(op)(riscv_word_t addr)) \
{ \
IIF(RW) \
(memory_##op(addr, (uint8_t *) &data), return memory_##op(addr)); \
}

#define R 0
#define W 1

IO_HANDLER_IMPL(word, ifetch, R)
IO_HANDLER_IMPL(word, read_w, R)
IO_HANDLER_IMPL(half, read_s, R)
IO_HANDLER_IMPL(byte, read_b, R)

IO_HANDLER_IMPL(word, write_w, W)
IO_HANDLER_IMPL(half, write_s, W)
IO_HANDLER_IMPL(byte, write_b, W)

#undef R
#undef W

static void print_usage(const char *filename)
{
fprintf(stderr,
Expand Down Expand Up @@ -227,28 +202,8 @@ int main(int argc, char **args)
assert(attr.data.user);
attr.data.user->elf_program = opt_prog_name;

/* install the I/O handlers for the RISC-V runtime */
const riscv_io_t io = {
/* memory read interface */
.mem_ifetch = MEMIO(ifetch),
.mem_read_w = MEMIO(read_w),
.mem_read_s = MEMIO(read_s),
.mem_read_b = MEMIO(read_b),

/* memory write interface */
.mem_write_w = MEMIO(write_w),
.mem_write_s = MEMIO(write_s),
.mem_write_b = MEMIO(write_b),

/* system */
.on_ecall = ecall_handler,
.on_ebreak = ebreak_handler,
.on_memcpy = memcpy_handler,
.on_memset = memset_handler,
};

/* create the RISC-V runtime */
riscv_t *rv = rv_create(&io, &attr);
riscv_t *rv = rv_create(&attr);
if (!rv) {
fprintf(stderr, "Unable to create riscv emulator\n");
return 1;
Expand Down
53 changes: 48 additions & 5 deletions src/riscv.c
Original file line number Diff line number Diff line change
Expand Up @@ -155,16 +155,38 @@ void rv_remap_stdstream(riscv_t *rv, fd_stream_pair_t *fsp, uint32_t fsp_size)
}
}

riscv_t *rv_create(const riscv_io_t *io, riscv_user_t rv_attr)
#define MEMIO(op) on_mem_##op
#define IO_HANDLER_IMPL(type, op, RW) \
static IIF(RW)( \
/* W */ void MEMIO(op)(riscv_word_t addr, riscv_##type##_t data), \
/* R */ riscv_##type##_t MEMIO(op)(riscv_word_t addr)) \
{ \
IIF(RW) \
(memory_##op(addr, (uint8_t *) &data), return memory_##op(addr)); \
}

#define R 0
#define W 1

IO_HANDLER_IMPL(word, ifetch, R)
IO_HANDLER_IMPL(word, read_w, R)
IO_HANDLER_IMPL(half, read_s, R)
IO_HANDLER_IMPL(byte, read_b, R)

IO_HANDLER_IMPL(word, write_w, W)
IO_HANDLER_IMPL(half, write_s, W)
IO_HANDLER_IMPL(byte, write_b, W)

#undef R
#undef W

riscv_t *rv_create(riscv_user_t rv_attr)
{
assert(io && rv_attr);
assert(rv_attr);

riscv_t *rv = calloc(1, sizeof(riscv_t));
assert(rv);

/* copy over the IO interface */
memcpy(&rv->io, io, sizeof(riscv_io_t));

/* copy over the attr */
rv->data = rv_attr;

Expand All @@ -190,6 +212,27 @@ riscv_t *rv_create(const riscv_io_t *io, riscv_user_t rv_attr)
assert(rv_set_pc(rv, hdr->e_entry));

elf_delete(elf);

/* install the I/O handlers */
const riscv_io_t io = {
/* memory read interface */
.mem_ifetch = MEMIO(ifetch),
.mem_read_w = MEMIO(read_w),
.mem_read_s = MEMIO(read_s),
.mem_read_b = MEMIO(read_b),

/* memory write interface */
.mem_write_w = MEMIO(write_w),
.mem_write_s = MEMIO(write_s),
.mem_write_b = MEMIO(write_b),

/* system services or essential routines */
.on_ecall = ecall_handler,
.on_ebreak = ebreak_handler,
.on_memcpy = memcpy_handler,
.on_memset = memset_handler,
};
memcpy(&rv->io, &io, sizeof(riscv_io_t));
} else {
/* TODO: system emulator */
}
Expand Down
4 changes: 3 additions & 1 deletion src/riscv.h
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,8 @@ typedef struct {
riscv_mem_write_s mem_write_s;
riscv_mem_write_b mem_write_b;

/* TODO: add peripheral I/O interfaces */

/* system */
riscv_on_ecall on_ecall;
riscv_on_ebreak on_ebreak;
Expand All @@ -150,7 +152,7 @@ typedef struct {
void rv_run(riscv_t *rv);

/* create a RISC-V emulator */
riscv_t *rv_create(const riscv_io_t *io, riscv_user_t attr);
riscv_t *rv_create(riscv_user_t attr);

/* delete a RISC-V emulator */
void rv_delete(riscv_t *rv);
Expand Down

0 comments on commit ff8a1ab

Please sign in to comment.