diff --git a/Makefile b/Makefile index 068d87e7..3aa0a35f 100644 --- a/Makefile +++ b/Makefile @@ -47,8 +47,6 @@ OBJS_EXT := ifeq ($(call has, SYSTEM), 1) OBJS_EXT += system.o -OBJS_EXT += plic.o -OBJS_EXT += uart.o endif # Integer Multiplication and Division instructions @@ -230,11 +228,22 @@ ifeq ($(call has, GDBSTUB), 1) $(OBJS): $(GDBSTUB_LIB) endif +# Peripherals for system emulation +ifeq ($(call has, SYSTEM), 1) +DEV_OUT := $(OUT)/devices +DEV_SRC := src/devices +$(DEV_OUT)/%.o: $(DEV_SRC)/%.c $(deps_emcc) + $(VECHO) " CC\t$@\n" + $(Q)$(CC) -o $@ $(CFLAGS) $(CFLAGS_emcc) -c -MMD -MF $@.d $< +DEV_OBJS := $(patsubst $(DEV_SRC)/%.c, $(DEV_OUT)/%.o, $(wildcard $(DEV_SRC)/*.c)) +deps += $(DEV_OBJS:%.o=%.o.d) +endif + $(OUT)/%.o: src/%.c $(deps_emcc) $(VECHO) " CC\t$@\n" $(Q)$(CC) -o $@ $(CFLAGS) $(CFLAGS_emcc) -c -MMD -MF $@.d $< -$(BIN): $(OBJS) +$(BIN): $(OBJS) $(DEV_OBJS) $(VECHO) " LD\t$@\n" $(Q)$(CC) -o $@ $(CFLAGS_emcc) $^ $(LDFLAGS) @@ -331,7 +340,7 @@ endif endif clean: - $(RM) $(BIN) $(OBJS) $(HIST_BIN) $(HIST_OBJS) $(deps) $(WEB_FILES) $(CACHE_OUT) src/rv32_jit.c + $(RM) $(BIN) $(OBJS) $(DEV_OBJS) $(HIST_BIN) $(HIST_OBJS) $(deps) $(WEB_FILES) $(CACHE_OUT) src/rv32_jit.c distclean: clean -$(RM) $(DOOM_DATA) $(QUAKE_DATA) $(RM) -r $(TIMIDITY_DATA) diff --git a/src/plic.c b/src/devices/plic.c similarity index 74% rename from src/plic.c rename to src/devices/plic.c index 77d45b09..19f73826 100644 --- a/src/plic.c +++ b/src/devices/plic.c @@ -1,9 +1,18 @@ +/* + * rv32emu is freely redistributable under the MIT License. See the file + * "LICENSE" for information on usage and redistribution of this file. + */ + +#include +#include + #include "plic.h" +#include "../riscv.h" +#include "../riscv_private.h" -void plic_update_interrupts(riscv_t *rv) +void plic_update_interrupts(plic_t *plic) { - vm_attr_t *attr = PRIV(rv); - plic_t *plic = attr->plic; + riscv_t *rv = (riscv_t *) plic->rv; /* Update pending interrupts */ plic->ip |= plic->active & ~plic->masked; @@ -15,11 +24,8 @@ void plic_update_interrupts(riscv_t *rv) rv->csr_sip &= ~SIP_SEIP; } -uint32_t plic_read(riscv_t *rv, const uint32_t addr) +uint32_t plic_read(plic_t *plic, const uint32_t addr) { - vm_attr_t *attr = PRIV(rv); - plic_t *plic = attr->plic; - /* no priority support: source priority hardwired to 1 */ if (1 <= addr && addr <= 31) return 0; @@ -54,11 +60,8 @@ uint32_t plic_read(riscv_t *rv, const uint32_t addr) return plic_read_val; } -void plic_write(riscv_t *rv, const uint32_t addr, uint32_t value) +void plic_write(plic_t *plic, const uint32_t addr, uint32_t value) { - vm_attr_t *attr = PRIV(rv); - plic_t *plic = attr->plic; - /* no priority support: source priority hardwired to 1 */ if (1 <= addr && addr <= 31) return; @@ -81,3 +84,11 @@ void plic_write(riscv_t *rv, const uint32_t addr, uint32_t value) return; } + +plic_t *plic_new() +{ + plic_t *plic = calloc(1, sizeof(plic_t)); + assert(plic); + + return plic; +} diff --git a/src/devices/plic.h b/src/devices/plic.h new file mode 100644 index 00000000..05bb21b5 --- /dev/null +++ b/src/devices/plic.h @@ -0,0 +1,31 @@ +/* + * rv32emu is freely redistributable under the MIT License. See the file + * "LICENSE" for information on usage and redistribution of this file. + */ + +#pragma once + +#include + +/* PLIC */ +typedef struct { + uint32_t masked; + uint32_t ip; + uint32_t ie; + /* state of input interrupt lines (level-triggered), set by environment */ + uint32_t active; + /* RISC-V instance to receive PLIC interrupt */ + void *rv; +} plic_t; + +/* update PLIC status */ +void plic_update_interrupts(plic_t *plic); + +/* read a word from PLIC */ +uint32_t plic_read(plic_t *plic, const uint32_t addr); + +/* write a word to PLIC */ +void plic_write(plic_t *plic, const uint32_t addr, uint32_t value); + +/* create a PLIC instance */ +plic_t *plic_new(); diff --git a/src/uart.c b/src/devices/uart.c similarity index 91% rename from src/uart.c rename to src/devices/uart.c index 6afd7762..61ef0353 100644 --- a/src/uart.c +++ b/src/devices/uart.c @@ -1,14 +1,20 @@ +/* + * rv32emu is freely redistributable under the MIT License. See the file + * "LICENSE" for information on usage and redistribution of this file. + */ + #include #include #include #include #include #include - -#include "io.h" +#include /* Emulate 8250 (plain, without loopback mode support) */ +#include "uart.h" + #define U8250_INT_THRE 1 void u8250_update_interrupts(u8250_state_t *uart) @@ -142,3 +148,11 @@ void u8250_write(u8250_state_t *uart, uint32_t addr, uint32_t value) { u8250_reg_write(uart, addr, value); } + +u8250_state_t *u8250_new() +{ + u8250_state_t *uart = calloc(1, sizeof(u8250_state_t)); + assert(uart); + + return uart; +} diff --git a/src/devices/uart.h b/src/devices/uart.h new file mode 100644 index 00000000..ee44b3f5 --- /dev/null +++ b/src/devices/uart.h @@ -0,0 +1,37 @@ +/* + * rv32emu is freely redistributable under the MIT License. See the file + * "LICENSE" for information on usage and redistribution of this file. + */ + +#pragma once + +#include +#include + +#define IRQ_UART 1 +#define IRQ_UART_BIT (1 << IRQ_UART) + +typedef struct { + uint8_t dll, dlh; /* divisor (ignored) */ + uint8_t lcr; /* UART config */ + uint8_t ier; /* interrupt config */ + uint8_t current_int, pending_ints; /* interrupt status */ + uint8_t mcr; /* other output signals, loopback mode (ignored) */ + int in_fd, out_fd; /* I/O handling */ + bool in_ready; +} u8250_state_t; + +/* update UART status */ +void u8250_update_interrupts(u8250_state_t *uart); + +/* poll UART status */ +void u8250_check_ready(u8250_state_t *uart); + +/* read a word from UART */ +uint32_t u8250_read(u8250_state_t *uart, uint32_t addr); + +/* write a word to UART */ +void u8250_write(u8250_state_t *uart, uint32_t addr, uint32_t value); + +/* create a UART instance */ +u8250_state_t *u8250_new(); diff --git a/src/emulate.c b/src/emulate.c index c1294cbe..8cebf410 100644 --- a/src/emulate.c +++ b/src/emulate.c @@ -10,10 +10,6 @@ #include #include -#if RV32_HAS(SYSTEM) -#include "plic.h" -#endif /* RV32_HAS(SYSTEM) */ - #ifdef __EMSCRIPTEN__ #include #endif diff --git a/src/io.c b/src/io.c index 84be5751..2009e452 100644 --- a/src/io.c +++ b/src/io.c @@ -15,22 +15,6 @@ #include "io.h" -u8250_state_t *u8250_new() -{ - u8250_state_t *uart = calloc(1, sizeof(u8250_state_t)); - assert(uart); - - return uart; -} - -plic_t *plic_new() -{ - plic_t *plic = calloc(1, sizeof(plic_t)); - assert(plic); - - return plic; -} - static uint8_t *data_memory_base; memory_t *memory_new(uint32_t size) diff --git a/src/io.h b/src/io.h index 5e74cd0e..1b4ebdef 100644 --- a/src/io.h +++ b/src/io.h @@ -9,43 +9,7 @@ #include #include -/* UART */ - -#define IRQ_UART 1 -#define IRQ_UART_BIT (1 << IRQ_UART) - -typedef struct { - uint8_t dll, dlh; /**< divisor (ignored) */ - uint8_t lcr; /**< UART config */ - uint8_t ier; /**< interrupt config */ - uint8_t current_int, pending_ints; /**< interrupt status */ - /* other output signals, loopback mode (ignored) */ - uint8_t mcr; - /* I/O handling */ - int in_fd, out_fd; - bool in_ready; -} u8250_state_t; -void u8250_update_interrupts(u8250_state_t *uart); -void u8250_check_ready(u8250_state_t *uart); - -uint32_t u8250_read(u8250_state_t *uart, uint32_t addr); - -void u8250_write(u8250_state_t *uart, uint32_t addr, uint32_t value); - -/* create a UART controller */ -u8250_state_t *u8250_new(); - -typedef struct { - uint32_t masked; - uint32_t ip; - uint32_t ie; - /* state of input interrupt lines (level-triggered), set by environment */ - uint32_t active; -} plic_t; - -/* create a PLIC core */ -plic_t *plic_new(); - +/* main memory */ typedef struct { uint8_t *mem_base; uint64_t mem_size; diff --git a/src/plic.h b/src/plic.h deleted file mode 100644 index 1be84e45..00000000 --- a/src/plic.h +++ /dev/null @@ -1,7 +0,0 @@ -#pragma once - -#include "riscv_private.h" - -void plic_update_interrupts(riscv_t *rv); -uint32_t plic_read(riscv_t *rv, const uint32_t addr); -void plic_write(riscv_t *rv, const uint32_t addr, uint32_t value); diff --git a/src/riscv.c b/src/riscv.c index d9c87164..69d22340 100644 --- a/src/riscv.c +++ b/src/riscv.c @@ -367,8 +367,9 @@ riscv_t *rv_create(riscv_user_t rv_attr) /* setup PLIC */ attr->plic = plic_new(); assert(attr->plic); + attr->plic->rv = rv; - /* setup PLIC */ + /* setup UART */ attr->uart = u8250_new(); assert(attr->uart); attr->uart->in_fd = 0; diff --git a/src/riscv.h b/src/riscv.h index 568efa70..149cf657 100644 --- a/src/riscv.h +++ b/src/riscv.h @@ -12,6 +12,11 @@ #include "io.h" #include "map.h" +#if RV32_HAS(SYSTEM) +#include "devices/plic.h" +#include "devices/uart.h" +#endif /* RV32_HAS(EXT_SYSTEM) */ + #if RV32_HAS(EXT_F) #define float16_t softfloat_float16_t #define bfloat16_t softfloat_bfloat16_t @@ -541,11 +546,13 @@ typedef struct { } vm_data_t; typedef struct { +#if RV32_HAS(SYSTEM) /* uart object */ u8250_state_t *uart; /* plic object */ plic_t *plic; +#endif /* RV32_HAS(SYSTEM) */ /* vm memory object */ memory_t *mem; diff --git a/src/system.c b/src/system.c index 7c4af2b0..dd9696e6 100644 --- a/src/system.c +++ b/src/system.c @@ -7,7 +7,8 @@ #error "Do not manage to build this file unless you enable system support." #endif -#include "plic.h" +#include "devices/plic.h" +#include "devices/uart.h" #include "riscv_private.h" void emu_update_uart_interrupts(riscv_t *rv) @@ -18,7 +19,7 @@ void emu_update_uart_interrupts(riscv_t *rv) attr->plic->active |= IRQ_UART_BIT; } else attr->plic->active &= ~IRQ_UART_BIT; - plic_update_interrupts(rv); + plic_update_interrupts(attr->plic); } #define MMIO_PLIC 1 @@ -31,11 +32,11 @@ uint8_t ret_char; #define MMIO_OP(io, rw) \ IIF(io)( /* PLIC */ \ IIF(rw)( /* read */ \ - read_val = plic_read(rv, (addr & 0x3FFFFFF) >> 2); \ - plic_update_interrupts(rv); return read_val; \ + read_val = plic_read(PRIV(rv)->plic, (addr & 0x3FFFFFF) >> 2); \ + plic_update_interrupts(PRIV(rv)->plic); return read_val; \ , /* write */ \ - plic_write(rv, (addr & 0x3FFFFFF) >> 2, val); \ - plic_update_interrupts(rv); return; \ + plic_write(PRIV(rv)->plic, (addr & 0x3FFFFFF) >> 2, val); \ + plic_update_interrupts(PRIV(rv)->plic); return; \ ) \ , /* UART */ \ IIF(rw)( /* read */ \