diff --git a/.clang-format b/.clang-format deleted file mode 100644 index 3ba9598..0000000 --- a/.clang-format +++ /dev/null @@ -1,4 +0,0 @@ ---- -Language: Cpp -BasedOnStyle: LLVM -ReflowComments: false diff --git a/.gitea/workflows/abstract-machine-build.yml b/.gitea/workflows/abstract-machine-build.yml new file mode 100644 index 0000000..f0fd9fd --- /dev/null +++ b/.gitea/workflows/abstract-machine-build.yml @@ -0,0 +1,21 @@ +name: Build abstract machine with nix +on: [push] + +jobs: + build-abstract-machine: + runs-on: nix + steps: + - uses: https://github.com/cachix/cachix-action@v14 + with: + name: ysyx + signingKey: '${{ secrets.CACHIX_SIGNING_KEY }}' + - uses: actions/checkout@v4 + with: + submodules: true + - name: Build abstract-machine + run: | + nix build .?submodules=1#abstract-machine + - name: Build nemu + run: | + nix build .?submodules=1#nemu + diff --git a/.gitea/workflows/build-nix-package.yml b/.gitea/workflows/build-nix-package.yml deleted file mode 100644 index 86bd52d..0000000 --- a/.gitea/workflows/build-nix-package.yml +++ /dev/null @@ -1,28 +0,0 @@ -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 }} diff --git a/.gitea/workflows/build-npc.yml b/.gitea/workflows/build-npc.yml deleted file mode 100644 index 7336129..0000000 --- a/.gitea/workflows/build-npc.yml +++ /dev/null @@ -1,21 +0,0 @@ -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 }} diff --git a/.gitignore b/.gitignore index e9c6af4..44a51ce 100644 --- a/.gitignore +++ b/.gitignore @@ -1,8 +1,14 @@ -*/.gdbinit -difftest/ +!*/ +!/nemu/* +!/nexus-am/* +!/nanos-lite/* +!/navy-apps/* +!/npc/* +!Makefile +!README.md +!.gitignore +!init.sh /fceux-am /nvboard **/.cache **/result -/.pre-commit-config.yaml -**/.vscode/ diff --git a/.gitmodules b/.gitmodules index 7e43040..3d834b3 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,7 +1,3 @@ [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 diff --git a/.scalafmt.conf b/.scalafmt.conf deleted file mode 100644 index cbc03c3..0000000 --- a/.scalafmt.conf +++ /dev/null @@ -1,2 +0,0 @@ -version = 3.7.17 -runner.dialect = scala213source3 diff --git a/abstract-machine/.gitignore b/abstract-machine/.gitignore index 0990b71..bcba0ab 100644 --- a/abstract-machine/.gitignore +++ b/abstract-machine/.gitignore @@ -2,7 +2,5 @@ **/build/ **/.envrc **/.cache -out/ .vscode compile_commands.json -cmakeUserh diff --git a/abstract-machine/CMakeLists.txt b/abstract-machine/CMakeLists.txt index b6e660c..508bc68 100644 --- a/abstract-machine/CMakeLists.txt +++ b/abstract-machine/CMakeLists.txt @@ -6,121 +6,82 @@ set(CMAKE_C_STANDARD 11) set(CMAKE_CXX_STANDARD 11) include(CMakeDependentOption) -include(CMakePackageConfigHelpers) # Used to find libcheck +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) +cmake_dependent_option( + __PLATFORM_NEMU__ "Run on NEMU" + ON "ISA MATCHES \"(riscv | x86)\"" 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]*)__$") +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() + 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) + message(STATUS "Variable: ${VAR}=${VAR_VALUE}, Platform: ${PLATFORM}") + endif() endforeach() -if((NOT PLATFORM) AND (NOT ISA MATCHES native)) - message(FATAL_ERROR "Platform not given!") +if(${PLATFORM} MATCHES "native") +set(ARCH "native") +else() +set(ARCH ${ISA}-${PLATFORM}) 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() +string(TOUPPER ${ARCH} ARCH_UPPER) # -- Target specific options -cmake_dependent_option(NATIVE_USE_KLIB "Use Klib even if on native" ON - "NOT __ISA_NATIVE__" OFF) +cmake_dependent_option( + NATIVE_USE_KLIB "Use Klib even if on native" + ON "NOT __ISA_NATIVE__" OFF) # -- Add compile definitions based on options +add_compile_definitions( + $ + __ISA_${ISA_UPPER}__ + __PLATFORM_${PLATFORM_UPPER}__ +) + +add_compile_definitions( + $<$:__NATIVE_USE_KLIB__> +) + +# -- Required compiler flags +add_compile_options( + # -Werror + -Wno-main + -fno-asynchronous-unwind-tables + -fno-builtin + -fno-stack-protector + -U_FORTIFY_SOURCE + $<$:-fno-exceptions> + $<$:-ffreestanding> + $<$:-fno-rtti>) + +add_link_options( + -znoexecstack +) + +# -- Include linker script here. Use this linker script at link time if INCLUDE_LINKER_SCRIPT is set to true +set(LINKER_SCRIPT linker.ld) 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 $ - $ - $) -target_compile_definitions(am_interface INTERFACE ARCH_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 $ - $) -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_compile_options(-march=rv32if -mabi=ilp32) +add_link_options(-march=rv32if -mabi=ilp32) add_subdirectory(klib) add_subdirectory(am) - -# -- Test depends on klib and am should be added last. -add_subdirectory(klib/tests) diff --git a/abstract-machine/CMakePresets.json b/abstract-machine/CMakePresets.json index fb5eb21..d14c0b6 100644 --- a/abstract-machine/CMakePresets.json +++ b/abstract-machine/CMakePresets.json @@ -7,23 +7,23 @@ "generator": "Unix Makefiles", "binaryDir": "${sourceDir}/out/build/${presetName}", "cacheVariables": { - "CMAKE_BUILD_TYPE": "RelWithDebInfo", + "CMAKE_BUILD_TYPE": "Debug", "ISA": "native", "__PLATFORM_NATIVE__": true, "NATIVE_USE_KLIB": true } }, { - "name": "riscv", - "displayName": "RV32 all platform", + "name": "riscv-nemu", + "displayName": "Riscv32 NEMU", "generator": "Unix Makefiles", "binaryDir": "${sourceDir}/out/build/${presetName}", + "installDir": "/home/xin/repo/ysyx-workbench/abstract-machine/out/install", "cacheVariables": { - "CMAKE_BUILD_TYPE": "RelWithDebInfo", + "CMAKE_BUILD_TYPE": "Debug", "ISA": "riscv", - "__PLATFORM_NPC__": true, "__PLATFORM_NEMU__": true } } ] -} +} \ No newline at end of file diff --git a/abstract-machine/CMakeUserPresets.json b/abstract-machine/CMakeUserPresets.json deleted file mode 100644 index 3f222ce..0000000 --- a/abstract-machine/CMakeUserPresets.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "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" - } - ] -} \ No newline at end of file diff --git a/abstract-machine/README b/abstract-machine/README index b67eb91..2e0392a 100644 --- a/abstract-machine/README +++ b/abstract-machine/README @@ -1,4 +1,4 @@ -AbstractMachine is a minimal, modularized, and machine-independent +AbstractMachine is a minimal, modularized, and machine-independent abstraction layer of the computer hardware: * physical memory and direct execution (The "Turing Machine"); @@ -9,5 +9,5 @@ abstraction layer of the computer hardware: CONTACTS -Bug reports and suggestions go to Yanyan Jiang (jyy@nju.edu.cn) and Zihao +Bug reports and suggestions go to Yanyan Jiang (jyy@nju.edu.cn) and Zihao Yu (yuzihao@ict.ac.cn). diff --git a/abstract-machine/am/CMakeLists.txt b/abstract-machine/am/CMakeLists.txt index f57d540..b0462e4 100644 --- a/abstract-machine/am/CMakeLists.txt +++ b/abstract-machine/am/CMakeLists.txt @@ -1,26 +1,10 @@ +include_directories(${CMAKE_CURRENT_SOURCE_DIR}/include) + +add_library(am_interface INTERFACE) +target_include_directories(am_interface INTERFACE + $ + $) + 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() +install(DIRECTORY include/ DESTINATION include/abstract-machine) diff --git a/abstract-machine/am/include/arch/riscv.h b/abstract-machine/am/include/arch/riscv.h index cb6ecc1..9709050 100644 --- a/abstract-machine/am/include/arch/riscv.h +++ b/abstract-machine/am/include/arch/riscv.h @@ -1,6 +1,5 @@ #ifndef ARCH_H__ #define ARCH_H__ -#include #ifdef __riscv_e #define NR_REGS 16 @@ -10,13 +9,10 @@ struct Context { // TODO: fix the order of these members to match trap.S - uintptr_t gpr[NR_REGS]; - uintptr_t mcause, mstatus, mepc; + uintptr_t mepc, mcause, gpr[NR_REGS], mstatus; void *pdir; }; -enum Cause { CauseEnvironmentCallFromMMode = 11 }; - #ifdef __riscv_e #define GPR1 gpr[15] // a5 #else diff --git a/abstract-machine/am/src/CMakeLists.txt b/abstract-machine/am/src/CMakeLists.txt index 4988276..533dd3b 100644 --- a/abstract-machine/am/src/CMakeLists.txt +++ b/abstract-machine/am/src/CMakeLists.txt @@ -1 +1,53 @@ -add_subdirectory(${ISA}) +if(ISA MATCHES "native") +set(SOURCEDIR "./${PLATFORM}") +else() +set(SOURCEDIR "./${ISA}/${PLATFORM}") +endif() + +add_subdirectory(${SOURCEDIR}) + +target_include_directories(am-${ARCH} + PRIVATE ${CMAKE_CURRENT_SOURCE_DIR} + PUBLIC + $ + $) +target_link_libraries(am-${ARCH} + PUBLIC klib_interface + INTERFACE m) + +# TODO: Check +target_link_options(am-${ARCH} INTERFACE + $ + $) + +# Interface compile flags +target_link_options(am-${ARCH} INTERFACE + -znoexecstack) + +target_compile_options(am-${ARCH} INTERFACE + -fno-asynchronous-unwind-tables + -fno-builtin + -fno-stack-protector + -U_FORTIFY_SOURCE + $<$:-fno-exceptions> + $<$:-ffreestanding> + $<$:-fno-rtti>) + +install(TARGETS am-${ARCH} klib_interface am_interface + EXPORT amTargets + LIBRARY DESTINATION lib) + +install(EXPORT amTargets + 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}) + +# TODO: check +install(FILES ${CMAKE_SOURCE_DIR}/scripts/${LINKER_SCRIPT} + DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/am-${ARCH}) diff --git a/abstract-machine/am/src/native/CMakeLists.txt b/abstract-machine/am/src/native/CMakeLists.txt index 3f5b769..e3c9303 100644 --- a/abstract-machine/am/src/native/CMakeLists.txt +++ b/abstract-machine/am/src/native/CMakeLists.txt @@ -1,3 +1,6 @@ +include(CheckPIESupported) +check_pie_supported() + set(SOURCES trap.S cte.c @@ -10,16 +13,14 @@ set(SOURCES ioe/disk.c ioe/gpu.c ioe/input.c - ioe/timer.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) +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) +target_link_libraries(am-${ARCH} PUBLIC SDL2::SDL2) diff --git a/abstract-machine/am/src/native/mpe.c b/abstract-machine/am/src/native/mpe.c index ec51442..a25c0fe 100644 --- a/abstract-machine/am/src/native/mpe.c +++ b/abstract-machine/am/src/native/mpe.c @@ -1,5 +1,5 @@ -#include "platform.h" #include +#include "platform.h" int __am_mpe_init = 0; extern bool __am_has_ioe; @@ -16,8 +16,7 @@ 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(); @@ -32,9 +31,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"); } @@ -44,7 +42,9 @@ 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); diff --git a/abstract-machine/am/src/native/platform.c b/abstract-machine/am/src/native/platform.c index 813939a..02f8941 100644 --- a/abstract-machine/am/src/native/platform.c +++ b/abstract-machine/am/src/native/platform.c @@ -1,11 +1,11 @@ #define _GNU_SOURCE -#include "platform.h" +#include +#include #include #include -#include #include -#include -#include +#include +#include "platform.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,8 +102,7 @@ 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 @@ -111,13 +110,11 @@ 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); @@ -125,7 +122,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 @@ -179,8 +176,7 @@ 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); } @@ -189,12 +185,10 @@ 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); } @@ -211,21 +205,26 @@ 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() { +} diff --git a/abstract-machine/am/src/platform/nemu/ioe/input.c b/abstract-machine/am/src/platform/nemu/ioe/input.c index f868d79..9cecca2 100644 --- a/abstract-machine/am/src/platform/nemu/ioe/input.c +++ b/abstract-machine/am/src/platform/nemu/ioe/input.c @@ -4,7 +4,6 @@ #define KEYDOWN_MASK 0x8000 void __am_input_keybrd(AM_INPUT_KEYBRD_T *kbd) { - uint32_t keycode = inl(KBD_ADDR); - kbd->keydown = ((keycode & KEYDOWN_MASK) != 0); - kbd->keycode = keycode & (~KEYDOWN_MASK); + kbd->keydown = 0; + kbd->keycode = AM_KEY_NONE; } diff --git a/abstract-machine/am/src/platform/nemu/ioe/timer.c b/abstract-machine/am/src/platform/nemu/ioe/timer.c index ce545de..f173ed4 100644 --- a/abstract-machine/am/src/platform/nemu/ioe/timer.c +++ b/abstract-machine/am/src/platform/nemu/ioe/timer.c @@ -1,17 +1,18 @@ #include #include -void __am_timer_init() {} +void __am_timer_init() { +} void __am_timer_uptime(AM_TIMER_UPTIME_T *uptime) { - uptime->us = ((uint64_t)inl(RTC_ADDR + 4) << 32) + inl(RTC_ADDR); + uptime->us = 0; } 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; } diff --git a/abstract-machine/am/src/platform/nemu/trm.c b/abstract-machine/am/src/platform/nemu/trm.c index 5d08a48..f1802aa 100644 --- a/abstract-machine/am/src/platform/nemu/trm.c +++ b/abstract-machine/am/src/platform/nemu/trm.c @@ -6,18 +6,19 @@ int main(const char *args); Area heap = RANGE(&_heap_start, PMEM_END); #ifndef MAINARGS -#define MAINARGS "i" +#define MAINARGS "" #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() { diff --git a/abstract-machine/am/src/riscv/CMakeLists.txt b/abstract-machine/am/src/riscv/CMakeLists.txt deleted file mode 100644 index 0c876d0..0000000 --- a/abstract-machine/am/src/riscv/CMakeLists.txt +++ /dev/null @@ -1,9 +0,0 @@ -foreach(PLATFORM IN LISTS PLATFORMS) - string(TOUPPER ${ARCH} ARCH_UPPER) - set(AM_COMMON_COMPILE_DEF - # -- Arch related - $ __ISA_${ISA_UPPER}__ - __PLATFORM_${PLATFORM_UPPER}__ - $<$:__NATIVE_USE_KLIB__>) - add_subdirectory(${PLATFORM}) -endforeach() diff --git a/abstract-machine/am/src/riscv/nemu/CMakeLists.txt b/abstract-machine/am/src/riscv/nemu/CMakeLists.txt index 36a1966..a6992db 100644 --- a/abstract-machine/am/src/riscv/nemu/CMakeLists.txt +++ b/abstract-machine/am/src/riscv/nemu/CMakeLists.txt @@ -1,41 +1,34 @@ include(nemu-settings) include(riscv-settings) -add_library(am-riscv-nemu cte.c start.S trap.S vme.c ${NEMU_SOURCES}) +add_library(am-${ISA}-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_compile_options(am-${ISA}-nemu PRIVATE + ${NEMU_COMPILE_OPTIONS} + ${RISCV_COMPILE_OPTIONS}) +target_link_options(am-${ISA}-nemu PRIVATE + ${NEMU_LINK_OPITIONS} + ${RISCV_LINK_OPTIONS}) +target_include_directories(am-${ISA}-nemu PRIVATE + ${NEMU_INCLUDE_DIRECTORIES}) +target_link_options(am-${ISA}-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 ${NEMU_LINK_OPITIONS} - ${RISCV_LINK_OPTIONS}) +target_compile_definitions(am-${ISA}-nemu PUBLIC + ARCH_H="arch/riscv.h") +target_compile_definitions(am-${ISA}-nemu PRIVATE + ISA_H="riscv/riscv.h") -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 - $ - $) - -target_link_libraries( - am-riscv-nemu - PUBLIC am_interface klib_interface - INTERFACE m) - -target_compile_definitions(am-riscv-nemu PRIVATE ISA_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}) +set_target_properties(am-${ISA}-nemu PROPERTIES + POSITION_INDEPENDENT_CODE OFF + INTERFACE_POSITION_INDEPENDENT_CODE OFF) diff --git a/abstract-machine/am/src/riscv/nemu/cte.c b/abstract-machine/am/src/riscv/nemu/cte.c index 8d71bbf..77a357c 100644 --- a/abstract-machine/am/src/riscv/nemu/cte.c +++ b/abstract-machine/am/src/riscv/nemu/cte.c @@ -1,21 +1,14 @@ -#include "arch/riscv.h" #include -#include #include -#include +#include -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) { - case CauseEnvironmentCallFromMMode: - ev.event = EVENT_YIELD; - break; - default: - ev.event = EVENT_ERROR; - break; + default: ev.event = EVENT_ERROR; break; } c = user_handler(ev, c); @@ -27,7 +20,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)); @@ -38,10 +31,7 @@ bool cte_init(Context *(*handler)(Event, Context *)) { } Context *kcontext(Area kstack, void (*entry)(void *), void *arg) { - Context *c = kstack.end - sizeof(Context); - c->mepc = (uintptr_t)entry; - c->gpr[10] = (uintptr_t)arg; - return c; + return NULL; } void yield() { @@ -52,6 +42,9 @@ void yield() { #endif } -bool ienabled() { return false; } +bool ienabled() { + return false; +} -void iset(bool enable) {} +void iset(bool enable) { +} diff --git a/abstract-machine/am/src/riscv/nemu/trap.S b/abstract-machine/am/src/riscv/nemu/trap.S index 5ce677d..5ec275a 100644 --- a/abstract-machine/am/src/riscv/nemu/trap.S +++ b/abstract-machine/am/src/riscv/nemu/trap.S @@ -60,8 +60,6 @@ __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 diff --git a/abstract-machine/am/src/riscv/npc/CMakeLists.txt b/abstract-machine/am/src/riscv/npc/CMakeLists.txt deleted file mode 100644 index fbcdd90..0000000 --- a/abstract-machine/am/src/riscv/npc/CMakeLists.txt +++ /dev/null @@ -1,46 +0,0 @@ -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 - $ - $) - -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 - $ - $) - -target_compile_definitions(am-riscv-npc PUBLIC ${AM_COMMON_COMPILE_DEF} - ARCH_H=) - -install(FILES ${CMAKE_SOURCE_DIR}/scripts/linker.ld - DESTINATION ${CMAKE_INSTALL_DATADIR}) diff --git a/abstract-machine/am/src/riscv/npc/ioe.c b/abstract-machine/am/src/riscv/npc/ioe.c index f794ce2..26bad0a 100644 --- a/abstract-machine/am/src/riscv/npc/ioe.c +++ b/abstract-machine/am/src/riscv/npc/ioe.c @@ -7,32 +7,26 @@ 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_uart_config(AM_UART_CONFIG_T *cfg) { cfg->present = false; } +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; } typedef void (*handler_t)(void *buf); static void *lut[128] = { - [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, + [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); } diff --git a/abstract-machine/am/src/riscv/npc/libgcc/CMakeLists.txt b/abstract-machine/am/src/riscv/npc/libgcc/CMakeLists.txt deleted file mode 100644 index feaec7e..0000000 --- a/abstract-machine/am/src/riscv/npc/libgcc/CMakeLists.txt +++ /dev/null @@ -1,9 +0,0 @@ -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) diff --git a/abstract-machine/am/src/riscv/npc/npc.h b/abstract-machine/am/src/riscv/npc/npc.h deleted file mode 100644 index e6c0241..0000000 --- a/abstract-machine/am/src/riscv/npc/npc.h +++ /dev/null @@ -1,6 +0,0 @@ -#ifndef _AM_NPC_NPC_H_ -#define _AM_NPC_NPC_H_ -#define SERIAL_PORT 0x10000000 -#define RTC_ADDR 0x10001000 - -#endif \ No newline at end of file diff --git a/abstract-machine/am/src/riscv/npc/timer.c b/abstract-machine/am/src/riscv/npc/timer.c index 844463d..6ea0ffa 100644 --- a/abstract-machine/am/src/riscv/npc/timer.c +++ b/abstract-machine/am/src/riscv/npc/timer.c @@ -1,18 +1,17 @@ -#include "npc.h" #include -#include -void __am_timer_init() {} +void __am_timer_init() { +} void __am_timer_uptime(AM_TIMER_UPTIME_T *uptime) { - uptime->us = ((uint64_t)inl(RTC_ADDR + 4) << 32) + inl(RTC_ADDR); + uptime->us = 0; } 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; } diff --git a/abstract-machine/am/src/riscv/npc/trm.c b/abstract-machine/am/src/riscv/npc/trm.c index ec9c965..0efe6e7 100644 --- a/abstract-machine/am/src/riscv/npc/trm.c +++ b/abstract-machine/am/src/riscv/npc/trm.c @@ -1,27 +1,24 @@ -#include "npc.h" #include #include -#include 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 "3" +#define MAINARGS "" #endif static const char mainargs[] = MAINARGS; -void putch(char ch) { outb(SERIAL_PORT, ch); } +void putch(char ch) { +} void halt(int code) { - asm volatile("mv a0, %0; ebreak" : : "r"(code)); - while (1) - ; + while (1); } void _trm_init() { diff --git a/abstract-machine/am/src/x86/qemu/trap32.S b/abstract-machine/am/src/x86/qemu/trap32.S index 43fb2e2..b0b41a8 100644 --- a/abstract-machine/am/src/x86/qemu/trap32.S +++ b/abstract-machine/am/src/x86/qemu/trap32.S @@ -55,25 +55,25 @@ __am_iret: popl %edi popl %ebp iret - + .kernel_iret: popl %eax popl %ebx popl %ecx popl %edx addl $4, %esp - + /* stack frame: 28 ss 24 esp (not popped by iret when returning to ring0) 20 eflags ---> move to new-esp 16 cs 12 eip - 8 ebp - 4 edi + 8 ebp + 4 edi 0 esi <--- %esp */ - + movl %esp, %ebp movl 24(%ebp), %edi // %edi is new-esp diff --git a/abstract-machine/cmake/am-config.cmake.in b/abstract-machine/cmake/am-config.cmake.in index 0445b66..f2fbb32 100644 --- a/abstract-machine/cmake/am-config.cmake.in +++ b/abstract-machine/cmake/am-config.cmake.in @@ -6,5 +6,4 @@ find_dependency(SDL2 REQUIRED) endif() # Include the targets file -include("${CMAKE_CURRENT_LIST_DIR}/../interfaceTargets.cmake") include("${CMAKE_CURRENT_LIST_DIR}/amTargets.cmake") diff --git a/abstract-machine/cmake/nemu-settings.cmake b/abstract-machine/cmake/nemu-settings.cmake index d19a2d3..910cdcf 100644 --- a/abstract-machine/cmake/nemu-settings.cmake +++ b/abstract-machine/cmake/nemu-settings.cmake @@ -1,12 +1,11 @@ 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]) + -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) diff --git a/abstract-machine/default.nix b/abstract-machine/default.nix index b452cdb..1f1f67d 100644 --- a/abstract-machine/default.nix +++ b/abstract-machine/default.nix @@ -1,23 +1,20 @@ -{ stdenv -, lib -, cmake -, SDL2 -, glibc -, isa ? "native" -, platform ? [ ] +{ stdenv, + lib, + cmake, + SDL2, + isa ? "native", + platform ? "NEMU" }: stdenv.mkDerivation { pname = "abstract-machine"; - version = "2024.06.01"; + version = "2024.02.18"; src = ./.; - cmakeFlags = [ + cmakeFlags = [ (lib.cmakeFeature "ISA" isa) - ] ++ map (p: (lib.cmakeBool "__PLATFORM_${lib.strings.toUpper p}__" true)) platform; - - cmakeBuildType = "Debug"; - dontStrip = true; + (lib.cmakeBool "__PLATFORM_${lib.strings.toUpper platform}__" true) + ]; nativeBuildInputs = [ cmake @@ -25,10 +22,5 @@ stdenv.mkDerivation { buildInputs = [ - ] ++ (if isa == "native" then [ SDL2 ] else [ ]); - propagatedBuildInputs = [ - - ] ++ (if isa == "native" then [ SDL2 ] else [ ]); - - doCheck = true; + ] ++ (if platform=="native" then [ SDL2 ] else [ ]); } diff --git a/abstract-machine/klib/CMakeLists.txt b/abstract-machine/klib/CMakeLists.txt index 4a7a3aa..2cf4a78 100644 --- a/abstract-machine/klib/CMakeLists.txt +++ b/abstract-machine/klib/CMakeLists.txt @@ -1,4 +1,12 @@ -install(DIRECTORY include/ - DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/abstract-machine) +include_directories(${CMAKE_CURRENT_SOURCE_DIR}/include) + +add_library(klib_interface INTERFACE) +target_include_directories(klib_interface + INTERFACE + $ + $) add_subdirectory(src) +# add_subdirectory(tests) + +install(DIRECTORY include/ DESTINATION include/abstract-machine) diff --git a/abstract-machine/klib/src/CMakeLists.txt b/abstract-machine/klib/src/CMakeLists.txt index 8f521fc..bf7e136 100644 --- a/abstract-machine/klib/src/CMakeLists.txt +++ b/abstract-machine/klib/src/CMakeLists.txt @@ -1,29 +1,33 @@ -# find_package(FLEX) find_package(BISON) +# 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} +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) +target_include_directories(klib PUBLIC $) +target_compile_definitions(klib PUBLIC $) -install( - TARGETS klib - EXPORT klibTargets - LIBRARY DESTINATION lib) +install(TARGETS klib + EXPORT klibTargets + LIBRARY DESTINATION lib) -install( - EXPORT klibTargets - FILE klibTargets.cmake - DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/klib) +install(EXPORT klibTargets + FILE klibTargets.cmake + DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/klib) -configure_package_config_file( - ${CMAKE_SOURCE_DIR}/cmake/klib-config.cmake.in +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) + diff --git a/abstract-machine/klib/src/stdio.c b/abstract-machine/klib/src/stdio.c index efcc671..fec63bc 100644 --- a/abstract-machine/klib/src/stdio.c +++ b/abstract-machine/klib/src/stdio.c @@ -1,91 +1,16 @@ #include -#include #include +#include #include #if !defined(__ISA_NATIVE__) || defined(__NATIVE_USE_KLIB__) -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 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 vprintf(const char *fmt, va_list ap) { + const char *p = fmt; + while(*p != '\0') { + putch(*p); } + return 0; } int printf(const char *fmt, ...) { @@ -96,99 +21,12 @@ int printf(const char *fmt, ...) { 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 vsprintf(char *out, const char *fmt, va_list ap) { + panic("Not implemented"); } int sprintf(char *out, const char *fmt, ...) { - va_list args; - va_start(args, fmt); - vsprintf(out, fmt, args); - va_end(args); - return 0; + panic("Not implemented"); } int snprintf(char *out, size_t n, const char *fmt, ...) { diff --git a/abstract-machine/klib/src/stdlib.c b/abstract-machine/klib/src/stdlib.c index 90432b6..382635d 100644 --- a/abstract-machine/klib/src/stdlib.c +++ b/abstract-machine/klib/src/stdlib.c @@ -1,6 +1,6 @@ #include -#include #include +#include #if !defined(__ISA_NATIVE__) || defined(__NATIVE_USE_KLIB__) static unsigned long int next = 1; @@ -8,21 +8,23 @@ 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; } @@ -31,19 +33,13 @@ 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() - 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; +#if !(defined(__ISA_NATIVE__) && defined(__NATIVE_USE_KLIB__)) + panic("Not implemented"); +#endif + return NULL; } -void free(void *ptr) {} +void free(void *ptr) { +} #endif diff --git a/abstract-machine/klib/src/string.c b/abstract-machine/klib/src/string.c index f8d95be..931e7dd 100644 --- a/abstract-machine/klib/src/string.c +++ b/abstract-machine/klib/src/string.c @@ -1,5 +1,5 @@ -#include #include +#include #include #if !defined(__ISA_NATIVE__) || defined(__NATIVE_USE_KLIB__) @@ -7,15 +7,14 @@ size_t strlen(const char *s) { const char *p = s; size_t len = 0; - while (*(p++) != '\0') - len++; + while(*(p++) != '\0') len++; return len; } char *strcpy(char *dst, const char *src) { char *p_dst = dst; const char *p_src = src; - for (; *p_src != '\0'; p_src++, p_dst++) { + for(; *p_src != '\0'; p_src++, p_dst++) { *p_dst = *p_src; } *p_dst = '\0'; @@ -24,10 +23,10 @@ char *strcpy(char *dst, const char *src) { char *strncpy(char *dst, const char *src, size_t n) { int i = 0; - for (; i < n && src[i] != '\0'; i++) { + for(; i < n && src[i] != '\0'; i++) { dst[i] = src[i]; } - for (; i < n; i++) { + for(; i < n; i++) { dst[i] = '\0'; } return dst; @@ -36,9 +35,8 @@ char *strncpy(char *dst, const char *src, size_t n) { char *strcat(char *dst, const char *src) { char *p_dst = dst; const char *p_src = src; - while (*p_dst != '\0') - p_dst++; - for (; *p_src != '\0'; p_src++, p_dst++) { + while(*p_dst != '\0') p_dst++; + for(; *p_src != '\0'; p_src++, p_dst++) { *p_dst = *p_src; } *p_dst = '\0'; @@ -47,56 +45,54 @@ char *strcat(char *dst, const char *src) { int strcmp(const char *s1, const char *s2) { const char *p_s1 = s1, *p_s2 = s2; - for (; *p_s1 == *p_s2; p_s1++, p_s2++) { - if (*p_s1 == '\0' || *p_s2 == '\0') { + 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) { 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') + 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) { uint8_t *p = s; - for (int i = 0; i < n; i++) { + for(int i = 0; i < n; i++) { p[i] = c; } return s; } void *memmove(void *dst, const void *src, size_t n) { - if (src + n > dst && src < dst) { + 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) { + while(p_dst >= dst) { memcpy(p_dst, p_src, len); p_src -= len; p_dst -= len; } - if (n % len) - memcpy(dst, src, n % 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) { + 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 { + if(n % len) memcpy(p_dst, p_src, n % len); + } else { memcpy(dst, src, n); } @@ -104,7 +100,7 @@ void *memmove(void *dst, const void *src, size_t n) { } void *memcpy(void *out, const void *in, size_t n) { - for (size_t i = 0; i < n; i++) { + for (size_t i = 0 ; i < n ; i++) { *(uint8_t *)(out + i) = *(uint8_t *)(in + i); } return out; @@ -113,10 +109,9 @@ void *memcpy(void *out, const void *in, size_t n) { int memcmp(const void *s1, const void *s2, size_t n) { const uint8_t *p1 = s1, *p2 = s2; for (int i = 0; i < n; i++) { - if (*p1 != *p2) + if(*p1 != *p2) return p1 - p2; - p1++; - p2++; + p1++; p2++; } return 0; } diff --git a/abstract-machine/klib/tests/CMakeLists.txt b/abstract-machine/klib/tests/CMakeLists.txt index d5e62ad..f72c555 100644 --- a/abstract-machine/klib/tests/CMakeLists.txt +++ b/abstract-machine/klib/tests/CMakeLists.txt @@ -1,11 +1,17 @@ -set(TEST_SOURCES stdio string) +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() + target_link_libraries(${TEST} am-${ARCH} klib m) + target_include_directories(${TEST} + PRIVATE $ + PRIVATE $ + ) + # TODO: Run tests in other configurations + if(__PLATFORM_NATIVE__) + add_test(NAME ${TEST} COMMAND ${TEST}) + endif() endforeach() diff --git a/abstract-machine/out/install/lib/libklib.a b/abstract-machine/out/install/lib/libklib.a new file mode 100644 index 0000000..5023a30 Binary files /dev/null and b/abstract-machine/out/install/lib/libklib.a differ diff --git a/am-kernels b/am-kernels new file mode 160000 index 0000000..2f55982 --- /dev/null +++ b/am-kernels @@ -0,0 +1 @@ +Subproject commit 2f559823a63cf6909d5a9e32dee47d6891caf553 diff --git a/flake.lock b/flake.lock index 1aa5691..36b9a39 100644 --- a/flake.lock +++ b/flake.lock @@ -1,112 +1,5 @@ { "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" @@ -125,220 +18,6 @@ "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, @@ -355,306 +34,10 @@ "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" + "flake-utils": "flake-utils", + "nixpkgs": "nixpkgs" } }, "systems": { @@ -671,136 +54,6 @@ "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", diff --git a/flake.nix b/flake.nix index 86c9a4f..3a07d79 100644 --- a/flake.nix +++ b/flake.nix @@ -1,35 +1,14 @@ { 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: + outputs = { self, ... }@inputs: with 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 { + pkgs = nixpkgs.legacyPackages.${system}; + crossPkgs = import nixpkgs { localSystem = system; crossSystem = { config = "riscv32-none-elf"; @@ -41,107 +20,39 @@ }; 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.nemu = pkgs.callPackage ./nemu { am-kernels = self.packages.${system}.am-kernels; }; + packages.abstract-machine = crossPkgs.callPackage ./abstract-machine { isa = "riscv"; platform = "nemu"; }; + + packages.am-kernels = crossPkgs.stdenv.mkDerivation rec { + pname = "am-kernels-cmake"; + version = "2024.02.18"; + + src = ./am-kernels; + + nativeBuildInputs = [ + pkgs.cmake + ]; + + cmakeFlags = [ + (pkgs.lib.cmakeFeature "ISA" "riscv") + (pkgs.lib.cmakeFeature "PLATFORM" "nemu") + (pkgs.lib.cmakeFeature "CMAKE_INSTALL_DATADIR" "share") + ]; + + buildInputs = [ + # SDL2 + self.packages.${system}.abstract-machine + ]; }; - - 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 + gdb ]; 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 - ]; }; } ); diff --git a/nemu/.clang-format b/nemu/.clang-format new file mode 100644 index 0000000..0515c02 --- /dev/null +++ b/nemu/.clang-format @@ -0,0 +1,3 @@ +--- +Language: Cpp +BasedOnStyle: LLVM \ No newline at end of file diff --git a/nemu/.gitignore b/nemu/.gitignore index 5bea786..36e223b 100644 --- a/nemu/.gitignore +++ b/nemu/.gitignore @@ -9,7 +9,6 @@ build/ .envrc .metals/ .vscode/ -.zed/ compile_commands.json ### C ### diff --git a/nemu/Kconfig b/nemu/Kconfig index 8c91522..2b316a5 100644 --- a/nemu/Kconfig +++ b/nemu/Kconfig @@ -126,26 +126,6 @@ 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" @@ -180,7 +160,7 @@ config ITRACE_BUFFER default 10 config MTRACE - depends on TRACE && LOG_TRACE + depends on TRACE && TARGET_NATIVE_ELF && ENGINE_INTERPRETER bool "Enable memory tracing" default n @@ -198,7 +178,7 @@ config MTRACE_RANGE_MAX default 10 config FTRACE - depends on TRACE && TARGET_NATIVE_ELF && ENGINE_INTERPRETER && LOG_TRACE + depends on TRACE && TARGET_NATIVE_ELF && ENGINE_INTERPRETER bool "Enable function tracing" default n diff --git a/nemu/Makefile b/nemu/Makefile index 1a645d7..e5e5838 100644 --- a/nemu/Makefile +++ b/nemu/Makefile @@ -83,7 +83,7 @@ $(IMAGES): %: %.bin $(BINARY) @echo + TEST $(notdir $<) @$(BINARY) -b $< >/dev/null 2>&1 || printf "\t%14s\n" $(notdir $<) >> $(RESULT) -integration-tests: $(IMAGES) +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) diff --git a/nemu/configs/libdefconfig b/nemu/configs/libdefconfig deleted file mode 100644 index 1408a84..0000000 --- a/nemu/configs/libdefconfig +++ /dev/null @@ -1,87 +0,0 @@ -# -# 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 diff --git a/nemu/configs/riscv32-lib_defconfig b/nemu/configs/riscv32-lib_defconfig deleted file mode 100644 index 15d8758..0000000 --- a/nemu/configs/riscv32-lib_defconfig +++ /dev/null @@ -1,72 +0,0 @@ -# -# 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 diff --git a/nemu/default.nix b/nemu/default.nix index 9f1276a..d3d5a70 100644 --- a/nemu/default.nix +++ b/nemu/default.nix @@ -1,26 +1,17 @@ -{ stdenv -, lib -, gnumake -, pkg-config -, bison -, flex -, dtc -, check -, mini-gdbstub -, readline -, libllvm -, SDL2 -, am-kernels ? "" -, defconfig ? "alldefconfig" +{ pkgs, + lib, + stdenv, + am-kernels, + dtc }: stdenv.mkDerivation rec { pname = "nemu"; - version = "2024-08-15"; + version = "2024-03-02"; src = ./.; - nativeBuildInputs = [ + nativeBuildInputs = with pkgs; [ gnumake pkg-config flex @@ -28,44 +19,45 @@ stdenv.mkDerivation rec { dtc ]; - buildInputs = [ - SDL2 + buildInputs = with pkgs; [ readline libllvm - mini-gdbstub ]; checkInputs = [ - check + pkgs.check am-kernels ]; configurePhase = '' export NEMU_HOME=$(pwd) - make ${defconfig} + make alldefconfig ''; buildPhase = '' make ''; - doCheck = (am-kernels != ""); + doCheck = true; checkPhase = '' - export NEMU_IMAGES_PATH=${am-kernels}/share/am-kernels + export IMAGES_PATH=${am-kernels}/share/binary 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 + mkdir -p $out/bin make PREFIX=$out install ''; shellHook = '' export NEMU_HOME=$(pwd) + export IMAGES_PATH=${am-kernels}/share/binary ''; + + meta = with lib; { + description = "NJU EMUlator, a full system x86/mips32/riscv32/riscv64 emulator for teaching"; + homepage = "https://github.com/NJU-ProjectN/nemu.git"; + license = with licenses; [ ]; + maintainers = with maintainers; [ ]; + }; } diff --git a/nemu/include/config.h b/nemu/include/config.h deleted file mode 100644 index 6df4bf9..0000000 --- a/nemu/include/config.h +++ /dev/null @@ -1,9 +0,0 @@ -#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__ diff --git a/nemu/include/cpu/cpu.h b/nemu/include/cpu/cpu.h index c9bb700..2be0d77 100644 --- a/nemu/include/cpu/cpu.h +++ b/nemu/include/cpu/cpu.h @@ -17,18 +17,8 @@ #define __CPU_CPU_H__ #include -#include - -#include -#include - -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); diff --git a/nemu/include/cpu/decode.h b/nemu/include/cpu/decode.h index 81946bf..a17c888 100644 --- a/nemu/include/cpu/decode.h +++ b/nemu/include/cpu/decode.h @@ -16,62 +16,39 @@ #ifndef __CPU_DECODE_H__ #define __CPU_DECODE_H__ -#include "types.h" #include -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; } 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 @@ -81,24 +58,21 @@ 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); @@ -110,22 +84,18 @@ 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_START(name) \ - { \ - const void **__instpat_end = &&concat(__instpat_end_, name); -#define INSTPAT_END(name) \ - concat(__instpat_end_, name) :; \ - } +// --- pattern matching wrappers for decode --- +#define INSTPAT(pattern, ...) do { \ + uint64_t key, mask, shift; \ + pattern_decode(pattern, STRLEN(pattern), &key, &mask, &shift); \ + if ((((uint64_t)INSTPAT_INST(s) >> shift) & mask) == key) { \ + INSTPAT_MATCH(s, ##__VA_ARGS__); \ + goto *(__instpat_end); \ + } \ +} while (0) + +#define INSTPAT_START(name) { const void ** __instpat_end = &&concat(__instpat_end_, name); +#define INSTPAT_END(name) concat(__instpat_end_, name): ; } #endif diff --git a/nemu/include/cpu/difftest.h b/nemu/include/cpu/difftest.h new file mode 100644 index 0000000..0c60d3b --- /dev/null +++ b/nemu/include/cpu/difftest.h @@ -0,0 +1,53 @@ +/*************************************************************************************** +* Copyright (c) 2014-2022 Zihao Yu, Nanjing University +* +* NEMU is licensed under Mulan PSL v2. +* You can use this software according to the terms and conditions of the Mulan PSL v2. +* You may obtain a copy of Mulan PSL v2 at: +* http://license.coscl.org.cn/MulanPSL2 +* +* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, +* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, +* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. +* +* See the Mulan PSL v2 for more details. +***************************************************************************************/ + +#ifndef __CPU_DIFFTEST_H__ +#define __CPU_DIFFTEST_H__ + +#include +#include + +#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 diff --git a/nemu/include/debug.h b/nemu/include/debug.h index c0f4952..329c64a 100644 --- a/nemu/include/debug.h +++ b/nemu/include/debug.h @@ -16,59 +16,41 @@ #ifndef __DEBUG_H__ #define __DEBUG_H__ -#include #include #include +#include IFDEF(CONFIG_ITRACE, void log_itrace_print()); -#if (CONFIG_LOG_LEVEL >= 4) -#define Trace(format, ...) _Log("[TRACE] " format "\n", ##__VA_ARGS__) -#else -#define Trace(format, ...) -#endif +#define Trace(format, ...) \ + _Log("[TRACE] " format "\n", ## __VA_ARGS__) -#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 +#define Log(format, ...) \ + _Log(ANSI_FMT("[INFO] %s:%d %s() ", ANSI_FG_BLUE) format "\n", \ + __FILE__, __LINE__, __func__, ## __VA_ARGS__) -#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 +#define Warning(format, ...) \ + _Log(ANSI_FMT("[WARNING] %s:%d %s() ", ANSI_FG_YELLOW) format "\n", \ + __FILE__, __LINE__, __func__, ## __VA_ARGS__) -#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 Error(format, ...) \ + _Log(ANSI_FMT("[ERROR] %s:%d %s() ", ANSI_FG_RED) format "\n", \ + __FILE__, __LINE__, __func__, ## __VA_ARGS__) -#define Assert(cond, format, ...) \ - do { \ - if (!(cond)) { \ - MUXDEF( \ - CONFIG_TARGET_AM, \ - printf(ANSI_FMT(format, ANSI_FG_RED) "\n", ##__VA_ARGS__), \ - (fflush(stdout), fprintf(stderr, ANSI_FMT(format, ANSI_FG_RED) "\n", \ - ##__VA_ARGS__))); \ - IFNDEF(CONFIG_TARGET_AM, extern FILE *log_fp; fflush(log_fp)); \ - IFDEF(CONFIG_ITRACE, log_itrace_print()); \ - extern void assert_fail_msg(); \ - assert_fail_msg(); \ - assert(cond); \ - } \ +#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") diff --git a/nemu/include/device/map.h b/nemu/include/device/map.h index ecea817..841d36c 100644 --- a/nemu/include/device/map.h +++ b/nemu/include/device/map.h @@ -16,12 +16,10 @@ #ifndef __DEVICE_MAP_H__ #define __DEVICE_MAP_H__ -#include -#include -#include +#include -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; @@ -38,19 +36,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)) { - nemu_do_difftest = false; + difftest_skip_ref(); return i; } } return -1; } -void add_pio_map(const char *name, ioaddr_t addr, void *space, uint32_t len, - io_callback_t callback); -void add_mmio_map(const char *name, paddr_t addr, void *space, uint32_t len, - io_callback_t callback); +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); diff --git a/nemu/include/difftest-def.h b/nemu/include/difftest-def.h new file mode 100644 index 0000000..77948fb --- /dev/null +++ b/nemu/include/difftest-def.h @@ -0,0 +1,40 @@ +/*************************************************************************************** +* Copyright (c) 2014-2022 Zihao Yu, Nanjing University +* +* NEMU is licensed under Mulan PSL v2. +* You can use this software according to the terms and conditions of the Mulan PSL v2. +* You may obtain a copy of Mulan PSL v2 at: +* http://license.coscl.org.cn/MulanPSL2 +* +* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, +* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, +* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. +* +* See the Mulan PSL v2 for more details. +***************************************************************************************/ + +#ifndef __DIFFTEST_DEF_H__ +#define __DIFFTEST_DEF_H__ + +#include +#include +#include + +#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 diff --git a/nemu/include/difftest.h b/nemu/include/difftest.h deleted file mode 100644 index f9933bc..0000000 --- a/nemu/include/difftest.h +++ /dev/null @@ -1,8 +0,0 @@ -#ifndef __NEMU_DIFFTEST_H__ -#define __NEMU_DIFFTEST_H__ - -#include - -extern bool nemu_do_difftest; - -#endif // __NEMU_DIFFTEST_H__ diff --git a/nemu/include/isa.h b/nemu/include/isa.h index e860538..5040349 100644 --- a/nemu/include/isa.h +++ b/nemu/include/isa.h @@ -17,7 +17,6 @@ #define __ISA_H__ // Located at src/isa/$(GUEST_ISA)/include/isa-def.h -#include #include // The macro `__GUEST_ISA__` is defined in $(CFLAGS). @@ -31,11 +30,8 @@ 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; diff --git a/nemu/include/macro.h b/nemu/include/macro.h index 041a65a..47f11b0 100644 --- a/nemu/include/macro.h +++ b/nemu/include/macro.h @@ -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,18 +39,17 @@ // 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) @@ -85,46 +84,29 @@ #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) +#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 -#define __EXPORT __attribute__((visibility("default"))) - // for AM IOE -#define io_read(reg) \ - ({ \ - reg##_T __io_param; \ - ioe_read(reg, &__io_param); \ - __io_param; \ - }) +#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); \ - }) +#define io_write(reg, ...) \ + ({ reg##_T __io_param = (reg##_T) { __VA_ARGS__ }; \ + ioe_write(reg, &__io_param); }) #endif diff --git a/nemu/include/nemu.h b/nemu/include/nemu.h deleted file mode 100644 index 505fc52..0000000 --- a/nemu/include/nemu.h +++ /dev/null @@ -1,28 +0,0 @@ -#ifndef __NEMU_HEADER__ -#define __NEMU_HEADER__ - -#include -#ifdef __cplusplus -extern "C" { -#endif -#include -#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__ diff --git a/nemu/include/utils.h b/nemu/include/utils.h index 43c30ad..f974584 100644 --- a/nemu/include/utils.h +++ b/nemu/include/utils.h @@ -20,14 +20,7 @@ // ----------- state ----------- -enum { - NEMU_RUNNING, - NEMU_GDB_INTERRUPT, - NEMU_STOP, - NEMU_END, - NEMU_ABORT, - NEMU_QUIT -}; +enum { NEMU_RUNNING, NEMU_STOP, NEMU_END, NEMU_ABORT, NEMU_QUIT }; typedef struct { int state; @@ -43,41 +36,42 @@ 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 diff --git a/nemu/resource/sdcard/README.md b/nemu/resource/sdcard/README.md index cad435a..80324e0 100644 --- a/nemu/resource/sdcard/README.md +++ b/nemu/resource/sdcard/README.md @@ -38,15 +38,15 @@ @@ -983,6 +983,7 @@ static int card_busy_detect(struct mmc_card *card, unsigned int timeout_ms, int err = 0; u32 status; - + + return err; do { bool done = time_after(jiffies, timeout); - + --- linux/drivers/mmc/core/core.h +++ linux/drivers/mmc/core/core.h @@ -64,6 +64,7 @@ void mmc_set_initial_state(struct mmc_host *host); - + static inline void mmc_delay(unsigned int ms) { + return; diff --git a/nemu/scripts/build.mk b/nemu/scripts/build.mk index f3bfe15..f050197 100644 --- a/nemu/scripts/build.mk +++ b/nemu/scripts/build.mk @@ -22,7 +22,7 @@ CXX := g++ endif LD := $(CXX) INCLUDES = $(addprefix -I, $(INC_PATH)) -CFLAGS := -O2 -MMD -Wall $(INCLUDES) $(CFLAGS) +CFLAGS := -O2 -MMD -Wall -Werror $(INCLUDES) $(CFLAGS) LDFLAGS := -O2 $(LDFLAGS) OBJS = $(SRCS:%.c=$(OBJ_DIR)/%.o) $(CXXSRC:%.cc=$(OBJ_DIR)/%.o) @@ -76,13 +76,8 @@ $(BINARY):: $(OBJS) $(ARCHIVES) @$(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) diff --git a/nemu/src/cpu/cpu-exec.c b/nemu/src/cpu/cpu-exec.c index 312451a..d2b1f98 100644 --- a/nemu/src/cpu/cpu-exec.c +++ b/nemu/src/cpu/cpu-exec.c @@ -13,11 +13,11 @@ * See the Mulan PSL v2 for more details. ***************************************************************************************/ -#include "gdbstub.h" +#include #include #include +#include #include -#include /* The assembly code of instructions executed is only output to the screen * when the number of instructions executed is less than this value. @@ -34,16 +34,13 @@ IFDEF(CONFIG_ITRACE, extern char logbuf[CONFIG_ITRACE_BUFFER][128]); IFDEF(CONFIG_ITRACE, extern int logbuf_rear); void device_update(); +bool wp_eval_all(); static void trace_and_difftest(Decode *_this, vaddr_t dnpc) { #ifdef CONFIG_ITRACE_COND - if (ITRACE_COND) { - log_write("%s\n", logbuf[logbuf_rear]); - } + if (ITRACE_COND) { log_write("%s\n", logbuf[logbuf_rear]); } #endif - if (g_print_step) { - IFDEF(CONFIG_ITRACE, puts(logbuf[logbuf_rear])); - } + if (g_print_step) { IFDEF(CONFIG_ITRACE, puts(logbuf[logbuf_rear])); } IFDEF(CONFIG_DIFFTEST, difftest_step(_this->pc, dnpc)); } @@ -59,13 +56,12 @@ static void exec_once(Decode *s, vaddr_t 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; @@ -73,8 +69,7 @@ static void exec_once(Decode *s, vaddr_t pc) { #ifndef CONFIG_ISA_loongarch32r void disassemble(char *str, int size, uint64_t pc, uint8_t *code, int nbyte); 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); + 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 @@ -83,12 +78,15 @@ 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) + if (wp_eval_all()) { + puts(logbuf[logbuf_rear]); break; + } + if (nemu_state.state != NEMU_RUNNING) break; IFDEF(CONFIG_DEVICE, device_update()); } } @@ -98,12 +96,8 @@ 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() { @@ -115,13 +109,10 @@ 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(); @@ -132,53 +123,18 @@ 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); - if (nemu_state.halt_ret != 0) { - IFDEF(CONFIG_ITRACE, log_itrace_print()); - } - } // 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) { + 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; -} diff --git a/nemu/src/cpu/difftest/dut.c b/nemu/src/cpu/difftest/dut.c new file mode 100644 index 0000000..b003202 --- /dev/null +++ b/nemu/src/cpu/difftest/dut.c @@ -0,0 +1,132 @@ +/*************************************************************************************** +* Copyright (c) 2014-2022 Zihao Yu, Nanjing University +* +* NEMU is licensed under Mulan PSL v2. +* You can use this software according to the terms and conditions of the Mulan PSL v2. +* You may obtain a copy of Mulan PSL v2 at: +* http://license.coscl.org.cn/MulanPSL2 +* +* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, +* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, +* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. +* +* See the Mulan PSL v2 for more details. +***************************************************************************************/ + +#include + +#include +#include +#include +#include +#include + +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 diff --git a/nemu/src/cpu/difftest/ref.c b/nemu/src/cpu/difftest/ref.c new file mode 100644 index 0000000..ef89a61 --- /dev/null +++ b/nemu/src/cpu/difftest/ref.c @@ -0,0 +1,42 @@ +/*************************************************************************************** +* Copyright (c) 2014-2022 Zihao Yu, Nanjing University +* +* NEMU is licensed under Mulan PSL v2. +* You can use this software according to the terms and conditions of the Mulan PSL v2. +* You may obtain a copy of Mulan PSL v2 at: +* http://license.coscl.org.cn/MulanPSL2 +* +* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, +* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, +* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. +* +* See the Mulan PSL v2 for more details. +***************************************************************************************/ + +#include +#include +#include +#include + +__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(); +} diff --git a/nemu/src/device/Kconfig b/nemu/src/device/Kconfig index 18eb789..c4118d6 100644 --- a/nemu/src/device/Kconfig +++ b/nemu/src/device/Kconfig @@ -1,4 +1,5 @@ menuconfig DEVICE + depends on !TARGET_SHARE bool "Devices" default n help diff --git a/nemu/src/device/io/map.c b/nemu/src/device/io/map.c index f170bb0..5ccf508 100644 --- a/nemu/src/device/io/map.c +++ b/nemu/src/device/io/map.c @@ -13,17 +13,17 @@ * See the Mulan PSL v2 for more details. ***************************************************************************************/ -#include #include #include #include +#include #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,25 +33,17 @@ 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() { diff --git a/nemu/src/device/io/port-io.c b/nemu/src/device/io/port-io.c index a2d502d..ba6977b 100644 --- a/nemu/src/device/io/port-io.c +++ b/nemu/src/device/io/port-io.c @@ -13,8 +13,6 @@ * See the Mulan PSL v2 for more details. ***************************************************************************************/ -#include -#include #include #define PORT_IO_SPACE_MAX 65535 @@ -24,19 +22,15 @@ 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 */ diff --git a/nemu/src/device/keyboard.c b/nemu/src/device/keyboard.c index 2ae5d17..da699b5 100644 --- a/nemu/src/device/keyboard.c +++ b/nemu/src/device/keyboard.c @@ -13,10 +13,7 @@ * See the Mulan PSL v2 for more details. ***************************************************************************************/ -#include -#include #include -#include #include #define KEYDOWN_MASK 0x8000 @@ -25,27 +22,28 @@ #include // 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] = {}; @@ -94,11 +92,9 @@ 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()); } diff --git a/nemu/src/device/serial.c b/nemu/src/device/serial.c index dba02f6..b181c5f 100644 --- a/nemu/src/device/serial.c +++ b/nemu/src/device/serial.c @@ -13,11 +13,8 @@ * See the Mulan PSL v2 for more details. ***************************************************************************************/ -#include -#include -#include -#include #include +#include /* http://en.wikibooks.org/wiki/Serial_Programming/8250_UART_Programming */ // NOTE: this is compatible to 16550 @@ -26,6 +23,7 @@ static uint8_t *serial_base = NULL; + static void serial_putc(char ch) { MUXDEF(CONFIG_TARGET_AM, putch(ch), putc(ch, stderr)); } @@ -33,23 +31,21 @@ 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 + } diff --git a/nemu/src/device/timer.c b/nemu/src/device/timer.c index 886ecd6..2aff819 100644 --- a/nemu/src/device/timer.c +++ b/nemu/src/device/timer.c @@ -13,10 +13,8 @@ * See the Mulan PSL v2 for more details. ***************************************************************************************/ -#include -#include #include -#include +#include #include static uint32_t *rtc_port_base = NULL; @@ -42,7 +40,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 diff --git a/nemu/src/engine/interpreter/hostcall.c b/nemu/src/engine/interpreter/hostcall.c index a0ab112..d37d5b5 100644 --- a/nemu/src/engine/interpreter/hostcall.c +++ b/nemu/src/engine/interpreter/hostcall.c @@ -13,19 +13,20 @@ * See the Mulan PSL v2 for more details. ***************************************************************************************/ -#include -#include -#include #include +#include +#include +#include void set_nemu_state(int state, vaddr_t pc, int halt_ret) { - nemu_do_difftest = false; + difftest_skip_ref(); nemu_state.state = state; nemu_state.halt_pc = pc; nemu_state.halt_ret = halt_ret; } -__attribute__((noinline)) void invalid_inst(vaddr_t thispc) { +__attribute__((noinline)) +void invalid_inst(vaddr_t thispc) { uint32_t temp[2]; vaddr_t pc = thispc; temp[0] = inst_fetch(&pc, 4); @@ -33,24 +34,18 @@ __attribute__((noinline)) 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); } diff --git a/nemu/src/engine/interpreter/init.c b/nemu/src/engine/interpreter/init.c index ab07185..a517c3e 100644 --- a/nemu/src/engine/interpreter/init.c +++ b/nemu/src/engine/interpreter/init.c @@ -13,26 +13,15 @@ * See the Mulan PSL v2 for more details. ***************************************************************************************/ -#include "debug.h" #include -#include -int gdbstub_loop(); -extern bool enable_gdbstub; +void sdb_mainloop(); void engine_start() { #ifdef CONFIG_TARGET_AM cpu_exec(-1); #else /* Receive commands from user. */ - int ret = 0; - if (enable_gdbstub) { - if ((ret = gdbstub_loop())) { - Error("gdbstub exited abnormally"); - exit(ret); - } - } else { - cpu_exec(-1); - } + sdb_mainloop(); #endif } diff --git a/nemu/src/filelist.mk b/nemu/src/filelist.mk index 4ae2376..03e05df 100644 --- a/nemu/src/filelist.mk +++ b/nemu/src/filelist.mk @@ -14,12 +14,12 @@ #**************************************************************************************/ SRCS-y += src/nemu-main.c -DIRS-y += src/cpu src/utils +DIRS-y += src/cpu src/monitor src/utils DIRS-$(CONFIG_MODE_SYSTEM) += src/memory DIRS-BLACKLIST-$(CONFIG_TARGET_AM) += src/monitor/sdb SHARE = $(if $(CONFIG_TARGET_SHARE),1,0) -LIBS += $(if $(CONFIG_TARGET_NATIVE_ELF),-lgdbstub -lreadline -ldl -pie,) +LIBS += $(if $(CONFIG_TARGET_NATIVE_ELF),-lreadline -ldl -pie,) ifdef mainargs ASFLAGS += -DBIN_PATH=\"$(mainargs)\" diff --git a/nemu/src/isa/mips32/logo.c b/nemu/src/isa/mips32/logo.c index e3c0968..9fedb02 100644 --- a/nemu/src/isa/mips32/logo.c +++ b/nemu/src/isa/mips32/logo.c @@ -16,62 +16,63 @@ // refer to http://www.patorjk.com/software/taag/#p=display&f=Big&t=Type%20Something%20 /* - _ ____ ___ __ __ _ + _ ____ ___ __ __ _ (_) |___ \__ \ | \/ | | | _ __ ___ _ _ __ ___ __) | ) | | \ / | __ _ _ __ _ _ __ _| | | '_ ` _ \| | '_ \/ __||__ < / / | |\/| |/ _` | '_ \| | | |/ _` | | | | | | | | | |_) \__ \___) / /_ | | | | (_| | | | | |_| | (_| | | |_| |_| |_|_| .__/|___/____/____| |_| |_|\__,_|_| |_|\__,_|\__,_|_| - | | - |_| + | | + |_| */ unsigned char isa_logo[] = { - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x5f, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x5f, 0x5f, 0x5f, 0x5f, 0x20, 0x5f, 0x5f, 0x5f, 0x20, 0x20, 0x20, 0x20, - 0x5f, 0x5f, 0x20, 0x20, 0x5f, 0x5f, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x5f, 0x20, 0x0a, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x28, 0x5f, 0x29, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7c, 0x5f, 0x5f, - 0x5f, 0x20, 0x5c, 0x5f, 0x5f, 0x20, 0x5c, 0x20, 0x20, 0x7c, 0x20, 0x20, - 0x5c, 0x2f, 0x20, 0x20, 0x7c, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x7c, 0x20, 0x7c, 0x0a, 0x20, 0x20, 0x5f, 0x20, - 0x5f, 0x5f, 0x20, 0x5f, 0x5f, 0x5f, 0x20, 0x20, 0x5f, 0x20, 0x5f, 0x20, - 0x5f, 0x5f, 0x20, 0x20, 0x5f, 0x5f, 0x5f, 0x20, 0x20, 0x5f, 0x5f, 0x29, - 0x20, 0x7c, 0x20, 0x29, 0x20, 0x7c, 0x20, 0x7c, 0x20, 0x5c, 0x20, 0x20, - 0x2f, 0x20, 0x7c, 0x20, 0x5f, 0x5f, 0x20, 0x5f, 0x20, 0x5f, 0x20, 0x5f, - 0x5f, 0x20, 0x20, 0x5f, 0x20, 0x20, 0x20, 0x5f, 0x20, 0x20, 0x5f, 0x5f, - 0x20, 0x5f, 0x7c, 0x20, 0x7c, 0x0a, 0x20, 0x7c, 0x20, 0x27, 0x5f, 0x20, - 0x60, 0x20, 0x5f, 0x20, 0x5c, 0x7c, 0x20, 0x7c, 0x20, 0x27, 0x5f, 0x20, - 0x5c, 0x2f, 0x20, 0x5f, 0x5f, 0x7c, 0x7c, 0x5f, 0x5f, 0x20, 0x3c, 0x20, - 0x2f, 0x20, 0x2f, 0x20, 0x20, 0x7c, 0x20, 0x7c, 0x5c, 0x2f, 0x7c, 0x20, - 0x7c, 0x2f, 0x20, 0x5f, 0x60, 0x20, 0x7c, 0x20, 0x27, 0x5f, 0x20, 0x5c, - 0x7c, 0x20, 0x7c, 0x20, 0x7c, 0x20, 0x7c, 0x2f, 0x20, 0x5f, 0x60, 0x20, - 0x7c, 0x20, 0x7c, 0x0a, 0x20, 0x7c, 0x20, 0x7c, 0x20, 0x7c, 0x20, 0x7c, - 0x20, 0x7c, 0x20, 0x7c, 0x20, 0x7c, 0x20, 0x7c, 0x5f, 0x29, 0x20, 0x5c, - 0x5f, 0x5f, 0x20, 0x5c, 0x5f, 0x5f, 0x5f, 0x29, 0x20, 0x2f, 0x20, 0x2f, - 0x5f, 0x20, 0x20, 0x7c, 0x20, 0x7c, 0x20, 0x20, 0x7c, 0x20, 0x7c, 0x20, - 0x28, 0x5f, 0x7c, 0x20, 0x7c, 0x20, 0x7c, 0x20, 0x7c, 0x20, 0x7c, 0x20, - 0x7c, 0x5f, 0x7c, 0x20, 0x7c, 0x20, 0x28, 0x5f, 0x7c, 0x20, 0x7c, 0x20, - 0x7c, 0x0a, 0x20, 0x7c, 0x5f, 0x7c, 0x20, 0x7c, 0x5f, 0x7c, 0x20, 0x7c, - 0x5f, 0x7c, 0x5f, 0x7c, 0x20, 0x2e, 0x5f, 0x5f, 0x2f, 0x7c, 0x5f, 0x5f, - 0x5f, 0x2f, 0x5f, 0x5f, 0x5f, 0x5f, 0x2f, 0x5f, 0x5f, 0x5f, 0x5f, 0x7c, - 0x20, 0x7c, 0x5f, 0x7c, 0x20, 0x20, 0x7c, 0x5f, 0x7c, 0x5c, 0x5f, 0x5f, - 0x2c, 0x5f, 0x7c, 0x5f, 0x7c, 0x20, 0x7c, 0x5f, 0x7c, 0x5c, 0x5f, 0x5f, - 0x2c, 0x5f, 0x7c, 0x5c, 0x5f, 0x5f, 0x2c, 0x5f, 0x7c, 0x5f, 0x7c, 0x0a, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x7c, 0x20, 0x7c, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x0a, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7c, - 0x5f, 0x7c, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x0a, '\0'}; + 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' +}; diff --git a/nemu/src/isa/riscv32/csr.c b/nemu/src/isa/riscv32/csr.c deleted file mode 100644 index 5b9a298..0000000 --- a/nemu/src/isa/riscv32/csr.c +++ /dev/null @@ -1,18 +0,0 @@ -#include - -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]; - } -} diff --git a/nemu/src/isa/riscv32/difftest/dut.c b/nemu/src/isa/riscv32/difftest/dut.c new file mode 100644 index 0000000..06748ce --- /dev/null +++ b/nemu/src/isa/riscv32/difftest/dut.c @@ -0,0 +1,28 @@ +/*************************************************************************************** +* Copyright (c) 2014-2022 Zihao Yu, Nanjing University +* +* NEMU is licensed under Mulan PSL v2. +* You can use this software according to the terms and conditions of the Mulan PSL v2. +* You may obtain a copy of Mulan PSL v2 at: +* http://license.coscl.org.cn/MulanPSL2 +* +* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, +* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, +* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. +* +* See the Mulan PSL v2 for more details. +***************************************************************************************/ + +#include +#include +#include "../local-include/reg.h" + +bool isa_difftest_checkregs(CPU_state *ref_r, vaddr_t pc) { + for(int i = 0; i < MUXDEF(CONFIG_RVE, 16, 32); i++) { + if(!difftest_check_reg(reg_name(i), pc, ref_r->gpr[i], gpr(i))) return false; + } + return true; +} + +void isa_difftest_attach() { +} diff --git a/nemu/src/isa/riscv32/include/isa-def.h b/nemu/src/isa/riscv32/include/isa-def.h index e3f514a..dd0105c 100644 --- a/nemu/src/isa/riscv32/include/isa-def.h +++ b/nemu/src/isa/riscv32/include/isa-def.h @@ -18,13 +18,8 @@ #include -#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); diff --git a/nemu/src/isa/riscv32/inst.c b/nemu/src/isa/riscv32/inst.c index b483b06..1c41c63 100644 --- a/nemu/src/isa/riscv32/inst.c +++ b/nemu/src/isa/riscv32/inst.c @@ -13,89 +13,45 @@ * See the Mulan PSL v2 for more details. ***************************************************************************************/ -#include "isa.h" +#include #include "local-include/reg.h" #include "macro.h" -#include "types.h" -#include #include -#include #include -#include +#include #include #include #define R(i) gpr(i) +#define Mr vaddr_read +#define Mw vaddr_write enum { - TYPE_R, - TYPE_I, - TYPE_I_SHIFT, - TYPE_U, - TYPE_S, - TYPE_B, - TYPE_J, - TYPE_CSR, - TYPE_CSRI, + TYPE_R, TYPE_I, TYPE_I_SHIFT, TYPE_U, TYPE_S, TYPE_B, TYPE_J, 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 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) +#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) 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) { - // 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 + 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; } } @@ -106,23 +62,11 @@ static void do_branch(Decode *s, bool condition, word_t 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) { + if(rs1 == 1 && rd == 0) { ftrace_return(s->pc, dst); } else { ftrace_call(s->pc, dst); @@ -136,159 +80,70 @@ static int decode_exec(Decode *s) { 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("??????? ????? ????? ??? ????? 01101 11", lui, U, R(rd) = imm); - INSTPAT("??????? ????? ????? ??? ????? 00101 11", auipc, U, - R(rd) = s->pc + imm); + INSTPAT("??????? ????? ????? ??? ????? 01101 11", lui , U, R(rd) = imm); + INSTPAT("??????? ????? ????? ??? ????? 00101 11", auipc , U, R(rd) = s->pc + imm); - 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("??????? ????? ????? ??? ????? 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 ????? 00000 11", lb , I, R(rd) = SEXT(Mr(src1 + imm, 1), 8)); + INSTPAT("??????? ????? ????? 001 ????? 00000 11", lh , I, R(rd) = SEXT(Mr(src1 + imm, 2), 16)); + INSTPAT("??????? ????? ????? 010 ????? 00000 11", lw , I, R(rd) = SEXT(Mr(src1 + imm, 4), 32)); + INSTPAT("??????? ????? ????? 100 ????? 00000 11", lbu , I, R(rd) = Mr(src1 + imm, 1)); + INSTPAT("??????? ????? ????? 101 ????? 00000 11", lhu , I, R(rd) = Mr(src1 + imm, 2)); + INSTPAT("??????? ????? ????? 000 ????? 01000 11", sb , S, Mw(src1 + imm, 1, src2)); + INSTPAT("??????? ????? ????? 001 ????? 01000 11", sh , S, Mw(src1 + imm, 2, src2)); + INSTPAT("??????? ????? ????? 010 ????? 01000 11", sw , S, Mw(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("??????? ????? ????? 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 + 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); + 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("??????? ????? ????? ??? ????? ????? ??", inv , N, INV(s->pc)); INSTPAT_END(); R(0) = 0; // reset $zero to 0 diff --git a/nemu/src/isa/riscv32/local-include/csr.h b/nemu/src/isa/riscv32/local-include/csr.h deleted file mode 100644 index 9dfca1c..0000000 --- a/nemu/src/isa/riscv32/local-include/csr.h +++ /dev/null @@ -1,29 +0,0 @@ -#ifndef __NEMU_CSR_H__ -#define __NEMU_CSR_H__ -#include -#include - -#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__ diff --git a/nemu/src/isa/riscv32/logo.c b/nemu/src/isa/riscv32/logo.c index c731672..d693d43 100644 --- a/nemu/src/isa/riscv32/logo.c +++ b/nemu/src/isa/riscv32/logo.c @@ -16,7 +16,7 @@ // refer to http://www.patorjk.com/software/taag/#p=display&f=Big&t=Type%20Something%20 /* - _ __ __ _ + _ __ __ _ (_) | \/ | | | _ __ _ ___ ___ ________ __ | \ / | __ _ _ __ _ _ __ _| | | '__| / __|/ __|______\ \ / / | |\/| |/ _` | '_ \| | | |/ _` | | @@ -25,49 +25,39 @@ */ -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! */ }; diff --git a/nemu/src/isa/riscv32/reg.c b/nemu/src/isa/riscv32/reg.c index f087982..4630df9 100644 --- a/nemu/src/isa/riscv32/reg.c +++ b/nemu/src/isa/riscv32/reg.c @@ -13,21 +13,20 @@ * See the Mulan PSL v2 for more details. ***************************************************************************************/ -#include "local-include/reg.h" -#include "csr.h" -#include "macro.h" -#include -#include #include +#include "local-include/reg.h" +#include "macro.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++) { + 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'); @@ -50,33 +49,3 @@ word_t isa_reg_str2val(const char *s, bool *success) { 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}; diff --git a/nemu/src/isa/riscv32/system/intr.c b/nemu/src/isa/riscv32/system/intr.c index 4fc8c35..3619b59 100644 --- a/nemu/src/isa/riscv32/system/intr.c +++ b/nemu/src/isa/riscv32/system/intr.c @@ -13,14 +13,16 @@ * See the Mulan PSL v2 for more details. ***************************************************************************************/ -#include #include word_t isa_raise_intr(word_t NO, vaddr_t epc) { - write_csr(cpu.csr, MEPC, epc); - write_csr(cpu.csr, MCAUSE, NO); + /* TODO: Trigger an interrupt/exception with ``NO''. + * Then return the address of the interrupt/exception vector. + */ - return read_csr(cpu.csr, MTVEC); + return 0; } -word_t isa_query_intr() { return INTR_EMPTY; } +word_t isa_query_intr() { + return INTR_EMPTY; +} diff --git a/nemu/src/isa/riscv64 b/nemu/src/isa/riscv64 new file mode 120000 index 0000000..4eb3f6d --- /dev/null +++ b/nemu/src/isa/riscv64 @@ -0,0 +1 @@ +riscv32 \ No newline at end of file diff --git a/nemu/src/memory/paddr.c b/nemu/src/memory/paddr.c index 28c7b2b..437debd 100644 --- a/nemu/src/memory/paddr.c +++ b/nemu/src/memory/paddr.c @@ -15,13 +15,12 @@ #include "common.h" #include "debug.h" -#include "utils.h" -#include -#include #include #include +#include +#include -#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 = {}; @@ -32,7 +31,7 @@ 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) { @@ -45,29 +44,22 @@ static void pmem_write(paddr_t addr, int len, word_t data) { } static void out_of_bound(paddr_t addr) { -#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 + 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_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); + if (addr <= mtrace_end[i] && addr >= mtrace_start[i] ) { + Trace("Mem %c " FMT_PADDR "%d D " FMT_PADDR, 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 @@ -75,17 +67,15 @@ void init_mem() { 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;) { + 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"); + 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; + if (!ptr) break; } Trace("MTRACE ranges: "); for (int i = 0; i < range_count; i++) { @@ -93,31 +83,24 @@ void init_mem() { } #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) { 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;) + 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); mtrace: IFDEF(CONFIG_MTRACE, mtrace_print('R', addr, len, result)); - + return result; } void paddr_write(paddr_t addr, int len, word_t data) { IFDEF(CONFIG_MTRACE, mtrace_print('W', addr, len, data)); - if (likely(in_pmem(addr))) { - pmem_write(addr, len, data); - return; - } + if (likely(in_pmem(addr))) { pmem_write(addr, len, data); return; } IFDEF(CONFIG_DEVICE, mmio_write(addr, len, data); return); out_of_bound(addr); } diff --git a/nemu/src/monitor/filelist.mk b/nemu/src/monitor/filelist.mk deleted file mode 100644 index 61231fe..0000000 --- a/nemu/src/monitor/filelist.mk +++ /dev/null @@ -1,4 +0,0 @@ -DIRS-y += src/monitor - -CXXSRC += src/monitor/gdbstub.cc -LIBS += -lgdbstub diff --git a/nemu/src/monitor/gdbstub.cc b/nemu/src/monitor/gdbstub.cc deleted file mode 100644 index 191c0e1..0000000 --- a/nemu/src/monitor/gdbstub.cc +++ /dev/null @@ -1,170 +0,0 @@ -#include "types.h" -#include "utils.h" -#include - -extern "C" { -#include -#include -#include -#include -#include -#include -#include -#include - -typedef struct { - std::vector *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(); - 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; -} -} diff --git a/nemu/src/monitor/monitor.c b/nemu/src/monitor/monitor.c index b4b0dc1..0154208 100644 --- a/nemu/src/monitor/monitor.c +++ b/nemu/src/monitor/monitor.c @@ -13,12 +13,8 @@ * See the Mulan PSL v2 for more details. ***************************************************************************************/ -#include -#include #include #include -#include -#include #include void init_rand(); @@ -26,77 +22,38 @@ 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"); } #ifndef CONFIG_TARGET_AM #include +void sdb_set_batch_mode(); + +static char *log_file = NULL; +static char *elf_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 } - // 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); - } + FILE *fp = fopen(img_file, "rb"); + Assert(fp, "Can not open '%s'", img_file); fseek(fp, 0, SEEK_END); long size = ftell(fp); @@ -113,54 +70,69 @@ 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'}, - {"debug", no_argument, NULL, 'g'}, {"elf", required_argument, NULL, 'f'}, - {"help", no_argument, NULL, 'h'}, {0, 0, NULL, 0}, + {"batch" , no_argument , NULL, 'b'}, + {"log" , required_argument, NULL, 'l'}, + {"diff" , required_argument, NULL, 'd'}, + {"port" , required_argument, NULL, 'p'}, + {"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 '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); + 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 'f': elf_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("\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); - void init_log(const char *log_file); + /* Set random seed. */ + init_rand(); + /* Open the log file. */ init_log(log_file); - /* Perform some global initialization. */ - nemu_init(malloc(nemu_dbg_state_size)); + /* Initialize memory. */ + init_mem(); + + /* Initialize devices. */ + IFDEF(CONFIG_DEVICE, init_device()); + + /* Perform ISA dependent initialization. */ + init_isa(); /* Load the image to memory. This will overwrite the built-in image. */ - load_img(); + long img_size = 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) { + if(elf_file != NULL) { #ifdef CONFIG_FTRACE void init_elf(const char *path); init_elf(elf_file); @@ -170,13 +142,14 @@ void init_monitor(int argc, char *argv[]) { } #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. */ diff --git a/npc/utils/sdb/addrexp.l b/nemu/src/monitor/sdb/addrexp.l similarity index 70% rename from npc/utils/sdb/addrexp.l rename to nemu/src/monitor/sdb/addrexp.l index d81f0e1..d814ee3 100644 --- a/npc/utils/sdb/addrexp.l +++ b/nemu/src/monitor/sdb/addrexp.l @@ -1,10 +1,8 @@ %{ - #include - #include - #include "addrexp.h" + #include + #include static bool success = false; - void yyerror(word_t *result, const char *err); - word_t reg_str2val(const char *name, bool*); + void yyerror(word_t *result, const char *err); %} %option noyywrap @@ -13,7 +11,7 @@ 0[xX][0-9a-fA-F]+ { yylval = strtoul(yytext, NULL, 16); return HEX_NUMBER; } [0-9]+ { yylval = strtoul(yytext, NULL, 10); return NUMBER; } $[asgprt$][0-9pa][0-9]? { - yylval = reg_str2val(yytext + 1, &success); + yylval = isa_reg_str2val(yytext + 1, &success); if(!success) { yyerror(NULL, "Failed to convert reg to value"); return YYerror; diff --git a/npc/utils/sdb/addrexp.y b/nemu/src/monitor/sdb/addrexp.y similarity index 75% rename from npc/utils/sdb/addrexp.y rename to nemu/src/monitor/sdb/addrexp.y index 477d8dd..4094e0b 100644 --- a/npc/utils/sdb/addrexp.y +++ b/nemu/src/monitor/sdb/addrexp.y @@ -1,17 +1,19 @@ %code requires { - #include + #include + #include #include #include extern int yylex(void); } %{ - #include + #include + #include + #include #include #include void yyerror(word_t *result, const char *err) { - fprintf(stderr, "%s", err); + Error("%s", err); } - int pmem_read(int raddr); %} %token NUMBER HEX_NUMBER @@ -22,7 +24,6 @@ %parse-param { uint32_t *result } %left '-' '+' %left '*' '/' -%expect 68 %% input @@ -39,21 +40,21 @@ expression | expression '<' expression { $$ = ($1 < $3); } | expression '+' expression { $$ = $1 + $3; } | expression '-' expression { $$ = $1 - $3; } - | expression '*' expression { $$ = $1 * $3; } + | expression '*' expression { $$ = $1 * $3; } | expression '/' expression { if($3 == 0) { - fprintf(stderr, "Error: divide by zero at" FMT_WORD " / " FMT_WORD "\n", $1, $3); + fprintf(stderr, "Error: divide by zero at %u / %u\n", $1, $3); YYABORT; }; $$ = $1 / $3; } | '-' number { $$ = -$2; } - | '*' expression { $$ = pmem_read($2); } + | '*' expression { $$ = vaddr_read($2, WORD_BYTES); } | '(' expression ')' { $$ = $2; } number : REGISTER - | NUMBER - | HEX_NUMBER + | NUMBER + | HEX_NUMBER %% diff --git a/nemu/src/monitor/sdb/filelist.mk b/nemu/src/monitor/sdb/filelist.mk new file mode 100644 index 0000000..f477a4f --- /dev/null +++ b/nemu/src/monitor/sdb/filelist.mk @@ -0,0 +1,2 @@ +SRCS-y += src/monitor/sdb/addrexp.tag.c src/monitor/sdb/addrexp.yy.c +LFLAGS += -DYY_NO_UNPUT -DYY_NO_INPUT diff --git a/nemu/src/monitor/sdb/sdb.c b/nemu/src/monitor/sdb/sdb.c new file mode 100644 index 0000000..3b56172 --- /dev/null +++ b/nemu/src/monitor/sdb/sdb.c @@ -0,0 +1,361 @@ +/*************************************************************************************** + * Copyright (c) 2014-2022 Zihao Yu, Nanjing University + * + * NEMU is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan + *PSL v2. You may obtain a copy of Mulan PSL v2 at: + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY + *KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO + *NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * + * See the Mulan PSL v2 for more details. + ***************************************************************************************/ + +#include "sdb.h" +#include "common.h" +#include "sys/types.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static int is_batch_mode = false; + +// command handlers +static int cmd_help(char *args); +static int cmd_c(char *args); +static int cmd_p(char *args); +static int cmd_q(char *args); +static int cmd_w(char *args); +static int cmd_x(char *args); +static int cmd_si(char *args); +static int cmd_info(char *args); +static int cmd_info_r(char *args); +static int cmd_info_w(char *args); + +static struct CommandTable { + const char *name; + const char *description; + int (*handler)(char *); + struct CommandTable *subcommand; + int nr_subcommand; +} cmd_info_table[] = + { + {"r", "List all registers and their contents", cmd_info_r, NULL, 0}, + {"w", "Status of specified watchpoints", cmd_info_w, NULL, 0}, +}, + cmd_table[] = { + {"help", "Display information about all supported commands", cmd_help, + NULL, 0}, + {"c", "Continue the execution of the program", cmd_c, NULL, 0}, + {"p", "Print expression result", cmd_p, NULL, 0}, + {"q", "Exit NEMU", cmd_q, NULL, 0}, + {"x", "Examine content of physical memory address", cmd_x, NULL, 0}, + {"w", "Break when expression is changed", cmd_w, NULL, 0}, + {"si", "Execute next [n] program line", cmd_si, NULL, 0}, + {"info", "Print information of registers or watchpoints", cmd_info, + cmd_info_table, ARRLEN(cmd_info_table)}, +}; + +#define NR_CMD ARRLEN(cmd_table) + +void init_regex(); +void init_wp_pool(); + +/* We use the `readline' library to provide more flexibility to read from stdin. + */ +static char *rl_gets() { + static char *line_read = NULL; + + if (line_read) { + free(line_read); + line_read = NULL; + } + + line_read = readline("\e[1;34m(nemu)\e[0m "); + + if (line_read && *line_read) { + add_history(line_read); + } + + return line_read; +} + +/* Extract Integer from a string. Can handle hex, binary and decimal numbers. + * Print error if meet any error. + * Return `UINTMAX_MAX` if the string is invalid or number exceed the limit of + * uint. + */ +static word_t parse_uint(const char *arg, bool *success) { + if (arg == NULL) { + puts("Invalid uint argument."); + *success = false; + return 0; + } + int base = 10; + int token_length = strnlen(arg, 34); + if (token_length > 2) { + if (arg[0] == '0' && (arg[1] == 'b' || arg[1] == 'B')) { + base = 2; + arg = arg + 2; + } else if (arg[0] == '0' && (arg[1] == 'x' || arg[1] == 'X')) { + base = 16; + arg = arg + 2; + } + } + char *endptr; + uintmax_t n = strtoumax(arg, &endptr, base); + if (errno == ERANGE || n > WORD_T_MAX) { + printf("%s exceed the limit of uint\n", arg); + *success = false; + return 0; + } else if (arg == endptr) { + puts("Invalid uint argument."); + *success = false; + return 0; + } else if (n > WORD_T_MAX) { + *success = false; + return WORD_T_MAX; + } else { + *success = true; + return n; + } +} + +word_t parse_expr(const char *arg, bool *success) { + if (arg == NULL) { + puts("Invalid expr argument."); + *success = false; + return 0; + } else { + word_t res; + yy_scan_string(arg); + *success = !yyparse(&res); + yylex_destroy(); + return res; + } +} + +static int cmd_c(char *args) { + cpu_exec(-1); + return 0; +} + +static int cmd_p(char *args) { + char *arg = strtok(NULL, ""); + bool res = false; + + word_t result = parse_expr(arg, &res); + if (!res) + goto wrong_usage; + printf("%s: %u\n", arg, result); + return 0; + +wrong_usage: + printf("Invalid argument for command p: %s\n", arg); + printf("Usage: p [EXPR: ]\n"); + return 0; +} + +static int cmd_q(char *args) { + nemu_state.state = NEMU_QUIT; + return -1; +} + +/* Single stepping + * : execute step + */ +static int cmd_si(char *args) { + char *arg = strtok(NULL, " "); + if (arg == NULL) { + cpu_exec(1); + } else { + bool res = false; + word_t n = parse_uint(arg, &res); + if (!res) + goto wrong_usage; + cpu_exec(n); + } + return 0; + +wrong_usage: + printf("Invalid argument for command si: %s\n", args); + printf("Usage: si [N: uint]\n"); + return 0; +} + +static int cmd_info_r(char *args) { + isa_reg_display(); + return 0; +} + +static int cmd_info_w(char *args) { + printf("Not implemented"); + return 0; +} + +static int cmd_w(char *args) { + char *expr = strtok(NULL, ""); + wp_add(expr); + return 0; +} + +static int cmd_x(char *args) { + char *arg = strtok(NULL, " "); + bool res = false; + word_t n = parse_uint(arg, &res); + if (!res) + goto wrong_usage; + // No deliminter here, just pass all the remain argument to `parse_expr()` + arg = strtok(NULL, ""); + word_t start_addr = parse_expr(arg, &res); + if (!res) + goto wrong_usage; + start_addr = start_addr & ~(WORD_BYTES - 1); + for (vaddr_t vaddr = start_addr; vaddr < start_addr + n; vaddr += WORD_BYTES) { + word_t value = vaddr_read(vaddr, WORD_BYTES); + printf("\e[1;34m" FMT_PADDR "\e[0m" + " " FMT_WORD "\n", + vaddr, value); + } + return 0; + +wrong_usage: + printf("Invalid argument for command x: %s\n", arg); + printf("Usage: x [N: uint] [EXPR: ]\n"); + return 0; +} + +static int cmd_info(char *args) { + char *arg = strtok(NULL, " "); + int i; + if (arg == NULL) { + goto wrong_usage; + return 0; + } + for (i = 0; i < ARRLEN(cmd_info_table); i++) { + if (strcmp(arg, cmd_info_table[i].name) == 0) { + cmd_info_table[i].handler(args); + return 0; + } + } + +wrong_usage: + printf("Invalid argument for command info: %s\n", args); + printf("Usage: info [r | w]\n"); + return 0; +} + +static int cmd_help_print(char *args, struct CommandTable *cur_cmd_table, + int cur_nr_cmd) { + int i; + char *arg = strtok(NULL, " "); + if (arg == NULL) { + return -1; + } else { + for (i = 0; i < cur_nr_cmd; i++) { + if (strcmp(arg, cur_cmd_table[i].name) == 0) { + printf("%s ", cur_cmd_table[i].name); + if (cmd_help_print(arg, cur_cmd_table[i].subcommand, + cur_cmd_table[i].nr_subcommand) == -1) { + printf("-- %s\n", cur_cmd_table[i].description); + } + return 0; + } + } + return -1; + } +} + +static int cmd_help(char *args) { + /* extract the first argument */ + char *arg = strtok(NULL, " "); + int i; + + if (arg == NULL) { + /* no argument given */ + for (i = 0; i < NR_CMD; i++) { + printf("%s -- %s\n", cmd_table[i].name, cmd_table[i].description); + } + } else { + for (i = 0; i < NR_CMD; i++) { + if (strcmp(arg, cmd_table[i].name) == 0) { + printf("%s ", cmd_table[i].name); + if (cmd_help_print(args, cmd_table[i].subcommand, + cmd_table[i].nr_subcommand) == -1) { + printf("-- %s\n", cmd_table[i].description); + // Print available subcommands + for (int j = 0; j < cmd_table[i].nr_subcommand; j++) { + struct CommandTable *sub_cmd_table = cmd_table[i].subcommand; + printf(" > %s -- %s\n", sub_cmd_table[j].name, + sub_cmd_table[j].description); + } + } + return 0; + } + } + printf("Unknown command '%s'\n", arg); + } + return 0; +} + +void sdb_set_batch_mode() { is_batch_mode = true; } + +void sdb_mainloop() { + if (is_batch_mode) { + cmd_c(NULL); + return; + } + + for (char *str; (str = rl_gets()) != NULL;) { + char *str_end = str + strlen(str); + + /* extract the first token as the command */ + char *cmd = strtok(str, " "); + if (cmd == NULL) { + continue; + } + + /* treat the remaining string as the arguments, + * which may need further parsing + */ + char *args = cmd + strlen(cmd) + 1; + if (args >= str_end) { + args = NULL; + } + +#ifdef CONFIG_DEVICE + extern void sdl_clear_event_queue(); + sdl_clear_event_queue(); +#endif + + int i; + for (i = 0; i < NR_CMD; i++) { + if (strcmp(cmd, cmd_table[i].name) == 0) { + if (cmd_table[i].handler(args) < 0) { + return; + } + break; + } + } + + if (i == NR_CMD) { + printf("Unknown command '%s'\n", cmd); + } + } +} + +void init_sdb() { + // /* Compile the regular expressions. */ + // init_regex(); + + /* Initialize the watchpoint pool. */ + init_wp_pool(); +} diff --git a/nemu/src/monitor/sdb/sdb.h b/nemu/src/monitor/sdb/sdb.h new file mode 100644 index 0000000..883f1b6 --- /dev/null +++ b/nemu/src/monitor/sdb/sdb.h @@ -0,0 +1,25 @@ +/*************************************************************************************** +* Copyright (c) 2014-2022 Zihao Yu, Nanjing University +* +* NEMU is licensed under Mulan PSL v2. +* You can use this software according to the terms and conditions of the Mulan PSL v2. +* You may obtain a copy of Mulan PSL v2 at: +* http://license.coscl.org.cn/MulanPSL2 +* +* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, +* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, +* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. +* +* See the Mulan PSL v2 for more details. +***************************************************************************************/ + +#ifndef __SDB_H__ +#define __SDB_H__ + +#include + +word_t parse_expr(const char *arg, bool *success); +int wp_add(char * expr); +int wp_remove_by_number(int number); + +#endif diff --git a/nemu/src/monitor/sdb/watchpoint.c b/nemu/src/monitor/sdb/watchpoint.c new file mode 100644 index 0000000..aa48d78 --- /dev/null +++ b/nemu/src/monitor/sdb/watchpoint.c @@ -0,0 +1,150 @@ +/*************************************************************************************** + * Copyright (c) 2014-2022 Zihao Yu, Nanjing University + * + * NEMU is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan + *PSL v2. You may obtain a copy of Mulan PSL v2 at: + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY + *KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO + *NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * + * See the Mulan PSL v2 for more details. + ***************************************************************************************/ + +#include "sdb.h" +#include +#include + +#define NR_WP 32 + +typedef struct watchpoint { + int NO; + struct watchpoint *next; + word_t val; + char *expr; +} WP; + +static WP wp_pool[NR_WP] = {}; +static WP *head = NULL, *tail = NULL, *free_ = NULL; +static int wp_count = 0; + +void init_wp_pool() { + int i; + for (i = 0; i < NR_WP; i++) { + wp_pool[i].NO = i; + wp_pool[i].next = (i == NR_WP - 1 ? NULL : &wp_pool[i + 1]); + } + + head = NULL; + free_ = wp_pool; +} + +static WP *wp_new() { + if (free_ == NULL) { + Error("wp_pool: Watchpoint pool not initialized or is full."); + return NULL; + } + + WP *ret = free_; + free_ = free_->next; + + ret->NO = 0; + ret->next = NULL; + return ret; +} + +static void wp_delete(WP *wp) { + Assert(wp, "Failed to delete watchpoint from pool."); + wp->next = free_; + free_ = wp; +} + +int wp_add(char * expr) { + WP *wp = wp_new(); + if (wp == NULL) { + Error("watchpoint: Failed to add watchpoint, pool is full."); + goto failed_create; + } + + wp->NO = wp_count++; + if (tail == NULL) { + head = wp; + tail = wp; + } else { + tail->next = wp; + tail = wp; + } + + bool success = false; + wp->val = parse_expr(expr, &success); + if (!success) { + Error("Failed to parse given expression `%s`", expr); + goto failed_create; + } + + int len = strlen(expr); + wp->expr = malloc((len + 1) * sizeof(char)); + if (wp->expr == NULL) { + Error("Failed to allocate memory for expression"); + goto failed_create; + } + strncpy(wp->expr, expr, len + 1); + wp->expr[len] = '\0'; + return 0; + +failed_create: + wp_delete(wp); + return 1; +} + +int wp_remove_by_number(int number) { + WP *target_prev; + // Find previous node of target number + for (target_prev = head; target_prev != NULL && target_prev->next->NO != number; target_prev = target_prev->next) ; + if (target_prev == NULL) { + Error("Watchpoint not found, you can check current watchpoints with `info w`"); + return 1; + } + WP *target = target_prev->next; + target_prev->next = target->next; + if (target == head) { + head = target->next; + } else if (target == tail) { + tail = target_prev; + } + wp_delete(target); + return 0; +} + +static bool wp_check_change(WP* wp) { + bool success = false; + word_t result; + + result = parse_expr(wp->expr, &success); + if (!success) { + panic("Failed to evaluate expression `%s`", wp->expr); + } + if (result != wp->val) { + wp->val = result; + return true; + } + return false; +} + +/* + Check if watchpoint value changed after execution +*/ +bool wp_eval_all() { + WP *wp; + bool value_change = false; + for (wp = head; wp != NULL; wp = wp->next) { + int prev_val = wp->val; + if (wp_check_change(wp)) { + printf("Watchpoint %d: %s\n %u -> %u\n", wp->NO, wp->expr, prev_val, wp->val); + value_change = true; + } + } + return value_change; +} diff --git a/nemu/src/utils/disasm.cc b/nemu/src/utils/disasm.cc index fc3e28e..7d98c2e 100644 --- a/nemu/src/utils/disasm.cc +++ b/nemu/src/utils/disasm.cc @@ -59,8 +59,7 @@ extern "C" void init_disasm(const char *triple) { llvm::MCRegisterInfo *gMRI = nullptr; auto target = llvm::TargetRegistry::lookupTarget(gTriple, errstr); if (!target) { - llvm::errs() << "Can't find target for " << gTriple << ": " << errstr - << "\n"; + llvm::errs() << "Can't find target for " << gTriple << ": " << errstr << "\n"; assert(0); } @@ -78,24 +77,22 @@ extern "C" void init_disasm(const char *triple) { gMRI = target->createMCRegInfo(gTriple); auto AsmInfo = target->createMCAsmInfo(*gMRI, gTriple, MCOptions); #if LLVM_VERSION_MAJOR >= 13 - auto llvmTripleTwine = Twine(triple); - auto llvmtriple = llvm::Triple(llvmTripleTwine); - auto Ctx = new llvm::MCContext(llvmtriple, AsmInfo, gMRI, nullptr); + auto llvmTripleTwine = Twine(triple); + auto llvmtriple = llvm::Triple(llvmTripleTwine); + auto Ctx = new llvm::MCContext(llvmtriple,AsmInfo, gMRI, nullptr); #else - auto Ctx = new llvm::MCContext(AsmInfo, gMRI, nullptr); + auto Ctx = new llvm::MCContext(AsmInfo, gMRI, nullptr); #endif gDisassembler = target->createMCDisassembler(*gSTI, *Ctx); gIP = target->createMCInstPrinter(llvm::Triple(gTriple), - AsmInfo->getAssemblerDialect(), *AsmInfo, - *gMII, *gMRI); + AsmInfo->getAssemblerDialect(), *AsmInfo, *gMII, *gMRI); gIP->setPrintImmHex(true); gIP->setPrintBranchImmAsAddress(true); if (isa == "riscv32" || isa == "riscv64") gIP->applyTargetSpecificCLOption("no-aliases"); } -extern "C" void disassemble(char *str, int size, uint64_t pc, uint8_t *code, - int nbyte) { +extern "C" void disassemble(char *str, int size, uint64_t pc, uint8_t *code, int nbyte) { MCInst inst; llvm::ArrayRef arr(code, nbyte); uint64_t dummy_size = 0; diff --git a/nemu/src/utils/filelist.mk b/nemu/src/utils/filelist.mk index 2537b81..bcd69c5 100644 --- a/nemu/src/utils/filelist.mk +++ b/nemu/src/utils/filelist.mk @@ -14,7 +14,7 @@ #**************************************************************************************/ ifneq ($(CONFIG_ITRACE)$(CONFIG_IQUEUE),) -CXXSRC += src/utils/disasm.cc +CXXSRC = src/utils/disasm.cc CXXFLAGS += $(shell llvm-config --cxxflags) -fPIE LIBS += $(shell llvm-config --libs) endif diff --git a/nemu/src/utils/ftrace.c b/nemu/src/utils/ftrace.c index 228eb34..a522be7 100644 --- a/nemu/src/utils/ftrace.c +++ b/nemu/src/utils/ftrace.c @@ -17,12 +17,10 @@ static int cmp_func_t(const void *a, const void *b) { static func_t *get_func(vaddr_t addr) { int l = 0, r = func_table_len - 1; - while (l <= r) { + while(l <= r) { int mid = (l + r) / 2; - if (func_table[mid].start <= addr) - l = mid + 1; - else - r = mid - 1; + if(func_table[mid].start <= addr) l = mid + 1; + else r = mid - 1; } return l == 0 ? NULL : &func_table[l - 1]; } @@ -35,27 +33,20 @@ void init_elf(const char *path) { func_table = (func_t *)calloc(func_table_size, sizeof(func_t)); assert(func_table); - FAILED_GOTO(failed_header, - fread(&header, sizeof(Elf32_Ehdr), 1, elf_file) <= 0); + FAILED_GOTO(failed_header, fread(&header, sizeof(Elf32_Ehdr), 1, elf_file) <= 0); FAILED_GOTO(failed_header, fseek(elf_file, header.e_shoff, SEEK_SET) != 0); - FAILED_GOTO(failed_header, fread(section_header, header.e_shentsize, - header.e_shnum, elf_file) <= 0); + FAILED_GOTO(failed_header, fread(section_header, header.e_shentsize, header.e_shnum, elf_file) <= 0); char *shstrtab = calloc(1, section_header[header.e_shstrndx].sh_size); - FAILED_GOTO(failed_shstrtab, - fseek(elf_file, section_header[header.e_shstrndx].sh_offset, - SEEK_SET) != 0); - FAILED_GOTO(failed_shstrtab, - fread(shstrtab, section_header[header.e_shstrndx].sh_size, 1, - elf_file) <= 0); + FAILED_GOTO(failed_shstrtab, fseek(elf_file, section_header[header.e_shstrndx].sh_offset, SEEK_SET) != 0); + FAILED_GOTO(failed_shstrtab, fread(shstrtab, section_header[header.e_shstrndx].sh_size, 1, elf_file) <= 0); Elf32_Shdr *symtab = NULL, *strtab = NULL; - for (int i = 0; i < header.e_shnum; i++) { + for(int i = 0; i < header.e_shnum; i++) { psh = section_header + i; if (psh->sh_type == SHT_SYMTAB) { symtab = psh; - } else if (psh->sh_type == SHT_STRTAB && - strncmp(shstrtab + psh->sh_name, ".strtab", 8) == 0) { + } else if (psh->sh_type == SHT_STRTAB && strncmp(shstrtab + psh->sh_name, ".strtab", 8) == 0) { strtab = psh; } } @@ -63,28 +54,22 @@ void init_elf(const char *path) { int sym_length = symtab->sh_size / sizeof(Elf32_Sym); Elf32_Sym *sym = calloc(sym_length, sizeof(Elf32_Sym)); assert(sym); - FAILED_GOTO(failed_funcname, - fseek(elf_file, symtab->sh_offset, SEEK_SET) != 0); - FAILED_GOTO(failed_funcname, - fread(sym, sizeof(Elf32_Sym), sym_length, elf_file) <= 0); - - for (int j = 0; j < sym_length; j++) { - if (ELF32_ST_TYPE(sym[j].st_info) != STT_FUNC) - continue; + FAILED_GOTO(failed_funcname, fseek(elf_file, symtab->sh_offset, SEEK_SET) != 0); + FAILED_GOTO(failed_funcname, fread(sym, sizeof(Elf32_Sym), sym_length, elf_file) <= 0); + + for(int j = 0; j < sym_length; j++) { + if(ELF32_ST_TYPE(sym[j].st_info) != STT_FUNC) continue; // Only read function type symbol func_t *f = &func_table[func_table_len]; char *func = (char *)malloc(30); - FAILED_GOTO(failed_funcname, - fseek(elf_file, strtab->sh_offset + sym[j].st_name, SEEK_SET) != - 0); + FAILED_GOTO(failed_funcname, fseek(elf_file, strtab->sh_offset + sym[j].st_name, SEEK_SET) != 0); FAILED_GOTO(failed_funcname, fgets(func, 30, elf_file) <= 0); f->start = sym[j].st_value; f->len = sym[j].st_size; f->name = func; ++func_table_len; - if (func_table_len >= func_table_size) { - Assert(func_table_size * 2 > func_table_size, - "Function table exceed memory limit"); + if(func_table_len >= func_table_size) { + Assert(func_table_size * 2 > func_table_size, "Function table exceed memory limit"); func_table_size *= 2; func_table = realloc(func_table, func_table_size * sizeof(func_t)); Assert(func_table, "Function table exceed memory limit"); @@ -103,12 +88,10 @@ failed_funcname: failed_shstrtab: free(shstrtab); failed_header: - for (int i = 0; i < func_table_len; i++) { + for(int i = 0; i < func_table_len; i++) { func_t *f = &func_table[i]; - if (f->name) { - free(f->name); - } - } + if(f->name) { free(f->name); } + } free(func_table); Error("Failed reading elf file"); return; @@ -131,12 +114,11 @@ void ftrace_return(vaddr_t pc, vaddr_t addr) { ftrace_stack_len--) { vaddr_t tco_addr = ftrace_stack[ftrace_stack_len]; func_t *f = get_func(tco_addr); - Trace("%*s0x%x ret 0x%x <%s+0x%x> (TCO)", ftrace_stack_len, "", pc, - tco_addr, f == NULL ? "???" : f->name, - f == NULL ? addr : addr - f->start); + Trace("%*s0x%x ret 0x%x <%s+0x%x> (TCO)", ftrace_stack_len, "", pc, tco_addr, + f == NULL ? "???" : f->name, f == NULL ? addr : addr - f->start); } func_t *f = get_func(addr); - Trace("%*s0x%x ret 0x%x <%s+0x%x>", ftrace_stack_len, "", pc, addr, + Trace("%*s0x%x ret 0x%x <%s+0x%x>", ftrace_stack_len, "", pc, addr, f == NULL ? "???" : f->name, f == NULL ? addr : addr - f->start); } #endif diff --git a/nemu/tests/Makefile b/nemu/tests/Makefile index ffbe26f..2e8c784 100644 --- a/nemu/tests/Makefile +++ b/nemu/tests/Makefile @@ -1,9 +1,10 @@ -TEST_SRCS += +TEST_SRCS += tests/expr_test.c +YACC = bison $(OBJ_DIR)/%: %.c $(TEST_OBJS) app @mkdir -p $(dir $@) @echo + CC $< - @$(CC) $(CFLAGS) -o $@.o -c $< + @$(CC) $(CFLAGS) -o $@.o -c $< @echo + LD $@ @$(LD) $(LIBS) $(LDFLAGS) -o $@ $(TEST_OBJS) $@.o @$@ diff --git a/nemu/tests/expr_test.c b/nemu/tests/expr_test.c new file mode 100644 index 0000000..d581cf2 --- /dev/null +++ b/nemu/tests/expr_test.c @@ -0,0 +1,244 @@ +#include "macro.h" +#include "sys/types.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +char buf[65536] = {}, ref_buf[65536] = {}; +static char code_buf[65536 + 128] = {}; // a little larger than `buf` +const int buf_start_pos = 0; +char *buf_ptr = buf + buf_start_pos, *ref_buf_ptr = ref_buf; +static char *code_format = "#include \n" + "#include \n" + "int main() { " + " uint32_t result = %s; " + " printf(\"%%u\", result); " + " return 0; " + "}"; + +void gen(char c) { + *(buf_ptr++) = c; + *(ref_buf_ptr++) = c; +} + +void gen_num(void) { + uint32_t num = rand(); + int len = 0, ref_len = 0; + switch (rand() % 3) { + case 0: + len = snprintf(buf_ptr, 100, "%u", num); + ref_len = snprintf(ref_buf_ptr, 100, "%uU", num); + break; + case 1: + len = snprintf(buf_ptr, 100, "0x%x", num); + ref_len = snprintf(ref_buf_ptr, 100, "%uU", num); + break; + case 2: + len = snprintf(buf_ptr, 100, "%d", num); + ref_len = snprintf(ref_buf_ptr, 100, "%d", num); + break; + default: + assert(0); + } + buf_ptr += len; + ref_buf_ptr += ref_len; +} + +void gen_rand_op(void) { + switch (rand() % 4) { + case 0: + gen('+'); + break; + case 1: + gen('-'); + break; + case 2: + gen('*'); + break; + case 3: + gen('/'); + break; + } +} + +void gen_rand_expr(void) { + int choice = rand() % 3; + if (buf_ptr - buf > 2000) { + choice = 0; + } + switch (choice) { + case 0: + gen_num(); + break; + case 1: + gen('('); + gen_rand_expr(); + gen(')'); + break; + default: + gen_rand_expr(); + gen(' '); + gen_rand_op(); + gen(' '); + gen_rand_expr(); + break; + } +} + +START_TEST(test_expr_random_100) { + srand(time(0) + _i * 100); + gen_rand_expr(); + + sprintf(code_buf, code_format, ref_buf); + + FILE *fp = fopen("/tmp/.code.c", "w"); + ck_assert(fp != NULL); + fputs(code_buf, fp); + fclose(fp); + + int ret = + system("gcc /tmp/.code.c -Werror=div-by-zero -o /tmp/.expr 2>/dev/null"); + if (ret == 256) { + // Probably devide by zero. Skip + goto clean_up; + } + ck_assert_msg(!ret, "system ret: %d, error: %s", ret, strerror(ret)); + + fp = popen("/tmp/.expr", "r"); + ck_assert(fp != NULL); + + uint32_t reference; + ret = fscanf(fp, "%u", &reference); + ck_assert(ret == 1); + pclose(fp); + // fprintf(stderr, "\n\tbuf = %s\n\taddr = %u, reference = %u", buf, addr, + // reference); + + yy_scan_string(buf + buf_start_pos); + uint32_t addr; + ck_assert(!yyparse(&addr)); + yylex_destroy(); + + ck_assert_msg(addr == reference, + "\n\tbuf = %s\n\t(addr = %u) != (reference = %u)\n", buf, addr, + reference); + +clean_up: + while (buf_ptr != buf + buf_start_pos) { + *(--buf_ptr) = '\0'; + } + while (ref_buf_ptr != ref_buf) { + *(--ref_buf_ptr) = '\0'; + } +} +END_TEST + +struct { + const char *expr; + uint32_t reference; +} exprs[] = { + {"-1", 0xFFFFFFFFU}, + {"-0x1", 0xFFFFFFFFU}, + {"0--1", 0x1}, + {"0--0x1", 0x1}, +}, reg_exprs[] = { + {"$ra", 0x1}, + {"0x2 + 4*-$a7", 0xFFFFFFBEU}, + {"0x1831/$gp + 13", 2077U}, + {"$$0 == 123", 0}, + {"$$0 == 0", 1}, +}; +START_TEST(test_expr_negative_operand) { + yy_scan_string(exprs[_i].expr); + uint32_t addr; + ck_assert(!yyparse(&addr)); + yylex_destroy(); + + ck_assert_msg(addr == exprs[_i].reference, + "\n\texpr = %s\n\t(addr = %u) != (reference = %u)\n", exprs[_i].expr, + addr, exprs[_i].reference); +} +END_TEST + +extern const char *regs[]; +START_TEST(test_expr_plain_register) { + int i, j, result; + char buf[30] = {}; + uint32_t value; + // NOTE: need to fix this if want to support more arch + buf[0] = '$'; + for (i = 0; i < 32; i++) { + ck_assert(strncpy(buf + 1, regs[i], 10) != NULL); + gpr(i) = i; + yy_scan_string(buf); + result = yyparse(&value); + yylex_destroy(); + ck_assert_msg(result == 0, "expr = %s\n", buf); + + ck_assert(value == i); + for (j = 1; j < 10; j++) { + buf[j] = '\0'; + } + } + +} +END_TEST + +START_TEST(test_expr_register) { + int i; + uint32_t value; + for (i = 0; i < 32; i++) { + gpr(i) = i; + } + + yy_scan_string(reg_exprs[_i].expr); + ck_assert(!yyparse(&value)); + yylex_destroy(); + + ck_assert_msg(value == reg_exprs[_i].reference, + "\n\texpr = %s\n\t(addr = %u) != (reference = %u)\n", reg_exprs[_i].expr, + value, reg_exprs[_i].reference); +} +END_TEST + +Suite *expr_suite(void) { + Suite *s; + TCase *tc_core; + + s = suite_create("Expr test"); + tc_core = tcase_create("Core"); + + tcase_add_loop_test(tc_core, test_expr_random_100, 0, 20); + tcase_add_loop_test(tc_core, test_expr_negative_operand, 0, + sizeof(exprs) / sizeof(exprs[0])); + tcase_add_loop_test(tc_core, test_expr_register, 0, + sizeof(reg_exprs) / sizeof(reg_exprs[0])); + tcase_add_test(tc_core, test_expr_plain_register); + suite_add_tcase(s, tc_core); + + return s; +} + +int main(void) { + int number_failed; + Suite *s; + SRunner *sr; + + s = expr_suite(); + sr = srunner_create(s); + + srunner_run_all(sr, CK_NORMAL); + number_failed = srunner_ntests_failed(sr); + srunner_free(sr); + + return (number_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE; +} diff --git a/nemu/tools/qemu-diff/include/isa.h b/nemu/tools/qemu-diff/include/isa.h index 9f1f9e6..3637206 100644 --- a/nemu/tools/qemu-diff/include/isa.h +++ b/nemu/tools/qemu-diff/include/isa.h @@ -18,14 +18,14 @@ #if defined(CONFIG_ISA_mips32) #define ISA_QEMU_BIN "qemu-system-mipsel" -#define ISA_QEMU_ARGS \ - "-machine", "mipssim", "-kernel", NEMU_HOME "/resource/mips-elf/mips.dummy", +#define ISA_QEMU_ARGS "-machine", "mipssim",\ + "-kernel", NEMU_HOME "/resource/mips-elf/mips.dummy", #elif defined(CONFIG_ISA_riscv) && !defined(CONFIG_RV64) #define ISA_QEMU_BIN "qemu-system-riscv32" #define ISA_QEMU_ARGS "-bios", "none", #elif defined(CONFIG_ISA_riscv) && defined(CONFIG_RV64) #define ISA_QEMU_BIN "qemu-system-riscv64" -#define ISA_QEMU_ARGS +#define ISA_QEMU_ARGS #elif defined(CONFIG_ISA_x86) #define ISA_QEMU_BIN "qemu-system-i386" #define ISA_QEMU_ARGS @@ -41,7 +41,7 @@ union isa_gdb_regs { #elif defined(CONFIG_ISA_riscv) && !defined(CONFIG_RV64) uint32_t gpr[32]; uint32_t pc; -#elif defined(CONFIG_ISA_riscv) && defined(CONFIG_RV64) +#elif defined(CONFIG_ISA_riscv) && defined(CONFIG_RV64) uint64_t gpr[32]; uint64_t fpr[32]; uint64_t pc; diff --git a/nemu/tools/spike-diff/difftest.cc b/nemu/tools/spike-diff/difftest.cc index d853594..580fb31 100644 --- a/nemu/tools/spike-diff/difftest.cc +++ b/nemu/tools/spike-diff/difftest.cc @@ -13,35 +13,35 @@ * See the Mulan PSL v2 for more details. ***************************************************************************************/ -#include "../../include/common.h" #include "mmu.h" #include "sim.h" +#include "../../include/common.h" #include #define NR_GPR MUXDEF(CONFIG_RVE, 16, 32) -static std::vector> - difftest_plugin_devices; +static std::vector> difftest_plugin_devices; static std::vector difftest_htif_args; -static std::vector> - difftest_mem(1, std::make_pair(reg_t(DRAM_BASE), new mem_t(CONFIG_MSIZE))); +static std::vector> difftest_mem( + 1, std::make_pair(reg_t(DRAM_BASE), new mem_t(CONFIG_MSIZE))); static debug_module_config_t difftest_dm_config = { - .progbufsize = 2, - .max_sba_data_width = 0, - .require_authentication = false, - .abstract_rti = 0, - .support_hasel = true, - .support_abstract_csr_access = true, - .support_abstract_fpr_access = true, - .support_haltgroups = true, - .support_impebreak = true}; + .progbufsize = 2, + .max_sba_data_width = 0, + .require_authentication = false, + .abstract_rti = 0, + .support_hasel = true, + .support_abstract_csr_access = true, + .support_abstract_fpr_access = true, + .support_haltgroups = true, + .support_impebreak = true +}; struct diff_context_t { word_t gpr[MUXDEF(CONFIG_RVE, 16, 32)]; word_t pc; }; -static sim_t *s = NULL; +static sim_t* s = NULL; static processor_t *p = NULL; static state_t *state = NULL; @@ -50,35 +50,36 @@ void sim_t::diff_init(int port) { state = p->get_state(); } -void sim_t::diff_step(uint64_t n) { step(n); } +void sim_t::diff_step(uint64_t n) { + step(n); +} -void sim_t::diff_get_regs(void *diff_context) { - struct diff_context_t *ctx = (struct diff_context_t *)diff_context; +void sim_t::diff_get_regs(void* diff_context) { + struct diff_context_t* ctx = (struct diff_context_t*)diff_context; for (int i = 0; i < NR_GPR; i++) { ctx->gpr[i] = state->XPR[i]; } ctx->pc = state->pc; } -void sim_t::diff_set_regs(void *diff_context) { - struct diff_context_t *ctx = (struct diff_context_t *)diff_context; +void sim_t::diff_set_regs(void* diff_context) { + struct diff_context_t* ctx = (struct diff_context_t*)diff_context; for (int i = 0; i < NR_GPR; i++) { state->XPR.write(i, (sword_t)ctx->gpr[i]); } state->pc = ctx->pc; } -void sim_t::diff_memcpy(reg_t dest, void *src, size_t n) { - mmu_t *mmu = p->get_mmu(); +void sim_t::diff_memcpy(reg_t dest, void* src, size_t n) { + mmu_t* mmu = p->get_mmu(); for (size_t i = 0; i < n; i++) { - mmu->store(dest + i, *((uint8_t *)src + i)); + mmu->store(dest+i, *((uint8_t*)src+i)); } } extern "C" { -__EXPORT void difftest_memcpy(paddr_t addr, void *buf, size_t n, - bool direction) { +__EXPORT void difftest_memcpy(paddr_t addr, void *buf, size_t n, bool direction) { if (direction == DIFFTEST_TO_REF) { s->diff_memcpy(addr, buf, n); } else { @@ -86,7 +87,7 @@ __EXPORT void difftest_memcpy(paddr_t addr, void *buf, size_t n, } } -__EXPORT void difftest_regcpy(void *dut, bool direction) { +__EXPORT void difftest_regcpy(void* dut, bool direction) { if (direction == DIFFTEST_TO_REF) { s->diff_set_regs(dut); } else { @@ -94,27 +95,31 @@ __EXPORT void difftest_regcpy(void *dut, bool direction) { } } -__EXPORT void difftest_exec(uint64_t n) { s->diff_step(n); } +__EXPORT void difftest_exec(uint64_t n) { + s->diff_step(n); +} __EXPORT void difftest_init(int port) { difftest_htif_args.push_back(""); - const char *isa = - "RV" MUXDEF(CONFIG_RV64, "64", "32") MUXDEF(CONFIG_RVE, "E", "I") "MAFDC"; + const char *isa = "RV" MUXDEF(CONFIG_RV64, "64", "32") MUXDEF(CONFIG_RVE, "E", "I") "MAFDC"; cfg_t cfg(/*default_initrd_bounds=*/std::make_pair((reg_t)0, (reg_t)0), /*default_bootargs=*/nullptr, /*default_isa=*/isa, /*default_priv=*/DEFAULT_PRIV, /*default_varch=*/DEFAULT_VARCH, /*default_misaligned=*/false, - /*default_endianness*/ endianness_little, + /*default_endianness*/endianness_little, /*default_pmpregions=*/16, /*default_mem_layout=*/std::vector(), /*default_hartids=*/std::vector(1), /*default_real_time_clint=*/false, /*default_trigger_count=*/4); - s = new sim_t(&cfg, false, difftest_mem, difftest_plugin_devices, - difftest_htif_args, difftest_dm_config, nullptr, false, NULL, - false, NULL, true); + s = new sim_t(&cfg, false, + difftest_mem, difftest_plugin_devices, difftest_htif_args, + difftest_dm_config, nullptr, false, NULL, + false, + NULL, + true); s->diff_init(port); } @@ -122,4 +127,5 @@ __EXPORT void difftest_raise_intr(uint64_t NO) { trap_t t(NO); p->take_trap_public(t, state->pc); } + } diff --git a/npc/.cmake-format b/npc/.cmake-format deleted file mode 100644 index d98e985..0000000 --- a/npc/.cmake-format +++ /dev/null @@ -1,24 +0,0 @@ -additional_commands = { - "verilate": { - "pargs": 1, - "flags": [ - "COVERAGE", - "SYSTEMC", - "THREADS", - "TRACE_THREADS", - "TRACE", - "TRACE_FST" - ], - "kwargs": { - "DIRECTORY": "?", - "INCLUDE_DIRS": "*", - "OPT_SLOW": "*", - "OPT_FAST": "*", - "OPT_GLOBAL": "*", - "PREFIX": "?", - "SOURCES": "+", - "TOP_MODULE": "?", - "VERILATOR_ARGS": "*", - } - } -} diff --git a/npc/.envrc b/npc/.envrc index beaa935..3550a30 100644 --- a/npc/.envrc +++ b/npc/.envrc @@ -1 +1 @@ -use flake ".?submodules=1#npc" +use flake diff --git a/npc/.gdbinit b/npc/.gdbinit deleted file mode 100644 index 59ce952..0000000 --- a/npc/.gdbinit +++ /dev/null @@ -1,3 +0,0 @@ -set substitute-path /build/am-kernels /home/xin/repo/ysyx-workbench/am-kernels -file /nix/store/g8hi9rlby6xm7grzcpfc8lpmdfgv1i92-am-kernel-riscv32-none-elf-2024-07-10/libexec/am-kernels/add -target remote gdbstub-npc.sock diff --git a/npc/.gitignore b/npc/.gitignore index 5a4f7bc..fd7efb6 100644 --- a/npc/.gitignore +++ b/npc/.gitignore @@ -15,5 +15,3 @@ hs_err_pid* .vscode/ .direnv/ compile_commands.json - -*.vcd diff --git a/npc/CMakeLists.txt b/npc/CMakeLists.txt index 22da348..db9d0a1 100644 --- a/npc/CMakeLists.txt +++ b/npc/CMakeLists.txt @@ -1,83 +1,101 @@ -cmake_minimum_required(VERSION 3.26) +cmake_minimum_required(VERSION 3.20) project(flow) -set(CMAKE_CXX_STANDARD 17) +set (CMAKE_CXX_STANDARD 11) cmake_policy(SET CMP0144 NEW) -include(CMakeDependentOption) -include(CTest) -include(GNUInstallDirs) -enable_testing() -list(APPEND CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake) +execute_process( + COMMAND ${CMAKE_SOURCE_DIR}/../git_commit.sh "configure(npc)" + WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/.. +) -# -- Build options -option(BUILD_CHISEL_EMIT_TARGET "Emit verilog file with chisel" ON) -option(BUILD_USE_BLOOP "Whether to use bloop to speed up elaborate" OFF) -option(BUILD_SIM_TARGET "Whether to build verilator simulation binary" ON) -cmake_dependent_option( - BUILD_SIM_NVBOARD_TARGET "Whether to build nvboard target" OFF - "BUILD_SIM_TARGET" OFF) -option(ENABLE_YSYX_GIT_TRACKER "Ysyx tracker support" ON) -set(TOPMODULE - "Flow" - CACHE STRING "Topmodule name in chisel") -set(DIFFTEST_LIB - "" - CACHE FILEPATH "Dynamic library file used as difftest reference") -set(DIFFTEST_RESOURCE_DIR - "" - CACHE PATH "Dynamic library file used as difftest reference") +find_package(SDL2 REQUIRED) +find_package(SDL2_image REQUIRED) -# -- Ysyx tracker, configure -if(ENABLE_YSYX_GIT_TRACKER) - execute_process(COMMAND ${CMAKE_SOURCE_DIR}/../git_commit.sh "configure(npc)" - WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/..) -endif() - -# -- Check dependencies -if(BUILD_SIM_TARGET) - find_package(verilator REQUIRED) -endif() -if(BUILD_SIM_NVBOARD_TARGET) - find_package(SDL2 REQUIRED) - find_package(SDL2_image REQUIRED) -endif() -find_package(CLI11 CONFIG REQUIRED) -find_package(spdlog REQUIRED) - -option(ENABLE_SDB "Enable simple debugger" OFF) +find_package(verilator REQUIRED) find_library(NVBOARD_LIBRARY NAMES nvboard) find_path(NVBOARD_INCLUDE_DIR NAMES nvboard.h) -if(BUILD_CHISEL_EMIT_TARGET) - # FIXME: all scala source file are tracked here, cause all files to rebuild - # after a source update. +set(TOPMODULES "Flow") + +foreach(TOPMODULE IN LISTS TOPMODULES) + + # FIXME: all scala source file are tracked here, cause all files to rebuild + # after a source update. set(SCALA_CORE "${CMAKE_CURRENT_SOURCE_DIR}/core") set(CHISEL_MODULE_CLASS "${CMAKE_PROJECT_NAME}.${TOPMODULE}") + file(GLOB_RECURSE SCALA_CORE_SOURCES "${SCALA_CORE}/src/main/scala/*.scala") + file(GLOB_RECURSE SCALA_CORE_TEST_SOURCES "${SCALA_CORE}/src/test/scala/*.scala") - set(CHISEL_OUTPUT_DIR ${CMAKE_CURRENT_BINARY_DIR}/${TOPMODULE}/vsrc) + # Configure time verilog source generation for verilator + execute_process( + COMMAND sbt "runMain circt.stage.ChiselMain --target-dir ${CMAKE_CURRENT_BINARY_DIR}/${TOPMODULE}/vsrc --module ${CHISEL_MODULE_CLASS} --target verilog" + WORKING_DIRECTORY ${SCALA_CORE} + ) - set(CHISEL_OUTPUT_VERILATOR_CONF ${CHISEL_OUTPUT_DIR}/conf.vlt) - set(CHISEL_OUTPUT_TOPMODULE ${CHISEL_OUTPUT_DIR}/${TOPMODULE}.sv) - set(CHISEL_EMIT_ARGS "--target-dir ${CHISEL_OUTPUT_DIR}") -endif() + add_custom_command( + OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${TOPMODULE}/vsrc/${TOPMODULE}.v + COMMAND sbt "runMain circt.stage.ChiselMain --target-dir ${CMAKE_CURRENT_BINARY_DIR}/${TOPMODULE}/vsrc --module ${CHISEL_MODULE_CLASS} --target verilog" + WORKING_DIRECTORY ${SCALA_CORE} + DEPENDS ${SCALA_CORE_SOURCES} + ) -# -- Build NVBoard executable -if(BUILD_SIM_NVBOARD_TARGET) - add_subdirectory(csrc_nvboard) -endif() - -# -- Build Verilator executable and add to test -add_subdirectory(utils) - -add_subdirectory(csrc) - -# -- Add build tracking -if(ENABLE_YSYX_GIT_TRACKER) add_custom_target( - ysyx_git_tracer ALL - COMMAND ${CMAKE_SOURCE_DIR}/../git_commit.sh - "build_${CMAKE_PROJECT_NAME}_V${TOPMODULE}" - WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/..) -endif() + ChiselBuild_${TOPMODULE} + DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/${TOPMODULE}/vsrc/${TOPMODULE}.v + ) + + # -- Build NVBoard executable + + add_custom_command( + OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${TOPMODULE}/auto_bind.cpp + COMMAND auto_pin_bind ${CMAKE_SOURCE_DIR}/constr/${TOPMODULE}.nxdc ${CMAKE_CURRENT_BINARY_DIR}/${TOPMODULE}/auto_bind.cpp + DEPENDS ${CMAKE_SOURCE_DIR}/constr/${TOPMODULE}.nxdc + ) + + unset(SOURCES) + file(GLOB_RECURSE SOURCES csrc_nvboard/${TOPMODULE}/*.cpp) + add_executable(V${TOPMODULE}_nvboard ${SOURCES} ${CMAKE_CURRENT_BINARY_DIR}/${TOPMODULE}/auto_bind.cpp) + + verilate(V${TOPMODULE}_nvboard TRACE THREADS + TOP_MODULE ${TOPMODULE} + PREFIX V${TOPMODULE} + SOURCES ${CMAKE_CURRENT_BINARY_DIR}/${TOPMODULE}/vsrc/${TOPMODULE}.v) + + add_dependencies(V${TOPMODULE}_nvboard ChiselBuild_${TOPMODULE}) + target_include_directories(V${TOPMODULE}_nvboard PRIVATE ${NVBOARD_INCLUDE_DIR} ${SDL2_INCLUDE_DIRS}) + target_link_libraries(V${TOPMODULE}_nvboard PRIVATE ${NVBOARD_LIBRARY} SDL2::SDL2 SDL2_image::SDL2_image) + + install(TARGETS V${TOPMODULE}_nvboard) + + # -- Build Verilator executable and add to test + + unset(SOURCES) + file(GLOB_RECURSE SOURCES csrc/${TOPMODULE}/*.cpp) + add_executable(V${TOPMODULE} ${SOURCES}) + + verilate(V${TOPMODULE} TRACE COVERAGE THREADS + TOP_MODULE ${TOPMODULE} + PREFIX V${TOPMODULE} + SOURCES ${CMAKE_CURRENT_BINARY_DIR}/${TOPMODULE}/vsrc/${TOPMODULE}.v) + + add_dependencies(V${TOPMODULE} ChiselBuild_${TOPMODULE}) + + enable_testing() + add_test(NAME V${TOPMODULE} COMMAND V${TOPMODULE}) + + # -- Add build tracking + add_custom_command( + TARGET V${TOPMODULE}_nvboard PRE_BUILD + COMMAND ${CMAKE_SOURCE_DIR}/../git_commit.sh "build_${CMAKE_PROJECT_NAME}_V${TOPMODULE}_nvboard" + WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/.. + ) + + add_custom_command( + TARGET V${TOPMODULE} PRE_BUILD + COMMAND ${CMAKE_SOURCE_DIR}/../git_commit.sh "build_${CMAKE_PROJECT_NAME}_V${TOPMODULE}" + WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/.. + ) + +endforeach() diff --git a/npc/LICENSE b/npc/LICENSE deleted file mode 100644 index f288702..0000000 --- a/npc/LICENSE +++ /dev/null @@ -1,674 +0,0 @@ - GNU GENERAL PUBLIC LICENSE - Version 3, 29 June 2007 - - Copyright (C) 2007 Free Software Foundation, Inc. - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - Preamble - - The GNU General Public License is a free, copyleft license for -software and other kinds of works. - - The licenses for most software and other practical works are designed -to take away your freedom to share and change the works. By contrast, -the GNU General Public License is intended to guarantee your freedom to -share and change all versions of a program--to make sure it remains free -software for all its users. We, the Free Software Foundation, use the -GNU General Public License for most of our software; it applies also to -any other work released this way by its authors. You can apply it to -your programs, too. - - When we speak of free software, we are referring to freedom, not -price. Our General Public Licenses are designed to make sure that you -have the freedom to distribute copies of free software (and charge for -them if you wish), that you receive source code or can get it if you -want it, that you can change the software or use pieces of it in new -free programs, and that you know you can do these things. - - To protect your rights, we need to prevent others from denying you -these rights or asking you to surrender the rights. Therefore, you have -certain responsibilities if you distribute copies of the software, or if -you modify it: responsibilities to respect the freedom of others. - - For example, if you distribute copies of such a program, whether -gratis or for a fee, you must pass on to the recipients the same -freedoms that you received. You must make sure that they, too, receive -or can get the source code. And you must show them these terms so they -know their rights. - - Developers that use the GNU GPL protect your rights with two steps: -(1) assert copyright on the software, and (2) offer you this License -giving you legal permission to copy, distribute and/or modify it. - - For the developers' and authors' protection, the GPL clearly explains -that there is no warranty for this free software. For both users' and -authors' sake, the GPL requires that modified versions be marked as -changed, so that their problems will not be attributed erroneously to -authors of previous versions. - - Some devices are designed to deny users access to install or run -modified versions of the software inside them, although the manufacturer -can do so. This is fundamentally incompatible with the aim of -protecting users' freedom to change the software. The systematic -pattern of such abuse occurs in the area of products for individuals to -use, which is precisely where it is most unacceptable. Therefore, we -have designed this version of the GPL to prohibit the practice for those -products. If such problems arise substantially in other domains, we -stand ready to extend this provision to those domains in future versions -of the GPL, as needed to protect the freedom of users. - - Finally, every program is threatened constantly by software patents. -States should not allow patents to restrict development and use of -software on general-purpose computers, but in those that do, we wish to -avoid the special danger that patents applied to a free program could -make it effectively proprietary. To prevent this, the GPL assures that -patents cannot be used to render the program non-free. - - The precise terms and conditions for copying, distribution and -modification follow. - - TERMS AND CONDITIONS - - 0. Definitions. - - "This License" refers to version 3 of the GNU General Public License. - - "Copyright" also means copyright-like laws that apply to other kinds of -works, such as semiconductor masks. - - "The Program" refers to any copyrightable work licensed under this -License. Each licensee is addressed as "you". "Licensees" and -"recipients" may be individuals or organizations. - - To "modify" a work means to copy from or adapt all or part of the work -in a fashion requiring copyright permission, other than the making of an -exact copy. The resulting work is called a "modified version" of the -earlier work or a work "based on" the earlier work. - - A "covered work" means either the unmodified Program or a work based -on the Program. - - To "propagate" a work means to do anything with it that, without -permission, would make you directly or secondarily liable for -infringement under applicable copyright law, except executing it on a -computer or modifying a private copy. Propagation includes copying, -distribution (with or without modification), making available to the -public, and in some countries other activities as well. - - To "convey" a work means any kind of propagation that enables other -parties to make or receive copies. Mere interaction with a user through -a computer network, with no transfer of a copy, is not conveying. - - An interactive user interface displays "Appropriate Legal Notices" -to the extent that it includes a convenient and prominently visible -feature that (1) displays an appropriate copyright notice, and (2) -tells the user that there is no warranty for the work (except to the -extent that warranties are provided), that licensees may convey the -work under this License, and how to view a copy of this License. If -the interface presents a list of user commands or options, such as a -menu, a prominent item in the list meets this criterion. - - 1. Source Code. - - The "source code" for a work means the preferred form of the work -for making modifications to it. "Object code" means any non-source -form of a work. - - A "Standard Interface" means an interface that either is an official -standard defined by a recognized standards body, or, in the case of -interfaces specified for a particular programming language, one that -is widely used among developers working in that language. - - The "System Libraries" of an executable work include anything, other -than the work as a whole, that (a) is included in the normal form of -packaging a Major Component, but which is not part of that Major -Component, and (b) serves only to enable use of the work with that -Major Component, or to implement a Standard Interface for which an -implementation is available to the public in source code form. A -"Major Component", in this context, means a major essential component -(kernel, window system, and so on) of the specific operating system -(if any) on which the executable work runs, or a compiler used to -produce the work, or an object code interpreter used to run it. - - The "Corresponding Source" for a work in object code form means all -the source code needed to generate, install, and (for an executable -work) run the object code and to modify the work, including scripts to -control those activities. However, it does not include the work's -System Libraries, or general-purpose tools or generally available free -programs which are used unmodified in performing those activities but -which are not part of the work. For example, Corresponding Source -includes interface definition files associated with source files for -the work, and the source code for shared libraries and dynamically -linked subprograms that the work is specifically designed to require, -such as by intimate data communication or control flow between those -subprograms and other parts of the work. - - The Corresponding Source need not include anything that users -can regenerate automatically from other parts of the Corresponding -Source. - - The Corresponding Source for a work in source code form is that -same work. - - 2. Basic Permissions. - - All rights granted under this License are granted for the term of -copyright on the Program, and are irrevocable provided the stated -conditions are met. This License explicitly affirms your unlimited -permission to run the unmodified Program. The output from running a -covered work is covered by this License only if the output, given its -content, constitutes a covered work. This License acknowledges your -rights of fair use or other equivalent, as provided by copyright law. - - You may make, run and propagate covered works that you do not -convey, without conditions so long as your license otherwise remains -in force. You may convey covered works to others for the sole purpose -of having them make modifications exclusively for you, or provide you -with facilities for running those works, provided that you comply with -the terms of this License in conveying all material for which you do -not control copyright. Those thus making or running the covered works -for you must do so exclusively on your behalf, under your direction -and control, on terms that prohibit them from making any copies of -your copyrighted material outside their relationship with you. - - Conveying under any other circumstances is permitted solely under -the conditions stated below. Sublicensing is not allowed; section 10 -makes it unnecessary. - - 3. Protecting Users' Legal Rights From Anti-Circumvention Law. - - No covered work shall be deemed part of an effective technological -measure under any applicable law fulfilling obligations under article -11 of the WIPO copyright treaty adopted on 20 December 1996, or -similar laws prohibiting or restricting circumvention of such -measures. - - When you convey a covered work, you waive any legal power to forbid -circumvention of technological measures to the extent such circumvention -is effected by exercising rights under this License with respect to -the covered work, and you disclaim any intention to limit operation or -modification of the work as a means of enforcing, against the work's -users, your or third parties' legal rights to forbid circumvention of -technological measures. - - 4. Conveying Verbatim Copies. - - You may convey verbatim copies of the Program's source code as you -receive it, in any medium, provided that you conspicuously and -appropriately publish on each copy an appropriate copyright notice; -keep intact all notices stating that this License and any -non-permissive terms added in accord with section 7 apply to the code; -keep intact all notices of the absence of any warranty; and give all -recipients a copy of this License along with the Program. - - You may charge any price or no price for each copy that you convey, -and you may offer support or warranty protection for a fee. - - 5. Conveying Modified Source Versions. - - You may convey a work based on the Program, or the modifications to -produce it from the Program, in the form of source code under the -terms of section 4, provided that you also meet all of these conditions: - - a) The work must carry prominent notices stating that you modified - it, and giving a relevant date. - - b) The work must carry prominent notices stating that it is - released under this License and any conditions added under section - 7. This requirement modifies the requirement in section 4 to - "keep intact all notices". - - c) You must license the entire work, as a whole, under this - License to anyone who comes into possession of a copy. This - License will therefore apply, along with any applicable section 7 - additional terms, to the whole of the work, and all its parts, - regardless of how they are packaged. This License gives no - permission to license the work in any other way, but it does not - invalidate such permission if you have separately received it. - - d) If the work has interactive user interfaces, each must display - Appropriate Legal Notices; however, if the Program has interactive - interfaces that do not display Appropriate Legal Notices, your - work need not make them do so. - - A compilation of a covered work with other separate and independent -works, which are not by their nature extensions of the covered work, -and which are not combined with it such as to form a larger program, -in or on a volume of a storage or distribution medium, is called an -"aggregate" if the compilation and its resulting copyright are not -used to limit the access or legal rights of the compilation's users -beyond what the individual works permit. Inclusion of a covered work -in an aggregate does not cause this License to apply to the other -parts of the aggregate. - - 6. Conveying Non-Source Forms. - - You may convey a covered work in object code form under the terms -of sections 4 and 5, provided that you also convey the -machine-readable Corresponding Source under the terms of this License, -in one of these ways: - - a) Convey the object code in, or embodied in, a physical product - (including a physical distribution medium), accompanied by the - Corresponding Source fixed on a durable physical medium - customarily used for software interchange. - - b) Convey the object code in, or embodied in, a physical product - (including a physical distribution medium), accompanied by a - written offer, valid for at least three years and valid for as - long as you offer spare parts or customer support for that product - model, to give anyone who possesses the object code either (1) a - copy of the Corresponding Source for all the software in the - product that is covered by this License, on a durable physical - medium customarily used for software interchange, for a price no - more than your reasonable cost of physically performing this - conveying of source, or (2) access to copy the - Corresponding Source from a network server at no charge. - - c) Convey individual copies of the object code with a copy of the - written offer to provide the Corresponding Source. This - alternative is allowed only occasionally and noncommercially, and - only if you received the object code with such an offer, in accord - with subsection 6b. - - d) Convey the object code by offering access from a designated - place (gratis or for a charge), and offer equivalent access to the - Corresponding Source in the same way through the same place at no - further charge. You need not require recipients to copy the - Corresponding Source along with the object code. If the place to - copy the object code is a network server, the Corresponding Source - may be on a different server (operated by you or a third party) - that supports equivalent copying facilities, provided you maintain - clear directions next to the object code saying where to find the - Corresponding Source. Regardless of what server hosts the - Corresponding Source, you remain obligated to ensure that it is - available for as long as needed to satisfy these requirements. - - e) Convey the object code using peer-to-peer transmission, provided - you inform other peers where the object code and Corresponding - Source of the work are being offered to the general public at no - charge under subsection 6d. - - A separable portion of the object code, whose source code is excluded -from the Corresponding Source as a System Library, need not be -included in conveying the object code work. - - A "User Product" is either (1) a "consumer product", which means any -tangible personal property which is normally used for personal, family, -or household purposes, or (2) anything designed or sold for incorporation -into a dwelling. In determining whether a product is a consumer product, -doubtful cases shall be resolved in favor of coverage. For a particular -product received by a particular user, "normally used" refers to a -typical or common use of that class of product, regardless of the status -of the particular user or of the way in which the particular user -actually uses, or expects or is expected to use, the product. A product -is a consumer product regardless of whether the product has substantial -commercial, industrial or non-consumer uses, unless such uses represent -the only significant mode of use of the product. - - "Installation Information" for a User Product means any methods, -procedures, authorization keys, or other information required to install -and execute modified versions of a covered work in that User Product from -a modified version of its Corresponding Source. The information must -suffice to ensure that the continued functioning of the modified object -code is in no case prevented or interfered with solely because -modification has been made. - - If you convey an object code work under this section in, or with, or -specifically for use in, a User Product, and the conveying occurs as -part of a transaction in which the right of possession and use of the -User Product is transferred to the recipient in perpetuity or for a -fixed term (regardless of how the transaction is characterized), the -Corresponding Source conveyed under this section must be accompanied -by the Installation Information. But this requirement does not apply -if neither you nor any third party retains the ability to install -modified object code on the User Product (for example, the work has -been installed in ROM). - - The requirement to provide Installation Information does not include a -requirement to continue to provide support service, warranty, or updates -for a work that has been modified or installed by the recipient, or for -the User Product in which it has been modified or installed. Access to a -network may be denied when the modification itself materially and -adversely affects the operation of the network or violates the rules and -protocols for communication across the network. - - Corresponding Source conveyed, and Installation Information provided, -in accord with this section must be in a format that is publicly -documented (and with an implementation available to the public in -source code form), and must require no special password or key for -unpacking, reading or copying. - - 7. Additional Terms. - - "Additional permissions" are terms that supplement the terms of this -License by making exceptions from one or more of its conditions. -Additional permissions that are applicable to the entire Program shall -be treated as though they were included in this License, to the extent -that they are valid under applicable law. If additional permissions -apply only to part of the Program, that part may be used separately -under those permissions, but the entire Program remains governed by -this License without regard to the additional permissions. - - When you convey a copy of a covered work, you may at your option -remove any additional permissions from that copy, or from any part of -it. (Additional permissions may be written to require their own -removal in certain cases when you modify the work.) You may place -additional permissions on material, added by you to a covered work, -for which you have or can give appropriate copyright permission. - - Notwithstanding any other provision of this License, for material you -add to a covered work, you may (if authorized by the copyright holders of -that material) supplement the terms of this License with terms: - - a) Disclaiming warranty or limiting liability differently from the - terms of sections 15 and 16 of this License; or - - b) Requiring preservation of specified reasonable legal notices or - author attributions in that material or in the Appropriate Legal - Notices displayed by works containing it; or - - c) Prohibiting misrepresentation of the origin of that material, or - requiring that modified versions of such material be marked in - reasonable ways as different from the original version; or - - d) Limiting the use for publicity purposes of names of licensors or - authors of the material; or - - e) Declining to grant rights under trademark law for use of some - trade names, trademarks, or service marks; or - - f) Requiring indemnification of licensors and authors of that - material by anyone who conveys the material (or modified versions of - it) with contractual assumptions of liability to the recipient, for - any liability that these contractual assumptions directly impose on - those licensors and authors. - - All other non-permissive additional terms are considered "further -restrictions" within the meaning of section 10. If the Program as you -received it, or any part of it, contains a notice stating that it is -governed by this License along with a term that is a further -restriction, you may remove that term. If a license document contains -a further restriction but permits relicensing or conveying under this -License, you may add to a covered work material governed by the terms -of that license document, provided that the further restriction does -not survive such relicensing or conveying. - - If you add terms to a covered work in accord with this section, you -must place, in the relevant source files, a statement of the -additional terms that apply to those files, or a notice indicating -where to find the applicable terms. - - Additional terms, permissive or non-permissive, may be stated in the -form of a separately written license, or stated as exceptions; -the above requirements apply either way. - - 8. Termination. - - You may not propagate or modify a covered work except as expressly -provided under this License. Any attempt otherwise to propagate or -modify it is void, and will automatically terminate your rights under -this License (including any patent licenses granted under the third -paragraph of section 11). - - However, if you cease all violation of this License, then your -license from a particular copyright holder is reinstated (a) -provisionally, unless and until the copyright holder explicitly and -finally terminates your license, and (b) permanently, if the copyright -holder fails to notify you of the violation by some reasonable means -prior to 60 days after the cessation. - - Moreover, your license from a particular copyright holder is -reinstated permanently if the copyright holder notifies you of the -violation by some reasonable means, this is the first time you have -received notice of violation of this License (for any work) from that -copyright holder, and you cure the violation prior to 30 days after -your receipt of the notice. - - Termination of your rights under this section does not terminate the -licenses of parties who have received copies or rights from you under -this License. If your rights have been terminated and not permanently -reinstated, you do not qualify to receive new licenses for the same -material under section 10. - - 9. Acceptance Not Required for Having Copies. - - You are not required to accept this License in order to receive or -run a copy of the Program. Ancillary propagation of a covered work -occurring solely as a consequence of using peer-to-peer transmission -to receive a copy likewise does not require acceptance. However, -nothing other than this License grants you permission to propagate or -modify any covered work. These actions infringe copyright if you do -not accept this License. Therefore, by modifying or propagating a -covered work, you indicate your acceptance of this License to do so. - - 10. Automatic Licensing of Downstream Recipients. - - Each time you convey a covered work, the recipient automatically -receives a license from the original licensors, to run, modify and -propagate that work, subject to this License. You are not responsible -for enforcing compliance by third parties with this License. - - An "entity transaction" is a transaction transferring control of an -organization, or substantially all assets of one, or subdividing an -organization, or merging organizations. If propagation of a covered -work results from an entity transaction, each party to that -transaction who receives a copy of the work also receives whatever -licenses to the work the party's predecessor in interest had or could -give under the previous paragraph, plus a right to possession of the -Corresponding Source of the work from the predecessor in interest, if -the predecessor has it or can get it with reasonable efforts. - - You may not impose any further restrictions on the exercise of the -rights granted or affirmed under this License. For example, you may -not impose a license fee, royalty, or other charge for exercise of -rights granted under this License, and you may not initiate litigation -(including a cross-claim or counterclaim in a lawsuit) alleging that -any patent claim is infringed by making, using, selling, offering for -sale, or importing the Program or any portion of it. - - 11. Patents. - - A "contributor" is a copyright holder who authorizes use under this -License of the Program or a work on which the Program is based. The -work thus licensed is called the contributor's "contributor version". - - A contributor's "essential patent claims" are all patent claims -owned or controlled by the contributor, whether already acquired or -hereafter acquired, that would be infringed by some manner, permitted -by this License, of making, using, or selling its contributor version, -but do not include claims that would be infringed only as a -consequence of further modification of the contributor version. For -purposes of this definition, "control" includes the right to grant -patent sublicenses in a manner consistent with the requirements of -this License. - - Each contributor grants you a non-exclusive, worldwide, royalty-free -patent license under the contributor's essential patent claims, to -make, use, sell, offer for sale, import and otherwise run, modify and -propagate the contents of its contributor version. - - In the following three paragraphs, a "patent license" is any express -agreement or commitment, however denominated, not to enforce a patent -(such as an express permission to practice a patent or covenant not to -sue for patent infringement). To "grant" such a patent license to a -party means to make such an agreement or commitment not to enforce a -patent against the party. - - If you convey a covered work, knowingly relying on a patent license, -and the Corresponding Source of the work is not available for anyone -to copy, free of charge and under the terms of this License, through a -publicly available network server or other readily accessible means, -then you must either (1) cause the Corresponding Source to be so -available, or (2) arrange to deprive yourself of the benefit of the -patent license for this particular work, or (3) arrange, in a manner -consistent with the requirements of this License, to extend the patent -license to downstream recipients. "Knowingly relying" means you have -actual knowledge that, but for the patent license, your conveying the -covered work in a country, or your recipient's use of the covered work -in a country, would infringe one or more identifiable patents in that -country that you have reason to believe are valid. - - If, pursuant to or in connection with a single transaction or -arrangement, you convey, or propagate by procuring conveyance of, a -covered work, and grant a patent license to some of the parties -receiving the covered work authorizing them to use, propagate, modify -or convey a specific copy of the covered work, then the patent license -you grant is automatically extended to all recipients of the covered -work and works based on it. - - A patent license is "discriminatory" if it does not include within -the scope of its coverage, prohibits the exercise of, or is -conditioned on the non-exercise of one or more of the rights that are -specifically granted under this License. You may not convey a covered -work if you are a party to an arrangement with a third party that is -in the business of distributing software, under which you make payment -to the third party based on the extent of your activity of conveying -the work, and under which the third party grants, to any of the -parties who would receive the covered work from you, a discriminatory -patent license (a) in connection with copies of the covered work -conveyed by you (or copies made from those copies), or (b) primarily -for and in connection with specific products or compilations that -contain the covered work, unless you entered into that arrangement, -or that patent license was granted, prior to 28 March 2007. - - Nothing in this License shall be construed as excluding or limiting -any implied license or other defenses to infringement that may -otherwise be available to you under applicable patent law. - - 12. No Surrender of Others' Freedom. - - If conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot convey a -covered work so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you may -not convey it at all. For example, if you agree to terms that obligate you -to collect a royalty for further conveying from those to whom you convey -the Program, the only way you could satisfy both those terms and this -License would be to refrain entirely from conveying the Program. - - 13. Use with the GNU Affero General Public License. - - Notwithstanding any other provision of this License, you have -permission to link or combine any covered work with a work licensed -under version 3 of the GNU Affero General Public License into a single -combined work, and to convey the resulting work. The terms of this -License will continue to apply to the part which is the covered work, -but the special requirements of the GNU Affero General Public License, -section 13, concerning interaction through a network will apply to the -combination as such. - - 14. Revised Versions of this License. - - The Free Software Foundation may publish revised and/or new versions of -the GNU General Public License from time to time. Such new versions will -be similar in spirit to the present version, but may differ in detail to -address new problems or concerns. - - Each version is given a distinguishing version number. If the -Program specifies that a certain numbered version of the GNU General -Public License "or any later version" applies to it, you have the -option of following the terms and conditions either of that numbered -version or of any later version published by the Free Software -Foundation. If the Program does not specify a version number of the -GNU General Public License, you may choose any version ever published -by the Free Software Foundation. - - If the Program specifies that a proxy can decide which future -versions of the GNU General Public License can be used, that proxy's -public statement of acceptance of a version permanently authorizes you -to choose that version for the Program. - - Later license versions may give you additional or different -permissions. However, no additional obligations are imposed on any -author or copyright holder as a result of your choosing to follow a -later version. - - 15. Disclaimer of Warranty. - - THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY -APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT -HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY -OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, -THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM -IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF -ALL NECESSARY SERVICING, REPAIR OR CORRECTION. - - 16. Limitation of Liability. - - IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS -THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY -GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE -USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF -DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD -PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), -EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF -SUCH DAMAGES. - - 17. Interpretation of Sections 15 and 16. - - If the disclaimer of warranty and limitation of liability provided -above cannot be given local legal effect according to their terms, -reviewing courts shall apply local law that most closely approximates -an absolute waiver of all civil liability in connection with the -Program, unless a warranty or assumption of liability accompanies a -copy of the Program in return for a fee. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Programs - - If you develop a new program, and you want it to be of the greatest -possible use to the public, the best way to achieve this is to make it -free software which everyone can redistribute and change under these terms. - - To do so, attach the following notices to the program. It is safest -to attach them to the start of each source file to most effectively -state the exclusion of warranty; and each file should have at least -the "copyright" line and a pointer to where the full notice is found. - - - Copyright (C) - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . - -Also add information on how to contact you by electronic and paper mail. - - If the program does terminal interaction, make it output a short -notice like this when it starts in an interactive mode: - - Copyright (C) - This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. - This is free software, and you are welcome to redistribute it - under certain conditions; type `show c' for details. - -The hypothetical commands `show w' and `show c' should show the appropriate -parts of the General Public License. Of course, your program's commands -might be different; for a GUI interface, you would use an "about box". - - You should also get your employer (if you work as a programmer) or school, -if any, to sign a "copyright disclaimer" for the program, if necessary. -For more information on this, and how to apply and follow the GNU GPL, see -. - - The GNU General Public License does not permit incorporating your program -into proprietary programs. If your program is a subroutine library, you -may consider it more useful to permit linking proprietary applications with -the library. If this is what you want to do, use the GNU Lesser General -Public License instead of this License. But first, please read -. diff --git a/npc/cmake/ChiselBuild.cmake b/npc/cmake/ChiselBuild.cmake deleted file mode 100644 index f446790..0000000 --- a/npc/cmake/ChiselBuild.cmake +++ /dev/null @@ -1,51 +0,0 @@ -# -- Add an always run target to generate verilog files with sbt/bloop, as we -# don't know if the result files will be different from cmake NOTE: Must -# reconfigure if we add new files in SCALA_CORE directory -file(GLOB_RECURSE SCALA_CORE_SOURCES "${SCALA_CORE}/src/main/scala/*.scala") -file(GLOB_RECURSE SCALA_CORE_RESOURCES "${SCALA_CORE}/src/main/resources/*") -message(STATUS "Found scala source file: ${SCALA_CORE_SOURCES}") -set(CHISEL_DEPENDENCY ${SCALA_CORE_SOURCES} ${SCALA_CORE_RESOURCES} - ${SCALA_CORE}/build.sbt) - -if(BUILD_USE_BLOOP) - message(STATUS "Building core using bloop") - set(CHISEL_TARGET bloop_${TOPMODULE}) - set(CHISEL_TEST_TARGET bloop_${TOPMODULE}_test) - # Export sbt build config to bloop - if(NOT EXISTS ${SCALA_CORE}/.bloop) - execute_process(COMMAND sbt bloopInstall WORKING_DIRECTORY ${SCALA_CORE}) - endif() - string(REPLACE " " ";" CHISEL_EMIT_ARGS_LIST ${CHISEL_EMIT_ARGS}) - list(TRANSFORM CHISEL_EMIT_ARGS_LIST PREPEND "--args;") - add_custom_command( - OUTPUT ${CHISEL_OUTPUT_TOPMODULE} ${CHISEL_OUTPUT_VERILATOR_CONF} - COMMAND bloop run --no-color root ${CHISEL_EMIT_ARGS_LIST} - WORKING_DIRECTORY ${SCALA_CORE} - DEPENDS ${CHISEL_DEPENDENCY} - COMMAND_EXPAND_LISTS - COMMENT "Run bloop from CMake") - # add_test( NAME bloop_${TOPMODULE}_test COMMAND bloop test WORKING_DIRECTORY - # ${SCALA_CORE} ) -else() - message(STATUS "Building core using sbt") - set(CHISEL_TARGET sbt_${TOPMODULE}) - set(CHISEL_TEST_TARGET sbt_${TOPMODULE}_test) - add_custom_command( - OUTPUT ${CHISEL_OUTPUT_TOPMODULE} ${CHISEL_OUTPUT_VERILATOR_CONF} - COMMAND sbt "run ${CHISEL_EMIT_ARGS}" - WORKING_DIRECTORY ${SCALA_CORE} - DEPENDS ${CHISEL_DEPENDENCY} - VERBATIM - COMMENT "Run sbt from CMake") - add_test( - NAME sbt_${TOPMODULE}_test - COMMAND sbt test - WORKING_DIRECTORY ${SCALA_CORE}) -endif() - -if(NOT EXISTS ${CHISEL_OUTPUT_TOPMODULE}) - # Probably cold build, generate verilog at configure time to produce top - # module file - execute_process(COMMAND sbt "run ${CHISEL_EMIT_ARGS}" - WORKING_DIRECTORY ${SCALA_CORE}) -endif() diff --git a/npc/cmake/FindReadline.cmake b/npc/cmake/FindReadline.cmake deleted file mode 100644 index dc2dd41..0000000 --- a/npc/cmake/FindReadline.cmake +++ /dev/null @@ -1,49 +0,0 @@ -# Code copied from sethhall@github -# -# - Try to find readline include dirs and libraries -# -# Usage of this module as follows: -# -# find_package(Readline) -# -# Variables used by this module, they can change the default behaviour and need -# to be set before calling find_package: -# -# Readline_ROOT_DIR Set this variable to the root installation of -# readline if the module has problems finding the -# proper installation path. -# -# Variables defined by this module: -# -# READLINE_FOUND System has readline, include and lib dirs found -# Readline_INCLUDE_DIR The readline include directories. -# Readline_LIBRARY The readline library. - -find_path(Readline_ROOT_DIR - NAMES include/readline/readline.h -) - -find_path(Readline_INCLUDE_DIR - NAMES readline/readline.h - HINTS ${Readline_ROOT_DIR}/include -) - -find_library(Readline_LIBRARY - NAMES readline - HINTS ${Readline_ROOT_DIR}/lib -) - -if(Readline_INCLUDE_DIR AND Readline_LIBRARY AND Ncurses_LIBRARY) - set(READLINE_FOUND TRUE) -else(Readline_INCLUDE_DIR AND Readline_LIBRARY AND Ncurses_LIBRARY) - find_library(Readline_LIBRARY NAMES readline) - include(FindPackageHandleStandardArgs) - find_package_handle_standard_args(Readline DEFAULT_MSG Readline_INCLUDE_DIR Readline_LIBRARY ) - mark_as_advanced(Readline_INCLUDE_DIR Readline_LIBRARY) -endif(Readline_INCLUDE_DIR AND Readline_LIBRARY AND Ncurses_LIBRARY) - -mark_as_advanced( - Readline_ROOT_DIR - Readline_INCLUDE_DIR - Readline_LIBRARY -) \ No newline at end of file diff --git a/npc/core/build.sbt b/npc/core/build.sbt index e5de39d..e04b603 100644 --- a/npc/core/build.sbt +++ b/npc/core/build.sbt @@ -1,8 +1,8 @@ -ThisBuild / scalaVersion := "2.13.12" -ThisBuild / version := "0.1.0" +ThisBuild / scalaVersion := "2.13.12" +ThisBuild / version := "0.1.0" + val chiselVersion = "6.2.0" -val circeVersion = "0.14.1" lazy val root = (project in file(".")) .settings( @@ -10,21 +10,14 @@ lazy val root = (project in file(".")) libraryDependencies ++= Seq( "org.chipsalliance" %% "chisel" % chiselVersion, "edu.berkeley.cs" %% "chiseltest" % "6.0.0" % "test", - "com.chuusai" %% "shapeless" % "2.3.3", - "com.github.scopt" %% "scopt" % "4.1.0" - ) ++ Seq( - "io.circe" %% "circe-core", - "io.circe" %% "circe-generic", - "io.circe" %% "circe-parser" - ).map(_ % circeVersion), + "com.chuusai" %% "shapeless" % "2.3.3" + ), scalacOptions ++= Seq( "-language:reflectiveCalls", "-deprecation", "-feature", "-Xcheckinit", - "-Ymacro-annotations" + "-Ymacro-annotations", ), - addCompilerPlugin( - "org.chipsalliance" % "chisel-plugin" % chiselVersion cross CrossVersion.full - ) + addCompilerPlugin("org.chipsalliance" % "chisel-plugin" % chiselVersion cross CrossVersion.full), ) diff --git a/npc/core/project/build.properties b/npc/core/project/build.properties deleted file mode 100644 index 04267b1..0000000 --- a/npc/core/project/build.properties +++ /dev/null @@ -1 +0,0 @@ -sbt.version=1.9.9 diff --git a/npc/core/src/main/resources/RamDpi.v b/npc/core/src/main/resources/RamDpi.v deleted file mode 100644 index cbab381..0000000 --- a/npc/core/src/main/resources/RamDpi.v +++ /dev/null @@ -1,29 +0,0 @@ -import "DPI-C" function int pmem_read(input int addr); -import "DPI-C" function void pmem_write(input int waddr, input int wdata, input byte wmask); - -module RamDpi ( - input clock, - input reset, - input writeEnable, - input valid, - input [31:0] writeAddr, - input [31:0] writeData, - input [3:0] writeMask, - input reg [31:0] readAddr, - output reg [31:0] readData, - input reg [31:0] pc, - output reg [31:0] inst -); - always @(posedge clock) begin - if (valid) begin // 有读写请求时 - readData = pmem_read(readAddr); - if (writeEnable) begin // 有写请求时 - pmem_write(writeAddr, writeData, { 4'h0, writeMask }); - end - end - else begin - readData = 32'h80000000; - end - end - assign inst = pmem_read(pc); -endmodule diff --git a/npc/core/src/main/scala/ALU.scala b/npc/core/src/main/scala/ALU.scala new file mode 100644 index 0000000..70f0fea --- /dev/null +++ b/npc/core/src/main/scala/ALU.scala @@ -0,0 +1,63 @@ +package flow.components + +import chisel3._ +import chisel3.util._ +import shapeless.{HNil, ::} + +class ALUControlInterface extends Bundle { + object OpSelect extends ChiselEnum { + val aOpAdd, aOpSub, aOpNot, aOpAnd, aOpOr, aOpXor, aOpSlt, aOpEq, aOpNop = Value + } + object SrcSelect extends ChiselEnum { + val aSrcRs1, aSrcImm = Value + } + val op = Input(OpSelect()) + val src = Input(SrcSelect()) + + type CtrlTypes = OpSelect.Type :: SrcSelect.Type :: HNil + def ctrlBindPorts: CtrlTypes = { + op :: src :: HNil + } +} + +class ALU[T <: UInt](tpe: T) extends Module { + val control = IO(new ALUControlInterface) + val in = IO(new Bundle { + val a = Input(Vec(control.SrcSelect.all.length, tpe)) + val b = Input(tpe) + }) + val out = IO(new Bundle { + val result = Output(tpe) + }) + + val a = in.a(control.src.asUInt) + + // val adder_b = (Fill(tpe.getWidth, io.op(0)) ^ io.b) + io.op(0) // take (-b) if sub + val add = a + in.b + val sub = a - in.b + val and = a & in.b + val not = ~a + val or = a | in.b + val xor = a ^ in.b + val slt = a < in.b + val eq = a === in.b + + import control.OpSelect._ + + out.result := MuxLookup(control.op, 0.U)(Seq( + aOpAdd -> add, + aOpSub -> sub, + aOpNot -> not, + aOpAnd -> and, + aOpOr -> or, + aOpXor -> xor, + aOpSlt -> slt, + aOpEq -> eq + )) +} + +object ALU { + def apply[T <: UInt](tpe: T): ALU[T] = { + Module(new ALU(tpe)) + } +} diff --git a/npc/core/src/main/scala/utils/Keyboard.scala b/npc/core/src/main/scala/Keyboard.scala similarity index 76% rename from npc/core/src/main/scala/utils/Keyboard.scala rename to npc/core/src/main/scala/Keyboard.scala index fd37a9c..716c304 100644 --- a/npc/core/src/main/scala/utils/Keyboard.scala +++ b/npc/core/src/main/scala/Keyboard.scala @@ -55,7 +55,7 @@ class KeyboardController extends Module { } class KeyboardSegController extends Module { - val io = IO(new Bundle { + val io = IO(new Bundle{ val keycode = Flipped(Decoupled(UInt(8.W))) val segs = Vec(8, UInt(8.W)) }) @@ -66,60 +66,30 @@ class KeyboardSegController extends Module { // 0x1C.U -> 0x41.U, ... val keycode_to_ascii = Seq( - 0x1c.U, - 0x32.U, - 0x21.U, - 0x23.U, - 0x24.U, - 0x2b.U, - 0x34.U, - 0x33.U, - 0x43.U, - 0x3b.U, - 0x42.U, - 0x4b.U, - 0x3a.U, - 0x31.U, - 0x44.U, - 0x4d.U, - 0x15.U, - 0x2d.U, - 0x1b.U, - 0x2c.U, - 0x3c.U, - 0x2a.U, - 0x1d.U, - 0x22.U, - 0x35.U, - 0x1a.U, - 0x45.U, - 0x16.U, - 0x1e.U, - 0x26.U, - 0x25.U, - 0x2e.U, - 0x36.U, - 0x3d.U, - 0x3e.U, - 0x46.U - ).zip(((0x41 to 0x5a) ++ (0x30 to 0x39)).map(_.U)) + 0x1C.U, 0x32.U, 0x21.U, 0x23.U, 0x24.U, 0x2B.U, + 0x34.U, 0x33.U, 0x43.U, 0x3B.U, 0x42.U, 0x4B.U, + 0x3A.U, 0x31.U, 0x44.U, 0x4D.U, 0x15.U, 0x2D.U, + 0x1B.U, 0x2C.U, 0x3C.U, 0x2A.U, 0x1D.U, 0x22.U, + 0x35.U, 0x1A.U, 0x45.U, 0x16.U, 0x1E.U, 0x26.U, + 0x25.U, 0x2E.U, 0x36.U, 0x3D.U, 0x3E.U, 0x46.U, + ).zip(((0x41 to 0x5A) ++ (0x30 to 0x39)).map(_.U)) val keycode = RegInit(0.U(8.W)) - val counter = Counter(0xff) + val counter = Counter(0xFF) val release_state = RegInit(Bool(), false.B) when(io.keycode.ready && io.keycode.valid) { - when(io.keycode.bits === 0xf0.U) { + when(io.keycode.bits === 0xF0.U) { release_state := true.B }.elsewhen(!release_state) { counter.inc() keycode := io.keycode.bits - }.otherwise { + }.otherwise{ // Release code on io.keycode.bits release_state := false.B } } - val keycode_digits = VecInit(keycode(3, 0)) ++ VecInit(keycode(7, 4)) + val keycode_digits = VecInit(keycode(3,0)) ++ VecInit(keycode(7,4)) val ascii = MuxLookup(keycode, 0.U)(keycode_to_ascii) val seg_contoller = Module(new SegControllerGenerator(8, UInt(8.W))) diff --git a/npc/core/src/main/scala/Main.scala b/npc/core/src/main/scala/Main.scala new file mode 100644 index 0000000..1ede7e1 --- /dev/null +++ b/npc/core/src/main/scala/Main.scala @@ -0,0 +1,129 @@ +package flow + +import scala.reflect.runtime.universe._ +import chisel3._ +import chisel3.util.{MuxLookup, Fill, Decoupled, Counter, Queue, Reverse} +import chisel3.util.{SRAM} +import chisel3.util.experimental.decode.{decoder, TruthTable} +import chisel3.stage.ChiselOption +import chisel3.util.log2Ceil +import chisel3.util.BitPat +import chisel3.util.Enum +import chisel3.experimental.prefix +import shapeless.{HNil, ::} +import shapeless.HList +import shapeless.ops.coproduct.Prepend +import chisel3.util.{ BinaryMemoryFile, HexMemoryFile } + +object RV32Inst { + private val bp = BitPat + val addi = this.bp("b???????_?????_?????_000_?????_00100_11") + val inv = this.bp("b???????_?????_?????_???_?????_?????_??") +} + +class PcControl(width: Int) extends Bundle { + object SrcSelect extends ChiselEnum { + val pPC, pExeResult = Value + } + val srcSelect = Output(SrcSelect()) +} + +import flow.components.{RegControl, PcControlInterface, ALUControlInterface} +class Control(width: Int) extends Module { + val inst = IO(Input(UInt(width.W))) + + val reg = IO(Flipped(new RegControl)) + val pc = IO(Flipped(new PcControlInterface)) + val alu = IO(Flipped(new ALUControlInterface)) + + // TODO: Add .ctrlTypes together instead of writing them by hand. + type T = + Bool :: reg.WriteSelect.Type :: pc.SrcSelect.Type :: alu.OpSelect.Type :: alu.SrcSelect.Type :: HNil + val dst: T = reg.ctrlBindPorts ++ pc.ctrlBindPorts ++ alu.ctrlBindPorts + + val dstList = dst.toList + val reversePrefixSum = dstList.scanLeft(0)(_ + _.getWidth).reverse + val slices = reversePrefixSum.zip(reversePrefixSum.tail) + + import reg.WriteSelect._ + import pc.SrcSelect._ + import alu.OpSelect._ + import alu.SrcSelect._ + import RV32Inst._ + val ControlMapping: Array[(BitPat, T)] = Array( + // Regs :: PC :: Exe + // writeEnable :: writeSelect :: srcSelect :: + (addi, true.B :: rAluOut :: pStaticNpc :: aOpAdd :: aSrcImm :: HNil), + ) + val default = BitPat.dontCare(dstList.map(_.getWidth).reduce(_ + _)) + + def toBits(t: T): BitPat = { + val list: List[Data] = t.toList + list.map(x => BitPat(x.litValue.toInt.U(x.getWidth.W))).reduceLeft(_ ## _) + } + val out = decoder( + inst, + TruthTable(ControlMapping.map(it => (it._1 -> toBits(it._2))), default)) + val srcList = slices.map(s => out(s._1 - 1, s._2)) + + srcList + .zip(dstList.reverse) + .foreach({ case (src, dst) => + dst := src.asTypeOf(dst) + }) +} + +import flow.components.{RegisterFile, RegFileInterface, ProgramCounter, ALU} +import chisel3.util.experimental.loadMemoryFromFileInline +class Flow extends Module { + val dataType = UInt(32.W) + + val ram = SRAM( + size = 1024, + tpe = dataType, + numReadPorts = 2, + numWritePorts = 1, + numReadwritePorts = 0, + memoryFile = HexMemoryFile("./resource/addi.txt") + ) + val control = Module(new Control(32)) + val reg = RegisterFile(32, dataType, 2, 2) + val pc = Module(new ProgramCounter(dataType)) + val alu = Module(new ALU(dataType)) + + ram.readPorts(0).enable := true.B + ram.readPorts(0).address := pc.out - 0x80000000L.U + val inst = ram.readPorts(0).data + + import control.pc.SrcSelect._ + + pc.in.pcSrcs(pStaticNpc.litValue.toInt) := pc.out + 4.U + pc.in.pcSrcs(pBranchResult.litValue.toInt) := alu.out.result + + control.inst := inst + reg.control <> control.reg + pc.control <> control.pc + alu.control <> control.alu + + import control.reg.WriteSelect._ + reg.in.writeData(rAluOut.litValue.toInt) := alu.out.result + // TODO: Read address in load command goes here + ram.readPorts(1).enable := false.B + ram.readPorts(1).address := 0.U + reg.in.writeData(rMemOut.litValue.toInt) := ram.readPorts(1).data + reg.in.writeAddr := inst(11, 7) + reg.in.rs(0) := inst(19, 15) + reg.in.rs(1) := inst(24, 20) + + // TODO: Memory write goes here + ram.writePorts(0).address := 1.U + ram.writePorts(0).data := 1.U + ram.writePorts(0).enable := false.B + + import control.alu.SrcSelect._ + alu.in.a(aSrcRs1.litValue.toInt) := reg.out.src(0) + alu.in.a(aSrcImm.litValue.toInt) := inst(31, 20) + alu.in.b := reg.out.src(1) + + dontTouch(control.out) +} diff --git a/npc/core/src/main/scala/ProgramCounter.scala b/npc/core/src/main/scala/ProgramCounter.scala new file mode 100644 index 0000000..bfb3e1b --- /dev/null +++ b/npc/core/src/main/scala/ProgramCounter.scala @@ -0,0 +1,39 @@ +package flow.components +import chisel3._ +import chisel3.util.{Valid, log2Ceil} +import chisel3.util.MuxLookup +import shapeless.{HNil, ::} + +class PcControlInterface extends Bundle { + object SrcSelect extends ChiselEnum { + val pStaticNpc, pBranchResult = Value + } + + val srcSelect = Input(SrcSelect()) + + type CtrlTypes = SrcSelect.Type :: HNil + def ctrlBindPorts: CtrlTypes = { + srcSelect :: HNil + } +} + +class ProgramCounter[T <: Data](tpe: T) extends Module { + + val control = IO(new PcControlInterface) + val in = IO(new Bundle { + val pcSrcs = Input(Vec(control.SrcSelect.all.length, tpe)) + }) + val out = IO(Output(tpe)) + + private val pc = RegInit(0x80000000L.U) + + pc := in.pcSrcs(control.srcSelect.asUInt) + out := pc +} + +object ProgramCounter { + def apply[T <: Data](tpe: T): ProgramCounter[T] = { + val pc = Module(new ProgramCounter(tpe)) + pc + } +} diff --git a/npc/core/src/main/scala/RegisterFile.scala b/npc/core/src/main/scala/RegisterFile.scala new file mode 100644 index 0000000..509ceaa --- /dev/null +++ b/npc/core/src/main/scala/RegisterFile.scala @@ -0,0 +1,86 @@ +package flow.components + +import chisel3._ +import chisel3.util.log2Ceil +import chisel3.util.UIntToOH +import chisel3.util.MuxLookup +import shapeless.{ HNil, :: } + +class RegControl extends Bundle { + object WriteSelect extends ChiselEnum { + val rAluOut, rMemOut = Value + } + + val writeEnable = Input(Bool()) + val writeSelect = Input(WriteSelect()) + + type CtrlTypes = Bool :: WriteSelect.Type :: HNil + def ctrlBindPorts: CtrlTypes = { + writeEnable :: writeSelect :: HNil + } +} + +class RegFileData[T <: Data](size:Int, tpe: T, numReadPorts: Int, numWritePorts: Int) extends Bundle { + val write = new Bundle { + val addr = Input(UInt(size.W)) + val data = Vec(numWritePorts, Input(tpe)) + } + val read = Vec(numReadPorts, new Bundle { + val rs = Input(UInt(size.W)) + val src = Output(tpe) + }) +} + +class RegFileInterface[T <: Data](size: Int, tpe: T, numReadPorts: Int, numWritePorts: Int) extends Bundle { + val control = new RegControl + // val data = new RegFileData(size, tpe, numReadPorts, numWritePorts) + val in = new Bundle { + val writeAddr = Input(UInt(size.W)) + val writeData = Input(Vec(numWritePorts, tpe)) + val rs = Input(Vec(numReadPorts, UInt(size.W))) + } + val out = new Bundle { + val src = Output(Vec(numReadPorts, tpe)) + } +} + +class RegisterFileCore[T <: Data](size: Int, tpe: T, numReadPorts: Int) extends Module { + require(numReadPorts >= 0) + val writePort = IO(new Bundle { + val enable = Input(Bool()) + val addr = Input(UInt(log2Ceil(size).W)) + val data = Input(tpe) + }) + val readPorts = IO(Vec(numReadPorts, new Bundle { + val addr = Input(UInt(log2Ceil(size).W)) + val data = Output(tpe) + })) + + val regFile = RegInit(VecInit(Seq.fill(size)(0.U(tpe.getWidth.W)))) + val writeAddrOH = UIntToOH(writePort.addr) + for ((reg, i) <- regFile.zipWithIndex.tail) { + reg := Mux(writeAddrOH(i) && writePort.enable, writePort.data, reg) + } + regFile(0) := 0.U + + for (readPort <- readPorts) { + readPort.data := regFile(readPort.addr) + } + dontTouch(regFile) +} + +object RegisterFile { + def apply[T <: Data](size: Int, tpe: T, numReadPorts: Int, numWritePorts: Int): RegFileInterface[T] = { + val core = Module(new RegisterFileCore(size, tpe, numReadPorts)) + val _out = Wire(new RegFileInterface(size, tpe, numReadPorts, numWritePorts)) + val clock = core.clock + for (i <- 0 until numReadPorts) { + core.readPorts(i).addr := _out.in.rs(i) + _out.out.src(i) := core.readPorts(i).data + } + core.writePort.addr := _out.in.writeAddr + core.writePort.data := _out.in.writeData(_out.control.writeSelect.asUInt) + core.writePort.enable := _out.control.writeEnable + _out + } +} diff --git a/npc/core/src/main/scala/SegControllerGenerator.scala b/npc/core/src/main/scala/SegControllerGenerator.scala new file mode 100644 index 0000000..7f2cb68 --- /dev/null +++ b/npc/core/src/main/scala/SegControllerGenerator.scala @@ -0,0 +1,24 @@ +package npc.util + +import chisel3._ +import chisel3.util._ +import chisel3.util.log2Ceil + +class SegControllerGenerator[T <: Data](seg_count: Int, t: T) extends Module { + val io = IO(new Bundle { + val in_segs = Input(Vec(seg_count / ((t.getWidth + 3) / 4), t)) + val segs = Output(Vec(seg_count, UInt(8.W))) + }) + val digit_to_seg = ((0 until 16).map(_.U)).zip(Seq( + "b00000011".U, "b10011111".U, "b00100101".U, "b00001101".U, + "b10011001".U, "b01001001".U, "b01000001".U, "b00011111".U, + "b00000001".U, "b00001001".U, "b00010001".U, "b11000001".U, + "b01100011".U, "b10000101".U, "b01100001".U, "b01110001".U, + )) + val vec = io.in_segs.asTypeOf(Vec(seg_count, UInt(4.W))) + + val segs = VecInit(Seq.fill(seg_count)(0.U(8.W))) + segs := vec.map(MuxLookup(_, 0xFF.U)(digit_to_seg)) + + io.segs := segs +} diff --git a/npc/core/src/main/scala/components/ALU.scala b/npc/core/src/main/scala/components/ALU.scala deleted file mode 100644 index 0c1f0ae..0000000 --- a/npc/core/src/main/scala/components/ALU.scala +++ /dev/null @@ -1,79 +0,0 @@ -package flow.components - -import chisel3._ -import chisel3.util._ -import shapeless.{HNil, ::} - -class ALUControlInterface extends Bundle { - object OpSelect extends ChiselEnum { - val aOpAdd, aOpSub, aOpNot, aOpAnd, aOpOr, aOpXor, aOpSlt, aOpSltu, aOpSll, - aOpSrl, aOpSra = Value - } - object SrcASelect extends ChiselEnum { - val aSrcARs1, aSrcAPc, aSrcAZero = Value - } - object SrcBSelect extends ChiselEnum { - val aSrcBRs2, aSrcBImmI, aSrcBImmJ, aSrcBImmS, aSrcBImmU = Value - } - val op = Input(OpSelect()) - val srcASelect = Input(SrcASelect()) - val srcBSelect = Input(SrcBSelect()) - val signExt = Input(Bool()) - - def ctrlBindPorts = { - op :: srcASelect :: srcBSelect :: signExt :: HNil - } -} - -class ALU[T <: UInt](tpe: T) extends Module { - val control = IO(new ALUControlInterface) - val in = IO(new Bundle { - val a = Input(Vec(control.SrcASelect.all.length, tpe)) - val b = Input(Vec(control.SrcBSelect.all.length, tpe)) - }) - val out = IO(new Bundle { - val eq = Output(Bool()) - val result = Output(tpe) - }) - - val a = in.a(control.srcASelect.asUInt) - val b = in.b(control.srcBSelect.asUInt) - - // val adder_b = (Fill(tpe.getWidth, io.op(0)) ^ io.b) + io.op(0) // take (-b) if sub - val add = a + b - val sub = a - b - val and = a & b - val not = ~a - val or = a | b - val xor = a ^ b - val slt = a.asSInt < b.asSInt - val sltu = a < b - val sll = a << b(log2Ceil(tpe.getWidth), 0) - val srl = a >> b(log2Ceil(tpe.getWidth), 0) - val sra = a.asSInt >> b(log2Ceil(tpe.getWidth), 0) - out.eq := a === b - - import control.OpSelect._ - - out.result := MuxLookup(control.op, 0.U)( - Seq( - aOpAdd -> add, - aOpSub -> sub, - aOpNot -> not, - aOpAnd -> and, - aOpOr -> or, - aOpXor -> xor, - aOpSlt -> slt, - aOpSltu -> sltu, - aOpSll -> sll, - aOpSrl -> srl, - aOpSra -> sra.asUInt - ) - ) -} - -object ALU { - def apply[T <: UInt](tpe: T): ALU[T] = { - Module(new ALU(tpe)) - } -} diff --git a/npc/core/src/main/scala/components/CSR.scala b/npc/core/src/main/scala/components/CSR.scala deleted file mode 100644 index 5ea795f..0000000 --- a/npc/core/src/main/scala/components/CSR.scala +++ /dev/null @@ -1,108 +0,0 @@ -package flow.components - -import chisel3._ -import chisel3.util.log2Ceil -import scala.reflect.runtime.universe._ -import cats.instances.MapInstances -import dataclass.data -import chisel3.util.experimental.decode.{decoder, TruthTable} -import shapeless.HNil -import flow.Params -import chisel3.util.BitPat -import chisel3.util.Fill - -class CSRControlInterface extends Bundle { - object csrRead extends ChiselEnum { - val csrReadDisabled, csrReadEnabled = Value - } - - object csrWrite extends ChiselEnum { - val csrWriteDisabled, csrWriteEnabled = Value - } - - val readEnable = Input(csrRead()) - val writeEnable = Input(csrWrite()) - - def ctrlBindPorts = { - readEnable :: writeEnable :: HNil - } -} - -class CSRCore(implicit val p: Params) extends Module { - val control = IO(new CSRControlInterface) - - val in = IO(new Bundle { - val csrAddr = Input(UInt(p.csrAddrWidth)) - val writeData = Input(UInt(p.XLEN)) - }) - - val out = IO(new Bundle { - val readData = Output(UInt(p.XLEN)) - val readValid = Output(Bool()) - }) - - implicit class fromChiselEnumToBool[T <: EnumType](x: T) { - def B: Bool = { - x.asUInt =/= 0.U - } - } - - val nameToAddr = Map( - "mstatus" -> 0x300, - "mtvec" -> 0x305, - "mie" -> 0x304, - "mepc" -> 0x341, - "mcause" -> 0x342, - "mtval" -> 0x343, - "mip" -> 0x344 - ) - val csrSize = nameToAddr.size - - val addrToIndex = nameToAddr.zipWithIndex - .map(x => { - val (name: String, csrAddr: Int) = x._1 - val index = x._2 - - csrAddr -> index - }) - .toMap - val indexToAddr = addrToIndex.map(_.swap) - - val csrIndexWidth = log2Ceil(csrSize).W - - private val align = (x: UInt, w: Width) => BitPat(x.litValue.U(w)) - val csrIndex = decoder( - in.csrAddr, - TruthTable( - addrToIndex.map(x => - // Addr Index - (align(x._1.U, p.csrAddrWidth), align(x._2.U, csrIndexWidth)) - ), - align(addrToIndex.head._2.U, csrIndexWidth) - ) - ) - - val csrIndexValid = !( - csrIndex === BitPat(0.U) && - in.csrAddr =/= align(indexToAddr(0).U, p.csrAddrWidth) - ) - - val regs = RegInit(VecInit(Seq.fill(csrSize)(0.U(p.XLEN)))) - - val regReadValue = regs(csrIndex) - - val delayWriteData = RegNext(in.writeData, 0.U(p.XLEN)) - val delayWriteEnable = RegNext(control.writeEnable) - - when(control.writeEnable.B) { - regs(csrIndex) := delayWriteData - } - - when(control.readEnable.B) { - out.readData := regReadValue - out.readValid := true.B && csrIndexValid - } otherwise { - out.readData := 0.U(p.XLEN) - out.readValid := false.B && csrIndexValid - } -} diff --git a/npc/core/src/main/scala/components/Mem.scala b/npc/core/src/main/scala/components/Mem.scala deleted file mode 100644 index 52889cb..0000000 --- a/npc/core/src/main/scala/components/Mem.scala +++ /dev/null @@ -1,42 +0,0 @@ -package flow.components - -import chisel3._ -import chisel3.experimental.noPrefix -import chisel3.util.HasBlackBoxPath -import chisel3.util.HasBlackBoxResource -import chisel3.util.log2Ceil -import flow.components -import shapeless.:: -import shapeless.HNil - -import scala.collection.SeqMap - -class RamControlInterface(addrWidth: Int) extends Bundle { - val valid = Input(Bool()) - val writeMask = Input(UInt((addrWidth / 8).W)) - val writeEnable = Input(Bool()) - def ctrlBindPorts = { - valid :: writeMask :: writeEnable :: HNil - } - -} - -/* FIXME: Extends here might not be the best solution. - * We need a way to merge two bundles together - */ -class RamInterface[T <: Data](tpe: T, addrWidth: Int) - extends RamControlInterface(addrWidth) { - val clock = Input(Clock()) - val reset = Input(Reset()) - val writeAddr = Input(UInt(addrWidth.W)) - val writeData = Input(tpe) - val readAddr = Input(UInt(addrWidth.W)) - val readData = Output(tpe) - val pc = Input(UInt(addrWidth.W)) - val inst = Output(tpe) -} - -class RamDpi extends BlackBox with HasBlackBoxResource { - val io = IO((new RamInterface(UInt(32.W), 32))) - addResource("/RamDpi.v") -} diff --git a/npc/core/src/main/scala/components/ProgramCounter.scala b/npc/core/src/main/scala/components/ProgramCounter.scala deleted file mode 100644 index 287ca7f..0000000 --- a/npc/core/src/main/scala/components/ProgramCounter.scala +++ /dev/null @@ -1,48 +0,0 @@ -package flow.components -import chisel3._ -import chisel3.util.{Valid, log2Ceil} -import chisel3.util.MuxLookup -import shapeless.{HNil, ::} - -class PcControlInterface extends Bundle { - object SrcSelect extends ChiselEnum { - val pStaticNpc, pExeOut = Value - } - - val useImmB = Input(Bool()) - val srcSelect = Input(SrcSelect()) - - def ctrlBindPorts = { - useImmB :: srcSelect :: HNil - } -} - -class ProgramCounter[T <: UInt](tpe: T) extends Module { - - val control = IO(new PcControlInterface) - val in = IO(new Bundle { - val immB = Input(tpe) - val exeOut = Input(tpe) - }) - val out = IO(Output(tpe)) - - private val pc_reg = RegInit(0x80000000L.U) - -// pc := in.pcSrcs(control.srcSelect.asUInt) - import control.SrcSelect._ - when(control.useImmB === true.B) { - pc_reg := pc_reg + in.immB - }.elsewhen(control.srcSelect === pStaticNpc) { - pc_reg := pc_reg + 4.U - }.elsewhen(control.srcSelect === pExeOut) { - pc_reg := in.exeOut - } - out := pc_reg -} - -object ProgramCounter { - def apply[T <: UInt](tpe: T): ProgramCounter[T] = { - val pc = Module(new ProgramCounter(tpe)) - pc - } -} diff --git a/npc/core/src/main/scala/components/RV32Inst.scala b/npc/core/src/main/scala/components/RV32Inst.scala deleted file mode 100644 index ddb06f9..0000000 --- a/npc/core/src/main/scala/components/RV32Inst.scala +++ /dev/null @@ -1,106 +0,0 @@ -package flow.components - -import chisel3.util.BitPat - -object RV32Inst { - private val bp = BitPat - - // format: off - val lui = this.bp("b???????_?????_?????_???_?????_01101_11") - val auipc = this.bp("b???????_?????_?????_???_?????_00101_11") - - val jal = this.bp("b???????_?????_?????_???_?????_11011_11") - val jalr = this.bp("b???????_?????_?????_???_?????_11001_11") - val beq = this.bp("b???????_?????_?????_000_?????_11000_11") - val bne = this.bp("b???????_?????_?????_001_?????_11000_11") - val blt = this.bp("b???????_?????_?????_100_?????_11000_11") - val bge = this.bp("b???????_?????_?????_101_?????_11000_11") - val bltu = this.bp("b???????_?????_?????_110_?????_11000_11") - val bgeu = this.bp("b???????_?????_?????_111_?????_11000_11") - - val lb = this.bp("b???????_?????_?????_000_?????_00000_11") - val lh = this.bp("b???????_?????_?????_001_?????_00000_11") - val lw = this.bp("b???????_?????_?????_010_?????_00000_11") - val lbu = this.bp("b???????_?????_?????_100_?????_00000_11") - val lhu = this.bp("b???????_?????_?????_101_?????_00000_11") - val sb = this.bp("b???????_?????_?????_000_?????_01000_11") - val sh = this.bp("b???????_?????_?????_001_?????_01000_11") - val sw = this.bp("b???????_?????_?????_010_?????_01000_11") - - val addi = this.bp("b???????_?????_?????_000_?????_00100_11") - val slti = this.bp("b???????_?????_?????_010_?????_00100_11") - val sltiu = this.bp("b???????_?????_?????_011_?????_00100_11") - val xori = this.bp("b???????_?????_?????_100_?????_00100_11") - val ori = this.bp("b???????_?????_?????_110_?????_00100_11") - val andi = this.bp("b???????_?????_?????_111_?????_00100_11") - val slli = this.bp("b0000000_?????_?????_001_?????_00100_11") - val srli = this.bp("b0000000_?????_?????_101_?????_00100_11") - val srai = this.bp("b0100000_?????_?????_101_?????_00100_11") - val add = this.bp("b0000000_?????_?????_000_?????_01100_11") - val sub = this.bp("b0100000_?????_?????_000_?????_01100_11") - val sll = this.bp("b0000000_?????_?????_001_?????_01100_11") - val slt = this.bp("b0000000_?????_?????_010_?????_01100_11") - val sltu = this.bp("b0000000_?????_?????_011_?????_01100_11") - val xor = this.bp("b0000000_?????_?????_100_?????_01100_11") - val srl = this.bp("b0000000_?????_?????_101_?????_01100_11") - val sra = this.bp("b0100000_?????_?????_101_?????_01100_11") - val or = this.bp("b0000000_?????_?????_110_?????_01100_11") - val and = this.bp("b0000000_?????_?????_111_?????_01100_11") - - val ebreak = this.bp("b0000000_00001_00000_000_00000_11100_11") - - val csrrw = this.bp("b???????_?????_?????_001_?????_11100_11") - - - val mul = this.bp("b0000001_?????_?????_000_?????_01100_11") - val mulh = this.bp("b0000001_?????_?????_001_?????_01100_11") - val mulhsu = this.bp("b0000001_?????_?????_010_?????_01100_11") - val mulhu = this.bp("b0000001_?????_?????_011_?????_01100_11") - val div = this.bp("b0000001_?????_?????_100_?????_01100_11") - val divu = this.bp("b0000001_?????_?????_101_?????_01100_11") - val rem = this.bp("b0000001_?????_?????_110_?????_01100_11") - val remu = this.bp("b0000001_?????_?????_111_?????_01100_11") - - val inv = this.bp("b???????_?????_?????_???_?????_?????_??") - // format: on -} - -import chisel3._ -import chisel3.util._ -import flow.Params -object RV32InstSubfields { - implicit class ImmDecoder(val inst: UInt) extends AnyVal { - def immB: UInt = Cat( - Fill(20, inst(31)), - inst(7), - inst(30, 25), - inst(11, 8), - 0.U(1.W) - ) - - def immI: UInt = Cat(Fill(20, inst(31)), inst(31, 20)) - - def immJ: UInt = Cat( - Fill(12, inst(31)), - inst(19, 12), - inst(20), - inst(30, 25), - inst(24, 21), - 0.U(1.W) - ) - - def immS: UInt = Cat( - Fill(20, inst(31)), - inst(31), - inst(30, 25), - inst(11, 8), - inst(7) - ) - - def immU: UInt = Cat(inst(31, 12), 0.U(12.W)) - - def rd: UInt = inst(11, 7) - def rs1: UInt = inst(19, 15) - def rs2: UInt = inst(24, 20) - } -} diff --git a/npc/core/src/main/scala/components/RegisterFile.scala b/npc/core/src/main/scala/components/RegisterFile.scala deleted file mode 100644 index fe646fd..0000000 --- a/npc/core/src/main/scala/components/RegisterFile.scala +++ /dev/null @@ -1,56 +0,0 @@ -package flow.components - -import chisel3._ -import chisel3.util.log2Ceil -import chisel3.util.UIntToOH -import chisel3.util.MuxLookup -import chisel3.experimental.Trace._ -import shapeless.{HList, HNil, ::} - -class RegControl extends Bundle { - object WriteSelect extends ChiselEnum { - val rAluOut, rMemOut, rNpc = Value - } - - val writeEnable = Input(Bool()) - val writeSelect = Input(WriteSelect()) - - def ctrlBindPorts = { - writeEnable :: writeSelect :: HNil - } - traceName(writeEnable) -} - -class RegisterFile[T <: Data](tpe: T, regCount: Int, numReadPorts: Int) - extends Module { - require(numReadPorts >= 0) - val control = IO(new RegControl) - val dataAddrWidth = log2Ceil(regCount).W - val in = IO(new Bundle { - val writeAddr = Input(UInt(dataAddrWidth)) - val writeData = Input(Vec(control.WriteSelect.all.length, tpe)) - val rs = Input(Vec(numReadPorts, UInt(dataAddrWidth))) - }) - val out = IO(new Bundle { - val src = Output(Vec(numReadPorts, tpe)) - }) - - val regResetValue = 0.U(tpe.getWidth.W) - val regFile = RegInit(VecInit(Seq.fill(regCount)(regResetValue))) - val writeAddrOH = UIntToOH(in.writeAddr) - - for ((reg, i) <- regFile.zipWithIndex.tail) { - reg := Mux( - writeAddrOH(i.U(log2Ceil(regCount).W)) && control.writeEnable, - in.writeData(control.writeSelect.asUInt), - reg - ) - } - regFile(0) := 0.U - - for (port <- 0 until numReadPorts) { - out.src(port) := regFile(in.rs(port).asUInt) - } - traceName(regFile) - dontTouch(regFile) -} diff --git a/npc/core/src/main/scala/top/ArgParse.scala b/npc/core/src/main/scala/top/ArgParse.scala deleted file mode 100644 index 1b8cf41..0000000 --- a/npc/core/src/main/scala/top/ArgParse.scala +++ /dev/null @@ -1,52 +0,0 @@ -package flow - -import scopt.{OParser, DefaultOEffectSetup} -import java.io.File - -case class CliOptions( - targetDir: File = new File("."), - configFile: Option[File] = None, - argsFile: Option[File] = None, - verilatorConfigFileOut: File = new File("conf.vlt") -) { - val builder = OParser.builder[CliOptions] - val parser = { - import builder._ - OParser.sequence( - programName("flow"), - help("help"), - opt[Option[File]]('c', "config") - .action((x, c) => c.copy(configFile = x)) - .text("JSON Configuration file for generation"), - opt[Option[File]]("args-file") - .action((x, c) => c.copy(argsFile = x)) - .text("Passing file content as args when emit"), - opt[File]('o', "target-dir") - .action((x, c) => c.copy(targetDir = x)) - .text("Output files relative to this path"), - opt[File]("out-verilator-conf") - .action((x, c) => c.copy(verilatorConfigFileOut = x)) - .text("Options needed when simulating with verilator") - ) - } - - def parse(args: Array[String]): CliOptions = { - OParser.runParser(parser, args, CliOptions()) match { - case (result, effects) => - OParser.runEffects( - effects, - new DefaultOEffectSetup { - // ignore terminate - override def terminate(exitState: Either[String, Unit]): Unit = () - } - ) - - result match { - case Some(cliOptions: CliOptions) => { return cliOptions } - case _ => { - throw new IllegalArgumentException("Wrong command line argument") - } - } - } - } -} diff --git a/npc/core/src/main/scala/top/Config.scala b/npc/core/src/main/scala/top/Config.scala deleted file mode 100644 index 4c21a25..0000000 --- a/npc/core/src/main/scala/top/Config.scala +++ /dev/null @@ -1,23 +0,0 @@ -package flow - -import io.circe.generic.JsonCodec - -// Which group of signals to trace -@JsonCodec case class TraceConfig( - enable: Boolean = false, - registers: Array[Int] = Array(), - mem: Array[(Int, Int)] = Array() -) - -@JsonCodec case class Config( - // Whether to enable Difftest - enableDifftest: Boolean = true, - traceConfig: TraceConfig = TraceConfig() -) - -import chisel3._ -case class Params( - XLEN: Width, - arch: String, - csrAddrWidth: Width = 12.W -) diff --git a/npc/core/src/main/scala/top/FlowMain.scala b/npc/core/src/main/scala/top/FlowMain.scala deleted file mode 100644 index 01b1972..0000000 --- a/npc/core/src/main/scala/top/FlowMain.scala +++ /dev/null @@ -1,466 +0,0 @@ -package flow - -import scala.reflect.runtime.universe._ -import chisel3._ -import chisel3.util.experimental.decode.{decoder, TruthTable} -import chisel3.util._ -import chisel3.experimental.Trace._ -import shapeless.{HNil, ::} -import shapeless.HList -import shapeless.ops.coproduct.Prepend -import chisel3.util.{BinaryMemoryFile, HexMemoryFile} - -import chisel3.experimental.Trace -import scala.collection.IndexedSeqView -import shapeless.Poly1 -import flow.components.RamControlInterface -import flow.components.RV32Inst -import flow.components.RV32InstSubfields._ - -import flow.components.{RegControl, PcControlInterface, ALUControlInterface} -class Control(width: Int) extends RawModule { - // Helpers - class WrapList[T](vl: T) { type Type = T; val v = vl } - object wrap extends Poly1 { - implicit def default[A] = at[A](Right(_).withLeft[Int]) - } - def lit(x: Element) = { x.litValue.toInt } - def toBits(t: dst.Type): BitPat = { - val list = t.toList - list - .map(e => - e match { - case Right(x) => BitPat(lit(x).U(x.getWidth.W)) - case Left(x) => BitPat.dontCare(x) - } - ) - .reduceLeft(_ ## _) - } - val r = Right - def l[T <: Any](x: T) = x match { - case x: ChiselEnum => Left(log2Ceil(x.all.length)) - case x: Data => Left(x.getWidth) - case _ => throw new IllegalArgumentException - } - - val inst = IO(Input(UInt(width.W))) - - val reg = IO(Flipped(new RegControl)) - val pc = IO(Flipped(new PcControlInterface)) - val alu = IO(Flipped(new ALUControlInterface)) - val ram = IO(Flipped(new RamControlInterface(32))) - - val dst = new WrapList( - (reg.ctrlBindPorts ++ - pc.ctrlBindPorts ++ - alu.ctrlBindPorts ++ - ram.ctrlBindPorts).map(wrap) - ) - - val dstList = dst.v.toList - val controlWidth = dstList.map(_.toOption.get.getWidth).reduce(_ + _) - val reversePrefixSum = dstList.scanLeft(0)(_ + _.toOption.get.getWidth) - val sliceIndex = reversePrefixSum.map(controlWidth - _) - val slices = sliceIndex.map(_ - 1).zip(sliceIndex.tail) - - import reg.WriteSelect._ - import reg._ - import pc.SrcSelect._ - import pc._ - import alu.OpSelect._ - import alu.SrcASelect._ - import alu.SrcBSelect._ - import pc._ - import RV32Inst._ - // format: off - val ControlMapping: Array[(BitPat, dst.Type)] = Array( - // Regs | writeEnable :: writeSelect :: HNil - // PC | useImmB :: srcSelect :: HNil - // Exe | op :: srcASelect :: srcBSelect :: signExt :: HNil - // Mem | valid :: writeMask :: writeEnable :: HNil - - (lui , ( - r(true.B) :: r(rAluOut) :: - r(false.B) :: r(pStaticNpc):: - r(aOpAdd) :: r(aSrcAZero) :: r(aSrcBImmU) :: r(false.B) :: - r(false.B) :: l(UInt(4.W)):: r(false.B) :: HNil - )), - - (auipc , ( - r(true.B) :: r(rAluOut) :: - r(false.B) :: r(pStaticNpc):: - r(aOpAdd) :: r(aSrcAPc) :: r(aSrcBImmU) :: r(false.B) :: - r(false.B) :: l(UInt(4.W)):: r(false.B) :: HNil - )), - - // ---- Control Transfer Instructions ---- - (jal , ( - r(true.B) :: r(rNpc) :: - r(false.B) :: r(pExeOut) :: - r(aOpAdd) :: r(aSrcAPc) :: r(aSrcBImmJ) :: r(false.B) :: - r(false.B) :: l(UInt(4.W)):: r(false.B) :: HNil - )), - - (jalr , ( - r(true.B) :: r(rNpc) :: - r(false.B) :: r(pExeOut) :: - r(aOpAdd) :: r(aSrcARs1) :: r(aSrcBImmI) :: r(false.B) :: - r(false.B) :: l(UInt(4.W)):: r(false.B) :: HNil - )), - - (beq , ( - r(false.B) :: l(WriteSelect) :: - r(true.B) :: r(pStaticNpc) :: - r(aOpSlt) :: r(aSrcARs1) :: r(aSrcBRs2) :: l(Bool()) :: - r(false.B) :: l(UInt(4.W)):: r(false.B) :: HNil - )), - - (bne , ( - r(false.B) :: l(WriteSelect) :: - r(true.B) :: r(pStaticNpc) :: - r(aOpSlt) :: r(aSrcARs1) :: r(aSrcBRs2) :: l(Bool()) :: - r(false.B) :: l(UInt(4.W)):: r(false.B) :: HNil - )), - - (blt , ( - r(false.B) :: l(WriteSelect) :: - r(true.B) :: r(pStaticNpc) :: - r(aOpSlt) :: r(aSrcARs1) :: r(aSrcBRs2) :: r(true.B) :: - r(false.B) :: l(UInt(4.W)):: r(false.B) :: HNil - )), - - (bge , ( - r(false.B) :: l(WriteSelect) :: - r(true.B) :: r(pStaticNpc) :: - r(aOpSlt) :: r(aSrcARs1) :: r(aSrcBRs2) :: r(true.B) :: - r(false.B) :: l(UInt(4.W)):: r(false.B) :: HNil - )), - - (bltu , ( - r(false.B) :: l(WriteSelect):: - r(true.B) :: r(pStaticNpc) :: - r(aOpSltu) :: r(aSrcARs1) :: r(aSrcBRs2) :: r(false.B) :: - r(false.B) :: l(UInt(4.W)) :: r(false.B) :: HNil - )), - - (bgeu , ( - r(false.B) :: l(WriteSelect):: - r(true.B) :: r(pStaticNpc) :: - r(aOpSltu) :: r(aSrcARs1) :: r(aSrcBRs2) :: r(false.B) :: - r(false.B) :: l(UInt(4.W)) :: r(false.B) :: HNil - )), - - // ---- Memory Access Instructions ---- - - (lb , ( - r(true.B) :: r(rMemOut) :: - r(false.B) :: r(pStaticNpc) :: - r(aOpAdd) :: r(aSrcARs1) :: r(aSrcBImmI) :: l(Bool()) :: - r(true.B) :: r(1.U(4.W)) :: r(false.B) :: HNil - )), - - (lbu , ( - r(true.B) :: r(rMemOut) :: - r(false.B) :: r(pStaticNpc) :: - r(aOpAdd) :: r(aSrcARs1) :: r(aSrcBImmI) :: l(Bool()) :: - r(true.B) :: r(0.U(4.W)) :: r(false.B) :: HNil - )), - - (lh , ( - r(true.B) :: r(rMemOut) :: - r(false.B) :: r(pStaticNpc) :: - r(aOpAdd) :: r(aSrcARs1) :: r(aSrcBImmI) :: l(Bool()) :: - r(true.B) :: r(3.U(4.W)) :: r(false.B) :: HNil - )), - - (lhu , ( - r(true.B) :: r(rMemOut) :: - r(false.B) :: r(pStaticNpc) :: - r(aOpAdd) :: r(aSrcARs1) :: r(aSrcBImmI) :: l(Bool()) :: - r(true.B) :: r(2.U(4.W)) :: r(false.B) :: HNil - )), - - (lw , ( - r(true.B) :: r(rMemOut) :: - r(false.B) :: r(pStaticNpc) :: - r(aOpAdd) :: r(aSrcARs1) :: r(aSrcBImmI) :: l(Bool()) :: - r(true.B) :: r(14.U(4.W)) :: r(false.B) :: HNil - )), - - (sb , ( - r(false.B) :: l(WriteSelect):: - r(false.B) :: r(pStaticNpc) :: - r(aOpAdd) :: r(aSrcARs1) :: r(aSrcBImmS) :: l(Bool()) :: - r(true.B) :: r(1.U(4.W)) :: r(true.B) :: HNil - )), - - (sh , ( - r(false.B) :: l(WriteSelect):: - r(false.B) :: r(pStaticNpc) :: - r(aOpAdd) :: r(aSrcARs1) :: r(aSrcBImmS) :: l(Bool()) :: - r(true.B) :: r(3.U(4.W)) :: r(true.B) :: HNil - )), - - (sw , ( - r(false.B) :: l(WriteSelect):: - r(false.B) :: r(pStaticNpc) :: - r(aOpAdd) :: r(aSrcARs1) :: r(aSrcBImmS) :: l(Bool()) :: - r(true.B) :: r(15.U(4.W)) :: r(true.B) :: HNil - )), - - // ---- Integer Computational Instructions --- - - (addi , ( - r(true.B) :: r(rAluOut) :: - r(false.B) :: r(pStaticNpc) :: - r(aOpAdd) :: r(aSrcARs1) :: r(aSrcBImmI) :: l(Bool()) :: - r(false.B) :: l(UInt(4.W)):: r(false.B) :: HNil - )), - - (slti , ( - r(true.B) :: r(rAluOut) :: - r(false.B) :: r(pStaticNpc) :: - r(aOpSlt) :: r(aSrcARs1) :: r(aSrcBImmI) :: r(true.B) :: - r(false.B) :: l(UInt(4.W)):: r(false.B) :: HNil - )), - - (sltiu , ( - r(true.B) :: r(rAluOut) :: - r(false.B) :: r(pStaticNpc) :: - r(aOpSltu) :: r(aSrcARs1) :: r(aSrcBImmI) :: r(false.B) :: - r(false.B) :: l(UInt(4.W)):: r(false.B) :: HNil - )), - - (xori , ( - r(true.B) :: r(rAluOut) :: - r(false.B) :: r(pStaticNpc) :: - r(aOpXor) :: r(aSrcARs1) :: r(aSrcBImmI) :: l(Bool()) :: - r(false.B) :: l(UInt(4.W)):: r(false.B) :: HNil - )), - - (ori , ( - r(true.B) :: r(rAluOut) :: - r(false.B) :: r(pStaticNpc) :: - r(aOpOr) :: r(aSrcARs1) :: r(aSrcBImmI) :: l(Bool()) :: - r(false.B) :: l(UInt(4.W)):: r(false.B) :: HNil - )), - - (andi , ( - r(true.B) :: r(rAluOut) :: - r(false.B) :: r(pStaticNpc) :: - r(aOpAnd) :: r(aSrcARs1) :: r(aSrcBImmI) :: l(Bool()) :: - r(false.B) :: l(UInt(4.W)):: r(false.B) :: HNil - )), - - (slli , ( - r(true.B) :: r(rAluOut) :: - r(false.B) :: r(pStaticNpc) :: - r(aOpSll) :: r(aSrcARs1) :: r(aSrcBImmI) :: l(Bool()) :: - r(false.B) :: l(UInt(4.W)):: r(false.B) :: HNil - )), - - (srli , ( - r(true.B) :: r(rAluOut) :: - r(false.B) :: r(pStaticNpc) :: - r(aOpSrl) :: r(aSrcARs1) :: r(aSrcBImmI) :: l(Bool()) :: - r(false.B) :: l(UInt(4.W)):: r(false.B) :: HNil - )), - - (srai , ( - r(true.B) :: r(rAluOut) :: - r(false.B) :: r(pStaticNpc) :: - r(aOpSra) :: r(aSrcARs1) :: r(aSrcBImmI) :: l(Bool()) :: - r(false.B) :: l(UInt(4.W)):: r(false.B) :: HNil - )), - - (add , ( - r(true.B) :: r(rAluOut) :: - r(false.B) :: r(pStaticNpc) :: - r(aOpAdd) :: r(aSrcARs1) :: r(aSrcBRs2) :: l(Bool()) :: - r(false.B) :: l(UInt(4.W)):: r(false.B) :: HNil - )), - - (sub , ( - r(true.B) :: r(rAluOut) :: - r(false.B) :: r(pStaticNpc) :: - r(aOpSub) :: r(aSrcARs1) :: r(aSrcBRs2) :: l(Bool()) :: - r(false.B) :: l(UInt(4.W)):: r(false.B) :: HNil - )), - - (sll , ( - r(true.B) :: r(rAluOut) :: - r(false.B) :: r(pStaticNpc) :: - r(aOpSll) :: r(aSrcARs1) :: r(aSrcBRs2) :: l(Bool()) :: - r(false.B) :: l(UInt(4.W)):: r(false.B) :: HNil - )), - - (slt , ( - r(true.B) :: r(rAluOut) :: - r(false.B) :: r(pStaticNpc) :: - r(aOpSlt) :: r(aSrcARs1) :: r(aSrcBRs2) :: r(true.B) :: - r(false.B) :: l(UInt(4.W)):: r(false.B) :: HNil - )), - - (sltu , ( - r(true.B) :: r(rAluOut) :: - r(false.B) :: r(pStaticNpc) :: - r(aOpSltu) :: r(aSrcARs1) :: r(aSrcBRs2) :: r(false.B) :: - r(false.B) :: l(UInt(4.W)):: r(false.B) :: HNil - )), - - (xor , ( - r(true.B) :: r(rAluOut) :: - r(false.B) :: r(pStaticNpc) :: - r(aOpXor) :: r(aSrcARs1) :: r(aSrcBRs2) :: l(Bool()) :: - r(false.B) :: l(UInt(4.W)):: r(false.B) :: HNil - )), - - (srl , ( - r(true.B) :: r(rAluOut) :: - r(false.B) :: r(pStaticNpc) :: - r(aOpSrl) :: r(aSrcARs1) :: r(aSrcBRs2) :: l(Bool()) :: - r(false.B) :: l(UInt(4.W)):: r(false.B) :: HNil - )), - - (sra , ( - r(true.B) :: r(rAluOut) :: - r(false.B) :: r(pStaticNpc) :: - r(aOpSra) :: r(aSrcARs1) :: r(aSrcBRs2) :: l(Bool()) :: - r(false.B) :: l(UInt(4.W)):: r(false.B) :: HNil - )), - - (or , ( - r(true.B) :: r(rAluOut) :: - r(false.B) :: r(pStaticNpc) :: - r(aOpOr) :: r(aSrcARs1) :: r(aSrcBRs2) :: l(Bool()) :: - r(false.B) :: l(UInt(4.W)):: r(false.B) :: HNil - )), - - (and , ( - r(true.B) :: r(rAluOut) :: - r(false.B) :: r(pStaticNpc) :: - r(aOpAnd) :: r(aSrcARs1) :: r(aSrcBRs2) :: l(Bool()) :: - r(false.B) :: l(UInt(4.W)):: r(false.B) :: HNil - )), - ) - // format: on - - val default = BitPat(0.U(controlWidth.W)) - -// println(s"ControlMapping = ${ControlMapping.map(it => (it._1 -> toBits(it._2))).foreach(x => println(x._2))}\n") - val out = decoder( - inst, - TruthTable(ControlMapping.map(it => (it._1 -> toBits(it._2))), default) - ) - val srcList = slices.map(s => out(s._1, s._2)) - - assert(out != default) - println(s"out = $out, default = $default\n") - println(s"dstList = ${dstList}\n") - println(s"srcList = ${srcList}\n") - srcList - .zip(dstList) - .foreach({ case (src, dst) => - dst.toOption.get := src.asTypeOf(dst.toOption.get) - }) -} - -import flow.components.{RegisterFile, ProgramCounter, ALU, RamDpi} -import chisel3.util.experimental.loadMemoryFromFileInline -class Flow extends Module { - def lit(x: Data) = { x.litValue.toInt } - - val dataType = UInt(32.W) - val ram = Module(new RamDpi) - val control = Module(new Control(32)) - val reg = Module(new RegisterFile(dataType, 32, 2)) - val pc = Module(new ProgramCounter(dataType)) - val alu = Module(new ALU(dataType)) - - // TODO: Switch to Decoupled and Arbiter later - ram.io.pc := pc.out - val inst = ram.io.inst - - dontTouch(reg.control.writeEnable) - - import control.pc.SrcSelect._ - - val npc = Wire(dataType) - npc := pc.out + 4.U - pc.in.exeOut := alu.out.result - pc.in.immB := inst.immB - - control.inst := inst - reg.control <> control.reg - // FIXME: Probably optimizable with bulk connection - pc.control <> control.pc - pc.control.useImmB := control.pc.useImmB - alu.control <> control.alu - val branchUseSlt = Wire(Bool()) - val branchInvertResult = Wire(Bool()) - branchUseSlt := inst(14) - branchInvertResult := inst(12) - val _branchResult = Mux(branchUseSlt, alu.out.result(0), alu.out.eq) - val branchResult = Mux(branchInvertResult, !_branchResult, _branchResult) - pc.control.useImmB := control.pc.useImmB && branchResult - // printf(cf"_branchResult = ${_branchResult}, branchResult = ${branchResult}\n") - // printf(cf"pcin.useImmB = ${pc.control.useImmB}, control.out.useImmB = ${control.pc.useImmB} \n") - - import control.reg.WriteSelect._ - reg.in.writeData(lit(rAluOut)) := alu.out.result - val maskedData = ram.io.readData & Cat( - Fill(8, ram.io.writeMask(3)), - Fill(8, ram.io.writeMask(2)), - Fill(8, ram.io.writeMask(1)), - "b11111111".U - ) - - val doSignExt = control.ram.writeMask(0) - val signExt16 = control.ram.writeMask(1) - when(!doSignExt) { - reg.in.writeData(lit(rMemOut)) := maskedData - // printf(cf"!doSignExt\n") - }.elsewhen(signExt16) { - reg.in.writeData(lit(rMemOut)) := Cat( - Fill(16, maskedData(15)), - maskedData(15, 0) - ) - // printf(cf"elsewhen\n") - }.otherwise { - reg.in - .writeData(lit(rMemOut)) := Cat(Fill(24, maskedData(7)), maskedData(7, 0)) - // printf(cf"otherwise\n") - } - // printf(cf"maskedData = ${maskedData}, writeData = ${reg.in.writeData(lit(rMemOut))}\n") - reg.in.writeData(lit(rNpc)) := npc - - reg.in.writeAddr := inst.rd - reg.in.rs(0) := inst.rs1 - reg.in.rs(1) := inst.rs2 - - // TODO: Bulk connection here - ram.io.clock := clock - ram.io.reset := reset - ram.io.writeAddr := alu.out.result - ram.io.writeData := reg.out.src(1) - ram.io.writeMask := control.ram.writeMask - ram.io.writeEnable := control.ram.writeEnable - ram.io.valid := control.ram.valid - ram.io.readAddr := alu.out.result - - import control.alu.SrcASelect._ - import control.alu.SrcBSelect._ - alu.in.a(lit(aSrcARs1)) := reg.out.src(0) - alu.in.a(lit(aSrcAPc)) := pc.out - alu.in.a(lit(aSrcAZero)) := 0.U - - alu.in.b(lit(aSrcBRs2)) := reg.out.src(1) - // alu.in.b(lit(aSrcBImmI)) := inst(31, 20).pad(aSrcBImmI.getWidth) - alu.in.b(lit(aSrcBImmI)) := inst.immI - alu.in.b(lit(aSrcBImmJ)) := inst.immJ - alu.in.b(lit(aSrcBImmS)) := inst.immS - alu.in.b(lit(aSrcBImmU)) := inst.immU - - Trace.traceName(pc.out) - dontTouch(control.out) -} diff --git a/npc/core/src/main/scala/top/Main.scala b/npc/core/src/main/scala/top/Main.scala deleted file mode 100644 index ba4ce99..0000000 --- a/npc/core/src/main/scala/top/Main.scala +++ /dev/null @@ -1,83 +0,0 @@ -package flow - -import flow._ - -import chisel3._ -import chisel3.experimental.Trace._ -import chisel3.stage.{ChiselGeneratorAnnotation, DesignAnnotation} -import chisel3.util.experimental.InlineInstance -import circt.stage.ChiselStage -import firrtl.AnnotationSeq -import firrtl.annotations.TargetToken.{Instance, OfModule, Ref} -import java.io.PrintWriter -import scala.io.Source -import java.io.File - -// TODO: Generate verilator config file - -object VerilogMain extends App { - val opt = CliOptions().parse(args) - val topName = "Flow" - - val config: Config = opt.configFile match { - case Some(f) => { - val source = Source.fromFile(f) - val jsonString = source.mkString - source.close() - io.circe.parser.decode[Config](jsonString) match { - case Right(x) => x - case Left(e) => throw e - } - } - case None => Config(traceConfig = TraceConfig(enable = true)) - } - - val annos = (new ChiselStage).execute( - Array( - "--target-dir", - opt.targetDir.toString, - "--target", - "systemverilog", - "--split-verilog", - "--full-stacktrace" - ), - Seq( - ) ++ (if (config.traceConfig.enable) - Seq(ChiselGeneratorAnnotation(() => new Flow)) - else Seq()) - ) - - if (config.traceConfig.enable) { - val dut = annos - .collectFirst { case DesignAnnotation(dut) => dut } - .get - .asInstanceOf[Flow] - - val verilatorConfigSeq = finalTargetMap(annos).values.flatten - .map(ct => - s"""public_flat_rd -module "${ct.tokens.collectFirst { - case OfModule(m) => m - }.get}" -var "${ct.tokens.collectFirst { case Ref(r) => r }.get}"""" - ) - finalTargetMap(annos).values.flatten - .foreach(ct => - println(s"""TOP.${ct.circuit}.${ct.path - .map { case (Instance(i), _) => i } - .mkString(".")}.${ct.tokens.collectFirst { case Ref(r) => - r - }.get}""") - ) - - val verilatorConfigWriter = new PrintWriter( - new File(opt.targetDir, opt.verilatorConfigFileOut.toString()) - ) - verilatorConfigWriter.write("`verilator_config\n") - try { - for (ct <- verilatorConfigSeq) { - verilatorConfigWriter.println(ct) - } - } finally { - verilatorConfigWriter.close() - } - } -} diff --git a/npc/core/src/main/scala/utils/DPI.scala b/npc/core/src/main/scala/utils/DPI.scala deleted file mode 100644 index 1a31361..0000000 --- a/npc/core/src/main/scala/utils/DPI.scala +++ /dev/null @@ -1,11 +0,0 @@ -package flow.utils - -import chisel3._ -import chisel3.util.HasBlackBoxResource - -// class DiffTester extends BlackBox with HasBlackBoxResource { -// val io = IO(new Bundle { -// val regs = -// }) -// addResource("difftest.v"); -// } diff --git a/npc/core/src/main/scala/utils/SegControllerGenerator.scala b/npc/core/src/main/scala/utils/SegControllerGenerator.scala deleted file mode 100644 index fdfcbc8..0000000 --- a/npc/core/src/main/scala/utils/SegControllerGenerator.scala +++ /dev/null @@ -1,40 +0,0 @@ -package npc.util - -import chisel3._ -import chisel3.util._ -import chisel3.util.log2Ceil - -class SegControllerGenerator[T <: Data](seg_count: Int, t: T) extends Module { - val io = IO(new Bundle { - val in_segs = Input(Vec(seg_count / ((t.getWidth + 3) / 4), t)) - val segs = Output(Vec(seg_count, UInt(8.W))) - }) - val digit_to_seg = ((0 until 16) - .map(_.U)) - .zip( - Seq( - "b00000011".U, - "b10011111".U, - "b00100101".U, - "b00001101".U, - "b10011001".U, - "b01001001".U, - "b01000001".U, - "b00011111".U, - "b00000001".U, - "b00001001".U, - "b00010001".U, - "b11000001".U, - "b01100011".U, - "b10000101".U, - "b01100001".U, - "b01110001".U - ) - ) - val vec = io.in_segs.asTypeOf(Vec(seg_count, UInt(4.W))) - - val segs = VecInit(Seq.fill(seg_count)(0.U(8.W))) - segs := vec.map(MuxLookup(_, 0xff.U)(digit_to_seg)) - - io.segs := segs -} diff --git a/npc/core/src/test/scala/CSR.scala b/npc/core/src/test/scala/CSR.scala deleted file mode 100644 index 35d41e3..0000000 --- a/npc/core/src/test/scala/CSR.scala +++ /dev/null @@ -1,59 +0,0 @@ -package flow.tests - -import chisel3._ -import chiseltest._ -import org.scalatest.freespec.AnyFreeSpec -import chiseltest.simulator.WriteVcdAnnotation - -import flow.components.CSRCore -import flow.tests.defaultParams - -class CSRSpec extends AnyFreeSpec with ChiselScalatestTester { - implicit val p: flow.Params = defaultParams() - "should compile" in { - test(new CSRCore) { c => - c.clock.step(1) - } - } - "Write" - { - "delayed" in { - test(new CSRCore) { c => - val tv = BigInt("deadbeef", 16) - c.in.csrAddr.poke(c.nameToAddr("mstatus")) - c.in.writeData.poke(tv) - c.control.writeEnable.poke(c.control.csrWrite.csrWriteEnabled) - c.clock.step(1) - - c.control.readEnable.poke(c.control.csrRead.csrReadEnabled) - c.out.readData.expect(0) - c.out.readValid.expect(1) - - c.clock.step(1) - c.out.readValid.expect(1) - c.out.readData.expect(tv) - } - } - } - - "Read" - { - "controlled by readEnable" in { - test(new CSRCore) { c => - val tv = BigInt("deadbeef", 16) - c.in.csrAddr.poke(c.nameToAddr("mstatus")) - c.in.writeData.poke(tv) - c.control.readEnable.poke(c.control.csrRead.csrReadEnabled) - c.control.writeEnable.poke(c.control.csrWrite.csrWriteEnabled) - c.clock.step(1) - - c.control.readEnable.poke(c.control.csrRead.csrReadDisabled) - c.out.readData.expect(0) - c.out.readValid.expect(0) - - c.clock.step(1) - c.out.readData.expect(0) - c.out.readValid.expect(0) - } - } - } - -} diff --git a/npc/core/src/test/scala/Main.scala b/npc/core/src/test/scala/Main.scala index cbca1f4..0cab4ef 100644 --- a/npc/core/src/test/scala/Main.scala +++ b/npc/core/src/test/scala/Main.scala @@ -13,7 +13,7 @@ class RV32CPUSpec extends AnyFreeSpec with ChiselScalatestTester { import chisel3.util.{SRAM, SRAMInterface, HexMemoryFile} class UserMem extends Module { val io = IO(new SRAMInterface(1024, UInt(32.W), 1, 1, 0)) - val memoryFile = HexMemoryFile("../resource/addi.txt") + val memoryFile = HexMemoryFile("../resource/addi.txt") io :<>= SRAM( size = 1024, tpe = UInt(32.W), @@ -22,7 +22,7 @@ class RV32CPUSpec extends AnyFreeSpec with ChiselScalatestTester { numReadwritePorts = 0, memoryFile = memoryFile ) - + val read = io.readPorts(0).data printf(cf"memoryFile=$memoryFile, readPort=$read%x\n") } diff --git a/npc/core/src/test/scala/params.scala b/npc/core/src/test/scala/params.scala deleted file mode 100644 index 2bb752d..0000000 --- a/npc/core/src/test/scala/params.scala +++ /dev/null @@ -1,8 +0,0 @@ -package flow.tests - -import chisel3._ -import flow.Params - -object defaultParams { - def apply(): Params = new Params(XLEN = 32.W) -} diff --git a/npc/csrc/CMakeLists.txt b/npc/csrc/CMakeLists.txt deleted file mode 100644 index 4adbc86..0000000 --- a/npc/csrc/CMakeLists.txt +++ /dev/null @@ -1,2 +0,0 @@ -add_subdirectory(devices) -add_subdirectory(${TOPMODULE}) diff --git a/npc/csrc/Flow/CMakeLists.txt b/npc/csrc/Flow/CMakeLists.txt deleted file mode 100644 index 4ee7fe9..0000000 --- a/npc/csrc/Flow/CMakeLists.txt +++ /dev/null @@ -1,42 +0,0 @@ -if(BUILD_CHISEL_EMIT_TARGET) - include(ChiselBuild) -endif() -add_executable(V${TOPMODULE} config.cpp gdbstub_wrapper.cpp main.cpp) -target_link_libraries(V${TOPMODULE} PRIVATE devices gdbstub spdlog::spdlog) -target_include_directories(V${TOPMODULE} PRIVATE ${CMAKE_SOURCE_DIR}/include) - -verilate( - V${TOPMODULE} - TRACE THREADS - TOP_MODULE ${TOPMODULE} - PREFIX V${TOPMODULE} - SOURCES ${CHISEL_OUTPUT_TOPMODULE} ${CHISEL_OUTPUT_VERILATOR_CONF} - INCLUDE_DIRS ${CHISEL_OUTPUT_DIR} - VERILATOR_ARGS "--vpi" "-Wno-UNOPTFLAT") - -install(TARGETS V${TOPMODULE}) - -foreach(DIFFTEST_BINARY_FILE IN LISTS DIFFTEST_BINARY_FILES) - get_filename_component(FILENAME ${DIFFTEST_BINARY_FILE} NAME_WE) - add_test(NAME V${TOPMODULE}.${FILENAME} - COMMAND V${TOPMODULE} -m ${DIFFTEST_BINARY_FILE} --diff-lib - ${DIFFTEST_LIB}) - unset(FILENAME) -endforeach() - -add_library(${TOPMODULE} SHARED config.cpp gdbstub_wrapper.cpp) -target_link_libraries(${TOPMODULE} PRIVATE devices gdbstub spdlog::spdlog) -target_include_directories(${TOPMODULE} PRIVATE ${CMAKE_SOURCE_DIR}/include) -set_property(TARGET PROPERTY POSITION_INDEPENDENT_CODE ON) -target_link_options(${TOPMODULE} PRIVATE -Wl,-E) - -verilate( - ${TOPMODULE} - TRACE THREADS - TOP_MODULE ${TOPMODULE} - PREFIX V${TOPMODULE} - SOURCES ${CHISEL_OUTPUT_TOPMODULE} ${CHISEL_OUTPUT_VERILATOR_CONF} - INCLUDE_DIRS ${CHISEL_OUTPUT_DIR} - VERILATOR_ARGS "--vpi" "-Wno-UNOPTFLAT") - -install(TARGETS ${TOPMODULE}) diff --git a/npc/csrc/Flow/config.cpp b/npc/csrc/Flow/config.cpp deleted file mode 100644 index e8e224b..0000000 --- a/npc/csrc/Flow/config.cpp +++ /dev/null @@ -1,22 +0,0 @@ -#include "config.hpp" - -void Config::cli_parse(int argc, char **argv) { - CLI::App app; - app.add_option("-l,--listen", gdbsocket, - "Listen to debugger at this address"); - app.add_flag("-g", do_debug, "Listen for gdb"); - app.add_option("-m,--memory", memory_file, "Content of memory") - ->check(CLI::ExistingFile); - app.add_flag("!--no-bin", memory_file_binary, - "Memory file is in text format"); - app.add_option("--wav", wavefile, "output .vcd file path"); - app.add_flag("-i", interactive, "Launch sdb for interactive session"); - - try { - app.parse(argc, argv); - } catch (const CLI::ParseError &e) { - exit((app).exit(e)); - } -} - -Config config; diff --git a/npc/csrc/Flow/gdbstub_wrapper.cpp b/npc/csrc/Flow/gdbstub_wrapper.cpp deleted file mode 100644 index 970ce55..0000000 --- a/npc/csrc/Flow/gdbstub_wrapper.cpp +++ /dev/null @@ -1,196 +0,0 @@ -extern "C" { -#include -} -#include "components.hpp" -#include -#include -#include -#include -#include -#include -#include -#include -#include - -using Registers = _RegistersVPI; -using VlModule = VlModuleInterfaceCommon; - -// SDB::SDB sdb_dut; -bool g_skip_memcheck = false; -VlModule *top; -Registers *regs; -vpiHandle pc = nullptr; - -const size_t PMEM_START = 0x80000000; -const size_t PMEM_END = 0x87ffffff; - -extern "C" { -/* === Memory Access === */ -using MMap = MemoryMap, Devices::DeviceMap>; -void *pmem_get() { - static Devices::DeviceMap devices{ - new Devices::Serial(0x10000000, 0x1000), - new Devices::RTC(0x10001000, 0x1000), - }; - static auto pmem = new MemoryMap, Devices::DeviceMap>( - std::make_unique>(config.memory_file, true, PMEM_START, - PMEM_END), - std::make_unique(devices)); - return pmem; -} - -int pmem_read(int raddr) { - void *pmem = pmem_get(); - auto mem = static_cast(pmem); - // TODO: Do memory difftest at memory read and write to diagnose at a finer - // granularity - mem->trace(raddr, true, regs->get_pc()); - if (g_skip_memcheck) - return mem->read(PMEM_START); - return mem->read(raddr); -} - -void pmem_write(int waddr, int wdata, char wmask) { - void *pmem = pmem_get(); - auto mem = static_cast(pmem); - mem->trace((std::size_t)waddr, false, regs->get_pc(), wdata); - return mem->write((std::size_t)waddr, wdata, wmask); -} - -/* === For gdbstub === */ - -int npc_read_mem(void *args, size_t addr, size_t len, void *val) { - void *pmem = pmem_get(); - auto mmap = static_cast(pmem); - return mmap->copy_to(addr, (uint8_t *)val, len); -} - -int npc_write_mem(void *args, size_t addr, size_t len, void *val) { - void *pmem = pmem_get(); - auto mmap = static_cast(pmem); - return mmap->copy_from(addr, (uint8_t *)val, len); -} - -int npc_read_reg(void *args, int regno, size_t *value) { - if (regno == 32) - *value = regs->get_pc(); - else - *value = (*regs)[regno]; - return 0; -} - -int npc_write_reg(void *args, int regno, size_t value) { return 1; } - -inline void breakpoint_to_action(const Breakpoint *bp, gdb_action_t *res) { - if (bp == nullptr) { - res->reason = gdb_action_t::ACT_NONE; - return; - } - switch (bp->type) { - case BP_SOFTWARE: - res->reason = gdb_action_t::ACT_BREAKPOINT; - break; - case BP_ACCESS: - res->reason = gdb_action_t::ACT_WATCH; - break; - case BP_WRITE: - res->reason = gdb_action_t::ACT_WWATCH; - break; - case BP_READ: - res->reason = gdb_action_t::ACT_RWATCH; - break; - } - res->data = bp->addr; -} - -void npc_cont(void *args, gdb_action_t *res) { - DbgState *dbg = (DbgState *)args; - const Breakpoint *stopped_at = nullptr; - stopped_at = top->cont(*dbg->bp); - breakpoint_to_action(stopped_at, res); -} - -void npc_stepi(void *args, gdb_action_t *res) { - DbgState *dbg = (DbgState *)args; - const Breakpoint *stopped_at = nullptr; - stopped_at = top->stepi(*dbg->bp); - breakpoint_to_action(stopped_at, res); -} - -bool npc_set_bp(void *args, size_t addr, bp_type_t type) { - DbgState *dbg = (DbgState *)args; - for (const auto &bp : *dbg->bp) { - if (bp.addr == addr && bp.type == type) { - return true; - } - } - dbg->bp->push_back({.addr = addr, .type = type}); - return true; -} - -bool npc_del_bp(void *args, size_t addr, bp_type_t type) { - DbgState *dbg = (DbgState *)args; - for (auto it = dbg->bp->begin(); it != dbg->bp->end(); it++) { - if (it->addr == addr && it->type == type) { - std::swap(*it, *dbg->bp->rbegin()); - dbg->bp->pop_back(); - return true; - } - } - return false; -} - -void npc_on_interrupt(void *args) { ; } - -void npc_init(void *args) { - DbgState *dbg = (DbgState *)args; - void *mem = pmem_get(); - dbg->bp = new std::vector; - - top = new VlModule; - regs = new Registers("TOP.Flow.reg_0.regFile_", "TOP.Flow.pc.out"); - top->setup(config.wavefile, regs); - top->reset_eval(10); -} - -bool npc_do_difftest = true; - -static gdbstub_t gdbstub_priv; -arch_info_t npc_isa_arch_info{ - .target_desc = strdup(TARGET_RV32), .reg_num = 32, .reg_byte = 4}; - -size_t npc_dbg_state_size = sizeof(DbgState); - -} // extern "C" - -int gdbstub_loop() { - DbgState dbg; - - target_ops npc_gdbstub_ops = {.cont = npc_cont, - .stepi = npc_stepi, - .read_reg = npc_read_reg, - .write_reg = npc_write_reg, - .read_mem = npc_read_mem, - .write_mem = npc_write_mem, - .set_bp = npc_set_bp, - .del_bp = npc_del_bp, - .on_interrupt = NULL}; - - if (!config.do_debug) { - gdb_action_t res; - npc_init(&dbg); - npc_cont(&dbg, &res); - return !(res.reason == gdb_action_t::ACT_SHUTDOWN); - } - - if (!gdbstub_init(&gdbstub_priv, &npc_gdbstub_ops, - (arch_info_t)npc_isa_arch_info, NULL, - config.gdbsocket.c_str())) { - return EINVAL; - } - npc_init(&dbg); - - bool success = gdbstub_run(&gdbstub_priv, &dbg); - // gdbstub_close(&gdbstub_priv); - return !success; -} diff --git a/npc/csrc/Flow/main.cpp b/npc/csrc/Flow/main.cpp index ff35334..c708610 100644 --- a/npc/csrc/Flow/main.cpp +++ b/npc/csrc/Flow/main.cpp @@ -1,13 +1,43 @@ -#include -#include -#include -#include - -int gdbstub_loop(); +#include +#include +#include +#include +#include +#include +#define MAX_SIM_TIME 100 +#define VERILATOR_TRACE int main(int argc, char **argv, char **env) { - spdlog::cfg::load_env_levels(); - config.cli_parse(argc, argv); - spdlog::debug("Configuration parsed"); - return gdbstub_loop(); + int sim_time = 0; + Verilated::commandArgs(argc, argv); + + VFlow *top = new VFlow; + + Verilated::traceEverOn(true); + VerilatedVcdC *m_trace = new VerilatedVcdC; +#ifdef VERILATOR_TRACE + top->trace(m_trace, 5); + m_trace->open("waveform.vcd"); +#endif + for (sim_time = 0; sim_time < 10; sim_time++) { + top->eval(); + top->clock = !top->clock; + top->reset = 1; +#ifdef VERILATOR_TRACE + m_trace->dump(sim_time); +#endif + } + top->reset = 0; + for (sim_time = 10; sim_time < MAX_SIM_TIME; sim_time++) { + top->eval(); + top->clock = !top->clock; +#ifdef VERILATOR_TRACE + m_trace->dump(sim_time); +#endif + } +#ifdef VERILATOR_TRACE + m_trace->close(); +#endif + delete top; + exit(EXIT_SUCCESS); } diff --git a/npc/csrc/Switch/main.cpp b/npc/csrc/Switch/main.cpp index 0a5467c..9a3f262 100644 --- a/npc/csrc/Switch/main.cpp +++ b/npc/csrc/Switch/main.cpp @@ -1,36 +1,36 @@ -#include +#include #include #include #include #include +#include -const int MAX_SIM_TIME = 100; +const int MAX_SIM_TIME=100; int main(int argc, char **argv, char **env) { - int sim_time = 0; - Verilated::commandArgs(argc, argv); - VSwitch *top = new VSwitch; + int sim_time = 0; + Verilated::commandArgs(argc, argv); + VSwitch *top = new VSwitch; - Verilated::traceEverOn(true); - VerilatedVcdC *m_trace = new VerilatedVcdC; + Verilated::traceEverOn(true); + VerilatedVcdC *m_trace = new VerilatedVcdC; #ifdef VERILATOR_TRACE - top->trace(m_trace, 5); - m_trace->open("waveform.vcd"); + top->trace(m_trace, 5); + m_trace->open("waveform.vcd"); #endif - for (sim_time = 0; sim_time < MAX_SIM_TIME; sim_time++) { - top->io_sw_0 = rand() % 2; - top->io_sw_1 = rand() % 2; - top->eval(); - printf("sw0 = %d, sw1 = %d, ledr = %d\n", top->io_sw_0, top->io_sw_1, - top->io_out); - assert(top->io_out == (top->io_sw_0 ^ top->io_sw_1)); + for (sim_time = 0; sim_time < MAX_SIM_TIME; sim_time++) { + top->io_sw_0 = rand() % 2; + top->io_sw_1 = rand() % 2; + top->eval(); + printf("sw0 = %d, sw1 = %d, ledr = %d\n", top->io_sw_0, top->io_sw_1, top->io_out); + assert(top->io_out == (top->io_sw_0 ^ top->io_sw_1)); #ifdef VERILATOR_TRACE - m_trace->dump(sim_time); + m_trace->dump(sim_time); #endif - } + } #ifdef VERILATOR_TRACE - m_trace->close(); + m_trace->close(); #endif - delete top; - exit(EXIT_SUCCESS); + delete top; + exit(EXIT_SUCCESS); } diff --git a/npc/csrc/devices/CMakeLists.txt b/npc/csrc/devices/CMakeLists.txt deleted file mode 100644 index 3480105..0000000 --- a/npc/csrc/devices/CMakeLists.txt +++ /dev/null @@ -1,4 +0,0 @@ -add_library(devices serial.cpp rtc.cpp) - -target_include_directories(devices PUBLIC include) -target_link_libraries(devices PRIVATE spdlog::spdlog) diff --git a/npc/csrc/devices/include/devices.hpp b/npc/csrc/devices/include/devices.hpp deleted file mode 100644 index 0470a44..0000000 --- a/npc/csrc/devices/include/devices.hpp +++ /dev/null @@ -1,84 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -namespace Devices { -class Device { -public: - uint8_t *p_buf; - uint64_t addr; - size_t len; - Device(uint64_t addr, size_t len, uint8_t buf[]) - : addr(addr), len(len), p_buf(buf) {} - virtual ~Device(){}; - virtual void io_handler(uint32_t offset, size_t len, bool is_write) = 0; - void transfer(uint8_t *src, size_t len, bool is_write) { - if (is_write) { - memmove(p_buf, src, len); - } else { - memmove(src, p_buf, len); - } - }; -}; - -class Serial : public Device { - uint8_t buf[1]; - -public: - Serial(uint64_t addr, size_t len); - ~Serial() override{}; - void io_handler(uint32_t offset, size_t len, bool is_write) override; - // void transfer(uint8_t *src, size_t len, bool is_write) override; -}; - -class RTC : public Device { - uint8_t buf[8]; - uint64_t boot_time; - uint64_t get_time_internal(); - uint64_t get_time(); - -public: - RTC(uint64_t addr, size_t len); - ~RTC() override{}; - void io_handler(uint32_t offset, size_t len, bool is_write) override; - // void transfer(uint8_t *src, size_t len, bool is_write) override; -}; - -class DeviceMap { - std::map addr_to_device; - std::shared_ptr logger = spdlog::stdout_color_mt("devicemap"); - -public: - DeviceMap(std::initializer_list devices) { - for (auto device : devices) { - addr_to_device.insert(std::make_pair(device->addr, device)); - } - } - bool handle(uint64_t addr, uint8_t *data, size_t len, bool is_write) { - auto it = addr_to_device.upper_bound(addr); - if (it == addr_to_device.begin() || - (--it)->second->addr + it->second->len <= addr) { - logger->error("Accessed an unintialized device at memory addr: 0x{:x}", - addr); - return false; - } - auto &device = it->second; - uint32_t offset = addr - device->addr; - if (is_write) { - device->transfer(data, len, is_write); - device->io_handler(offset, len, is_write); - } else { - device->io_handler(offset, len, is_write); - device->transfer(data, len, is_write); - } - return true; - } -}; -} // namespace Devices diff --git a/npc/csrc/devices/rtc.cpp b/npc/csrc/devices/rtc.cpp deleted file mode 100644 index 1a26ab1..0000000 --- a/npc/csrc/devices/rtc.cpp +++ /dev/null @@ -1,49 +0,0 @@ -#include -#include - -namespace Devices { -uint64_t RTC::get_time_internal() { -#if defined(CONFIG_TARGET_AM) - uint64_t us = io_read(AM_TIMER_UPTIME).us; -#elif defined(CONFIG_TIMER_GETTIMEOFDAY) - struct timeval now; - gettimeofday(&now, NULL); - uint64_t us = now.tv_sec * 1000000 + now.tv_usec; -#else - struct timespec now; - clock_gettime(CLOCK_MONOTONIC_COARSE, &now); - uint64_t us = now.tv_sec * 1000000 + now.tv_nsec / 1000; -#endif - return us; -} - -uint64_t RTC::get_time() { - if (boot_time == 0) - boot_time = get_time_internal(); - uint64_t now = get_time_internal(); - return now - boot_time; -} - -RTC::RTC(uint64_t addr, size_t len) : Device(addr, len, buf) { - *(uint64_t *)buf = 0; -}; - -void RTC::io_handler(uint32_t offset, size_t len, bool is_write) { - assert(offset == 0 || offset == 4); - if (!is_write && offset == 4) { - uint64_t us = get_time(); - buf[0] = (uint32_t)us; - buf[1] = us >> 32; - } -} - -// void RTC::transfer(uint8_t *src, size_t len, bool is_write) { -// if (is_write) { -// for (size_t i = 0; i < len; i++) -// buf[i] = src[i]; -// } else { -// for (size_t i = 0; i < len; i++) -// src[i] = buf[i]; -// } -// } -} // namespace Devices diff --git a/npc/csrc/devices/serial.cpp b/npc/csrc/devices/serial.cpp deleted file mode 100644 index 8a09551..0000000 --- a/npc/csrc/devices/serial.cpp +++ /dev/null @@ -1,22 +0,0 @@ -#include -#include - -namespace Devices { -Serial::Serial(uint64_t addr, size_t len) : Device(addr, len, buf) { - buf[0] = 0; -}; -void Serial::io_handler(uint32_t offset, size_t len, bool is_write) { - if (is_write) { - std::cout << (char)buf[0]; - } -} -// void Serial::transfer(uint8_t *src, size_t len, bool is_write) { -// if (is_write) { -// for (size_t i = 0; i < len; i++) -// buf[i] = src[i]; -// } else { -// for (size_t i = 0; i < len; i++) -// src[i] = buf[i]; -// } -// } -} // namespace Devices diff --git a/npc/csrc_nvboard/Flow/CMakeLists.txt b/npc/csrc_nvboard/Flow/CMakeLists.txt deleted file mode 100644 index 90e8add..0000000 --- a/npc/csrc_nvboard/Flow/CMakeLists.txt +++ /dev/null @@ -1,26 +0,0 @@ -include(ChiselBuild) - -add_custom_command( - OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${TOPMODULE}/auto_bind.cpp - COMMAND auto_pin_bind ${CMAKE_SOURCE_DIR}/constr/${TOPMODULE}.nxdc - ${CMAKE_CURRENT_BINARY_DIR}/${TOPMODULE}/auto_bind.cpp - DEPENDS ${CMAKE_SOURCE_DIR}/constr/${TOPMODULE}.nxdc) - -add_executable(V${TOPMODULE}_nvboard - ${CMAKE_CURRENT_BINARY_DIR}/${TOPMODULE}/auto_bind.cpp main.cpp) - -verilate( - V${TOPMODULE}_nvboard - TRACE THREADS - TOP_MODULE ${TOPMODULE} - PREFIX V${TOPMODULE} - SOURCES ${CHISEL_OUTPUT_TOPMODULE} - INCLUDE_DIRS ${CHISEL_OUTPUT_DIR}) - -target_include_directories(V${TOPMODULE}_nvboard PRIVATE ${NVBOARD_INCLUDE_DIR} - ${SDL2_INCLUDE_DIRS}) -target_link_libraries( - V${TOPMODULE}_nvboard PRIVATE ${NVBOARD_LIBRARY} SDL2::SDL2 - SDL2_image::SDL2_image) - -install(TARGETS V${TOPMODULE}_nvboard) diff --git a/npc/csrc_nvboard/Keyboard/main.cpp b/npc/csrc_nvboard/Keyboard/main.cpp index 372bbaa..8f5ea74 100644 --- a/npc/csrc_nvboard/Keyboard/main.cpp +++ b/npc/csrc_nvboard/Keyboard/main.cpp @@ -49,10 +49,11 @@ int main(int argc, char **argv, char **env) { while (true) { nvboard_update(); cycle(top, [&] { - if (keycode != top->io_ps2_data) { + if (keycode != top->io_ps2_data){ keycode = top->io_ps2_data; printf("%d\n", keycode); - }); + } + }); } delete top; - } +} \ No newline at end of file diff --git a/npc/flake.lock b/npc/flake.lock index b473f33..76de6c7 100644 --- a/npc/flake.lock +++ b/npc/flake.lock @@ -18,28 +18,13 @@ "type": "github" } }, - "flake-utils_2": { - "locked": { - "lastModified": 1667395993, - "narHash": "sha256-nuEHfE/LcWyuSWnS8t12N1wc105Qtau+/OdUAjtQ0rA=", - "owner": "numtide", - "repo": "flake-utils", - "rev": "5aed5285a952e0b949eb3ba02c12fa4fcfef535f", - "type": "github" - }, - "original": { - "owner": "numtide", - "repo": "flake-utils", - "type": "github" - } - }, "nixpkgs": { "locked": { - "lastModified": 1723362943, - "narHash": "sha256-dFZRVSgmJkyM0bkPpaYRtG/kRMRTorUIDj8BxoOt1T4=", + "lastModified": 1709961763, + "narHash": "sha256-6H95HGJHhEZtyYA3rIQpvamMKAGoa8Yh2rFV29QnuGw=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "a58bc8ad779655e790115244571758e8de055e3d", + "rev": "3030f185ba6a4bf4f18b87f345f104e6a6961f34", "type": "github" }, "original": { @@ -72,11 +57,11 @@ ] }, "locked": { - "lastModified": 1721891452, - "narHash": "sha256-2c9nDuXXARzoRXE67lte5kKBeFb1XmTNsvdiIbRUEgE=", + "lastModified": 1707020873, + "narHash": "sha256-+dNltc7tjgTIyle/I/5siQ5IvPwu+R5Uf6e24CmjLNk=", "ref": "refs/heads/master", - "rev": "de8ad578fc4fe527772cec23a7f660bde14c8570", - "revCount": 152, + "rev": "8142717e7154dbaadee0679f0224fe75cebb1735", + "revCount": 147, "type": "git", "url": "https://git.xinyang.life/xin/nur.git" }, @@ -90,29 +75,7 @@ "flake-utils": "flake-utils", "nixpkgs": "nixpkgs", "nixpkgs-circt162": "nixpkgs-circt162", - "nur-xin": "nur-xin", - "sbt-derivation": "sbt-derivation" - } - }, - "sbt-derivation": { - "inputs": { - "flake-utils": "flake-utils_2", - "nixpkgs": [ - "nixpkgs" - ] - }, - "locked": { - "lastModified": 1698464090, - "narHash": "sha256-Pnej7WZIPomYWg8f/CZ65sfW85IfIUjYhphMMg7/LT0=", - "owner": "zaninime", - "repo": "sbt-derivation", - "rev": "6762cf2c31de50efd9ff905cbcc87239995a4ef9", - "type": "github" - }, - "original": { - "owner": "zaninime", - "repo": "sbt-derivation", - "type": "github" + "nur-xin": "nur-xin" } }, "systems": { diff --git a/npc/flake.nix b/npc/flake.nix index d725b57..15b910f 100644 --- a/npc/flake.nix +++ b/npc/flake.nix @@ -2,40 +2,115 @@ inputs = { nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable"; nixpkgs-circt162.url = "github:NixOS/nixpkgs/7995cae3ad60e3d6931283d650d7f43d31aaa5c7"; + flake-utils.url = "github:numtide/flake-utils"; nur-xin = { url = "git+https://git.xinyang.life/xin/nur.git"; inputs.nixpkgs.follows = "nixpkgs"; }; - flake-utils.url = "github:numtide/flake-utils"; - sbt-derivation = { - url = "github:zaninime/sbt-derivation"; - inputs.nixpkgs.follows = "nixpkgs"; - }; }; - outputs = { self, nixpkgs, flake-utils, nur-xin, nixpkgs-circt162, sbt-derivation }: + outputs = { self, ... }@inputs: with 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; - }) - ]; - }; + pkgs = import nixpkgs { inherit system; config.allowUnfree = true; }// + { nur.xin = nur-xin.legacyPackages.${system}; }; in { - packages = rec { - flow = pkgs.callPackage ./flow.nix { - inherit (sbt-derivation.lib) mkSbtDerivation; - }; + devShells.default = with pkgs; mkShell { + CHISEL_FIRTOOL_PATH = "${nixpkgs-circt162.legacyPackages.${system}.circt}/bin"; + packages = [ + clang-tools + # rnix-lsp + coursier + espresso - flow-simlib = pkgs.callPackage ./flow-simlib.nix { - inherit flow; - }; + gdb + jre + + gtkwave + ]; + + inputsFrom = [ self.packages.${system}.default ]; }; - }); + packages.default = with pkgs; clangStdenv.mkDerivation { + name = "npc"; + version = "0.0.1"; + src = ./.; + nativeBuildInputs = [ + cmake + sbt + nur.xin.nvboard + nixpkgs-circt162.legacyPackages.${system}.circt + yosys + ]; + buildInputs = [ + verilator + nur.xin.nvboard + ]; + + NEMU_HOME="/home/xin/repo/ysyx-workbench/nemu"; + }; + + # This version (1.43.0) of circt does not exist in nixpkgs + # and Chisel 5.1.0 specifically build against it, so here we are. + # Ref: https://github.com/NixOS/nixpkgs/blob/b6465c8/pkgs/development/compilers/circt/default.nix + packages.circt = + with pkgs; + let + pythonEnv = python3.withPackages (ps: [ ps.psutil ]); + in + stdenv.mkDerivation rec { + pname = "circt"; + version = "1.43.0"; + src = fetchFromGitHub { + owner = "llvm"; + repo = "circt"; + rev = "firtool-${version}"; + sha256 = "sha256-RkjigboswLkLgLkgOGahQLIygCkC3Q9rbVw3LqIzREY="; + fetchSubmodules = true; + }; + + requiredSystemFeatures = [ "big-parallel" ]; + + nativeBuildInputs = [ cmake ninja git pythonEnv ]; + + cmakeDir = "../llvm/llvm"; + cmakeFlags = [ + "-DLLVM_ENABLE_BINDINGS=OFF" + "-DLLVM_ENABLE_OCAMLDOC=OFF" + "-DLLVM_BUILD_EXAMPLES=OFF" + "-DLLVM_OPTIMIZED_TABLEGEN=ON" + "-DLLVM_ENABLE_PROJECTS=mlir" + "-DLLVM_EXTERNAL_PROJECTS=circt" + "-DLLVM_EXTERNAL_CIRCT_SOURCE_DIR=.." + "-DCIRCT_LLHD_SIM_ENABLED=OFF" + ]; + + LIT_FILTER_OUT = if stdenv.cc.isClang then "CIRCT :: Target/ExportSystemC/.*\.mlir" else null; + + preConfigure = '' + find ./test -name '*.mlir' -exec sed -i 's|/usr/bin/env|${coreutils}/bin/env|g' {} \; + ''; + + installPhase = '' + runHook preInstall + mkdir -p $out/bin + mv bin/{{fir,hls}tool,circt-{as,dis,lsp-server,opt,reduce,translate}} $out/bin + runHook postInstall + ''; + + doCheck = true; + checkTarget = "check-circt check-circt-integration"; + + meta = { + description = "Circuit IR compilers and tools"; + homepage = "https://circt.org/"; + license = lib.licenses.asl20; + maintainers = with lib.maintainers; [ sharzy ]; + platforms = lib.platforms.all; + }; + }; + } + ); } + diff --git a/npc/flow-simlib.nix b/npc/flow-simlib.nix deleted file mode 100644 index 5127421..0000000 --- a/npc/flow-simlib.nix +++ /dev/null @@ -1,47 +0,0 @@ -{ flow -, cmake -, ninja -, nvboard -, cli11 -, flex -, bison -, verilator -, spdlog -, mini-gdbstub -, stdenv -, lib -, topmodule ? "Flow" -}: -stdenv.mkDerivation { - pname = "npc-flow-simlib"; - version = "0.0.0"; - - src = ./.; - - nativeBuildInputs = [ - cmake - ninja - flex - bison - nvboard - verilator - flow - ]; - - buildInputs = [ - cli11 - spdlog - mini-gdbstub - ]; - - cmakeFlags = with lib; [ - (cmakeBool "ENABLE_YSYX_GIT_TRACKER" false) - (cmakeBool "BUILD_CHISEL_EMIT_TARGET" false) - (cmakeOptionType "string" "TOPMODULE" "${topmodule}") - (cmakeOptionType "string" "CHISEL_OUTPUT_VERILATOR_CONF" "${flow}/share/conf.vlt") - (cmakeOptionType "string" "CHISEL_OUTPUT_TOPMODULE" "${flow}/share/${topmodule}.sv") - (cmakeOptionType "string" "CHISEL_OUTPUT_DIR" "${flow}/share") - ]; - - enableParallelBuilding = true; -} diff --git a/npc/flow.nix b/npc/flow.nix deleted file mode 100644 index b12b416..0000000 --- a/npc/flow.nix +++ /dev/null @@ -1,35 +0,0 @@ -{ mkSbtDerivation -, pkgs -, circt -}: mkSbtDerivation -{ - pname = "npc-flow"; - version = "0.0.0"; - - inherit pkgs; - - src = ./core; - - nativeBuildInputs = [ - circt - ]; - CHISEL_FIRTOOL_PATH = "${circt}/bin"; - - depsWarmupCommand = '' - CHISEL_FIRTOOL_PATH="${circt}/bin" sbt run - ''; - depsSha256 = "sha256-FsiEEEcv43lAz4RHO1CuCSj8syWdqnl602t7xnlkMrw="; - - buildPhase = - let - emitArgs = "--target-dir build"; - in - '' - sbt "run ${emitArgs}" - ''; - - installPhase = '' - mkdir -p $out/share - cp build/* $out/share - ''; -} diff --git a/npc/include/components.hpp b/npc/include/components.hpp deleted file mode 100644 index 887ded0..0000000 --- a/npc/include/components.hpp +++ /dev/null @@ -1,129 +0,0 @@ - -#ifndef _NPC_COMPONENTS_H_ -#define _NPC_COMPONENTS_H_ -#include "types.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -template class _RegistersBase { - std::shared_ptr logger = spdlog::stdout_color_mt("registers"); - - virtual T fetch_pc() const = 0; - virtual T fetch_reg(std::size_t id) const = 0; - -public: - T operator[](size_t id) const { return fetch_reg(id); } - T get_pc() const { return fetch_pc(); } -}; - -template class Memory { -public: - std::array mem; - - Memory(std::filesystem::path filepath, bool is_binary, paddr_t pmem_start, - paddr_t pmem_end) - : pmem_start(pmem_start), pmem_end(pmem_end) { - read_memory(filepath, is_binary); - } - - const word_t &operator[](std::size_t addr) { return this->read(addr); } - - void transfer(paddr_t addr, uint8_t data[], size_t len, bool is_write) { - if (is_write) { - // memcpy(guest_to_host(addr), data, len); - size_t offset = (addr - pmem_start); - std::copy(data, data + len, &mem[offset]); - } else { - // memcpy(data, guest_to_host(addr), len); - size_t offset = (addr - pmem_start); - std::copy(&mem[offset], &mem[offset + len], data); - } - } - - bool in_pmem(paddr_t addr) const { - return addr >= pmem_start && addr <= pmem_end; - } - -private: - paddr_t pmem_start, pmem_end; - - void read_memory(std::filesystem::path filepath, bool is_binary) { - if (!std::filesystem::exists(filepath)) - throw std::runtime_error("Memory file not found"); - if (is_binary) { - std::ifstream file(filepath, std::ios::binary); - char *pmem = reinterpret_cast(mem.data()); - file.read(pmem, mem.size() * sizeof(mem[0])); - } else { - std::string line; - std::ifstream file(filepath); - int i = 0; - while (std::getline(file, line)) { - mem[i++] = std::stoul(line, 0, 16); - } - } - } -}; - -template class MemoryMap { -public: - MemoryMap(std::unique_ptr &&ram, - std::unique_ptr &&devices) noexcept - : ram(std::move(ram)), devices(std::move(devices)) {} - - void write(paddr_t waddr, word_t wdata, char wmask) { - size_t len = (wmask & 1) + ((wmask & 2) >> 1) + ((wmask & 4) >> 2) + - ((wmask & 8) >> 3); - if (ram->in_pmem(waddr)) { - ram->transfer(waddr, (uint8_t *)&wdata, len, true); - } else if (devices->handle(waddr, (uint8_t *)&wdata, len, true)) { - } - } - - word_t read(paddr_t raddr) const { - word_t res = 0; - if (ram->in_pmem(raddr)) { - ram->transfer(raddr, (uint8_t *)&res, 4, false); - } else if (devices->handle(raddr, (uint8_t *)&res, 4, false)) { - } - return res; - } - - int copy_to(paddr_t addr, uint8_t *buf, size_t len) const { - if (ram->in_pmem(addr)) { - ram->transfer(addr, buf, len, false); - return 0; - } else { - return EINVAL; - } - } - - int copy_from(paddr_t addr, uint8_t *buf, size_t len) { - if (ram->in_pmem(addr)) { - ram->transfer(addr, buf, len, true); - return 0; - } else { - return EINVAL; - } - } - - void *get_pmem() { return ram->mem.data(); } - - void trace(paddr_t addr, bool is_read, word_t pc = 0, word_t value = 0) { - logger->trace("[{}] 0x{:x}", is_read ? 'R' : 'W', this->read(addr)); - } - -private: - std::unique_ptr ram; - std::unique_ptr devices; - std::shared_ptr logger = spdlog::stdout_color_mt("mmap"); -}; -#endif diff --git a/npc/include/config.hpp b/npc/include/config.hpp deleted file mode 100644 index 8d6bf33..0000000 --- a/npc/include/config.hpp +++ /dev/null @@ -1,20 +0,0 @@ -#ifndef _NPC_CONFIG_H_ -#define _NPC_CONFIG_H_ -#include -#include -#include -#include - -struct Config { - std::filesystem::path memory_file; - std::string gdbsocket = "gdbstub-npc.sock"; - bool do_debug{false}; - bool interactive{false}; - bool memory_file_binary = {true}; - std::filesystem::path wavefile; - void cli_parse(int argc, char **argv); -}; - -extern Config config; - -#endif diff --git a/npc/include/types.h b/npc/include/types.h deleted file mode 100644 index f34f168..0000000 --- a/npc/include/types.h +++ /dev/null @@ -1,38 +0,0 @@ -#ifndef _NPC_TYPES_H__ -#define _NPC_TYPES_H__ -#ifdef __cplusplus -extern "C" { -#endif -#include -#include - -typedef uint32_t word_t; -typedef int32_t sword_t; -static const word_t WORD_T_MAX = UINT32_MAX; -static const sword_t SWORD_T_MAX = INT32_MAX; -static const sword_t SWORD_T_MIN = INT32_MIN; -#define WORD_BYTES 4 -#define REG_COUNT 32 - -typedef uint32_t vaddr_t; -typedef uint32_t paddr_t; -typedef uint16_t ioaddr_t; - -struct Breakpoint { - size_t addr; - bp_type_t type; -}; - -#ifdef __cplusplus -} -#endif - -#ifdef __cplusplus -#include - -struct DbgState { - std::vector *bp; -}; -#endif - -#endif diff --git a/npc/include/vl_wrapper.hpp b/npc/include/vl_wrapper.hpp deleted file mode 100644 index aa8e798..0000000 --- a/npc/include/vl_wrapper.hpp +++ /dev/null @@ -1,98 +0,0 @@ -#ifndef _NPC_TRACER_H_ -#define _NPC_TRACER_H_ -#include "components.hpp" -#include "types.h" -#include "verilated.h" -#include -#include -#include -#include - -template class Tracer { - std::shared_ptr top; - std::unique_ptr m_trace; - uint64_t cycle = 0; - -public: - Tracer(T *top, std::filesystem::path wavefile) { - top = top; - Verilated::traceEverOn(true); - m_trace = std::make_unique(); - top->trace(m_trace.get(), 5); - m_trace->open(wavefile.c_str()); - } - ~Tracer() { m_trace->close(); } - - /** - * Dump signals to waveform file. Must be called once after every top->eval() - * call. - */ - void update() { m_trace->dump(cycle++); } -}; - -template class VlModuleInterfaceCommon : public T { - uint64_t sim_time = 0; - uint64_t posedge_cnt = 0; - std::unique_ptr> tracer; - -public: - const R *registers; - VlModuleInterfaceCommon() { - tracer = nullptr; - registers = nullptr; - } - - void setup(std::filesystem::path wavefile, const R *r) { - if (!wavefile.empty()) - tracer = std::make_unique>(this, wavefile); - registers = r; - } - - void eval(void) { - if (this->is_posedge()) { - posedge_cnt++; - } - T::clock = !T::clock; - sim_time++; - T::eval(); - if (tracer) - tracer->update(); - } - - const Breakpoint *stepi(const std::vector &breakpoints) { - this->eval(); - this->eval(); - size_t pc = registers->get_pc(); - for (const auto &bp : breakpoints) { - if (pc == bp.addr) { - return &bp; - } - } - return nullptr; - } - - const Breakpoint *cont(const std::vector &breakpoints) { - const Breakpoint *res = nullptr; - do { - res = stepi(breakpoints); - } while (res == nullptr); - return res; - } - - void reset_eval(int n) { - extern bool g_skip_memcheck; - g_skip_memcheck = true; - this->reset = 1; - do { - this->eval(); - } while (--n); - this->reset = 0; - g_skip_memcheck = false; - } - bool is_posedge() { - // Will be posedge when eval is called - return T::clock == 0; - } -}; - -#endif diff --git a/npc/include/vpi_wrapper.hpp b/npc/include/vpi_wrapper.hpp deleted file mode 100644 index 22b1876..0000000 --- a/npc/include/vpi_wrapper.hpp +++ /dev/null @@ -1,45 +0,0 @@ -#ifndef _NPC_VPI_WRAPPER_H_ -#define _NPC_VPI_WRAPPER_H_ -#include -#include -#include -#include -#include - -template -class _RegistersVPI : public _RegistersBase { - std::array reg_handles; - vpiHandle pc_handle; - - T vpi_get(vpiHandle vh) const { - s_vpi_value v; - v.format = vpiIntVal; - vpi_get_value(vh, &v); - return v.value.integer; - } - T fetch_pc(void) const { return vpi_get(pc_handle); } - T fetch_reg(std::size_t id) const { return vpi_get(reg_handles[id]); } - -public: - _RegistersVPI(const std::string regs_prefix, - const std::string pcname) { - init_handlers(regs_prefix, pcname); - } - -private: - void init_handlers(const std::string regs_prefix, const std::string pcname) { - for (int i = 0; i < nr; i++) { - std::string regname = regs_prefix + std::to_string(i); - vpiHandle vh = vpi_handle_by_name((PLI_BYTE8 *)regname.c_str(), nullptr); - if (vh == nullptr) { - std::cerr << "vpiHandle " << regname.c_str() << " not found" - << std::endl; - exit(EXIT_FAILURE); - } - reg_handles[i] = vh; - } - pc_handle = vpi_handle_by_name((PLI_BYTE8 *)pcname.c_str(), nullptr); - } -}; - -#endif diff --git a/npc/resource/addi.txt b/npc/resource/addi.txt index 6fb3e74..8eb11e4 100644 --- a/npc/resource/addi.txt +++ b/npc/resource/addi.txt @@ -1,17 +1,10 @@ -00110113 -00110113 -00110113 -00110113 -00110113 -00110113 -00110113 -00110113 -00110113 -00110113 -00110113 -00110113 -00110113 -00110113 -00110113 -00110113 -00110113 +00114113 +00114113 +00114113 +00114113 +00114113 +00114113 +00114113 +00114113 +00114113 +00114113 diff --git a/npc/utils/CMakeLists.txt b/npc/utils/CMakeLists.txt deleted file mode 100644 index 545b778..0000000 --- a/npc/utils/CMakeLists.txt +++ /dev/null @@ -1,3 +0,0 @@ -if(ENABLE_SDB) - add_subdirectory(sdb) -endif() diff --git a/npc/utils/sdb/CMakeLists.txt b/npc/utils/sdb/CMakeLists.txt deleted file mode 100644 index 70b3f3d..0000000 --- a/npc/utils/sdb/CMakeLists.txt +++ /dev/null @@ -1,34 +0,0 @@ -find_package(Readline REQUIRED) -find_package(FLEX REQUIRED) -find_package(BISON REQUIRED) -find_package(LLVM CONFIG REQUIRED) -set(PARSER_DIR "${CMAKE_CURRENT_BINARY_DIR}") -set(LEXER_OUT "${PARSER_DIR}/lexer.c") -set(PARSER_OUT "${PARSER_DIR}/parser.c") -flex_target(LEXER addrexp.l "${LEXER_OUT}" - DEFINES_FILE "${PARSER_DIR}/addrexp_lex.h") -bison_target(PARSER addrexp.y "${PARSER_OUT}" - DEFINES_FILE "${PARSER_DIR}/addrexp.h") -add_flex_bison_dependency(LEXER PARSER) - -add_library(sdb OBJECT sdb.cpp console.cpp disasm.cpp "${LEXER_OUT}" - "${PARSER_OUT}") -llvm_map_components_to_libnames( - LLVM_LIBS - core - target - asmparser - riscvasmparser - riscvdesc - riscvdisassembler - riscvinfo - riscvtargetmca) -target_link_libraries(sdb PUBLIC ${LLVM_LIBS}) -target_link_libraries(sdb PRIVATE ${Readline_LIBRARY}) - -target_include_directories( - sdb - PRIVATE ${PARSER_DIR} ${Readline_INCLUDE_DIR} - PUBLIC ${CMAKE_SOURCE_DIR}/include) - -target_include_directories(sdb PUBLIC include) diff --git a/npc/utils/sdb/console.cpp b/npc/utils/sdb/console.cpp deleted file mode 100644 index 61c9452..0000000 --- a/npc/utils/sdb/console.cpp +++ /dev/null @@ -1,221 +0,0 @@ -// cpp-readline library -// -// @author zmij -// @date Nov 30, 2015 - -#include - -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -namespace CppReadline { -namespace { - -Console *currentConsole = nullptr; -HISTORY_STATE *emptyHistory = history_get_history_state(); - -} /* namespace */ - -struct Console::Impl { - using RegisteredCommands = - std::unordered_map; - - ::std::string greeting_; - // These are hardcoded commands. They do not do anything and are catched manually in the executeCommand function. - RegisteredCommands commands_; - HISTORY_STATE *history_ = nullptr; - - Impl(::std::string const &greeting) : greeting_(greeting), commands_() {} - ~Impl() { free(history_); } - - Impl(Impl const &) = delete; - Impl(Impl &&) = delete; - Impl &operator=(Impl const &) = delete; - Impl &operator=(Impl &&) = delete; -}; - -// Here we set default commands, they do nothing since we quit with them -// Quitting behaviour is hardcoded in readLine() -Console::Console(std::string const &greeting) : pimpl_{new Impl{greeting}} { - // Init readline basics - rl_attempted_completion_function = &Console::getCommandCompletions; - - // These are default hardcoded commands. - // Help command lists available commands. - pimpl_->commands_["help"] = [this](const Arguments &) { - auto commands = getRegisteredCommands(); - std::cout << "Available commands are:\n"; - for (auto &command : commands) - std::cout << "\t" << command << "\n"; - return ReturnCode::Ok; - }; - // Run command executes all commands in an external file. - pimpl_->commands_["run"] = [this](const Arguments &input) { - if (input.size() < 2) { - std::cout << "Usage: " << input[0] << " script_filename\n"; - return 1; - } - return executeFile(input[1]); - }; - // Quit and Exit simply terminate the console. - pimpl_->commands_["quit"] = [this](const Arguments &) { - return ReturnCode::Quit; - }; - - pimpl_->commands_["exit"] = [this](const Arguments &) { - return ReturnCode::Quit; - }; -} - -Console::~Console() = default; - -void Console::registerCommand(const std::string &s, CommandFunction f) { - pimpl_->commands_[s] = f; -} - -void Console::removeCommands(const std::vector sv) { - for (auto const &s : sv) { - pimpl_->commands_.erase(s); - } -} - -std::vector Console::getRegisteredCommands() const { - std::vector allCommands; - for (auto &pair : pimpl_->commands_) - allCommands.push_back(pair.first); - - return allCommands; -} - -void Console::saveState() { - free(pimpl_->history_); - pimpl_->history_ = history_get_history_state(); -} - -void Console::reserveConsole() { - if (currentConsole == this) - return; - - // Save state of other Console - if (currentConsole) - currentConsole->saveState(); - - // Else we swap state - if (!pimpl_->history_) - history_set_history_state(emptyHistory); - else - history_set_history_state(pimpl_->history_); - - // Tell others we are using the console - currentConsole = this; -} - -void Console::setGreeting(const std::string &greeting) { - pimpl_->greeting_ = greeting; -} - -std::string Console::getGreeting() const { return pimpl_->greeting_; } - -int Console::executeCommand(const std::string &command) { - // Convert input to vector - std::vector inputs; - { - std::istringstream iss(command); - std::copy(std::istream_iterator(iss), - std::istream_iterator(), std::back_inserter(inputs)); - } - - if (inputs.size() == 0) - return ReturnCode::Ok; - - Impl::RegisteredCommands::iterator it; - if ((it = pimpl_->commands_.find(inputs[0])) != end(pimpl_->commands_)) { - return static_cast((it->second)(inputs)); - } - - std::cout << "Command '" << inputs[0] << "' not found.\n"; - return ReturnCode::Error; -} - -int Console::executeFile(const std::string &filename) { - std::ifstream input(filename); - if (!input) { - std::cout << "Could not find the specified file to execute.\n"; - return ReturnCode::Error; - } - std::string command; - int counter = 0, result; - - while (std::getline(input, command)) { - if (command[0] == '#') - continue; // Ignore comments - // Report what the Console is executing. - std::cout << "[" << counter << "] " << command << '\n'; - if ((result = executeCommand(command))) - return result; - ++counter; - std::cout << '\n'; - } - - // If we arrived successfully at the end, all is ok - return ReturnCode::Ok; -} - -int Console::readLine() { - reserveConsole(); - - char *buffer = readline(pimpl_->greeting_.c_str()); - if (!buffer) { - std::cout - << '\n'; // EOF doesn't put last endline so we put that so that it looks uniform. - return ReturnCode::Quit; - } - - // TODO: Maybe add commands to history only if succeeded? - if (buffer[0] != '\0') - add_history(buffer); - - std::string line(buffer); - free(buffer); - - return executeCommand(line); -} - -char **Console::getCommandCompletions(const char *text, int start, int) { - char **completionList = nullptr; - - if (start == 0) - completionList = rl_completion_matches(text, &Console::commandIterator); - - return completionList; -} - -char *Console::commandIterator(const char *text, int state) { - static Impl::RegisteredCommands::iterator it; - if (!currentConsole) - return nullptr; - auto &commands = currentConsole->pimpl_->commands_; - - if (state == 0) - it = begin(commands); - - while (it != end(commands)) { - auto &command = it->first; - ++it; - if (command.find(text) != std::string::npos) { - return strdup(command.c_str()); - } - } - return nullptr; -} -} // namespace CppReadline diff --git a/npc/utils/sdb/disasm.cpp b/npc/utils/sdb/disasm.cpp deleted file mode 100644 index e4671f0..0000000 --- a/npc/utils/sdb/disasm.cpp +++ /dev/null @@ -1,90 +0,0 @@ -#include -#include -#include -#include -#include -#include -#if LLVM_VERSION_MAJOR >= 14 -#include -#if LLVM_VERSION_MAJOR >= 15 -#include -#endif -#else -#include -#endif -#include -#include -#include - -#if defined(__GNUC__) && !defined(__clang__) -#pragma GCC diagnostic pop -#endif - -#if LLVM_VERSION_MAJOR < 11 -#error Please use LLVM with major version >= 11 -#endif - -Disassembler::Disassembler(std::string triple) : triple(triple) { - // llvm::InitializeAllTargetInfos(); - // llvm::InitializeAllTargetMCs(); - // llvm::InitializeAllAsmParsers(); - // llvm::InitializeAllDisassemblers(); - LLVMInitializeRISCVTargetInfo(); - LLVMInitializeRISCVTargetMC(); - LLVMInitializeRISCVAsmParser(); - LLVMInitializeRISCVDisassembler(); - std::string errstr; - - llvm::MCInstrInfo *gMII = nullptr; - llvm::MCRegisterInfo *gMRI = nullptr; - auto target = llvm::TargetRegistry::lookupTarget(triple, errstr); - if (!target) { - llvm::errs() << "Can't find target for " << triple << ": " << errstr - << "\n"; - assert(0); - } - - llvm::MCTargetOptions MCOptions; - gSTI = target->createMCSubtargetInfo(triple, "", ""); - std::string isa = target->getName(); - if (isa == "riscv32" || isa == "riscv64") { - gSTI->ApplyFeatureFlag("+m"); - gSTI->ApplyFeatureFlag("+a"); - gSTI->ApplyFeatureFlag("+c"); - gSTI->ApplyFeatureFlag("+f"); - gSTI->ApplyFeatureFlag("+d"); - } - gMII = target->createMCInstrInfo(); - gMRI = target->createMCRegInfo(triple); - auto AsmInfo = target->createMCAsmInfo(*gMRI, triple, MCOptions); -#if LLVM_VERSION_MAJOR >= 13 - auto llvmTripleTwine = llvm::Twine(triple); - auto llvmtriple = llvm::Triple(llvmTripleTwine); - auto Ctx = new llvm::MCContext(llvmtriple, AsmInfo, gMRI, nullptr); -#else - auto Ctx = new llvm::MCContext(AsmInfo, gMRI, nullptr); -#endif - gDisassembler = target->createMCDisassembler(*gSTI, *Ctx); - gIP = target->createMCInstPrinter(llvm::Triple(triple), - AsmInfo->getAssemblerDialect(), *AsmInfo, - *gMII, *gMRI); - gIP->setPrintImmHex(true); - gIP->setPrintBranchImmAsAddress(true); - if (isa == "riscv32" || isa == "riscv64") - gIP->applyTargetSpecificCLOption("no-aliases"); -} - -std::string Disassembler::disassemble(uint64_t pc, uint8_t *code, int nbyte) { - llvm::MCInst inst; - llvm::ArrayRef arr(code, nbyte); - uint64_t dummy_size = 0; - gDisassembler->getInstruction(inst, dummy_size, arr, pc, llvm::nulls()); - - std::stringstream ss; - ss << "0x" << std::hex << pc << ": "; - std::string s = ss.str(); - llvm::raw_string_ostream os{s}; - gIP->printInst(&inst, pc, "", *gSTI, os); - - return s; -} diff --git a/npc/utils/sdb/include/console.hpp b/npc/utils/sdb/include/console.hpp deleted file mode 100644 index 69c4099..0000000 --- a/npc/utils/sdb/include/console.hpp +++ /dev/null @@ -1,152 +0,0 @@ -// cpp-readline library -// -// @author zmij -// @date Nov 30, 2015 - -#ifndef CONSOLE_CONSOLE_HEADER_FILE -#define CONSOLE_CONSOLE_HEADER_FILE - -#include -#include -#include -#include - -namespace CppReadline { -class Console { -public: - /** - * @brief This is the function type that is used to interface with the Console class. - * - * These are the functions that are going to get called by Console - * when the user types in a message. The vector will hold the - * command elements, and the function needs to return its result. - * The result can either be Quit (-1), OK (0), or an arbitrary - * error (>=1). - */ - using Arguments = std::vector; - using CommandFunction = std::function; - - enum ReturnCode { - Quit = -1, - Ok = 0, - Error = 1 // Or greater! - }; - - /** - * @brief Basic constructor. - * - * The Console comes with two predefined commands: "quit" and - * "exit", which both terminate the console, "help" which prints a - * list of all registered commands, and "run" which executes script - * files. - * - * These commands can be overridden or unregistered - but remember - * to leave at least one to quit ;). - * - * @param greeting This represents the prompt of the Console. - */ - explicit Console(std::string const &greeting); - - /** - * @brief Basic destructor. - * - * Frees the history which is been produced by GNU readline. - */ - ~Console(); - - /** - * @brief This function registers a new command within the Console. - * - * If the command already existed, it overwrites the previous entry. - * - * @param s The name of the command as inserted by the user. - * @param f The function that will be called once the user writes the command. - */ - void registerCommand(const std::string &s, CommandFunction f); - - /** - * @brief This function removes a list of registered commands. - * - * @param sv The vector of command names to be removed. - */ - void removeCommands(const std::vector sv); - - /** - * @brief This function returns a list with the currently available commands. - * - * @return A vector containing all registered commands names. - */ - std::vector getRegisteredCommands() const; - - /** - * @brief Sets the prompt for this Console. - * - * @param greeting The new greeting. - */ - void setGreeting(const std::string &greeting); - - /** - * @brief Gets the current prompt of this Console. - * - * @return The currently set greeting. - */ - std::string getGreeting() const; - - /** - * @brief This function executes an arbitrary string as if it was inserted via stdin. - * - * @param command The command that needs to be executed. - * - * @return The result of the operation. - */ - int executeCommand(const std::string &command); - - /** - * @brief This function calls an external script and executes all commands inside. - * - * This function stops execution as soon as any single command returns something - * different from 0, be it a quit code or an error code. - * - * @param filename The pathname of the script. - * - * @return What the last command executed returned. - */ - int executeFile(const std::string &filename); - - /** - * @brief This function executes a single command from the user via stdin. - * - * @return The result of the operation. - */ - int readLine(); - -private: - Console(const Console &) = delete; - Console(Console &&) = delete; - Console &operator=(Console const &) = delete; - Console &operator=(Console &&) = delete; - - struct Impl; - using PImpl = ::std::unique_ptr; - PImpl pimpl_; - - /** - * @brief This function saves the current state so that some other Console can make use of the GNU readline facilities. - */ - void saveState(); - /** - * @brief This function reserves the use of the GNU readline facilities to the calling Console instance. - */ - void reserveConsole(); - - // GNU newline interface to our commands. - using commandCompleterFunction = char **(const char *text, int start, - int end); - using commandIteratorFunction = char *(const char *text, int state); - - static commandCompleterFunction getCommandCompletions; - static commandIteratorFunction commandIterator; -}; -} // namespace CppReadline - -#endif diff --git a/npc/utils/sdb/include/disasm.hpp b/npc/utils/sdb/include/disasm.hpp deleted file mode 100644 index a14ebb3..0000000 --- a/npc/utils/sdb/include/disasm.hpp +++ /dev/null @@ -1,17 +0,0 @@ -#ifndef _NPC_UTILS_DISASM_ -#define _NPC_UTILS_DISASM_ -#include "llvm/MC/MCDisassembler/MCDisassembler.h" -#include "llvm/MC/MCInstPrinter.h" - -class Disassembler { - llvm::MCDisassembler *gDisassembler = nullptr; - llvm::MCSubtargetInfo *gSTI = nullptr; - llvm::MCInstPrinter *gIP = nullptr; - std::string triple; - -public: - Disassembler(std::string); - std::string disassemble(uint64_t pc, uint8_t *code, int nbyte); -}; - -#endif \ No newline at end of file diff --git a/npc/utils/sdb/include/sdb.hpp b/npc/utils/sdb/include/sdb.hpp deleted file mode 100644 index 569773b..0000000 --- a/npc/utils/sdb/include/sdb.hpp +++ /dev/null @@ -1,99 +0,0 @@ -#ifndef _SDB_SDB_HEADER_FILE_ -#define _SDB_SDB_HEADER_FILE_ - -#include -#include -#include -#include -#include -#include -#include - -namespace cr = CppReadline; -using ret = cr::Console::ReturnCode; - -namespace SDB { - -enum SDBStatus { - SDB_SUCCESS, - SDB_EBREAK = 2, - SDB_WRONG_ARGUMENT, - SDB_DIFFTEST_FAILED -}; - -class SDBHandlers; - -struct Handler { - const std::vector names; - // cr::Console::CommandFunction f; - std::function f; -}; - -class SDBHandlers { -private: - const TrmInterface &funcs; - std::vector all_handlers = { - Handler{{"c", "continue"}, &SDBHandlers::cmd_continue}, - Handler{{"si", "step-instruction"}, &SDBHandlers::cmd_step}, - Handler{{"info-r"}, &SDBHandlers::cmd_info_registers}, - Handler{{"p", "print"}, &SDBHandlers::cmd_print}, - Handler{{"disas", "disassemble"}, &SDBHandlers::cmd_disassemble}, - }; - int cmd_continue(const cr::Console::Arguments &input); - int cmd_step(const std::vector &input); - int cmd_info_registers(const std::vector &input); - int cmd_print(const std::vector &input); - int cmd_disassemble(const std::vector &input); - int exec_catch(uint64_t); - -public: - SDBHandlers(const TrmInterface &funcs) : funcs(funcs){}; - void register_handlers(cr::Console *c); -}; - -class SDB { -private: - std::unique_ptr c; - const TrmInterface &funcs; - SDBHandlers handlers; - -public: - SDB(const TrmInterface &funcs, - std::string const &greeting = "\033[1;34m(npc)\033[0m ") - : handlers(SDBHandlers{funcs}), funcs(funcs) { - c = std::make_unique(greeting); - - handlers.register_handlers(c.get()); - }; - - int main_loop() { - int ret_code; - funcs.init(0); - std::vector step_commands{"c", "continue", "si", - "step-instruction"}; - do { - ret_code = c->readLine(); - // We can also change the prompt based on last return value: - if (ret_code == SDB_SUCCESS || ret_code == SDB_EBREAK) - c->setGreeting("\033[1;34m(npc)\033[0m "); - else - c->setGreeting("\033[1;31m(npc)\033[0m "); - - switch (ret_code) { - case SDB_EBREAK: { - std::cout << "\033[1;31m=== ebreak ===\033[0m" << std::endl; - c->removeCommands(step_commands); - break; - } - case SDB_WRONG_ARGUMENT: { - std::cout << "Wrong argument(s) is given to command handler\n"; - break; - } - } - } while (ret_code != ret::Quit); - return 0; - } -}; -} // namespace SDB - -#endif diff --git a/npc/utils/sdb/sdb.cpp b/npc/utils/sdb/sdb.cpp deleted file mode 100644 index 36aa787..0000000 --- a/npc/utils/sdb/sdb.cpp +++ /dev/null @@ -1,113 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -extern "C" { -#include -#include -} - -namespace cr = CppReadline; -using ret = cr::Console::ReturnCode; - -std::ostream &operator<<(std::ostream &os, const TrmInterface &d) { - d.print(os); - return os; -}; - -Disassembler d{"riscv32-linux-pc-gnu"}; - -namespace SDB { - -int SDBHandlers::exec_catch(uint64_t n) { - try { - this->funcs.exec(n); - } catch (TrmRuntimeException &e) { - switch (e.error_code()) { - case TrmRuntimeException::EBREAK: - return SDB_EBREAK; - case TrmRuntimeException::DIFFTEST_FAILED: - std::cout << "Difftest Failed" << std::endl << funcs << std::endl; - return SDB_DIFFTEST_FAILED; - default: - std::cerr << "Unknown error code" << std::endl; - exit(1); - } - } - return SDB_SUCCESS; -} - -int SDBHandlers::cmd_continue(const cr::Console::Arguments &input) { - if (input.size() > 1) - return SDB_WRONG_ARGUMENT; - return exec_catch(-1); -} - -int SDBHandlers::cmd_step(const std::vector &input) { - if (input.size() > 2) { - return SDB_WRONG_ARGUMENT; - } - uint64_t step_count = input.size() == 2 ? std::stoull(input[1]) : 1; - return exec_catch(step_count); - // std::cout << funcs << std::endl; -} - -int SDBHandlers::cmd_info_registers(const std::vector &input) { - if (input.size() > 1) - return SDB_WRONG_ARGUMENT; - std::cout << this->funcs << std::endl; - return SDB_SUCCESS; -} - -word_t parse_expr(const char *arg) { - if (arg == NULL) { - puts("Invalid expr argument."); - return 0; - } else { - word_t res; - yy_scan_string(arg); - yyparse(&res); - yylex_destroy(); - return res; - } -} - -int SDBHandlers::cmd_print(const std::vector &input) { - word_t buf[2]; - word_t addr = parse_expr(input[1].c_str()); - this->funcs.memcpy(addr, &buf, sizeof(word_t), TRM_FROM_MACHINE); - // TODO: Difftest only - std::cout << std::hex << "dut: 0x" << buf[0] << ' ' << "ref: 0x" << buf[1] - << std::dec << std::endl; - return SDB_SUCCESS; -} - -int SDBHandlers::cmd_disassemble(const std::vector &input) { - word_t buf[2]; - word_t addr = parse_expr(input[1].c_str()); - this->funcs.memcpy(addr, &buf, sizeof(word_t), TRM_FROM_MACHINE); - // TODO: Difftest only - std::cout << "dut: \n" - << d.disassemble(addr, (uint8_t *)&buf[0], sizeof(word_t)) - << std::endl - << "ref: \n" - << d.disassemble(addr, (uint8_t *)&buf[0], sizeof(word_t)) - << std::endl; - ; - return SDB_SUCCESS; -} - -void SDBHandlers::register_handlers(cr::Console *c) { - for (auto &h : this->all_handlers) { - for (auto &name : h.names) { - std::function)> f{ - std::bind(h.f, this, std::placeholders::_1)}; - c->registerCommand(name, f); - } - } -} - -} // namespace SDB