Compare commits

...

2 commits

Author SHA1 Message Date
c9ad69a32d
nemu: break before executing instruction
Some checks failed
Build abstract machine with nix / build-abstract-machine (push) Failing after 45s
Run CTests within npc / npc-test (push) Failing after 47s
2024-07-25 17:56:30 +08:00
385d448746
abstract-machine(nemu): support context switch 2024-07-25 17:16:41 +08:00
23 changed files with 238 additions and 89 deletions

2
.gitmodules vendored
View file

@ -4,4 +4,4 @@
branch = dev
[submodule "diffu"]
path = diffu
url = https://git.xinyang.life/xin/diffu.git
url = git@github.com:xinyangli/diffu.git

View file

@ -76,7 +76,8 @@ target_include_directories(
INTERFACE $<BUILD_INTERFACE:${CMAKE_SOURCE_DIR}/am/include>
$<BUILD_INTERFACE:${CMAKE_SOURCE_DIR}/am/src>
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>)
target_compile_definitions(am_interface INTERFACE ARCH_H=<arch/${ISA}.h>)
target_compile_definitions(am_interface INTERFACE ARCH_H=<arch/${ISA}.h>
"__ISA__=\"${ISA}\"")
file(GLOB_RECURSE AM_HEADERS "${CMAKE_SOURCE_DIR}/am/include/*.h")
target_sources(
am_interface

View file

@ -1,5 +1,6 @@
#ifndef ARCH_H__
#define ARCH_H__
#include <stdint.h>
#ifdef __riscv_e
#define NR_REGS 16
@ -9,10 +10,13 @@
struct Context {
// TODO: fix the order of these members to match trap.S
uintptr_t mepc, mcause, gpr[NR_REGS], mstatus;
uintptr_t gpr[NR_REGS];
uintptr_t mcause, mstatus, mepc;
void *pdir;
};
enum Cause { CauseEnvironmentCallFromMMode = 11 };
#ifdef __riscv_e
#define GPR1 gpr[15] // a5
#else

View file

@ -6,7 +6,7 @@ int main(const char *args);
Area heap = RANGE(&_heap_start, PMEM_END);
#ifndef MAINARGS
#define MAINARGS "5"
#define MAINARGS "i"
#endif
static const char mainargs[] = MAINARGS;

View file

@ -1,14 +1,21 @@
#include "arch/riscv.h"
#include <am.h>
#include <riscv/riscv.h>
#include <klib.h>
#include <riscv/riscv.h>
#include <stdint.h>
static Context* (*user_handler)(Event, Context*) = NULL;
static Context *(*user_handler)(Event, Context *) = NULL;
Context* __am_irq_handle(Context *c) {
Context *__am_irq_handle(Context *c) {
if (user_handler) {
Event ev = {0};
switch (c->mcause) {
default: ev.event = EVENT_ERROR; break;
case CauseEnvironmentCallFromMMode:
ev.event = EVENT_YIELD;
break;
default:
ev.event = EVENT_ERROR;
break;
}
c = user_handler(ev, c);
@ -20,7 +27,7 @@ Context* __am_irq_handle(Context *c) {
extern void __am_asm_trap(void);
bool cte_init(Context*(*handler)(Event, Context*)) {
bool cte_init(Context *(*handler)(Event, Context *)) {
// initialize exception entry
asm volatile("csrw mtvec, %0" : : "r"(__am_asm_trap));
@ -31,7 +38,10 @@ bool cte_init(Context*(*handler)(Event, Context*)) {
}
Context *kcontext(Area kstack, void (*entry)(void *), void *arg) {
return NULL;
Context *c = kstack.end - sizeof(Context);
c->mepc = (uintptr_t)entry;
c->gpr[10] = (uintptr_t)arg;
return c;
}
void yield() {
@ -42,9 +52,6 @@ void yield() {
#endif
}
bool ienabled() {
return false;
}
bool ienabled() { return false; }
void iset(bool enable) {
}
void iset(bool enable) {}

View file

@ -60,6 +60,8 @@ __am_asm_trap:
mv a0, sp
jal __am_irq_handle
mv sp, a0
LOAD t1, OFFSET_STATUS(sp)
LOAD t2, OFFSET_EPC(sp)
csrw mstatus, t1

View file

@ -15,6 +15,9 @@ stdenv.mkDerivation {
(lib.cmakeFeature "ISA" isa)
] ++ map (p: (lib.cmakeBool "__PLATFORM_${lib.strings.toUpper p}__" true)) platform;
cmakeBuildType = "Debug";
dontStrip = true;
nativeBuildInputs = [
cmake
];

@ -1 +1 @@
Subproject commit 02b38e7b44f673f808abcb3bf9464811f8c58d4b
Subproject commit 8c4ea046225e2dce599dc36aeef6c4c857996d00

View file

@ -128,11 +128,11 @@
]
},
"locked": {
"lastModified": 1721457008,
"narHash": "sha256-ekpve0om5hzC1Ntd3zm1cZ9oS5pnr7a2n/tueyqFOsg=",
"lastModified": 1721891452,
"narHash": "sha256-2c9nDuXXARzoRXE67lte5kKBeFb1XmTNsvdiIbRUEgE=",
"ref": "refs/heads/master",
"rev": "e7aa3319d52fa987ac2192f63aef3dcb1b057e3a",
"revCount": 151,
"rev": "de8ad578fc4fe527772cec23a7f660bde14c8570",
"revCount": 152,
"type": "git",
"url": "https://git.xinyang.life/xin/nur.git"
},

View file

@ -64,13 +64,14 @@
abstract-machine = rv32CrossConfig.callPackage ./abstract-machine { isa = "riscv"; platform = [ "nemu" "npc" ]; };
am-kernels-npc = rv32CrossConfig.callPackage ./am-kernels { inherit abstract-machine; arch = "riscv-npc"; };
am-kernels-nemu = rv32CrossConfig.callPackage ./am-kernels { inherit abstract-machine; arch = "riscv-nemu"; };
am-kernels = rv32CrossConfig.callPackage ./am-kernels { abstract-machine = abstract-machine; arch = "riscv"; };
};
};
devShells.nemu = pkgs.mkShell {
packages = with pkgs; [
clang-tools
gdb
gef
SDL2
gnumake
pkg-config

1
nemu/.gitignore vendored
View file

@ -9,6 +9,7 @@ build/
.envrc
.metals/
.vscode/
.zed/
compile_commands.json
### C ###

View file

@ -20,7 +20,14 @@
// ----------- state -----------
enum { NEMU_RUNNING, NEMU_STOP, NEMU_END, NEMU_ABORT, NEMU_QUIT };
enum {
NEMU_RUNNING,
NEMU_GDB_INTERRUPT,
NEMU_STOP,
NEMU_END,
NEMU_ABORT,
NEMU_QUIT
};
typedef struct {
int state;
@ -36,42 +43,41 @@ uint64_t get_time();
// ----------- log -----------
#define ANSI_FG_BLACK "\33[1;30m"
#define ANSI_FG_RED "\33[1;31m"
#define ANSI_FG_GREEN "\33[1;32m"
#define ANSI_FG_YELLOW "\33[1;33m"
#define ANSI_FG_BLUE "\33[1;34m"
#define ANSI_FG_BLACK "\33[1;30m"
#define ANSI_FG_RED "\33[1;31m"
#define ANSI_FG_GREEN "\33[1;32m"
#define ANSI_FG_YELLOW "\33[1;33m"
#define ANSI_FG_BLUE "\33[1;34m"
#define ANSI_FG_MAGENTA "\33[1;35m"
#define ANSI_FG_CYAN "\33[1;36m"
#define ANSI_FG_WHITE "\33[1;37m"
#define ANSI_BG_BLACK "\33[1;40m"
#define ANSI_BG_RED "\33[1;41m"
#define ANSI_BG_GREEN "\33[1;42m"
#define ANSI_BG_YELLOW "\33[1;43m"
#define ANSI_BG_BLUE "\33[1;44m"
#define ANSI_FG_CYAN "\33[1;36m"
#define ANSI_FG_WHITE "\33[1;37m"
#define ANSI_BG_BLACK "\33[1;40m"
#define ANSI_BG_RED "\33[1;41m"
#define ANSI_BG_GREEN "\33[1;42m"
#define ANSI_BG_YELLOW "\33[1;43m"
#define ANSI_BG_BLUE "\33[1;44m"
#define ANSI_BG_MAGENTA "\33[1;35m"
#define ANSI_BG_CYAN "\33[1;46m"
#define ANSI_BG_WHITE "\33[1;47m"
#define ANSI_NONE "\33[0m"
#define ANSI_BG_CYAN "\33[1;46m"
#define ANSI_BG_WHITE "\33[1;47m"
#define ANSI_NONE "\33[0m"
#define ANSI_FMT(str, fmt) fmt str ANSI_NONE
#define log_write(...) IFDEF(CONFIG_TARGET_NATIVE_ELF, \
do { \
extern FILE* log_fp; \
extern bool log_enable(); \
if (log_enable()) { \
fprintf(log_fp, __VA_ARGS__); \
fflush(log_fp); \
} \
} while (0) \
)
#define log_write(...) \
IFDEF( \
CONFIG_TARGET_NATIVE_ELF, do { \
extern FILE *log_fp; \
extern bool log_enable(); \
if (log_enable()) { \
fprintf(log_fp, __VA_ARGS__); \
fflush(log_fp); \
} \
} while (0))
#define _Log(...) \
do { \
printf(__VA_ARGS__); \
log_write(__VA_ARGS__); \
#define _Log(...) \
do { \
printf(__VA_ARGS__); \
log_write(__VA_ARGS__); \
} while (0)
#endif

View file

@ -158,8 +158,6 @@ breakpoint_t *cpu_exec_with_bp(uint64_t n, breakpoint_t *bp, size_t len) {
static Decode s;
nemu_state.state = NEMU_RUNNING;
do {
exec_once(&s, cpu.pc);
g_nr_guest_inst++;
for (int i = 0; i < len; i++) {
size_t addr = bp[i].addr;
bp_type_t bptype = bp[i].type;
@ -176,6 +174,8 @@ breakpoint_t *cpu_exec_with_bp(uint64_t n, breakpoint_t *bp, size_t len) {
return bp + i;
}
}
exec_once(&s, cpu.pc);
g_nr_guest_inst++;
if (nemu_state.state != NEMU_RUNNING)
return NULL;
} while (--n);

View file

@ -13,7 +13,10 @@
* See the Mulan PSL v2 for more details.
***************************************************************************************/
#include <assert.h>
#include <debug.h>
#include <device/map.h>
#include <generated/autoconf.h>
#include <utils.h>
#define KEYDOWN_MASK 0x8000
@ -22,28 +25,27 @@
#include <SDL2/SDL.h>
// Note that this is not the standard
#define NEMU_KEYS(f) \
f(ESCAPE) f(F1) f(F2) f(F3) f(F4) f(F5) f(F6) f(F7) f(F8) f(F9) f(F10) f(F11) f(F12) \
f(GRAVE) f(1) f(2) f(3) f(4) f(5) f(6) f(7) f(8) f(9) f(0) f(MINUS) f(EQUALS) f(BACKSPACE) \
f(TAB) f(Q) f(W) f(E) f(R) f(T) f(Y) f(U) f(I) f(O) f(P) f(LEFTBRACKET) f(RIGHTBRACKET) f(BACKSLASH) \
f(CAPSLOCK) f(A) f(S) f(D) f(F) f(G) f(H) f(J) f(K) f(L) f(SEMICOLON) f(APOSTROPHE) f(RETURN) \
f(LSHIFT) f(Z) f(X) f(C) f(V) f(B) f(N) f(M) f(COMMA) f(PERIOD) f(SLASH) f(RSHIFT) \
f(LCTRL) f(APPLICATION) f(LALT) f(SPACE) f(RALT) f(RCTRL) \
f(UP) f(DOWN) f(LEFT) f(RIGHT) f(INSERT) f(DELETE) f(HOME) f(END) f(PAGEUP) f(PAGEDOWN)
#define NEMU_KEYS(f) \
f(ESCAPE) f(F1) f(F2) f(F3) f(F4) f(F5) f(F6) f(F7) f(F8) f(F9) f(F10) \
f(F11) f(F12) f(GRAVE) f(1) f(2) f(3) f(4) f(5) f(6) f(7) f(8) f(9) f(0) \
f(MINUS) f(EQUALS) f(BACKSPACE) f(TAB) f(Q) f(W) f(E) f(R) f(T) f(Y) \
f(U) f(I) f(O) f(P) f(LEFTBRACKET) f(RIGHTBRACKET) f(BACKSLASH) \
f(CAPSLOCK) f(A) f(S) f(D) f(F) f(G) f(H) f(J) f(K) f(L) \
f(SEMICOLON) f(APOSTROPHE) f(RETURN) f(LSHIFT) f(Z) f(X) \
f(C) f(V) f(B) f(N) f(M) f(COMMA) f(PERIOD) f(SLASH) \
f(RSHIFT) f(LCTRL) f(APPLICATION) f(LALT) \
f(SPACE) f(RALT) f(RCTRL) f(UP) f(DOWN) \
f(LEFT) f(RIGHT) f(INSERT) f(DELETE) \
f(HOME) f(END) f(PAGEUP) f(PAGEDOWN)
#define NEMU_KEY_NAME(k) NEMU_KEY_ ## k,
#define NEMU_KEY_NAME(k) NEMU_KEY_##k,
enum {
NEMU_KEY_NONE = 0,
MAP(NEMU_KEYS, NEMU_KEY_NAME)
};
enum { NEMU_KEY_NONE = 0, MAP(NEMU_KEYS, NEMU_KEY_NAME) };
#define SDL_KEYMAP(k) keymap[SDL_SCANCODE_ ## k] = NEMU_KEY_ ## k;
#define SDL_KEYMAP(k) keymap[SDL_SCANCODE_##k] = NEMU_KEY_##k;
static uint32_t keymap[256] = {};
static void init_keymap() {
MAP(NEMU_KEYS, SDL_KEYMAP)
}
static void init_keymap() { MAP(NEMU_KEYS, SDL_KEYMAP) }
#define KEY_QUEUE_LEN 1024
static int key_queue[KEY_QUEUE_LEN] = {};
@ -92,9 +94,11 @@ void init_i8042() {
i8042_data_port_base = (uint32_t *)new_space(4);
i8042_data_port_base[0] = NEMU_KEY_NONE;
#ifdef CONFIG_HAS_PORT_IO
add_pio_map ("keyboard", CONFIG_I8042_DATA_PORT, i8042_data_port_base, 4, i8042_data_io_handler);
add_pio_map("keyboard", CONFIG_I8042_DATA_PORT, i8042_data_port_base, 4,
i8042_data_io_handler);
#else
add_mmio_map("keyboard", CONFIG_I8042_DATA_MMIO, i8042_data_port_base, 4, i8042_data_io_handler);
add_mmio_map("keyboard", CONFIG_I8042_DATA_MMIO, i8042_data_port_base, 4,
i8042_data_io_handler);
#endif
IFNDEF(CONFIG_TARGET_AM, init_keymap());
}

View file

@ -16,6 +16,7 @@
#include <assert.h>
#include <debug.h>
#include <device/map.h>
#include <generated/autoconf.h>
#include <utils.h>
/* http://en.wikibooks.org/wiki/Serial_Programming/8250_UART_Programming */

View file

@ -16,6 +16,7 @@
#include <assert.h>
#include <device/alarm.h>
#include <device/map.h>
#include <generated/autoconf.h>
#include <utils.h>
static uint32_t *rtc_port_base = NULL;

View file

@ -0,0 +1,18 @@
#include <csr.h>
void init_csr(csr_t csr) { memset(csr, 0, sizeof(word_t)); }
void write_csr(csr_t csr, csr_addr_t csrnum, word_t value) {
switch (csrnum) {
default:
csr[csrnum] = value;
}
}
word_t read_csr(csr_t csr, csr_addr_t csrnum) {
switch (csrnum) {
// TODO: Implement csr read checks
default:
return csr[csrnum];
}
}

View file

@ -18,9 +18,13 @@
#include <common.h>
#define CSR_SIZE (0x1000)
typedef word_t csr_t[CSR_SIZE];
typedef struct {
word_t gpr[MUXDEF(CONFIG_RVE, 16, 32)];
// word_t csr[MUXDEF(CONFIG_RVE, )]
csr_t csr;
vaddr_t pc;
} MUXDEF(CONFIG_RV64, riscv64_CPU_state, riscv32_CPU_state);

View file

@ -13,6 +13,7 @@
* See the Mulan PSL v2 for more details.
***************************************************************************************/
#include "isa.h"
#include "local-include/reg.h"
#include "macro.h"
#include "types.h"
@ -20,6 +21,7 @@
#include <cpu/cpu.h>
#include <cpu/decode.h>
#include <cpu/ifetch.h>
#include <csr.h>
#include <ftrace.h>
#include <utils.h>
@ -33,6 +35,8 @@ enum {
TYPE_S,
TYPE_B,
TYPE_J,
TYPE_CSR,
TYPE_CSRI,
TYPE_N, // none
};
@ -66,6 +70,14 @@ enum {
*imm = SEXT(BITS(i, 31, 31), 1) << 20 | BITS(i, 30, 21) << 1 | \
BITS(i, 20, 20) << 11 | BITS(i, 19, 12) << 12; \
} while (0)
#define csr() \
do { \
*src2 = BITS(i, 31, 20); \
} while (0)
#define uimm() \
do { \
*imm = BITS(i, 19, 15); \
} while (0)
static void decode_operand(Decode *s, int *rd, word_t *src1, word_t *src2,
word_t *imm, int type) {
@ -98,6 +110,14 @@ static void decode_operand(Decode *s, int *rd, word_t *src1, word_t *src2,
src2R();
immB();
break;
case TYPE_CSR:
src1R();
csr();
break;
case TYPE_CSRI:
csr();
uimm();
break;
}
}
@ -249,6 +269,44 @@ static int decode_exec(Decode *s) {
INSTPAT("0000001 ????? ????? 111 ????? 01100 11", remu, R,
R(rd) = src1 % src2);
// "Previledge"
// -- CSR instructions
INSTPAT(
"??????? ????? ????? 001 ????? 11100 11", csrrw, CSR, do {
R(rd) = read_csr(cpu.csr, src2);
write_csr(cpu.csr, src2, src1);
} while (0););
INSTPAT(
"??????? ????? ????? 010 ????? 11100 11", csrrs, CSR, do {
R(rd) = read_csr(cpu.csr, src2);
set_csr_bits(cpu.csr, src2, src1);
} while (0););
INSTPAT(
"??????? ????? ????? 011 ????? 11100 11", csrrc, CSR, do {
R(rd) = read_csr(cpu.csr, src2);
clear_csr_bits(cpu.csr, src2, src1);
} while (0););
INSTPAT(
"??????? ????? ????? 101 ????? 11100 11", csrrwi, CSRI, do {
R(rd) = read_csr(cpu.csr, src2);
write_csr(cpu.csr, src2, imm);
} while (0););
INSTPAT(
"??????? ????? ????? 110 ????? 11100 11", csrrsi, CSRI, do {
R(rd) = read_csr(cpu.csr, src2);
set_csr_bits(cpu.csr, src2, imm);
} while (0););
INSTPAT(
"??????? ????? ????? 111 ????? 11100 11", csrrci, CSRI, do {
R(rd) = read_csr(cpu.csr, src2);
clear_csr_bits(cpu.csr, src2, imm);
} while (0););
// -- Machine level
INSTPAT("0000000 00000 00000 000 00000 11100 11", ecall, N,
s->dnpc = isa_raise_intr(CauseEnvironmentCallFromMMode, cpu.pc));
INSTPAT("0011000 00010 00000 000 00000 11100 11", mret, N,
s->dnpc = read_csr(cpu.csr, MEPC));
INSTPAT("??????? ????? ????? ??? ????? ????? ??", inv, N, INV(s->pc));
INSTPAT_END();

View file

@ -0,0 +1,29 @@
#ifndef __NEMU_CSR_H__
#define __NEMU_CSR_H__
#include <isa-def.h>
#include <types.h>
#define MSTATUS 0x300
#define MISA 0x301
#define MIE 0x304
#define MTVEC 0x305
#define MEPC 0x341
#define MCAUSE 0x342
enum { CauseEnvironmentCallFromMMode = 11 };
typedef uint16_t csr_addr_t;
void init_csr(csr_t csr);
/* macro for setting and clearing csr bits */
#define set_csr_bits(csr, reg, mask) \
write_csr(csr, reg, read_csr(csr, reg) | (mask))
#define clear_csr_bits(csr, reg, mask) \
write_csr(csr, reg, read_csr(csr, reg) & ~(mask))
void write_csr(csr_t csr, csr_addr_t csrnum, word_t value);
word_t read_csr(csr_t csr, csr_addr_t csrnum);
#endif // __NEMU_CSR_H__

View file

@ -14,6 +14,7 @@
***************************************************************************************/
#include "local-include/reg.h"
#include "csr.h"
#include "macro.h"
#include <errno.h>
#include <gdbstub.h>
@ -51,11 +52,13 @@ word_t isa_reg_str2val(const char *s, bool *success) {
}
int isa_read_reg(void *args, int regno, size_t *reg_value) {
if (regno > 32) {
if (regno > 33) {
return EFAULT;
}
if (regno == 32) {
if (regno == 33) {
*reg_value = cpu.csr[MTVEC];
} else if (regno == 32) {
*reg_value = cpu.pc;
} else {
*reg_value = cpu.gpr[regno];
@ -64,11 +67,13 @@ int isa_read_reg(void *args, int regno, size_t *reg_value) {
}
int isa_write_reg(void *args, int regno, size_t data) {
if (regno > 32) {
if (regno > 33) {
return EFAULT;
}
if (regno == 32) {
if (regno == 33) {
cpu.csr[MTVEC] = data;
} else if (regno == 32) {
cpu.pc = data;
} else {
cpu.gpr[regno] = data;
@ -76,6 +81,6 @@ int isa_write_reg(void *args, int regno, size_t data) {
return 0;
}
__EXPORT arch_info_t isa_arch_info = {.reg_num = 32,
__EXPORT arch_info_t isa_arch_info = {.reg_num = 33,
.reg_byte = MUXDEF(CONFIG_RV64, 8, 4),
.target_desc = TARGET_RV32};

View file

@ -13,16 +13,14 @@
* See the Mulan PSL v2 for more details.
***************************************************************************************/
#include <csr.h>
#include <isa.h>
word_t isa_raise_intr(word_t NO, vaddr_t epc) {
/* TODO: Trigger an interrupt/exception with ``NO''.
* Then return the address of the interrupt/exception vector.
*/
write_csr(cpu.csr, MEPC, epc);
write_csr(cpu.csr, MCAUSE, NO);
return 0;
return read_csr(cpu.csr, MTVEC);
}
word_t isa_query_intr() {
return INTR_EMPTY;
}
word_t isa_query_intr() { return INTR_EMPTY; }

View file

@ -59,6 +59,11 @@ static void nemu_is_stopped(gdb_action_t *act, breakpoint_t *stopped_at) {
}
break;
case NEMU_GDB_INTERRUPT:
act->reason = gdb_action_t::ACT_BREAKPOINT;
act->data = cpu.pc;
break;
default:
act->reason = gdb_action_t::ACT_SHUTDOWN;
act->data = nemu_state.halt_ret;
@ -103,7 +108,7 @@ __EXPORT bool nemu_del_bp(void *args, size_t addr, bp_type_t type) {
}
__EXPORT void nemu_on_interrupt(void *args) {
// fputs("Not implemented", stderr);
nemu_state.state = NEMU_GDB_INTERRUPT;
}
__EXPORT int nemu_read_reg(void *args, int regno, size_t *data) {
@ -121,7 +126,8 @@ static struct target_ops nemu_gdbstub_ops = {.cont = nemu_cont,
.write_mem = nemu_write_mem,
.set_bp = nemu_set_bp,
.del_bp = nemu_del_bp,
.on_interrupt = NULL};
.on_interrupt = nemu_on_interrupt,
.monitor = NULL};
static DbgState *pdbg;
static gdbstub_t gdbstub_priv;
const char SOCKET_ADDR[] = "/tmp/gdbstub-nemu.sock";
@ -152,7 +158,7 @@ __EXPORT void nemu_init(void *args) {
int gdbstub_loop() {
if (!gdbstub_init(&gdbstub_priv, &nemu_gdbstub_ops,
(arch_info_t)isa_arch_info, SOCKET_ADDR)) {
(arch_info_t)isa_arch_info, NULL, SOCKET_ADDR)) {
return EINVAL;
}
printf("Waiting for gdb connection at %s", SOCKET_ADDR);