NJU-ProjectN/nemu ics2023 initialized

NJU-ProjectN/nemu eb63cf3568dbf4e0c3c6ef462e6ec685550fabbc Merge pull request #76 from rijuyuezhu/master
This commit is contained in:
xinyangli 2023-12-21 00:20:36 +08:00
parent 1efe03efb9
commit 2824efad33
141 changed files with 19573 additions and 0 deletions

12
nemu/.gitignore vendored Normal file
View file

@ -0,0 +1,12 @@
*.*
*
!*/
!Makefile
!*.mk
!*.[cSh]
!*.cc
!.gitignore
!README.md
!Kconfig
include/config
include/generated

217
nemu/Kconfig Normal file
View file

@ -0,0 +1,217 @@
mainmenu "NEMU Configuration Menu"
choice
prompt "Base ISA"
default ISA_riscv
config ISA_x86
bool "x86"
config ISA_mips32
bool "mips32"
config ISA_riscv
bool "riscv"
config ISA_loongarch32r
bool "loongarch32r"
endchoice
config ISA
string
default "x86" if ISA_x86
default "mips32" if ISA_mips32
default "riscv32" if ISA_riscv && !RV64
default "riscv64" if ISA_riscv && RV64
default "loongarch32r" if ISA_loongarch32r
default "none"
config ISA64
depends on ISA_riscv && RV64
bool
default y
if ISA_riscv
source "src/isa/riscv32/Kconfig"
endif
choice
prompt "NEMU execution engine"
default ENGINE_INTERPRETER
config ENGINE_INTERPRETER
bool "Interpreter"
help
Interpreter guest instructions one by one.
endchoice
config ENGINE
string
default "interpreter" if ENGINE_INTERPRETER
default "none"
choice
prompt "Running mode"
default MODE_SYSTEM
config MODE_SYSTEM
bool "System mode"
help
Support full-system functionality, including privileged instructions, MMU and devices.
endchoice
choice
prompt "Build target"
default TARGET_NATIVE_ELF
config TARGET_NATIVE_ELF
bool "Executable on Linux Native"
config TARGET_SHARE
bool "Shared object (used as REF for differential testing)"
config TARGET_AM
bool "Application on Abstract-Machine (DON'T CHOOSE)"
endchoice
menu "Build Options"
choice
prompt "Compiler"
default CC_GCC
config CC_GCC
bool "gcc"
config CC_GPP
bool "g++"
config CC_CLANG
depends on !TARGET_AM
bool "clang"
endchoice
config CC
string
default "gcc" if CC_GCC
default "g++" if CC_GPP
default "clang" if CC_CLANG
default "none"
choice
prompt "Optimization Level"
default CC_O2
config CC_O0
bool "O0"
config CC_O1
bool "O1"
config CC_O2
bool "O2"
config CC_O3
bool "O3"
endchoice
config CC_OPT
string
default "-O0" if CC_O0
default "-O1" if CC_O1
default "-O2" if CC_O2
default "-O3" if CC_O3
default "none"
config CC_LTO
depends on !TARGET_AM
bool "Enable link-time optimization"
default n
config CC_DEBUG
bool "Enable debug information"
default n
config CC_ASAN
depends on MODE_SYSTEM
bool "Enable address sanitizer"
default n
endmenu
menu "Testing and Debugging"
config TRACE
bool "Enable tracer"
default y
config TRACE_START
depends on TRACE
int "When tracing is enabled (unit: number of instructions)"
default 0
config TRACE_END
depends on TRACE
int "When tracing is disabled (unit: number of instructions)"
default 10000
config ITRACE
depends on TRACE && TARGET_NATIVE_ELF && ENGINE_INTERPRETER
bool "Enable instruction tracer"
default y
config ITRACE_COND
depends on ITRACE
string "Only trace instructions when the condition is true"
default "true"
config DIFFTEST
depends on TARGET_NATIVE_ELF
bool "Enable differential testing"
default n
help
Enable differential testing with a reference design.
Note that this will significantly reduce the performance of NEMU.
choice
prompt "Reference design"
default DIFFTEST_REF_SPIKE if ISA_riscv
default DIFFTEST_REF_KVM if ISA_x86
default DIFFTEST_REF_QEMU
depends on DIFFTEST
config DIFFTEST_REF_QEMU
bool "QEMU, communicate with socket"
if ISA_riscv
config DIFFTEST_REF_SPIKE
bool "Spike"
endif
if ISA_x86
config DIFFTEST_REF_KVM
bool "KVM"
endif
endchoice
config DIFFTEST_REF_PATH
string
default "tools/qemu-diff" if DIFFTEST_REF_QEMU
default "tools/kvm-diff" if DIFFTEST_REF_KVM
default "tools/spike-diff" if DIFFTEST_REF_SPIKE
default "none"
config DIFFTEST_REF_NAME
string
default "qemu" if DIFFTEST_REF_QEMU
default "kvm" if DIFFTEST_REF_KVM
default "spike" if DIFFTEST_REF_SPIKE
default "none"
endmenu
if MODE_SYSTEM
source "src/memory/Kconfig"
source "src/device/Kconfig"
endif
menu "Miscellaneous"
choice
depends on !TARGET_AM
prompt "Host timer"
default TIMER_GETTIMEOFDAY
config TIMER_GETTIMEOFDAY
bool "gettimeofday"
config TIMER_CLOCK_GETTIME
bool "clock_gettime"
endchoice
config RT_CHECK
bool "Enable runtime checking"
default y
endmenu

61
nemu/Makefile Normal file
View file

@ -0,0 +1,61 @@
#***************************************************************************************
# Copyright (c) 2014-2022 Zihao Yu, Nanjing University
#
# NEMU is licensed under Mulan PSL v2.
# You can use this software according to the terms and conditions of the Mulan PSL v2.
# You may obtain a copy of Mulan PSL v2 at:
# http://license.coscl.org.cn/MulanPSL2
#
# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
# EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
# MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
#
# See the Mulan PSL v2 for more details.
#**************************************************************************************/
# Sanity check
ifeq ($(wildcard $(NEMU_HOME)/src/nemu-main.c),)
$(error NEMU_HOME=$(NEMU_HOME) is not a NEMU repo)
endif
# Include variables and rules generated by menuconfig
-include $(NEMU_HOME)/include/config/auto.conf
-include $(NEMU_HOME)/include/config/auto.conf.cmd
remove_quote = $(patsubst "%",%,$(1))
# Extract variabls from menuconfig
GUEST_ISA ?= $(call remove_quote,$(CONFIG_ISA))
ENGINE ?= $(call remove_quote,$(CONFIG_ENGINE))
NAME = $(GUEST_ISA)-nemu-$(ENGINE)
# Include all filelist.mk to merge file lists
FILELIST_MK = $(shell find -L ./src -name "filelist.mk")
include $(FILELIST_MK)
# Filter out directories and files in blacklist to obtain the final set of source files
DIRS-BLACKLIST-y += $(DIRS-BLACKLIST)
SRCS-BLACKLIST-y += $(SRCS-BLACKLIST) $(shell find -L $(DIRS-BLACKLIST-y) -name "*.c")
SRCS-y += $(shell find -L $(DIRS-y) -name "*.c")
SRCS = $(filter-out $(SRCS-BLACKLIST-y),$(SRCS-y))
# Extract compiler and options from menuconfig
CC = $(call remove_quote,$(CONFIG_CC))
CFLAGS_BUILD += $(call remove_quote,$(CONFIG_CC_OPT))
CFLAGS_BUILD += $(if $(CONFIG_CC_LTO),-flto,)
CFLAGS_BUILD += $(if $(CONFIG_CC_DEBUG),-Og -ggdb3,)
CFLAGS_BUILD += $(if $(CONFIG_CC_ASAN),-fsanitize=address,)
CFLAGS_TRACE += -DITRACE_COND=$(if $(CONFIG_ITRACE_COND),$(call remove_quote,$(CONFIG_ITRACE_COND)),true)
CFLAGS += $(CFLAGS_BUILD) $(CFLAGS_TRACE) -D__GUEST_ISA__=$(GUEST_ISA)
LDFLAGS += $(CFLAGS_BUILD)
# Include rules for menuconfig
include $(NEMU_HOME)/scripts/config.mk
ifdef CONFIG_TARGET_AM
include $(AM_HOME)/Makefile
LINKAGE += $(ARCHIVES)
else
# Include rules to build NEMU
include $(NEMU_HOME)/scripts/native.mk
endif

35
nemu/README.md Normal file
View file

@ -0,0 +1,35 @@
# NEMU
NEMU(NJU Emulator) is a simple but complete full-system emulator designed for teaching purpose.
Currently it supports x86, mips32, riscv32 and riscv64.
To build programs run above NEMU, refer to the [AM project](https://github.com/NJU-ProjectN/abstract-machine).
The main features of NEMU include
* a small monitor with a simple debugger
* single step
* register/memory examination
* expression evaluation without the support of symbols
* watch point
* differential testing with reference design (e.g. QEMU)
* snapshot
* CPU core with support of most common used instructions
* x86
* real mode is not supported
* x87 floating point instructions are not supported
* mips32
* CP1 floating point instructions are not supported
* riscv32
* only RV32IM
* riscv64
* only RV64IM
* memory
* paging
* TLB is optional (but necessary for mips32)
* protection is not supported
* interrupt and exception
* protection is not supported
* 5 devices
* serial, timer, keyboard, VGA, audio
* most of them are simplified and unprogrammable
* 2 types of I/O
* port-mapped I/O and memory-mapped I/O

1
nemu/configs/.gitignore vendored Normal file
View file

@ -0,0 +1 @@
!*_defconfig

View file

@ -0,0 +1,5 @@
CONFIG_ISA_mips32=y
CONFIG_TARGET_AM=y
# CONFIG_TRACE is not set
CONFIG_MSIZE=0x2000000
CONFIG_DEVICE=y

View file

@ -0,0 +1,4 @@
CONFIG_TARGET_AM=y
# CONFIG_TRACE is not set
CONFIG_MSIZE=0x2000000
CONFIG_DEVICE=y

View file

@ -0,0 +1,5 @@
CONFIG_ISA_riscv64=y
CONFIG_TARGET_AM=y
# CONFIG_TRACE is not set
CONFIG_MSIZE=0x2000000
CONFIG_DEVICE=y

49
nemu/include/common.h Normal file
View file

@ -0,0 +1,49 @@
/***************************************************************************************
* Copyright (c) 2014-2022 Zihao Yu, Nanjing University
*
* NEMU is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
* http://license.coscl.org.cn/MulanPSL2
*
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
*
* See the Mulan PSL v2 for more details.
***************************************************************************************/
#ifndef __COMMON_H__
#define __COMMON_H__
#include <stdint.h>
#include <inttypes.h>
#include <stdbool.h>
#include <string.h>
#include <generated/autoconf.h>
#include <macro.h>
#ifdef CONFIG_TARGET_AM
#include <klib.h>
#else
#include <assert.h>
#include <stdlib.h>
#endif
#if CONFIG_MBASE + CONFIG_MSIZE > 0x100000000ul
#define PMEM64 1
#endif
typedef MUXDEF(CONFIG_ISA64, uint64_t, uint32_t) word_t;
typedef MUXDEF(CONFIG_ISA64, int64_t, int32_t) sword_t;
#define FMT_WORD MUXDEF(CONFIG_ISA64, "0x%016" PRIx64, "0x%08" PRIx32)
typedef word_t vaddr_t;
typedef MUXDEF(PMEM64, uint64_t, uint32_t) paddr_t;
#define FMT_PADDR MUXDEF(PMEM64, "0x%016" PRIx64, "0x%08" PRIx32)
typedef uint16_t ioaddr_t;
#include <debug.h>
#endif

29
nemu/include/cpu/cpu.h Normal file
View file

@ -0,0 +1,29 @@
/***************************************************************************************
* Copyright (c) 2014-2022 Zihao Yu, Nanjing University
*
* NEMU is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
* http://license.coscl.org.cn/MulanPSL2
*
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
*
* See the Mulan PSL v2 for more details.
***************************************************************************************/
#ifndef __CPU_CPU_H__
#define __CPU_CPU_H__
#include <common.h>
void cpu_exec(uint64_t n);
void set_nemu_state(int state, vaddr_t pc, int halt_ret);
void invalid_inst(vaddr_t thispc);
#define NEMUTRAP(thispc, code) set_nemu_state(NEMU_END, thispc, code)
#define INV(thispc) invalid_inst(thispc)
#endif

102
nemu/include/cpu/decode.h Normal file
View file

@ -0,0 +1,102 @@
/***************************************************************************************
* Copyright (c) 2014-2022 Zihao Yu, Nanjing University
*
* NEMU is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
* http://license.coscl.org.cn/MulanPSL2
*
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
*
* See the Mulan PSL v2 for more details.
***************************************************************************************/
#ifndef __CPU_DECODE_H__
#define __CPU_DECODE_H__
#include <isa.h>
typedef struct Decode {
vaddr_t pc;
vaddr_t snpc; // static next pc
vaddr_t dnpc; // dynamic next pc
ISADecodeInfo isa;
IFDEF(CONFIG_ITRACE, char logbuf[128]);
} Decode;
// --- pattern matching mechanism ---
__attribute__((always_inline))
static inline void pattern_decode(const char *str, int len,
uint64_t *key, uint64_t *mask, uint64_t *shift) {
uint64_t __key = 0, __mask = 0, __shift = 0;
#define macro(i) \
if ((i) >= len) goto finish; \
else { \
char c = str[i]; \
if (c != ' ') { \
Assert(c == '0' || c == '1' || c == '?', \
"invalid character '%c' in pattern string", c); \
__key = (__key << 1) | (c == '1' ? 1 : 0); \
__mask = (__mask << 1) | (c == '?' ? 0 : 1); \
__shift = (c == '?' ? __shift + 1 : 0); \
} \
}
#define macro2(i) macro(i); macro((i) + 1)
#define macro4(i) macro2(i); macro2((i) + 2)
#define macro8(i) macro4(i); macro4((i) + 4)
#define macro16(i) macro8(i); macro8((i) + 8)
#define macro32(i) macro16(i); macro16((i) + 16)
#define macro64(i) macro32(i); macro32((i) + 32)
macro64(0);
panic("pattern too long");
#undef macro
finish:
*key = __key >> __shift;
*mask = __mask >> __shift;
*shift = __shift;
}
__attribute__((always_inline))
static inline void pattern_decode_hex(const char *str, int len,
uint64_t *key, uint64_t *mask, uint64_t *shift) {
uint64_t __key = 0, __mask = 0, __shift = 0;
#define macro(i) \
if ((i) >= len) goto finish; \
else { \
char c = str[i]; \
if (c != ' ') { \
Assert((c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || c == '?', \
"invalid character '%c' in pattern string", c); \
__key = (__key << 4) | (c == '?' ? 0 : (c >= '0' && c <= '9') ? c - '0' : c - 'a' + 10); \
__mask = (__mask << 4) | (c == '?' ? 0 : 0xf); \
__shift = (c == '?' ? __shift + 4 : 0); \
} \
}
macro16(0);
panic("pattern too long");
#undef macro
finish:
*key = __key >> __shift;
*mask = __mask >> __shift;
*shift = __shift;
}
// --- pattern matching wrappers for decode ---
#define INSTPAT(pattern, ...) do { \
uint64_t key, mask, shift; \
pattern_decode(pattern, STRLEN(pattern), &key, &mask, &shift); \
if ((((uint64_t)INSTPAT_INST(s) >> shift) & mask) == key) { \
INSTPAT_MATCH(s, ##__VA_ARGS__); \
goto *(__instpat_end); \
} \
} while (0)
#define INSTPAT_START(name) { const void ** __instpat_end = &&concat(__instpat_end_, name);
#define INSTPAT_END(name) concat(__instpat_end_, name): ; }
#endif

View file

@ -0,0 +1,53 @@
/***************************************************************************************
* Copyright (c) 2014-2022 Zihao Yu, Nanjing University
*
* NEMU is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
* http://license.coscl.org.cn/MulanPSL2
*
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
*
* See the Mulan PSL v2 for more details.
***************************************************************************************/
#ifndef __CPU_DIFFTEST_H__
#define __CPU_DIFFTEST_H__
#include <common.h>
#include <difftest-def.h>
#ifdef CONFIG_DIFFTEST
void difftest_skip_ref();
void difftest_skip_dut(int nr_ref, int nr_dut);
void difftest_set_patch(void (*fn)(void *arg), void *arg);
void difftest_step(vaddr_t pc, vaddr_t npc);
void difftest_detach();
void difftest_attach();
#else
static inline void difftest_skip_ref() {}
static inline void difftest_skip_dut(int nr_ref, int nr_dut) {}
static inline void difftest_set_patch(void (*fn)(void *arg), void *arg) {}
static inline void difftest_step(vaddr_t pc, vaddr_t npc) {}
static inline void difftest_detach() {}
static inline void difftest_attach() {}
#endif
extern void (*ref_difftest_memcpy)(paddr_t addr, void *buf, size_t n, bool direction);
extern void (*ref_difftest_regcpy)(void *dut, bool direction);
extern void (*ref_difftest_exec)(uint64_t n);
extern void (*ref_difftest_raise_intr)(uint64_t NO);
static inline bool difftest_check_reg(const char *name, vaddr_t pc, word_t ref, word_t dut) {
if (ref != dut) {
Log("%s is different after executing instruction at pc = " FMT_WORD
", right = " FMT_WORD ", wrong = " FMT_WORD ", diff = " FMT_WORD,
name, pc, ref, dut, ref ^ dut);
return false;
}
return true;
}
#endif

26
nemu/include/cpu/ifetch.h Normal file
View file

@ -0,0 +1,26 @@
/***************************************************************************************
* Copyright (c) 2014-2022 Zihao Yu, Nanjing University
*
* NEMU is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
* http://license.coscl.org.cn/MulanPSL2
*
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
*
* See the Mulan PSL v2 for more details.
***************************************************************************************/
#ifndef __CPU_IFETCH_H__
#include <memory/vaddr.h>
static inline uint32_t inst_fetch(vaddr_t *pc, int len) {
uint32_t inst = vaddr_ifetch(*pc, len);
(*pc) += len;
return inst;
}
#endif

43
nemu/include/debug.h Normal file
View file

@ -0,0 +1,43 @@
/***************************************************************************************
* Copyright (c) 2014-2022 Zihao Yu, Nanjing University
*
* NEMU is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
* http://license.coscl.org.cn/MulanPSL2
*
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
*
* See the Mulan PSL v2 for more details.
***************************************************************************************/
#ifndef __DEBUG_H__
#define __DEBUG_H__
#include <common.h>
#include <stdio.h>
#include <utils.h>
#define Log(format, ...) \
_Log(ANSI_FMT("[%s:%d %s] " format, ANSI_FG_BLUE) "\n", \
__FILE__, __LINE__, __func__, ## __VA_ARGS__)
#define Assert(cond, format, ...) \
do { \
if (!(cond)) { \
MUXDEF(CONFIG_TARGET_AM, printf(ANSI_FMT(format, ANSI_FG_RED) "\n", ## __VA_ARGS__), \
(fflush(stdout), fprintf(stderr, ANSI_FMT(format, ANSI_FG_RED) "\n", ## __VA_ARGS__))); \
IFNDEF(CONFIG_TARGET_AM, extern FILE* log_fp; fflush(log_fp)); \
extern void assert_fail_msg(); \
assert_fail_msg(); \
assert(cond); \
} \
} while (0)
#define panic(format, ...) Assert(0, format, ## __VA_ARGS__)
#define TODO() panic("please implement me")
#endif

View file

@ -0,0 +1,24 @@
/***************************************************************************************
* Copyright (c) 2014-2022 Zihao Yu, Nanjing University
*
* NEMU is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
* http://license.coscl.org.cn/MulanPSL2
*
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
*
* See the Mulan PSL v2 for more details.
***************************************************************************************/
#ifndef __DEVICE_ALARM_H__
#define __DEVICE_ALARM_H__
#define TIMER_HZ 60
typedef void (*alarm_handler_t) ();
void add_alarm_handle(alarm_handler_t h);
#endif

56
nemu/include/device/map.h Normal file
View file

@ -0,0 +1,56 @@
/***************************************************************************************
* Copyright (c) 2014-2022 Zihao Yu, Nanjing University
*
* NEMU is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
* http://license.coscl.org.cn/MulanPSL2
*
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
*
* See the Mulan PSL v2 for more details.
***************************************************************************************/
#ifndef __DEVICE_MAP_H__
#define __DEVICE_MAP_H__
#include <cpu/difftest.h>
typedef void(*io_callback_t)(uint32_t, int, bool);
uint8_t* new_space(int size);
typedef struct {
const char *name;
// we treat ioaddr_t as paddr_t here
paddr_t low;
paddr_t high;
void *space;
io_callback_t callback;
} IOMap;
static inline bool map_inside(IOMap *map, paddr_t addr) {
return (addr >= map->low && addr <= map->high);
}
static inline int find_mapid_by_addr(IOMap *maps, int size, paddr_t addr) {
int i;
for (i = 0; i < size; i ++) {
if (map_inside(maps + i, addr)) {
difftest_skip_ref();
return i;
}
}
return -1;
}
void add_pio_map(const char *name, ioaddr_t addr,
void *space, uint32_t len, io_callback_t callback);
void add_mmio_map(const char *name, paddr_t addr,
void *space, uint32_t len, io_callback_t callback);
word_t map_read(paddr_t addr, int len, IOMap *map);
void map_write(paddr_t addr, int len, word_t data, IOMap *map);
#endif

View file

@ -0,0 +1,24 @@
/***************************************************************************************
* Copyright (c) 2014-2022 Zihao Yu, Nanjing University
*
* NEMU is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
* http://license.coscl.org.cn/MulanPSL2
*
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
*
* See the Mulan PSL v2 for more details.
***************************************************************************************/
#ifndef __DEVICE_MMIO_H__
#define __DEVICE_MMIO_H__
#include <common.h>
word_t mmio_read(paddr_t addr, int len);
void mmio_write(paddr_t addr, int len, word_t data);
#endif

View file

@ -0,0 +1,40 @@
/***************************************************************************************
* Copyright (c) 2014-2022 Zihao Yu, Nanjing University
*
* NEMU is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
* http://license.coscl.org.cn/MulanPSL2
*
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
*
* See the Mulan PSL v2 for more details.
***************************************************************************************/
#ifndef __DIFFTEST_DEF_H__
#define __DIFFTEST_DEF_H__
#include <stdint.h>
#include <macro.h>
#include <generated/autoconf.h>
#define __EXPORT __attribute__((visibility("default")))
enum { DIFFTEST_TO_DUT, DIFFTEST_TO_REF };
#if defined(CONFIG_ISA_x86)
# define DIFFTEST_REG_SIZE (sizeof(uint32_t) * 9) // GPRs + pc
#elif defined(CONFIG_ISA_mips32)
# define DIFFTEST_REG_SIZE (sizeof(uint32_t) * 38) // GPRs + status + lo + hi + badvaddr + cause + pc
#elif defined(CONFIG_ISA_riscv)
#define RISCV_GPR_TYPE MUXDEF(CONFIG_RV64, uint64_t, uint32_t)
#define RISCV_GPR_NUM MUXDEF(CONFIG_RVE , 16, 32)
#define DIFFTEST_REG_SIZE (sizeof(RISCV_GPR_TYPE) * (RISCV_GPR_NUM + 1)) // GPRs + pc
#elif defined(CONFIG_ISA_loongarch32r)
# define DIFFTEST_REG_SIZE (sizeof(uint32_t) * 33) // GPRs + pc
#else
# error Unsupport ISA
#endif
#endif

58
nemu/include/isa.h Normal file
View file

@ -0,0 +1,58 @@
/***************************************************************************************
* Copyright (c) 2014-2022 Zihao Yu, Nanjing University
*
* NEMU is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
* http://license.coscl.org.cn/MulanPSL2
*
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
*
* See the Mulan PSL v2 for more details.
***************************************************************************************/
#ifndef __ISA_H__
#define __ISA_H__
// Located at src/isa/$(GUEST_ISA)/include/isa-def.h
#include <isa-def.h>
// The macro `__GUEST_ISA__` is defined in $(CFLAGS).
// It will be expanded as "x86" or "mips32" ...
typedef concat(__GUEST_ISA__, _CPU_state) CPU_state;
typedef concat(__GUEST_ISA__, _ISADecodeInfo) ISADecodeInfo;
// monitor
extern unsigned char isa_logo[];
void init_isa();
// reg
extern CPU_state cpu;
void isa_reg_display();
word_t isa_reg_str2val(const char *name, bool *success);
// exec
struct Decode;
int isa_exec_once(struct Decode *s);
// memory
enum { MMU_DIRECT, MMU_TRANSLATE, MMU_FAIL };
enum { MEM_TYPE_IFETCH, MEM_TYPE_READ, MEM_TYPE_WRITE };
enum { MEM_RET_OK, MEM_RET_FAIL, MEM_RET_CROSS_PAGE };
#ifndef isa_mmu_check
int isa_mmu_check(vaddr_t vaddr, int len, int type);
#endif
paddr_t isa_mmu_translate(vaddr_t vaddr, int len, int type);
// interrupt/exception
vaddr_t isa_raise_intr(word_t NO, vaddr_t epc);
#define INTR_EMPTY ((word_t)-1)
word_t isa_query_intr();
// difftest
bool isa_difftest_checkregs(CPU_state *ref_r, vaddr_t pc);
void isa_difftest_attach();
#endif

110
nemu/include/macro.h Normal file
View file

@ -0,0 +1,110 @@
/***************************************************************************************
* Copyright (c) 2014-2022 Zihao Yu, Nanjing University
*
* NEMU is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
* http://license.coscl.org.cn/MulanPSL2
*
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
*
* See the Mulan PSL v2 for more details.
***************************************************************************************/
#ifndef __MACRO_H__
#define __MACRO_H__
#include <string.h>
// macro stringizing
#define str_temp(x) #x
#define str(x) str_temp(x)
// strlen() for string constant
#define STRLEN(CONST_STR) (sizeof(CONST_STR) - 1)
// calculate the length of an array
#define ARRLEN(arr) (int)(sizeof(arr) / sizeof(arr[0]))
// macro concatenation
#define concat_temp(x, y) x ## y
#define concat(x, y) concat_temp(x, y)
#define concat3(x, y, z) concat(concat(x, y), z)
#define concat4(x, y, z, w) concat3(concat(x, y), z, w)
#define concat5(x, y, z, v, w) concat4(concat(x, y), z, v, w)
// macro testing
// See https://stackoverflow.com/questions/26099745/test-if-preprocessor-symbol-is-defined-inside-macro
#define CHOOSE2nd(a, b, ...) b
#define MUX_WITH_COMMA(contain_comma, a, b) CHOOSE2nd(contain_comma a, b)
#define MUX_MACRO_PROPERTY(p, macro, a, b) MUX_WITH_COMMA(concat(p, macro), a, b)
// define placeholders for some property
#define __P_DEF_0 X,
#define __P_DEF_1 X,
#define __P_ONE_1 X,
#define __P_ZERO_0 X,
// define some selection functions based on the properties of BOOLEAN macro
#define MUXDEF(macro, X, Y) MUX_MACRO_PROPERTY(__P_DEF_, macro, X, Y)
#define MUXNDEF(macro, X, Y) MUX_MACRO_PROPERTY(__P_DEF_, macro, Y, X)
#define MUXONE(macro, X, Y) MUX_MACRO_PROPERTY(__P_ONE_, macro, X, Y)
#define MUXZERO(macro, X, Y) MUX_MACRO_PROPERTY(__P_ZERO_,macro, X, Y)
// test if a boolean macro is defined
#define ISDEF(macro) MUXDEF(macro, 1, 0)
// test if a boolean macro is undefined
#define ISNDEF(macro) MUXNDEF(macro, 1, 0)
// test if a boolean macro is defined to 1
#define ISONE(macro) MUXONE(macro, 1, 0)
// test if a boolean macro is defined to 0
#define ISZERO(macro) MUXZERO(macro, 1, 0)
// test if a macro of ANY type is defined
// NOTE1: it ONLY works inside a function, since it calls `strcmp()`
// NOTE2: macros defined to themselves (#define A A) will get wrong results
#define isdef(macro) (strcmp("" #macro, "" str(macro)) != 0)
// simplification for conditional compilation
#define __IGNORE(...)
#define __KEEP(...) __VA_ARGS__
// keep the code if a boolean macro is defined
#define IFDEF(macro, ...) MUXDEF(macro, __KEEP, __IGNORE)(__VA_ARGS__)
// keep the code if a boolean macro is undefined
#define IFNDEF(macro, ...) MUXNDEF(macro, __KEEP, __IGNORE)(__VA_ARGS__)
// keep the code if a boolean macro is defined to 1
#define IFONE(macro, ...) MUXONE(macro, __KEEP, __IGNORE)(__VA_ARGS__)
// keep the code if a boolean macro is defined to 0
#define IFZERO(macro, ...) MUXZERO(macro, __KEEP, __IGNORE)(__VA_ARGS__)
// functional-programming-like macro (X-macro)
// apply the function `f` to each element in the container `c`
// NOTE1: `c` should be defined as a list like:
// f(a0) f(a1) f(a2) ...
// NOTE2: each element in the container can be a tuple
#define MAP(c, f) c(f)
#define BITMASK(bits) ((1ull << (bits)) - 1)
#define BITS(x, hi, lo) (((x) >> (lo)) & BITMASK((hi) - (lo) + 1)) // similar to x[hi:lo] in verilog
#define SEXT(x, len) ({ struct { int64_t n : len; } __x = { .n = x }; (uint64_t)__x.n; })
#define ROUNDUP(a, sz) ((((uintptr_t)a) + (sz) - 1) & ~((sz) - 1))
#define ROUNDDOWN(a, sz) ((((uintptr_t)a)) & ~((sz) - 1))
#define PG_ALIGN __attribute((aligned(4096)))
#if !defined(likely)
#define likely(cond) __builtin_expect(cond, 1)
#define unlikely(cond) __builtin_expect(cond, 0)
#endif
// for AM IOE
#define io_read(reg) \
({ reg##_T __io_param; \
ioe_read(reg, &__io_param); \
__io_param; })
#define io_write(reg, ...) \
({ reg##_T __io_param = (reg##_T) { __VA_ARGS__ }; \
ioe_write(reg, &__io_param); })
#endif

View file

@ -0,0 +1,41 @@
/***************************************************************************************
* Copyright (c) 2014-2022 Zihao Yu, Nanjing University
*
* NEMU is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
* http://license.coscl.org.cn/MulanPSL2
*
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
*
* See the Mulan PSL v2 for more details.
***************************************************************************************/
#ifndef __MEMORY_HOST_H__
#define __MEMORY_HOST_H__
#include <common.h>
static inline word_t host_read(void *addr, int len) {
switch (len) {
case 1: return *(uint8_t *)addr;
case 2: return *(uint16_t *)addr;
case 4: return *(uint32_t *)addr;
IFDEF(CONFIG_ISA64, case 8: return *(uint64_t *)addr);
default: MUXDEF(CONFIG_RT_CHECK, assert(0), return 0);
}
}
static inline void host_write(void *addr, int len, word_t data) {
switch (len) {
case 1: *(uint8_t *)addr = data; return;
case 2: *(uint16_t *)addr = data; return;
case 4: *(uint32_t *)addr = data; return;
IFDEF(CONFIG_ISA64, case 8: *(uint64_t *)addr = data; return);
IFDEF(CONFIG_RT_CHECK, default: assert(0));
}
}
#endif

View file

@ -0,0 +1,37 @@
/***************************************************************************************
* Copyright (c) 2014-2022 Zihao Yu, Nanjing University
*
* NEMU is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
* http://license.coscl.org.cn/MulanPSL2
*
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
*
* See the Mulan PSL v2 for more details.
***************************************************************************************/
#ifndef __MEMORY_PADDR_H__
#define __MEMORY_PADDR_H__
#include <common.h>
#define PMEM_LEFT ((paddr_t)CONFIG_MBASE)
#define PMEM_RIGHT ((paddr_t)CONFIG_MBASE + CONFIG_MSIZE - 1)
#define RESET_VECTOR (PMEM_LEFT + CONFIG_PC_RESET_OFFSET)
/* convert the guest physical address in the guest program to host virtual address in NEMU */
uint8_t* guest_to_host(paddr_t paddr);
/* convert the host virtual address in NEMU to guest physical address in the guest program */
paddr_t host_to_guest(uint8_t *haddr);
static inline bool in_pmem(paddr_t addr) {
return addr - CONFIG_MBASE < CONFIG_MSIZE;
}
word_t paddr_read(paddr_t addr, int len);
void paddr_write(paddr_t addr, int len, word_t data);
#endif

View file

@ -0,0 +1,29 @@
/***************************************************************************************
* Copyright (c) 2014-2022 Zihao Yu, Nanjing University
*
* NEMU is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
* http://license.coscl.org.cn/MulanPSL2
*
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
*
* See the Mulan PSL v2 for more details.
***************************************************************************************/
#ifndef __MEMORY_VADDR_H__
#define __MEMORY_VADDR_H__
#include <common.h>
word_t vaddr_ifetch(vaddr_t addr, int len);
word_t vaddr_read(vaddr_t addr, int len);
void vaddr_write(vaddr_t addr, int len, word_t data);
#define PAGE_SHIFT 12
#define PAGE_SIZE (1ul << PAGE_SHIFT)
#define PAGE_MASK (PAGE_SIZE - 1)
#endif

77
nemu/include/utils.h Normal file
View file

@ -0,0 +1,77 @@
/***************************************************************************************
* Copyright (c) 2014-2022 Zihao Yu, Nanjing University
*
* NEMU is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
* http://license.coscl.org.cn/MulanPSL2
*
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
*
* See the Mulan PSL v2 for more details.
***************************************************************************************/
#ifndef __UTILS_H__
#define __UTILS_H__
#include <common.h>
// ----------- state -----------
enum { NEMU_RUNNING, NEMU_STOP, NEMU_END, NEMU_ABORT, NEMU_QUIT };
typedef struct {
int state;
vaddr_t halt_pc;
uint32_t halt_ret;
} NEMUState;
extern NEMUState nemu_state;
// ----------- timer -----------
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_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_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_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(...) \
do { \
printf(__VA_ARGS__); \
log_write(__VA_ARGS__); \
} while (0)
#endif

View file

@ -0,0 +1,172 @@
# riscv64 debian镜像制作
制作需要`qemu-riscv64-static`, 建议在debian 10或ubuntu 19.04的系统(可尝试使用docker)中进行操作.
* 创建空镜像和分区
```
dd if=/dev/zero of=debian.img bs=1G count=16 # 此处镜像大小为16GB
sudo cfdisk debian.img # 可创建两个分区, 第一个分区12GB作为rootfs, 第二个分区4GB作为swap
sudo losetup --partscan --show --find debian.img # 将debian.img作为loop设备
ls /dev/loop0* # 此时应该能看到/dev/loop0p1和/dev/loop0p2两个分区
```
* 创建ext4和swap文件系统
```
sudo mkfs.ext4 /dev/loop0p1
sudo mkswap /dev/loop0p2
```
* 挂载ext4分区
```
sudo mount /dev/loop0p1 /mnt
```
* 安装debian base system.
下面两条命令的操作来自[debian社区的安装指南](https://wiki.debian.org/RISC-V#debootstrap).
```
sudo apt-get install debootstrap qemu-user-static binfmt-support debian-ports-archive-keyring
sudo debootstrap --arch=riscv64 --keyring /usr/share/keyrings/debian-ports-archive-keyring.gpg --include=debian-ports-archive-keyring unstable /mnt http://deb.debian.org/debian-ports
```
若要安装x86系统, 则输入
```
sudo debootstrap --arch=i386 --keyring /usr/share/keyrings/debian-archive-keyring.gpg --include=debian-archive-keyring stable /mnt http://deb.debian.org/debian
```
* 进入镜像
```
sudo chroot /mnt /bin/bash
```
此时实际上是通过`qemu-riscv64-static`来执行镜像中的riscv64可执行文件.
* 安装所需工具(根据实际情况选择)
```
apt-get update
apt-get install systemd
apt-get install gcc build-essential
apt-get install tmux libreadline-dev
apt-get install net-tools openssh-server
# fix long delay of openssh server
apt-get install haveged
apt-get install sbt
```
* 修复`NO_PUBKEY E852514F5DF312F6`错误, 见[这里](https://www.reddit.com/r/RISCV/comments/sn0cph/sipeed_debian_the_following_signatures_couldnt_be/)
```
curl https://www.ports.debian.org/archive_2022.key | apt-key add -
```
* 同步时间
```
apt-get install ntpdate
ntpdate 0.asia.pool.ntp.org
```
* 在`/etc/fstab`中添加swap分区
```
/dev/mmcblk0p2 none swap sw 0 0
```
* 添加/root/目录的写和执行权限, 使得host上的普通用户可以访问
```
chmod a+w,a+x /root
```
* 在/root/目录下提前写入所需的测试文件, 如hello.c等.
* 在/root/.bashrc中添加如下内容, 可以实现登录后自动运行命令(根据实际情况修改测试的命令):
```
TMP_DIR=/run/mytest
cmd=(
# enbale swap
"swapon -a"
# show system information
"uname -a"
"cat /etc/issue"
"cat /proc/cpuinfo"
"df -ah"
"free -h"
# show time
"date"
"uptime"
# create and switch to tmp directory
"mkdir $TMP_DIR"
"cd $TMP_DIR"
# compile and run hello
"ls /root"
"ls /root/hello"
"cat /root/hello/hello.c"
"gcc -time /root/hello/hello.c -o $TMP_DIR/hello"
"ls -lh $TMP_DIR"
"$TMP_DIR/hello"
# compile and run x86-nemu
"ls /root/nemu"
"cp -r /root/nemu $TMP_DIR"
"export NEMU_HOME=$TMP_DIR/nemu"
"make -C $TMP_DIR/nemu ISA=x86"
"ls -lh /root/nemu-prog"
"file /root/nemu-prog/amtest-x86-nemu.elf"
"$TMP_DIR/nemu/build/x86-nemu --batch --mainargs=h /root/nemu-prog/amtest-x86-nemu.bin"
"file /root/nemu-prog/microbench-x86-nemu.elf"
"$TMP_DIR/nemu/build/x86-nemu --batch --mainargs=test /root/nemu-prog/microbench-x86-nemu.bin"
# compile and run riscv64-nemu
"make -C $TMP_DIR/nemu clean"
"make -C $TMP_DIR/nemu ISA=riscv64"
"$TMP_DIR/nemu/build/riscv64-nemu --batch /root/nemu-prog/linux-hello-riscv64-nemu.bin"
)
prompt="`whoami`@`hostname`:`pwd`#"
echo -e "\n============ Now running preset commands =============\n"
for ((i = 0; i < ${#cmd[@]}; i++)); do
c=${cmd[$i]}
echo "$prompt $c"
$c
echo ""
done
echo -e "\n============ End of preset commands =============\n"
/root/nemutrap/good-trap
```
* 若在不方便输入的环境(如NEMU, verilator仿真等)中测试, 可采用如下两种方式的其中一种, 避免登录时输入
* 通过紧急模式登录
```
cd /lib/systemd/system
# 通过紧急模式登录, 不启动非必须的服务, 节省将近一半的登录时间
ln -sf emergency.target default.target
# 跳过登录提示符, 直接运行bash
vim emergency.service
-ExecStart=-/lib/systemd/systemd-sulogin-shell emergency
+ExecStart=-/bin/bash
```
* 免密码登录, 见[这里](https://superuser.com/questions/969923/automatic-root-login-in-debian-8-0-console-only)
```
cd /lib/systemd/system
vim serial-getty@.service
-ExecStart=-/sbin/agetty -o '-p -- \\u' --keep-baud 115200,57600,38400,9600 %I $TERM
+ExecStart=-/sbin/agetty -a root --keep-baud 115200,57600,38400,9600 %I $TERM
```
* 退出并卸载镜像
```
exit # 之前通过`chroot`方式进入
sudo umount /mnt # 记得卸载! 在未卸载镜像的情况下通过可写方式再次打开`debian.img`(如作为qemu的文件系统), 镜像将会损坏!
sudo losetup -d /dev/loop0 # 删除loop设备
```
* 修改`nemu/src/device/sdcard.c`中`init_sdcard()`中打开的镜像文件路径, 即可使用制作的镜像.
在i9-9900k上测试, 约90s后看到debian的登录提示符.
* 当以可写方式启动镜像时, NEMU遇到错误或通过Ctrl+C直接退出NEMU时, 可能会损坏镜像的崩溃一致性, 此时可以通过fsck命令修复分区.
* 更多命令可参考[这里](https://github.com/carlosedp/riscv-bringup/blob/master/Debian-Rootfs-Guide.md).

View file

@ -0,0 +1 @@
This is a dummy ELF file used by qemu-system-mips32 to start.

View file

@ -0,0 +1,58 @@
# NEMU sdhost驱动
本驱动裁剪自`linux/drivers/mmc/host/bcm2835.c`, 去除了DMA和中断, 改成直接轮询, 处理器无需支持DMA和中断即可运行.
## 使用方法
* 将本目录下的`nemu.c`复制到`linux/drivers/mmc/host/`目录下
* 在`linux/drivers/mmc/host/Makefile`中添加一行`obj-y += nemu.o`
* 在menuconfig中取消`General setup -> Initial RAM filesystem and RAM disk (initramfs/initrd) support`
* 在menuconfig中选中`Device Drivers -> MMC/SD/SDIO card support`
* 在dts中加入以下节点
```
/ {
soc {
sdhci: mmc {
compatible = "nemu-sdhost";
reg = <0x0 0xa3000000 0x0 0x1000>;
};
};
chosen {
bootargs = "root=/dev/mmcblk0p1 rootfstype=ext4 ro rootwait earlycon";
};
};
```
## 在没有中断的处理器上访问SD卡
访问真实的SD卡需要等待一定的延迟, 这需要处理器的中断机制对内核支持计时的功能.
在没有中断机制的处理器上, 我们可以修改内核的部分代码, 使得无需等待这些延迟,
来达到确定性可重复的仿真效果.
具体只需修改以下文件:
```diff
--- linux/drivers/mmc/core/block.c
+++ linux/drivers/mmc/core/block.c
@@ -983,6 +983,7 @@ static int card_busy_detect(struct mmc_card *card, unsigned int timeout_ms,
int err = 0;
u32 status;
+ return err;
do {
bool done = time_after(jiffies, timeout);
--- linux/drivers/mmc/core/core.h
+++ linux/drivers/mmc/core/core.h
@@ -64,6 +64,7 @@ void mmc_set_initial_state(struct mmc_host *host);
static inline void mmc_delay(unsigned int ms)
{
+ return;
if (ms <= 20)
usleep_range(ms * 1000, ms * 1250);
else
```
注意: 上述修改仅能用于模拟和仿真, 修改后将不能在真实的SD卡上运行!!!

542
nemu/resource/sdcard/nemu.c Normal file
View file

@ -0,0 +1,542 @@
/*
* NEMU (NJU Emulator) sdhost driver.
*
* Author: Zihao Yu <yuzihao@ict.ac.cn>
*
* Based on
* bcm2835.c by Phil Elwell
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/device.h>
#include <linux/dmaengine.h>
#include <linux/dma-mapping.h>
#include <linux/err.h>
#include <linux/highmem.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/iopoll.h>
#include <linux/module.h>
#include <linux/of_address.h>
#include <linux/of_irq.h>
#include <linux/platform_device.h>
#include <linux/scatterlist.h>
#include <linux/time.h>
#include <linux/workqueue.h>
#include <linux/mmc/host.h>
#include <linux/mmc/mmc.h>
#include <linux/mmc/sd.h>
#define SDCMD 0x00 /* Command to SD card - 16 R/W */
#define SDARG 0x04 /* Argument to SD card - 32 R/W */
#define SDTOUT 0x08 /* Start value for timeout counter - 32 R/W */
#define SDCDIV 0x0c /* Start value for clock divider - 11 R/W */
#define SDRSP0 0x10 /* SD card response (31:0) - 32 R */
#define SDRSP1 0x14 /* SD card response (63:32) - 32 R */
#define SDRSP2 0x18 /* SD card response (95:64) - 32 R */
#define SDRSP3 0x1c /* SD card response (127:96) - 32 R */
#define SDHSTS 0x20 /* SD host status - 11 R/W */
#define SDVDD 0x30 /* SD card power control - 1 R/W */
#define SDEDM 0x34 /* Emergency Debug Mode - 13 R/W */
#define SDHCFG 0x38 /* Host configuration - 2 R/W */
#define SDHBCT 0x3c /* Host byte count (debug) - 32 R/W */
#define SDDATA 0x40 /* Data to/from SD card - 32 R/W */
#define SDHBLC 0x50 /* Host block count (SDIO/SDHC) - 9 R/W */
#define SDCMD_NEW_FLAG 0x8000
#define SDCMD_FAIL_FLAG 0x4000
#define SDCMD_BUSYWAIT 0x800
#define SDCMD_NO_RESPONSE 0x400
#define SDCMD_LONG_RESPONSE 0x200
#define SDCMD_WRITE_CMD 0x80
#define SDCMD_READ_CMD 0x40
#define SDCMD_CMD_MASK 0x3f
#define SDCDIV_MAX_CDIV 0x7ff
#define SDDATA_FIFO_WORDS 16
#define FIFO_READ_THRESHOLD 4
#define FIFO_WRITE_THRESHOLD 4
#define SDDATA_FIFO_PIO_BURST 8
#define PIO_THRESHOLD 1 /* Maximum block count for PIO (0 = always DMA) */
struct nemu_host {
spinlock_t lock;
struct mutex mutex;
void __iomem *ioaddr;
u32 phys_addr;
struct mmc_host *mmc;
struct platform_device *pdev;
int clock; /* Current clock speed */
unsigned int max_clk; /* Max possible freq */
struct sg_mapping_iter sg_miter; /* SG state for PIO */
unsigned int blocks; /* remaining PIO blocks */
struct mmc_request *mrq; /* Current request */
struct mmc_command *cmd; /* Current command */
struct mmc_data *data; /* Current data request */
bool data_complete:1;/* Data finished before cmd */
bool use_sbc:1; /* Send CMD23 */
};
static void nemu_reset(struct mmc_host *mmc)
{
}
static void nemu_finish_command(struct nemu_host *host);
static void nemu_transfer_block_pio(struct nemu_host *host, bool is_read)
{
unsigned long flags;
size_t blksize;
blksize = host->data->blksz;
local_irq_save(flags);
while (blksize) {
int copy_words;
size_t len;
u32 *buf;
if (!sg_miter_next(&host->sg_miter)) {
host->data->error = -EINVAL;
break;
}
len = min(host->sg_miter.length, blksize);
if (len % 4) {
host->data->error = -EINVAL;
break;
}
blksize -= len;
host->sg_miter.consumed = len;
buf = (u32 *)host->sg_miter.addr;
copy_words = len / 4;
while (copy_words) {
int burst_words, words;
u32 edm;
burst_words = min(SDDATA_FIFO_PIO_BURST, copy_words);
edm = (8 << 4);
if (is_read)
words = ((edm >> 4) & 0x1f);
else
words = SDDATA_FIFO_WORDS - ((edm >> 4) & 0x1f);
if (words < burst_words) {
continue;
} else if (words > copy_words) {
words = copy_words;
}
copy_words -= words;
while (words) {
if (is_read)
*(buf++) = readl(host->ioaddr + SDDATA);
else
writel(*(buf++), host->ioaddr + SDDATA);
words--;
}
}
}
sg_miter_stop(&host->sg_miter);
local_irq_restore(flags);
}
static void nemu_transfer_pio(struct nemu_host *host)
{
bool is_read = (host->data->flags & MMC_DATA_READ) != 0;
nemu_transfer_block_pio(host, is_read);
}
static
void nemu_prepare_data(struct nemu_host *host, struct mmc_command *cmd)
{
struct mmc_data *data = cmd->data;
int flags = SG_MITER_ATOMIC;
WARN_ON(host->data);
host->data = data;
if (!data)
return;
host->data_complete = false;
host->data->bytes_xfered = 0;
/* Use PIO */
if (data->flags & MMC_DATA_READ)
flags |= SG_MITER_TO_SG;
else
flags |= SG_MITER_FROM_SG;
sg_miter_start(&host->sg_miter, data->sg, data->sg_len, flags);
host->blocks = data->blocks;
}
static void nemu_finish_request(struct nemu_host *host)
{
struct mmc_request *mrq;
mrq = host->mrq;
host->mrq = NULL;
host->cmd = NULL;
host->data = NULL;
mmc_request_done(host->mmc, mrq);
}
static
bool nemu_send_command(struct nemu_host *host, struct mmc_command *cmd)
{
u32 sdcmd;
WARN_ON(host->cmd);
host->cmd = cmd;
nemu_prepare_data(host, cmd);
writel(cmd->arg, host->ioaddr + SDARG);
sdcmd = cmd->opcode & SDCMD_CMD_MASK;
if (!(cmd->flags & MMC_RSP_PRESENT)) {
sdcmd |= SDCMD_NO_RESPONSE;
} else {
if (cmd->flags & MMC_RSP_136)
sdcmd |= SDCMD_LONG_RESPONSE;
if (cmd->flags & MMC_RSP_BUSY) {
sdcmd |= SDCMD_BUSYWAIT;
}
}
if (cmd->data) {
if (cmd->data->flags & MMC_DATA_WRITE) {
sdcmd |= SDCMD_WRITE_CMD;
}
if (cmd->data->flags & MMC_DATA_READ)
sdcmd |= SDCMD_READ_CMD;
}
writel(sdcmd | SDCMD_NEW_FLAG, host->ioaddr + SDCMD);
return true;
}
static void nemu_transfer_complete(struct nemu_host *host)
{
struct mmc_data *data;
WARN_ON(!host->data_complete);
data = host->data;
host->data = NULL;
/* Need to send CMD12 if -
* a) open-ended multiblock transfer (no CMD23)
* b) error in multiblock transfer
*/
if (host->mrq->stop && (data->error || !host->use_sbc)) {
if (nemu_send_command(host, host->mrq->stop)) {
nemu_finish_command(host);
}
} else {
nemu_finish_request(host);
}
}
static void nemu_finish_data(struct nemu_host *host)
{
struct device *dev = &host->pdev->dev;
struct mmc_data *data;
data = host->data;
data->bytes_xfered = data->error ? 0 : (data->blksz * data->blocks);
host->data_complete = true;
if (host->cmd) {
/* Data managed to finish before the
* command completed. Make sure we do
* things in the proper order.
*/
dev_dbg(dev, "Finished early - HSTS %08x\n",
readl(host->ioaddr + SDHSTS));
} else {
nemu_transfer_complete(host);
}
}
static void nemu_finish_command(struct nemu_host *host)
{
struct mmc_command *cmd = host->cmd;
int i;
if (cmd->flags & MMC_RSP_PRESENT) {
if (cmd->flags & MMC_RSP_136) {
for (i = 0; i < 4; i++) {
cmd->resp[3 - i] =
readl(host->ioaddr + SDRSP0 + i * 4);
}
} else {
cmd->resp[0] = readl(host->ioaddr + SDRSP0);
}
}
if (cmd == host->mrq->sbc) {
/* Finished CMD23, now send actual command. */
host->cmd = NULL;
if (nemu_send_command(host, host->mrq->cmd)) {
if (host->data) {
// start PIO right now
for (i = 0; i < host->data->blocks; i ++) {
nemu_transfer_pio(host);
}
nemu_finish_data(host);
}
nemu_finish_command(host);
}
} else if (cmd == host->mrq->stop) {
/* Finished CMD12 */
nemu_finish_request(host);
} else {
/* Processed actual command. */
host->cmd = NULL;
if (!host->data) {
nemu_finish_request(host);
}
else if (host->data_complete) {
nemu_transfer_complete(host);
}
}
}
static void nemu_request(struct mmc_host *mmc, struct mmc_request *mrq)
{
struct nemu_host *host = mmc_priv(mmc);
struct device *dev = &host->pdev->dev;
/* Reset the error statuses in case this is a retry */
if (mrq->sbc)
mrq->sbc->error = 0;
if (mrq->cmd)
mrq->cmd->error = 0;
if (mrq->data)
mrq->data->error = 0;
if (mrq->stop)
mrq->stop->error = 0;
if (mrq->data && !is_power_of_2(mrq->data->blksz)) {
dev_err(dev, "unsupported block size (%d bytes)\n",
mrq->data->blksz);
if (mrq->cmd)
mrq->cmd->error = -EINVAL;
mmc_request_done(mmc, mrq);
return;
}
mutex_lock(&host->mutex);
WARN_ON(host->mrq);
host->mrq = mrq;
host->use_sbc = !!mrq->sbc && host->mrq->data &&
(host->mrq->data->flags & MMC_DATA_READ);
if (host->use_sbc) {
if (nemu_send_command(host, mrq->sbc)) {
nemu_finish_command(host);
}
} else if (mrq->cmd && nemu_send_command(host, mrq->cmd)) {
if (host->data) {
int i;
// start PIO right now
for (i = 0; i < host->data->blocks; i ++) {
nemu_transfer_pio(host);
}
nemu_finish_data(host);
}
nemu_finish_command(host);
}
mutex_unlock(&host->mutex);
}
static void nemu_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
{
}
static const struct mmc_host_ops nemu_ops = {
.request = nemu_request,
.set_ios = nemu_set_ios,
.hw_reset = nemu_reset,
};
static int nemu_add_host(struct nemu_host *host)
{
struct mmc_host *mmc = host->mmc;
struct device *dev = &host->pdev->dev;
int ret;
if (!mmc->f_max || mmc->f_max > host->max_clk)
mmc->f_max = host->max_clk;
mmc->f_min = host->max_clk / SDCDIV_MAX_CDIV;
mmc->max_busy_timeout = ~0 / (mmc->f_max / 1000);
dev_dbg(dev, "f_max %d, f_min %d, max_busy_timeout %d\n",
mmc->f_max, mmc->f_min, mmc->max_busy_timeout);
/* host controller capabilities */
mmc->caps |= MMC_CAP_SD_HIGHSPEED | MMC_CAP_MMC_HIGHSPEED |
MMC_CAP_NEEDS_POLL | MMC_CAP_HW_RESET | MMC_CAP_ERASE |
MMC_CAP_CMD23;
spin_lock_init(&host->lock);
mutex_init(&host->mutex);
mmc->max_segs = 128;
mmc->max_req_size = 524288;
mmc->max_seg_size = mmc->max_req_size;
mmc->max_blk_size = 1024;
mmc->max_blk_count = 65535;
/* report supported voltage ranges */
mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34;
ret = mmc_add_host(mmc);
if (ret) {
return ret;
}
dev_info(dev, "loaded - DMA %s\n", "disabled");
return 0;
}
static int nemu_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct resource *iomem;
struct nemu_host *host;
struct mmc_host *mmc;
const __be32 *regaddr_p;
int ret;
dev_dbg(dev, "%s\n", __func__);
mmc = mmc_alloc_host(sizeof(*host), dev);
if (!mmc)
return -ENOMEM;
mmc->ops = &nemu_ops;
host = mmc_priv(mmc);
host->mmc = mmc;
host->pdev = pdev;
spin_lock_init(&host->lock);
iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
host->ioaddr = devm_ioremap_resource(dev, iomem);
if (IS_ERR(host->ioaddr)) {
ret = PTR_ERR(host->ioaddr);
goto err;
}
/* Parse OF address directly to get the physical address for
* DMA to our registers.
*/
regaddr_p = of_get_address(pdev->dev.of_node, 0, NULL, NULL);
if (!regaddr_p) {
dev_err(dev, "Can't get phys address\n");
ret = -EINVAL;
goto err;
}
host->phys_addr = be32_to_cpup(regaddr_p);
host->max_clk = 1000000; //clk_get_rate(clk);
ret = mmc_of_parse(mmc);
if (ret)
goto err;
ret = nemu_add_host(host);
if (ret)
goto err;
platform_set_drvdata(pdev, host);
dev_dbg(dev, "%s -> OK\n", __func__);
return 0;
err:
dev_dbg(dev, "%s -> err %d\n", __func__, ret);
mmc_free_host(mmc);
return ret;
}
static int nemu_remove(struct platform_device *pdev)
{
struct nemu_host *host = platform_get_drvdata(pdev);
mmc_remove_host(host->mmc);
mmc_free_host(host->mmc);
platform_set_drvdata(pdev, NULL);
return 0;
}
static const struct of_device_id nemu_match[] = {
{ .compatible = "nemu-sdhost" },
{ }
};
MODULE_DEVICE_TABLE(of, nemu_match);
static struct platform_driver nemu_driver = {
.probe = nemu_probe,
.remove = nemu_remove,
.driver = {
.name = "sdhost-nemu",
.of_match_table = nemu_match,
},
};
module_platform_driver(nemu_driver);
MODULE_ALIAS("platform:sdhost-nemu");
MODULE_DESCRIPTION("NEMU SDHost driver");
MODULE_LICENSE("GPL v2");
MODULE_AUTHOR("Zihao Yu");

57
nemu/scripts/build.mk Normal file
View file

@ -0,0 +1,57 @@
.DEFAULT_GOAL = app
# Add necessary options if the target is a shared library
ifeq ($(SHARE),1)
SO = -so
CFLAGS += -fPIC -fvisibility=hidden
LDFLAGS += -shared -fPIC
endif
WORK_DIR = $(shell pwd)
BUILD_DIR = $(WORK_DIR)/build
INC_PATH := $(WORK_DIR)/include $(INC_PATH)
OBJ_DIR = $(BUILD_DIR)/obj-$(NAME)$(SO)
BINARY = $(BUILD_DIR)/$(NAME)$(SO)
# Compilation flags
ifeq ($(CC),clang)
CXX := clang++
else
CXX := g++
endif
LD := $(CXX)
INCLUDES = $(addprefix -I, $(INC_PATH))
CFLAGS := -O2 -MMD -Wall -Werror $(INCLUDES) $(CFLAGS)
LDFLAGS := -O2 $(LDFLAGS)
OBJS = $(SRCS:%.c=$(OBJ_DIR)/%.o) $(CXXSRC:%.cc=$(OBJ_DIR)/%.o)
# Compilation patterns
$(OBJ_DIR)/%.o: %.c
@echo + CC $<
@mkdir -p $(dir $@)
@$(CC) $(CFLAGS) -c -o $@ $<
$(call call_fixdep, $(@:.o=.d), $@)
$(OBJ_DIR)/%.o: %.cc
@echo + CXX $<
@mkdir -p $(dir $@)
@$(CXX) $(CFLAGS) $(CXXFLAGS) -c -o $@ $<
$(call call_fixdep, $(@:.o=.d), $@)
# Depencies
-include $(OBJS:.o=.d)
# Some convenient rules
.PHONY: app clean
app: $(BINARY)
$(BINARY):: $(OBJS) $(ARCHIVES)
@echo + LD $@
@$(LD) -o $@ $(OBJS) $(LDFLAGS) $(ARCHIVES) $(LIBS)
clean:
-rm -rf $(BUILD_DIR)

70
nemu/scripts/config.mk Normal file
View file

@ -0,0 +1,70 @@
#***************************************************************************************
# Copyright (c) 2014-2022 Zihao Yu, Nanjing University
#
# NEMU is licensed under Mulan PSL v2.
# You can use this software according to the terms and conditions of the Mulan PSL v2.
# You may obtain a copy of Mulan PSL v2 at:
# http://license.coscl.org.cn/MulanPSL2
#
# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
# EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
# MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
#
# See the Mulan PSL v2 for more details.
#**************************************************************************************/
COLOR_RED := $(shell echo "\033[1;31m")
COLOR_END := $(shell echo "\033[0m")
ifeq ($(wildcard .config),)
$(warning $(COLOR_RED)Warning: .config does not exists!$(COLOR_END))
$(warning $(COLOR_RED)To build the project, first run 'make menuconfig'.$(COLOR_END))
endif
Q := @
KCONFIG_PATH := $(NEMU_HOME)/tools/kconfig
FIXDEP_PATH := $(NEMU_HOME)/tools/fixdep
Kconfig := $(NEMU_HOME)/Kconfig
rm-distclean += include/generated include/config .config .config.old
silent := -s
CONF := $(KCONFIG_PATH)/build/conf
MCONF := $(KCONFIG_PATH)/build/mconf
FIXDEP := $(FIXDEP_PATH)/build/fixdep
$(CONF):
$(Q)$(MAKE) $(silent) -C $(KCONFIG_PATH) NAME=conf
$(MCONF):
$(Q)$(MAKE) $(silent) -C $(KCONFIG_PATH) NAME=mconf
$(FIXDEP):
$(Q)$(MAKE) $(silent) -C $(FIXDEP_PATH)
menuconfig: $(MCONF) $(CONF) $(FIXDEP)
$(Q)$(MCONF) $(Kconfig)
$(Q)$(CONF) $(silent) --syncconfig $(Kconfig)
savedefconfig: $(CONF)
$(Q)$< $(silent) --$@=configs/defconfig $(Kconfig)
%defconfig: $(CONF) $(FIXDEP)
$(Q)$< $(silent) --defconfig=configs/$@ $(Kconfig)
$(Q)$< $(silent) --syncconfig $(Kconfig)
.PHONY: menuconfig savedefconfig defconfig
# Help text used by make help
help:
@echo ' menuconfig - Update current config utilising a menu based program'
@echo ' savedefconfig - Save current config as configs/defconfig (minimal config)'
distclean: clean
-@rm -rf $(rm-distclean)
.PHONY: help distclean
define call_fixdep
@$(FIXDEP) $(1) $(2) unused > $(1).tmp
@mv $(1).tmp $(1)
endef

50
nemu/scripts/native.mk Normal file
View file

@ -0,0 +1,50 @@
#***************************************************************************************
# Copyright (c) 2014-2022 Zihao Yu, Nanjing University
#
# NEMU is licensed under Mulan PSL v2.
# You can use this software according to the terms and conditions of the Mulan PSL v2.
# You may obtain a copy of Mulan PSL v2 at:
# http://license.coscl.org.cn/MulanPSL2
#
# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
# EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
# MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
#
# See the Mulan PSL v2 for more details.
#**************************************************************************************/
-include $(NEMU_HOME)/../Makefile
include $(NEMU_HOME)/scripts/build.mk
include $(NEMU_HOME)/tools/difftest.mk
compile_git:
$(call git_commit, "compile NEMU")
$(BINARY):: compile_git
# Some convenient rules
override ARGS ?= --log=$(BUILD_DIR)/nemu-log.txt
override ARGS += $(ARGS_DIFF)
# Command to execute NEMU
IMG ?=
NEMU_EXEC := $(BINARY) $(ARGS) $(IMG)
run-env: $(BINARY) $(DIFF_REF_SO)
run: run-env
$(call git_commit, "run NEMU")
$(NEMU_EXEC)
gdb: run-env
$(call git_commit, "gdb NEMU")
gdb -s $(BINARY) --args $(NEMU_EXEC)
clean-tools = $(dir $(shell find ./tools -maxdepth 2 -mindepth 2 -name "Makefile"))
$(clean-tools):
-@$(MAKE) -s -C $@ clean
clean-tools: $(clean-tools)
clean-all: clean distclean clean-tools
.PHONY: run gdb run-env clean-tools clean-all $(clean-tools)

22
nemu/src/am-bin.S Normal file
View file

@ -0,0 +1,22 @@
/***************************************************************************************
* Copyright (c) 2014-2022 Zihao Yu, Nanjing University
*
* NEMU is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
* http://license.coscl.org.cn/MulanPSL2
*
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
*
* See the Mulan PSL v2 for more details.
***************************************************************************************/
.section .rodata
.globl bin_start, bin_end
bin_start:
#ifdef BIN_PATH
.incbin BIN_PATH
#endif
bin_end:

128
nemu/src/cpu/cpu-exec.c Normal file
View file

@ -0,0 +1,128 @@
/***************************************************************************************
* Copyright (c) 2014-2022 Zihao Yu, Nanjing University
*
* NEMU is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
* http://license.coscl.org.cn/MulanPSL2
*
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
*
* See the Mulan PSL v2 for more details.
***************************************************************************************/
#include <cpu/cpu.h>
#include <cpu/decode.h>
#include <cpu/difftest.h>
#include <locale.h>
/* The assembly code of instructions executed is only output to the screen
* when the number of instructions executed is less than this value.
* This is useful when you use the `si' command.
* You can modify this value as you want.
*/
#define MAX_INST_TO_PRINT 10
CPU_state cpu = {};
uint64_t g_nr_guest_inst = 0;
static uint64_t g_timer = 0; // unit: us
static bool g_print_step = false;
void device_update();
static void trace_and_difftest(Decode *_this, vaddr_t dnpc) {
#ifdef CONFIG_ITRACE_COND
if (ITRACE_COND) { log_write("%s\n", _this->logbuf); }
#endif
if (g_print_step) { IFDEF(CONFIG_ITRACE, puts(_this->logbuf)); }
IFDEF(CONFIG_DIFFTEST, difftest_step(_this->pc, dnpc));
}
static void exec_once(Decode *s, vaddr_t pc) {
s->pc = pc;
s->snpc = pc;
isa_exec_once(s);
cpu.pc = s->dnpc;
#ifdef CONFIG_ITRACE
char *p = s->logbuf;
p += snprintf(p, sizeof(s->logbuf), FMT_WORD ":", s->pc);
int ilen = s->snpc - s->pc;
int i;
uint8_t *inst = (uint8_t *)&s->isa.inst.val;
for (i = ilen - 1; i >= 0; i --) {
p += snprintf(p, 4, " %02x", inst[i]);
}
int ilen_max = MUXDEF(CONFIG_ISA_x86, 8, 4);
int space_len = ilen_max - ilen;
if (space_len < 0) space_len = 0;
space_len = space_len * 3 + 1;
memset(p, ' ', space_len);
p += space_len;
#ifndef CONFIG_ISA_loongarch32r
void disassemble(char *str, int size, uint64_t pc, uint8_t *code, int nbyte);
disassemble(p, s->logbuf + sizeof(s->logbuf) - p,
MUXDEF(CONFIG_ISA_x86, s->snpc, s->pc), (uint8_t *)&s->isa.inst.val, ilen);
#else
p[0] = '\0'; // the upstream llvm does not support loongarch32r
#endif
#endif
}
static void execute(uint64_t n) {
Decode s;
for (;n > 0; n --) {
exec_once(&s, cpu.pc);
g_nr_guest_inst ++;
trace_and_difftest(&s, cpu.pc);
if (nemu_state.state != NEMU_RUNNING) break;
IFDEF(CONFIG_DEVICE, device_update());
}
}
static void statistic() {
IFNDEF(CONFIG_TARGET_AM, setlocale(LC_NUMERIC, ""));
#define NUMBERIC_FMT MUXDEF(CONFIG_TARGET_AM, "%", "%'") PRIu64
Log("host time spent = " NUMBERIC_FMT " us", g_timer);
Log("total guest instructions = " NUMBERIC_FMT, g_nr_guest_inst);
if (g_timer > 0) Log("simulation frequency = " NUMBERIC_FMT " inst/s", g_nr_guest_inst * 1000000 / g_timer);
else Log("Finish running in less than 1 us and can not calculate the simulation frequency");
}
void assert_fail_msg() {
isa_reg_display();
statistic();
}
/* Simulate how the CPU works. */
void cpu_exec(uint64_t n) {
g_print_step = (n < MAX_INST_TO_PRINT);
switch (nemu_state.state) {
case NEMU_END: case NEMU_ABORT:
printf("Program execution has ended. To restart the program, exit NEMU and run again.\n");
return;
default: nemu_state.state = NEMU_RUNNING;
}
uint64_t timer_start = get_time();
execute(n);
uint64_t timer_end = get_time();
g_timer += timer_end - timer_start;
switch (nemu_state.state) {
case NEMU_RUNNING: nemu_state.state = NEMU_STOP; break;
case NEMU_END: case NEMU_ABORT:
Log("nemu: %s at pc = " FMT_WORD,
(nemu_state.state == NEMU_ABORT ? ANSI_FMT("ABORT", ANSI_FG_RED) :
(nemu_state.halt_ret == 0 ? ANSI_FMT("HIT GOOD TRAP", ANSI_FG_GREEN) :
ANSI_FMT("HIT BAD TRAP", ANSI_FG_RED))),
nemu_state.halt_pc);
// fall through
case NEMU_QUIT: statistic();
}
}

132
nemu/src/cpu/difftest/dut.c Normal file
View file

@ -0,0 +1,132 @@
/***************************************************************************************
* Copyright (c) 2014-2022 Zihao Yu, Nanjing University
*
* NEMU is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
* http://license.coscl.org.cn/MulanPSL2
*
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
*
* See the Mulan PSL v2 for more details.
***************************************************************************************/
#include <dlfcn.h>
#include <isa.h>
#include <cpu/cpu.h>
#include <memory/paddr.h>
#include <utils.h>
#include <difftest-def.h>
void (*ref_difftest_memcpy)(paddr_t addr, void *buf, size_t n, bool direction) = NULL;
void (*ref_difftest_regcpy)(void *dut, bool direction) = NULL;
void (*ref_difftest_exec)(uint64_t n) = NULL;
void (*ref_difftest_raise_intr)(uint64_t NO) = NULL;
#ifdef CONFIG_DIFFTEST
static bool is_skip_ref = false;
static int skip_dut_nr_inst = 0;
// this is used to let ref skip instructions which
// can not produce consistent behavior with NEMU
void difftest_skip_ref() {
is_skip_ref = true;
// If such an instruction is one of the instruction packing in QEMU
// (see below), we end the process of catching up with QEMU's pc to
// keep the consistent behavior in our best.
// Note that this is still not perfect: if the packed instructions
// already write some memory, and the incoming instruction in NEMU
// will load that memory, we will encounter false negative. But such
// situation is infrequent.
skip_dut_nr_inst = 0;
}
// this is used to deal with instruction packing in QEMU.
// Sometimes letting QEMU step once will execute multiple instructions.
// We should skip checking until NEMU's pc catches up with QEMU's pc.
// The semantic is
// Let REF run `nr_ref` instructions first.
// We expect that DUT will catch up with REF within `nr_dut` instructions.
void difftest_skip_dut(int nr_ref, int nr_dut) {
skip_dut_nr_inst += nr_dut;
while (nr_ref -- > 0) {
ref_difftest_exec(1);
}
}
void init_difftest(char *ref_so_file, long img_size, int port) {
assert(ref_so_file != NULL);
void *handle;
handle = dlopen(ref_so_file, RTLD_LAZY);
assert(handle);
ref_difftest_memcpy = dlsym(handle, "difftest_memcpy");
assert(ref_difftest_memcpy);
ref_difftest_regcpy = dlsym(handle, "difftest_regcpy");
assert(ref_difftest_regcpy);
ref_difftest_exec = dlsym(handle, "difftest_exec");
assert(ref_difftest_exec);
ref_difftest_raise_intr = dlsym(handle, "difftest_raise_intr");
assert(ref_difftest_raise_intr);
void (*ref_difftest_init)(int) = dlsym(handle, "difftest_init");
assert(ref_difftest_init);
Log("Differential testing: %s", ANSI_FMT("ON", ANSI_FG_GREEN));
Log("The result of every instruction will be compared with %s. "
"This will help you a lot for debugging, but also significantly reduce the performance. "
"If it is not necessary, you can turn it off in menuconfig.", ref_so_file);
ref_difftest_init(port);
ref_difftest_memcpy(RESET_VECTOR, guest_to_host(RESET_VECTOR), img_size, DIFFTEST_TO_REF);
ref_difftest_regcpy(&cpu, DIFFTEST_TO_REF);
}
static void checkregs(CPU_state *ref, vaddr_t pc) {
if (!isa_difftest_checkregs(ref, pc)) {
nemu_state.state = NEMU_ABORT;
nemu_state.halt_pc = pc;
isa_reg_display();
}
}
void difftest_step(vaddr_t pc, vaddr_t npc) {
CPU_state ref_r;
if (skip_dut_nr_inst > 0) {
ref_difftest_regcpy(&ref_r, DIFFTEST_TO_DUT);
if (ref_r.pc == npc) {
skip_dut_nr_inst = 0;
checkregs(&ref_r, npc);
return;
}
skip_dut_nr_inst --;
if (skip_dut_nr_inst == 0)
panic("can not catch up with ref.pc = " FMT_WORD " at pc = " FMT_WORD, ref_r.pc, pc);
return;
}
if (is_skip_ref) {
// to skip the checking of an instruction, just copy the reg state to reference design
ref_difftest_regcpy(&cpu, DIFFTEST_TO_REF);
is_skip_ref = false;
return;
}
ref_difftest_exec(1);
ref_difftest_regcpy(&ref_r, DIFFTEST_TO_DUT);
checkregs(&ref_r, pc);
}
#else
void init_difftest(char *ref_so_file, long img_size, int port) { }
#endif

View file

@ -0,0 +1,42 @@
/***************************************************************************************
* Copyright (c) 2014-2022 Zihao Yu, Nanjing University
*
* NEMU is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
* http://license.coscl.org.cn/MulanPSL2
*
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
*
* See the Mulan PSL v2 for more details.
***************************************************************************************/
#include <isa.h>
#include <cpu/cpu.h>
#include <difftest-def.h>
#include <memory/paddr.h>
__EXPORT void difftest_memcpy(paddr_t addr, void *buf, size_t n, bool direction) {
assert(0);
}
__EXPORT void difftest_regcpy(void *dut, bool direction) {
assert(0);
}
__EXPORT void difftest_exec(uint64_t n) {
assert(0);
}
__EXPORT void difftest_raise_intr(word_t NO) {
assert(0);
}
__EXPORT void difftest_init(int port) {
void init_mem();
init_mem();
/* Perform ISA dependent initialization. */
init_isa();
}

154
nemu/src/device/Kconfig Normal file
View file

@ -0,0 +1,154 @@
menuconfig DEVICE
depends on !TARGET_SHARE
bool "Devices"
default n
help
Provide device support for NEMU.
if DEVICE
config HAS_PORT_IO
bool
default y if ISA_x86
default n
menuconfig HAS_SERIAL
bool "Enable serial"
default y
if HAS_SERIAL
config SERIAL_PORT
depends on HAS_PORT_IO
hex "Port address of the serial controller"
default 0x3f8
config SERIAL_MMIO
hex "MMIO address of the serial controller"
default 0xa00003f8
config SERIAL_INPUT_FIFO
bool "Enable input FIFO with /tmp/nemu.serial"
default n
endif # HAS_SERIAL
menuconfig HAS_TIMER
bool "Enable timer"
default y
if HAS_TIMER
config RTC_PORT
depends on HAS_PORT_IO
hex "Port address of the timer"
default 0x48
config RTC_MMIO
hex "MMIO address of the timer"
default 0xa0000048
endif # HAS_TIMER
menuconfig HAS_KEYBOARD
bool "Enable keyboard"
default y
if HAS_KEYBOARD
config I8042_DATA_PORT
depends on HAS_PORT_IO
hex "Port address of the keyboard controller"
default 0x60
config I8042_DATA_MMIO
hex "MMIO address of the keyboard controller"
default 0xa0000060
endif # HAS_KEYBOARD
menuconfig HAS_VGA
bool "Enable VGA"
default y
if HAS_VGA
config FB_ADDR
hex "Physical address of the VGA frame buffer"
default 0xa1000000
config VGA_CTL_PORT
depends on HAS_PORT_IO
hex "Port address of the VGA controller"
default 0x100
config VGA_CTL_MMIO
hex "MMIO address of the VGA controller"
default 0xa0000100
config VGA_SHOW_SCREEN
bool "Enable SDL SCREEN"
default y
choice
prompt "Screen Size"
default VGA_SIZE_400x300
config VGA_SIZE_400x300
bool "400 x 300"
config VGA_SIZE_800x600
bool "800 x 600"
endchoice
endif # HAS_VGA
if !TARGET_AM
menuconfig HAS_AUDIO
bool "Enable audio"
default y
if HAS_AUDIO
config SB_ADDR
hex "Physical address of the audio stream buffer"
default 0xa1200000
config SB_SIZE
hex "Size of the audio stream buffer"
default 0x10000
config AUDIO_CTL_PORT
depends on HAS_PORT_IO
hex "Port address of the audio controller"
default 0x200
config AUDIO_CTL_MMIO
hex "MMIO address of the audio controller"
default 0xa0000200
endif # HAS_AUDIO
menuconfig HAS_DISK
bool "Enable disk"
default y
if HAS_DISK
config DISK_CTL_PORT
depends on HAS_PORT_IO
hex "Port address of the disk controller"
default 0x300
config DISK_CTL_MMIO
hex "MMIO address of the disk controller"
default 0xa0000300
config DISK_IMG_PATH
string "The path of disk image"
default ""
endif # HAS_DISK
menuconfig HAS_SDCARD
bool "Enable sdcard"
default n
if HAS_SDCARD
config SDCARD_CTL_MMIO
hex "MMIO address of the sdcard controller"
default 0xa3000000
config SDCARD_IMG_PATH
string "The path of sdcard image"
default ""
endif # HAS_SDCARD
endif
endif # DEVICE

51
nemu/src/device/alarm.c Normal file
View file

@ -0,0 +1,51 @@
/***************************************************************************************
* Copyright (c) 2014-2022 Zihao Yu, Nanjing University
*
* NEMU is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
* http://license.coscl.org.cn/MulanPSL2
*
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
*
* See the Mulan PSL v2 for more details.
***************************************************************************************/
#include <common.h>
#include <device/alarm.h>
#include <sys/time.h>
#include <signal.h>
#define MAX_HANDLER 8
static alarm_handler_t handler[MAX_HANDLER] = {};
static int idx = 0;
void add_alarm_handle(alarm_handler_t h) {
assert(idx < MAX_HANDLER);
handler[idx ++] = h;
}
static void alarm_sig_handler(int signum) {
int i;
for (i = 0; i < idx; i ++) {
handler[i]();
}
}
void init_alarm() {
struct sigaction s;
memset(&s, 0, sizeof(s));
s.sa_handler = alarm_sig_handler;
int ret = sigaction(SIGVTALRM, &s, NULL);
Assert(ret == 0, "Can not set signal handler");
struct itimerval it = {};
it.it_value.tv_sec = 0;
it.it_value.tv_usec = 1000000 / TIMER_HZ;
it.it_interval = it.it_value;
ret = setitimer(ITIMER_VIRTUAL, &it, NULL);
Assert(ret == 0, "Can not set timer");
}

47
nemu/src/device/audio.c Normal file
View file

@ -0,0 +1,47 @@
/***************************************************************************************
* Copyright (c) 2014-2022 Zihao Yu, Nanjing University
*
* NEMU is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
* http://license.coscl.org.cn/MulanPSL2
*
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
*
* See the Mulan PSL v2 for more details.
***************************************************************************************/
#include <common.h>
#include <device/map.h>
#include <SDL2/SDL.h>
enum {
reg_freq,
reg_channels,
reg_samples,
reg_sbuf_size,
reg_init,
reg_count,
nr_reg
};
static uint8_t *sbuf = NULL;
static uint32_t *audio_base = NULL;
static void audio_io_handler(uint32_t offset, int len, bool is_write) {
}
void init_audio() {
uint32_t space_size = sizeof(uint32_t) * nr_reg;
audio_base = (uint32_t *)new_space(space_size);
#ifdef CONFIG_HAS_PORT_IO
add_pio_map ("audio", CONFIG_AUDIO_CTL_PORT, audio_base, space_size, audio_io_handler);
#else
add_mmio_map("audio", CONFIG_AUDIO_CTL_MMIO, audio_base, space_size, audio_io_handler);
#endif
sbuf = (uint8_t *)new_space(CONFIG_SB_SIZE);
add_mmio_map("audio-sbuf", CONFIG_SB_ADDR, sbuf, CONFIG_SB_SIZE, NULL);
}

89
nemu/src/device/device.c Normal file
View file

@ -0,0 +1,89 @@
/***************************************************************************************
* Copyright (c) 2014-2022 Zihao Yu, Nanjing University
*
* NEMU is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
* http://license.coscl.org.cn/MulanPSL2
*
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
*
* See the Mulan PSL v2 for more details.
***************************************************************************************/
#include <common.h>
#include <utils.h>
#include <device/alarm.h>
#ifndef CONFIG_TARGET_AM
#include <SDL2/SDL.h>
#endif
void init_map();
void init_serial();
void init_timer();
void init_vga();
void init_i8042();
void init_audio();
void init_disk();
void init_sdcard();
void init_alarm();
void send_key(uint8_t, bool);
void vga_update_screen();
void device_update() {
static uint64_t last = 0;
uint64_t now = get_time();
if (now - last < 1000000 / TIMER_HZ) {
return;
}
last = now;
IFDEF(CONFIG_HAS_VGA, vga_update_screen());
#ifndef CONFIG_TARGET_AM
SDL_Event event;
while (SDL_PollEvent(&event)) {
switch (event.type) {
case SDL_QUIT:
nemu_state.state = NEMU_QUIT;
break;
#ifdef CONFIG_HAS_KEYBOARD
// If a key was pressed
case SDL_KEYDOWN:
case SDL_KEYUP: {
uint8_t k = event.key.keysym.scancode;
bool is_keydown = (event.key.type == SDL_KEYDOWN);
send_key(k, is_keydown);
break;
}
#endif
default: break;
}
}
#endif
}
void sdl_clear_event_queue() {
#ifndef CONFIG_TARGET_AM
SDL_Event event;
while (SDL_PollEvent(&event));
#endif
}
void init_device() {
IFDEF(CONFIG_TARGET_AM, ioe_init());
init_map();
IFDEF(CONFIG_HAS_SERIAL, init_serial());
IFDEF(CONFIG_HAS_TIMER, init_timer());
IFDEF(CONFIG_HAS_VGA, init_vga());
IFDEF(CONFIG_HAS_KEYBOARD, init_i8042());
IFDEF(CONFIG_HAS_AUDIO, init_audio());
IFDEF(CONFIG_HAS_DISK, init_disk());
IFDEF(CONFIG_HAS_SDCARD, init_sdcard());
IFNDEF(CONFIG_TARGET_AM, init_alarm());
}

19
nemu/src/device/disk.c Normal file
View file

@ -0,0 +1,19 @@
/***************************************************************************************
* Copyright (c) 2014-2022 Zihao Yu, Nanjing University
*
* NEMU is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
* http://license.coscl.org.cn/MulanPSL2
*
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
*
* See the Mulan PSL v2 for more details.
***************************************************************************************/
#include <device/map.h>
void init_disk() {
}

View file

@ -0,0 +1,32 @@
#***************************************************************************************
# Copyright (c) 2014-2022 Zihao Yu, Nanjing University
#
# NEMU is licensed under Mulan PSL v2.
# You can use this software according to the terms and conditions of the Mulan PSL v2.
# You may obtain a copy of Mulan PSL v2 at:
# http://license.coscl.org.cn/MulanPSL2
#
# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
# EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
# MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
#
# See the Mulan PSL v2 for more details.
#**************************************************************************************/
DIRS-y += src/device/io
SRCS-$(CONFIG_DEVICE) += src/device/device.c src/device/alarm.c src/device/intr.c
SRCS-$(CONFIG_HAS_SERIAL) += src/device/serial.c
SRCS-$(CONFIG_HAS_TIMER) += src/device/timer.c
SRCS-$(CONFIG_HAS_KEYBOARD) += src/device/keyboard.c
SRCS-$(CONFIG_HAS_VGA) += src/device/vga.c
SRCS-$(CONFIG_HAS_AUDIO) += src/device/audio.c
SRCS-$(CONFIG_HAS_DISK) += src/device/disk.c
SRCS-$(CONFIG_HAS_SDCARD) += src/device/sdcard.c
SRCS-BLACKLIST-$(CONFIG_TARGET_AM) += src/device/alarm.c
ifdef CONFIG_DEVICE
ifndef CONFIG_TARGET_AM
LIBS += -lSDL2
endif
endif

19
nemu/src/device/intr.c Normal file
View file

@ -0,0 +1,19 @@
/***************************************************************************************
* Copyright (c) 2014-2022 Zihao Yu, Nanjing University
*
* NEMU is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
* http://license.coscl.org.cn/MulanPSL2
*
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
*
* See the Mulan PSL v2 for more details.
***************************************************************************************/
#include <isa.h>
void dev_raise_intr() {
}

70
nemu/src/device/io/map.c Normal file
View file

@ -0,0 +1,70 @@
/***************************************************************************************
* Copyright (c) 2014-2022 Zihao Yu, Nanjing University
*
* NEMU is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
* http://license.coscl.org.cn/MulanPSL2
*
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
*
* See the Mulan PSL v2 for more details.
***************************************************************************************/
#include <isa.h>
#include <memory/host.h>
#include <memory/vaddr.h>
#include <device/map.h>
#define IO_SPACE_MAX (2 * 1024 * 1024)
static uint8_t *io_space = NULL;
static uint8_t *p_space = NULL;
uint8_t* new_space(int size) {
uint8_t *p = p_space;
// page aligned;
size = (size + (PAGE_SIZE - 1)) & ~PAGE_MASK;
p_space += size;
assert(p_space - io_space < IO_SPACE_MAX);
return p;
}
static void check_bound(IOMap *map, paddr_t addr) {
if (map == NULL) {
Assert(map != NULL, "address (" FMT_PADDR ") is out of bound at pc = " FMT_WORD, addr, cpu.pc);
} else {
Assert(addr <= map->high && addr >= map->low,
"address (" FMT_PADDR ") is out of bound {%s} [" FMT_PADDR ", " FMT_PADDR "] at pc = " FMT_WORD,
addr, map->name, map->low, map->high, cpu.pc);
}
}
static void invoke_callback(io_callback_t c, paddr_t offset, int len, bool is_write) {
if (c != NULL) { c(offset, len, is_write); }
}
void init_map() {
io_space = malloc(IO_SPACE_MAX);
assert(io_space);
p_space = io_space;
}
word_t map_read(paddr_t addr, int len, IOMap *map) {
assert(len >= 1 && len <= 8);
check_bound(map, addr);
paddr_t offset = addr - map->low;
invoke_callback(map->callback, offset, len, false); // prepare data to read
word_t ret = host_read(map->space + offset, len);
return ret;
}
void map_write(paddr_t addr, int len, word_t data, IOMap *map) {
assert(len >= 1 && len <= 8);
check_bound(map, addr);
paddr_t offset = addr - map->low;
host_write(map->space + offset, len, data);
invoke_callback(map->callback, offset, len, true);
}

63
nemu/src/device/io/mmio.c Normal file
View file

@ -0,0 +1,63 @@
/***************************************************************************************
* Copyright (c) 2014-2022 Zihao Yu, Nanjing University
*
* NEMU is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
* http://license.coscl.org.cn/MulanPSL2
*
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
*
* See the Mulan PSL v2 for more details.
***************************************************************************************/
#include <device/map.h>
#include <memory/paddr.h>
#define NR_MAP 16
static IOMap maps[NR_MAP] = {};
static int nr_map = 0;
static IOMap* fetch_mmio_map(paddr_t addr) {
int mapid = find_mapid_by_addr(maps, nr_map, addr);
return (mapid == -1 ? NULL : &maps[mapid]);
}
static void report_mmio_overlap(const char *name1, paddr_t l1, paddr_t r1,
const char *name2, paddr_t l2, paddr_t r2) {
panic("MMIO region %s@[" FMT_PADDR ", " FMT_PADDR "] is overlapped "
"with %s@[" FMT_PADDR ", " FMT_PADDR "]", name1, l1, r1, name2, l2, r2);
}
/* device interface */
void add_mmio_map(const char *name, paddr_t addr, void *space, uint32_t len, io_callback_t callback) {
assert(nr_map < NR_MAP);
paddr_t left = addr, right = addr + len - 1;
if (in_pmem(left) || in_pmem(right)) {
report_mmio_overlap(name, left, right, "pmem", PMEM_LEFT, PMEM_RIGHT);
}
for (int i = 0; i < nr_map; i++) {
if (left <= maps[i].high && right >= maps[i].low) {
report_mmio_overlap(name, left, right, maps[i].name, maps[i].low, maps[i].high);
}
}
maps[nr_map] = (IOMap){ .name = name, .low = addr, .high = addr + len - 1,
.space = space, .callback = callback };
Log("Add mmio map '%s' at [" FMT_PADDR ", " FMT_PADDR "]",
maps[nr_map].name, maps[nr_map].low, maps[nr_map].high);
nr_map ++;
}
/* bus interface */
word_t mmio_read(paddr_t addr, int len) {
return map_read(addr, len, fetch_mmio_map(addr));
}
void mmio_write(paddr_t addr, int len, word_t data) {
map_write(addr, len, data, fetch_mmio_map(addr));
}

View file

@ -0,0 +1,49 @@
/***************************************************************************************
* Copyright (c) 2014-2022 Zihao Yu, Nanjing University
*
* NEMU is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
* http://license.coscl.org.cn/MulanPSL2
*
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
*
* See the Mulan PSL v2 for more details.
***************************************************************************************/
#include <device/map.h>
#define PORT_IO_SPACE_MAX 65535
#define NR_MAP 16
static IOMap maps[NR_MAP] = {};
static int nr_map = 0;
/* device interface */
void add_pio_map(const char *name, ioaddr_t addr, void *space, uint32_t len, io_callback_t callback) {
assert(nr_map < NR_MAP);
assert(addr + len <= PORT_IO_SPACE_MAX);
maps[nr_map] = (IOMap){ .name = name, .low = addr, .high = addr + len - 1,
.space = space, .callback = callback };
Log("Add port-io map '%s' at [" FMT_PADDR ", " FMT_PADDR "]",
maps[nr_map].name, maps[nr_map].low, maps[nr_map].high);
nr_map ++;
}
/* CPU interface */
uint32_t pio_read(ioaddr_t addr, int len) {
assert(addr + len - 1 < PORT_IO_SPACE_MAX);
int mapid = find_mapid_by_addr(maps, nr_map, addr);
assert(mapid != -1);
return map_read(addr, len, &maps[mapid]);
}
void pio_write(ioaddr_t addr, int len, uint32_t data) {
assert(addr + len - 1 < PORT_IO_SPACE_MAX);
int mapid = find_mapid_by_addr(maps, nr_map, addr);
assert(mapid != -1);
map_write(addr, len, data, &maps[mapid]);
}

100
nemu/src/device/keyboard.c Normal file
View file

@ -0,0 +1,100 @@
/***************************************************************************************
* Copyright (c) 2014-2022 Zihao Yu, Nanjing University
*
* NEMU is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
* http://license.coscl.org.cn/MulanPSL2
*
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
*
* See the Mulan PSL v2 for more details.
***************************************************************************************/
#include <device/map.h>
#include <utils.h>
#define KEYDOWN_MASK 0x8000
#ifndef CONFIG_TARGET_AM
#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_KEY_NAME(k) NEMU_KEY_ ## k,
enum {
NEMU_KEY_NONE = 0,
MAP(NEMU_KEYS, NEMU_KEY_NAME)
};
#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)
}
#define KEY_QUEUE_LEN 1024
static int key_queue[KEY_QUEUE_LEN] = {};
static int key_f = 0, key_r = 0;
static void key_enqueue(uint32_t am_scancode) {
key_queue[key_r] = am_scancode;
key_r = (key_r + 1) % KEY_QUEUE_LEN;
Assert(key_r != key_f, "key queue overflow!");
}
static uint32_t key_dequeue() {
uint32_t key = NEMU_KEY_NONE;
if (key_f != key_r) {
key = key_queue[key_f];
key_f = (key_f + 1) % KEY_QUEUE_LEN;
}
return key;
}
void send_key(uint8_t scancode, bool is_keydown) {
if (nemu_state.state == NEMU_RUNNING && keymap[scancode] != NEMU_KEY_NONE) {
uint32_t am_scancode = keymap[scancode] | (is_keydown ? KEYDOWN_MASK : 0);
key_enqueue(am_scancode);
}
}
#else // !CONFIG_TARGET_AM
#define NEMU_KEY_NONE 0
static uint32_t key_dequeue() {
AM_INPUT_KEYBRD_T ev = io_read(AM_INPUT_KEYBRD);
uint32_t am_scancode = ev.keycode | (ev.keydown ? KEYDOWN_MASK : 0);
return am_scancode;
}
#endif
static uint32_t *i8042_data_port_base = NULL;
static void i8042_data_io_handler(uint32_t offset, int len, bool is_write) {
assert(!is_write);
assert(offset == 0);
i8042_data_port_base[0] = key_dequeue();
}
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);
#else
add_mmio_map("keyboard", CONFIG_I8042_DATA_MMIO, i8042_data_port_base, 4, i8042_data_io_handler);
#endif
IFNDEF(CONFIG_TARGET_AM, init_keymap());
}

439
nemu/src/device/mmc.h Normal file
View file

@ -0,0 +1,439 @@
/*
* Header for MultiMediaCard (MMC)
*
* Copyright 2002 Hewlett-Packard Company
*
* Use consistent with the GNU GPL is permitted,
* provided that this copyright notice is
* preserved in its entirety in all copies and derived works.
*
* HEWLETT-PACKARD COMPANY MAKES NO WARRANTIES, EXPRESSED OR IMPLIED,
* AS TO THE USEFULNESS OR CORRECTNESS OF THIS CODE OR ITS
* FITNESS FOR ANY PARTICULAR PURPOSE.
*
* Many thanks to Alessandro Rubini and Jonathan Corbet!
*
* Based strongly on code by:
*
* Author: Yong-iL Joh <tolkien@mizi.com>
*
* Author: Andrew Christian
* 15 May 2002
*/
#ifndef LINUX_MMC_MMC_H
#define LINUX_MMC_MMC_H
/* Standard MMC commands (4.1) type argument response */
/* class 1 */
#define MMC_GO_IDLE_STATE 0 /* bc */
#define MMC_SEND_OP_COND 1 /* bcr [31:0] OCR R3 */
#define MMC_ALL_SEND_CID 2 /* bcr R2 */
#define MMC_SET_RELATIVE_ADDR 3 /* ac [31:16] RCA R1 */
#define MMC_SET_DSR 4 /* bc [31:16] RCA */
#define MMC_SLEEP_AWAKE 5 /* ac [31:16] RCA 15:flg R1b */
#define MMC_SWITCH 6 /* ac [31:0] See below R1b */
#define MMC_SELECT_CARD 7 /* ac [31:16] RCA R1 */
#define MMC_SEND_EXT_CSD 8 /* adtc R1 */
#define MMC_SEND_CSD 9 /* ac [31:16] RCA R2 */
#define MMC_SEND_CID 10 /* ac [31:16] RCA R2 */
#define MMC_READ_DAT_UNTIL_STOP 11 /* adtc [31:0] dadr R1 */
#define MMC_STOP_TRANSMISSION 12 /* ac R1b */
#define MMC_SEND_STATUS 13 /* ac [31:16] RCA R1 */
#define MMC_BUS_TEST_R 14 /* adtc R1 */
#define MMC_GO_INACTIVE_STATE 15 /* ac [31:16] RCA */
#define MMC_BUS_TEST_W 19 /* adtc R1 */
#define MMC_SPI_READ_OCR 58 /* spi spi_R3 */
#define MMC_SPI_CRC_ON_OFF 59 /* spi [0:0] flag spi_R1 */
/* class 2 */
#define MMC_SET_BLOCKLEN 16 /* ac [31:0] block len R1 */
#define MMC_READ_SINGLE_BLOCK 17 /* adtc [31:0] data addr R1 */
#define MMC_READ_MULTIPLE_BLOCK 18 /* adtc [31:0] data addr R1 */
#define MMC_SEND_TUNING_BLOCK 19 /* adtc R1 */
#define MMC_SEND_TUNING_BLOCK_HS200 21 /* adtc R1 */
/* class 3 */
#define MMC_WRITE_DAT_UNTIL_STOP 20 /* adtc [31:0] data addr R1 */
/* class 4 */
#define MMC_SET_BLOCK_COUNT 23 /* adtc [31:0] data addr R1 */
#define MMC_WRITE_BLOCK 24 /* adtc [31:0] data addr R1 */
#define MMC_WRITE_MULTIPLE_BLOCK 25 /* adtc R1 */
#define MMC_PROGRAM_CID 26 /* adtc R1 */
#define MMC_PROGRAM_CSD 27 /* adtc R1 */
/* class 6 */
#define MMC_SET_WRITE_PROT 28 /* ac [31:0] data addr R1b */
#define MMC_CLR_WRITE_PROT 29 /* ac [31:0] data addr R1b */
#define MMC_SEND_WRITE_PROT 30 /* adtc [31:0] wpdata addr R1 */
/* class 5 */
#define MMC_ERASE_GROUP_START 35 /* ac [31:0] data addr R1 */
#define MMC_ERASE_GROUP_END 36 /* ac [31:0] data addr R1 */
#define MMC_ERASE 38 /* ac R1b */
/* class 9 */
#define MMC_FAST_IO 39 /* ac <Complex> R4 */
#define MMC_GO_IRQ_STATE 40 /* bcr R5 */
/* class 7 */
#define MMC_LOCK_UNLOCK 42 /* adtc R1b */
/* class 8 */
#define MMC_APP_CMD 55 /* ac [31:16] RCA R1 */
#define MMC_GEN_CMD 56 /* adtc [0] RD/WR R1 */
/* class 11 */
#define MMC_QUE_TASK_PARAMS 44 /* ac [20:16] task id R1 */
#define MMC_QUE_TASK_ADDR 45 /* ac [31:0] data addr R1 */
#define MMC_EXECUTE_READ_TASK 46 /* adtc [20:16] task id R1 */
#define MMC_EXECUTE_WRITE_TASK 47 /* adtc [20:16] task id R1 */
#define MMC_CMDQ_TASK_MGMT 48 /* ac [20:16] task id R1b */
//static inline bool mmc_op_multi(u32 opcode)
//{
// return opcode == MMC_WRITE_MULTIPLE_BLOCK ||
// opcode == MMC_READ_MULTIPLE_BLOCK;
//}
/*
* MMC_SWITCH argument format:
*
* [31:26] Always 0
* [25:24] Access Mode
* [23:16] Location of target Byte in EXT_CSD
* [15:08] Value Byte
* [07:03] Always 0
* [02:00] Command Set
*/
/*
MMC status in R1, for native mode (SPI bits are different)
Type
e : error bit
s : status bit
r : detected and set for the actual command response
x : detected and set during command execution. the host must poll
the card by sending status command in order to read these bits.
Clear condition
a : according to the card state
b : always related to the previous command. Reception of
a valid command will clear it (with a delay of one command)
c : clear by read
*/
#define R1_OUT_OF_RANGE (1 << 31) /* er, c */
#define R1_ADDRESS_ERROR (1 << 30) /* erx, c */
#define R1_BLOCK_LEN_ERROR (1 << 29) /* er, c */
#define R1_ERASE_SEQ_ERROR (1 << 28) /* er, c */
#define R1_ERASE_PARAM (1 << 27) /* ex, c */
#define R1_WP_VIOLATION (1 << 26) /* erx, c */
#define R1_CARD_IS_LOCKED (1 << 25) /* sx, a */
#define R1_LOCK_UNLOCK_FAILED (1 << 24) /* erx, c */
#define R1_COM_CRC_ERROR (1 << 23) /* er, b */
#define R1_ILLEGAL_COMMAND (1 << 22) /* er, b */
#define R1_CARD_ECC_FAILED (1 << 21) /* ex, c */
#define R1_CC_ERROR (1 << 20) /* erx, c */
#define R1_ERROR (1 << 19) /* erx, c */
#define R1_UNDERRUN (1 << 18) /* ex, c */
#define R1_OVERRUN (1 << 17) /* ex, c */
#define R1_CID_CSD_OVERWRITE (1 << 16) /* erx, c, CID/CSD overwrite */
#define R1_WP_ERASE_SKIP (1 << 15) /* sx, c */
#define R1_CARD_ECC_DISABLED (1 << 14) /* sx, a */
#define R1_ERASE_RESET (1 << 13) /* sr, c */
#define R1_STATUS(x) (x & 0xFFFFE000)
#define R1_CURRENT_STATE(x) ((x & 0x00001E00) >> 9) /* sx, b (4 bits) */
#define R1_READY_FOR_DATA (1 << 8) /* sx, a */
#define R1_SWITCH_ERROR (1 << 7) /* sx, c */
#define R1_EXCEPTION_EVENT (1 << 6) /* sr, a */
#define R1_APP_CMD (1 << 5) /* sr, c */
#define R1_STATE_IDLE 0
#define R1_STATE_READY 1
#define R1_STATE_IDENT 2
#define R1_STATE_STBY 3
#define R1_STATE_TRAN 4
#define R1_STATE_DATA 5
#define R1_STATE_RCV 6
#define R1_STATE_PRG 7
#define R1_STATE_DIS 8
/*
* MMC/SD in SPI mode reports R1 status always, and R2 for SEND_STATUS
* R1 is the low order byte; R2 is the next highest byte, when present.
*/
#define R1_SPI_IDLE (1 << 0)
#define R1_SPI_ERASE_RESET (1 << 1)
#define R1_SPI_ILLEGAL_COMMAND (1 << 2)
#define R1_SPI_COM_CRC (1 << 3)
#define R1_SPI_ERASE_SEQ (1 << 4)
#define R1_SPI_ADDRESS (1 << 5)
#define R1_SPI_PARAMETER (1 << 6)
/* R1 bit 7 is always zero */
#define R2_SPI_CARD_LOCKED (1 << 8)
#define R2_SPI_WP_ERASE_SKIP (1 << 9) /* or lock/unlock fail */
#define R2_SPI_LOCK_UNLOCK_FAIL R2_SPI_WP_ERASE_SKIP
#define R2_SPI_ERROR (1 << 10)
#define R2_SPI_CC_ERROR (1 << 11)
#define R2_SPI_CARD_ECC_ERROR (1 << 12)
#define R2_SPI_WP_VIOLATION (1 << 13)
#define R2_SPI_ERASE_PARAM (1 << 14)
#define R2_SPI_OUT_OF_RANGE (1 << 15) /* or CSD overwrite */
#define R2_SPI_CSD_OVERWRITE R2_SPI_OUT_OF_RANGE
/*
* OCR bits are mostly in host.h
*/
#define MMC_CARD_BUSY 0x80000000 /* Card Power up status bit */
/*
* Card Command Classes (CCC)
*/
#define CCC_BASIC (1<<0) /* (0) Basic protocol functions */
/* (CMD0,1,2,3,4,7,9,10,12,13,15) */
/* (and for SPI, CMD58,59) */
#define CCC_STREAM_READ (1<<1) /* (1) Stream read commands */
/* (CMD11) */
#define CCC_BLOCK_READ (1<<2) /* (2) Block read commands */
/* (CMD16,17,18) */
#define CCC_STREAM_WRITE (1<<3) /* (3) Stream write commands */
/* (CMD20) */
#define CCC_BLOCK_WRITE (1<<4) /* (4) Block write commands */
/* (CMD16,24,25,26,27) */
#define CCC_ERASE (1<<5) /* (5) Ability to erase blocks */
/* (CMD32,33,34,35,36,37,38,39) */
#define CCC_WRITE_PROT (1<<6) /* (6) Able to write protect blocks */
/* (CMD28,29,30) */
#define CCC_LOCK_CARD (1<<7) /* (7) Able to lock down card */
/* (CMD16,CMD42) */
#define CCC_APP_SPEC (1<<8) /* (8) Application specific */
/* (CMD55,56,57,ACMD*) */
#define CCC_IO_MODE (1<<9) /* (9) I/O mode */
/* (CMD5,39,40,52,53) */
#define CCC_SWITCH (1<<10) /* (10) High speed switch */
/* (CMD6,34,35,36,37,50) */
/* (11) Reserved */
/* (CMD?) */
/*
* CSD field definitions
*/
#define CSD_STRUCT_VER_1_0 0 /* Valid for system specification 1.0 - 1.2 */
#define CSD_STRUCT_VER_1_1 1 /* Valid for system specification 1.4 - 2.2 */
#define CSD_STRUCT_VER_1_2 2 /* Valid for system specification 3.1 - 3.2 - 3.31 - 4.0 - 4.1 */
#define CSD_STRUCT_EXT_CSD 3 /* Version is coded in CSD_STRUCTURE in EXT_CSD */
#define CSD_SPEC_VER_0 0 /* Implements system specification 1.0 - 1.2 */
#define CSD_SPEC_VER_1 1 /* Implements system specification 1.4 */
#define CSD_SPEC_VER_2 2 /* Implements system specification 2.0 - 2.2 */
#define CSD_SPEC_VER_3 3 /* Implements system specification 3.1 - 3.2 - 3.31 */
#define CSD_SPEC_VER_4 4 /* Implements system specification 4.0 - 4.1 */
/*
* EXT_CSD fields
*/
#define EXT_CSD_CMDQ_MODE_EN 15 /* R/W */
#define EXT_CSD_FLUSH_CACHE 32 /* W */
#define EXT_CSD_CACHE_CTRL 33 /* R/W */
#define EXT_CSD_POWER_OFF_NOTIFICATION 34 /* R/W */
#define EXT_CSD_PACKED_FAILURE_INDEX 35 /* RO */
#define EXT_CSD_PACKED_CMD_STATUS 36 /* RO */
#define EXT_CSD_EXP_EVENTS_STATUS 54 /* RO, 2 bytes */
#define EXT_CSD_EXP_EVENTS_CTRL 56 /* R/W, 2 bytes */
#define EXT_CSD_DATA_SECTOR_SIZE 61 /* R */
#define EXT_CSD_GP_SIZE_MULT 143 /* R/W */
#define EXT_CSD_PARTITION_SETTING_COMPLETED 155 /* R/W */
#define EXT_CSD_PARTITION_ATTRIBUTE 156 /* R/W */
#define EXT_CSD_PARTITION_SUPPORT 160 /* RO */
#define EXT_CSD_HPI_MGMT 161 /* R/W */
#define EXT_CSD_RST_N_FUNCTION 162 /* R/W */
#define EXT_CSD_BKOPS_EN 163 /* R/W */
#define EXT_CSD_BKOPS_START 164 /* W */
#define EXT_CSD_SANITIZE_START 165 /* W */
#define EXT_CSD_WR_REL_PARAM 166 /* RO */
#define EXT_CSD_RPMB_MULT 168 /* RO */
#define EXT_CSD_FW_CONFIG 169 /* R/W */
#define EXT_CSD_BOOT_WP 173 /* R/W */
#define EXT_CSD_ERASE_GROUP_DEF 175 /* R/W */
#define EXT_CSD_PART_CONFIG 179 /* R/W */
#define EXT_CSD_ERASED_MEM_CONT 181 /* RO */
#define EXT_CSD_BUS_WIDTH 183 /* R/W */
#define EXT_CSD_STROBE_SUPPORT 184 /* RO */
#define EXT_CSD_HS_TIMING 185 /* R/W */
#define EXT_CSD_POWER_CLASS 187 /* R/W */
#define EXT_CSD_REV 192 /* RO */
#define EXT_CSD_STRUCTURE 194 /* RO */
#define EXT_CSD_CARD_TYPE 196 /* RO */
#define EXT_CSD_DRIVER_STRENGTH 197 /* RO */
#define EXT_CSD_OUT_OF_INTERRUPT_TIME 198 /* RO */
#define EXT_CSD_PART_SWITCH_TIME 199 /* RO */
#define EXT_CSD_PWR_CL_52_195 200 /* RO */
#define EXT_CSD_PWR_CL_26_195 201 /* RO */
#define EXT_CSD_PWR_CL_52_360 202 /* RO */
#define EXT_CSD_PWR_CL_26_360 203 /* RO */
#define EXT_CSD_SEC_CNT 212 /* RO, 4 bytes */
#define EXT_CSD_S_A_TIMEOUT 217 /* RO */
#define EXT_CSD_REL_WR_SEC_C 222 /* RO */
#define EXT_CSD_HC_WP_GRP_SIZE 221 /* RO */
#define EXT_CSD_ERASE_TIMEOUT_MULT 223 /* RO */
#define EXT_CSD_HC_ERASE_GRP_SIZE 224 /* RO */
#define EXT_CSD_BOOT_MULT 226 /* RO */
#define EXT_CSD_SEC_TRIM_MULT 229 /* RO */
#define EXT_CSD_SEC_ERASE_MULT 230 /* RO */
#define EXT_CSD_SEC_FEATURE_SUPPORT 231 /* RO */
#define EXT_CSD_TRIM_MULT 232 /* RO */
#define EXT_CSD_PWR_CL_200_195 236 /* RO */
#define EXT_CSD_PWR_CL_200_360 237 /* RO */
#define EXT_CSD_PWR_CL_DDR_52_195 238 /* RO */
#define EXT_CSD_PWR_CL_DDR_52_360 239 /* RO */
#define EXT_CSD_BKOPS_STATUS 246 /* RO */
#define EXT_CSD_POWER_OFF_LONG_TIME 247 /* RO */
#define EXT_CSD_GENERIC_CMD6_TIME 248 /* RO */
#define EXT_CSD_CACHE_SIZE 249 /* RO, 4 bytes */
#define EXT_CSD_PWR_CL_DDR_200_360 253 /* RO */
#define EXT_CSD_FIRMWARE_VERSION 254 /* RO, 8 bytes */
#define EXT_CSD_PRE_EOL_INFO 267 /* RO */
#define EXT_CSD_DEVICE_LIFE_TIME_EST_TYP_A 268 /* RO */
#define EXT_CSD_DEVICE_LIFE_TIME_EST_TYP_B 269 /* RO */
#define EXT_CSD_CMDQ_DEPTH 307 /* RO */
#define EXT_CSD_CMDQ_SUPPORT 308 /* RO */
#define EXT_CSD_SUPPORTED_MODE 493 /* RO */
#define EXT_CSD_TAG_UNIT_SIZE 498 /* RO */
#define EXT_CSD_DATA_TAG_SUPPORT 499 /* RO */
#define EXT_CSD_MAX_PACKED_WRITES 500 /* RO */
#define EXT_CSD_MAX_PACKED_READS 501 /* RO */
#define EXT_CSD_BKOPS_SUPPORT 502 /* RO */
#define EXT_CSD_HPI_FEATURES 503 /* RO */
/*
* EXT_CSD field definitions
*/
#define EXT_CSD_WR_REL_PARAM_EN (1<<2)
#define EXT_CSD_BOOT_WP_B_PWR_WP_DIS (0x40)
#define EXT_CSD_BOOT_WP_B_PERM_WP_DIS (0x10)
#define EXT_CSD_BOOT_WP_B_PERM_WP_EN (0x04)
#define EXT_CSD_BOOT_WP_B_PWR_WP_EN (0x01)
#define EXT_CSD_PART_CONFIG_ACC_MASK (0x7)
#define EXT_CSD_PART_CONFIG_ACC_BOOT0 (0x1)
#define EXT_CSD_PART_CONFIG_ACC_RPMB (0x3)
#define EXT_CSD_PART_CONFIG_ACC_GP0 (0x4)
#define EXT_CSD_PART_SETTING_COMPLETED (0x1)
#define EXT_CSD_PART_SUPPORT_PART_EN (0x1)
#define EXT_CSD_CMD_SET_NORMAL (1<<0)
#define EXT_CSD_CMD_SET_SECURE (1<<1)
#define EXT_CSD_CMD_SET_CPSECURE (1<<2)
#define EXT_CSD_CARD_TYPE_HS_26 (1<<0) /* Card can run at 26MHz */
#define EXT_CSD_CARD_TYPE_HS_52 (1<<1) /* Card can run at 52MHz */
#define EXT_CSD_CARD_TYPE_HS (EXT_CSD_CARD_TYPE_HS_26 | \
EXT_CSD_CARD_TYPE_HS_52)
#define EXT_CSD_CARD_TYPE_DDR_1_8V (1<<2) /* Card can run at 52MHz */
/* DDR mode @1.8V or 3V I/O */
#define EXT_CSD_CARD_TYPE_DDR_1_2V (1<<3) /* Card can run at 52MHz */
/* DDR mode @1.2V I/O */
#define EXT_CSD_CARD_TYPE_DDR_52 (EXT_CSD_CARD_TYPE_DDR_1_8V \
| EXT_CSD_CARD_TYPE_DDR_1_2V)
#define EXT_CSD_CARD_TYPE_HS200_1_8V (1<<4) /* Card can run at 200MHz */
#define EXT_CSD_CARD_TYPE_HS200_1_2V (1<<5) /* Card can run at 200MHz */
/* SDR mode @1.2V I/O */
#define EXT_CSD_CARD_TYPE_HS200 (EXT_CSD_CARD_TYPE_HS200_1_8V | \
EXT_CSD_CARD_TYPE_HS200_1_2V)
#define EXT_CSD_CARD_TYPE_HS400_1_8V (1<<6) /* Card can run at 200MHz DDR, 1.8V */
#define EXT_CSD_CARD_TYPE_HS400_1_2V (1<<7) /* Card can run at 200MHz DDR, 1.2V */
#define EXT_CSD_CARD_TYPE_HS400 (EXT_CSD_CARD_TYPE_HS400_1_8V | \
EXT_CSD_CARD_TYPE_HS400_1_2V)
#define EXT_CSD_CARD_TYPE_HS400ES (1<<8) /* Card can run at HS400ES */
#define EXT_CSD_BUS_WIDTH_1 0 /* Card is in 1 bit mode */
#define EXT_CSD_BUS_WIDTH_4 1 /* Card is in 4 bit mode */
#define EXT_CSD_BUS_WIDTH_8 2 /* Card is in 8 bit mode */
#define EXT_CSD_DDR_BUS_WIDTH_4 5 /* Card is in 4 bit DDR mode */
#define EXT_CSD_DDR_BUS_WIDTH_8 6 /* Card is in 8 bit DDR mode */
#define EXT_CSD_BUS_WIDTH_STROBE BIT(7) /* Enhanced strobe mode */
#define EXT_CSD_TIMING_BC 0 /* Backwards compatility */
#define EXT_CSD_TIMING_HS 1 /* High speed */
#define EXT_CSD_TIMING_HS200 2 /* HS200 */
#define EXT_CSD_TIMING_HS400 3 /* HS400 */
#define EXT_CSD_DRV_STR_SHIFT 4 /* Driver Strength shift */
#define EXT_CSD_SEC_ER_EN BIT(0)
#define EXT_CSD_SEC_BD_BLK_EN BIT(2)
#define EXT_CSD_SEC_GB_CL_EN BIT(4)
#define EXT_CSD_SEC_SANITIZE BIT(6) /* v4.5 only */
#define EXT_CSD_RST_N_EN_MASK 0x3
#define EXT_CSD_RST_N_ENABLED 1 /* RST_n is enabled on card */
#define EXT_CSD_NO_POWER_NOTIFICATION 0
#define EXT_CSD_POWER_ON 1
#define EXT_CSD_POWER_OFF_SHORT 2
#define EXT_CSD_POWER_OFF_LONG 3
#define EXT_CSD_PWR_CL_8BIT_MASK 0xF0 /* 8 bit PWR CLS */
#define EXT_CSD_PWR_CL_4BIT_MASK 0x0F /* 8 bit PWR CLS */
#define EXT_CSD_PWR_CL_8BIT_SHIFT 4
#define EXT_CSD_PWR_CL_4BIT_SHIFT 0
#define EXT_CSD_PACKED_EVENT_EN BIT(3)
/*
* EXCEPTION_EVENT_STATUS field
*/
#define EXT_CSD_URGENT_BKOPS BIT(0)
#define EXT_CSD_DYNCAP_NEEDED BIT(1)
#define EXT_CSD_SYSPOOL_EXHAUSTED BIT(2)
#define EXT_CSD_PACKED_FAILURE BIT(3)
#define EXT_CSD_PACKED_GENERIC_ERROR BIT(0)
#define EXT_CSD_PACKED_INDEXED_ERROR BIT(1)
/*
* BKOPS status level
*/
#define EXT_CSD_BKOPS_LEVEL_2 0x2
/*
* BKOPS modes
*/
#define EXT_CSD_MANUAL_BKOPS_MASK 0x01
#define EXT_CSD_AUTO_BKOPS_MASK 0x02
/*
* Command Queue
*/
#define EXT_CSD_CMDQ_MODE_ENABLED BIT(0)
#define EXT_CSD_CMDQ_DEPTH_MASK GENMASK(4, 0)
#define EXT_CSD_CMDQ_SUPPORTED BIT(0)
/*
* MMC_SWITCH access modes
*/
#define MMC_SWITCH_MODE_CMD_SET 0x00 /* Change the command set */
#define MMC_SWITCH_MODE_SET_BITS 0x01 /* Set bits which are 1 in value */
#define MMC_SWITCH_MODE_CLEAR_BITS 0x02 /* Clear bits which are 1 in value */
#define MMC_SWITCH_MODE_WRITE_BYTE 0x03 /* Set target to value */
/*
* Erase/trim/discard
*/
#define MMC_ERASE_ARG 0x00000000
#define MMC_SECURE_ERASE_ARG 0x80000000
#define MMC_TRIM_ARG 0x00000001
#define MMC_DISCARD_ARG 0x00000003
#define MMC_SECURE_TRIM1_ARG 0x80000001
#define MMC_SECURE_TRIM2_ARG 0x80008000
#define MMC_SECURE_ARGS 0x80000000
#define MMC_TRIM_ARGS 0x00008001
#define mmc_driver_type_mask(n) (1 << (n))
#endif /* LINUX_MMC_MMC_H */

134
nemu/src/device/sdcard.c Normal file
View file

@ -0,0 +1,134 @@
/***************************************************************************************
* Copyright (c) 2014-2022 Zihao Yu, Nanjing University
*
* NEMU is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
* http://license.coscl.org.cn/MulanPSL2
*
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
*
* See the Mulan PSL v2 for more details.
***************************************************************************************/
#include <device/map.h>
#include "mmc.h"
// http://www.files.e-shop.co.il/pdastore/Tech-mmc-samsung/SEC%20MMC%20SPEC%20ver09.pdf
// see page 26 of the manual above
#define MEMORY_SIZE (16ull * 1024 * 1024 * 1024) // 16GB
#define READ_BL_LEN 15
#define BLOCK_LEN (1 << READ_BL_LEN)
#define NR_BLOCK (MEMORY_SIZE / BLOCK_LEN)
#define C_SIZE_MULT 7 // only 3 bits
#define MULT (1 << (C_SIZE_MULT + 2))
#define C_SIZE (NR_BLOCK / MULT - 1)
// This is a simple hardware implementation of linux/drivers/mmc/host/bcm2835.c
// No DMA and IRQ is supported, so the driver must be modified to start PIO
// right after sending the actual read/write commands.
enum {
SDCMD, SDARG, SDTOUT, SDCDIV,
SDRSP0, SDRSP1, SDRSP2, SDRSP3,
SDHSTS, __PAD0, __PAD1, __PAD2,
SDVDD, SDEDM, SDHCFG, SDHBCT,
SDDATA, __PAD10, __PAD11, __PAD12,
SDHBLC
};
static FILE *fp = NULL;
static uint32_t *base = NULL;
static uint32_t blkcnt = 0;
static long blk_addr = 0;
static uint32_t addr = 0;
static bool write_cmd = 0;
static bool read_ext_csd = false;
static void prepare_rw(int is_write) {
blk_addr = base[SDARG];
addr = 0;
if (fp) fseek(fp, blk_addr << 9, SEEK_SET);
write_cmd = is_write;
}
static void sdcard_handle_cmd(int cmd) {
switch (cmd) {
case MMC_GO_IDLE_STATE: break;
case MMC_SEND_OP_COND: base[SDRSP0] = 0x80ff8000; break;
case MMC_ALL_SEND_CID:
base[SDRSP0] = 0x00000001;
base[SDRSP1] = 0x00000000;
base[SDRSP2] = 0x00000000;
base[SDRSP3] = 0x15000000;
break;
case 52: // ???
break;
case MMC_SEND_CSD:
base[SDRSP0] = 0x92404001;
base[SDRSP1] = 0x124b97e3 | ((C_SIZE & 0x3) << 30);
base[SDRSP2] = 0x0f508000 | (C_SIZE >> 2) | (READ_BL_LEN << 16);
base[SDRSP3] = 0x9026012a;
break;
case MMC_SEND_EXT_CSD: read_ext_csd = true; addr = 0; break;
case MMC_SLEEP_AWAKE: break;
case MMC_APP_CMD: break;
case MMC_SET_RELATIVE_ADDR: break;
case MMC_SELECT_CARD: break;
case MMC_SET_BLOCK_COUNT: blkcnt = base[SDARG] & 0xffff; break;
case MMC_READ_MULTIPLE_BLOCK: prepare_rw(false); break;
case MMC_WRITE_MULTIPLE_BLOCK: prepare_rw(true); break;
case MMC_SEND_STATUS: base[SDRSP0] = 0x900; base[SDRSP1] = base[SDRSP2] = base[SDRSP3] = 0; break;
case MMC_STOP_TRANSMISSION: break;
default:
panic("unhandled command = %d", cmd);
}
}
static void sdcard_io_handler(uint32_t offset, int len, bool is_write) {
int idx = offset / 4;
switch (idx) {
case SDCMD: sdcard_handle_cmd(base[SDCMD] & 0x3f); break;
case SDARG:
case SDRSP0:
case SDRSP1:
case SDRSP2:
case SDRSP3:
break;
case SDDATA:
if (read_ext_csd) {
// See section 8.1 JEDEC Standard JED84-A441
uint32_t data;
switch (addr) {
case 192: data = 2; break; // EXT_CSD_REV
case 212: data = MEMORY_SIZE / 512; break;
default: data = 0;
}
base[SDDATA] = data;
if (addr == 512 - 4) read_ext_csd = false;
} else if (fp) {
__attribute__((unused)) int ret;
if (!write_cmd) { ret = fread(&base[SDDATA], 4, 1, fp); }
else { ret = fwrite(&base[SDDATA], 4, 1, fp); }
}
addr += 4;
break;
default:
Log("offset = 0x%x(idx = %d), is_write = %d, data = 0x%x", offset, idx, is_write, base[idx]);
panic("unhandle offset = %d", offset);
}
}
void init_sdcard() {
base = (uint32_t *)new_space(0x80);
add_mmio_map("sdhci", CONFIG_SDCARD_CTL_MMIO, base, 0x80, sdcard_io_handler);
Assert(C_SIZE < (1 << 12), "shoule be fit in 12 bits");
const char *img = CONFIG_SDCARD_IMG_PATH;
fp = fopen(img, "r+");
if (fp == NULL) Log("Can not find sdcard image: %s", img);
}

51
nemu/src/device/serial.c Normal file
View file

@ -0,0 +1,51 @@
/***************************************************************************************
* Copyright (c) 2014-2022 Zihao Yu, Nanjing University
*
* NEMU is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
* http://license.coscl.org.cn/MulanPSL2
*
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
*
* See the Mulan PSL v2 for more details.
***************************************************************************************/
#include <utils.h>
#include <device/map.h>
/* http://en.wikibooks.org/wiki/Serial_Programming/8250_UART_Programming */
// NOTE: this is compatible to 16550
#define CH_OFFSET 0
static uint8_t *serial_base = NULL;
static void serial_putc(char ch) {
MUXDEF(CONFIG_TARGET_AM, putch(ch), putc(ch, stderr));
}
static void serial_io_handler(uint32_t offset, int len, bool is_write) {
assert(len == 1);
switch (offset) {
/* We bind the serial port with the host stderr in NEMU. */
case CH_OFFSET:
if (is_write) serial_putc(serial_base[0]);
else panic("do not support read");
break;
default: panic("do not support offset = %d", offset);
}
}
void init_serial() {
serial_base = new_space(8);
#ifdef CONFIG_HAS_PORT_IO
add_pio_map ("serial", CONFIG_SERIAL_PORT, serial_base, 8, serial_io_handler);
#else
add_mmio_map("serial", CONFIG_SERIAL_MMIO, serial_base, 8, serial_io_handler);
#endif
}

48
nemu/src/device/timer.c Normal file
View file

@ -0,0 +1,48 @@
/***************************************************************************************
* Copyright (c) 2014-2022 Zihao Yu, Nanjing University
*
* NEMU is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
* http://license.coscl.org.cn/MulanPSL2
*
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
*
* See the Mulan PSL v2 for more details.
***************************************************************************************/
#include <device/map.h>
#include <device/alarm.h>
#include <utils.h>
static uint32_t *rtc_port_base = NULL;
static void rtc_io_handler(uint32_t offset, int len, bool is_write) {
assert(offset == 0 || offset == 4);
if (!is_write && offset == 4) {
uint64_t us = get_time();
rtc_port_base[0] = (uint32_t)us;
rtc_port_base[1] = us >> 32;
}
}
#ifndef CONFIG_TARGET_AM
static void timer_intr() {
if (nemu_state.state == NEMU_RUNNING) {
extern void dev_raise_intr();
dev_raise_intr();
}
}
#endif
void init_timer() {
rtc_port_base = (uint32_t *)new_space(8);
#ifdef CONFIG_HAS_PORT_IO
add_pio_map ("rtc", CONFIG_RTC_PORT, rtc_port_base, 8, rtc_io_handler);
#else
add_mmio_map("rtc", CONFIG_RTC_MMIO, rtc_port_base, 8, rtc_io_handler);
#endif
IFNDEF(CONFIG_TARGET_AM, add_alarm_handle(timer_intr));
}

92
nemu/src/device/vga.c Normal file
View file

@ -0,0 +1,92 @@
/***************************************************************************************
* Copyright (c) 2014-2022 Zihao Yu, Nanjing University
*
* NEMU is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
* http://license.coscl.org.cn/MulanPSL2
*
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
*
* See the Mulan PSL v2 for more details.
***************************************************************************************/
#include <common.h>
#include <device/map.h>
#define SCREEN_W (MUXDEF(CONFIG_VGA_SIZE_800x600, 800, 400))
#define SCREEN_H (MUXDEF(CONFIG_VGA_SIZE_800x600, 600, 300))
static uint32_t screen_width() {
return MUXDEF(CONFIG_TARGET_AM, io_read(AM_GPU_CONFIG).width, SCREEN_W);
}
static uint32_t screen_height() {
return MUXDEF(CONFIG_TARGET_AM, io_read(AM_GPU_CONFIG).height, SCREEN_H);
}
static uint32_t screen_size() {
return screen_width() * screen_height() * sizeof(uint32_t);
}
static void *vmem = NULL;
static uint32_t *vgactl_port_base = NULL;
#ifdef CONFIG_VGA_SHOW_SCREEN
#ifndef CONFIG_TARGET_AM
#include <SDL2/SDL.h>
static SDL_Renderer *renderer = NULL;
static SDL_Texture *texture = NULL;
static void init_screen() {
SDL_Window *window = NULL;
char title[128];
sprintf(title, "%s-NEMU", str(__GUEST_ISA__));
SDL_Init(SDL_INIT_VIDEO);
SDL_CreateWindowAndRenderer(
SCREEN_W * (MUXDEF(CONFIG_VGA_SIZE_400x300, 2, 1)),
SCREEN_H * (MUXDEF(CONFIG_VGA_SIZE_400x300, 2, 1)),
0, &window, &renderer);
SDL_SetWindowTitle(window, title);
texture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_ARGB8888,
SDL_TEXTUREACCESS_STATIC, SCREEN_W, SCREEN_H);
SDL_RenderPresent(renderer);
}
static inline void update_screen() {
SDL_UpdateTexture(texture, NULL, vmem, SCREEN_W * sizeof(uint32_t));
SDL_RenderClear(renderer);
SDL_RenderCopy(renderer, texture, NULL, NULL);
SDL_RenderPresent(renderer);
}
#else
static void init_screen() {}
static inline void update_screen() {
io_write(AM_GPU_FBDRAW, 0, 0, vmem, screen_width(), screen_height(), true);
}
#endif
#endif
void vga_update_screen() {
// TODO: call `update_screen()` when the sync register is non-zero,
// then zero out the sync register
}
void init_vga() {
vgactl_port_base = (uint32_t *)new_space(8);
vgactl_port_base[0] = (screen_width() << 16) | screen_height();
#ifdef CONFIG_HAS_PORT_IO
add_pio_map ("vgactl", CONFIG_VGA_CTL_PORT, vgactl_port_base, 8, NULL);
#else
add_mmio_map("vgactl", CONFIG_VGA_CTL_MMIO, vgactl_port_base, 8, NULL);
#endif
vmem = new_space(screen_size());
add_mmio_map("vmem", CONFIG_FB_ADDR, vmem, screen_size(), NULL);
IFDEF(CONFIG_VGA_SHOW_SCREEN, init_screen());
IFDEF(CONFIG_VGA_SHOW_SCREEN, memset(vmem, 0, screen_size()));
}

View file

@ -0,0 +1,17 @@
#***************************************************************************************
# Copyright (c) 2014-2022 Zihao Yu, Nanjing University
#
# NEMU is licensed under Mulan PSL v2.
# You can use this software according to the terms and conditions of the Mulan PSL v2.
# You may obtain a copy of Mulan PSL v2 at:
# http://license.coscl.org.cn/MulanPSL2
#
# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
# EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
# MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
#
# See the Mulan PSL v2 for more details.
#**************************************************************************************/
INC_PATH += $(NEMU_HOME)/src/engine/$(ENGINE)
DIRS-y += src/engine/$(ENGINE)

View file

@ -0,0 +1,51 @@
/***************************************************************************************
* Copyright (c) 2014-2022 Zihao Yu, Nanjing University
*
* NEMU is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
* http://license.coscl.org.cn/MulanPSL2
*
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
*
* See the Mulan PSL v2 for more details.
***************************************************************************************/
#include <utils.h>
#include <cpu/ifetch.h>
#include <isa.h>
#include <cpu/difftest.h>
void set_nemu_state(int state, vaddr_t pc, int halt_ret) {
difftest_skip_ref();
nemu_state.state = state;
nemu_state.halt_pc = pc;
nemu_state.halt_ret = halt_ret;
}
__attribute__((noinline))
void invalid_inst(vaddr_t thispc) {
uint32_t temp[2];
vaddr_t pc = thispc;
temp[0] = inst_fetch(&pc, 4);
temp[1] = inst_fetch(&pc, 4);
uint8_t *p = (uint8_t *)temp;
printf("invalid opcode(PC = " FMT_WORD "):\n"
"\t%02x %02x %02x %02x %02x %02x %02x %02x ...\n"
"\t%08x %08x...\n",
thispc, p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7], temp[0], temp[1]);
printf("There are two cases which will trigger this unexpected exception:\n"
"1. The instruction at PC = " FMT_WORD " is not implemented.\n"
"2. Something is implemented incorrectly.\n", thispc);
printf("Find this PC(" FMT_WORD ") in the disassembling result to distinguish which case it is.\n\n", thispc);
printf(ANSI_FMT("If it is the first case, see\n%s\nfor more details.\n\n"
"If it is the second case, remember:\n"
"* The machine is always right!\n"
"* Every line of untested code is always wrong!\n\n", ANSI_FG_RED), isa_logo);
set_nemu_state(NEMU_ABORT, thispc, -1);
}

View file

@ -0,0 +1,27 @@
/***************************************************************************************
* Copyright (c) 2014-2022 Zihao Yu, Nanjing University
*
* NEMU is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
* http://license.coscl.org.cn/MulanPSL2
*
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
*
* See the Mulan PSL v2 for more details.
***************************************************************************************/
#include <cpu/cpu.h>
void sdb_mainloop();
void engine_start() {
#ifdef CONFIG_TARGET_AM
cpu_exec(-1);
#else
/* Receive commands from user. */
sdb_mainloop();
#endif
}

28
nemu/src/filelist.mk Normal file
View file

@ -0,0 +1,28 @@
#***************************************************************************************
# Copyright (c) 2014-2022 Zihao Yu, Nanjing University
#
# NEMU is licensed under Mulan PSL v2.
# You can use this software according to the terms and conditions of the Mulan PSL v2.
# You may obtain a copy of Mulan PSL v2 at:
# http://license.coscl.org.cn/MulanPSL2
#
# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
# EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
# MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
#
# See the Mulan PSL v2 for more details.
#**************************************************************************************/
SRCS-y += src/nemu-main.c
DIRS-y += src/cpu src/monitor src/utils
DIRS-$(CONFIG_MODE_SYSTEM) += src/memory
DIRS-BLACKLIST-$(CONFIG_TARGET_AM) += src/monitor/sdb
SHARE = $(if $(CONFIG_TARGET_SHARE),1,0)
LIBS += $(if $(CONFIG_TARGET_NATIVE_ELF),-lreadline -ldl -pie,)
ifdef mainargs
ASFLAGS += -DBIN_PATH=\"$(mainargs)\"
endif
SRCS-$(CONFIG_TARGET_AM) += src/am-bin.S
.PHONY: src/am-bin.S

17
nemu/src/isa/filelist.mk Normal file
View file

@ -0,0 +1,17 @@
#***************************************************************************************
# Copyright (c) 2014-2022 Zihao Yu, Nanjing University
#
# NEMU is licensed under Mulan PSL v2.
# You can use this software according to the terms and conditions of the Mulan PSL v2.
# You may obtain a copy of Mulan PSL v2 at:
# http://license.coscl.org.cn/MulanPSL2
#
# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
# EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
# MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
#
# See the Mulan PSL v2 for more details.
#**************************************************************************************/
INC_PATH += $(NEMU_HOME)/src/isa/$(GUEST_ISA)/include
DIRS-y += src/isa/$(GUEST_ISA)

View file

@ -0,0 +1,25 @@
/***************************************************************************************
* Copyright (c) 2014-2022 Zihao Yu, Nanjing University
*
* NEMU is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
* http://license.coscl.org.cn/MulanPSL2
*
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
*
* See the Mulan PSL v2 for more details.
***************************************************************************************/
#include <isa.h>
#include <cpu/difftest.h>
#include "../local-include/reg.h"
bool isa_difftest_checkregs(CPU_state *ref_r, vaddr_t pc) {
return false;
}
void isa_difftest_attach() {
}

View file

@ -0,0 +1,35 @@
/***************************************************************************************
* Copyright (c) 2014-2022 Zihao Yu, Nanjing University
*
* NEMU is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
* http://license.coscl.org.cn/MulanPSL2
*
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
*
* See the Mulan PSL v2 for more details.
***************************************************************************************/
#ifndef __ISA_LOONGARCH32R_H__
#define __ISA_LOONGARCH32R_H__
#include <common.h>
typedef struct {
word_t gpr[32];
vaddr_t pc;
} loongarch32r_CPU_state;
// decode
typedef struct {
union {
uint32_t val;
} inst;
} loongarch32r_ISADecodeInfo;
#define isa_mmu_check(vaddr, len, type) (MMU_DIRECT)
#endif

View file

@ -0,0 +1,43 @@
/***************************************************************************************
* Copyright (c) 2014-2022 Zihao Yu, Nanjing University
*
* NEMU is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
* http://license.coscl.org.cn/MulanPSL2
*
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
*
* See the Mulan PSL v2 for more details.
***************************************************************************************/
#include <isa.h>
#include <memory/paddr.h>
// this is not consistent with uint8_t
// but it is ok since we do not access the array directly
static const uint32_t img [] = {
0x1c00000c, // pcaddu12i $t0,0
0x29804180, // st.w $zero,$t0,16
0x28804184, // ld.w $a0,$t0,16
0x002a0000, // break 0 (used as nemu_trap)
0xdeadbeef, // some data
};
static void restart() {
/* Set the initial program counter. */
cpu.pc = RESET_VECTOR;
/* The zero register is always 0. */
cpu.gpr[0] = 0;
}
void init_isa() {
/* Load built-in image. */
memcpy(guest_to_host(RESET_VECTOR), img, sizeof(img));
/* Initialize this virtual computer system. */
restart();
}

View file

@ -0,0 +1,72 @@
/***************************************************************************************
* Copyright (c) 2014-2022 Zihao Yu, Nanjing University
*
* NEMU is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
* http://license.coscl.org.cn/MulanPSL2
*
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
*
* See the Mulan PSL v2 for more details.
***************************************************************************************/
#include "local-include/reg.h"
#include <cpu/cpu.h>
#include <cpu/ifetch.h>
#include <cpu/decode.h>
#define R(i) gpr(i)
#define Mr vaddr_read
#define Mw vaddr_write
enum {
TYPE_2RI12, TYPE_1RI20,
TYPE_N, // none
};
#define src1R() do { *src1 = R(rj); } while (0)
#define simm12() do { *imm = SEXT(BITS(i, 21, 10), 12); } while (0)
#define simm20() do { *imm = SEXT(BITS(i, 24, 5), 20) << 12; } while (0)
static void decode_operand(Decode *s, int *rd_, word_t *src1, word_t *src2, word_t *imm, int type) {
uint32_t i = s->isa.inst.val;
int rj = BITS(i, 9, 5);
*rd_ = BITS(i, 4, 0);
switch (type) {
case TYPE_1RI20: simm20(); src1R(); break;
case TYPE_2RI12: simm12(); src1R(); break;
}
}
static int decode_exec(Decode *s) {
int rd = 0;
word_t src1 = 0, src2 = 0, imm = 0;
s->dnpc = s->snpc;
#define INSTPAT_INST(s) ((s)->isa.inst.val)
#define INSTPAT_MATCH(s, name, type, ... /* execute body */ ) { \
decode_operand(s, &rd, &src1, &src2, &imm, concat(TYPE_, type)); \
__VA_ARGS__ ; \
}
INSTPAT_START();
INSTPAT("0001110 ????? ????? ????? ????? ?????" , pcaddu12i, 1RI20 , R(rd) = s->pc + imm);
INSTPAT("0010100010 ???????????? ????? ?????" , ld.w , 2RI12 , R(rd) = Mr(src1 + imm, 4));
INSTPAT("0010100110 ???????????? ????? ?????" , st.w , 2RI12 , Mw(src1 + imm, 4, R(rd)));
INSTPAT("0000 0000 0010 10100 ????? ????? ?????", break , N , NEMUTRAP(s->pc, R(4))); // R(4) is $a0
INSTPAT("????????????????? ????? ????? ?????" , inv , N , INV(s->pc));
INSTPAT_END();
R(0) = 0; // reset $zero to 0
return 0;
}
int isa_exec_once(Decode *s) {
s->isa.inst.val = inst_fetch(&s->snpc, 4);
return decode_exec(s);
}

View file

@ -0,0 +1,33 @@
/***************************************************************************************
* Copyright (c) 2014-2022 Zihao Yu, Nanjing University
*
* NEMU is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
* http://license.coscl.org.cn/MulanPSL2
*
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
*
* See the Mulan PSL v2 for more details.
***************************************************************************************/
#ifndef __LOONGARCH32R_REG_H__
#define __LOONGARCH32R_REG_H__
#include <common.h>
static inline int check_reg_idx(int idx) {
IFDEF(CONFIG_RT_CHECK, assert(idx >= 0 && idx < 32));
return idx;
}
#define gpr(idx) cpu.gpr[check_reg_idx(idx)]
static inline const char* reg_name(int idx) {
extern const char* regs[];
return regs[check_reg_idx(idx)];
}
#endif

View file

@ -0,0 +1,16 @@
/***************************************************************************************
* Copyright (c) 2014-2022 Zihao Yu, Nanjing University
*
* NEMU is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
* http://license.coscl.org.cn/MulanPSL2
*
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
*
* See the Mulan PSL v2 for more details.
***************************************************************************************/
unsigned char isa_logo[] = "loongarch32r manual";

View file

@ -0,0 +1,31 @@
/***************************************************************************************
* Copyright (c) 2014-2022 Zihao Yu, Nanjing University
*
* NEMU is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
* http://license.coscl.org.cn/MulanPSL2
*
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
*
* See the Mulan PSL v2 for more details.
***************************************************************************************/
#include <isa.h>
#include "local-include/reg.h"
const char *regs[] = {
"$0", "ra", "tp", "sp", "a0", "a1", "a2", "a3",
"a4", "a5", "a6", "a7", "t0", "t1", "t2", "t3",
"t4", "t5", "t6", "t7", "t8", "rs", "fp", "s0",
"s1", "s2", "s3", "s4", "s5", "s6", "s7", "s8"
};
void isa_reg_display() {
}
word_t isa_reg_str2val(const char *s, bool *success) {
return 0;
}

View file

@ -0,0 +1,28 @@
/***************************************************************************************
* Copyright (c) 2014-2022 Zihao Yu, Nanjing University
*
* NEMU is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
* http://license.coscl.org.cn/MulanPSL2
*
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
*
* See the Mulan PSL v2 for more details.
***************************************************************************************/
#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.
*/
return 0;
}
word_t isa_query_intr() {
return INTR_EMPTY;
}

View file

@ -0,0 +1,22 @@
/***************************************************************************************
* Copyright (c) 2014-2022 Zihao Yu, Nanjing University
*
* NEMU is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
* http://license.coscl.org.cn/MulanPSL2
*
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
*
* See the Mulan PSL v2 for more details.
***************************************************************************************/
#include <isa.h>
#include <memory/paddr.h>
#include <memory/vaddr.h>
paddr_t isa_mmu_translate(vaddr_t vaddr, int len, int type) {
return MEM_RET_FAIL;
}

View file

@ -0,0 +1,25 @@
/***************************************************************************************
* Copyright (c) 2014-2022 Zihao Yu, Nanjing University
*
* NEMU is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
* http://license.coscl.org.cn/MulanPSL2
*
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
*
* See the Mulan PSL v2 for more details.
***************************************************************************************/
#include <isa.h>
#include <cpu/difftest.h>
#include "../local-include/reg.h"
bool isa_difftest_checkregs(CPU_state *ref_r, vaddr_t pc) {
return false;
}
void isa_difftest_attach() {
}

View file

@ -0,0 +1,36 @@
/***************************************************************************************
* Copyright (c) 2014-2022 Zihao Yu, Nanjing University
*
* NEMU is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
* http://license.coscl.org.cn/MulanPSL2
*
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
*
* See the Mulan PSL v2 for more details.
***************************************************************************************/
#ifndef __ISA_MIPS32_H__
#define __ISA_MIPS32_H__
#include <common.h>
typedef struct {
word_t gpr[32];
word_t pad[5];
vaddr_t pc;
} mips32_CPU_state;
// decode
typedef struct {
union {
uint32_t val;
} inst;
} mips32_ISADecodeInfo;
#define isa_mmu_check(vaddr, len, type) (MMU_DIRECT)
#endif

View file

@ -0,0 +1,42 @@
/***************************************************************************************
* Copyright (c) 2014-2022 Zihao Yu, Nanjing University
*
* NEMU is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
* http://license.coscl.org.cn/MulanPSL2
*
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
*
* See the Mulan PSL v2 for more details.
***************************************************************************************/
#include <isa.h>
#include <memory/paddr.h>
// this is not consistent with uint8_t
// but it is ok since we do not access the array directly
static const uint32_t img [] = {
0x3c048000, // lui a0, 0x8000
0xac800000, // sw zero, 0(a0)
0x8c820000, // lw v0,0(a0)
0x7000003f, // sdbbp (used as nemu_trap)
};
static void restart() {
/* Set the initial program counter. */
cpu.pc = RESET_VECTOR;
/* The zero register is always 0. */
cpu.gpr[0] = 0;
}
void init_isa() {
/* Load built-in image. */
memcpy(guest_to_host(RESET_VECTOR), img, sizeof(img));
/* Initialize this virtual computer system. */
restart();
}

View file

@ -0,0 +1,74 @@
/***************************************************************************************
* Copyright (c) 2014-2022 Zihao Yu, Nanjing University
*
* NEMU is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
* http://license.coscl.org.cn/MulanPSL2
*
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
*
* See the Mulan PSL v2 for more details.
***************************************************************************************/
#include "local-include/reg.h"
#include <cpu/cpu.h>
#include <cpu/ifetch.h>
#include <cpu/decode.h>
#define R(i) gpr(i)
#define Mr vaddr_read
#define Mw vaddr_write
enum {
TYPE_I, TYPE_U,
TYPE_N, // none
};
#define src1R() do { *src1 = R(rs); } while (0)
#define src2R() do { *src2 = R(rt); } while (0)
#define immI() do { *imm = SEXT(BITS(i, 15, 0), 16); } while(0)
#define immU() do { *imm = BITS(i, 15, 0); } while(0)
static void decode_operand(Decode *s, int *rd, word_t *src1, word_t *src2, word_t *imm, int type) {
uint32_t i = s->isa.inst.val;
int rt = BITS(i, 20, 16);
int rs = BITS(i, 25, 21);
*rd = (type == TYPE_U || type == TYPE_I) ? rt : BITS(i, 15, 11);
switch (type) {
case TYPE_I: src1R(); immI(); break;
case TYPE_U: src1R(); immU(); break;
}
}
static int decode_exec(Decode *s) {
int rd = 0;
word_t src1 = 0, src2 = 0, imm = 0;
s->dnpc = s->snpc;
#define INSTPAT_INST(s) ((s)->isa.inst.val)
#define INSTPAT_MATCH(s, name, type, ... /* execute body */ ) { \
decode_operand(s, &rd, &src1, &src2, &imm, concat(TYPE_, type)); \
__VA_ARGS__ ; \
}
INSTPAT_START();
INSTPAT("001111 ????? ????? ????? ????? ??????", lui , U, R(rd) = imm << 16);
INSTPAT("100011 ????? ????? ????? ????? ??????", lw , I, R(rd) = Mr(src1 + imm, 4));
INSTPAT("101011 ????? ????? ????? ????? ??????", sw , I, Mw(src1 + imm, 4, R(rd)));
INSTPAT("011100 ????? ????? ????? ????? 111111", sdbbp , N, NEMUTRAP(s->pc, R(2))); // R(2) is $v0;
INSTPAT("?????? ????? ????? ????? ????? ??????", inv , N, INV(s->pc));
INSTPAT_END();
R(0) = 0; // reset $zero to 0
return 0;
}
int isa_exec_once(Decode *s) {
s->isa.inst.val = inst_fetch(&s->snpc, 4);
return decode_exec(s);
}

View file

@ -0,0 +1,33 @@
/***************************************************************************************
* Copyright (c) 2014-2022 Zihao Yu, Nanjing University
*
* NEMU is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
* http://license.coscl.org.cn/MulanPSL2
*
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
*
* See the Mulan PSL v2 for more details.
***************************************************************************************/
#ifndef __MIPS32_REG_H__
#define __MIPS32_REG_H__
#include <common.h>
static inline int check_reg_idx(int idx) {
IFDEF(CONFIG_RT_CHECK, assert(idx >= 0 && idx < 32));
return idx;
}
#define gpr(idx) cpu.gpr[check_reg_idx(idx)]
static inline const char* reg_name(int idx) {
extern const char* regs[];
return regs[check_reg_idx(idx)];
}
#endif

View file

@ -0,0 +1,78 @@
/***************************************************************************************
* Copyright (c) 2014-2022 Zihao Yu, Nanjing University
*
* NEMU is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
* http://license.coscl.org.cn/MulanPSL2
*
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
*
* See the Mulan PSL v2 for more details.
***************************************************************************************/
// refer to http://www.patorjk.com/software/taag/#p=display&f=Big&t=Type%20Something%20
/*
_ ____ ___ __ __ _
(_) |___ \__ \ | \/ | | |
_ __ ___ _ _ __ ___ __) | ) | | \ / | __ _ _ __ _ _ __ _| |
| '_ ` _ \| | '_ \/ __||__ < / / | |\/| |/ _` | '_ \| | | |/ _` | |
| | | | | | | |_) \__ \___) / /_ | | | | (_| | | | | |_| | (_| | |
|_| |_| |_|_| .__/|___/____/____| |_| |_|\__,_|_| |_|\__,_|\__,_|_|
| |
|_|
*/
unsigned char isa_logo[] = {
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x5f, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x5f, 0x5f, 0x5f, 0x5f, 0x20, 0x5f, 0x5f, 0x5f, 0x20, 0x20, 0x20, 0x20,
0x5f, 0x5f, 0x20, 0x20, 0x5f, 0x5f, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x5f, 0x20, 0x0a, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x28, 0x5f, 0x29,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7c, 0x5f, 0x5f,
0x5f, 0x20, 0x5c, 0x5f, 0x5f, 0x20, 0x5c, 0x20, 0x20, 0x7c, 0x20, 0x20,
0x5c, 0x2f, 0x20, 0x20, 0x7c, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x7c, 0x20, 0x7c, 0x0a, 0x20, 0x20, 0x5f, 0x20,
0x5f, 0x5f, 0x20, 0x5f, 0x5f, 0x5f, 0x20, 0x20, 0x5f, 0x20, 0x5f, 0x20,
0x5f, 0x5f, 0x20, 0x20, 0x5f, 0x5f, 0x5f, 0x20, 0x20, 0x5f, 0x5f, 0x29,
0x20, 0x7c, 0x20, 0x29, 0x20, 0x7c, 0x20, 0x7c, 0x20, 0x5c, 0x20, 0x20,
0x2f, 0x20, 0x7c, 0x20, 0x5f, 0x5f, 0x20, 0x5f, 0x20, 0x5f, 0x20, 0x5f,
0x5f, 0x20, 0x20, 0x5f, 0x20, 0x20, 0x20, 0x5f, 0x20, 0x20, 0x5f, 0x5f,
0x20, 0x5f, 0x7c, 0x20, 0x7c, 0x0a, 0x20, 0x7c, 0x20, 0x27, 0x5f, 0x20,
0x60, 0x20, 0x5f, 0x20, 0x5c, 0x7c, 0x20, 0x7c, 0x20, 0x27, 0x5f, 0x20,
0x5c, 0x2f, 0x20, 0x5f, 0x5f, 0x7c, 0x7c, 0x5f, 0x5f, 0x20, 0x3c, 0x20,
0x2f, 0x20, 0x2f, 0x20, 0x20, 0x7c, 0x20, 0x7c, 0x5c, 0x2f, 0x7c, 0x20,
0x7c, 0x2f, 0x20, 0x5f, 0x60, 0x20, 0x7c, 0x20, 0x27, 0x5f, 0x20, 0x5c,
0x7c, 0x20, 0x7c, 0x20, 0x7c, 0x20, 0x7c, 0x2f, 0x20, 0x5f, 0x60, 0x20,
0x7c, 0x20, 0x7c, 0x0a, 0x20, 0x7c, 0x20, 0x7c, 0x20, 0x7c, 0x20, 0x7c,
0x20, 0x7c, 0x20, 0x7c, 0x20, 0x7c, 0x20, 0x7c, 0x5f, 0x29, 0x20, 0x5c,
0x5f, 0x5f, 0x20, 0x5c, 0x5f, 0x5f, 0x5f, 0x29, 0x20, 0x2f, 0x20, 0x2f,
0x5f, 0x20, 0x20, 0x7c, 0x20, 0x7c, 0x20, 0x20, 0x7c, 0x20, 0x7c, 0x20,
0x28, 0x5f, 0x7c, 0x20, 0x7c, 0x20, 0x7c, 0x20, 0x7c, 0x20, 0x7c, 0x20,
0x7c, 0x5f, 0x7c, 0x20, 0x7c, 0x20, 0x28, 0x5f, 0x7c, 0x20, 0x7c, 0x20,
0x7c, 0x0a, 0x20, 0x7c, 0x5f, 0x7c, 0x20, 0x7c, 0x5f, 0x7c, 0x20, 0x7c,
0x5f, 0x7c, 0x5f, 0x7c, 0x20, 0x2e, 0x5f, 0x5f, 0x2f, 0x7c, 0x5f, 0x5f,
0x5f, 0x2f, 0x5f, 0x5f, 0x5f, 0x5f, 0x2f, 0x5f, 0x5f, 0x5f, 0x5f, 0x7c,
0x20, 0x7c, 0x5f, 0x7c, 0x20, 0x20, 0x7c, 0x5f, 0x7c, 0x5c, 0x5f, 0x5f,
0x2c, 0x5f, 0x7c, 0x5f, 0x7c, 0x20, 0x7c, 0x5f, 0x7c, 0x5c, 0x5f, 0x5f,
0x2c, 0x5f, 0x7c, 0x5c, 0x5f, 0x5f, 0x2c, 0x5f, 0x7c, 0x5f, 0x7c, 0x0a,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x7c, 0x20, 0x7c, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x0a, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7c,
0x5f, 0x7c, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x0a, '\0'
};

31
nemu/src/isa/mips32/reg.c Normal file
View file

@ -0,0 +1,31 @@
/***************************************************************************************
* Copyright (c) 2014-2022 Zihao Yu, Nanjing University
*
* NEMU is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
* http://license.coscl.org.cn/MulanPSL2
*
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
*
* See the Mulan PSL v2 for more details.
***************************************************************************************/
#include <isa.h>
#include "local-include/reg.h"
const char *regs[] = {
"$0", "at", "v0", "v1", "a0", "a1", "a2", "a3",
"t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7",
"s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7",
"t8", "t9", "k0", "k1", "gp", "sp", "s8", "ra"
};
void isa_reg_display() {
}
word_t isa_reg_str2val(const char *s, bool *success) {
return 0;
}

View file

@ -0,0 +1,28 @@
/***************************************************************************************
* Copyright (c) 2014-2022 Zihao Yu, Nanjing University
*
* NEMU is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
* http://license.coscl.org.cn/MulanPSL2
*
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
*
* See the Mulan PSL v2 for more details.
***************************************************************************************/
#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.
*/
return 0;
}
word_t isa_query_intr() {
return INTR_EMPTY;
}

View file

@ -0,0 +1,22 @@
/***************************************************************************************
* Copyright (c) 2014-2022 Zihao Yu, Nanjing University
*
* NEMU is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
* http://license.coscl.org.cn/MulanPSL2
*
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
*
* See the Mulan PSL v2 for more details.
***************************************************************************************/
#include <isa.h>
#include <memory/paddr.h>
#include <memory/vaddr.h>
paddr_t isa_mmu_translate(vaddr_t vaddr, int len, int type) {
return MEM_RET_FAIL;
}

View file

@ -0,0 +1,10 @@
menu "ISA-dependent Options for riscv"
config RV64
bool "64-bit RISC-V architecture"
default n
config RVE
bool "Use E extension"
default n
endmenu

View file

@ -0,0 +1,25 @@
/***************************************************************************************
* Copyright (c) 2014-2022 Zihao Yu, Nanjing University
*
* NEMU is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
* http://license.coscl.org.cn/MulanPSL2
*
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
*
* See the Mulan PSL v2 for more details.
***************************************************************************************/
#include <isa.h>
#include <cpu/difftest.h>
#include "../local-include/reg.h"
bool isa_difftest_checkregs(CPU_state *ref_r, vaddr_t pc) {
return false;
}
void isa_difftest_attach() {
}

View file

@ -0,0 +1,35 @@
/***************************************************************************************
* Copyright (c) 2014-2022 Zihao Yu, Nanjing University
*
* NEMU is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
* http://license.coscl.org.cn/MulanPSL2
*
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
*
* See the Mulan PSL v2 for more details.
***************************************************************************************/
#ifndef __ISA_RISCV_H__
#define __ISA_RISCV_H__
#include <common.h>
typedef struct {
word_t gpr[MUXDEF(CONFIG_RVE, 16, 32)];
vaddr_t pc;
} MUXDEF(CONFIG_RV64, riscv64_CPU_state, riscv32_CPU_state);
// decode
typedef struct {
union {
uint32_t val;
} inst;
} MUXDEF(CONFIG_RV64, riscv64_ISADecodeInfo, riscv32_ISADecodeInfo);
#define isa_mmu_check(vaddr, len, type) (MMU_DIRECT)
#endif

View file

@ -0,0 +1,43 @@
/***************************************************************************************
* Copyright (c) 2014-2022 Zihao Yu, Nanjing University
*
* NEMU is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
* http://license.coscl.org.cn/MulanPSL2
*
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
*
* See the Mulan PSL v2 for more details.
***************************************************************************************/
#include <isa.h>
#include <memory/paddr.h>
// this is not consistent with uint8_t
// but it is ok since we do not access the array directly
static const uint32_t img [] = {
0x00000297, // auipc t0,0
0x00028823, // sb zero,16(t0)
0x0102c503, // lbu a0,16(t0)
0x00100073, // ebreak (used as nemu_trap)
0xdeadbeef, // some data
};
static void restart() {
/* Set the initial program counter. */
cpu.pc = RESET_VECTOR;
/* The zero register is always 0. */
cpu.gpr[0] = 0;
}
void init_isa() {
/* Load built-in image. */
memcpy(guest_to_host(RESET_VECTOR), img, sizeof(img));
/* Initialize this virtual computer system. */
restart();
}

View file

@ -0,0 +1,76 @@
/***************************************************************************************
* Copyright (c) 2014-2022 Zihao Yu, Nanjing University
*
* NEMU is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
* http://license.coscl.org.cn/MulanPSL2
*
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
*
* See the Mulan PSL v2 for more details.
***************************************************************************************/
#include "local-include/reg.h"
#include <cpu/cpu.h>
#include <cpu/ifetch.h>
#include <cpu/decode.h>
#define R(i) gpr(i)
#define Mr vaddr_read
#define Mw vaddr_write
enum {
TYPE_I, TYPE_U, TYPE_S,
TYPE_N, // none
};
#define src1R() do { *src1 = R(rs1); } while (0)
#define src2R() do { *src2 = R(rs2); } while (0)
#define immI() do { *imm = SEXT(BITS(i, 31, 20), 12); } while(0)
#define immU() do { *imm = SEXT(BITS(i, 31, 12), 20) << 12; } while(0)
#define immS() do { *imm = (SEXT(BITS(i, 31, 25), 7) << 5) | BITS(i, 11, 7); } while(0)
static void decode_operand(Decode *s, int *rd, word_t *src1, word_t *src2, word_t *imm, int type) {
uint32_t i = s->isa.inst.val;
int rs1 = BITS(i, 19, 15);
int rs2 = BITS(i, 24, 20);
*rd = BITS(i, 11, 7);
switch (type) {
case TYPE_I: src1R(); immI(); break;
case TYPE_U: immU(); break;
case TYPE_S: src1R(); src2R(); immS(); break;
}
}
static int decode_exec(Decode *s) {
int rd = 0;
word_t src1 = 0, src2 = 0, imm = 0;
s->dnpc = s->snpc;
#define INSTPAT_INST(s) ((s)->isa.inst.val)
#define INSTPAT_MATCH(s, name, type, ... /* execute body */ ) { \
decode_operand(s, &rd, &src1, &src2, &imm, concat(TYPE_, type)); \
__VA_ARGS__ ; \
}
INSTPAT_START();
INSTPAT("??????? ????? ????? ??? ????? 00101 11", auipc , U, R(rd) = s->pc + imm);
INSTPAT("??????? ????? ????? 100 ????? 00000 11", lbu , I, R(rd) = Mr(src1 + imm, 1));
INSTPAT("??????? ????? ????? 000 ????? 01000 11", sb , S, Mw(src1 + imm, 1, src2));
INSTPAT("0000000 00001 00000 000 00000 11100 11", ebreak , N, NEMUTRAP(s->pc, R(10))); // R(10) is $a0
INSTPAT("??????? ????? ????? ??? ????? ????? ??", inv , N, INV(s->pc));
INSTPAT_END();
R(0) = 0; // reset $zero to 0
return 0;
}
int isa_exec_once(Decode *s) {
s->isa.inst.val = inst_fetch(&s->snpc, 4);
return decode_exec(s);
}

View file

@ -0,0 +1,33 @@
/***************************************************************************************
* Copyright (c) 2014-2022 Zihao Yu, Nanjing University
*
* NEMU is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
* http://license.coscl.org.cn/MulanPSL2
*
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
*
* See the Mulan PSL v2 for more details.
***************************************************************************************/
#ifndef __RISCV_REG_H__
#define __RISCV_REG_H__
#include <common.h>
static inline int check_reg_idx(int idx) {
IFDEF(CONFIG_RT_CHECK, assert(idx >= 0 && idx < MUXDEF(CONFIG_RVE, 16, 32)));
return idx;
}
#define gpr(idx) (cpu.gpr[check_reg_idx(idx)])
static inline const char* reg_name(int idx) {
extern const char* regs[];
return regs[check_reg_idx(idx)];
}
#endif

View file

@ -0,0 +1,63 @@
/***************************************************************************************
* Copyright (c) 2014-2022 Zihao Yu, Nanjing University
*
* NEMU is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
* http://license.coscl.org.cn/MulanPSL2
*
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
*
* See the Mulan PSL v2 for more details.
***************************************************************************************/
// refer to http://www.patorjk.com/software/taag/#p=display&f=Big&t=Type%20Something%20
/*
_ __ __ _
(_) | \/ | | |
_ __ _ ___ ___ ________ __ | \ / | __ _ _ __ _ _ __ _| |
| '__| / __|/ __|______\ \ / / | |\/| |/ _` | '_ \| | | |/ _` | |
| | | \__ \ (__ \ V / | | | | (_| | | | | |_| | (_| | |
|_| |_|___/\___| \_/ |_| |_|\__,_|_| |_|\__,_|\__,_|_|
*/
unsigned char isa_logo[] = {
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x5f, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x5f, 0x5f, 0x20,
0x20, 0x5f, 0x5f, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x5f, 0x20, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x28, 0x5f, 0x29, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x7c, 0x20, 0x20, 0x5c, 0x2f, 0x20, 0x20, 0x7c, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7c, 0x20,
0x7c, 0x0a, 0x20, 0x20, 0x5f, 0x20, 0x5f, 0x5f, 0x20, 0x5f, 0x20, 0x5f,
0x5f, 0x5f, 0x20, 0x20, 0x5f, 0x5f, 0x5f, 0x20, 0x5f, 0x5f, 0x5f, 0x5f,
0x5f, 0x5f, 0x5f, 0x5f, 0x20, 0x20, 0x20, 0x5f, 0x5f, 0x20, 0x7c, 0x20,
0x5c, 0x20, 0x20, 0x2f, 0x20, 0x7c, 0x20, 0x5f, 0x5f, 0x20, 0x5f, 0x20,
0x5f, 0x20, 0x5f, 0x5f, 0x20, 0x20, 0x5f, 0x20, 0x20, 0x20, 0x5f, 0x20,
0x20, 0x5f, 0x5f, 0x20, 0x5f, 0x7c, 0x20, 0x7c, 0x0a, 0x20, 0x7c, 0x20,
0x27, 0x5f, 0x5f, 0x7c, 0x20, 0x2f, 0x20, 0x5f, 0x5f, 0x7c, 0x2f, 0x20,
0x5f, 0x5f, 0x7c, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5c, 0x20, 0x5c,
0x20, 0x2f, 0x20, 0x2f, 0x20, 0x7c, 0x20, 0x7c, 0x5c, 0x2f, 0x7c, 0x20,
0x7c, 0x2f, 0x20, 0x5f, 0x60, 0x20, 0x7c, 0x20, 0x27, 0x5f, 0x20, 0x5c,
0x7c, 0x20, 0x7c, 0x20, 0x7c, 0x20, 0x7c, 0x2f, 0x20, 0x5f, 0x60, 0x20,
0x7c, 0x20, 0x7c, 0x0a, 0x20, 0x7c, 0x20, 0x7c, 0x20, 0x20, 0x7c, 0x20,
0x5c, 0x5f, 0x5f, 0x20, 0x5c, 0x20, 0x28, 0x5f, 0x5f, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x5c, 0x20, 0x56, 0x20, 0x2f, 0x20, 0x20,
0x7c, 0x20, 0x7c, 0x20, 0x20, 0x7c, 0x20, 0x7c, 0x20, 0x28, 0x5f, 0x7c,
0x20, 0x7c, 0x20, 0x7c, 0x20, 0x7c, 0x20, 0x7c, 0x20, 0x7c, 0x5f, 0x7c,
0x20, 0x7c, 0x20, 0x28, 0x5f, 0x7c, 0x20, 0x7c, 0x20, 0x7c, 0x0a, 0x20,
0x7c, 0x5f, 0x7c, 0x20, 0x20, 0x7c, 0x5f, 0x7c, 0x5f, 0x5f, 0x5f, 0x2f,
0x5c, 0x5f, 0x5f, 0x5f, 0x7c, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x5c, 0x5f, 0x2f, 0x20, 0x20, 0x20, 0x7c, 0x5f, 0x7c, 0x20, 0x20,
0x7c, 0x5f, 0x7c, 0x5c, 0x5f, 0x5f, 0x2c, 0x5f, 0x7c, 0x5f, 0x7c, 0x20,
0x7c, 0x5f, 0x7c, 0x5c, 0x5f, 0x5f, 0x2c, 0x5f, 0x7c, 0x5c, 0x5f, 0x5f,
0x2c, 0x5f, 0x7c, 0x5f, 0x7c, 0x0a, '\0' /* Termination Character is indispensable! */
};

View file

@ -0,0 +1,31 @@
/***************************************************************************************
* Copyright (c) 2014-2022 Zihao Yu, Nanjing University
*
* NEMU is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
* http://license.coscl.org.cn/MulanPSL2
*
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
*
* See the Mulan PSL v2 for more details.
***************************************************************************************/
#include <isa.h>
#include "local-include/reg.h"
const char *regs[] = {
"$0", "ra", "sp", "gp", "tp", "t0", "t1", "t2",
"s0", "s1", "a0", "a1", "a2", "a3", "a4", "a5",
"a6", "a7", "s2", "s3", "s4", "s5", "s6", "s7",
"s8", "s9", "s10", "s11", "t3", "t4", "t5", "t6"
};
void isa_reg_display() {
}
word_t isa_reg_str2val(const char *s, bool *success) {
return 0;
}

View file

@ -0,0 +1,28 @@
/***************************************************************************************
* Copyright (c) 2014-2022 Zihao Yu, Nanjing University
*
* NEMU is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
* http://license.coscl.org.cn/MulanPSL2
*
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
*
* See the Mulan PSL v2 for more details.
***************************************************************************************/
#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.
*/
return 0;
}
word_t isa_query_intr() {
return INTR_EMPTY;
}

View file

@ -0,0 +1,22 @@
/***************************************************************************************
* Copyright (c) 2014-2022 Zihao Yu, Nanjing University
*
* NEMU is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
* http://license.coscl.org.cn/MulanPSL2
*
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
*
* See the Mulan PSL v2 for more details.
***************************************************************************************/
#include <isa.h>
#include <memory/vaddr.h>
#include <memory/paddr.h>
paddr_t isa_mmu_translate(vaddr_t vaddr, int len, int type) {
return MEM_RET_FAIL;
}

34
nemu/src/memory/Kconfig Normal file
View file

@ -0,0 +1,34 @@
menu "Memory Configuration"
config MBASE
hex "Memory base address"
default 0x0 if ISA_x86
default 0x80000000
config MSIZE
hex "Memory size"
default 0x8000000
config PC_RESET_OFFSET
hex "Offset of reset vector from the base of memory"
default 0x100000 if ISA_x86
default 0
choice
prompt "Physical memory definition"
default PMEM_GARRAY
config PMEM_MALLOC
bool "Using malloc()"
config PMEM_GARRAY
depends on !TARGET_AM
bool "Using global array"
endchoice
config MEM_RANDOM
depends on MODE_SYSTEM && !DIFFTEST && !TARGET_AM
bool "Initialize the memory with random values"
default y
help
This may help to find undefined behaviors.
endmenu #MEMORY

64
nemu/src/memory/paddr.c Normal file
View file

@ -0,0 +1,64 @@
/***************************************************************************************
* Copyright (c) 2014-2022 Zihao Yu, Nanjing University
*
* NEMU is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
* http://license.coscl.org.cn/MulanPSL2
*
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
*
* See the Mulan PSL v2 for more details.
***************************************************************************************/
#include <memory/host.h>
#include <memory/paddr.h>
#include <device/mmio.h>
#include <isa.h>
#if defined(CONFIG_PMEM_MALLOC)
static uint8_t *pmem = NULL;
#else // CONFIG_PMEM_GARRAY
static uint8_t pmem[CONFIG_MSIZE] PG_ALIGN = {};
#endif
uint8_t* guest_to_host(paddr_t paddr) { return pmem + paddr - CONFIG_MBASE; }
paddr_t host_to_guest(uint8_t *haddr) { return haddr - pmem + CONFIG_MBASE; }
static word_t pmem_read(paddr_t addr, int len) {
word_t ret = host_read(guest_to_host(addr), len);
return ret;
}
static void pmem_write(paddr_t addr, int len, word_t data) {
host_write(guest_to_host(addr), len, data);
}
static void out_of_bound(paddr_t addr) {
panic("address = " FMT_PADDR " is out of bound of pmem [" FMT_PADDR ", " FMT_PADDR "] at pc = " FMT_WORD,
addr, PMEM_LEFT, PMEM_RIGHT, cpu.pc);
}
void init_mem() {
#if defined(CONFIG_PMEM_MALLOC)
pmem = malloc(CONFIG_MSIZE);
assert(pmem);
#endif
IFDEF(CONFIG_MEM_RANDOM, memset(pmem, rand(), CONFIG_MSIZE));
Log("physical memory area [" FMT_PADDR ", " FMT_PADDR "]", PMEM_LEFT, PMEM_RIGHT);
}
word_t paddr_read(paddr_t addr, int len) {
if (likely(in_pmem(addr))) return pmem_read(addr, len);
IFDEF(CONFIG_DEVICE, return mmio_read(addr, len));
out_of_bound(addr);
return 0;
}
void paddr_write(paddr_t addr, int len, word_t data) {
if (likely(in_pmem(addr))) { pmem_write(addr, len, data); return; }
IFDEF(CONFIG_DEVICE, mmio_write(addr, len, data); return);
out_of_bound(addr);
}

29
nemu/src/memory/vaddr.c Normal file
View file

@ -0,0 +1,29 @@
/***************************************************************************************
* Copyright (c) 2014-2022 Zihao Yu, Nanjing University
*
* NEMU is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
* http://license.coscl.org.cn/MulanPSL2
*
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
*
* See the Mulan PSL v2 for more details.
***************************************************************************************/
#include <isa.h>
#include <memory/paddr.h>
word_t vaddr_ifetch(vaddr_t addr, int len) {
return paddr_read(addr, len);
}
word_t vaddr_read(vaddr_t addr, int len) {
return paddr_read(addr, len);
}
void vaddr_write(vaddr_t addr, int len, word_t data) {
paddr_write(addr, len, data);
}

162
nemu/src/monitor/monitor.c Normal file
View file

@ -0,0 +1,162 @@
/***************************************************************************************
* Copyright (c) 2014-2022 Zihao Yu, Nanjing University
*
* NEMU is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
* http://license.coscl.org.cn/MulanPSL2
*
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
*
* See the Mulan PSL v2 for more details.
***************************************************************************************/
#include <isa.h>
#include <memory/paddr.h>
void init_rand();
void init_log(const char *log_file);
void init_mem();
void init_difftest(char *ref_so_file, long img_size, int port);
void init_device();
void init_sdb();
void init_disasm(const char *triple);
static void welcome() {
Log("Trace: %s", MUXDEF(CONFIG_TRACE, ANSI_FMT("ON", ANSI_FG_GREEN), ANSI_FMT("OFF", ANSI_FG_RED)));
IFDEF(CONFIG_TRACE, Log("If trace is enabled, a log file will be generated "
"to record the trace. This may lead to a large log file. "
"If it is not necessary, you can disable it in menuconfig"));
Log("Build time: %s, %s", __TIME__, __DATE__);
printf("Welcome to %s-NEMU!\n", ANSI_FMT(str(__GUEST_ISA__), ANSI_FG_YELLOW ANSI_BG_RED));
printf("For help, type \"help\"\n");
Log("Exercise: Please remove me in the source code and compile NEMU again.");
assert(0);
}
#ifndef CONFIG_TARGET_AM
#include <getopt.h>
void sdb_set_batch_mode();
static char *log_file = NULL;
static char *diff_so_file = NULL;
static char *img_file = NULL;
static int difftest_port = 1234;
static long load_img() {
if (img_file == NULL) {
Log("No image is given. Use the default build-in image.");
return 4096; // built-in image size
}
FILE *fp = fopen(img_file, "rb");
Assert(fp, "Can not open '%s'", img_file);
fseek(fp, 0, SEEK_END);
long size = ftell(fp);
Log("The image is %s, size = %ld", img_file, size);
fseek(fp, 0, SEEK_SET);
int ret = fread(guest_to_host(RESET_VECTOR), size, 1, fp);
assert(ret == 1);
fclose(fp);
return size;
}
static int parse_args(int argc, char *argv[]) {
const struct option table[] = {
{"batch" , no_argument , NULL, 'b'},
{"log" , required_argument, NULL, 'l'},
{"diff" , required_argument, NULL, 'd'},
{"port" , required_argument, NULL, 'p'},
{"help" , no_argument , NULL, 'h'},
{0 , 0 , NULL, 0 },
};
int o;
while ( (o = getopt_long(argc, argv, "-bhl:d:p:", table, NULL)) != -1) {
switch (o) {
case 'b': sdb_set_batch_mode(); break;
case 'p': sscanf(optarg, "%d", &difftest_port); break;
case 'l': log_file = optarg; break;
case 'd': diff_so_file = optarg; break;
case 1: img_file = optarg; return 0;
default:
printf("Usage: %s [OPTION...] IMAGE [args]\n\n", argv[0]);
printf("\t-b,--batch run with batch mode\n");
printf("\t-l,--log=FILE output log to FILE\n");
printf("\t-d,--diff=REF_SO run DiffTest with reference REF_SO\n");
printf("\t-p,--port=PORT run DiffTest with port PORT\n");
printf("\n");
exit(0);
}
}
return 0;
}
void init_monitor(int argc, char *argv[]) {
/* Perform some global initialization. */
/* Parse arguments. */
parse_args(argc, argv);
/* Set random seed. */
init_rand();
/* Open the log file. */
init_log(log_file);
/* Initialize memory. */
init_mem();
/* Initialize devices. */
IFDEF(CONFIG_DEVICE, init_device());
/* Perform ISA dependent initialization. */
init_isa();
/* Load the image to memory. This will overwrite the built-in image. */
long img_size = load_img();
/* Initialize differential testing. */
init_difftest(diff_so_file, img_size, difftest_port);
/* Initialize the simple debugger. */
init_sdb();
#ifndef CONFIG_ISA_loongarch32r
IFDEF(CONFIG_ITRACE, init_disasm(
MUXDEF(CONFIG_ISA_x86, "i686",
MUXDEF(CONFIG_ISA_mips32, "mipsel",
MUXDEF(CONFIG_ISA_riscv,
MUXDEF(CONFIG_RV64, "riscv64",
"riscv32"),
"bad"))) "-pc-linux-gnu"
));
#endif
/* Display welcome message. */
welcome();
}
#else // CONFIG_TARGET_AM
static long load_img() {
extern char bin_start, bin_end;
size_t size = &bin_end - &bin_start;
Log("img size = %ld", size);
memcpy(guest_to_host(RESET_VECTOR), &bin_start, size);
return size;
}
void am_init_monitor() {
init_rand();
init_mem();
init_isa();
load_img();
IFDEF(CONFIG_DEVICE, init_device());
welcome();
}
#endif

125
nemu/src/monitor/sdb/expr.c Normal file
View file

@ -0,0 +1,125 @@
/***************************************************************************************
* Copyright (c) 2014-2022 Zihao Yu, Nanjing University
*
* NEMU is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
* http://license.coscl.org.cn/MulanPSL2
*
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
*
* See the Mulan PSL v2 for more details.
***************************************************************************************/
#include <isa.h>
/* We use the POSIX regex functions to process regular expressions.
* Type 'man regex' for more information about POSIX regex functions.
*/
#include <regex.h>
enum {
TK_NOTYPE = 256, TK_EQ,
/* TODO: Add more token types */
};
static struct rule {
const char *regex;
int token_type;
} rules[] = {
/* TODO: Add more rules.
* Pay attention to the precedence level of different rules.
*/
{" +", TK_NOTYPE}, // spaces
{"\\+", '+'}, // plus
{"==", TK_EQ}, // equal
};
#define NR_REGEX ARRLEN(rules)
static regex_t re[NR_REGEX] = {};
/* Rules are used for many times.
* Therefore we compile them only once before any usage.
*/
void init_regex() {
int i;
char error_msg[128];
int ret;
for (i = 0; i < NR_REGEX; i ++) {
ret = regcomp(&re[i], rules[i].regex, REG_EXTENDED);
if (ret != 0) {
regerror(ret, &re[i], error_msg, 128);
panic("regex compilation failed: %s\n%s", error_msg, rules[i].regex);
}
}
}
typedef struct token {
int type;
char str[32];
} Token;
static Token tokens[32] __attribute__((used)) = {};
static int nr_token __attribute__((used)) = 0;
static bool make_token(char *e) {
int position = 0;
int i;
regmatch_t pmatch;
nr_token = 0;
while (e[position] != '\0') {
/* Try all rules one by one. */
for (i = 0; i < NR_REGEX; i ++) {
if (regexec(&re[i], e + position, 1, &pmatch, 0) == 0 && pmatch.rm_so == 0) {
char *substr_start = e + position;
int substr_len = pmatch.rm_eo;
Log("match rules[%d] = \"%s\" at position %d with len %d: %.*s",
i, rules[i].regex, position, substr_len, substr_len, substr_start);
position += substr_len;
/* TODO: Now a new token is recognized with rules[i]. Add codes
* to record the token in the array `tokens'. For certain types
* of tokens, some extra actions should be performed.
*/
switch (rules[i].token_type) {
default: TODO();
}
break;
}
}
if (i == NR_REGEX) {
printf("no match at position %d\n%s\n%*.s^\n", position, e, position, "");
return false;
}
}
return true;
}
word_t expr(char *e, bool *success) {
if (!make_token(e)) {
*success = false;
return 0;
}
/* TODO: Insert codes to evaluate the expression. */
TODO();
return 0;
}

143
nemu/src/monitor/sdb/sdb.c Normal file
View file

@ -0,0 +1,143 @@
/***************************************************************************************
* Copyright (c) 2014-2022 Zihao Yu, Nanjing University
*
* NEMU is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
* http://license.coscl.org.cn/MulanPSL2
*
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
*
* See the Mulan PSL v2 for more details.
***************************************************************************************/
#include <isa.h>
#include <cpu/cpu.h>
#include <readline/readline.h>
#include <readline/history.h>
#include "sdb.h"
static int is_batch_mode = false;
void init_regex();
void init_wp_pool();
/* We use the `readline' library to provide more flexibility to read from stdin. */
static char* rl_gets() {
static char *line_read = NULL;
if (line_read) {
free(line_read);
line_read = NULL;
}
line_read = readline("(nemu) ");
if (line_read && *line_read) {
add_history(line_read);
}
return line_read;
}
static int cmd_c(char *args) {
cpu_exec(-1);
return 0;
}
static int cmd_q(char *args) {
return -1;
}
static int cmd_help(char *args);
static struct {
const char *name;
const char *description;
int (*handler) (char *);
} cmd_table [] = {
{ "help", "Display information about all supported commands", cmd_help },
{ "c", "Continue the execution of the program", cmd_c },
{ "q", "Exit NEMU", cmd_q },
/* TODO: Add more commands */
};
#define NR_CMD ARRLEN(cmd_table)
static int cmd_help(char *args) {
/* extract the first argument */
char *arg = strtok(NULL, " ");
int i;
if (arg == NULL) {
/* no argument given */
for (i = 0; i < NR_CMD; i ++) {
printf("%s - %s\n", cmd_table[i].name, cmd_table[i].description);
}
}
else {
for (i = 0; i < NR_CMD; i ++) {
if (strcmp(arg, cmd_table[i].name) == 0) {
printf("%s - %s\n", cmd_table[i].name, cmd_table[i].description);
return 0;
}
}
printf("Unknown command '%s'\n", arg);
}
return 0;
}
void sdb_set_batch_mode() {
is_batch_mode = true;
}
void sdb_mainloop() {
if (is_batch_mode) {
cmd_c(NULL);
return;
}
for (char *str; (str = rl_gets()) != NULL; ) {
char *str_end = str + strlen(str);
/* extract the first token as the command */
char *cmd = strtok(str, " ");
if (cmd == NULL) { continue; }
/* treat the remaining string as the arguments,
* which may need further parsing
*/
char *args = cmd + strlen(cmd) + 1;
if (args >= str_end) {
args = NULL;
}
#ifdef CONFIG_DEVICE
extern void sdl_clear_event_queue();
sdl_clear_event_queue();
#endif
int i;
for (i = 0; i < NR_CMD; i ++) {
if (strcmp(cmd, cmd_table[i].name) == 0) {
if (cmd_table[i].handler(args) < 0) { return; }
break;
}
}
if (i == NR_CMD) { printf("Unknown command '%s'\n", cmd); }
}
}
void init_sdb() {
/* Compile the regular expressions. */
init_regex();
/* Initialize the watchpoint pool. */
init_wp_pool();
}

View file

@ -0,0 +1,23 @@
/***************************************************************************************
* Copyright (c) 2014-2022 Zihao Yu, Nanjing University
*
* NEMU is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
* http://license.coscl.org.cn/MulanPSL2
*
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
*
* See the Mulan PSL v2 for more details.
***************************************************************************************/
#ifndef __SDB_H__
#define __SDB_H__
#include <common.h>
word_t expr(char *e, bool *success);
#endif

View file

@ -0,0 +1,43 @@
/***************************************************************************************
* Copyright (c) 2014-2022 Zihao Yu, Nanjing University
*
* NEMU is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
* http://license.coscl.org.cn/MulanPSL2
*
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
*
* See the Mulan PSL v2 for more details.
***************************************************************************************/
#include "sdb.h"
#define NR_WP 32
typedef struct watchpoint {
int NO;
struct watchpoint *next;
/* TODO: Add more members if necessary */
} WP;
static WP wp_pool[NR_WP] = {};
static WP *head = NULL, *free_ = NULL;
void init_wp_pool() {
int i;
for (i = 0; i < NR_WP; i ++) {
wp_pool[i].NO = i;
wp_pool[i].next = (i == NR_WP - 1 ? NULL : &wp_pool[i + 1]);
}
head = NULL;
free_ = wp_pool;
}
/* TODO: Implement the functionality of watchpoint */

35
nemu/src/nemu-main.c Normal file
View file

@ -0,0 +1,35 @@
/***************************************************************************************
* Copyright (c) 2014-2022 Zihao Yu, Nanjing University
*
* NEMU is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
* http://license.coscl.org.cn/MulanPSL2
*
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
*
* See the Mulan PSL v2 for more details.
***************************************************************************************/
#include <common.h>
void init_monitor(int, char *[]);
void am_init_monitor();
void engine_start();
int is_exit_status_bad();
int main(int argc, char *argv[]) {
/* Initialize the monitor. */
#ifdef CONFIG_TARGET_AM
am_init_monitor();
#else
init_monitor(argc, argv);
#endif
/* Start engine. */
engine_start();
return is_exit_status_bad();
}

109
nemu/src/utils/disasm.cc Normal file
View file

@ -0,0 +1,109 @@
/***************************************************************************************
* Copyright (c) 2014-2022 Zihao Yu, Nanjing University
*
* NEMU is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
* http://license.coscl.org.cn/MulanPSL2
*
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
*
* See the Mulan PSL v2 for more details.
***************************************************************************************/
#if defined(__GNUC__) && !defined(__clang__)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
#endif
#include "llvm/MC/MCAsmInfo.h"
#include "llvm/MC/MCContext.h"
#include "llvm/MC/MCDisassembler/MCDisassembler.h"
#include "llvm/MC/MCInstPrinter.h"
#if LLVM_VERSION_MAJOR >= 14
#include "llvm/MC/TargetRegistry.h"
#if LLVM_VERSION_MAJOR >= 15
#include "llvm/MC/MCSubtargetInfo.h"
#endif
#else
#include "llvm/Support/TargetRegistry.h"
#endif
#include "llvm/Support/TargetSelect.h"
#if defined(__GNUC__) && !defined(__clang__)
#pragma GCC diagnostic pop
#endif
#if LLVM_VERSION_MAJOR < 11
#error Please use LLVM with major version >= 11
#endif
using namespace llvm;
static llvm::MCDisassembler *gDisassembler = nullptr;
static llvm::MCSubtargetInfo *gSTI = nullptr;
static llvm::MCInstPrinter *gIP = nullptr;
extern "C" void init_disasm(const char *triple) {
llvm::InitializeAllTargetInfos();
llvm::InitializeAllTargetMCs();
llvm::InitializeAllAsmParsers();
llvm::InitializeAllDisassemblers();
std::string errstr;
std::string gTriple(triple);
llvm::MCInstrInfo *gMII = nullptr;
llvm::MCRegisterInfo *gMRI = nullptr;
auto target = llvm::TargetRegistry::lookupTarget(gTriple, errstr);
if (!target) {
llvm::errs() << "Can't find target for " << gTriple << ": " << errstr << "\n";
assert(0);
}
MCTargetOptions MCOptions;
gSTI = target->createMCSubtargetInfo(gTriple, "", "");
std::string isa = target->getName();
if (isa == "riscv32" || isa == "riscv64") {
gSTI->ApplyFeatureFlag("+m");
gSTI->ApplyFeatureFlag("+a");
gSTI->ApplyFeatureFlag("+c");
gSTI->ApplyFeatureFlag("+f");
gSTI->ApplyFeatureFlag("+d");
}
gMII = target->createMCInstrInfo();
gMRI = target->createMCRegInfo(gTriple);
auto AsmInfo = target->createMCAsmInfo(*gMRI, gTriple, MCOptions);
#if LLVM_VERSION_MAJOR >= 13
auto llvmTripleTwine = Twine(triple);
auto llvmtriple = llvm::Triple(llvmTripleTwine);
auto Ctx = new llvm::MCContext(llvmtriple,AsmInfo, gMRI, nullptr);
#else
auto Ctx = new llvm::MCContext(AsmInfo, gMRI, nullptr);
#endif
gDisassembler = target->createMCDisassembler(*gSTI, *Ctx);
gIP = target->createMCInstPrinter(llvm::Triple(gTriple),
AsmInfo->getAssemblerDialect(), *AsmInfo, *gMII, *gMRI);
gIP->setPrintImmHex(true);
gIP->setPrintBranchImmAsAddress(true);
if (isa == "riscv32" || isa == "riscv64")
gIP->applyTargetSpecificCLOption("no-aliases");
}
extern "C" void disassemble(char *str, int size, uint64_t pc, uint8_t *code, int nbyte) {
MCInst inst;
llvm::ArrayRef<uint8_t> arr(code, nbyte);
uint64_t dummy_size = 0;
gDisassembler->getInstruction(inst, dummy_size, arr, pc, llvm::nulls());
std::string s;
raw_string_ostream os(s);
gIP->printInst(&inst, pc, "", *gSTI, os);
int skip = s.find_first_not_of('\t');
const char *p = s.c_str() + skip;
assert((int)s.length() - skip < size);
strcpy(str, p);
}

View file

@ -0,0 +1,20 @@
#***************************************************************************************
# Copyright (c) 2014-2022 Zihao Yu, Nanjing University
#
# NEMU is licensed under Mulan PSL v2.
# You can use this software according to the terms and conditions of the Mulan PSL v2.
# You may obtain a copy of Mulan PSL v2 at:
# http://license.coscl.org.cn/MulanPSL2
#
# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
# EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
# MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
#
# See the Mulan PSL v2 for more details.
#**************************************************************************************/
ifneq ($(CONFIG_ITRACE)$(CONFIG_IQUEUE),)
CXXSRC = src/utils/disasm.cc
CXXFLAGS += $(shell llvm-config --cxxflags) -fPIE
LIBS += $(shell llvm-config --libs)
endif

37
nemu/src/utils/log.c Normal file
View file

@ -0,0 +1,37 @@
/***************************************************************************************
* Copyright (c) 2014-2022 Zihao Yu, Nanjing University
*
* NEMU is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
* http://license.coscl.org.cn/MulanPSL2
*
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
*
* See the Mulan PSL v2 for more details.
***************************************************************************************/
#include <common.h>
extern uint64_t g_nr_guest_inst;
#ifndef CONFIG_TARGET_AM
FILE *log_fp = NULL;
void init_log(const char *log_file) {
log_fp = stdout;
if (log_file != NULL) {
FILE *fp = fopen(log_file, "w");
Assert(fp, "Can not open '%s'", log_file);
log_fp = fp;
}
Log("Log is written to %s", log_file ? log_file : "stdout");
}
bool log_enable() {
return MUXDEF(CONFIG_TRACE, (g_nr_guest_inst >= CONFIG_TRACE_START) &&
(g_nr_guest_inst <= CONFIG_TRACE_END), false);
}
#endif

24
nemu/src/utils/state.c Normal file
View file

@ -0,0 +1,24 @@
/***************************************************************************************
* Copyright (c) 2014-2022 Zihao Yu, Nanjing University
*
* NEMU is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
* http://license.coscl.org.cn/MulanPSL2
*
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
*
* See the Mulan PSL v2 for more details.
***************************************************************************************/
#include <utils.h>
NEMUState nemu_state = { .state = NEMU_STOP };
int is_exit_status_bad() {
int good = (nemu_state.state == NEMU_END && nemu_state.halt_ret == 0) ||
(nemu_state.state == NEMU_QUIT);
return !good;
}

49
nemu/src/utils/timer.c Normal file
View file

@ -0,0 +1,49 @@
/***************************************************************************************
* Copyright (c) 2014-2022 Zihao Yu, Nanjing University
*
* NEMU is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
* http://license.coscl.org.cn/MulanPSL2
*
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
*
* See the Mulan PSL v2 for more details.
***************************************************************************************/
#include <common.h>
#include MUXDEF(CONFIG_TIMER_GETTIMEOFDAY, <sys/time.h>, <time.h>)
IFDEF(CONFIG_TIMER_CLOCK_GETTIME,
static_assert(CLOCKS_PER_SEC == 1000000, "CLOCKS_PER_SEC != 1000000"));
IFDEF(CONFIG_TIMER_CLOCK_GETTIME,
static_assert(sizeof(clock_t) == 8, "sizeof(clock_t) != 8"));
static uint64_t boot_time = 0;
static uint64_t get_time_internal() {
#if defined(CONFIG_TARGET_AM)
uint64_t us = io_read(AM_TIMER_UPTIME).us;
#elif defined(CONFIG_TIMER_GETTIMEOFDAY)
struct timeval now;
gettimeofday(&now, NULL);
uint64_t us = now.tv_sec * 1000000 + now.tv_usec;
#else
struct timespec now;
clock_gettime(CLOCK_MONOTONIC_COARSE, &now);
uint64_t us = now.tv_sec * 1000000 + now.tv_nsec / 1000;
#endif
return us;
}
uint64_t get_time() {
if (boot_time == 0) boot_time = get_time_internal();
uint64_t now = get_time_internal();
return now - boot_time;
}
void init_rand() {
srand(get_time_internal());
}

28
nemu/tools/difftest.mk Normal file
View file

@ -0,0 +1,28 @@
#***************************************************************************************
# Copyright (c) 2014-2022 Zihao Yu, Nanjing University
#
# NEMU is licensed under Mulan PSL v2.
# You can use this software according to the terms and conditions of the Mulan PSL v2.
# You may obtain a copy of Mulan PSL v2 at:
# http://license.coscl.org.cn/MulanPSL2
#
# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
# EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
# MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
#
# See the Mulan PSL v2 for more details.
#**************************************************************************************/
ifdef CONFIG_DIFFTEST
DIFF_REF_PATH = $(NEMU_HOME)/$(call remove_quote,$(CONFIG_DIFFTEST_REF_PATH))
DIFF_REF_SO = $(DIFF_REF_PATH)/build/$(GUEST_ISA)-$(call remove_quote,$(CONFIG_DIFFTEST_REF_NAME))-so
MKFLAGS = GUEST_ISA=$(GUEST_ISA) SHARE=1 ENGINE=interpreter
ARGS_DIFF = --diff=$(DIFF_REF_SO)
ifndef CONFIG_DIFFTEST_REF_NEMU
$(DIFF_REF_SO):
$(MAKE) -s -C $(DIFF_REF_PATH) $(MKFLAGS)
endif
.PHONY: $(DIFF_REF_SO)
endif

View file

@ -0,0 +1,3 @@
NAME = fixdep
SRCS = fixdep.c
include $(NEMU_HOME)/scripts/build.mk

Some files were not shown because too many files have changed in this diff Show more