Compare commits
105 commits
tracer-ysy
...
master
Author | SHA1 | Date | |
---|---|---|---|
4c540bd109 | |||
0e408882b2 | |||
3d64dbd200 | |||
1f3e64bb37 | |||
bc04c05081 | |||
b403f8a40b | |||
5ba306c74e | |||
64aee9ae21 | |||
8ee1551dc2 | |||
96ae890632 | |||
a5790308f0 | |||
ba18436c6c | |||
d9efde7a44 | |||
de9f770d08 | |||
85d7840804 | |||
fed4ac225d | |||
c9ad69a32d | |||
385d448746 | |||
ef51673020 | |||
422ff9e006 | |||
f852ee8689 | |||
b317827c3c | |||
f5ea31f676 | |||
d46cd7b4ae | |||
8ffab061ed | |||
5a97fab28f | |||
2ab098d181 | |||
7c982b238b | |||
3acab0a751 | |||
29a9850210 | |||
955f1f2d79 | |||
f38674ce79 | |||
7f0d1ba75a | |||
a54c0d6480 | |||
6ab5d4c156 | |||
4bc4c34af4 | |||
8665aaf7d2 | |||
9f64a88f8d | |||
4c07b66093 | |||
e99236f711 | |||
55230247b2 | |||
89847cfdb4 | |||
e828e140cd | |||
8500df8a6e | |||
50f7d4d7b9 | |||
ca06354f16 | |||
e1438e25ed | |||
6f7d7ba383 | |||
c242e8c507 | |||
f02d5eb2f1 | |||
849f2bb5f3 | |||
97cf418c86 | |||
a478ef7639 | |||
a91adb3a7d | |||
db66021248 | |||
84c8de8461 | |||
dc2cb010ce | |||
e2602b5bad | |||
2209c26dce | |||
b02b1d2e37 | |||
c29cbf8090 | |||
642444b384 | |||
1cd55fb7cb | |||
d5feb71b50 | |||
d5521806d9 | |||
2cc992a181 | |||
8545a92c1f | |||
da0c42422d | |||
18db852763 | |||
a62a132587 | |||
9229e4318e | |||
0f7c6fd508 | |||
c917083554 | |||
f1a575b2fd | |||
d67fb1138a | |||
|
64f891308e | ||
833cf7b6d1 | |||
e764133868 | |||
3c7c5f060e | |||
f9808d0a40 | |||
86ba43a25b | |||
12f5ba0897 | |||
504d270947 | |||
2675a647b0 | |||
4aa536e1ef | |||
ebece52aec | |||
e19e89f70e | |||
9cca9de2a8 | |||
69264e69c6 | |||
4770b4ce97 | |||
1af1dbcd20 | |||
096cc220d1 | |||
fd3838a61d | |||
4a38cb566b | |||
674702b552 | |||
1118f64668 | |||
0b34b19bdf | |||
a2986aab78 | |||
ccbcbabb27 | |||
77ea7e3b8c | |||
1702da0a0a | |||
38818f6f66 | |||
8e861a43fb | |||
97df569747 | |||
f6803239c7 |
185 changed files with 8696 additions and 1330 deletions
4
.clang-format
Normal file
4
.clang-format
Normal file
|
@ -0,0 +1,4 @@
|
|||
---
|
||||
Language: Cpp
|
||||
BasedOnStyle: LLVM
|
||||
ReflowComments: false
|
28
.gitea/workflows/build-nix-package.yml
Normal file
28
.gitea/workflows/build-nix-package.yml
Normal file
|
@ -0,0 +1,28 @@
|
|||
name: Build abstract machine with nix
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
pull_request:
|
||||
branches:
|
||||
- master
|
||||
|
||||
jobs:
|
||||
build-packages:
|
||||
runs-on: nix
|
||||
strategy:
|
||||
matrix:
|
||||
package:
|
||||
- "abstract-machine"
|
||||
- "nemu"
|
||||
- "nemu-lib"
|
||||
- "rv32Cross.abstract-machine"
|
||||
steps:
|
||||
- uses: https://github.com/cachix/cachix-action@v14
|
||||
with:
|
||||
name: ysyx
|
||||
authToken: '${{ secrets.CACHIX_SIGNING_KEY }}'
|
||||
- uses: actions/checkout@v4
|
||||
- name: Build package
|
||||
run: |
|
||||
nix build -L .#${{ matrix.package }}
|
21
.gitea/workflows/build-npc.yml
Normal file
21
.gitea/workflows/build-npc.yml
Normal file
|
@ -0,0 +1,21 @@
|
|||
name: Build npc tests
|
||||
on: [push]
|
||||
|
||||
jobs:
|
||||
npc-build:
|
||||
strategy:
|
||||
matrix:
|
||||
package: [ "flow", "flow-simlib"]
|
||||
runs-on: nix
|
||||
defaults:
|
||||
run:
|
||||
working-directory: ./npc
|
||||
steps:
|
||||
- uses: https://github.com/cachix/cachix-action@v14
|
||||
with:
|
||||
name: ysyx
|
||||
authToken: '${{ secrets.CACHIX_SIGNING_KEY }}'
|
||||
- uses: actions/checkout@v4
|
||||
- name: Build package
|
||||
run: |
|
||||
nix build -L .#${{ matrix.package }}
|
19
.gitignore
vendored
19
.gitignore
vendored
|
@ -1,13 +1,8 @@
|
|||
*.*
|
||||
*
|
||||
!*/
|
||||
!/nemu/*
|
||||
!/nexus-am/*
|
||||
!/nanos-lite/*
|
||||
!/navy-apps/*
|
||||
!/npc/*
|
||||
!Makefile
|
||||
!README.md
|
||||
!.gitignore
|
||||
!init.sh
|
||||
*/.gdbinit
|
||||
difftest/
|
||||
/fceux-am
|
||||
/nvboard
|
||||
**/.cache
|
||||
**/result
|
||||
/.pre-commit-config.yaml
|
||||
**/.vscode/
|
||||
|
|
7
.gitmodules
vendored
Normal file
7
.gitmodules
vendored
Normal file
|
@ -0,0 +1,7 @@
|
|||
[submodule "am-kernels"]
|
||||
path = am-kernels
|
||||
url = https://git.xinyang.life/xin/am-kernels.git
|
||||
branch = dev
|
||||
[submodule "diffu"]
|
||||
path = diffu
|
||||
url = git@github.com:xinyangli/diffu.git
|
2
.scalafmt.conf
Normal file
2
.scalafmt.conf
Normal file
|
@ -0,0 +1,2 @@
|
|||
version = 3.7.17
|
||||
runner.dialect = scala213source3
|
2
Makefile
2
Makefile
|
@ -4,7 +4,7 @@ STUNAME = 李心杨
|
|||
# DO NOT modify the following code!!!
|
||||
|
||||
TRACER = tracer-ysyx
|
||||
GITFLAGS = -q --author='$(TRACER) <tracer@ysyx.org>' --no-verify --allow-empty
|
||||
GITFLAGS = -q --author='$(TRACER) <tracer@ysyx.org>' --no-verify --allow-empty --no-gpg-sign
|
||||
|
||||
YSYX_HOME = $(NEMU_HOME)/..
|
||||
WORK_BRANCH = $(shell git rev-parse --abbrev-ref HEAD)
|
||||
|
|
25
abstract-machine/.gitignore
vendored
25
abstract-machine/.gitignore
vendored
|
@ -1,19 +1,8 @@
|
|||
*
|
||||
!*/
|
||||
!*.h
|
||||
!*.c
|
||||
!*.cc
|
||||
!*.S
|
||||
!*.ld
|
||||
!*.sh
|
||||
!*.py
|
||||
!*.mk
|
||||
!Makefile
|
||||
!README
|
||||
!LICENSE
|
||||
.*
|
||||
_*
|
||||
*~
|
||||
build/
|
||||
!.gitignore
|
||||
**/.direnv/
|
||||
**/build/
|
||||
**/.envrc
|
||||
**/.cache
|
||||
out/
|
||||
.vscode
|
||||
compile_commands.json
|
||||
cmakeUserh
|
||||
|
|
126
abstract-machine/CMakeLists.txt
Normal file
126
abstract-machine/CMakeLists.txt
Normal file
|
@ -0,0 +1,126 @@
|
|||
cmake_minimum_required(VERSION 3.22)
|
||||
|
||||
project(abstract-machine)
|
||||
enable_language(CXX C ASM)
|
||||
set(CMAKE_C_STANDARD 11)
|
||||
set(CMAKE_CXX_STANDARD 11)
|
||||
|
||||
include(CMakeDependentOption)
|
||||
include(CMakePackageConfigHelpers) # Used to find libcheck
|
||||
include(CTest)
|
||||
include(GNUInstallDirs)
|
||||
|
||||
# -- General options
|
||||
set(ISA CACHE STRING "Target ISA")
|
||||
set_property(CACHE ISA PROPERTY STRINGS "riscv" "x86" "x86_64" "native")
|
||||
string(TOUPPER ${ISA} ISA_UPPER)
|
||||
|
||||
cmake_dependent_option(__PLATFORM_NEMU__ "Run on NEMU" ON
|
||||
"ISA MATCHES \"(riscv | x86)\"" OFF)
|
||||
cmake_dependent_option(__PLATFORM_NPC__ "Run on NPC" ON "ISA MATCHES riscv" OFF)
|
||||
cmake_dependent_option(__PLATFORM_NATIVE__ "Run on native" ON
|
||||
"ISA MATCHES native" OFF)
|
||||
|
||||
# -- Set PLATFORM according to options
|
||||
set(MATCH_PLATFORM_PATTERN "^__PLATFORM_([A-Z]*)__$")
|
||||
get_cmake_property(CACHE_VARS CACHE_VARIABLES)
|
||||
|
||||
message(STATUS "ISA: ${ISA}")
|
||||
foreach(VAR IN LISTS CACHE_VARS)
|
||||
if(VAR MATCHES ${MATCH_PLATFORM_PATTERN})
|
||||
# Retrieve the value of the cache variable
|
||||
get_property(
|
||||
VAR_VALUE
|
||||
CACHE ${VAR}
|
||||
PROPERTY VALUE)
|
||||
set(PLATFORM_UPPER ${CMAKE_MATCH_1})
|
||||
string(TOLOWER ${PLATFORM_UPPER} PLATFORM)
|
||||
list(APPEND PLATFORMS ${PLATFORM})
|
||||
message(STATUS "Variable: ${VAR}=${VAR_VALUE}, Platform: ${PLATFORM}")
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
if((NOT PLATFORM) AND (NOT ISA MATCHES native))
|
||||
message(FATAL_ERROR "Platform not given!")
|
||||
endif()
|
||||
|
||||
set(SUPPORTED_ARCH "riscv-nemu" "riscv-npc" "native")
|
||||
foreach(PLATFORM IN LISTS PLATFORMS)
|
||||
if(${ISA} MATCHES "native")
|
||||
set(ARCH "native")
|
||||
else()
|
||||
set(ARCH ${ISA}-${PLATFORM})
|
||||
endif()
|
||||
|
||||
if(NOT ARCH IN_LIST SUPPORTED_ARCH)
|
||||
message(
|
||||
FATAL_ERROR
|
||||
"Given ISA-PLATFORM (${ISA}-${PLATFORM}) does not match one of the following: ${SUPPORTED_ARCH}"
|
||||
)
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
# -- Target specific options
|
||||
cmake_dependent_option(NATIVE_USE_KLIB "Use Klib even if on native" ON
|
||||
"NOT __ISA_NATIVE__" OFF)
|
||||
|
||||
# -- Add compile definitions based on options
|
||||
|
||||
list(APPEND CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake")
|
||||
|
||||
# NOTE: klib and am include header files in each other, so we need to create
|
||||
# interface libraries for correct dependency
|
||||
add_library(am_interface INTERFACE)
|
||||
target_include_directories(
|
||||
am_interface
|
||||
INTERFACE $<BUILD_INTERFACE:${CMAKE_SOURCE_DIR}/am/include>
|
||||
$<BUILD_INTERFACE:${CMAKE_SOURCE_DIR}/am/src>
|
||||
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>)
|
||||
target_compile_definitions(am_interface INTERFACE ARCH_H=<arch/${ISA}.h>
|
||||
"__ISA__=\"${ISA}\"")
|
||||
file(GLOB_RECURSE AM_HEADERS "${CMAKE_SOURCE_DIR}/am/include/*.h")
|
||||
target_sources(
|
||||
am_interface
|
||||
PUBLIC FILE_SET
|
||||
am_headers
|
||||
TYPE
|
||||
HEADERS
|
||||
BASE_DIRS
|
||||
${CMAKE_SOURCE_DIR}/am/include
|
||||
FILES
|
||||
${AM_HEADERS})
|
||||
|
||||
add_library(klib_interface INTERFACE)
|
||||
target_include_directories(
|
||||
klib_interface
|
||||
INTERFACE $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/klib/include>
|
||||
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>)
|
||||
file(GLOB_RECURSE KLIB_HEADERS "${CMAKE_SOURCE_DIR}/klib/include/*.h")
|
||||
target_sources(
|
||||
klib_interface
|
||||
PUBLIC FILE_SET
|
||||
klib_headers
|
||||
TYPE
|
||||
HEADERS
|
||||
BASE_DIRS
|
||||
${CMAKE_SOURCE_DIR}/klib/include
|
||||
FILES
|
||||
${KLIB_HEADERS})
|
||||
|
||||
install(
|
||||
TARGETS am_interface klib_interface
|
||||
EXPORT interfaceTargets
|
||||
FILE_SET klib_headers FILE_SET am_headers
|
||||
INCLUDES
|
||||
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})
|
||||
|
||||
install(
|
||||
EXPORT interfaceTargets
|
||||
FILE interfaceTargets.cmake
|
||||
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake)
|
||||
|
||||
add_subdirectory(klib)
|
||||
add_subdirectory(am)
|
||||
|
||||
# -- Test depends on klib and am should be added last.
|
||||
add_subdirectory(klib/tests)
|
29
abstract-machine/CMakePresets.json
Normal file
29
abstract-machine/CMakePresets.json
Normal file
|
@ -0,0 +1,29 @@
|
|||
{
|
||||
"version": 6,
|
||||
"configurePresets": [
|
||||
{
|
||||
"name": "native",
|
||||
"displayName": "Native",
|
||||
"generator": "Unix Makefiles",
|
||||
"binaryDir": "${sourceDir}/out/build/${presetName}",
|
||||
"cacheVariables": {
|
||||
"CMAKE_BUILD_TYPE": "RelWithDebInfo",
|
||||
"ISA": "native",
|
||||
"__PLATFORM_NATIVE__": true,
|
||||
"NATIVE_USE_KLIB": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "riscv",
|
||||
"displayName": "RV32 all platform",
|
||||
"generator": "Unix Makefiles",
|
||||
"binaryDir": "${sourceDir}/out/build/${presetName}",
|
||||
"cacheVariables": {
|
||||
"CMAKE_BUILD_TYPE": "RelWithDebInfo",
|
||||
"ISA": "riscv",
|
||||
"__PLATFORM_NPC__": true,
|
||||
"__PLATFORM_NEMU__": true
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
15
abstract-machine/CMakeUserPresets.json
Normal file
15
abstract-machine/CMakeUserPresets.json
Normal file
|
@ -0,0 +1,15 @@
|
|||
{
|
||||
"version": 6,
|
||||
"configurePresets": [
|
||||
{
|
||||
"name": "Native install",
|
||||
"inherits": "native",
|
||||
"installDir": "/home/xin/repo/ysyx-workbench/abstract-machine/out/install"
|
||||
},
|
||||
{
|
||||
"name": "RISCV install",
|
||||
"inherits": "riscv",
|
||||
"installDir": "/home/xin/repo/ysyx-workbench/abstract-machine/out/install"
|
||||
}
|
||||
]
|
||||
}
|
|
@ -47,33 +47,32 @@ endif
|
|||
|
||||
### Create the destination directory (`build/$ARCH`)
|
||||
WORK_DIR = $(shell pwd)
|
||||
DST_DIR = $(WORK_DIR)/build/$(ARCH)
|
||||
BUILD_DIR ?= $(WORK_DIR)/build
|
||||
DST_DIR = $(BUILD_DIR)/$(ARCH)
|
||||
$(shell mkdir -p $(DST_DIR))
|
||||
|
||||
### Compilation targets (a binary image or archive)
|
||||
IMAGE_REL = build/$(NAME)-$(ARCH)
|
||||
IMAGE_REL = $(DST_DIR)/$(NAME)-$(ARCH)
|
||||
IMAGE = $(abspath $(IMAGE_REL))
|
||||
ARCHIVE = $(WORK_DIR)/build/$(NAME)-$(ARCH).a
|
||||
ARCHIVE = $(BUILD_DIR)/$(NAME)-$(ARCH).a
|
||||
|
||||
### Collect the files to be linked: object files (`.o`) and libraries (`.a`)
|
||||
OBJS = $(addprefix $(DST_DIR)/, $(addsuffix .o, $(basename $(SRCS))))
|
||||
LIBS := $(sort $(LIBS) am klib) # lazy evaluation ("=") causes infinite recursions
|
||||
LINKAGE = $(OBJS) \
|
||||
$(addsuffix -$(ARCH).a, $(join \
|
||||
$(addsuffix /build/, $(addprefix $(AM_HOME)/, $(LIBS))), \
|
||||
$(LIBS) ))
|
||||
$(addsuffix -$(ARCH).a, $(addprefix $(BUILD_DIR)/, $(LIBS)))
|
||||
|
||||
## 3. General Compilation Flags
|
||||
|
||||
### (Cross) compilers, e.g., mips-linux-gnu-g++
|
||||
AS = $(CROSS_COMPILE)gcc
|
||||
CC = $(CROSS_COMPILE)gcc
|
||||
CXX = $(CROSS_COMPILE)g++
|
||||
LD = $(CROSS_COMPILE)ld
|
||||
AR = $(CROSS_COMPILE)ar
|
||||
OBJDUMP = $(CROSS_COMPILE)objdump
|
||||
OBJCOPY = $(CROSS_COMPILE)objcopy
|
||||
READELF = $(CROSS_COMPILE)readelf
|
||||
AS ?= $(CROSS_COMPILE)gcc
|
||||
CC ?= $(CROSS_COMPILE)gcc
|
||||
CXX ?= $(CROSS_COMPILE)g++
|
||||
LD ?= $(CROSS_COMPILE)ld
|
||||
AR ?= $(CROSS_COMPILE)ar
|
||||
OBJDUMP ?= $(CROSS_COMPILE)objdump
|
||||
OBJCOPY ?= $(CROSS_COMPILE)objcopy
|
||||
READELF ?= $(CROSS_COMPILE)readelf
|
||||
|
||||
### Compilation flags
|
||||
INC_PATH += $(WORK_DIR)/include $(addsuffix /include/, $(addprefix $(AM_HOME)/, $(LIBS)))
|
||||
|
|
26
abstract-machine/am/CMakeLists.txt
Normal file
26
abstract-machine/am/CMakeLists.txt
Normal file
|
@ -0,0 +1,26 @@
|
|||
add_subdirectory(src)
|
||||
|
||||
foreach(PLATFORM IN LISTS PLATFORMS)
|
||||
if(ISA MATCHES "native")
|
||||
set(ARCH "native")
|
||||
else()
|
||||
set(ARCH ${ISA}-${PLATFORM})
|
||||
endif()
|
||||
install(
|
||||
TARGETS am-${ARCH}
|
||||
EXPORT amTargets-${ARCH}
|
||||
LIBRARY DESTINATION lib)
|
||||
|
||||
install(
|
||||
EXPORT amTargets-${ARCH}
|
||||
FILE amTargets.cmake
|
||||
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/am-${ARCH})
|
||||
|
||||
configure_package_config_file(
|
||||
${CMAKE_SOURCE_DIR}/cmake/am-config.cmake.in
|
||||
${CMAKE_CURRENT_BINARY_DIR}/am-${ARCH}-config.cmake
|
||||
INSTALL_DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/am-${ARCH})
|
||||
|
||||
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/am-${ARCH}-config.cmake
|
||||
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/am-${ARCH})
|
||||
endforeach()
|
|
@ -1,5 +1,6 @@
|
|||
#ifndef ARCH_H__
|
||||
#define ARCH_H__
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef __riscv_e
|
||||
#define NR_REGS 16
|
||||
|
@ -9,10 +10,13 @@
|
|||
|
||||
struct Context {
|
||||
// TODO: fix the order of these members to match trap.S
|
||||
uintptr_t mepc, mcause, gpr[NR_REGS], mstatus;
|
||||
uintptr_t gpr[NR_REGS];
|
||||
uintptr_t mcause, mstatus, mepc;
|
||||
void *pdir;
|
||||
};
|
||||
|
||||
enum Cause { CauseEnvironmentCallFromMMode = 11 };
|
||||
|
||||
#ifdef __riscv_e
|
||||
#define GPR1 gpr[15] // a5
|
||||
#else
|
||||
|
|
1
abstract-machine/am/src/CMakeLists.txt
Normal file
1
abstract-machine/am/src/CMakeLists.txt
Normal file
|
@ -0,0 +1 @@
|
|||
add_subdirectory(${ISA})
|
25
abstract-machine/am/src/native/CMakeLists.txt
Normal file
25
abstract-machine/am/src/native/CMakeLists.txt
Normal file
|
@ -0,0 +1,25 @@
|
|||
set(SOURCES
|
||||
trap.S
|
||||
cte.c
|
||||
ioe.c
|
||||
mpe.c
|
||||
platform.c
|
||||
trm.c
|
||||
vme.c
|
||||
ioe/audio.c
|
||||
ioe/disk.c
|
||||
ioe/gpu.c
|
||||
ioe/input.c
|
||||
ioe/timer.c)
|
||||
add_library(am-native ${SOURCES})
|
||||
|
||||
# FIXME: get free(): invalid address when user program compiled without pie
|
||||
set_target_properties(
|
||||
am-native PROPERTIES POSITION_INDEPENDENT_CODE TRUE
|
||||
INTERFACE_POSITION_INDEPENDENT_CODE TRUE)
|
||||
|
||||
find_package(SDL2 REQUIRED)
|
||||
target_link_libraries(
|
||||
am-native
|
||||
PUBLIC SDL2::SDL2 dl m
|
||||
PRIVATE klib_interface am_interface)
|
|
@ -1,5 +1,5 @@
|
|||
#include <stdatomic.h>
|
||||
#include "platform.h"
|
||||
#include <stdatomic.h>
|
||||
|
||||
int __am_mpe_init = 0;
|
||||
extern bool __am_has_ioe;
|
||||
|
@ -16,7 +16,8 @@ bool mpe_init(void (*entry)()) {
|
|||
char ch;
|
||||
assert(read(sync_pipe[0], &ch, 1) == 1);
|
||||
assert(ch == '+');
|
||||
close(sync_pipe[0]); close(sync_pipe[1]);
|
||||
close(sync_pipe[0]);
|
||||
close(sync_pipe[1]);
|
||||
|
||||
thiscpu->cpuid = i;
|
||||
__am_init_timer_irq();
|
||||
|
@ -31,7 +32,8 @@ bool mpe_init(void (*entry)()) {
|
|||
for (int i = 1; i < cpu_count(); i++) {
|
||||
assert(write(sync_pipe[1], "+", 1) == 1);
|
||||
}
|
||||
close(sync_pipe[0]); close(sync_pipe[1]);
|
||||
close(sync_pipe[0]);
|
||||
close(sync_pipe[1]);
|
||||
|
||||
entry();
|
||||
panic("MP entry should not return\n");
|
||||
|
@ -42,9 +44,7 @@ int cpu_count() {
|
|||
return __am_ncpu;
|
||||
}
|
||||
|
||||
int cpu_current() {
|
||||
return thiscpu->cpuid;
|
||||
}
|
||||
int cpu_current() { return thiscpu->cpuid; }
|
||||
|
||||
int atomic_xchg(int *addr, int newval) {
|
||||
return atomic_exchange((int *)addr, newval);
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
#define _GNU_SOURCE
|
||||
#include <sys/mman.h>
|
||||
#include <sys/auxv.h>
|
||||
#include "platform.h"
|
||||
#include <dlfcn.h>
|
||||
#include <elf.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include "platform.h"
|
||||
#include <stdlib.h>
|
||||
#include <sys/auxv.h>
|
||||
#include <sys/mman.h>
|
||||
|
||||
#define MAX_CPU 16
|
||||
#define TRAP_PAGE_START (void *)0x100000
|
||||
|
@ -70,12 +70,12 @@ static void init_platform() {
|
|||
assert(ret2 == 0);
|
||||
|
||||
pmem = mmap(PMEM_START, PMEM_SIZE, PROT_READ | PROT_WRITE | PROT_EXEC,
|
||||
MAP_SHARED | MAP_FIXED, pmem_fd, 0);
|
||||
MAP_SHARED | MAP_FIXED, pmem_fd, 0);
|
||||
assert(pmem != (void *)-1);
|
||||
|
||||
// allocate private per-cpu structure
|
||||
thiscpu = mmap(NULL, sizeof(*thiscpu), PROT_READ | PROT_WRITE,
|
||||
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
|
||||
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
|
||||
assert(thiscpu != (void *)-1);
|
||||
thiscpu->cpuid = 0;
|
||||
thiscpu->vm_head = NULL;
|
||||
|
@ -83,7 +83,7 @@ static void init_platform() {
|
|||
// create trap page to receive syscall and yield by SIGSEGV
|
||||
int sys_pgsz = sysconf(_SC_PAGESIZE);
|
||||
void *ret = mmap(TRAP_PAGE_START, sys_pgsz, PROT_NONE,
|
||||
MAP_SHARED | MAP_ANONYMOUS | MAP_FIXED, -1, 0);
|
||||
MAP_SHARED | MAP_ANONYMOUS | MAP_FIXED, -1, 0);
|
||||
assert(ret != (void *)-1);
|
||||
|
||||
// save the address of memcpy() in glibc, since it may be linked with klib
|
||||
|
@ -94,7 +94,7 @@ static void init_platform() {
|
|||
Elf64_Phdr *phdr = (void *)getauxval(AT_PHDR);
|
||||
int phnum = (int)getauxval(AT_PHNUM);
|
||||
int i;
|
||||
for (i = 0; i < phnum; i ++) {
|
||||
for (i = 0; i < phnum; i++) {
|
||||
if (phdr[i].p_type == PT_LOAD && (phdr[i].p_flags & PF_W)) {
|
||||
// allocate temporary memory
|
||||
extern char end;
|
||||
|
@ -102,7 +102,8 @@ static void init_platform() {
|
|||
uintptr_t pad = (uintptr_t)vaddr & 0xfff;
|
||||
void *vaddr_align = vaddr - pad;
|
||||
uintptr_t size = phdr[i].p_memsz + pad;
|
||||
void *temp_mem = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
|
||||
void *temp_mem = mmap(NULL, size, PROT_READ | PROT_WRITE,
|
||||
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
|
||||
assert(temp_mem != (void *)-1);
|
||||
|
||||
// save data and bss sections
|
||||
|
@ -110,11 +111,13 @@ static void init_platform() {
|
|||
|
||||
// save the address of mmap() which will be used after munamp(),
|
||||
// since calling the library functions requires accessing GOT, which will be unmapped
|
||||
void *(*mmap_libc)(void *, size_t, int, int, int, off_t) = dlsym(RTLD_NEXT, "mmap");
|
||||
void *(*mmap_libc)(void *, size_t, int, int, int, off_t) =
|
||||
dlsym(RTLD_NEXT, "mmap");
|
||||
assert(mmap_libc != NULL);
|
||||
// load the address of memcpy() on stack, which can still be accessed
|
||||
// after the data section is unmapped
|
||||
void *(*volatile memcpy_libc_temp)(void *, const void *, size_t) = memcpy_libc;
|
||||
void *(*volatile memcpy_libc_temp)(void *, const void *, size_t) =
|
||||
memcpy_libc;
|
||||
|
||||
// unmap the data and bss sections
|
||||
ret2 = munmap(vaddr_align, size);
|
||||
|
@ -122,7 +125,7 @@ static void init_platform() {
|
|||
|
||||
// map the sections again with MAP_SHARED, which will be shared across fork()
|
||||
ret = mmap_libc(vaddr_align, size, PROT_READ | PROT_WRITE | PROT_EXEC,
|
||||
MAP_SHARED | MAP_FIXED | MAP_ANONYMOUS, -1, 0);
|
||||
MAP_SHARED | MAP_FIXED | MAP_ANONYMOUS, -1, 0);
|
||||
assert(ret == vaddr_align);
|
||||
|
||||
// restore the data in the sections
|
||||
|
@ -176,7 +179,8 @@ static void init_platform() {
|
|||
void __am_exit_platform(int code) {
|
||||
// let Linux clean up other resource
|
||||
extern int __am_mpe_init;
|
||||
if (__am_mpe_init && cpu_count() > 1) kill(0, SIGKILL);
|
||||
if (__am_mpe_init && cpu_count() > 1)
|
||||
kill(0, SIGKILL);
|
||||
exit(code);
|
||||
}
|
||||
|
||||
|
@ -185,10 +189,12 @@ void __am_pmem_map(void *va, void *pa, int prot) {
|
|||
int mmap_prot = PROT_NONE;
|
||||
// we do not support executable bit, so mark
|
||||
// all readable pages executable as well
|
||||
if (prot & MMAP_READ) mmap_prot |= PROT_READ | PROT_EXEC;
|
||||
if (prot & MMAP_WRITE) mmap_prot |= PROT_WRITE;
|
||||
void *ret = mmap(va, __am_pgsize, mmap_prot,
|
||||
MAP_SHARED | MAP_FIXED, pmem_fd, (uintptr_t)(pa - pmem));
|
||||
if (prot & MMAP_READ)
|
||||
mmap_prot |= PROT_READ | PROT_EXEC;
|
||||
if (prot & MMAP_WRITE)
|
||||
mmap_prot |= PROT_WRITE;
|
||||
void *ret = mmap(va, __am_pgsize, mmap_prot, MAP_SHARED | MAP_FIXED, pmem_fd,
|
||||
(uintptr_t)(pa - pmem));
|
||||
assert(ret != (void *)-1);
|
||||
}
|
||||
|
||||
|
@ -205,26 +211,21 @@ void __am_get_intr_sigmask(sigset_t *s) {
|
|||
memcpy_libc(s, &__am_intr_sigmask, sizeof(__am_intr_sigmask));
|
||||
}
|
||||
|
||||
int __am_is_sigmask_sti(sigset_t *s) {
|
||||
return !sigismember(s, SIGVTALRM);
|
||||
}
|
||||
int __am_is_sigmask_sti(sigset_t *s) { return !sigismember(s, SIGVTALRM); }
|
||||
|
||||
void __am_send_kbd_intr() {
|
||||
kill(getpid(), SIGUSR1);
|
||||
}
|
||||
void __am_send_kbd_intr() { kill(getpid(), SIGUSR1); }
|
||||
|
||||
void __am_pmem_protect() {
|
||||
// int ret = mprotect(PMEM_START, PMEM_SIZE, PROT_NONE);
|
||||
// assert(ret == 0);
|
||||
// int ret = mprotect(PMEM_START, PMEM_SIZE, PROT_NONE);
|
||||
// assert(ret == 0);
|
||||
}
|
||||
|
||||
void __am_pmem_unprotect() {
|
||||
// int ret = mprotect(PMEM_START, PMEM_SIZE, PROT_READ | PROT_WRITE | PROT_EXEC);
|
||||
// assert(ret == 0);
|
||||
// int ret = mprotect(PMEM_START, PMEM_SIZE, PROT_READ | PROT_WRITE | PROT_EXEC);
|
||||
// assert(ret == 0);
|
||||
}
|
||||
|
||||
// This dummy function will be called in trm.c.
|
||||
// The purpose of this dummy function is to let linker add this file to the object
|
||||
// file set. Without it, the constructor of @_init_platform will not be linked.
|
||||
void __am_platform_dummy() {
|
||||
}
|
||||
void __am_platform_dummy() {}
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
#define KEYDOWN_MASK 0x8000
|
||||
|
||||
void __am_input_keybrd(AM_INPUT_KEYBRD_T *kbd) {
|
||||
kbd->keydown = 0;
|
||||
kbd->keycode = AM_KEY_NONE;
|
||||
uint32_t keycode = inl(KBD_ADDR);
|
||||
kbd->keydown = ((keycode & KEYDOWN_MASK) != 0);
|
||||
kbd->keycode = keycode & (~KEYDOWN_MASK);
|
||||
}
|
||||
|
|
|
@ -1,18 +1,17 @@
|
|||
#include <am.h>
|
||||
#include <nemu.h>
|
||||
|
||||
void __am_timer_init() {
|
||||
}
|
||||
void __am_timer_init() {}
|
||||
|
||||
void __am_timer_uptime(AM_TIMER_UPTIME_T *uptime) {
|
||||
uptime->us = 0;
|
||||
uptime->us = ((uint64_t)inl(RTC_ADDR + 4) << 32) + inl(RTC_ADDR);
|
||||
}
|
||||
|
||||
void __am_timer_rtc(AM_TIMER_RTC_T *rtc) {
|
||||
rtc->second = 0;
|
||||
rtc->minute = 0;
|
||||
rtc->hour = 0;
|
||||
rtc->day = 0;
|
||||
rtc->month = 0;
|
||||
rtc->year = 1900;
|
||||
rtc->hour = 0;
|
||||
rtc->day = 0;
|
||||
rtc->month = 0;
|
||||
rtc->year = 1900;
|
||||
}
|
||||
|
|
|
@ -6,19 +6,18 @@ int main(const char *args);
|
|||
|
||||
Area heap = RANGE(&_heap_start, PMEM_END);
|
||||
#ifndef MAINARGS
|
||||
#define MAINARGS ""
|
||||
#define MAINARGS "i"
|
||||
#endif
|
||||
static const char mainargs[] = MAINARGS;
|
||||
|
||||
void putch(char ch) {
|
||||
outb(SERIAL_PORT, ch);
|
||||
}
|
||||
void putch(char ch) { outb(SERIAL_PORT, ch); }
|
||||
|
||||
void halt(int code) {
|
||||
nemu_trap(code);
|
||||
|
||||
// should not reach here
|
||||
while (1);
|
||||
while (1)
|
||||
;
|
||||
}
|
||||
|
||||
void _trm_init() {
|
||||
|
|
9
abstract-machine/am/src/riscv/CMakeLists.txt
Normal file
9
abstract-machine/am/src/riscv/CMakeLists.txt
Normal file
|
@ -0,0 +1,9 @@
|
|||
foreach(PLATFORM IN LISTS PLATFORMS)
|
||||
string(TOUPPER ${ARCH} ARCH_UPPER)
|
||||
set(AM_COMMON_COMPILE_DEF
|
||||
# -- Arch related
|
||||
$<MAKE_C_IDENTIFIER:__ARCH_${ARCH_UPPER}__> __ISA_${ISA_UPPER}__
|
||||
__PLATFORM_${PLATFORM_UPPER}__
|
||||
$<$<BOOL:${NATIVE_USE_KLIB}>:__NATIVE_USE_KLIB__>)
|
||||
add_subdirectory(${PLATFORM})
|
||||
endforeach()
|
41
abstract-machine/am/src/riscv/nemu/CMakeLists.txt
Normal file
41
abstract-machine/am/src/riscv/nemu/CMakeLists.txt
Normal file
|
@ -0,0 +1,41 @@
|
|||
include(nemu-settings)
|
||||
include(riscv-settings)
|
||||
|
||||
add_library(am-riscv-nemu cte.c start.S trap.S vme.c ${NEMU_SOURCES})
|
||||
|
||||
target_compile_options(am-riscv-nemu PRIVATE ${NEMU_COMPILE_OPTIONS}
|
||||
${RISCV_COMPILE_OPTIONS})
|
||||
|
||||
target_link_options(am-riscv-nemu INTERFACE ${NEMU_LINK_OPITIONS}
|
||||
${RISCV_LINK_OPTIONS})
|
||||
|
||||
target_include_directories(am-riscv-nemu PRIVATE ${NEMU_INCLUDE_DIRECTORIES})
|
||||
|
||||
target_link_options(
|
||||
am-riscv-nemu
|
||||
INTERFACE
|
||||
LINKER:--defsym=_pmem_start=0x80000000
|
||||
LINKER:--defsym=_entry_offset=0x0
|
||||
LINKER:--gc-sections
|
||||
LINKER:-e
|
||||
_start
|
||||
-nostartfiles)
|
||||
|
||||
target_link_options(
|
||||
am-riscv-nemu INTERFACE
|
||||
$<BUILD_INTERFACE:-T${CMAKE_SOURCE_DIR}/scripts/linker.ld>
|
||||
$<INSTALL_INTERFACE:-T${CMAKE_INSTALL_FULL_DATADIR}/linker.ld>)
|
||||
|
||||
target_link_libraries(
|
||||
am-riscv-nemu
|
||||
PUBLIC am_interface klib_interface
|
||||
INTERFACE m)
|
||||
|
||||
target_compile_definitions(am-riscv-nemu PRIVATE ISA_H=<riscv/riscv.h>)
|
||||
|
||||
set_target_properties(
|
||||
am-riscv-nemu PROPERTIES POSITION_INDEPENDENT_CODE OFF
|
||||
INTERFACE_POSITION_INDEPENDENT_CODE OFF)
|
||||
|
||||
install(FILES ${CMAKE_SOURCE_DIR}/scripts/linker.ld
|
||||
DESTINATION ${CMAKE_INSTALL_DATADIR})
|
|
@ -1,14 +1,21 @@
|
|||
#include "arch/riscv.h"
|
||||
#include <am.h>
|
||||
#include <riscv/riscv.h>
|
||||
#include <klib.h>
|
||||
#include <riscv/riscv.h>
|
||||
#include <stdint.h>
|
||||
|
||||
static Context* (*user_handler)(Event, Context*) = NULL;
|
||||
static Context *(*user_handler)(Event, Context *) = NULL;
|
||||
|
||||
Context* __am_irq_handle(Context *c) {
|
||||
Context *__am_irq_handle(Context *c) {
|
||||
if (user_handler) {
|
||||
Event ev = {0};
|
||||
switch (c->mcause) {
|
||||
default: ev.event = EVENT_ERROR; break;
|
||||
case CauseEnvironmentCallFromMMode:
|
||||
ev.event = EVENT_YIELD;
|
||||
break;
|
||||
default:
|
||||
ev.event = EVENT_ERROR;
|
||||
break;
|
||||
}
|
||||
|
||||
c = user_handler(ev, c);
|
||||
|
@ -20,7 +27,7 @@ Context* __am_irq_handle(Context *c) {
|
|||
|
||||
extern void __am_asm_trap(void);
|
||||
|
||||
bool cte_init(Context*(*handler)(Event, Context*)) {
|
||||
bool cte_init(Context *(*handler)(Event, Context *)) {
|
||||
// initialize exception entry
|
||||
asm volatile("csrw mtvec, %0" : : "r"(__am_asm_trap));
|
||||
|
||||
|
@ -31,7 +38,10 @@ bool cte_init(Context*(*handler)(Event, Context*)) {
|
|||
}
|
||||
|
||||
Context *kcontext(Area kstack, void (*entry)(void *), void *arg) {
|
||||
return NULL;
|
||||
Context *c = kstack.end - sizeof(Context);
|
||||
c->mepc = (uintptr_t)entry;
|
||||
c->gpr[10] = (uintptr_t)arg;
|
||||
return c;
|
||||
}
|
||||
|
||||
void yield() {
|
||||
|
@ -42,9 +52,6 @@ void yield() {
|
|||
#endif
|
||||
}
|
||||
|
||||
bool ienabled() {
|
||||
return false;
|
||||
}
|
||||
bool ienabled() { return false; }
|
||||
|
||||
void iset(bool enable) {
|
||||
}
|
||||
void iset(bool enable) {}
|
||||
|
|
|
@ -60,6 +60,8 @@ __am_asm_trap:
|
|||
mv a0, sp
|
||||
jal __am_irq_handle
|
||||
|
||||
mv sp, a0
|
||||
|
||||
LOAD t1, OFFSET_STATUS(sp)
|
||||
LOAD t2, OFFSET_EPC(sp)
|
||||
csrw mstatus, t1
|
||||
|
|
46
abstract-machine/am/src/riscv/npc/CMakeLists.txt
Normal file
46
abstract-machine/am/src/riscv/npc/CMakeLists.txt
Normal file
|
@ -0,0 +1,46 @@
|
|||
include(riscv-settings)
|
||||
|
||||
add_subdirectory(libgcc)
|
||||
|
||||
add_library(
|
||||
am-riscv-npc
|
||||
cte.c
|
||||
input.c
|
||||
ioe.c
|
||||
mpe.c
|
||||
start.S
|
||||
timer.c
|
||||
trap.S
|
||||
trm.c
|
||||
vme.c)
|
||||
|
||||
target_link_libraries(
|
||||
am-riscv-npc
|
||||
PRIVATE npcgcc
|
||||
PUBLIC am_interface klib_interface)
|
||||
|
||||
target_link_options(
|
||||
am-riscv-npc INTERFACE
|
||||
$<BUILD_INTERFACE:-T${CMAKE_SOURCE_DIR}/scripts/linker.ld>
|
||||
$<INSTALL_INTERFACE:-T${CMAKE_INSTALL_FULL_DATADIR}/linker.ld>)
|
||||
|
||||
target_link_options(
|
||||
am-riscv-npc
|
||||
INTERFACE
|
||||
LINKER:--defsym=_pmem_start=0x80000000
|
||||
LINKER:--defsym=_entry_offset=0x0
|
||||
LINKER:--gc-sections
|
||||
LINKER:-e
|
||||
_start
|
||||
-nostartfiles)
|
||||
|
||||
target_link_options(
|
||||
am-riscv-npc INTERFACE
|
||||
$<BUILD_INTERFACE:-T${CMAKE_SOURCE_DIR}/scripts/linker.ld>
|
||||
$<INSTALL_INTERFACE:-T${CMAKE_INSTALL_FULL_DATADIR}/linker.ld>)
|
||||
|
||||
target_compile_definitions(am-riscv-npc PUBLIC ${AM_COMMON_COMPILE_DEF}
|
||||
ARCH_H=<arch/riscv.h>)
|
||||
|
||||
install(FILES ${CMAKE_SOURCE_DIR}/scripts/linker.ld
|
||||
DESTINATION ${CMAKE_INSTALL_DATADIR})
|
|
@ -7,26 +7,32 @@ void __am_timer_rtc(AM_TIMER_RTC_T *);
|
|||
void __am_timer_uptime(AM_TIMER_UPTIME_T *);
|
||||
void __am_input_keybrd(AM_INPUT_KEYBRD_T *);
|
||||
|
||||
static void __am_timer_config(AM_TIMER_CONFIG_T *cfg) { cfg->present = true; cfg->has_rtc = true; }
|
||||
static void __am_input_config(AM_INPUT_CONFIG_T *cfg) { cfg->present = true; }
|
||||
static void __am_timer_config(AM_TIMER_CONFIG_T *cfg) {
|
||||
cfg->present = true;
|
||||
cfg->has_rtc = true;
|
||||
}
|
||||
static void __am_input_config(AM_INPUT_CONFIG_T *cfg) { cfg->present = true; }
|
||||
static void __am_uart_config(AM_UART_CONFIG_T *cfg) { cfg->present = false; }
|
||||
|
||||
typedef void (*handler_t)(void *buf);
|
||||
static void *lut[128] = {
|
||||
[AM_TIMER_CONFIG] = __am_timer_config,
|
||||
[AM_TIMER_RTC ] = __am_timer_rtc,
|
||||
[AM_TIMER_UPTIME] = __am_timer_uptime,
|
||||
[AM_INPUT_CONFIG] = __am_input_config,
|
||||
[AM_INPUT_KEYBRD] = __am_input_keybrd,
|
||||
[AM_UART_CONFIG] = __am_uart_config,
|
||||
[AM_TIMER_CONFIG] = __am_timer_config,
|
||||
[AM_TIMER_RTC] = __am_timer_rtc,
|
||||
[AM_TIMER_UPTIME] = __am_timer_uptime,
|
||||
[AM_INPUT_CONFIG] = __am_input_config,
|
||||
[AM_INPUT_KEYBRD] = __am_input_keybrd,
|
||||
};
|
||||
|
||||
static void fail(void *buf) { panic("access nonexist register"); }
|
||||
|
||||
bool ioe_init() {
|
||||
for (int i = 0; i < LENGTH(lut); i++)
|
||||
if (!lut[i]) lut[i] = fail;
|
||||
if (!lut[i])
|
||||
lut[i] = fail;
|
||||
__am_timer_init();
|
||||
return true;
|
||||
}
|
||||
|
||||
void ioe_read (int reg, void *buf) { ((handler_t)lut[reg])(buf); }
|
||||
void ioe_read(int reg, void *buf) { ((handler_t)lut[reg])(buf); }
|
||||
void ioe_write(int reg, void *buf) { ((handler_t)lut[reg])(buf); }
|
||||
|
|
9
abstract-machine/am/src/riscv/npc/libgcc/CMakeLists.txt
Normal file
9
abstract-machine/am/src/riscv/npc/libgcc/CMakeLists.txt
Normal file
|
@ -0,0 +1,9 @@
|
|||
add_library(npcgcc ashldi3.c div.S muldi3.S multi3.c unused.c)
|
||||
|
||||
target_link_libraries(npcgcc PRIVATE klib_interface am_interface)
|
||||
target_link_options(npcgcc INTERFACE -nolibc -nostdlib)
|
||||
|
||||
install(
|
||||
TARGETS npcgcc
|
||||
EXPORT amTargets-riscv-npc
|
||||
LIBRARY DESTINATION lib)
|
6
abstract-machine/am/src/riscv/npc/npc.h
Normal file
6
abstract-machine/am/src/riscv/npc/npc.h
Normal file
|
@ -0,0 +1,6 @@
|
|||
#ifndef _AM_NPC_NPC_H_
|
||||
#define _AM_NPC_NPC_H_
|
||||
#define SERIAL_PORT 0x10000000
|
||||
#define RTC_ADDR 0x10001000
|
||||
|
||||
#endif
|
|
@ -1,17 +1,18 @@
|
|||
#include "npc.h"
|
||||
#include <am.h>
|
||||
#include <riscv/riscv.h>
|
||||
|
||||
void __am_timer_init() {
|
||||
}
|
||||
void __am_timer_init() {}
|
||||
|
||||
void __am_timer_uptime(AM_TIMER_UPTIME_T *uptime) {
|
||||
uptime->us = 0;
|
||||
uptime->us = ((uint64_t)inl(RTC_ADDR + 4) << 32) + inl(RTC_ADDR);
|
||||
}
|
||||
|
||||
void __am_timer_rtc(AM_TIMER_RTC_T *rtc) {
|
||||
rtc->second = 0;
|
||||
rtc->minute = 0;
|
||||
rtc->hour = 0;
|
||||
rtc->day = 0;
|
||||
rtc->month = 0;
|
||||
rtc->year = 1900;
|
||||
rtc->hour = 0;
|
||||
rtc->day = 0;
|
||||
rtc->month = 0;
|
||||
rtc->year = 1900;
|
||||
}
|
||||
|
|
|
@ -1,24 +1,27 @@
|
|||
#include "npc.h"
|
||||
#include <am.h>
|
||||
#include <klib-macros.h>
|
||||
#include <riscv/riscv.h>
|
||||
|
||||
extern char _heap_start;
|
||||
int main(const char *args);
|
||||
|
||||
extern char _pmem_start;
|
||||
#define PMEM_SIZE (128 * 1024 * 1024)
|
||||
#define PMEM_END ((uintptr_t)&_pmem_start + PMEM_SIZE)
|
||||
#define PMEM_END ((uintptr_t)&_pmem_start + PMEM_SIZE)
|
||||
|
||||
Area heap = RANGE(&_heap_start, PMEM_END);
|
||||
#ifndef MAINARGS
|
||||
#define MAINARGS ""
|
||||
#define MAINARGS "3"
|
||||
#endif
|
||||
static const char mainargs[] = MAINARGS;
|
||||
|
||||
void putch(char ch) {
|
||||
}
|
||||
void putch(char ch) { outb(SERIAL_PORT, ch); }
|
||||
|
||||
void halt(int code) {
|
||||
while (1);
|
||||
asm volatile("mv a0, %0; ebreak" : : "r"(code));
|
||||
while (1)
|
||||
;
|
||||
}
|
||||
|
||||
void _trm_init() {
|
||||
|
|
10
abstract-machine/cmake/am-config.cmake.in
Normal file
10
abstract-machine/cmake/am-config.cmake.in
Normal file
|
@ -0,0 +1,10 @@
|
|||
@PACKAGE_INIT@
|
||||
|
||||
include(CMakeFindDependencyMacro)
|
||||
if(${ARCH} MATCHES "native")
|
||||
find_dependency(SDL2 REQUIRED)
|
||||
endif()
|
||||
|
||||
# Include the targets file
|
||||
include("${CMAKE_CURRENT_LIST_DIR}/../interfaceTargets.cmake")
|
||||
include("${CMAKE_CURRENT_LIST_DIR}/amTargets.cmake")
|
6
abstract-machine/cmake/klib-config.cmake.in
Normal file
6
abstract-machine/cmake/klib-config.cmake.in
Normal file
|
@ -0,0 +1,6 @@
|
|||
@PACKAGE_INIT@
|
||||
|
||||
include(CMakeFindDependencyMacro)
|
||||
|
||||
# Include the targets file
|
||||
include("${CMAKE_CURRENT_LIST_DIR}/klibTargets.cmake")
|
12
abstract-machine/cmake/nemu-settings.cmake
Normal file
12
abstract-machine/cmake/nemu-settings.cmake
Normal file
|
@ -0,0 +1,12 @@
|
|||
set(NEMU_COMPILE_OPTIONS -fdata-sections -ffunction-sections)
|
||||
set(NEMU_LINK_OPTIONS
|
||||
-nostartfiles
|
||||
-nolibc
|
||||
--defsym=_pmem_start=0x80000000
|
||||
--defsym=_entry_offset=0x0
|
||||
--gc-sections
|
||||
-e
|
||||
_start)
|
||||
set(NEMU_INCLUDE_DIRECTORIES ${CMAKE_SOURCE_DIR}/am/src/platform/nemu/include)
|
||||
file(GLOB_RECURSE NEMU_SOURCES ${CMAKE_SOURCE_DIR}/am/src/platform/nemu/*.[cS])
|
||||
set(INCLUDE_LINKER_SCRIPT ON)
|
2
abstract-machine/cmake/riscv-settings.cmake
Normal file
2
abstract-machine/cmake/riscv-settings.cmake
Normal file
|
@ -0,0 +1,2 @@
|
|||
set(RISCV_COMPILE_OPTIONS)
|
||||
set(RISCV_LINK_OPTIONS)
|
34
abstract-machine/default.nix
Normal file
34
abstract-machine/default.nix
Normal file
|
@ -0,0 +1,34 @@
|
|||
{ stdenv
|
||||
, lib
|
||||
, cmake
|
||||
, SDL2
|
||||
, glibc
|
||||
, isa ? "native"
|
||||
, platform ? [ ]
|
||||
}:
|
||||
stdenv.mkDerivation {
|
||||
pname = "abstract-machine";
|
||||
version = "2024.06.01";
|
||||
|
||||
src = ./.;
|
||||
|
||||
cmakeFlags = [
|
||||
(lib.cmakeFeature "ISA" isa)
|
||||
] ++ map (p: (lib.cmakeBool "__PLATFORM_${lib.strings.toUpper p}__" true)) platform;
|
||||
|
||||
cmakeBuildType = "Debug";
|
||||
dontStrip = true;
|
||||
|
||||
nativeBuildInputs = [
|
||||
cmake
|
||||
];
|
||||
|
||||
buildInputs = [
|
||||
|
||||
] ++ (if isa == "native" then [ SDL2 ] else [ ]);
|
||||
propagatedBuildInputs = [
|
||||
|
||||
] ++ (if isa == "native" then [ SDL2 ] else [ ]);
|
||||
|
||||
doCheck = true;
|
||||
}
|
4
abstract-machine/klib/CMakeLists.txt
Normal file
4
abstract-machine/klib/CMakeLists.txt
Normal file
|
@ -0,0 +1,4 @@
|
|||
install(DIRECTORY include/
|
||||
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/abstract-machine)
|
||||
|
||||
add_subdirectory(src)
|
|
@ -35,6 +35,7 @@ int atoi (const char *nptr);
|
|||
int printf (const char *format, ...);
|
||||
int sprintf (char *str, const char *format, ...);
|
||||
int snprintf (char *str, size_t size, const char *format, ...);
|
||||
int vprintf (const char *format, va_list ap);
|
||||
int vsprintf (char *str, const char *format, va_list ap);
|
||||
int vsnprintf (char *str, size_t size, const char *format, va_list ap);
|
||||
|
||||
|
|
29
abstract-machine/klib/src/CMakeLists.txt
Normal file
29
abstract-machine/klib/src/CMakeLists.txt
Normal file
|
@ -0,0 +1,29 @@
|
|||
# find_package(FLEX) find_package(BISON)
|
||||
|
||||
# FLEX_TARGET(fmt_scanner fmt_scanner.l fmt_scanner.c)
|
||||
|
||||
set(SOURCES cpp.c int64.c stdio.c stdlib.c string.c
|
||||
# ${FLEX_fmt_scanner_OUTPUTS}
|
||||
)
|
||||
|
||||
add_library(klib ${SOURCES})
|
||||
target_link_libraries(klib PUBLIC am_interface klib_interface)
|
||||
target_compile_options(klib PUBLIC -fno-builtin)
|
||||
|
||||
install(
|
||||
TARGETS klib
|
||||
EXPORT klibTargets
|
||||
LIBRARY DESTINATION lib)
|
||||
|
||||
install(
|
||||
EXPORT klibTargets
|
||||
FILE klibTargets.cmake
|
||||
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/klib)
|
||||
|
||||
configure_package_config_file(
|
||||
${CMAKE_SOURCE_DIR}/cmake/klib-config.cmake.in
|
||||
${CMAKE_CURRENT_BINARY_DIR}/klib-config.cmake
|
||||
INSTALL_DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/klib)
|
||||
|
||||
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/klib-config.cmake
|
||||
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/klib)
|
|
@ -1,20 +1,194 @@
|
|||
#include <am.h>
|
||||
#include <klib.h>
|
||||
#include <klib-macros.h>
|
||||
#include <klib.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
#if !defined(__ISA_NATIVE__) || defined(__NATIVE_USE_KLIB__)
|
||||
|
||||
int printf(const char *fmt, ...) {
|
||||
panic("Not implemented");
|
||||
void print_int(int num, int width, char pad) {
|
||||
int reverse = 0;
|
||||
int count = 0;
|
||||
|
||||
if (num == 0) {
|
||||
reverse = 0;
|
||||
count = 1;
|
||||
} else {
|
||||
if (num < 0) {
|
||||
putch('-');
|
||||
num = -num;
|
||||
}
|
||||
while (num != 0) {
|
||||
reverse = reverse * 10 + (num % 10);
|
||||
num /= 10;
|
||||
count++;
|
||||
}
|
||||
}
|
||||
|
||||
while (width > count) {
|
||||
putch(pad);
|
||||
width--;
|
||||
}
|
||||
|
||||
if (reverse == 0) {
|
||||
putch('0');
|
||||
} else {
|
||||
while (reverse != 0) {
|
||||
putch('0' + (reverse % 10));
|
||||
reverse /= 10;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int vsprintf(char *out, const char *fmt, va_list ap) {
|
||||
panic("Not implemented");
|
||||
int vprintf(const char *format, va_list args) {
|
||||
const char *p = format;
|
||||
|
||||
while (*p) {
|
||||
if (*p == '%') {
|
||||
p++; // Skip the '%'
|
||||
char pad = ' ';
|
||||
int width = 0;
|
||||
|
||||
if (*p == '0') {
|
||||
pad = '0';
|
||||
p++;
|
||||
}
|
||||
|
||||
while (*p >= '0' && *p <= '9') {
|
||||
width = width * 10 + (*p - '0');
|
||||
p++;
|
||||
}
|
||||
|
||||
switch (*p) {
|
||||
case 'd': { // Integer
|
||||
int ival = va_arg(args, int);
|
||||
print_int(ival, width, pad);
|
||||
break;
|
||||
}
|
||||
case 'c': { // Character
|
||||
char c = (char)va_arg(args, int);
|
||||
putch(c);
|
||||
break;
|
||||
}
|
||||
case 's': { // String
|
||||
char *s = va_arg(args, char *);
|
||||
putstr(s);
|
||||
break;
|
||||
}
|
||||
case '%': {
|
||||
putch('%');
|
||||
break;
|
||||
}
|
||||
default:
|
||||
panic("Wrong formatter provided to printf");
|
||||
}
|
||||
} else {
|
||||
putch(*p);
|
||||
}
|
||||
p++;
|
||||
}
|
||||
}
|
||||
|
||||
int printf(const char *fmt, ...) {
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
vprintf(fmt, args);
|
||||
va_end(args);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void append_to_buffer(char **buf, int *pos, char c) { (*buf)[(*pos)++] = c; }
|
||||
|
||||
void print_int_to_buf(char **buf, int *pos, int num, int width, char pad) {
|
||||
int reverse = 0, count = 0, neg = 0;
|
||||
|
||||
if (num == 0) {
|
||||
reverse = 0;
|
||||
count = 1;
|
||||
} else {
|
||||
if (num < 0) {
|
||||
append_to_buffer(buf, pos, '-');
|
||||
num = -num;
|
||||
neg = 1;
|
||||
}
|
||||
while (num != 0) {
|
||||
reverse = reverse * 10 + (num % 10);
|
||||
num /= 10;
|
||||
count++;
|
||||
}
|
||||
}
|
||||
|
||||
width -= neg;
|
||||
while (width > count) {
|
||||
append_to_buffer(buf, pos, pad);
|
||||
width--;
|
||||
}
|
||||
|
||||
for (int i = 0; i < count; i++) {
|
||||
append_to_buffer(buf, pos, '0' + (reverse % 10));
|
||||
reverse /= 10;
|
||||
}
|
||||
}
|
||||
|
||||
int vsprintf(char *buf, const char *format, va_list args) {
|
||||
const char *p = format;
|
||||
int pos = 0; // Position in buf
|
||||
|
||||
while (*p) {
|
||||
if (*p == '%') {
|
||||
p++; // Skip the '%'
|
||||
char pad = ' ';
|
||||
int width = 0;
|
||||
|
||||
if (*p == '0') {
|
||||
pad = '0';
|
||||
p++;
|
||||
}
|
||||
|
||||
while (*p >= '0' && *p <= '9') {
|
||||
width = width * 10 + (*p - '0');
|
||||
p++;
|
||||
}
|
||||
|
||||
switch (*p) {
|
||||
case 'd': { // Integer
|
||||
int ival = va_arg(args, int);
|
||||
print_int_to_buf(&buf, &pos, ival, width, pad);
|
||||
break;
|
||||
}
|
||||
case 'c': { // Character
|
||||
char c = (char)va_arg(args, int);
|
||||
append_to_buffer(&buf, &pos, c);
|
||||
break;
|
||||
}
|
||||
case 's': { // String
|
||||
char *s = va_arg(args, char *);
|
||||
while (*s) {
|
||||
append_to_buffer(&buf, &pos, *s++);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case '%': {
|
||||
append_to_buffer(&buf, &pos, '%');
|
||||
break;
|
||||
}
|
||||
default:
|
||||
panic("Unsupported format specifier");
|
||||
}
|
||||
} else {
|
||||
append_to_buffer(&buf, &pos, *p);
|
||||
}
|
||||
p++;
|
||||
}
|
||||
buf[pos] = '\0'; // Null-terminate the string
|
||||
return pos;
|
||||
}
|
||||
|
||||
int sprintf(char *out, const char *fmt, ...) {
|
||||
panic("Not implemented");
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
vsprintf(out, fmt, args);
|
||||
va_end(args);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int snprintf(char *out, size_t n, const char *fmt, ...) {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
#include <am.h>
|
||||
#include <klib.h>
|
||||
#include <klib-macros.h>
|
||||
#include <klib.h>
|
||||
|
||||
#if !defined(__ISA_NATIVE__) || defined(__NATIVE_USE_KLIB__)
|
||||
static unsigned long int next = 1;
|
||||
|
@ -8,23 +8,21 @@ static unsigned long int next = 1;
|
|||
int rand(void) {
|
||||
// RAND_MAX assumed to be 32767
|
||||
next = next * 1103515245 + 12345;
|
||||
return (unsigned int)(next/65536) % 32768;
|
||||
return (unsigned int)(next / 65536) % 32768;
|
||||
}
|
||||
|
||||
void srand(unsigned int seed) {
|
||||
next = seed;
|
||||
}
|
||||
void srand(unsigned int seed) { next = seed; }
|
||||
|
||||
int abs(int x) {
|
||||
return (x < 0 ? -x : x);
|
||||
}
|
||||
int abs(int x) { return (x < 0 ? -x : x); }
|
||||
|
||||
int atoi(const char* nptr) {
|
||||
int atoi(const char *nptr) {
|
||||
int x = 0;
|
||||
while (*nptr == ' ') { nptr ++; }
|
||||
while (*nptr == ' ') {
|
||||
nptr++;
|
||||
}
|
||||
while (*nptr >= '0' && *nptr <= '9') {
|
||||
x = x * 10 + *nptr - '0';
|
||||
nptr ++;
|
||||
nptr++;
|
||||
}
|
||||
return x;
|
||||
}
|
||||
|
@ -33,13 +31,19 @@ void *malloc(size_t size) {
|
|||
// On native, malloc() will be called during initializaion of C runtime.
|
||||
// Therefore do not call panic() here, else it will yield a dead recursion:
|
||||
// panic() -> putchar() -> (glibc) -> malloc() -> panic()
|
||||
#if !(defined(__ISA_NATIVE__) && defined(__NATIVE_USE_KLIB__))
|
||||
panic("Not implemented");
|
||||
#endif
|
||||
return NULL;
|
||||
static void *addr = NULL;
|
||||
void *ret = NULL;
|
||||
if (addr == 0) {
|
||||
addr = heap.start;
|
||||
ret = addr;
|
||||
} else {
|
||||
panic_on(addr + size > heap.end, "Memory space not enough");
|
||||
ret = addr;
|
||||
addr += size;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
void free(void *ptr) {
|
||||
}
|
||||
void free(void *ptr) {}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,47 +1,124 @@
|
|||
#include <klib.h>
|
||||
#include <klib-macros.h>
|
||||
#include <klib.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#if !defined(__ISA_NATIVE__) || defined(__NATIVE_USE_KLIB__)
|
||||
|
||||
size_t strlen(const char *s) {
|
||||
panic("Not implemented");
|
||||
const char *p = s;
|
||||
size_t len = 0;
|
||||
while (*(p++) != '\0')
|
||||
len++;
|
||||
return len;
|
||||
}
|
||||
|
||||
char *strcpy(char *dst, const char *src) {
|
||||
panic("Not implemented");
|
||||
char *p_dst = dst;
|
||||
const char *p_src = src;
|
||||
for (; *p_src != '\0'; p_src++, p_dst++) {
|
||||
*p_dst = *p_src;
|
||||
}
|
||||
*p_dst = '\0';
|
||||
return dst;
|
||||
}
|
||||
|
||||
char *strncpy(char *dst, const char *src, size_t n) {
|
||||
panic("Not implemented");
|
||||
int i = 0;
|
||||
for (; i < n && src[i] != '\0'; i++) {
|
||||
dst[i] = src[i];
|
||||
}
|
||||
for (; i < n; i++) {
|
||||
dst[i] = '\0';
|
||||
}
|
||||
return dst;
|
||||
}
|
||||
|
||||
char *strcat(char *dst, const char *src) {
|
||||
panic("Not implemented");
|
||||
char *p_dst = dst;
|
||||
const char *p_src = src;
|
||||
while (*p_dst != '\0')
|
||||
p_dst++;
|
||||
for (; *p_src != '\0'; p_src++, p_dst++) {
|
||||
*p_dst = *p_src;
|
||||
}
|
||||
*p_dst = '\0';
|
||||
return dst;
|
||||
}
|
||||
|
||||
int strcmp(const char *s1, const char *s2) {
|
||||
panic("Not implemented");
|
||||
const char *p_s1 = s1, *p_s2 = s2;
|
||||
for (; *p_s1 == *p_s2; p_s1++, p_s2++) {
|
||||
if (*p_s1 == '\0' || *p_s2 == '\0') {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return *p_s1 - *p_s2;
|
||||
}
|
||||
|
||||
int strncmp(const char *s1, const char *s2, size_t n) {
|
||||
panic("Not implemented");
|
||||
const char *p_s1 = s1, *p_s2 = s2;
|
||||
int i = 0;
|
||||
for (i = 0; i < n - 1; i++) {
|
||||
if (s1[i] == '\0' || s2[i] == '\0')
|
||||
break;
|
||||
}
|
||||
return s1[i] - s2[i];
|
||||
}
|
||||
|
||||
void *memset(void *s, int c, size_t n) {
|
||||
panic("Not implemented");
|
||||
uint8_t *p = s;
|
||||
for (int i = 0; i < n; i++) {
|
||||
p[i] = c;
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
void *memmove(void *dst, const void *src, size_t n) {
|
||||
panic("Not implemented");
|
||||
if (src + n > dst && src < dst) {
|
||||
size_t len = dst - src;
|
||||
void *p_dst = (void *)src + n;
|
||||
const void *p_src = src + n - len;
|
||||
while (p_dst >= dst) {
|
||||
memcpy(p_dst, p_src, len);
|
||||
p_src -= len;
|
||||
p_dst -= len;
|
||||
}
|
||||
if (n % len)
|
||||
memcpy(dst, src, n % len);
|
||||
} else if (dst < src && dst + n > src) {
|
||||
size_t len = src - dst;
|
||||
void *p_dst = dst;
|
||||
const void *p_src = src;
|
||||
while (p_src < src + n) {
|
||||
memcpy(p_dst, p_src, len);
|
||||
p_src += len;
|
||||
p_dst += len;
|
||||
}
|
||||
if (n % len)
|
||||
memcpy(p_dst, p_src, n % len);
|
||||
} else {
|
||||
memcpy(dst, src, n);
|
||||
}
|
||||
|
||||
return dst;
|
||||
}
|
||||
|
||||
void *memcpy(void *out, const void *in, size_t n) {
|
||||
panic("Not implemented");
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
*(uint8_t *)(out + i) = *(uint8_t *)(in + i);
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
int memcmp(const void *s1, const void *s2, size_t n) {
|
||||
panic("Not implemented");
|
||||
const uint8_t *p1 = s1, *p2 = s2;
|
||||
for (int i = 0; i < n; i++) {
|
||||
if (*p1 != *p2)
|
||||
return p1 - p2;
|
||||
p1++;
|
||||
p2++;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
11
abstract-machine/klib/tests/CMakeLists.txt
Normal file
11
abstract-machine/klib/tests/CMakeLists.txt
Normal file
|
@ -0,0 +1,11 @@
|
|||
set(TEST_SOURCES stdio string)
|
||||
|
||||
foreach(TEST IN LISTS TEST_SOURCES)
|
||||
# TODO: Run tests in other configurations
|
||||
if(__PLATFORM_NATIVE__)
|
||||
add_executable(${TEST} ${TEST}.c)
|
||||
target_link_libraries(${TEST} PRIVATE am_interface klib_interface klib)
|
||||
target_link_libraries(${TEST} PRIVATE am-native)
|
||||
add_test(NAME ${TEST} COMMAND ${TEST})
|
||||
endif()
|
||||
endforeach()
|
5
abstract-machine/klib/tests/stdio.c
Normal file
5
abstract-machine/klib/tests/stdio.c
Normal file
|
@ -0,0 +1,5 @@
|
|||
#include <klib.h>
|
||||
|
||||
int main(void) {
|
||||
return 0;
|
||||
}
|
75
abstract-machine/klib/tests/string.c
Normal file
75
abstract-machine/klib/tests/string.c
Normal file
|
@ -0,0 +1,75 @@
|
|||
#include <klib.h>
|
||||
#include <klib-macros.h>
|
||||
#include <stdint.h>
|
||||
|
||||
void test_strcpy() {
|
||||
char b[32];
|
||||
char *s;
|
||||
b[16]='a'; b[17]='b'; b[18]='c'; b[19]=0;
|
||||
panic_on((s = strcpy(b, b+16)) != b, "strcpy wrong return value");
|
||||
panic_on(strcmp(s, "abc") != 0, "strcpy gave incorrect string");
|
||||
panic_on((s = strcpy(b+1, b+16)) != b+1, "strcpy wrong return value");
|
||||
panic_on(strcmp(s, "abc") != 0, "strcpy gave incorrect string");
|
||||
|
||||
panic_on((s = strcpy(b+1, b+17)) != b+1, "strcpy wrong return value");
|
||||
panic_on(strcmp(s, "bc") != 0, "strcpy gave incorrect string");
|
||||
}
|
||||
|
||||
void test_strncpy() {
|
||||
char b[32];
|
||||
char *s;
|
||||
int i;
|
||||
b[3] = 'x'; b[4] = 0;
|
||||
panic_on((s = strncpy(b, "abc", 3)) != b, "strncpy wrong return value");
|
||||
panic_on(b[2] != 'c', "strncpy fails to copy last byte");
|
||||
panic_on(b[3] != 'x', "strncpy overruns buffer to null-terminate");
|
||||
}
|
||||
|
||||
void test_strncmp() {
|
||||
panic_on(strncmp("abcd", "abce", 3) != 0, "strncmp compares past n");
|
||||
panic_on(strncmp("abc", "abd", 3) == 0, "strncmp fails to compare n-1st byte");
|
||||
}
|
||||
|
||||
void test_memset() {
|
||||
uint8_t arr[128];
|
||||
arr[120] = 0xd;
|
||||
panic_on(memset(arr, 0xf, 120) != arr, "memset wrong return value");
|
||||
panic_on(arr[7] != 0xf, "memset fails to set value in range");
|
||||
panic_on(arr[120] != 0xd, "memset set value past n");
|
||||
}
|
||||
|
||||
void test_memcpy() {
|
||||
const uint8_t src[] = { 0x0, 0x0, 0x1, 0x2, 0x3, 0x4, 0x0, 0x0 };
|
||||
uint8_t dst[8] = {0};
|
||||
memcpy(dst, src, 8);
|
||||
panic_on(memcmp(dst, src, 8) != 0, "memcpy fails to copy memory");
|
||||
}
|
||||
|
||||
void test_memmove() {
|
||||
const uint8_t ref[] = { 0x0, 0x0, 0x1, 0x2, 0x3, 0x4, 0x0, 0x0 };
|
||||
uint8_t dst[8] = {0};
|
||||
const uint8_t ans1[] = { 0x1, 0x2, 0x3, 0x4, 0x3, 0x4, 0x0, 0x0 };
|
||||
const uint8_t ans2[] = { 0x1, 0x2, 0x2, 0x3, 0x4, 0x3, 0x0, 0x0 };
|
||||
const uint8_t ans3[] = { 0x1, 0x2, 0x2, 0x1, 0x2, 0x2, 0x3, 0x4 };
|
||||
memmove(dst, ref, 8);
|
||||
panic_on(memcmp(dst, ref, 8) != 0, "memmove fails to copy non-overlapping memory");
|
||||
|
||||
memmove(dst, dst + 2, 4);
|
||||
panic_on(memcmp(dst, ans1, 8) != 0, "memmove fails to copy overlapping memory (dst < src)");
|
||||
|
||||
memmove(dst + 2, dst + 1, 4);
|
||||
panic_on(memcmp(dst, ans2, 8) != 0, "memmove fails to copy overlapping memory (src < dst)");
|
||||
|
||||
memmove(dst + 3, dst, 5);
|
||||
panic_on(memcmp(dst, ans3, 8) != 0, "memmove fails to copy overlapping memory (src < dst)");
|
||||
}
|
||||
|
||||
int main(void) {
|
||||
test_strcpy();
|
||||
test_strncpy();
|
||||
test_strncmp();
|
||||
test_memset();
|
||||
test_memcpy();
|
||||
test_memmove();
|
||||
return 0;
|
||||
}
|
808
flake.lock
Normal file
808
flake.lock
Normal file
|
@ -0,0 +1,808 @@
|
|||
{
|
||||
"nodes": {
|
||||
"am-kernels": {
|
||||
"inputs": {
|
||||
"flake-utils": "flake-utils",
|
||||
"nixpkgs": "nixpkgs",
|
||||
"pre-commit-hooks": "pre-commit-hooks",
|
||||
"ysyx-workbench": "ysyx-workbench"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1723617032,
|
||||
"narHash": "sha256-oL5Vx933Jhn+T9jn67wFbh8vy7w8OJNCn4DOOlX/r0U=",
|
||||
"ref": "dev",
|
||||
"rev": "3ee527c3de481e38767fffbd9e16bf48359fc638",
|
||||
"revCount": 78,
|
||||
"type": "git",
|
||||
"url": "https://git.xinyang.life/xin/am-kernels.git"
|
||||
},
|
||||
"original": {
|
||||
"ref": "dev",
|
||||
"type": "git",
|
||||
"url": "https://git.xinyang.life/xin/am-kernels.git"
|
||||
}
|
||||
},
|
||||
"diffu": {
|
||||
"inputs": {
|
||||
"flake-utils": "flake-utils_5",
|
||||
"nixpkgs": "nixpkgs_2",
|
||||
"nur-xin": "nur-xin_2",
|
||||
"pre-commit-hooks": "pre-commit-hooks_3"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1723627842,
|
||||
"narHash": "sha256-+Ovf1e5ESap4sGMsH945SkZLhyYUxGE7shKVl3Ue1CQ=",
|
||||
"ref": "refs/heads/master",
|
||||
"rev": "7b3881a9712bcb7bfea90614a44888ae5df6e849",
|
||||
"revCount": 17,
|
||||
"type": "git",
|
||||
"url": "https://git.xinyang.life/xin/diffu.git"
|
||||
},
|
||||
"original": {
|
||||
"type": "git",
|
||||
"url": "https://git.xinyang.life/xin/diffu.git"
|
||||
}
|
||||
},
|
||||
"flake-compat": {
|
||||
"flake": false,
|
||||
"locked": {
|
||||
"lastModified": 1696426674,
|
||||
"narHash": "sha256-kvjfFW7WAETZlt09AgDn1MrtKzP7t90Vf7vypd3OL1U=",
|
||||
"owner": "edolstra",
|
||||
"repo": "flake-compat",
|
||||
"rev": "0f9255e01c2351cc7d116c072cb317785dd33b33",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "edolstra",
|
||||
"repo": "flake-compat",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"flake-compat_2": {
|
||||
"flake": false,
|
||||
"locked": {
|
||||
"lastModified": 1696426674,
|
||||
"narHash": "sha256-kvjfFW7WAETZlt09AgDn1MrtKzP7t90Vf7vypd3OL1U=",
|
||||
"owner": "edolstra",
|
||||
"repo": "flake-compat",
|
||||
"rev": "0f9255e01c2351cc7d116c072cb317785dd33b33",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "edolstra",
|
||||
"repo": "flake-compat",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"flake-compat_3": {
|
||||
"flake": false,
|
||||
"locked": {
|
||||
"lastModified": 1696426674,
|
||||
"narHash": "sha256-kvjfFW7WAETZlt09AgDn1MrtKzP7t90Vf7vypd3OL1U=",
|
||||
"owner": "edolstra",
|
||||
"repo": "flake-compat",
|
||||
"rev": "0f9255e01c2351cc7d116c072cb317785dd33b33",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "edolstra",
|
||||
"repo": "flake-compat",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"flake-compat_4": {
|
||||
"flake": false,
|
||||
"locked": {
|
||||
"lastModified": 1696426674,
|
||||
"narHash": "sha256-kvjfFW7WAETZlt09AgDn1MrtKzP7t90Vf7vypd3OL1U=",
|
||||
"owner": "edolstra",
|
||||
"repo": "flake-compat",
|
||||
"rev": "0f9255e01c2351cc7d116c072cb317785dd33b33",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "edolstra",
|
||||
"repo": "flake-compat",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"flake-utils": {
|
||||
"inputs": {
|
||||
"systems": "systems"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1709126324,
|
||||
"narHash": "sha256-q6EQdSeUZOG26WelxqkmR7kArjgWCdw5sfJVHPH/7j8=",
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"rev": "d465f4819400de7c8d874d50b982301f28a84605",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"flake-utils_2": {
|
||||
"inputs": {
|
||||
"systems": "systems_2"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1710146030,
|
||||
"narHash": "sha256-SZ5L6eA7HJ/nmkzGG7/ISclqe6oZdOZTNoesiInkXPQ=",
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"rev": "b1d9ab70662946ef0850d488da1c9019f3a9752a",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"flake-utils_3": {
|
||||
"inputs": {
|
||||
"systems": "systems_3"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1709126324,
|
||||
"narHash": "sha256-q6EQdSeUZOG26WelxqkmR7kArjgWCdw5sfJVHPH/7j8=",
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"rev": "d465f4819400de7c8d874d50b982301f28a84605",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"flake-utils_4": {
|
||||
"inputs": {
|
||||
"systems": "systems_4"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1710146030,
|
||||
"narHash": "sha256-SZ5L6eA7HJ/nmkzGG7/ISclqe6oZdOZTNoesiInkXPQ=",
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"rev": "b1d9ab70662946ef0850d488da1c9019f3a9752a",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"flake-utils_5": {
|
||||
"inputs": {
|
||||
"systems": "systems_5"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1710146030,
|
||||
"narHash": "sha256-SZ5L6eA7HJ/nmkzGG7/ISclqe6oZdOZTNoesiInkXPQ=",
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"rev": "b1d9ab70662946ef0850d488da1c9019f3a9752a",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"flake-utils_6": {
|
||||
"inputs": {
|
||||
"systems": "systems_6"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1710146030,
|
||||
"narHash": "sha256-SZ5L6eA7HJ/nmkzGG7/ISclqe6oZdOZTNoesiInkXPQ=",
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"rev": "b1d9ab70662946ef0850d488da1c9019f3a9752a",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"flake-utils_7": {
|
||||
"inputs": {
|
||||
"systems": "systems_7"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1709126324,
|
||||
"narHash": "sha256-q6EQdSeUZOG26WelxqkmR7kArjgWCdw5sfJVHPH/7j8=",
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"rev": "d465f4819400de7c8d874d50b982301f28a84605",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"flake-utils_8": {
|
||||
"inputs": {
|
||||
"systems": "systems_8"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1710146030,
|
||||
"narHash": "sha256-SZ5L6eA7HJ/nmkzGG7/ISclqe6oZdOZTNoesiInkXPQ=",
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"rev": "b1d9ab70662946ef0850d488da1c9019f3a9752a",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"gitignore": {
|
||||
"inputs": {
|
||||
"nixpkgs": [
|
||||
"am-kernels",
|
||||
"pre-commit-hooks",
|
||||
"nixpkgs"
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1709087332,
|
||||
"narHash": "sha256-HG2cCnktfHsKV0s4XW83gU3F57gaTljL9KNSuG6bnQs=",
|
||||
"owner": "hercules-ci",
|
||||
"repo": "gitignore.nix",
|
||||
"rev": "637db329424fd7e46cf4185293b9cc8c88c95394",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "hercules-ci",
|
||||
"repo": "gitignore.nix",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"gitignore_2": {
|
||||
"inputs": {
|
||||
"nixpkgs": [
|
||||
"am-kernels",
|
||||
"ysyx-workbench",
|
||||
"pre-commit-hooks",
|
||||
"nixpkgs"
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1709087332,
|
||||
"narHash": "sha256-HG2cCnktfHsKV0s4XW83gU3F57gaTljL9KNSuG6bnQs=",
|
||||
"owner": "hercules-ci",
|
||||
"repo": "gitignore.nix",
|
||||
"rev": "637db329424fd7e46cf4185293b9cc8c88c95394",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "hercules-ci",
|
||||
"repo": "gitignore.nix",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"gitignore_3": {
|
||||
"inputs": {
|
||||
"nixpkgs": [
|
||||
"diffu",
|
||||
"pre-commit-hooks",
|
||||
"nixpkgs"
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1709087332,
|
||||
"narHash": "sha256-HG2cCnktfHsKV0s4XW83gU3F57gaTljL9KNSuG6bnQs=",
|
||||
"owner": "hercules-ci",
|
||||
"repo": "gitignore.nix",
|
||||
"rev": "637db329424fd7e46cf4185293b9cc8c88c95394",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "hercules-ci",
|
||||
"repo": "gitignore.nix",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"gitignore_4": {
|
||||
"inputs": {
|
||||
"nixpkgs": [
|
||||
"pre-commit-hooks",
|
||||
"nixpkgs"
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1709087332,
|
||||
"narHash": "sha256-HG2cCnktfHsKV0s4XW83gU3F57gaTljL9KNSuG6bnQs=",
|
||||
"owner": "hercules-ci",
|
||||
"repo": "gitignore.nix",
|
||||
"rev": "637db329424fd7e46cf4185293b9cc8c88c95394",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "hercules-ci",
|
||||
"repo": "gitignore.nix",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixpkgs": {
|
||||
"locked": {
|
||||
"lastModified": 1709237383,
|
||||
"narHash": "sha256-cy6ArO4k5qTx+l5o+0mL9f5fa86tYUX3ozE1S+Txlds=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "1536926ef5621b09bba54035ae2bb6d806d72ac8",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "NixOS",
|
||||
"ref": "nixos-unstable",
|
||||
"repo": "nixpkgs",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixpkgs-circt162": {
|
||||
"locked": {
|
||||
"lastModified": 1705645507,
|
||||
"narHash": "sha256-tX3vipIAmNDBA8WNWG4oY4KyTfnm2YieTHO2BhG8ISA=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "7995cae3ad60e3d6931283d650d7f43d31aaa5c7",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "7995cae3ad60e3d6931283d650d7f43d31aaa5c7",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixpkgs-circt162_2": {
|
||||
"locked": {
|
||||
"lastModified": 1705645507,
|
||||
"narHash": "sha256-tX3vipIAmNDBA8WNWG4oY4KyTfnm2YieTHO2BhG8ISA=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "7995cae3ad60e3d6931283d650d7f43d31aaa5c7",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "7995cae3ad60e3d6931283d650d7f43d31aaa5c7",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixpkgs-stable": {
|
||||
"locked": {
|
||||
"lastModified": 1710695816,
|
||||
"narHash": "sha256-3Eh7fhEID17pv9ZxrPwCLfqXnYP006RKzSs0JptsN84=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "614b4613980a522ba49f0d194531beddbb7220d3",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "NixOS",
|
||||
"ref": "nixos-23.11",
|
||||
"repo": "nixpkgs",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixpkgs-stable_2": {
|
||||
"locked": {
|
||||
"lastModified": 1710695816,
|
||||
"narHash": "sha256-3Eh7fhEID17pv9ZxrPwCLfqXnYP006RKzSs0JptsN84=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "614b4613980a522ba49f0d194531beddbb7220d3",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "NixOS",
|
||||
"ref": "nixos-23.11",
|
||||
"repo": "nixpkgs",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixpkgs-stable_3": {
|
||||
"locked": {
|
||||
"lastModified": 1710695816,
|
||||
"narHash": "sha256-3Eh7fhEID17pv9ZxrPwCLfqXnYP006RKzSs0JptsN84=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "614b4613980a522ba49f0d194531beddbb7220d3",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "NixOS",
|
||||
"ref": "nixos-23.11",
|
||||
"repo": "nixpkgs",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixpkgs-stable_4": {
|
||||
"locked": {
|
||||
"lastModified": 1710695816,
|
||||
"narHash": "sha256-3Eh7fhEID17pv9ZxrPwCLfqXnYP006RKzSs0JptsN84=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "614b4613980a522ba49f0d194531beddbb7220d3",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "NixOS",
|
||||
"ref": "nixos-23.11",
|
||||
"repo": "nixpkgs",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixpkgs_2": {
|
||||
"locked": {
|
||||
"lastModified": 1711703276,
|
||||
"narHash": "sha256-iMUFArF0WCatKK6RzfUJknjem0H9m4KgorO/p3Dopkk=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "d8fe5e6c92d0d190646fb9f1056741a229980089",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "NixOS",
|
||||
"ref": "nixos-unstable",
|
||||
"repo": "nixpkgs",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixpkgs_3": {
|
||||
"locked": {
|
||||
"lastModified": 1709237383,
|
||||
"narHash": "sha256-cy6ArO4k5qTx+l5o+0mL9f5fa86tYUX3ozE1S+Txlds=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "1536926ef5621b09bba54035ae2bb6d806d72ac8",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "NixOS",
|
||||
"ref": "nixos-unstable",
|
||||
"repo": "nixpkgs",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nur-xin": {
|
||||
"inputs": {
|
||||
"nixpkgs": [
|
||||
"am-kernels",
|
||||
"ysyx-workbench",
|
||||
"nixpkgs"
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1721891452,
|
||||
"narHash": "sha256-2c9nDuXXARzoRXE67lte5kKBeFb1XmTNsvdiIbRUEgE=",
|
||||
"ref": "refs/heads/master",
|
||||
"rev": "de8ad578fc4fe527772cec23a7f660bde14c8570",
|
||||
"revCount": 152,
|
||||
"type": "git",
|
||||
"url": "https://git.xinyang.life/xin/nur.git"
|
||||
},
|
||||
"original": {
|
||||
"type": "git",
|
||||
"url": "https://git.xinyang.life/xin/nur.git"
|
||||
}
|
||||
},
|
||||
"nur-xin_2": {
|
||||
"inputs": {
|
||||
"nixpkgs": [
|
||||
"diffu",
|
||||
"nixpkgs"
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1721891452,
|
||||
"narHash": "sha256-2c9nDuXXARzoRXE67lte5kKBeFb1XmTNsvdiIbRUEgE=",
|
||||
"ref": "refs/heads/master",
|
||||
"rev": "de8ad578fc4fe527772cec23a7f660bde14c8570",
|
||||
"revCount": 152,
|
||||
"type": "git",
|
||||
"url": "https://git.xinyang.life/xin/nur.git"
|
||||
},
|
||||
"original": {
|
||||
"type": "git",
|
||||
"url": "https://git.xinyang.life/xin/nur.git"
|
||||
}
|
||||
},
|
||||
"nur-xin_3": {
|
||||
"inputs": {
|
||||
"nixpkgs": [
|
||||
"nixpkgs"
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1721891452,
|
||||
"narHash": "sha256-2c9nDuXXARzoRXE67lte5kKBeFb1XmTNsvdiIbRUEgE=",
|
||||
"ref": "refs/heads/master",
|
||||
"rev": "de8ad578fc4fe527772cec23a7f660bde14c8570",
|
||||
"revCount": 152,
|
||||
"type": "git",
|
||||
"url": "https://git.xinyang.life/xin/nur.git"
|
||||
},
|
||||
"original": {
|
||||
"type": "git",
|
||||
"url": "https://git.xinyang.life/xin/nur.git"
|
||||
}
|
||||
},
|
||||
"pre-commit-hooks": {
|
||||
"inputs": {
|
||||
"flake-compat": "flake-compat",
|
||||
"flake-utils": "flake-utils_2",
|
||||
"gitignore": "gitignore",
|
||||
"nixpkgs": [
|
||||
"am-kernels",
|
||||
"nixpkgs"
|
||||
],
|
||||
"nixpkgs-stable": "nixpkgs-stable"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1712055707,
|
||||
"narHash": "sha256-4XLvuSIDZJGS17xEwSrNuJLL7UjDYKGJSbK1WWX2AK8=",
|
||||
"owner": "cachix",
|
||||
"repo": "pre-commit-hooks.nix",
|
||||
"rev": "e35aed5fda3cc79f88ed7f1795021e559582093a",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "cachix",
|
||||
"repo": "pre-commit-hooks.nix",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"pre-commit-hooks_2": {
|
||||
"inputs": {
|
||||
"flake-compat": "flake-compat_2",
|
||||
"flake-utils": "flake-utils_4",
|
||||
"gitignore": "gitignore_2",
|
||||
"nixpkgs": [
|
||||
"am-kernels",
|
||||
"ysyx-workbench",
|
||||
"nixpkgs"
|
||||
],
|
||||
"nixpkgs-stable": "nixpkgs-stable_2"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1712055707,
|
||||
"narHash": "sha256-4XLvuSIDZJGS17xEwSrNuJLL7UjDYKGJSbK1WWX2AK8=",
|
||||
"owner": "cachix",
|
||||
"repo": "pre-commit-hooks.nix",
|
||||
"rev": "e35aed5fda3cc79f88ed7f1795021e559582093a",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "cachix",
|
||||
"repo": "pre-commit-hooks.nix",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"pre-commit-hooks_3": {
|
||||
"inputs": {
|
||||
"flake-compat": "flake-compat_3",
|
||||
"flake-utils": "flake-utils_6",
|
||||
"gitignore": "gitignore_3",
|
||||
"nixpkgs": [
|
||||
"diffu",
|
||||
"nixpkgs"
|
||||
],
|
||||
"nixpkgs-stable": "nixpkgs-stable_3"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1712055707,
|
||||
"narHash": "sha256-4XLvuSIDZJGS17xEwSrNuJLL7UjDYKGJSbK1WWX2AK8=",
|
||||
"owner": "cachix",
|
||||
"repo": "pre-commit-hooks.nix",
|
||||
"rev": "e35aed5fda3cc79f88ed7f1795021e559582093a",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "cachix",
|
||||
"repo": "pre-commit-hooks.nix",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"pre-commit-hooks_4": {
|
||||
"inputs": {
|
||||
"flake-compat": "flake-compat_4",
|
||||
"flake-utils": "flake-utils_8",
|
||||
"gitignore": "gitignore_4",
|
||||
"nixpkgs": [
|
||||
"nixpkgs"
|
||||
],
|
||||
"nixpkgs-stable": "nixpkgs-stable_4"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1712055707,
|
||||
"narHash": "sha256-4XLvuSIDZJGS17xEwSrNuJLL7UjDYKGJSbK1WWX2AK8=",
|
||||
"owner": "cachix",
|
||||
"repo": "pre-commit-hooks.nix",
|
||||
"rev": "e35aed5fda3cc79f88ed7f1795021e559582093a",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "cachix",
|
||||
"repo": "pre-commit-hooks.nix",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"root": {
|
||||
"inputs": {
|
||||
"am-kernels": "am-kernels",
|
||||
"diffu": "diffu",
|
||||
"flake-utils": "flake-utils_7",
|
||||
"nixpkgs": "nixpkgs_3",
|
||||
"nixpkgs-circt162": "nixpkgs-circt162_2",
|
||||
"nur-xin": "nur-xin_3",
|
||||
"pre-commit-hooks": "pre-commit-hooks_4"
|
||||
}
|
||||
},
|
||||
"systems": {
|
||||
"locked": {
|
||||
"lastModified": 1681028828,
|
||||
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
|
||||
"owner": "nix-systems",
|
||||
"repo": "default",
|
||||
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "nix-systems",
|
||||
"repo": "default",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"systems_2": {
|
||||
"locked": {
|
||||
"lastModified": 1681028828,
|
||||
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
|
||||
"owner": "nix-systems",
|
||||
"repo": "default",
|
||||
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "nix-systems",
|
||||
"repo": "default",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"systems_3": {
|
||||
"locked": {
|
||||
"lastModified": 1681028828,
|
||||
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
|
||||
"owner": "nix-systems",
|
||||
"repo": "default",
|
||||
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "nix-systems",
|
||||
"repo": "default",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"systems_4": {
|
||||
"locked": {
|
||||
"lastModified": 1681028828,
|
||||
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
|
||||
"owner": "nix-systems",
|
||||
"repo": "default",
|
||||
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "nix-systems",
|
||||
"repo": "default",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"systems_5": {
|
||||
"locked": {
|
||||
"lastModified": 1681028828,
|
||||
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
|
||||
"owner": "nix-systems",
|
||||
"repo": "default",
|
||||
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "nix-systems",
|
||||
"repo": "default",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"systems_6": {
|
||||
"locked": {
|
||||
"lastModified": 1681028828,
|
||||
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
|
||||
"owner": "nix-systems",
|
||||
"repo": "default",
|
||||
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "nix-systems",
|
||||
"repo": "default",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"systems_7": {
|
||||
"locked": {
|
||||
"lastModified": 1681028828,
|
||||
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
|
||||
"owner": "nix-systems",
|
||||
"repo": "default",
|
||||
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "nix-systems",
|
||||
"repo": "default",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"systems_8": {
|
||||
"locked": {
|
||||
"lastModified": 1681028828,
|
||||
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
|
||||
"owner": "nix-systems",
|
||||
"repo": "default",
|
||||
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "nix-systems",
|
||||
"repo": "default",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"ysyx-workbench": {
|
||||
"inputs": {
|
||||
"flake-utils": "flake-utils_3",
|
||||
"nixpkgs": [
|
||||
"am-kernels",
|
||||
"nixpkgs"
|
||||
],
|
||||
"nixpkgs-circt162": "nixpkgs-circt162",
|
||||
"nur-xin": "nur-xin",
|
||||
"pre-commit-hooks": "pre-commit-hooks_2"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1723551098,
|
||||
"narHash": "sha256-/AnVxufgQoAuvNBSKm0BG+tTS++/HuaNoW+loroSQig=",
|
||||
"ref": "refs/heads/master",
|
||||
"rev": "8ee1551dc2857091fca6456c1367aab7090899fe",
|
||||
"revCount": 119,
|
||||
"type": "git",
|
||||
"url": "https://git.xinyang.life/xin/ysyx-workbench"
|
||||
},
|
||||
"original": {
|
||||
"type": "git",
|
||||
"url": "https://git.xinyang.life/xin/ysyx-workbench"
|
||||
}
|
||||
}
|
||||
},
|
||||
"root": "root",
|
||||
"version": 7
|
||||
}
|
148
flake.nix
Normal file
148
flake.nix
Normal file
|
@ -0,0 +1,148 @@
|
|||
{
|
||||
inputs = {
|
||||
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
|
||||
nixpkgs-circt162.url = "github:NixOS/nixpkgs/7995cae3ad60e3d6931283d650d7f43d31aaa5c7";
|
||||
flake-utils.url = "github:numtide/flake-utils";
|
||||
pre-commit-hooks = {
|
||||
url = "github:cachix/pre-commit-hooks.nix";
|
||||
inputs.nixpkgs.follows = "nixpkgs";
|
||||
};
|
||||
nur-xin = {
|
||||
url = "git+https://git.xinyang.life/xin/nur.git";
|
||||
inputs.nixpkgs.follows = "nixpkgs";
|
||||
};
|
||||
diffu.url = "git+https://git.xinyang.life/xin/diffu.git";
|
||||
am-kernels.url = "git+https://git.xinyang.life/xin/am-kernels.git?ref=dev";
|
||||
};
|
||||
|
||||
outputs = { self, flake-utils, nixpkgs, nixpkgs-circt162, pre-commit-hooks, nur-xin, diffu, am-kernels }@inputs:
|
||||
flake-utils.lib.eachDefaultSystem (system:
|
||||
let
|
||||
pkgs = import nixpkgs {
|
||||
inherit system;
|
||||
config.allowUnfree = true;
|
||||
overlays = [
|
||||
(self: super: {
|
||||
nvboard = nur-xin.legacyPackages.${system}.nvboard;
|
||||
mini-gdbstub = nur-xin.legacyPackages.${system}.mini-gdbstub;
|
||||
})
|
||||
];
|
||||
};
|
||||
|
||||
rv32CrossConfig = import nixpkgs {
|
||||
localSystem = system;
|
||||
crossSystem = {
|
||||
config = "riscv32-none-elf";
|
||||
gcc = {
|
||||
abi = "ilp32";
|
||||
arch = "rv32if";
|
||||
};
|
||||
};
|
||||
};
|
||||
in
|
||||
{
|
||||
checks = {
|
||||
pre-commit-check = pre-commit-hooks.lib.${system}.run {
|
||||
src = ./.;
|
||||
hooks = {
|
||||
trim-trailing-whitespace.enable = true;
|
||||
end-of-file-fixer.enable = true;
|
||||
cmake-format.enable = true;
|
||||
clang-format = {
|
||||
enable = true;
|
||||
types_or = pkgs.lib.mkForce [ "c" "c++" ];
|
||||
};
|
||||
scalafmt = {
|
||||
enable = true;
|
||||
package = pkgs.scalafmt;
|
||||
name = "Scalafmt";
|
||||
types = [ "scala" ];
|
||||
entry = "${pkgs.scalafmt}/bin/scalafmt --non-interactive";
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
packages = rec {
|
||||
abstract-machine = pkgs.callPackage ./abstract-machine { isa = "native"; };
|
||||
nemu = pkgs.callPackage ./nemu { };
|
||||
nemu-lib = pkgs.callPackage ./nemu { };
|
||||
|
||||
rv32Cross = rec {
|
||||
abstract-machine = rv32CrossConfig.callPackage ./abstract-machine { isa = "riscv"; platform = [ "nemu" "npc" ]; };
|
||||
};
|
||||
};
|
||||
|
||||
devShells.nemu = pkgs.mkShell {
|
||||
packages = with pkgs; [
|
||||
clang-tools
|
||||
gef
|
||||
SDL2
|
||||
gnumake
|
||||
pkg-config
|
||||
flex
|
||||
bison
|
||||
dtc
|
||||
|
||||
readline
|
||||
libllvm
|
||||
mini-gdbstub
|
||||
];
|
||||
inputsFrom = [
|
||||
self.packages.${system}.nemu
|
||||
];
|
||||
NEMU_HOME = "/home/xin/repo/ysyx-workbench/nemu";
|
||||
# NEMU_IMAGES_PATH = self.packages.${system}.rv32Cross.am-kernels-nemu + "/share/am-kernels";
|
||||
};
|
||||
|
||||
devShells.npc = pkgs.mkShell.override { stdenv = pkgs.ccacheStdenv; } {
|
||||
inherit (self.checks.${system}.pre-commit-check) shellHook;
|
||||
CHISEL_FIRTOOL_PATH = "${nixpkgs-circt162.legacyPackages.${system}.circt}/bin";
|
||||
# NPC_IMAGES_PATH = "${self.packages.${system}.rv32Cross.am-kernels-npc}/share/am-kernels";
|
||||
packages = with pkgs; [
|
||||
clang-tools
|
||||
cmake
|
||||
coursier
|
||||
espresso
|
||||
bloop
|
||||
|
||||
gdb
|
||||
jre
|
||||
|
||||
gtkwave
|
||||
];
|
||||
|
||||
nativeBuildInputs = with pkgs; [
|
||||
cmake
|
||||
ninja
|
||||
sbt
|
||||
nvboard
|
||||
nixpkgs-circt162.legacyPackages.${system}.circt
|
||||
yosys
|
||||
cli11
|
||||
flex
|
||||
bison
|
||||
verilator
|
||||
];
|
||||
|
||||
buildInputs = with pkgs; [
|
||||
spdlog
|
||||
nvboard
|
||||
openssl
|
||||
libllvm
|
||||
libxml2
|
||||
readline
|
||||
mini-gdbstub
|
||||
] ++ self.checks.${system}.pre-commit-check.enabledPackages;
|
||||
};
|
||||
|
||||
devShells.difftest = pkgs.mkShell {
|
||||
packages = [
|
||||
diffu.packages.${system}.default
|
||||
am-kernels.packages.${system}.rv32Cross.am-kernels-npc
|
||||
self.packages.${system}.nemu-lib
|
||||
];
|
||||
};
|
||||
}
|
||||
);
|
||||
}
|
41
git_commit.sh
Executable file
41
git_commit.sh
Executable file
|
@ -0,0 +1,41 @@
|
|||
#/usr/bin/env bash
|
||||
|
||||
STUID=ysyx_22040000
|
||||
STUNAME=李心杨
|
||||
|
||||
TRACER=tracer-ysyx
|
||||
GITFLAGS="-q --author=$TRACER<tracer@ysyx.org> --no-verify --allow-empty --no-gpg-sign"
|
||||
|
||||
WORK_BRANCH=$(git rev-parse --abbrev-ref HEAD)
|
||||
WORK_INDEX=.git/index.${WORK_BRANCH}
|
||||
TRACER_BRANCH=$TRACER
|
||||
|
||||
LOCK_DIR=.git/
|
||||
|
||||
git_soft_checkout () {
|
||||
git checkout --detach -q && git reset --soft $1 -q -- && git checkout $1 -q -- ;
|
||||
}
|
||||
|
||||
git_commit () {
|
||||
# create tracer branch if not existent
|
||||
git branch $TRACER_BRANCH -q 2>/dev/null || true
|
||||
# backup git index
|
||||
cp -a .git/index $WORK_INDEX
|
||||
# switch to tracer branch
|
||||
git_soft_checkout "$TRACER_BRANCH"
|
||||
# add files to commit
|
||||
git add . -A --ignore-errors
|
||||
# generate commit msg, commit changes in tracer branch
|
||||
printf "> $1 \n $STUID $STUNAME \n $(uname -a) \n $(uptime)\n" | git commit -F - $GITFLAGS
|
||||
git_soft_checkout "$WORK_BRANCH"
|
||||
mv $WORK_INDEX .git/index
|
||||
}
|
||||
|
||||
git_commit $1
|
||||
|
||||
if [ $? -eq 0 ]; then
|
||||
echo "[OK] Git commit track"
|
||||
else
|
||||
echo "[FAIL] Git commit track" && false
|
||||
fi
|
||||
|
75
nemu/.gitignore
vendored
75
nemu/.gitignore
vendored
|
@ -1,12 +1,67 @@
|
|||
*.*
|
||||
*
|
||||
!*/
|
||||
!Makefile
|
||||
!*.mk
|
||||
!*.[cSh]
|
||||
!*.cc
|
||||
!.gitignore
|
||||
!README.md
|
||||
!Kconfig
|
||||
include/config
|
||||
include/generated
|
||||
configs/defconfig
|
||||
build/
|
||||
.cache/
|
||||
.direnv/
|
||||
.config
|
||||
.config.old
|
||||
.envrc
|
||||
.metals/
|
||||
.vscode/
|
||||
.zed/
|
||||
compile_commands.json
|
||||
|
||||
### C ###
|
||||
# Prerequisites
|
||||
*.d
|
||||
|
||||
# Object files
|
||||
*.o
|
||||
*.ko
|
||||
*.obj
|
||||
*.elf
|
||||
|
||||
# Linker output
|
||||
*.ilk
|
||||
*.map
|
||||
*.exp
|
||||
|
||||
# Precompiled Headers
|
||||
*.gch
|
||||
*.pch
|
||||
|
||||
# Libraries
|
||||
*.lib
|
||||
*.a
|
||||
*.la
|
||||
*.lo
|
||||
|
||||
# Shared objects (inc. Windows DLLs)
|
||||
*.dll
|
||||
*.so
|
||||
*.so.*
|
||||
*.dylib
|
||||
|
||||
# Executables
|
||||
*.exe
|
||||
*.out
|
||||
*.app
|
||||
*.i*86
|
||||
*.x86_64
|
||||
*.hex
|
||||
|
||||
# Debug files
|
||||
*.dSYM/
|
||||
*.su
|
||||
*.idb
|
||||
*.pdb
|
||||
|
||||
# Kernel Module Compile Results
|
||||
*.mod*
|
||||
*.cmd
|
||||
.tmp_versions/
|
||||
modules.order
|
||||
Module.symvers
|
||||
Mkfile.old
|
||||
dkms.conf
|
||||
|
|
0
nemu/.result.tmp
Normal file
0
nemu/.result.tmp
Normal file
62
nemu/Kconfig
62
nemu/Kconfig
|
@ -126,6 +126,26 @@ endmenu
|
|||
|
||||
menu "Testing and Debugging"
|
||||
|
||||
choice
|
||||
prompt "Choose log level"
|
||||
default LOG_TRACE
|
||||
config LOG_TRACE
|
||||
bool "trace"
|
||||
config LOG_INFO
|
||||
bool "info"
|
||||
config LOG_WARNING
|
||||
bool "warning"
|
||||
config LOG_ERROR
|
||||
bool "error"
|
||||
endchoice
|
||||
|
||||
config LOG_LEVEL
|
||||
int
|
||||
default 1 if LOG_ERROR
|
||||
default 2 if LOG_WARNING
|
||||
default 3 if LOG_INFO
|
||||
default 4 if LOG_TRACE
|
||||
default 0
|
||||
|
||||
config TRACE
|
||||
bool "Enable tracer"
|
||||
|
@ -143,14 +163,54 @@ config TRACE_END
|
|||
|
||||
config ITRACE
|
||||
depends on TRACE && TARGET_NATIVE_ELF && ENGINE_INTERPRETER
|
||||
bool "Enable instruction tracer"
|
||||
bool "Enable instruction tracing"
|
||||
default y
|
||||
help
|
||||
Instraction tracing will log past instructions into a ring buffer
|
||||
and print them when NEMU exit unexpectedly.
|
||||
|
||||
config ITRACE_COND
|
||||
depends on ITRACE
|
||||
string "Only trace instructions when the condition is true"
|
||||
default "true"
|
||||
|
||||
config ITRACE_BUFFER
|
||||
depends on ITRACE
|
||||
int "Buffer size for intruction trace (unit: number of instructions)"
|
||||
default 10
|
||||
|
||||
config MTRACE
|
||||
depends on TRACE && LOG_TRACE
|
||||
bool "Enable memory tracing"
|
||||
default n
|
||||
|
||||
config MTRACE_RANGE
|
||||
depends on MTRACE
|
||||
string "Memory trace active range"
|
||||
default "0x0-0xfffffff"
|
||||
help
|
||||
Memory tracer will only print memory access in these ranges.
|
||||
Use comma to seperate between ranges.
|
||||
|
||||
config MTRACE_RANGE_MAX
|
||||
depends on MTRACE
|
||||
int "Max range count in MTRACE_RANGE"
|
||||
default 10
|
||||
|
||||
config FTRACE
|
||||
depends on TRACE && TARGET_NATIVE_ELF && ENGINE_INTERPRETER && LOG_TRACE
|
||||
bool "Enable function tracing"
|
||||
default n
|
||||
|
||||
config FTRACE_STACK_SIZE
|
||||
depends on FTRACE
|
||||
int "Max function track stack size"
|
||||
default 256
|
||||
|
||||
config FTRACE_LOG
|
||||
depends on FTRACE
|
||||
bool "Print log when entering a funciton"
|
||||
default n
|
||||
|
||||
config DIFFTEST
|
||||
depends on TARGET_NATIVE_ELF
|
||||
|
|
127
nemu/LICENSE
Normal file
127
nemu/LICENSE
Normal file
|
@ -0,0 +1,127 @@
|
|||
木兰宽松许可证, 第2版
|
||||
|
||||
木兰宽松许可证, 第2版
|
||||
2020年1月 http://license.coscl.org.cn/MulanPSL2
|
||||
|
||||
|
||||
您对“软件”的复制、使用、修改及分发受木兰宽松许可证,第2版(“本许可证”)的如下条款的约束:
|
||||
|
||||
0. 定义
|
||||
|
||||
“软件”是指由“贡献”构成的许可在“本许可证”下的程序和相关文档的集合。
|
||||
|
||||
“贡献”是指由任一“贡献者”许可在“本许可证”下的受版权法保护的作品。
|
||||
|
||||
“贡献者”是指将受版权法保护的作品许可在“本许可证”下的自然人或“法人实体”。
|
||||
|
||||
“法人实体”是指提交贡献的机构及其“关联实体”。
|
||||
|
||||
“关联实体”是指,对“本许可证”下的行为方而言,控制、受控制或与其共同受控制的机构,此处的控制是指有受控方或共同受控方至少50%直接或间接的投票权、资金或其他有价证券。
|
||||
|
||||
1. 授予版权许可
|
||||
|
||||
每个“贡献者”根据“本许可证”授予您永久性的、全球性的、免费的、非独占的、不可撤销的版权许可,您可以复制、使用、修改、分发其“贡献”,不论修改与否。
|
||||
|
||||
2. 授予专利许可
|
||||
|
||||
每个“贡献者”根据“本许可证”授予您永久性的、全球性的、免费的、非独占的、不可撤销的(根据本条规定撤销除外)专利许可,供您制造、委托制造、使用、许诺销售、销售、进口其“贡献”或以其他方式转移其“贡献”。前述专利许可仅限于“贡献者”现在或将来拥有或控制的其“贡献”本身或其“贡献”与许可“贡献”时的“软件”结合而将必然会侵犯的专利权利要求,不包括对“贡献”的修改或包含“贡献”的其他结合。如果您或您的“关联实体”直接或间接地,就“软件”或其中的“贡献”对任何人发起专利侵权诉讼(包括反诉或交叉诉讼)或其他专利维权行动,指控其侵犯专利权,则“本许可证”授予您对“软件”的专利许可自您提起诉讼或发起维权行动之日终止。
|
||||
|
||||
3. 无商标许可
|
||||
|
||||
“本许可证”不提供对“贡献者”的商品名称、商标、服务标志或产品名称的商标许可,但您为满足第4条规定的声明义务而必须使用除外。
|
||||
|
||||
4. 分发限制
|
||||
|
||||
您可以在任何媒介中将“软件”以源程序形式或可执行形式重新分发,不论修改与否,但您必须向接收者提供“本许可证”的副本,并保留“软件”中的版权、商标、专利及免责声明。
|
||||
|
||||
5. 免责声明与责任限制
|
||||
|
||||
“软件”及其中的“贡献”在提供时不带任何明示或默示的担保。在任何情况下,“贡献者”或版权所有者不对任何人因使用“软件”或其中的“贡献”而引发的任何直接或间接损失承担责任,不论因何种原因导致或者基于何种法律理论,即使其曾被建议有此种损失的可能性。
|
||||
|
||||
6. 语言
|
||||
“本许可证”以中英文双语表述,中英文版本具有同等法律效力。如果中英文版本存在任何冲突不一致,以中文版为准。
|
||||
|
||||
条款结束
|
||||
|
||||
如何将木兰宽松许可证,第2版,应用到您的软件
|
||||
|
||||
如果您希望将木兰宽松许可证,第2版,应用到您的新软件,为了方便接收者查阅,建议您完成如下三步:
|
||||
|
||||
1, 请您补充如下声明中的空白,包括软件名、软件的首次发表年份以及您作为版权人的名字;
|
||||
|
||||
2, 请您在软件包的一级目录下创建以“LICENSE”为名的文件,将整个许可证文本放入该文件中;
|
||||
|
||||
3, 请将如下声明文本放入每个源文件的头部注释中。
|
||||
|
||||
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.
|
||||
|
||||
|
||||
Mulan Permissive Software License,Version 2
|
||||
|
||||
Mulan Permissive Software License,Version 2 (Mulan PSL v2)
|
||||
January 2020 http://license.coscl.org.cn/MulanPSL2
|
||||
|
||||
Your reproduction, use, modification and distribution of the Software shall be subject to Mulan PSL v2 (this License) with the following terms and conditions:
|
||||
|
||||
0. Definition
|
||||
|
||||
Software means the program and related documents which are licensed under this License and comprise all Contribution(s).
|
||||
|
||||
Contribution means the copyrightable work licensed by a particular Contributor under this License.
|
||||
|
||||
Contributor means the Individual or Legal Entity who licenses its copyrightable work under this License.
|
||||
|
||||
Legal Entity means the entity making a Contribution and all its Affiliates.
|
||||
|
||||
Affiliates means entities that control, are controlled by, or are under common control with the acting entity under this License, ‘control’ means direct or indirect ownership of at least fifty percent (50%) of the voting power, capital or other securities of controlled or commonly controlled entity.
|
||||
|
||||
1. Grant of Copyright License
|
||||
|
||||
Subject to the terms and conditions of this License, each Contributor hereby grants to you a perpetual, worldwide, royalty-free, non-exclusive, irrevocable copyright license to reproduce, use, modify, or distribute its Contribution, with modification or not.
|
||||
|
||||
2. Grant of Patent License
|
||||
|
||||
Subject to the terms and conditions of this License, each Contributor hereby grants to you a perpetual, worldwide, royalty-free, non-exclusive, irrevocable (except for revocation under this Section) patent license to make, have made, use, offer for sale, sell, import or otherwise transfer its Contribution, where such patent license is only limited to the patent claims owned or controlled by such Contributor now or in future which will be necessarily infringed by its Contribution alone, or by combination of the Contribution with the Software to which the Contribution was contributed. The patent license shall not apply to any modification of the Contribution, and any other combination which includes the Contribution. If you or your Affiliates directly or indirectly institute patent litigation (including a cross claim or counterclaim in a litigation) or other patent enforcement activities against any individual or entity by alleging that the Software or any Contribution in it infringes patents, then any patent license granted to you under this License for the Software shall terminate as of the date such litigation or activity is filed or taken.
|
||||
|
||||
3. No Trademark License
|
||||
|
||||
No trademark license is granted to use the trade names, trademarks, service marks, or product names of Contributor, except as required to fulfill notice requirements in Section 4.
|
||||
|
||||
4. Distribution Restriction
|
||||
|
||||
You may distribute the Software in any medium with or without modification, whether in source or executable forms, provided that you provide recipients with a copy of this License and retain copyright, patent, trademark and disclaimer statements in the Software.
|
||||
|
||||
5. Disclaimer of Warranty and Limitation of Liability
|
||||
|
||||
THE SOFTWARE AND CONTRIBUTION IN IT ARE PROVIDED WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED. IN NO EVENT SHALL ANY CONTRIBUTOR OR COPYRIGHT HOLDER BE LIABLE TO YOU FOR ANY DAMAGES, INCLUDING, BUT NOT LIMITED TO ANY DIRECT, OR INDIRECT, SPECIAL OR CONSEQUENTIAL DAMAGES ARISING FROM YOUR USE OR INABILITY TO USE THE SOFTWARE OR THE CONTRIBUTION IN IT, NO MATTER HOW IT’S CAUSED OR BASED ON WHICH LEGAL THEORY, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
|
||||
|
||||
6. Language
|
||||
|
||||
THIS LICENSE IS WRITTEN IN BOTH CHINESE AND ENGLISH, AND THE CHINESE VERSION AND ENGLISH VERSION SHALL HAVE THE SAME LEGAL EFFECT. IN THE CASE OF DIVERGENCE BETWEEN THE CHINESE AND ENGLISH VERSIONS, THE CHINESE VERSION SHALL PREVAIL.
|
||||
|
||||
END OF THE TERMS AND CONDITIONS
|
||||
|
||||
How to Apply the Mulan Permissive Software License,Version 2 (Mulan PSL v2) to Your Software
|
||||
|
||||
To apply the Mulan PSL v2 to your work, for easy identification by recipients, you are suggested to complete following three steps:
|
||||
|
||||
i Fill in the blanks in following statement, including insert your software name, the year of the first publication of your software, and your name identified as the copyright owner;
|
||||
|
||||
ii Create a file named “LICENSE” which contains the whole context of this License in the first directory of your software package;
|
||||
|
||||
iii Attach the statement to the appropriate annotated syntax at the beginning of each source file.
|
||||
|
||||
|
||||
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.
|
|
@ -40,7 +40,9 @@ SRCS-y += $(shell find -L $(DIRS-y) -name "*.c")
|
|||
SRCS = $(filter-out $(SRCS-BLACKLIST-y),$(SRCS-y))
|
||||
|
||||
# Extract compiler and options from menuconfig
|
||||
ifneq ($(CONFIG_CC),)
|
||||
CC = $(call remove_quote,$(CONFIG_CC))
|
||||
endif
|
||||
CFLAGS_BUILD += $(call remove_quote,$(CONFIG_CC_OPT))
|
||||
CFLAGS_BUILD += $(if $(CONFIG_CC_LTO),-flto,)
|
||||
CFLAGS_BUILD += $(if $(CONFIG_CC_DEBUG),-Og -ggdb3,)
|
||||
|
@ -48,6 +50,7 @@ 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)
|
||||
INC_PATH += $(NEMU_HOME)/src/isa/$(GUEST_ISA)/local-include
|
||||
|
||||
# Include rules for menuconfig
|
||||
include $(NEMU_HOME)/scripts/config.mk
|
||||
|
@ -59,3 +62,36 @@ else
|
|||
# Include rules to build NEMU
|
||||
include $(NEMU_HOME)/scripts/native.mk
|
||||
endif
|
||||
|
||||
include $(NEMU_HOME)/tests/Makefile
|
||||
unit-tests: TEST_OBJS = $(filter-out $(OBJ_DIR)/src/nemu-main.o, $(OBJS))
|
||||
unit-tests: CFLAGS += $(shell pkg-config --cflags check)
|
||||
unit-tests: LDFLAGS += $(shell pkg-config --libs check)
|
||||
unit-tests: $(TEST_SRCS:%.c=$(OBJ_DIR)/%)
|
||||
|
||||
IMAGES = $(patsubst %.bin, %, $(shell find $(IMAGES_PATH) -type f -name '*.bin'))
|
||||
|
||||
COLOR_RED = \033[1;31m
|
||||
COLOR_GREEN = \033[1;32m
|
||||
COLOR_BLUE = \033[1;34m
|
||||
COLOR_NONE = \033[0m
|
||||
|
||||
RESULT = .result.tmp
|
||||
$(shell > $(RESULT)) # Clear result file
|
||||
|
||||
$(IMAGES): %: %.bin $(BINARY)
|
||||
@echo + TEST $(notdir $<)
|
||||
@$(BINARY) -b $< >/dev/null 2>&1 || printf "\t%14s\n" $(notdir $<) >> $(RESULT)
|
||||
|
||||
integration-tests: $(IMAGES)
|
||||
@printf "$(COLOR_BLUE)INTEGRATION TEST:$(COLOR_NONE)\n\tALL: %s\n\tFAILED: %s\n" $(words $(IMAGES)) $(shell wc -l $(RESULT) | cut -f1 -d' ')
|
||||
@test ! -s $(RESULT) || printf "$(COLOR_RED)FAILED:$(COLOR_NONE)\n"
|
||||
@cat $(RESULT)
|
||||
@test ! -s $(RESULT); \
|
||||
r=$$?; \
|
||||
$(RM) $(RESULT); \
|
||||
test $$r -eq 0
|
||||
|
||||
test: unit-tests integration-tests
|
||||
|
||||
.PHONY: test unit-tests integration-tests
|
||||
|
|
87
nemu/configs/libdefconfig
Normal file
87
nemu/configs/libdefconfig
Normal file
|
@ -0,0 +1,87 @@
|
|||
#
|
||||
# Automatically generated file; DO NOT EDIT.
|
||||
# NEMU Configuration Menu
|
||||
#
|
||||
# CONFIG_ISA_x86 is not set
|
||||
# CONFIG_ISA_mips32 is not set
|
||||
CONFIG_ISA_riscv=y
|
||||
# CONFIG_ISA_loongarch32r is not set
|
||||
CONFIG_ISA="riscv32"
|
||||
|
||||
#
|
||||
# ISA-dependent Options for riscv
|
||||
#
|
||||
# CONFIG_RV64 is not set
|
||||
# CONFIG_RVE is not set
|
||||
# end of ISA-dependent Options for riscv
|
||||
|
||||
CONFIG_ENGINE_INTERPRETER=y
|
||||
CONFIG_ENGINE="interpreter"
|
||||
CONFIG_MODE_SYSTEM=y
|
||||
# CONFIG_TARGET_NATIVE_ELF is not set
|
||||
CONFIG_TARGET_SHARE=y
|
||||
# CONFIG_TARGET_AM is not set
|
||||
|
||||
#
|
||||
# Build Options
|
||||
#
|
||||
CONFIG_CC_GCC=y
|
||||
# CONFIG_CC_GPP is not set
|
||||
# CONFIG_CC_CLANG is not set
|
||||
CONFIG_CC="gcc"
|
||||
# CONFIG_CC_O0 is not set
|
||||
# CONFIG_CC_O1 is not set
|
||||
CONFIG_CC_O2=y
|
||||
# CONFIG_CC_O3 is not set
|
||||
CONFIG_CC_OPT="-O2"
|
||||
# CONFIG_CC_LTO is not set
|
||||
# CONFIG_CC_DEBUG is not set
|
||||
# CONFIG_CC_ASAN is not set
|
||||
# end of Build Options
|
||||
|
||||
#
|
||||
# Testing and Debugging
|
||||
#
|
||||
CONFIG_LOG_TRACE=y
|
||||
# CONFIG_LOG_INFO is not set
|
||||
# CONFIG_LOG_WARNING is not set
|
||||
# CONFIG_LOG_ERROR is not set
|
||||
CONFIG_LOG_LEVEL=4
|
||||
CONFIG_TRACE=y
|
||||
CONFIG_TRACE_START=0
|
||||
CONFIG_TRACE_END=10000
|
||||
# CONFIG_MTRACE is not set
|
||||
CONFIG_DIFFTEST_REF_PATH="none"
|
||||
CONFIG_DIFFTEST_REF_NAME="none"
|
||||
# end of Testing and Debugging
|
||||
|
||||
#
|
||||
# Memory Configuration
|
||||
#
|
||||
CONFIG_MBASE=0x80000000
|
||||
CONFIG_MSIZE=0x8000000
|
||||
CONFIG_PC_RESET_OFFSET=0
|
||||
# CONFIG_PMEM_MALLOC is not set
|
||||
CONFIG_PMEM_GARRAY=y
|
||||
CONFIG_MEM_RANDOM=y
|
||||
# end of Memory Configuration
|
||||
|
||||
CONFIG_DEVICE=y
|
||||
CONFIG_HAS_SERIAL=y
|
||||
CONFIG_SERIAL_MMIO=0x10000000
|
||||
# CONFIG_SERIAL_INPUT_FIFO is not set
|
||||
CONFIG_HAS_TIMER=y
|
||||
CONFIG_RTC_MMIO=0x10001000
|
||||
# CONFIG_HAS_KEYBOARD is not set
|
||||
# CONFIG_HAS_VGA is not set
|
||||
# CONFIG_HAS_AUDIO is not set
|
||||
# CONFIG_HAS_DISK is not set
|
||||
# CONFIG_HAS_SDCARD is not set
|
||||
|
||||
#
|
||||
# Miscellaneous
|
||||
#
|
||||
CONFIG_TIMER_GETTIMEOFDAY=y
|
||||
# CONFIG_TIMER_CLOCK_GETTIME is not set
|
||||
CONFIG_RT_CHECK=y
|
||||
# end of Miscellaneous
|
72
nemu/configs/riscv32-lib_defconfig
Normal file
72
nemu/configs/riscv32-lib_defconfig
Normal file
|
@ -0,0 +1,72 @@
|
|||
#
|
||||
# Automatically generated file; DO NOT EDIT.
|
||||
# NEMU Configuration Menu
|
||||
#
|
||||
# CONFIG_ISA_x86 is not set
|
||||
# CONFIG_ISA_mips32 is not set
|
||||
CONFIG_ISA_riscv=y
|
||||
# CONFIG_ISA_loongarch32r is not set
|
||||
CONFIG_ISA="riscv32"
|
||||
|
||||
#
|
||||
# ISA-dependent Options for riscv
|
||||
#
|
||||
# CONFIG_RV64 is not set
|
||||
# CONFIG_RVE is not set
|
||||
# end of ISA-dependent Options for riscv
|
||||
|
||||
CONFIG_ENGINE_INTERPRETER=y
|
||||
CONFIG_ENGINE="interpreter"
|
||||
CONFIG_MODE_SYSTEM=y
|
||||
# CONFIG_TARGET_NATIVE_ELF is not set
|
||||
CONFIG_TARGET_SHARE=y
|
||||
# CONFIG_TARGET_AM is not set
|
||||
|
||||
#
|
||||
# Build Options
|
||||
#
|
||||
CONFIG_CC_GCC=y
|
||||
# CONFIG_CC_GPP is not set
|
||||
# CONFIG_CC_CLANG is not set
|
||||
CONFIG_CC="gcc"
|
||||
# CONFIG_CC_O0 is not set
|
||||
# CONFIG_CC_O1 is not set
|
||||
CONFIG_CC_O2=y
|
||||
# CONFIG_CC_O3 is not set
|
||||
CONFIG_CC_OPT="-O2"
|
||||
CONFIG_CC_LTO=y
|
||||
CONFIG_CC_DEBUG=y
|
||||
# CONFIG_CC_ASAN is not set
|
||||
# end of Build Options
|
||||
|
||||
#
|
||||
# Testing and Debugging
|
||||
#
|
||||
CONFIG_LOG_TRACE=y
|
||||
# CONFIG_LOG_INFO is not set
|
||||
# CONFIG_LOG_WARNING is not set
|
||||
# CONFIG_LOG_ERROR is not set
|
||||
CONFIG_LOG_LEVEL=4
|
||||
# CONFIG_TRACE is not set
|
||||
CONFIG_DIFFTEST_REF_PATH="none"
|
||||
CONFIG_DIFFTEST_REF_NAME="none"
|
||||
# end of Testing and Debugging
|
||||
|
||||
#
|
||||
# Memory Configuration
|
||||
#
|
||||
CONFIG_MBASE=0x80000000
|
||||
CONFIG_MSIZE=0x8000000
|
||||
CONFIG_PC_RESET_OFFSET=0
|
||||
# CONFIG_PMEM_MALLOC is not set
|
||||
CONFIG_PMEM_GARRAY=y
|
||||
CONFIG_MEM_RANDOM=y
|
||||
# end of Memory Configuration
|
||||
|
||||
#
|
||||
# Miscellaneous
|
||||
#
|
||||
CONFIG_TIMER_GETTIMEOFDAY=y
|
||||
# CONFIG_TIMER_CLOCK_GETTIME is not set
|
||||
CONFIG_RT_CHECK=y
|
||||
# end of Miscellaneous
|
74
nemu/configs/rv32_defconfig
Normal file
74
nemu/configs/rv32_defconfig
Normal file
|
@ -0,0 +1,74 @@
|
|||
#
|
||||
# Automatically generated file; DO NOT EDIT.
|
||||
# NEMU Configuration Menu
|
||||
#
|
||||
# CONFIG_ISA_x86 is not set
|
||||
# CONFIG_ISA_mips32 is not set
|
||||
CONFIG_ISA_riscv=y
|
||||
# CONFIG_ISA_loongarch32r is not set
|
||||
CONFIG_ISA="riscv32"
|
||||
|
||||
#
|
||||
# ISA-dependent Options for riscv
|
||||
#
|
||||
# CONFIG_RV64 is not set
|
||||
# CONFIG_RVE is not set
|
||||
# end of ISA-dependent Options for riscv
|
||||
|
||||
CONFIG_ENGINE_INTERPRETER=y
|
||||
CONFIG_ENGINE="interpreter"
|
||||
CONFIG_MODE_SYSTEM=y
|
||||
CONFIG_TARGET_NATIVE_ELF=y
|
||||
# CONFIG_TARGET_SHARE is not set
|
||||
# CONFIG_TARGET_AM is not set
|
||||
|
||||
#
|
||||
# Build Options
|
||||
#
|
||||
CONFIG_CC_GCC=y
|
||||
# CONFIG_CC_GPP is not set
|
||||
# CONFIG_CC_CLANG is not set
|
||||
CONFIG_CC="gcc"
|
||||
# CONFIG_CC_O0 is not set
|
||||
# CONFIG_CC_O1 is not set
|
||||
CONFIG_CC_O2=y
|
||||
# CONFIG_CC_O3 is not set
|
||||
CONFIG_CC_OPT="-O2"
|
||||
# CONFIG_CC_LTO is not set
|
||||
# CONFIG_CC_DEBUG is not set
|
||||
CONFIG_CC_ASAN=y
|
||||
# end of Build Options
|
||||
|
||||
#
|
||||
# Testing and Debugging
|
||||
#
|
||||
CONFIG_TRACE=y
|
||||
CONFIG_TRACE_START=0
|
||||
CONFIG_TRACE_END=10000
|
||||
CONFIG_ITRACE=y
|
||||
CONFIG_ITRACE_COND="true"
|
||||
# CONFIG_DIFFTEST is not set
|
||||
CONFIG_DIFFTEST_REF_PATH="none"
|
||||
CONFIG_DIFFTEST_REF_NAME="none"
|
||||
# end of Testing and Debugging
|
||||
|
||||
#
|
||||
# Memory Configuration
|
||||
#
|
||||
CONFIG_MBASE=0x80000000
|
||||
CONFIG_MSIZE=0x8000000
|
||||
CONFIG_PC_RESET_OFFSET=0
|
||||
# CONFIG_PMEM_MALLOC is not set
|
||||
CONFIG_PMEM_GARRAY=y
|
||||
CONFIG_MEM_RANDOM=y
|
||||
# end of Memory Configuration
|
||||
|
||||
# CONFIG_DEVICE is not set
|
||||
|
||||
#
|
||||
# Miscellaneous
|
||||
#
|
||||
CONFIG_TIMER_GETTIMEOFDAY=y
|
||||
# CONFIG_TIMER_CLOCK_GETTIME is not set
|
||||
CONFIG_RT_CHECK=y
|
||||
# end of Miscellaneous
|
71
nemu/default.nix
Normal file
71
nemu/default.nix
Normal file
|
@ -0,0 +1,71 @@
|
|||
{ stdenv
|
||||
, lib
|
||||
, gnumake
|
||||
, pkg-config
|
||||
, bison
|
||||
, flex
|
||||
, dtc
|
||||
, check
|
||||
, mini-gdbstub
|
||||
, readline
|
||||
, libllvm
|
||||
, SDL2
|
||||
, am-kernels ? ""
|
||||
, defconfig ? "alldefconfig"
|
||||
}:
|
||||
|
||||
stdenv.mkDerivation rec {
|
||||
pname = "nemu";
|
||||
version = "2024-08-15";
|
||||
|
||||
src = ./.;
|
||||
|
||||
nativeBuildInputs = [
|
||||
gnumake
|
||||
pkg-config
|
||||
flex
|
||||
bison
|
||||
dtc
|
||||
];
|
||||
|
||||
buildInputs = [
|
||||
SDL2
|
||||
readline
|
||||
libllvm
|
||||
mini-gdbstub
|
||||
];
|
||||
|
||||
checkInputs = [
|
||||
check
|
||||
am-kernels
|
||||
];
|
||||
|
||||
configurePhase = ''
|
||||
export NEMU_HOME=$(pwd)
|
||||
make ${defconfig}
|
||||
'';
|
||||
|
||||
buildPhase = ''
|
||||
make
|
||||
'';
|
||||
|
||||
doCheck = (am-kernels != "");
|
||||
checkPhase = ''
|
||||
export NEMU_IMAGES_PATH=${am-kernels}/share/am-kernels
|
||||
make test
|
||||
'';
|
||||
|
||||
installPhase = ''
|
||||
if [ -d "./lib" ] && [ "$(ls -A ./lib)" ]; then
|
||||
mkdir -p "$out/lib"
|
||||
fi
|
||||
if [ -d "./bin" ] && [ "$(ls -A ./bin)" ]; then
|
||||
mkdir -p $out/bin
|
||||
fi
|
||||
make PREFIX=$out install
|
||||
'';
|
||||
|
||||
shellHook = ''
|
||||
export NEMU_HOME=$(pwd)
|
||||
'';
|
||||
}
|
|
@ -17,12 +17,12 @@
|
|||
#define __COMMON_H__
|
||||
|
||||
#include <stdint.h>
|
||||
#include <inttypes.h>
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <generated/autoconf.h>
|
||||
#include <macro.h>
|
||||
#include <types.h>
|
||||
|
||||
#ifdef CONFIG_TARGET_AM
|
||||
#include <klib.h>
|
||||
|
@ -31,19 +31,6 @@
|
|||
#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
|
||||
|
|
9
nemu/include/config.h
Normal file
9
nemu/include/config.h
Normal file
|
@ -0,0 +1,9 @@
|
|||
#ifndef __NEMU_CONFIG_H__
|
||||
#define __NEMU_CONFIG_H__
|
||||
|
||||
extern char *log_file = NULL;
|
||||
extern char *elf_file = NULL;
|
||||
extern char *img_file = NULL;
|
||||
extern bool enable_gdbstub = false;
|
||||
|
||||
#endif // __NEMU_CONFIG_H__
|
|
@ -17,8 +17,18 @@
|
|||
#define __CPU_CPU_H__
|
||||
|
||||
#include <common.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#include <gdbstub.h>
|
||||
#include <stddef.h>
|
||||
|
||||
typedef struct {
|
||||
size_t addr;
|
||||
bp_type_t type;
|
||||
} breakpoint_t;
|
||||
|
||||
void cpu_exec(uint64_t n);
|
||||
breakpoint_t *cpu_exec_with_bp(uint64_t n, breakpoint_t *bp, size_t len);
|
||||
|
||||
void set_nemu_state(int state, vaddr_t pc, int halt_ret);
|
||||
void invalid_inst(vaddr_t thispc);
|
||||
|
|
|
@ -16,40 +16,62 @@
|
|||
#ifndef __CPU_DECODE_H__
|
||||
#define __CPU_DECODE_H__
|
||||
|
||||
#include "types.h"
|
||||
#include <isa.h>
|
||||
|
||||
typedef enum { INST_NORMAL, INST_MEM_WRITE, INST_MEM_READ } inst_type_t;
|
||||
|
||||
typedef union {
|
||||
paddr_t rmem;
|
||||
paddr_t wmem;
|
||||
} inst_type_op;
|
||||
|
||||
typedef struct Decode {
|
||||
vaddr_t pc;
|
||||
vaddr_t snpc; // static next pc
|
||||
vaddr_t dnpc; // dynamic next pc
|
||||
inst_type_t inst_type;
|
||||
inst_type_op inst_value;
|
||||
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) {
|
||||
__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 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)
|
||||
#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
|
||||
|
@ -59,21 +81,24 @@ finish:
|
|||
*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) {
|
||||
__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); \
|
||||
} \
|
||||
#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);
|
||||
|
@ -85,18 +110,22 @@ finish:
|
|||
*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(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): ; }
|
||||
#define INSTPAT_START(name) \
|
||||
{ \
|
||||
const void **__instpat_end = &&concat(__instpat_end_, name);
|
||||
#define INSTPAT_END(name) \
|
||||
concat(__instpat_end_, name) :; \
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,53 +0,0 @@
|
|||
/***************************************************************************************
|
||||
* 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
|
|
@ -16,27 +16,59 @@
|
|||
#ifndef __DEBUG_H__
|
||||
#define __DEBUG_H__
|
||||
|
||||
#include <common.h>
|
||||
#include <macro.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__)
|
||||
IFDEF(CONFIG_ITRACE, void log_itrace_print());
|
||||
|
||||
#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); \
|
||||
} \
|
||||
#if (CONFIG_LOG_LEVEL >= 4)
|
||||
#define Trace(format, ...) _Log("[TRACE] " format "\n", ##__VA_ARGS__)
|
||||
#else
|
||||
#define Trace(format, ...)
|
||||
#endif
|
||||
|
||||
#if (CONFIG_LOG_LEVEL >= 3)
|
||||
#define Log(format, ...) \
|
||||
_Log(ANSI_FMT("[INFO] %s:%d %s() ", ANSI_FG_BLUE) format "\n", __FILE__, \
|
||||
__LINE__, __func__, ##__VA_ARGS__)
|
||||
#else
|
||||
#define Log(format, ...)
|
||||
#endif
|
||||
|
||||
#if (CONFIG_LOG_LEVEL >= 2)
|
||||
#define Warning(format, ...) \
|
||||
_Log(ANSI_FMT("[WARNING] %s:%d %s() ", ANSI_FG_YELLOW) format "\n", \
|
||||
__FILE__, __LINE__, __func__, ##__VA_ARGS__)
|
||||
#else
|
||||
#define Warning(format, ...)
|
||||
#endif
|
||||
|
||||
#if (CONFIG_LOG_LEVEL >= 1)
|
||||
#define Error(format, ...) \
|
||||
_Log(ANSI_FMT("[ERROR] %s:%d %s() ", ANSI_FG_RED) format "\n", __FILE__, \
|
||||
__LINE__, __func__, ##__VA_ARGS__)
|
||||
#else
|
||||
#define Error(format, ...)
|
||||
#endif
|
||||
|
||||
#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)); \
|
||||
IFDEF(CONFIG_ITRACE, log_itrace_print()); \
|
||||
extern void assert_fail_msg(); \
|
||||
assert_fail_msg(); \
|
||||
assert(cond); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define panic(format, ...) Assert(0, format, ## __VA_ARGS__)
|
||||
#define panic(format, ...) Assert(0, format, ##__VA_ARGS__)
|
||||
|
||||
#define TODO() panic("please implement me")
|
||||
|
||||
|
|
|
@ -16,10 +16,12 @@
|
|||
#ifndef __DEVICE_MAP_H__
|
||||
#define __DEVICE_MAP_H__
|
||||
|
||||
#include <cpu/difftest.h>
|
||||
#include <difftest.h>
|
||||
#include <stdbool.h>
|
||||
#include <types.h>
|
||||
|
||||
typedef void(*io_callback_t)(uint32_t, int, bool);
|
||||
uint8_t* new_space(int size);
|
||||
typedef void (*io_callback_t)(uint32_t, int, bool);
|
||||
uint8_t *new_space(int size);
|
||||
|
||||
typedef struct {
|
||||
const char *name;
|
||||
|
@ -36,19 +38,19 @@ static inline bool map_inside(IOMap *map, paddr_t addr) {
|
|||
|
||||
static inline int find_mapid_by_addr(IOMap *maps, int size, paddr_t addr) {
|
||||
int i;
|
||||
for (i = 0; i < size; i ++) {
|
||||
for (i = 0; i < size; i++) {
|
||||
if (map_inside(maps + i, addr)) {
|
||||
difftest_skip_ref();
|
||||
nemu_do_difftest = false;
|
||||
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);
|
||||
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);
|
||||
|
|
|
@ -1,40 +0,0 @@
|
|||
/***************************************************************************************
|
||||
* 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
|
8
nemu/include/difftest.h
Normal file
8
nemu/include/difftest.h
Normal file
|
@ -0,0 +1,8 @@
|
|||
#ifndef __NEMU_DIFFTEST_H__
|
||||
#define __NEMU_DIFFTEST_H__
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
extern bool nemu_do_difftest;
|
||||
|
||||
#endif // __NEMU_DIFFTEST_H__
|
18
nemu/include/ftrace.h
Normal file
18
nemu/include/ftrace.h
Normal file
|
@ -0,0 +1,18 @@
|
|||
#ifndef __FUNC_DEF_H__
|
||||
#define __FUNC_DEF_H__
|
||||
#include <common.h>
|
||||
|
||||
#ifdef CONFIG_FTRACE
|
||||
typedef struct {
|
||||
vaddr_t start;
|
||||
vaddr_t len;
|
||||
char * name;
|
||||
} func_t;
|
||||
|
||||
extern func_t *func_table;
|
||||
void ftrace_call(vaddr_t, vaddr_t);
|
||||
void ftrace_return(vaddr_t, vaddr_t);
|
||||
// const char *get_func_name(vaddr_t addr);
|
||||
#endif
|
||||
|
||||
#endif
|
|
@ -17,6 +17,7 @@
|
|||
#define __ISA_H__
|
||||
|
||||
// Located at src/isa/$(GUEST_ISA)/include/isa-def.h
|
||||
#include <gdbstub.h>
|
||||
#include <isa-def.h>
|
||||
|
||||
// The macro `__GUEST_ISA__` is defined in $(CFLAGS).
|
||||
|
@ -30,8 +31,11 @@ void init_isa();
|
|||
|
||||
// reg
|
||||
extern CPU_state cpu;
|
||||
extern arch_info_t isa_arch_info;
|
||||
void isa_reg_display();
|
||||
word_t isa_reg_str2val(const char *name, bool *success);
|
||||
int isa_read_reg(void *args, int regno, size_t *reg_value);
|
||||
int isa_write_reg(void *args, int regno, size_t data);
|
||||
|
||||
// exec
|
||||
struct Decode;
|
||||
|
|
|
@ -29,7 +29,7 @@
|
|||
#define ARRLEN(arr) (int)(sizeof(arr) / sizeof(arr[0]))
|
||||
|
||||
// macro concatenation
|
||||
#define concat_temp(x, y) x ## y
|
||||
#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)
|
||||
|
@ -39,17 +39,18 @@
|
|||
// 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 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_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 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)
|
||||
#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)
|
||||
|
@ -84,27 +85,46 @@
|
|||
#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 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 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)))
|
||||
|
||||
#define FAILED_GOTO(tag, exp) \
|
||||
do { \
|
||||
if ((exp)) \
|
||||
goto tag; \
|
||||
} while (0)
|
||||
|
||||
#if !defined(likely)
|
||||
#define likely(cond) __builtin_expect(cond, 1)
|
||||
#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 __EXPORT __attribute__((visibility("default")))
|
||||
|
||||
#define io_write(reg, ...) \
|
||||
({ reg##_T __io_param = (reg##_T) { __VA_ARGS__ }; \
|
||||
ioe_write(reg, &__io_param); })
|
||||
// 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
|
||||
|
|
28
nemu/include/nemu.h
Normal file
28
nemu/include/nemu.h
Normal file
|
@ -0,0 +1,28 @@
|
|||
#ifndef __NEMU_HEADER__
|
||||
#define __NEMU_HEADER__
|
||||
|
||||
#include <stddef.h>
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
#include <gdbstub.h>
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
int nemu_read_mem(void *args, size_t addr, size_t len, void *val);
|
||||
int nemu_write_mem(void *args, size_t addr, size_t len, void *val);
|
||||
void nemu_cont(void *args, gdb_action_t *res);
|
||||
void nemu_stepi(void *args, gdb_action_t *res);
|
||||
bool nemu_set_bp(void *args, size_t addr, bp_type_t type);
|
||||
bool nemu_del_bp(void *args, size_t addr, bp_type_t type);
|
||||
void nemu_on_interrupt(void *args);
|
||||
int nemu_read_reg(void *args, int regno, size_t *data);
|
||||
int nemu_write_reg(void *args, int regno, size_t data);
|
||||
void nemu_init(void *args);
|
||||
|
||||
extern arch_info_t nemu_isa_arch_info;
|
||||
extern bool nemu_do_difftest;
|
||||
extern bool nemu_dbg_state_size;
|
||||
|
||||
#endif // __NEMU_HEADER__
|
21
nemu/include/types.h
Normal file
21
nemu/include/types.h
Normal file
|
@ -0,0 +1,21 @@
|
|||
#ifndef __TYPES_H__
|
||||
#define __TYPES_H__
|
||||
#include <inttypes.h>
|
||||
#include <macro.h>
|
||||
#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;
|
||||
static const word_t WORD_T_MAX = MUXDEF(CONFIG_ISA64, UINT64_MAX, UINT32_MAX);
|
||||
static const sword_t SWORD_T_MAX = MUXDEF(CONFIG_ISA64, INT64_MAX, INT32_MAX);
|
||||
static const sword_t SWORD_T_MIN = MUXDEF(CONFIG_ISA64, INT64_MIN, INT32_MIN);
|
||||
#define WORD_BYTES MUXDEF(CONFIG_ISA64, 8, 4)
|
||||
#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;
|
||||
#endif
|
|
@ -16,11 +16,18 @@
|
|||
#ifndef __UTILS_H__
|
||||
#define __UTILS_H__
|
||||
|
||||
#include <common.h>
|
||||
#include <types.h>
|
||||
|
||||
// ----------- state -----------
|
||||
|
||||
enum { NEMU_RUNNING, NEMU_STOP, NEMU_END, NEMU_ABORT, NEMU_QUIT };
|
||||
enum {
|
||||
NEMU_RUNNING,
|
||||
NEMU_GDB_INTERRUPT,
|
||||
NEMU_STOP,
|
||||
NEMU_END,
|
||||
NEMU_ABORT,
|
||||
NEMU_QUIT
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
int state;
|
||||
|
@ -36,42 +43,41 @@ uint64_t get_time();
|
|||
|
||||
// ----------- log -----------
|
||||
|
||||
#define ANSI_FG_BLACK "\33[1;30m"
|
||||
#define ANSI_FG_RED "\33[1;31m"
|
||||
#define ANSI_FG_GREEN "\33[1;32m"
|
||||
#define ANSI_FG_YELLOW "\33[1;33m"
|
||||
#define ANSI_FG_BLUE "\33[1;34m"
|
||||
#define ANSI_FG_BLACK "\33[1;30m"
|
||||
#define ANSI_FG_RED "\33[1;31m"
|
||||
#define ANSI_FG_GREEN "\33[1;32m"
|
||||
#define ANSI_FG_YELLOW "\33[1;33m"
|
||||
#define ANSI_FG_BLUE "\33[1;34m"
|
||||
#define ANSI_FG_MAGENTA "\33[1;35m"
|
||||
#define ANSI_FG_CYAN "\33[1;36m"
|
||||
#define ANSI_FG_WHITE "\33[1;37m"
|
||||
#define ANSI_BG_BLACK "\33[1;40m"
|
||||
#define ANSI_BG_RED "\33[1;41m"
|
||||
#define ANSI_BG_GREEN "\33[1;42m"
|
||||
#define ANSI_BG_YELLOW "\33[1;43m"
|
||||
#define ANSI_BG_BLUE "\33[1;44m"
|
||||
#define ANSI_FG_CYAN "\33[1;36m"
|
||||
#define ANSI_FG_WHITE "\33[1;37m"
|
||||
#define ANSI_BG_BLACK "\33[1;40m"
|
||||
#define ANSI_BG_RED "\33[1;41m"
|
||||
#define ANSI_BG_GREEN "\33[1;42m"
|
||||
#define ANSI_BG_YELLOW "\33[1;43m"
|
||||
#define ANSI_BG_BLUE "\33[1;44m"
|
||||
#define ANSI_BG_MAGENTA "\33[1;35m"
|
||||
#define ANSI_BG_CYAN "\33[1;46m"
|
||||
#define ANSI_BG_WHITE "\33[1;47m"
|
||||
#define ANSI_NONE "\33[0m"
|
||||
#define ANSI_BG_CYAN "\33[1;46m"
|
||||
#define ANSI_BG_WHITE "\33[1;47m"
|
||||
#define ANSI_NONE "\33[0m"
|
||||
|
||||
#define ANSI_FMT(str, fmt) fmt str ANSI_NONE
|
||||
|
||||
#define log_write(...) IFDEF(CONFIG_TARGET_NATIVE_ELF, \
|
||||
do { \
|
||||
extern FILE* log_fp; \
|
||||
extern bool log_enable(); \
|
||||
if (log_enable()) { \
|
||||
fprintf(log_fp, __VA_ARGS__); \
|
||||
fflush(log_fp); \
|
||||
} \
|
||||
} while (0) \
|
||||
)
|
||||
#define log_write(...) \
|
||||
IFDEF( \
|
||||
CONFIG_TARGET_NATIVE_ELF, do { \
|
||||
extern FILE *log_fp; \
|
||||
extern bool log_enable(); \
|
||||
if (log_enable()) { \
|
||||
fprintf(log_fp, __VA_ARGS__); \
|
||||
fflush(log_fp); \
|
||||
} \
|
||||
} while (0))
|
||||
|
||||
#define _Log(...) \
|
||||
do { \
|
||||
printf(__VA_ARGS__); \
|
||||
log_write(__VA_ARGS__); \
|
||||
#define _Log(...) \
|
||||
do { \
|
||||
printf(__VA_ARGS__); \
|
||||
log_write(__VA_ARGS__); \
|
||||
} while (0)
|
||||
|
||||
|
||||
#endif
|
||||
|
|
|
@ -10,7 +10,7 @@ endif
|
|||
WORK_DIR = $(shell pwd)
|
||||
BUILD_DIR = $(WORK_DIR)/build
|
||||
|
||||
INC_PATH := $(WORK_DIR)/include $(INC_PATH)
|
||||
INC_PATH := $(WORK_DIR)/include $(BUILD_DIR)/include $(INC_PATH)
|
||||
OBJ_DIR = $(BUILD_DIR)/obj-$(NAME)$(SO)
|
||||
BINARY = $(BUILD_DIR)/$(NAME)$(SO)
|
||||
|
||||
|
@ -22,7 +22,7 @@ CXX := g++
|
|||
endif
|
||||
LD := $(CXX)
|
||||
INCLUDES = $(addprefix -I, $(INC_PATH))
|
||||
CFLAGS := -O2 -MMD -Wall -Werror $(INCLUDES) $(CFLAGS)
|
||||
CFLAGS := -O2 -MMD -Wall $(INCLUDES) $(CFLAGS)
|
||||
LDFLAGS := -O2 $(LDFLAGS)
|
||||
|
||||
OBJS = $(SRCS:%.c=$(OBJ_DIR)/%.o) $(CXXSRC:%.cc=$(OBJ_DIR)/%.o)
|
||||
|
@ -40,12 +40,34 @@ $(OBJ_DIR)/%.o: %.cc
|
|||
@$(CXX) $(CFLAGS) $(CXXFLAGS) -c -o $@ $<
|
||||
$(call call_fixdep, $(@:.o=.d), $@)
|
||||
|
||||
$(OBJ_DIR)/%.tag.c: %.y
|
||||
@echo + YACC $<
|
||||
@mkdir -p $(dir $@) $(BUILD_DIR)/include
|
||||
@$(YACC) $(YFLAGS) --header=$(BUILD_DIR)/include/$(notdir $(<:.y=.h)) -o $@ $<
|
||||
|
||||
$(OBJ_DIR)/%.yy.c: %.l $(OBJ_DIR)/%.tag.c
|
||||
@echo + LEX $<
|
||||
@mkdir -p $(dir $@) $(BUILD_DIR)/include
|
||||
@$(LEX) $(LFLAGS) --header=$(BUILD_DIR)/include/$(notdir $(<:.l=_lex.h)) -o $@ $<
|
||||
|
||||
$(OBJ_DIR)/%.tag.o: $(OBJ_DIR)/%.tag.c
|
||||
@echo + CC $<
|
||||
@mkdir -p $(dir $@)
|
||||
@$(CC) $(CFLAGS) -c -o $@ $<
|
||||
$(call call_fixdep, $(@:.o=.d), $@)
|
||||
|
||||
$(OBJ_DIR)/%.yy.o: $(OBJ_DIR)/%.yy.c
|
||||
@echo + CC $<
|
||||
@mkdir -p $(dir $@)
|
||||
@$(CC) $(CFLAGS) -c -o $@ $<
|
||||
$(call call_fixdep, $(@:.o=.d), $@)
|
||||
|
||||
# Depencies
|
||||
-include $(OBJS:.o=.d)
|
||||
|
||||
# Some convenient rules
|
||||
|
||||
.PHONY: app clean
|
||||
.PHONY: app install clean
|
||||
|
||||
app: $(BINARY)
|
||||
|
||||
|
@ -53,5 +75,14 @@ $(BINARY):: $(OBJS) $(ARCHIVES)
|
|||
@echo + LD $@
|
||||
@$(LD) -o $@ $(OBJS) $(LDFLAGS) $(ARCHIVES) $(LIBS)
|
||||
|
||||
install: $(BINARY)
|
||||
ifeq ($(SHARE),1)
|
||||
@mkdir -p $(PREFIX)/lib
|
||||
@cp $(BINARY) $(PREFIX)/lib/
|
||||
else
|
||||
@mkdir -p $(PREFIX)/bin
|
||||
@cp $(BINARY) $(PREFIX)/bin/
|
||||
endif
|
||||
|
||||
clean:
|
||||
-rm -rf $(BUILD_DIR)
|
||||
|
|
|
@ -48,6 +48,9 @@ menuconfig: $(MCONF) $(CONF) $(FIXDEP)
|
|||
savedefconfig: $(CONF)
|
||||
$(Q)$< $(silent) --$@=configs/defconfig $(Kconfig)
|
||||
|
||||
alldefconfig: $(CONF) $(FIXDEP)
|
||||
$(Q)$(CONF) $(silent) --$@ $(Kconfig)
|
||||
|
||||
%defconfig: $(CONF) $(FIXDEP)
|
||||
$(Q)$< $(silent) --defconfig=configs/$@ $(Kconfig)
|
||||
$(Q)$< $(silent) --syncconfig $(Kconfig)
|
||||
|
@ -60,7 +63,7 @@ help:
|
|||
@echo ' savedefconfig - Save current config as configs/defconfig (minimal config)'
|
||||
|
||||
distclean: clean
|
||||
-@rm -rf $(rm-distclean)
|
||||
-rm -rf $(rm-distclean)
|
||||
|
||||
.PHONY: help distclean
|
||||
|
||||
|
|
|
@ -13,10 +13,11 @@
|
|||
* See the Mulan PSL v2 for more details.
|
||||
***************************************************************************************/
|
||||
|
||||
#include "gdbstub.h"
|
||||
#include <cpu/cpu.h>
|
||||
#include <cpu/decode.h>
|
||||
#include <cpu/difftest.h>
|
||||
#include <locale.h>
|
||||
#include <utils.h>
|
||||
|
||||
/* The assembly code of instructions executed is only output to the screen
|
||||
* when the number of instructions executed is less than this value.
|
||||
|
@ -29,14 +30,20 @@ CPU_state cpu = {};
|
|||
uint64_t g_nr_guest_inst = 0;
|
||||
static uint64_t g_timer = 0; // unit: us
|
||||
static bool g_print_step = false;
|
||||
IFDEF(CONFIG_ITRACE, extern char logbuf[CONFIG_ITRACE_BUFFER][128]);
|
||||
IFDEF(CONFIG_ITRACE, extern int logbuf_rear);
|
||||
|
||||
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); }
|
||||
if (ITRACE_COND) {
|
||||
log_write("%s\n", logbuf[logbuf_rear]);
|
||||
}
|
||||
#endif
|
||||
if (g_print_step) { IFDEF(CONFIG_ITRACE, puts(_this->logbuf)); }
|
||||
if (g_print_step) {
|
||||
IFDEF(CONFIG_ITRACE, puts(logbuf[logbuf_rear]));
|
||||
}
|
||||
IFDEF(CONFIG_DIFFTEST, difftest_step(_this->pc, dnpc));
|
||||
}
|
||||
|
||||
|
@ -46,25 +53,28 @@ static void exec_once(Decode *s, vaddr_t 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);
|
||||
logbuf_rear = (logbuf_rear + 1) % CONFIG_ITRACE_BUFFER;
|
||||
char *p = logbuf[logbuf_rear];
|
||||
p += snprintf(p, sizeof(logbuf[logbuf_rear]), 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 --) {
|
||||
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;
|
||||
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);
|
||||
disassemble(p, logbuf[logbuf_rear] + sizeof(logbuf[logbuf_rear]) - 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
|
||||
|
@ -73,11 +83,12 @@ static void exec_once(Decode *s, vaddr_t pc) {
|
|||
|
||||
static void execute(uint64_t n) {
|
||||
Decode s;
|
||||
for (;n > 0; n --) {
|
||||
for (; n > 0; n--) {
|
||||
exec_once(&s, cpu.pc);
|
||||
g_nr_guest_inst ++;
|
||||
g_nr_guest_inst++;
|
||||
trace_and_difftest(&s, cpu.pc);
|
||||
if (nemu_state.state != NEMU_RUNNING) break;
|
||||
if (nemu_state.state != NEMU_RUNNING)
|
||||
break;
|
||||
IFDEF(CONFIG_DEVICE, device_update());
|
||||
}
|
||||
}
|
||||
|
@ -87,8 +98,12 @@ static void statistic() {
|
|||
#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");
|
||||
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() {
|
||||
|
@ -100,10 +115,13 @@ void assert_fail_msg() {
|
|||
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;
|
||||
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();
|
||||
|
@ -114,15 +132,53 @@ void cpu_exec(uint64_t n) {
|
|||
g_timer += timer_end - timer_start;
|
||||
|
||||
switch (nemu_state.state) {
|
||||
case NEMU_RUNNING: nemu_state.state = NEMU_STOP; break;
|
||||
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();
|
||||
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);
|
||||
if (nemu_state.halt_ret != 0) {
|
||||
IFDEF(CONFIG_ITRACE, log_itrace_print());
|
||||
}
|
||||
} // fall through
|
||||
case NEMU_QUIT:
|
||||
statistic();
|
||||
}
|
||||
}
|
||||
|
||||
breakpoint_t *cpu_exec_with_bp(uint64_t n, breakpoint_t *bp, size_t len) {
|
||||
static Decode s;
|
||||
nemu_state.state = NEMU_RUNNING;
|
||||
do {
|
||||
for (int i = 0; i < len; i++) {
|
||||
size_t addr = bp[i].addr;
|
||||
bp_type_t bptype = bp[i].type;
|
||||
if (bptype == BP_SOFTWARE && cpu.pc == addr) {
|
||||
return bp + i;
|
||||
}
|
||||
bool is_write = (bptype == BP_WRITE) || (bptype == BP_ACCESS);
|
||||
bool is_read = (bptype == BP_READ) || (bptype == BP_ACCESS);
|
||||
if (s.inst_type == INST_MEM_READ && s.inst_value.rmem == addr &&
|
||||
is_write) {
|
||||
return bp + i;
|
||||
} else if (s.inst_type == INST_MEM_WRITE && s.inst_value.wmem == addr &&
|
||||
is_read) {
|
||||
return bp + i;
|
||||
}
|
||||
}
|
||||
exec_once(&s, cpu.pc);
|
||||
g_nr_guest_inst++;
|
||||
IFDEF(CONFIG_DEVICE, device_update());
|
||||
if (nemu_state.state != NEMU_RUNNING)
|
||||
return NULL;
|
||||
} while (--n);
|
||||
return NULL;
|
||||
}
|
||||
|
|
|
@ -1,132 +0,0 @@
|
|||
/***************************************************************************************
|
||||
* 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
|
|
@ -1,42 +0,0 @@
|
|||
/***************************************************************************************
|
||||
* 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();
|
||||
}
|
|
@ -1,5 +1,4 @@
|
|||
menuconfig DEVICE
|
||||
depends on !TARGET_SHARE
|
||||
bool "Devices"
|
||||
default n
|
||||
help
|
||||
|
|
|
@ -13,17 +13,17 @@
|
|||
* See the Mulan PSL v2 for more details.
|
||||
***************************************************************************************/
|
||||
|
||||
#include <device/map.h>
|
||||
#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 *new_space(int size) {
|
||||
uint8_t *p = p_space;
|
||||
// page aligned;
|
||||
size = (size + (PAGE_SIZE - 1)) & ~PAGE_MASK;
|
||||
|
@ -33,17 +33,25 @@ uint8_t* new_space(int size) {
|
|||
}
|
||||
|
||||
static void check_bound(IOMap *map, paddr_t addr) {
|
||||
#ifndef CONFIG_TARGET_SHARE
|
||||
if (map == NULL) {
|
||||
Assert(map != NULL, "address (" FMT_PADDR ") is out of bound at pc = " FMT_WORD, addr, cpu.pc);
|
||||
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);
|
||||
"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);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
static void invoke_callback(io_callback_t c, paddr_t offset, int len, bool is_write) {
|
||||
if (c != NULL) { c(offset, len, is_write); }
|
||||
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() {
|
||||
|
|
|
@ -13,6 +13,8 @@
|
|||
* See the Mulan PSL v2 for more details.
|
||||
***************************************************************************************/
|
||||
|
||||
#include <assert.h>
|
||||
#include <debug.h>
|
||||
#include <device/map.h>
|
||||
|
||||
#define PORT_IO_SPACE_MAX 65535
|
||||
|
@ -22,15 +24,19 @@ 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) {
|
||||
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 };
|
||||
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 ++;
|
||||
nr_map++;
|
||||
}
|
||||
|
||||
/* CPU interface */
|
||||
|
|
|
@ -13,7 +13,10 @@
|
|||
* See the Mulan PSL v2 for more details.
|
||||
***************************************************************************************/
|
||||
|
||||
#include <assert.h>
|
||||
#include <debug.h>
|
||||
#include <device/map.h>
|
||||
#include <generated/autoconf.h>
|
||||
#include <utils.h>
|
||||
|
||||
#define KEYDOWN_MASK 0x8000
|
||||
|
@ -22,28 +25,27 @@
|
|||
#include <SDL2/SDL.h>
|
||||
|
||||
// Note that this is not the standard
|
||||
#define NEMU_KEYS(f) \
|
||||
f(ESCAPE) f(F1) f(F2) f(F3) f(F4) f(F5) f(F6) f(F7) f(F8) f(F9) f(F10) f(F11) f(F12) \
|
||||
f(GRAVE) f(1) f(2) f(3) f(4) f(5) f(6) f(7) f(8) f(9) f(0) f(MINUS) f(EQUALS) f(BACKSPACE) \
|
||||
f(TAB) f(Q) f(W) f(E) f(R) f(T) f(Y) f(U) f(I) f(O) f(P) f(LEFTBRACKET) f(RIGHTBRACKET) f(BACKSLASH) \
|
||||
f(CAPSLOCK) f(A) f(S) f(D) f(F) f(G) f(H) f(J) f(K) f(L) f(SEMICOLON) f(APOSTROPHE) f(RETURN) \
|
||||
f(LSHIFT) f(Z) f(X) f(C) f(V) f(B) f(N) f(M) f(COMMA) f(PERIOD) f(SLASH) f(RSHIFT) \
|
||||
f(LCTRL) f(APPLICATION) f(LALT) f(SPACE) f(RALT) f(RCTRL) \
|
||||
f(UP) f(DOWN) f(LEFT) f(RIGHT) f(INSERT) f(DELETE) f(HOME) f(END) f(PAGEUP) f(PAGEDOWN)
|
||||
#define NEMU_KEYS(f) \
|
||||
f(ESCAPE) f(F1) f(F2) f(F3) f(F4) f(F5) f(F6) f(F7) f(F8) f(F9) f(F10) \
|
||||
f(F11) f(F12) f(GRAVE) f(1) f(2) f(3) f(4) f(5) f(6) f(7) f(8) f(9) f(0) \
|
||||
f(MINUS) f(EQUALS) f(BACKSPACE) f(TAB) f(Q) f(W) f(E) f(R) f(T) f(Y) \
|
||||
f(U) f(I) f(O) f(P) f(LEFTBRACKET) f(RIGHTBRACKET) f(BACKSLASH) \
|
||||
f(CAPSLOCK) f(A) f(S) f(D) f(F) f(G) f(H) f(J) f(K) f(L) \
|
||||
f(SEMICOLON) f(APOSTROPHE) f(RETURN) f(LSHIFT) f(Z) f(X) \
|
||||
f(C) f(V) f(B) f(N) f(M) f(COMMA) f(PERIOD) f(SLASH) \
|
||||
f(RSHIFT) f(LCTRL) f(APPLICATION) f(LALT) \
|
||||
f(SPACE) f(RALT) f(RCTRL) f(UP) f(DOWN) \
|
||||
f(LEFT) f(RIGHT) f(INSERT) f(DELETE) \
|
||||
f(HOME) f(END) f(PAGEUP) f(PAGEDOWN)
|
||||
|
||||
#define NEMU_KEY_NAME(k) NEMU_KEY_ ## k,
|
||||
#define NEMU_KEY_NAME(k) NEMU_KEY_##k,
|
||||
|
||||
enum {
|
||||
NEMU_KEY_NONE = 0,
|
||||
MAP(NEMU_KEYS, NEMU_KEY_NAME)
|
||||
};
|
||||
enum { NEMU_KEY_NONE = 0, MAP(NEMU_KEYS, NEMU_KEY_NAME) };
|
||||
|
||||
#define SDL_KEYMAP(k) keymap[SDL_SCANCODE_ ## k] = NEMU_KEY_ ## k;
|
||||
#define SDL_KEYMAP(k) keymap[SDL_SCANCODE_##k] = NEMU_KEY_##k;
|
||||
static uint32_t keymap[256] = {};
|
||||
|
||||
static void init_keymap() {
|
||||
MAP(NEMU_KEYS, SDL_KEYMAP)
|
||||
}
|
||||
static void init_keymap() { MAP(NEMU_KEYS, SDL_KEYMAP) }
|
||||
|
||||
#define KEY_QUEUE_LEN 1024
|
||||
static int key_queue[KEY_QUEUE_LEN] = {};
|
||||
|
@ -92,9 +94,11 @@ void init_i8042() {
|
|||
i8042_data_port_base = (uint32_t *)new_space(4);
|
||||
i8042_data_port_base[0] = NEMU_KEY_NONE;
|
||||
#ifdef CONFIG_HAS_PORT_IO
|
||||
add_pio_map ("keyboard", CONFIG_I8042_DATA_PORT, i8042_data_port_base, 4, i8042_data_io_handler);
|
||||
add_pio_map("keyboard", CONFIG_I8042_DATA_PORT, i8042_data_port_base, 4,
|
||||
i8042_data_io_handler);
|
||||
#else
|
||||
add_mmio_map("keyboard", CONFIG_I8042_DATA_MMIO, i8042_data_port_base, 4, i8042_data_io_handler);
|
||||
add_mmio_map("keyboard", CONFIG_I8042_DATA_MMIO, i8042_data_port_base, 4,
|
||||
i8042_data_io_handler);
|
||||
#endif
|
||||
IFNDEF(CONFIG_TARGET_AM, init_keymap());
|
||||
}
|
||||
|
|
|
@ -13,8 +13,11 @@
|
|||
* See the Mulan PSL v2 for more details.
|
||||
***************************************************************************************/
|
||||
|
||||
#include <utils.h>
|
||||
#include <assert.h>
|
||||
#include <debug.h>
|
||||
#include <device/map.h>
|
||||
#include <generated/autoconf.h>
|
||||
#include <utils.h>
|
||||
|
||||
/* http://en.wikibooks.org/wiki/Serial_Programming/8250_UART_Programming */
|
||||
// NOTE: this is compatible to 16550
|
||||
|
@ -23,7 +26,6 @@
|
|||
|
||||
static uint8_t *serial_base = NULL;
|
||||
|
||||
|
||||
static void serial_putc(char ch) {
|
||||
MUXDEF(CONFIG_TARGET_AM, putch(ch), putc(ch, stderr));
|
||||
}
|
||||
|
@ -31,21 +33,23 @@ static void serial_putc(char ch) {
|
|||
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);
|
||||
/* 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);
|
||||
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
|
||||
|
||||
}
|
||||
|
|
|
@ -13,8 +13,10 @@
|
|||
* See the Mulan PSL v2 for more details.
|
||||
***************************************************************************************/
|
||||
|
||||
#include <device/map.h>
|
||||
#include <assert.h>
|
||||
#include <device/alarm.h>
|
||||
#include <device/map.h>
|
||||
#include <generated/autoconf.h>
|
||||
#include <utils.h>
|
||||
|
||||
static uint32_t *rtc_port_base = NULL;
|
||||
|
@ -40,7 +42,7 @@ static void timer_intr() {
|
|||
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);
|
||||
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
|
||||
|
|
|
@ -13,20 +13,19 @@
|
|||
* See the Mulan PSL v2 for more details.
|
||||
***************************************************************************************/
|
||||
|
||||
#include <utils.h>
|
||||
#include <cpu/ifetch.h>
|
||||
#include <difftest.h>
|
||||
#include <isa.h>
|
||||
#include <cpu/difftest.h>
|
||||
#include <utils.h>
|
||||
|
||||
void set_nemu_state(int state, vaddr_t pc, int halt_ret) {
|
||||
difftest_skip_ref();
|
||||
nemu_do_difftest = false;
|
||||
nemu_state.state = state;
|
||||
nemu_state.halt_pc = pc;
|
||||
nemu_state.halt_ret = halt_ret;
|
||||
}
|
||||
|
||||
__attribute__((noinline))
|
||||
void invalid_inst(vaddr_t thispc) {
|
||||
__attribute__((noinline)) void invalid_inst(vaddr_t thispc) {
|
||||
uint32_t temp[2];
|
||||
vaddr_t pc = thispc;
|
||||
temp[0] = inst_fetch(&pc, 4);
|
||||
|
@ -34,18 +33,24 @@ void invalid_inst(vaddr_t thispc) {
|
|||
|
||||
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]);
|
||||
"\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);
|
||||
"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);
|
||||
"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);
|
||||
}
|
||||
|
|
|
@ -13,15 +13,26 @@
|
|||
* See the Mulan PSL v2 for more details.
|
||||
***************************************************************************************/
|
||||
|
||||
#include "debug.h"
|
||||
#include <cpu/cpu.h>
|
||||
#include <gdbstub.h>
|
||||
|
||||
void sdb_mainloop();
|
||||
int gdbstub_loop();
|
||||
extern bool enable_gdbstub;
|
||||
|
||||
void engine_start() {
|
||||
#ifdef CONFIG_TARGET_AM
|
||||
cpu_exec(-1);
|
||||
#else
|
||||
/* Receive commands from user. */
|
||||
sdb_mainloop();
|
||||
int ret = 0;
|
||||
if (enable_gdbstub) {
|
||||
if ((ret = gdbstub_loop())) {
|
||||
Error("gdbstub exited abnormally");
|
||||
exit(ret);
|
||||
}
|
||||
} else {
|
||||
cpu_exec(-1);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
|
|
@ -14,12 +14,12 @@
|
|||
#**************************************************************************************/
|
||||
|
||||
SRCS-y += src/nemu-main.c
|
||||
DIRS-y += src/cpu src/monitor src/utils
|
||||
DIRS-y += src/cpu 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,)
|
||||
LIBS += $(if $(CONFIG_TARGET_NATIVE_ELF),-lgdbstub -lreadline -ldl -pie,)
|
||||
|
||||
ifdef mainargs
|
||||
ASFLAGS += -DBIN_PATH=\"$(mainargs)\"
|
||||
|
|
|
@ -28,51 +28,50 @@
|
|||
*/
|
||||
|
||||
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'
|
||||
};
|
||||
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'};
|
||||
|
|
18
nemu/src/isa/riscv32/csr.c
Normal file
18
nemu/src/isa/riscv32/csr.c
Normal file
|
@ -0,0 +1,18 @@
|
|||
#include <csr.h>
|
||||
|
||||
void init_csr(csr_t csr) { memset(csr, 0, sizeof(word_t)); }
|
||||
|
||||
void write_csr(csr_t csr, csr_addr_t csrnum, word_t value) {
|
||||
switch (csrnum) {
|
||||
default:
|
||||
csr[csrnum] = value;
|
||||
}
|
||||
}
|
||||
|
||||
word_t read_csr(csr_t csr, csr_addr_t csrnum) {
|
||||
switch (csrnum) {
|
||||
// TODO: Implement csr read checks
|
||||
default:
|
||||
return csr[csrnum];
|
||||
}
|
||||
}
|
|
@ -1,25 +0,0 @@
|
|||
/***************************************************************************************
|
||||
* 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() {
|
||||
}
|
|
@ -18,8 +18,13 @@
|
|||
|
||||
#include <common.h>
|
||||
|
||||
#define CSR_SIZE (0x1000)
|
||||
|
||||
typedef word_t csr_t[CSR_SIZE];
|
||||
|
||||
typedef struct {
|
||||
word_t gpr[MUXDEF(CONFIG_RVE, 16, 32)];
|
||||
csr_t csr;
|
||||
vaddr_t pc;
|
||||
} MUXDEF(CONFIG_RV64, riscv64_CPU_state, riscv32_CPU_state);
|
||||
|
||||
|
|
|
@ -1,68 +1,294 @@
|
|||
/***************************************************************************************
|
||||
* 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.
|
||||
***************************************************************************************/
|
||||
* 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"
|
||||
#include "macro.h"
|
||||
#include "types.h"
|
||||
#include <common.h>
|
||||
#include <cpu/cpu.h>
|
||||
#include <cpu/ifetch.h>
|
||||
#include <cpu/decode.h>
|
||||
#include <cpu/ifetch.h>
|
||||
#include <csr.h>
|
||||
#include <ftrace.h>
|
||||
#include <utils.h>
|
||||
|
||||
#define R(i) gpr(i)
|
||||
#define Mr vaddr_read
|
||||
#define Mw vaddr_write
|
||||
|
||||
enum {
|
||||
TYPE_I, TYPE_U, TYPE_S,
|
||||
TYPE_R,
|
||||
TYPE_I,
|
||||
TYPE_I_SHIFT,
|
||||
TYPE_U,
|
||||
TYPE_S,
|
||||
TYPE_B,
|
||||
TYPE_J,
|
||||
TYPE_CSR,
|
||||
TYPE_CSRI,
|
||||
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)
|
||||
#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)
|
||||
#define immB() \
|
||||
do { \
|
||||
*imm = SEXT(BITS(i, 31, 31), 1) << 12 | BITS(i, 30, 25) << 5 | \
|
||||
BITS(i, 11, 8) << 1 | BITS(i, 7, 7) << 11; \
|
||||
} while (0)
|
||||
#define immJ() \
|
||||
do { \
|
||||
*imm = SEXT(BITS(i, 31, 31), 1) << 20 | BITS(i, 30, 21) << 1 | \
|
||||
BITS(i, 20, 20) << 11 | BITS(i, 19, 12) << 12; \
|
||||
} while (0)
|
||||
#define csr() \
|
||||
do { \
|
||||
*src2 = BITS(i, 31, 20); \
|
||||
} while (0)
|
||||
#define uimm() \
|
||||
do { \
|
||||
*imm = BITS(i, 19, 15); \
|
||||
} while (0)
|
||||
|
||||
static void decode_operand(Decode *s, int *rd, word_t *src1, word_t *src2, word_t *imm, int type) {
|
||||
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);
|
||||
*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;
|
||||
// clang-format off
|
||||
case TYPE_R: src1R(); src2R(); break;
|
||||
case TYPE_I: src1R(); immI(); break;
|
||||
case TYPE_U: immU(); break;
|
||||
case TYPE_J: immJ(); break;
|
||||
case TYPE_S: src1R(); src2R(); immS(); break;
|
||||
case TYPE_B: src1R(); src2R(); immB(); break;
|
||||
case TYPE_CSR: src1R(); csr(); break;
|
||||
case TYPE_CSRI: csr(); uimm(); break;
|
||||
// clang-format on
|
||||
}
|
||||
}
|
||||
|
||||
static void do_branch(Decode *s, bool condition, word_t offset) {
|
||||
if (condition) {
|
||||
// puts(s->logbuf[s->logbuf_rear]);
|
||||
s->dnpc = s->pc + offset;
|
||||
}
|
||||
}
|
||||
|
||||
static inline word_t Mr(Decode *s, vaddr_t addr, int len) {
|
||||
s->inst_type = INST_MEM_READ;
|
||||
s->inst_value.rmem = addr & ~0x3;
|
||||
return vaddr_read(addr, len);
|
||||
}
|
||||
|
||||
static inline void Mw(Decode *s, vaddr_t addr, int len, word_t data) {
|
||||
vaddr_write(addr, len, data);
|
||||
s->inst_type = INST_MEM_WRITE;
|
||||
s->inst_value.wmem = addr & ~0x3;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_FTRACE
|
||||
static void ftrace_jalr(Decode *s, int rd, vaddr_t dst) {
|
||||
uint32_t i = s->isa.inst.val;
|
||||
int rs1 = BITS(i, 19, 15);
|
||||
if (rs1 == 1 && rd == 0) {
|
||||
ftrace_return(s->pc, dst);
|
||||
} else {
|
||||
ftrace_call(s->pc, dst);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
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__ ; \
|
||||
}
|
||||
#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("??????? ????? ????? ??? ????? 01101 11", lui, U, R(rd) = imm);
|
||||
INSTPAT("??????? ????? ????? ??? ????? 00101 11", auipc, U,
|
||||
R(rd) = s->pc + imm);
|
||||
|
||||
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(
|
||||
"??????? ????? ????? ??? ????? 11011 11", jal, J, do {
|
||||
s->dnpc = s->pc + imm;
|
||||
R(rd) = s->pc + 4;
|
||||
IFDEF(CONFIG_FTRACE, ftrace_call(s->pc, s->pc + imm));
|
||||
} while (0));
|
||||
INSTPAT(
|
||||
"??????? ????? ????? ??? ????? 11001 11", jalr, I, do {
|
||||
s->dnpc = src1 + imm;
|
||||
R(rd) = s->pc + 4;
|
||||
IFDEF(CONFIG_FTRACE, ftrace_jalr(s, rd, src1 + imm));
|
||||
} while (0));
|
||||
INSTPAT("??????? ????? ????? 000 ????? 11000 11", beq, B,
|
||||
do_branch(s, src1 == src2, imm));
|
||||
INSTPAT("??????? ????? ????? 001 ????? 11000 11", bne, B,
|
||||
do_branch(s, src1 != src2, imm));
|
||||
INSTPAT("??????? ????? ????? 100 ????? 11000 11", blt, B,
|
||||
do_branch(s, (sword_t)src1 < (sword_t)src2, imm));
|
||||
INSTPAT("??????? ????? ????? 101 ????? 11000 11", bge, B,
|
||||
do_branch(s, (sword_t)src1 >= (sword_t)src2, imm));
|
||||
INSTPAT("??????? ????? ????? 110 ????? 11000 11", bltu, B,
|
||||
do_branch(s, src1 < src2, imm));
|
||||
INSTPAT("??????? ????? ????? 111 ????? 11000 11", bgeu, B,
|
||||
do_branch(s, src1 >= src2, imm));
|
||||
|
||||
INSTPAT("??????? ????? ????? 000 ????? 00000 11", lb, I,
|
||||
R(rd) = SEXT(Mr(s, src1 + imm, 1), 8));
|
||||
INSTPAT("??????? ????? ????? 001 ????? 00000 11", lh, I,
|
||||
R(rd) = SEXT(Mr(s, src1 + imm, 2), 16));
|
||||
INSTPAT("??????? ????? ????? 010 ????? 00000 11", lw, I,
|
||||
R(rd) = SEXT(Mr(s, src1 + imm, 4), 32));
|
||||
INSTPAT("??????? ????? ????? 100 ????? 00000 11", lbu, I,
|
||||
R(rd) = Mr(s, src1 + imm, 1));
|
||||
INSTPAT("??????? ????? ????? 101 ????? 00000 11", lhu, I,
|
||||
R(rd) = Mr(s, src1 + imm, 2));
|
||||
INSTPAT("??????? ????? ????? 000 ????? 01000 11", sb, S,
|
||||
Mw(s, src1 + imm, 1, src2));
|
||||
INSTPAT("??????? ????? ????? 001 ????? 01000 11", sh, S,
|
||||
Mw(s, src1 + imm, 2, src2));
|
||||
INSTPAT("??????? ????? ????? 010 ????? 01000 11", sw, S,
|
||||
Mw(s, src1 + imm, 4, src2));
|
||||
|
||||
INSTPAT("??????? ????? ????? 000 ????? 00100 11", addi, I,
|
||||
R(rd) = src1 + imm);
|
||||
INSTPAT("??????? ????? ????? 010 ????? 00100 11", slti, I,
|
||||
R(rd) = (sword_t)src1 < (sword_t)imm ? 1 : 0);
|
||||
INSTPAT("??????? ????? ????? 011 ????? 00100 11", sltiu, I,
|
||||
R(rd) = src1 < imm ? 1 : 0);
|
||||
INSTPAT("??????? ????? ????? 100 ????? 00100 11", xori, I,
|
||||
R(rd) = src1 ^ imm);
|
||||
INSTPAT("??????? ????? ????? 110 ????? 00100 11", ori, I, R(rd) = src1 | imm);
|
||||
INSTPAT("??????? ????? ????? 111 ????? 00100 11", andi, I,
|
||||
R(rd) = src1 & imm);
|
||||
INSTPAT("0000000 ????? ????? 001 ????? 00100 11", slli, I,
|
||||
R(rd) = src1 << imm);
|
||||
INSTPAT("0000000 ????? ????? 101 ????? 00100 11", srli, I,
|
||||
R(rd) = src1 >> imm);
|
||||
INSTPAT("0100000 ????? ????? 101 ????? 00100 11", srai, I,
|
||||
R(rd) = (sword_t)src1 >> (imm & 0x01F));
|
||||
INSTPAT("0000000 ????? ????? 000 ????? 01100 11", add, R,
|
||||
R(rd) = src1 + src2);
|
||||
INSTPAT("0100000 ????? ????? 000 ????? 01100 11", sub, R,
|
||||
R(rd) = src1 - src2);
|
||||
INSTPAT("0000000 ????? ????? 001 ????? 01100 11", sll, R,
|
||||
R(rd) = src1 << src2);
|
||||
INSTPAT("0000000 ????? ????? 010 ????? 01100 11", slt, R,
|
||||
R(rd) = (sword_t)src1 < (sword_t)src2 ? 1 : 0);
|
||||
INSTPAT("0000000 ????? ????? 011 ????? 01100 11", sltu, R,
|
||||
R(rd) = src1 < src2 ? 1 : 0);
|
||||
INSTPAT("0000000 ????? ????? 100 ????? 01100 11", xor, R,
|
||||
R(rd) = src1 ^ src2);
|
||||
INSTPAT("0000000 ????? ????? 101 ????? 01100 11", srl, R,
|
||||
R(rd) = src1 >> src2);
|
||||
INSTPAT("0100000 ????? ????? 101 ????? 01100 11", sra, R,
|
||||
R(rd) = (sword_t)src1 >> (src2 & 0x01F));
|
||||
INSTPAT("0000000 ????? ????? 110 ????? 01100 11", or, R, R(rd) = src1 | src2);
|
||||
INSTPAT("0000000 ????? ????? 111 ????? 01100 11", and, R,
|
||||
R(rd) = src1 & src2);
|
||||
|
||||
INSTPAT("0000000 00001 00000 000 00000 11100 11", ebreak, N,
|
||||
NEMUTRAP(s->pc, R(10))); // R(10) is $a0
|
||||
|
||||
// "M"
|
||||
INSTPAT("0000001 ????? ????? 000 ????? 01100 11", mul, R,
|
||||
R(rd) = src1 * src2);
|
||||
INSTPAT("0000001 ????? ????? 001 ????? 01100 11", mulh, R,
|
||||
R(rd) = (int64_t)(sword_t)src1 * (sword_t)src2 >> 32);
|
||||
INSTPAT("0000001 ????? ????? 010 ????? 01100 11", mulhsu, R,
|
||||
R(rd) = (int64_t)(sword_t)src1 * (uint64_t)src2 >> 32);
|
||||
INSTPAT("0000001 ????? ????? 011 ????? 01100 11", mulhu, R,
|
||||
R(rd) = (uint64_t)src1 * (uint64_t)src2 >> 32);
|
||||
INSTPAT("0000001 ????? ????? 100 ????? 01100 11", div, R,
|
||||
R(rd) = (sword_t)src1 / (sword_t)src2);
|
||||
INSTPAT("0000001 ????? ????? 101 ????? 01100 11", divu, R,
|
||||
R(rd) = src1 / src2);
|
||||
INSTPAT("0000001 ????? ????? 110 ????? 01100 11", rem, R,
|
||||
R(rd) = (sword_t)src1 % (sword_t)src2);
|
||||
INSTPAT("0000001 ????? ????? 111 ????? 01100 11", remu, R,
|
||||
R(rd) = src1 % src2);
|
||||
|
||||
// "Previledge"
|
||||
// -- CSR instructions
|
||||
// src2: R(read register)
|
||||
// src1: R(write source)
|
||||
// imm: write data()
|
||||
INSTPAT(
|
||||
"??????? ????? ????? 001 ????? 11100 11", csrrw, CSR, do {
|
||||
R(rd) = read_csr(cpu.csr, src2);
|
||||
write_csr(cpu.csr, src2, src1);
|
||||
} while (0););
|
||||
INSTPAT(
|
||||
"??????? ????? ????? 010 ????? 11100 11", csrrs, CSR, do {
|
||||
R(rd) = read_csr(cpu.csr, src2);
|
||||
set_csr_bits(cpu.csr, src2, src1);
|
||||
} while (0););
|
||||
INSTPAT(
|
||||
"??????? ????? ????? 011 ????? 11100 11", csrrc, CSR, do {
|
||||
R(rd) = read_csr(cpu.csr, src2);
|
||||
clear_csr_bits(cpu.csr, src2, src1);
|
||||
} while (0););
|
||||
INSTPAT(
|
||||
"??????? ????? ????? 101 ????? 11100 11", csrrwi, CSRI, do {
|
||||
R(rd) = read_csr(cpu.csr, src2);
|
||||
write_csr(cpu.csr, src2, imm);
|
||||
} while (0););
|
||||
INSTPAT(
|
||||
"??????? ????? ????? 110 ????? 11100 11", csrrsi, CSRI, do {
|
||||
R(rd) = read_csr(cpu.csr, src2);
|
||||
set_csr_bits(cpu.csr, src2, imm);
|
||||
} while (0););
|
||||
INSTPAT(
|
||||
"??????? ????? ????? 111 ????? 11100 11", csrrci, CSRI, do {
|
||||
R(rd) = read_csr(cpu.csr, src2);
|
||||
clear_csr_bits(cpu.csr, src2, imm);
|
||||
} while (0););
|
||||
// -- Machine level
|
||||
INSTPAT("0000000 00000 00000 000 00000 11100 11", ecall, N,
|
||||
s->dnpc = isa_raise_intr(CauseEnvironmentCallFromMMode, cpu.pc));
|
||||
INSTPAT("0011000 00010 00000 000 00000 11100 11", mret, N,
|
||||
s->dnpc = read_csr(cpu.csr, MEPC));
|
||||
|
||||
INSTPAT("??????? ????? ????? ??? ????? ????? ??", inv, N, INV(s->pc));
|
||||
INSTPAT_END();
|
||||
|
||||
R(0) = 0; // reset $zero to 0
|
||||
|
|
29
nemu/src/isa/riscv32/local-include/csr.h
Normal file
29
nemu/src/isa/riscv32/local-include/csr.h
Normal file
|
@ -0,0 +1,29 @@
|
|||
#ifndef __NEMU_CSR_H__
|
||||
#define __NEMU_CSR_H__
|
||||
#include <isa-def.h>
|
||||
#include <types.h>
|
||||
|
||||
#define MSTATUS 0x300
|
||||
#define MISA 0x301
|
||||
#define MIE 0x304
|
||||
#define MTVEC 0x305
|
||||
#define MEPC 0x341
|
||||
#define MCAUSE 0x342
|
||||
|
||||
enum { CauseEnvironmentCallFromMMode = 11 };
|
||||
|
||||
typedef uint16_t csr_addr_t;
|
||||
|
||||
void init_csr(csr_t csr);
|
||||
|
||||
/* macro for setting and clearing csr bits */
|
||||
#define set_csr_bits(csr, reg, mask) \
|
||||
write_csr(csr, reg, read_csr(csr, reg) | (mask))
|
||||
|
||||
#define clear_csr_bits(csr, reg, mask) \
|
||||
write_csr(csr, reg, read_csr(csr, reg) & ~(mask))
|
||||
|
||||
void write_csr(csr_t csr, csr_addr_t csrnum, word_t value);
|
||||
word_t read_csr(csr_t csr, csr_addr_t csrnum);
|
||||
|
||||
#endif // __NEMU_CSR_H__
|
|
@ -25,39 +25,49 @@
|
|||
|
||||
*/
|
||||
|
||||
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! */
|
||||
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! */
|
||||
};
|
||||
|
|
|
@ -13,19 +13,70 @@
|
|||
* See the Mulan PSL v2 for more details.
|
||||
***************************************************************************************/
|
||||
|
||||
#include <isa.h>
|
||||
#include "local-include/reg.h"
|
||||
#include "csr.h"
|
||||
#include "macro.h"
|
||||
#include <errno.h>
|
||||
#include <gdbstub.h>
|
||||
#include <isa.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"
|
||||
};
|
||||
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() {
|
||||
int colomn_per_row = 4;
|
||||
for (int i = 0; i < ARRLEN(regs); i++) {
|
||||
printf("\e[1;34m%3s\e[0m: " FMT_PADDR, reg_name(i), gpr(i));
|
||||
if (i % colomn_per_row == 3)
|
||||
putchar('\n');
|
||||
else
|
||||
putchar('|');
|
||||
}
|
||||
}
|
||||
|
||||
word_t isa_reg_str2val(const char *s, bool *success) {
|
||||
assert(s);
|
||||
int i;
|
||||
for (i = 0; i < 32 && strcmp(s, regs[i]) != 0; i++)
|
||||
;
|
||||
|
||||
if (i == 32) {
|
||||
*success = false;
|
||||
return 0;
|
||||
}
|
||||
*success = true;
|
||||
|
||||
return gpr(i);
|
||||
}
|
||||
|
||||
int isa_read_reg(void *args, int regno, size_t *reg_value) {
|
||||
if (regno > 32) {
|
||||
return EFAULT;
|
||||
}
|
||||
|
||||
if (regno == 32) {
|
||||
*reg_value = cpu.pc;
|
||||
} else {
|
||||
*reg_value = cpu.gpr[regno];
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int isa_write_reg(void *args, int regno, size_t data) {
|
||||
if (regno > 32) {
|
||||
return EFAULT;
|
||||
}
|
||||
|
||||
if (regno == 32) {
|
||||
cpu.pc = data;
|
||||
} else {
|
||||
cpu.gpr[regno] = data;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
__EXPORT arch_info_t isa_arch_info = {.reg_num = 32,
|
||||
.reg_byte = MUXDEF(CONFIG_RV64, 8, 4),
|
||||
.target_desc = TARGET_RV32};
|
||||
|
|
|
@ -13,16 +13,14 @@
|
|||
* See the Mulan PSL v2 for more details.
|
||||
***************************************************************************************/
|
||||
|
||||
#include <csr.h>
|
||||
#include <isa.h>
|
||||
|
||||
word_t isa_raise_intr(word_t NO, vaddr_t epc) {
|
||||
/* TODO: Trigger an interrupt/exception with ``NO''.
|
||||
* Then return the address of the interrupt/exception vector.
|
||||
*/
|
||||
write_csr(cpu.csr, MEPC, epc);
|
||||
write_csr(cpu.csr, MCAUSE, NO);
|
||||
|
||||
return 0;
|
||||
return read_csr(cpu.csr, MTVEC);
|
||||
}
|
||||
|
||||
word_t isa_query_intr() {
|
||||
return INTR_EMPTY;
|
||||
}
|
||||
word_t isa_query_intr() { return INTR_EMPTY; }
|
||||
|
|
|
@ -13,18 +13,26 @@
|
|||
* See the Mulan PSL v2 for more details.
|
||||
***************************************************************************************/
|
||||
|
||||
#include <memory/host.h>
|
||||
#include <memory/paddr.h>
|
||||
#include "common.h"
|
||||
#include "debug.h"
|
||||
#include "utils.h"
|
||||
#include <device/mmio.h>
|
||||
#include <isa.h>
|
||||
#include <memory/host.h>
|
||||
#include <memory/paddr.h>
|
||||
|
||||
#if defined(CONFIG_PMEM_MALLOC)
|
||||
#if defined(CONFIG_PMEM_MALLOC)
|
||||
static uint8_t *pmem = NULL;
|
||||
#else // CONFIG_PMEM_GARRAY
|
||||
static uint8_t pmem[CONFIG_MSIZE] PG_ALIGN = {};
|
||||
#endif
|
||||
#ifdef CONFIG_MTRACE
|
||||
static word_t mtrace_start[CONFIG_MTRACE_RANGE_MAX] = {0};
|
||||
static word_t mtrace_end[CONFIG_MTRACE_RANGE_MAX] = {0};
|
||||
static int range_count = 0;
|
||||
#endif
|
||||
|
||||
uint8_t* guest_to_host(paddr_t paddr) { return pmem + paddr - CONFIG_MBASE; }
|
||||
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) {
|
||||
|
@ -37,28 +45,79 @@ static void pmem_write(paddr_t addr, int len, word_t 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);
|
||||
#ifdef CONFIG_TARGET_SHARE
|
||||
// Do not panic when used as a library. Give an error in log
|
||||
Error("Out of bound at 0x%x", addr);
|
||||
#else
|
||||
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);
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef CONFIG_MTRACE
|
||||
static void mtrace_print(char type, word_t addr, int len, word_t data) {
|
||||
for (int i = 0; i < range_count; i++)
|
||||
if (addr <= mtrace_end[i] && addr >= mtrace_start[i]) {
|
||||
Trace("PC=" FMT_PADDR " Mem %c" FMT_PADDR " %d D " FMT_PADDR, cpu.pc,
|
||||
type, addr, len, data);
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
void init_mem() {
|
||||
#if defined(CONFIG_PMEM_MALLOC)
|
||||
#if defined(CONFIG_PMEM_MALLOC)
|
||||
pmem = malloc(CONFIG_MSIZE);
|
||||
assert(pmem);
|
||||
#endif
|
||||
#ifdef CONFIG_MTRACE
|
||||
char range[sizeof(CONFIG_MTRACE_RANGE)] = CONFIG_MTRACE_RANGE;
|
||||
char *saveptr, *ptr;
|
||||
ptr = strtok_r(range, ",", &saveptr);
|
||||
for (range_count = 0; range_count < CONFIG_MTRACE_RANGE_MAX;) {
|
||||
word_t start, end;
|
||||
Assert(sscanf(ptr, FMT_PADDR "-" FMT_PADDR, &start, &end) == 2,
|
||||
"Config option MTRACE_RANGE has wrong format");
|
||||
mtrace_start[range_count] = start;
|
||||
mtrace_end[range_count] = end;
|
||||
|
||||
range_count++;
|
||||
ptr = strtok_r(NULL, ",", &saveptr);
|
||||
if (!ptr)
|
||||
break;
|
||||
}
|
||||
Trace("MTRACE ranges: ");
|
||||
for (int i = 0; i < range_count; i++) {
|
||||
Trace("[0x%x, 0x%x]", mtrace_start[i], mtrace_end[i]);
|
||||
}
|
||||
#endif
|
||||
IFDEF(CONFIG_MEM_RANDOM, memset(pmem, rand(), CONFIG_MSIZE));
|
||||
Log("physical memory area [" FMT_PADDR ", " FMT_PADDR "]", PMEM_LEFT, PMEM_RIGHT);
|
||||
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));
|
||||
word_t result = 0;
|
||||
if (likely(in_pmem(addr))) {
|
||||
result = pmem_read(addr, len);
|
||||
goto mtrace;
|
||||
}
|
||||
IFDEF(CONFIG_DEVICE, result = mmio_read(addr, len); goto mtrace;)
|
||||
out_of_bound(addr);
|
||||
return 0;
|
||||
|
||||
mtrace:
|
||||
IFDEF(CONFIG_MTRACE, mtrace_print('R', addr, len, result));
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void paddr_write(paddr_t addr, int len, word_t data) {
|
||||
if (likely(in_pmem(addr))) { pmem_write(addr, len, data); return; }
|
||||
IFDEF(CONFIG_MTRACE, mtrace_print('W', addr, len, 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);
|
||||
}
|
||||
|
|
4
nemu/src/monitor/filelist.mk
Normal file
4
nemu/src/monitor/filelist.mk
Normal file
|
@ -0,0 +1,4 @@
|
|||
DIRS-y += src/monitor
|
||||
|
||||
CXXSRC += src/monitor/gdbstub.cc
|
||||
LIBS += -lgdbstub
|
170
nemu/src/monitor/gdbstub.cc
Normal file
170
nemu/src/monitor/gdbstub.cc
Normal file
|
@ -0,0 +1,170 @@
|
|||
#include "types.h"
|
||||
#include "utils.h"
|
||||
#include <vector>
|
||||
|
||||
extern "C" {
|
||||
#include <cpu/cpu.h>
|
||||
#include <debug.h>
|
||||
#include <errno.h>
|
||||
#include <gdbstub.h>
|
||||
#include <isa.h>
|
||||
#include <memory/paddr.h>
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
typedef struct {
|
||||
std::vector<breakpoint_t> *bp;
|
||||
bool halt;
|
||||
} DbgState;
|
||||
|
||||
__EXPORT size_t nemu_dbg_state_size = sizeof(DbgState);
|
||||
__EXPORT bool nemu_do_difftest = true;
|
||||
__EXPORT arch_info_t nemu_isa_arch_info = isa_arch_info;
|
||||
|
||||
__EXPORT int nemu_read_mem(void *args, size_t addr, size_t len, void *val) {
|
||||
if (!in_pmem(addr))
|
||||
return EINVAL;
|
||||
memcpy(val, guest_to_host(addr), len);
|
||||
return 0;
|
||||
}
|
||||
|
||||
__EXPORT int nemu_write_mem(void *args, size_t addr, size_t len, void *val) {
|
||||
if (!in_pmem(addr))
|
||||
return EINVAL;
|
||||
memcpy(guest_to_host(addr), val, len);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void nemu_is_stopped(gdb_action_t *act, breakpoint_t *stopped_at) {
|
||||
switch (nemu_state.state) {
|
||||
case NEMU_RUNNING:
|
||||
nemu_state.state = NEMU_STOP;
|
||||
if (stopped_at == NULL) {
|
||||
act->reason = gdb_action_t::ACT_NONE;
|
||||
} else {
|
||||
switch (stopped_at->type) {
|
||||
case BP_SOFTWARE:
|
||||
act->reason = gdb_action_t::ACT_BREAKPOINT;
|
||||
break;
|
||||
case BP_ACCESS:
|
||||
act->reason = gdb_action_t::ACT_WATCH;
|
||||
break;
|
||||
case BP_WRITE:
|
||||
act->reason = gdb_action_t::ACT_WWATCH;
|
||||
break;
|
||||
case BP_READ:
|
||||
act->reason = gdb_action_t::ACT_RWATCH;
|
||||
break;
|
||||
}
|
||||
act->data = stopped_at->addr;
|
||||
}
|
||||
break;
|
||||
|
||||
case NEMU_GDB_INTERRUPT:
|
||||
act->reason = gdb_action_t::ACT_BREAKPOINT;
|
||||
act->data = cpu.pc;
|
||||
break;
|
||||
|
||||
default:
|
||||
act->reason = gdb_action_t::ACT_SHUTDOWN;
|
||||
act->data = nemu_state.halt_ret;
|
||||
}
|
||||
}
|
||||
|
||||
__EXPORT void nemu_cont(void *args, gdb_action_t *res) {
|
||||
DbgState *dbg_state = (DbgState *)args;
|
||||
breakpoint_t *stopped_at =
|
||||
cpu_exec_with_bp(-1, dbg_state->bp->data(), dbg_state->bp->size());
|
||||
nemu_is_stopped(res, stopped_at);
|
||||
}
|
||||
|
||||
__EXPORT void nemu_stepi(void *args, gdb_action_t *res) {
|
||||
DbgState *dbg_state = (DbgState *)args;
|
||||
breakpoint_t *stopped_at =
|
||||
cpu_exec_with_bp(1, dbg_state->bp->data(), dbg_state->bp->size());
|
||||
nemu_is_stopped(res, stopped_at);
|
||||
}
|
||||
|
||||
__EXPORT bool nemu_set_bp(void *args, size_t addr, bp_type_t type) {
|
||||
DbgState *dbg_state = (DbgState *)args;
|
||||
for (const auto &bp : *dbg_state->bp) {
|
||||
if (bp.addr == addr && bp.type == type) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
dbg_state->bp->push_back({.addr = addr, .type = type});
|
||||
return true;
|
||||
}
|
||||
|
||||
__EXPORT bool nemu_del_bp(void *args, size_t addr, bp_type_t type) {
|
||||
DbgState *dbg_state = (DbgState *)args;
|
||||
for (auto it = dbg_state->bp->begin(); it != dbg_state->bp->end(); it++) {
|
||||
if (it->addr == addr && it->type == type) {
|
||||
std::swap(*it, *dbg_state->bp->rbegin());
|
||||
dbg_state->bp->pop_back();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
__EXPORT void nemu_on_interrupt(void *args) {
|
||||
nemu_state.state = NEMU_GDB_INTERRUPT;
|
||||
}
|
||||
|
||||
__EXPORT int nemu_read_reg(void *args, int regno, size_t *data) {
|
||||
return isa_read_reg(args, regno, data);
|
||||
}
|
||||
__EXPORT int nemu_write_reg(void *args, int regno, size_t data) {
|
||||
return isa_write_reg(args, regno, data);
|
||||
}
|
||||
|
||||
static struct target_ops nemu_gdbstub_ops = {.cont = nemu_cont,
|
||||
.stepi = nemu_stepi,
|
||||
.read_reg = nemu_read_reg,
|
||||
.write_reg = nemu_write_reg,
|
||||
.read_mem = nemu_read_mem,
|
||||
.write_mem = nemu_write_mem,
|
||||
.set_bp = nemu_set_bp,
|
||||
.del_bp = nemu_del_bp,
|
||||
.on_interrupt = nemu_on_interrupt,
|
||||
.monitor = NULL};
|
||||
static DbgState *pdbg;
|
||||
static gdbstub_t gdbstub_priv;
|
||||
const char SOCKET_ADDR[] = "/tmp/gdbstub-nemu.sock";
|
||||
|
||||
static void init_remote_gdbstub(void *args) {
|
||||
DbgState *dbg_state = (DbgState *)args;
|
||||
pdbg = (DbgState *)args;
|
||||
dbg_state->bp = new std::vector<breakpoint_t>();
|
||||
dbg_state->halt = 0;
|
||||
Assert(dbg_state->bp != NULL, "Failed to allocate breakpoint");
|
||||
}
|
||||
|
||||
__EXPORT void nemu_init(void *args) {
|
||||
init_remote_gdbstub(args);
|
||||
|
||||
void init_rand();
|
||||
void init_mem();
|
||||
|
||||
IFDEF(CONFIG_DEVICE, void init_device());
|
||||
|
||||
init_rand();
|
||||
init_mem();
|
||||
IFDEF(CONFIG_DEVICE, init_device());
|
||||
|
||||
/* Perform ISA dependent initialization. */
|
||||
init_isa();
|
||||
}
|
||||
|
||||
int gdbstub_loop() {
|
||||
if (!gdbstub_init(&gdbstub_priv, &nemu_gdbstub_ops,
|
||||
(arch_info_t)isa_arch_info, NULL, SOCKET_ADDR)) {
|
||||
return EINVAL;
|
||||
}
|
||||
printf("Waiting for gdb connection at %s", SOCKET_ADDR);
|
||||
bool success = gdbstub_run(&gdbstub_priv, pdbg);
|
||||
// gdbstub_close(&gdbstub_priv);
|
||||
return !success;
|
||||
}
|
||||
}
|
|
@ -13,47 +13,90 @@
|
|||
* See the Mulan PSL v2 for more details.
|
||||
***************************************************************************************/
|
||||
|
||||
#include <cpu/cpu.h>
|
||||
#include <errno.h>
|
||||
#include <isa.h>
|
||||
#include <memory/paddr.h>
|
||||
#include <nemu.h>
|
||||
#include <strings.h>
|
||||
#include <utils.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);
|
||||
|
||||
char *log_file = NULL;
|
||||
char *elf_file = NULL;
|
||||
char *img_file = NULL;
|
||||
bool enable_gdbstub = false;
|
||||
|
||||
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("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("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() {
|
||||
FILE *fp = NULL;
|
||||
size_t img_filename_len = strlen(img_file);
|
||||
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);
|
||||
// Image file is searched from paths in environment variable NEMU_IMAGES_PATH if it's a relative path
|
||||
if (img_file[0] != '/') {
|
||||
char *search_paths = getenv("NEMU_IMAGES_PATH");
|
||||
if (search_paths == NULL)
|
||||
search_paths = "./";
|
||||
search_paths = strdup(search_paths);
|
||||
Trace("NEMU_IMAGES_PATH=%s", search_paths);
|
||||
|
||||
char *paths_end = strchr(search_paths, '\0');
|
||||
char *p_start = search_paths;
|
||||
do {
|
||||
char *p = strchr(p_start, ':');
|
||||
if (p != NULL)
|
||||
*p = '\0';
|
||||
else
|
||||
p = paths_end;
|
||||
|
||||
char *file_path = malloc(p - p_start + img_filename_len + 2);
|
||||
strcpy(file_path, p_start);
|
||||
strcat(file_path, "/");
|
||||
strcat(file_path, img_file);
|
||||
|
||||
fp = fopen(file_path, "rb");
|
||||
free(file_path);
|
||||
|
||||
if (fp) {
|
||||
Log("Found '%s' in '%s'", img_file, p_start);
|
||||
break;
|
||||
}
|
||||
|
||||
Assert(fp != NULL || errno == ENOENT, "Cannot open '%s'", img_file);
|
||||
p_start = p + 1;
|
||||
} while (p_start < paths_end);
|
||||
free(search_paths);
|
||||
|
||||
Assert(fp, "Cannot find '%s'", img_file);
|
||||
} else {
|
||||
fp = fopen(img_file, "rb");
|
||||
Assert(fp, "Cannot open '%s'", img_file);
|
||||
}
|
||||
|
||||
fseek(fp, 0, SEEK_END);
|
||||
long size = ftell(fp);
|
||||
|
@ -70,73 +113,70 @@ static long load_img() {
|
|||
|
||||
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 },
|
||||
{"batch", no_argument, NULL, 'b'}, {"log", required_argument, NULL, 'l'},
|
||||
{"debug", no_argument, NULL, 'g'}, {"elf", required_argument, NULL, 'f'},
|
||||
{"help", no_argument, NULL, 'h'}, {0, 0, NULL, 0},
|
||||
};
|
||||
int o;
|
||||
while ( (o = getopt_long(argc, argv, "-bhl:d:p:", table, NULL)) != -1) {
|
||||
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);
|
||||
case 'l':
|
||||
log_file = optarg;
|
||||
break;
|
||||
case 'f':
|
||||
elf_file = optarg;
|
||||
break;
|
||||
case 'g':
|
||||
enable_gdbstub = true;
|
||||
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-g,--debug enable gdb remote server\n");
|
||||
printf("\t-l,--log=FILE output log to FILE\n");
|
||||
printf("\t-f,--elf=FILE elf file with debug info\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();
|
||||
|
||||
void init_log(const char *log_file);
|
||||
/* 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();
|
||||
/* Perform some global initialization. */
|
||||
nemu_init(malloc(nemu_dbg_state_size));
|
||||
|
||||
/* Load the image to memory. This will overwrite the built-in image. */
|
||||
long img_size = load_img();
|
||||
load_img();
|
||||
|
||||
/* Initialize differential testing. */
|
||||
init_difftest(diff_so_file, img_size, difftest_port);
|
||||
|
||||
/* Initialize the simple debugger. */
|
||||
init_sdb();
|
||||
// printf("elf_file: %s\n", elf_file);
|
||||
if (elf_file != NULL) {
|
||||
#ifdef CONFIG_FTRACE
|
||||
void init_elf(const char *path);
|
||||
init_elf(elf_file);
|
||||
#else
|
||||
Warning("Elf file provided, but ftrace not turned on. Ignoring elf file.");
|
||||
#endif
|
||||
}
|
||||
|
||||
#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"
|
||||
));
|
||||
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. */
|
||||
|
|
|
@ -1,125 +0,0 @@
|
|||
/***************************************************************************************
|
||||
* 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;
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue