diff --git a/.gitignore b/.gitignore index 76cec07..7a06b53 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,4 @@ !*/ -difftest/ !/nemu/* !/nexus-am/* !/nanos-lite/* @@ -14,4 +13,3 @@ difftest/ **/.cache **/result /.pre-commit-config.yaml -**/.vscode/ diff --git a/.gitmodules b/.gitmodules index 7553118..3d834b3 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,4 +1,3 @@ [submodule "am-kernels"] path = am-kernels url = https://git.xinyang.life/xin/am-kernels.git - branch = dev 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 659bb84..508bc68 100644 --- a/abstract-machine/CMakeLists.txt +++ b/abstract-machine/CMakeLists.txt @@ -6,120 +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=) -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/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/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 d991825..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 - PRIVATE klib_interface am_interface) +target_link_libraries(am-${ARCH} PUBLIC SDL2::SDL2) 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 c4287c5..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 "5" +#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 0ec140f..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 PRIVATE ${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/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/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/default.nix b/abstract-machine/default.nix index ef21cf2..1f1f67d 100644 --- a/abstract-machine/default.nix +++ b/abstract-machine/default.nix @@ -1,19 +1,20 @@ -{ stdenv, +{ stdenv, lib, cmake, SDL2, isa ? "native", - platform ? [ ] + platform ? "NEMU" }: stdenv.mkDerivation { pname = "abstract-machine"; - version = "2024.06.01"; + version = "2024.02.18"; src = ./.; cmakeFlags = [ (lib.cmakeFeature "ISA" isa) - ] ++ map (p: (lib.cmakeBool "__PLATFORM_${lib.strings.toUpper p}__" true)) platform; + (lib.cmakeBool "__PLATFORM_${lib.strings.toUpper platform}__" true) + ]; nativeBuildInputs = [ cmake @@ -21,7 +22,5 @@ stdenv.mkDerivation { buildInputs = [ - ] ++ (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 5d173b7..bf7e136 100644 --- a/abstract-machine/klib/src/CMakeLists.txt +++ b/abstract-machine/klib/src/CMakeLists.txt @@ -1,30 +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_link_options(klib PUBLIC -nostartfiles -nolibc) +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 35f9f59..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,103 +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--; - } - - if (reverse == 0) { - append_to_buffer(buf, pos, '0'); - } else { - while (reverse != 0) { - 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/tests/CMakeLists.txt b/abstract-machine/klib/tests/CMakeLists.txt index 6d1c225..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 m) - 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/flake.nix b/flake.nix index 0ea12c7..c824872 100644 --- a/flake.nix +++ b/flake.nix @@ -42,8 +42,6 @@ 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++" ]; @@ -54,8 +52,7 @@ packages.nemu = pkgs.callPackage ./nemu { am-kernels = self.packages.${system}.am-kernels; }; packages.nemu-lib = pkgs.callPackage ./nemu { am-kernels = self.packages.${system}.am-kernels; defconfig = "riscv32-lib_defconfig"; }; - packages.abstract-machine = crossPkgs.callPackage ./abstract-machine { isa = "riscv"; platform = [ "nemu" "npc" ]; }; - packages.abstract-machine-native = pkgs.callPackage ./abstract-machine { isa = "native"; }; + packages.abstract-machine = crossPkgs.callPackage ./abstract-machine { isa = "riscv"; platform = "nemu"; }; packages.am-kernels = crossPkgs.stdenv.mkDerivation rec { pname = "am-kernels-cmake"; @@ -70,6 +67,7 @@ cmakeFlags = [ (pkgs.lib.cmakeFeature "ISA" "riscv") (pkgs.lib.cmakeFeature "PLATFORM" "nemu") + (pkgs.lib.cmakeFeature "CMAKE_INSTALL_DATADIR" "share") ]; buildInputs = [ @@ -86,16 +84,16 @@ inputsFrom = [ self.packages.${system}.nemu ]; - NEMU_HOME = "/home/xin/repo/ysyx-workbench/nemu"; - NEMU_IMAGES_PATH = self.packages.${system}.am-kernels + "/share/am-kernels"; + IMAGES_PATH = "${self.packages.${system}.am-kernels}/share/binary"; }; - devShells.npc = with pkgs; mkShell.override { stdenv = ccacheStdenv; } { + devShells.npc = with pkgs; mkShell { inherit (self.checks.${system}.pre-commit-check) shellHook; CHISEL_FIRTOOL_PATH = "${nixpkgs-circt162.legacyPackages.${system}.circt}/bin"; packages = [ clang-tools cmake + ninja coursier espresso bloop diff --git a/nemu/Kconfig b/nemu/Kconfig index 8c91522..5816143 100644 --- a/nemu/Kconfig +++ b/nemu/Kconfig @@ -180,7 +180,7 @@ config ITRACE_BUFFER default 10 config MTRACE - depends on TRACE && LOG_TRACE + depends on TRACE bool "Enable memory tracing" default n @@ -198,7 +198,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/default.nix b/nemu/default.nix index 785d77e..052b4a7 100644 --- a/nemu/default.nix +++ b/nemu/default.nix @@ -3,7 +3,6 @@ stdenv, am-kernels, dtc, - mini-gdbstub, defconfig ? "alldefconfig", }: @@ -24,7 +23,6 @@ stdenv.mkDerivation rec { buildInputs = with pkgs; [ readline libllvm - mini-gdbstub ]; checkInputs = [ @@ -43,7 +41,7 @@ stdenv.mkDerivation rec { doCheck = (defconfig == "alldefconfig"); checkPhase = if doCheck then '' - export NEMU_IMAGES_PATH=${am-kernels}/share/am-kernels + export IMAGES_PATH=${am-kernels}/share/binary make test '' else ""; 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/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/scripts/build.mk b/nemu/scripts/build.mk index f3bfe15..a3b71d2 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) diff --git a/nemu/src/cpu/cpu-exec.c b/nemu/src/cpu/cpu-exec.c index f4be925..097c02f 100644 --- a/nemu/src/cpu/cpu-exec.c +++ b/nemu/src/cpu/cpu-exec.c @@ -13,12 +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. @@ -35,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)); } @@ -60,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; @@ -74,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 @@ -84,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()) { + IFDEF(CONFIG_ITRACE, puts(logbuf[logbuf_rear])); break; + } + if (nemu_state.state != NEMU_RUNNING) break; IFDEF(CONFIG_DEVICE, device_update()); } } @@ -99,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() { @@ -116,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(); @@ -133,52 +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) { + IFDEF(CONFIG_ITRACE, log_itrace_print()); + } + } // fall through + case NEMU_QUIT: statistic(); } } - -breakpoint_t *cpu_exec_with_bp(uint64_t n, breakpoint_t *bp, size_t len) { - static Decode s; - nemu_state.state = NEMU_RUNNING; - do { - exec_once(&s, cpu.pc); - g_nr_guest_inst++; - for (int i = 0; i < len; i++) { - size_t addr = bp[i].addr; - bp_type_t bptype = bp[i].type; - 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; - } - } - if (nemu_state.state != NEMU_RUNNING) - return NULL; - } while (--n); - return NULL; -} diff --git a/nemu/src/engine/interpreter/init.c b/nemu/src/engine/interpreter/init.c index fed4923..a517c3e 100644 --- a/nemu/src/engine/interpreter/init.c +++ b/nemu/src/engine/interpreter/init.c @@ -13,9 +13,7 @@ * See the Mulan PSL v2 for more details. ***************************************************************************************/ -#include "debug.h" #include -#include void sdb_mainloop(); @@ -24,10 +22,6 @@ void engine_start() { cpu_exec(-1); #else /* Receive commands from user. */ - int nemu_gdbstub_run(); - if (nemu_gdbstub_run()) { - Error("gdbstub exited abnormally"); - exit(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/riscv32/include/isa-def.h b/nemu/src/isa/riscv32/include/isa-def.h index 524cb4e..dd0105c 100644 --- a/nemu/src/isa/riscv32/include/isa-def.h +++ b/nemu/src/isa/riscv32/include/isa-def.h @@ -20,7 +20,6 @@ typedef struct { word_t gpr[MUXDEF(CONFIG_RVE, 16, 32)]; - // word_t csr[MUXDEF(CONFIG_RVE, )] 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 dc65f47..1c41c63 100644 --- a/nemu/src/isa/riscv32/inst.c +++ b/nemu/src/isa/riscv32/inst.c @@ -13,91 +13,45 @@ * See the Mulan PSL v2 for more details. ***************************************************************************************/ +#include #include "local-include/reg.h" #include "macro.h" -#include "types.h" -#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_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 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) { - 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_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; } } @@ -108,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); @@ -138,118 +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); - 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/reg.c b/nemu/src/isa/riscv32/reg.c index 52e6ba0..4630df9 100644 --- a/nemu/src/isa/riscv32/reg.c +++ b/nemu/src/isa/riscv32/reg.c @@ -13,20 +13,20 @@ * See the Mulan PSL v2 for more details. ***************************************************************************************/ -#include "local-include/reg.h" -#include "gdbstub.h" -#include "macro.h" -#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'); @@ -49,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; -} - -arch_info_t isa_arch_info = {.reg_num = 33, - .reg_byte = MUXDEF(CONFIG_RV64, 8, 4), - .target_desc = TARGET_RV32}; 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 10ee66c..437debd 100644 --- a/nemu/src/memory/paddr.c +++ b/nemu/src/memory/paddr.c @@ -15,12 +15,12 @@ #include "common.h" #include "debug.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 = {}; @@ -31,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) { @@ -44,24 +44,22 @@ static void pmem_write(paddr_t addr, int len, word_t data) { } static void out_of_bound(paddr_t addr) { - panic("address = " FMT_PADDR " is out of bound of pmem [" FMT_PADDR - ", " FMT_PADDR "] at pc = " FMT_WORD, - addr, PMEM_LEFT, PMEM_RIGHT, cpu.pc); + 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 @@ -69,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++) { @@ -87,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 07c4fe5..0000000 --- a/nemu/src/monitor/filelist.mk +++ /dev/null @@ -1,3 +0,0 @@ -DIRS-y += src/monitor - -CXXSRC += src/monitor/gdbstub.cc diff --git a/nemu/src/monitor/gdbstub.cc b/nemu/src/monitor/gdbstub.cc deleted file mode 100644 index 40aa594..0000000 --- a/nemu/src/monitor/gdbstub.cc +++ /dev/null @@ -1,130 +0,0 @@ -#include "utils.h" -#include - -extern "C" { -#include -#include -#include -#include -#include -#include -#include -#include -} - -typedef struct { - std::vector *bp; - bool halt; -} DbgState; - -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; -} - -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; - 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; - - default: - act->reason = gdb_action_t::ACT_SHUTDOWN; - act->data = nemu_state.halt_ret; - } -} - -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); -} - -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); -} - -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; -} - -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; -} - -void nemu_on_interrupt(void *args) { - // fputs("Not implemented", stderr); -} - -static struct target_ops nemu_gdbstub_ops = {.cont = nemu_cont, - .stepi = nemu_stepi, - .read_reg = isa_read_reg, - .write_reg = isa_write_reg, - .read_mem = nemu_read_mem, - .write_mem = nemu_write_mem, - .set_bp = nemu_set_bp, - .del_bp = nemu_del_bp, - .on_interrupt = NULL}; -static DbgState dbg; -extern "C" { -static gdbstub_t gdbstub_priv; -#define SOCKET_ADDR "127.0.0.1:1234" -int nemu_gdbstub_init() { - dbg.bp = new std::vector(); - assert(dbg.bp); - if (!gdbstub_init(&gdbstub_priv, &nemu_gdbstub_ops, - (arch_info_t)isa_arch_info, SOCKET_ADDR)) { - return EINVAL; - } - return 0; -} -int nemu_gdbstub_run() { - puts("Waiting for gdb connection at " SOCKET_ADDR); - bool success = gdbstub_run(&gdbstub_priv, &dbg); - gdbstub_close(&gdbstub_priv); - return !success; -} -} diff --git a/nemu/src/monitor/monitor.c b/nemu/src/monitor/monitor.c index b9b343e..0154208 100644 --- a/nemu/src/monitor/monitor.c +++ b/nemu/src/monitor/monitor.c @@ -13,10 +13,8 @@ * See the Mulan PSL v2 for more details. ***************************************************************************************/ -#include #include #include -#include #include void init_rand(); @@ -24,25 +22,24 @@ 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); -int nemu_gdbstub_init(); 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; @@ -50,50 +47,13 @@ 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); @@ -110,41 +70,32 @@ static long load_img() { static int parse_args(int argc, char *argv[]) { const struct option table[] = { - {"batch", no_argument, NULL, 'b'}, - {"log", required_argument, NULL, 'l'}, - {"diff", required_argument, NULL, 'd'}, - {"port", required_argument, NULL, 'p'}, - {"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 '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); + 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; @@ -177,14 +128,11 @@ void init_monitor(int argc, char *argv[]) { /* Initialize differential testing. */ init_difftest(diff_so_file, img_size, difftest_port); - /* Initialize debugger */ - if (nemu_gdbstub_init()) { - Error("Failed to init"); - exit(1); - } + /* 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); @@ -194,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/nemu/src/monitor/sdb/addrexp.l b/nemu/src/monitor/sdb/addrexp.l new file mode 100644 index 0000000..d814ee3 --- /dev/null +++ b/nemu/src/monitor/sdb/addrexp.l @@ -0,0 +1,24 @@ +%{ + #include + #include + static bool success = false; + void yyerror(word_t *result, const char *err); +%} +%option noyywrap + +%% + +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 = isa_reg_str2val(yytext + 1, &success); + if(!success) { + yyerror(NULL, "Failed to convert reg to value"); + return YYerror; + } + return REGISTER; +} +[+\-*/<=()] { return *yytext; } +[ \t] { } +. { printf("Unexpected character: %s\n", yytext); return YYerror; } +%% diff --git a/nemu/src/monitor/sdb/addrexp.y b/nemu/src/monitor/sdb/addrexp.y new file mode 100644 index 0000000..4094e0b --- /dev/null +++ b/nemu/src/monitor/sdb/addrexp.y @@ -0,0 +1,60 @@ +%code requires { + #include + #include + #include + #include + extern int yylex(void); +} +%{ + #include + #include + #include + #include + #include + void yyerror(word_t *result, const char *err) { + Error("%s", err); + } +%} + +%token NUMBER HEX_NUMBER +%token REGISTER +%locations +%start input +%define api.value.type { word_t } +%parse-param { uint32_t *result } +%left '-' '+' +%left '*' '/' + +%% +input + : expression { *result = $1; } + ; + +expression + : number { $$ = $1; } + | expression '>' '=' expression { $$ = ($1 >= $4); } + | expression '<' '=' expression { $$ = ($1 <= $4); } + | expression '=' '=' expression { $$ = ($1 == $4); } + | expression '!' '=' expression { $$ = ($1 == $4); } + | 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 %u / %u\n", $1, $3); + YYABORT; + }; + $$ = $1 / $3; + } + | '-' number { $$ = -$2; } + | '*' expression { $$ = vaddr_read($2, WORD_BYTES); } + | '(' expression ')' { $$ = $2; } + +number + : REGISTER + | 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/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