Compare commits
5 commits
6ab5d4c156
...
29a9850210
Author | SHA1 | Date | |
---|---|---|---|
29a9850210 | |||
955f1f2d79 | |||
f38674ce79 | |||
7f0d1ba75a | |||
a54c0d6480 |
52 changed files with 1188 additions and 1120 deletions
2
.gitignore
vendored
2
.gitignore
vendored
|
@ -1,4 +1,5 @@
|
||||||
!*/
|
!*/
|
||||||
|
difftest/
|
||||||
!/nemu/*
|
!/nemu/*
|
||||||
!/nexus-am/*
|
!/nexus-am/*
|
||||||
!/nanos-lite/*
|
!/nanos-lite/*
|
||||||
|
@ -13,3 +14,4 @@
|
||||||
**/.cache
|
**/.cache
|
||||||
**/result
|
**/result
|
||||||
/.pre-commit-config.yaml
|
/.pre-commit-config.yaml
|
||||||
|
**/.vscode/
|
||||||
|
|
1
.gitmodules
vendored
1
.gitmodules
vendored
|
@ -1,3 +1,4 @@
|
||||||
[submodule "am-kernels"]
|
[submodule "am-kernels"]
|
||||||
path = am-kernels
|
path = am-kernels
|
||||||
url = https://git.xinyang.life/xin/am-kernels.git
|
url = https://git.xinyang.life/xin/am-kernels.git
|
||||||
|
branch = dev
|
||||||
|
|
2
abstract-machine/.gitignore
vendored
2
abstract-machine/.gitignore
vendored
|
@ -2,5 +2,7 @@
|
||||||
**/build/
|
**/build/
|
||||||
**/.envrc
|
**/.envrc
|
||||||
**/.cache
|
**/.cache
|
||||||
|
out/
|
||||||
.vscode
|
.vscode
|
||||||
compile_commands.json
|
compile_commands.json
|
||||||
|
cmakeUserh
|
||||||
|
|
|
@ -8,80 +8,118 @@ set(CMAKE_CXX_STANDARD 11)
|
||||||
include(CMakeDependentOption)
|
include(CMakeDependentOption)
|
||||||
include(CMakePackageConfigHelpers) # Used to find libcheck
|
include(CMakePackageConfigHelpers) # Used to find libcheck
|
||||||
include(CTest)
|
include(CTest)
|
||||||
|
include(GNUInstallDirs)
|
||||||
|
|
||||||
# -- General options
|
# -- General options
|
||||||
set(ISA CACHE STRING "Target ISA")
|
set(ISA CACHE STRING "Target ISA")
|
||||||
set_property(CACHE ISA PROPERTY STRINGS "riscv" "x86" "x86_64" "native")
|
set_property(CACHE ISA PROPERTY STRINGS "riscv" "x86" "x86_64" "native")
|
||||||
string(TOUPPER ${ISA} ISA_UPPER)
|
string(TOUPPER ${ISA} ISA_UPPER)
|
||||||
|
|
||||||
cmake_dependent_option(
|
cmake_dependent_option(__PLATFORM_NEMU__ "Run on NEMU" ON
|
||||||
__PLATFORM_NEMU__ "Run on NEMU"
|
"ISA MATCHES \"(riscv | x86)\"" OFF)
|
||||||
ON "ISA MATCHES \"(riscv | x86)\"" OFF)
|
cmake_dependent_option(__PLATFORM_NPC__ "Run on NPC" ON "ISA MATCHES riscv" OFF)
|
||||||
cmake_dependent_option(
|
cmake_dependent_option(__PLATFORM_NATIVE__ "Run on native" ON
|
||||||
__PLATFORM_NATIVE__ "Run on native"
|
"ISA MATCHES native" OFF)
|
||||||
ON "ISA MATCHES native" OFF)
|
|
||||||
|
|
||||||
# -- Set PLATFORM according to options
|
# -- 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)
|
get_cmake_property(CACHE_VARS CACHE_VARIABLES)
|
||||||
|
|
||||||
message(STATUS "ISA: ${ISA}")
|
message(STATUS "ISA: ${ISA}")
|
||||||
foreach(VAR IN LISTS CACHE_VARS)
|
foreach(VAR IN LISTS CACHE_VARS)
|
||||||
if(VAR MATCHES ${MATCH_PLATFORM_PATTERN})
|
if(VAR MATCHES ${MATCH_PLATFORM_PATTERN})
|
||||||
# Retrieve the value of the cache variable
|
# Retrieve the value of the cache variable
|
||||||
get_property(VAR_VALUE CACHE ${VAR} PROPERTY VALUE)
|
get_property(
|
||||||
|
VAR_VALUE
|
||||||
|
CACHE ${VAR}
|
||||||
|
PROPERTY VALUE)
|
||||||
set(PLATFORM_UPPER ${CMAKE_MATCH_1})
|
set(PLATFORM_UPPER ${CMAKE_MATCH_1})
|
||||||
string(TOLOWER ${PLATFORM_UPPER} PLATFORM)
|
string(TOLOWER ${PLATFORM_UPPER} PLATFORM)
|
||||||
|
list(APPEND PLATFORMS ${PLATFORM})
|
||||||
message(STATUS "Variable: ${VAR}=${VAR_VALUE}, Platform: ${PLATFORM}")
|
message(STATUS "Variable: ${VAR}=${VAR_VALUE}, Platform: ${PLATFORM}")
|
||||||
endif()
|
endif()
|
||||||
endforeach()
|
endforeach()
|
||||||
|
|
||||||
if(${PLATFORM} MATCHES "native")
|
if((NOT PLATFORM) AND (NOT ISA MATCHES native))
|
||||||
set(ARCH "native")
|
message(FATAL_ERROR "Platform not given!")
|
||||||
else()
|
|
||||||
set(ARCH ${ISA}-${PLATFORM})
|
|
||||||
endif()
|
endif()
|
||||||
string(TOUPPER ${ARCH} ARCH_UPPER)
|
|
||||||
|
set(SUPPORTED_ARCH "riscv-nemu" "riscv-npc" "native")
|
||||||
|
foreach(PLATFORM IN LISTS PLATFORMS)
|
||||||
|
if(${ISA} MATCHES "native")
|
||||||
|
set(ARCH "native")
|
||||||
|
else()
|
||||||
|
set(ARCH ${ISA}-${PLATFORM})
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(NOT ARCH IN_LIST SUPPORTED_ARCH)
|
||||||
|
message(
|
||||||
|
FATAL_ERROR
|
||||||
|
"Given ISA-PLATFORM (${ISA}-${PLATFORM}) does not match one of the following: ${SUPPORTED_ARCH}"
|
||||||
|
)
|
||||||
|
endif()
|
||||||
|
endforeach()
|
||||||
|
|
||||||
# -- Target specific options
|
# -- Target specific options
|
||||||
cmake_dependent_option(
|
cmake_dependent_option(NATIVE_USE_KLIB "Use Klib even if on native" ON
|
||||||
NATIVE_USE_KLIB "Use Klib even if on native"
|
"NOT __ISA_NATIVE__" OFF)
|
||||||
ON "NOT __ISA_NATIVE__" OFF)
|
|
||||||
|
|
||||||
# -- Add compile definitions based on options
|
# -- Add compile definitions based on options
|
||||||
add_compile_definitions(
|
|
||||||
$<MAKE_C_IDENTIFIER:__ARCH_${ARCH_UPPER}__>
|
|
||||||
__ISA_${ISA_UPPER}__
|
|
||||||
__PLATFORM_${PLATFORM_UPPER}__
|
|
||||||
)
|
|
||||||
|
|
||||||
add_compile_definitions(
|
|
||||||
$<$<BOOL:${NATIVE_USE_KLIB}>:__NATIVE_USE_KLIB__>
|
|
||||||
)
|
|
||||||
|
|
||||||
# -- Required compiler flags
|
|
||||||
add_compile_options(
|
|
||||||
# -Werror
|
|
||||||
-Wno-main
|
|
||||||
-fno-asynchronous-unwind-tables
|
|
||||||
-fno-builtin
|
|
||||||
-fno-stack-protector
|
|
||||||
-U_FORTIFY_SOURCE
|
|
||||||
$<$<COMPILE_LANGUAGE:CXX>:-fno-exceptions>
|
|
||||||
$<$<COMPILE_LANGUAGE:CXX>:-ffreestanding>
|
|
||||||
$<$<COMPILE_LANGUAGE:CXX>:-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")
|
list(APPEND CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake")
|
||||||
|
|
||||||
add_compile_options(-march=rv32if -mabi=ilp32)
|
# NOTE: klib and am include header files in each other, so we need to create
|
||||||
add_link_options(-march=rv32if -mabi=ilp32)
|
# interface libraries for correct dependency
|
||||||
|
add_library(am_interface INTERFACE)
|
||||||
|
target_include_directories(
|
||||||
|
am_interface
|
||||||
|
INTERFACE $<BUILD_INTERFACE:${CMAKE_SOURCE_DIR}/am/include>
|
||||||
|
$<BUILD_INTERFACE:${CMAKE_SOURCE_DIR}/am/src>
|
||||||
|
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>)
|
||||||
|
target_compile_definitions(am_interface INTERFACE ARCH_H=<arch/${ISA}.h>)
|
||||||
|
file(GLOB_RECURSE AM_HEADERS "${CMAKE_SOURCE_DIR}/am/include/*.h")
|
||||||
|
target_sources(
|
||||||
|
am_interface
|
||||||
|
PUBLIC FILE_SET
|
||||||
|
am_headers
|
||||||
|
TYPE
|
||||||
|
HEADERS
|
||||||
|
BASE_DIRS
|
||||||
|
${CMAKE_SOURCE_DIR}/am/include
|
||||||
|
FILES
|
||||||
|
${AM_HEADERS})
|
||||||
|
|
||||||
|
add_library(klib_interface INTERFACE)
|
||||||
|
target_include_directories(
|
||||||
|
klib_interface
|
||||||
|
INTERFACE $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/klib/include>
|
||||||
|
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>)
|
||||||
|
file(GLOB_RECURSE KLIB_HEADERS "${CMAKE_SOURCE_DIR}/klib/include/*.h")
|
||||||
|
target_sources(
|
||||||
|
klib_interface
|
||||||
|
PUBLIC FILE_SET
|
||||||
|
klib_headers
|
||||||
|
TYPE
|
||||||
|
HEADERS
|
||||||
|
BASE_DIRS
|
||||||
|
${CMAKE_SOURCE_DIR}/klib/include
|
||||||
|
FILES
|
||||||
|
${KLIB_HEADERS})
|
||||||
|
|
||||||
|
install(
|
||||||
|
TARGETS am_interface klib_interface
|
||||||
|
EXPORT interfaceTargets
|
||||||
|
FILE_SET klib_headers FILE_SET am_headers
|
||||||
|
INCLUDES
|
||||||
|
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})
|
||||||
|
|
||||||
|
install(
|
||||||
|
EXPORT interfaceTargets
|
||||||
|
FILE interfaceTargets.cmake
|
||||||
|
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake)
|
||||||
|
|
||||||
add_subdirectory(klib)
|
add_subdirectory(klib)
|
||||||
add_subdirectory(am)
|
add_subdirectory(am)
|
||||||
|
|
||||||
|
# -- Test depends on klib and am should be added last.
|
||||||
|
add_subdirectory(klib/tests)
|
||||||
|
|
|
@ -7,21 +7,21 @@
|
||||||
"generator": "Unix Makefiles",
|
"generator": "Unix Makefiles",
|
||||||
"binaryDir": "${sourceDir}/out/build/${presetName}",
|
"binaryDir": "${sourceDir}/out/build/${presetName}",
|
||||||
"cacheVariables": {
|
"cacheVariables": {
|
||||||
"CMAKE_BUILD_TYPE": "Debug",
|
"CMAKE_BUILD_TYPE": "RelWithDebInfo",
|
||||||
"ISA": "native",
|
"ISA": "native",
|
||||||
"__PLATFORM_NATIVE__": true,
|
"__PLATFORM_NATIVE__": true,
|
||||||
"NATIVE_USE_KLIB": true
|
"NATIVE_USE_KLIB": true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "riscv-nemu",
|
"name": "riscv",
|
||||||
"displayName": "Riscv32 NEMU",
|
"displayName": "RV32 all platform",
|
||||||
"generator": "Unix Makefiles",
|
"generator": "Unix Makefiles",
|
||||||
"binaryDir": "${sourceDir}/out/build/${presetName}",
|
"binaryDir": "${sourceDir}/out/build/${presetName}",
|
||||||
"installDir": "/home/xin/repo/ysyx-workbench/abstract-machine/out/install",
|
|
||||||
"cacheVariables": {
|
"cacheVariables": {
|
||||||
"CMAKE_BUILD_TYPE": "Debug",
|
"CMAKE_BUILD_TYPE": "RelWithDebInfo",
|
||||||
"ISA": "riscv",
|
"ISA": "riscv",
|
||||||
|
"__PLATFORM_NPC__": true,
|
||||||
"__PLATFORM_NEMU__": true
|
"__PLATFORM_NEMU__": true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
15
abstract-machine/CMakeUserPresets.json
Normal file
15
abstract-machine/CMakeUserPresets.json
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
{
|
||||||
|
"version": 6,
|
||||||
|
"configurePresets": [
|
||||||
|
{
|
||||||
|
"name": "Native install",
|
||||||
|
"inherits": "native",
|
||||||
|
"installDir": "/home/xin/repo/ysyx-workbench/abstract-machine/out/install"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "RISCV install",
|
||||||
|
"inherits": "riscv",
|
||||||
|
"installDir": "/home/xin/repo/ysyx-workbench/abstract-machine/out/install"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
|
@ -1,10 +1,26 @@
|
||||||
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/include)
|
|
||||||
|
|
||||||
add_library(am_interface INTERFACE)
|
|
||||||
target_include_directories(am_interface INTERFACE
|
|
||||||
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
|
|
||||||
$<INSTALL_INTERFACE:include/abstract-machine>)
|
|
||||||
|
|
||||||
add_subdirectory(src)
|
add_subdirectory(src)
|
||||||
|
|
||||||
install(DIRECTORY include/ DESTINATION include/abstract-machine)
|
foreach(PLATFORM IN LISTS PLATFORMS)
|
||||||
|
if(ISA MATCHES "native")
|
||||||
|
set(ARCH "native")
|
||||||
|
else()
|
||||||
|
set(ARCH ${ISA}-${PLATFORM})
|
||||||
|
endif()
|
||||||
|
install(
|
||||||
|
TARGETS am-${ARCH}
|
||||||
|
EXPORT amTargets-${ARCH}
|
||||||
|
LIBRARY DESTINATION lib)
|
||||||
|
|
||||||
|
install(
|
||||||
|
EXPORT amTargets-${ARCH}
|
||||||
|
FILE amTargets.cmake
|
||||||
|
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/am-${ARCH})
|
||||||
|
|
||||||
|
configure_package_config_file(
|
||||||
|
${CMAKE_SOURCE_DIR}/cmake/am-config.cmake.in
|
||||||
|
${CMAKE_CURRENT_BINARY_DIR}/am-${ARCH}-config.cmake
|
||||||
|
INSTALL_DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/am-${ARCH})
|
||||||
|
|
||||||
|
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/am-${ARCH}-config.cmake
|
||||||
|
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/am-${ARCH})
|
||||||
|
endforeach()
|
||||||
|
|
|
@ -1,53 +1 @@
|
||||||
if(ISA MATCHES "native")
|
add_subdirectory(${ISA})
|
||||||
set(SOURCEDIR "./${PLATFORM}")
|
|
||||||
else()
|
|
||||||
set(SOURCEDIR "./${ISA}/${PLATFORM}")
|
|
||||||
endif()
|
|
||||||
|
|
||||||
add_subdirectory(${SOURCEDIR})
|
|
||||||
|
|
||||||
target_include_directories(am-${ARCH}
|
|
||||||
PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}
|
|
||||||
PUBLIC
|
|
||||||
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/../include>
|
|
||||||
$<INSTALL_INTERFACE:include/abstract-machine>)
|
|
||||||
target_link_libraries(am-${ARCH}
|
|
||||||
PUBLIC klib_interface
|
|
||||||
INTERFACE m)
|
|
||||||
|
|
||||||
# TODO: Check
|
|
||||||
target_link_options(am-${ARCH} INTERFACE
|
|
||||||
$<BUILD_INTERFACE:-T${CMAKE_SOURCE_DIR}/scripts/${LINKER_SCRIPT}>
|
|
||||||
$<INSTALL_INTERFACE:-T${CMAKE_INSTALL_LIBDIR}/cmake/am-${ARCH}/${LINKER_SCRIPT}>)
|
|
||||||
|
|
||||||
# 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
|
|
||||||
$<$<COMPILE_LANGUAGE:CXX>:-fno-exceptions>
|
|
||||||
$<$<COMPILE_LANGUAGE:CXX>:-ffreestanding>
|
|
||||||
$<$<COMPILE_LANGUAGE:CXX>:-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})
|
|
||||||
|
|
|
@ -1,6 +1,3 @@
|
||||||
include(CheckPIESupported)
|
|
||||||
check_pie_supported()
|
|
||||||
|
|
||||||
set(SOURCES
|
set(SOURCES
|
||||||
trap.S
|
trap.S
|
||||||
cte.c
|
cte.c
|
||||||
|
@ -13,14 +10,16 @@ set(SOURCES
|
||||||
ioe/disk.c
|
ioe/disk.c
|
||||||
ioe/gpu.c
|
ioe/gpu.c
|
||||||
ioe/input.c
|
ioe/input.c
|
||||||
ioe/timer.c
|
ioe/timer.c)
|
||||||
)
|
|
||||||
add_library(am-native ${SOURCES})
|
add_library(am-native ${SOURCES})
|
||||||
|
|
||||||
# FIXME: get free(): invalid address when user program compiled without pie
|
# FIXME: get free(): invalid address when user program compiled without pie
|
||||||
set_target_properties(am-native PROPERTIES
|
set_target_properties(
|
||||||
POSITION_INDEPENDENT_CODE TRUE
|
am-native PROPERTIES POSITION_INDEPENDENT_CODE TRUE
|
||||||
INTERFACE_POSITION_INDEPENDENT_CODE TRUE)
|
INTERFACE_POSITION_INDEPENDENT_CODE TRUE)
|
||||||
|
|
||||||
find_package(SDL2 REQUIRED)
|
find_package(SDL2 REQUIRED)
|
||||||
target_link_libraries(am-${ARCH} PUBLIC SDL2::SDL2)
|
target_link_libraries(
|
||||||
|
am-native
|
||||||
|
PUBLIC SDL2::SDL2
|
||||||
|
PRIVATE klib_interface am_interface)
|
||||||
|
|
|
@ -1,11 +1,10 @@
|
||||||
#include <am.h>
|
#include <am.h>
|
||||||
#include <nemu.h>
|
#include <nemu.h>
|
||||||
|
|
||||||
void __am_timer_init() {
|
void __am_timer_init() {}
|
||||||
}
|
|
||||||
|
|
||||||
void __am_timer_uptime(AM_TIMER_UPTIME_T *uptime) {
|
void __am_timer_uptime(AM_TIMER_UPTIME_T *uptime) {
|
||||||
uptime->us = 0;
|
uptime->us = ((uint64_t)inl(RTC_ADDR + 4) << 32) + inl(RTC_ADDR);
|
||||||
}
|
}
|
||||||
|
|
||||||
void __am_timer_rtc(AM_TIMER_RTC_T *rtc) {
|
void __am_timer_rtc(AM_TIMER_RTC_T *rtc) {
|
||||||
|
|
|
@ -6,19 +6,18 @@ int main(const char *args);
|
||||||
|
|
||||||
Area heap = RANGE(&_heap_start, PMEM_END);
|
Area heap = RANGE(&_heap_start, PMEM_END);
|
||||||
#ifndef MAINARGS
|
#ifndef MAINARGS
|
||||||
#define MAINARGS ""
|
#define MAINARGS "5"
|
||||||
#endif
|
#endif
|
||||||
static const char mainargs[] = MAINARGS;
|
static const char mainargs[] = MAINARGS;
|
||||||
|
|
||||||
void putch(char ch) {
|
void putch(char ch) { outb(SERIAL_PORT, ch); }
|
||||||
outb(SERIAL_PORT, ch);
|
|
||||||
}
|
|
||||||
|
|
||||||
void halt(int code) {
|
void halt(int code) {
|
||||||
nemu_trap(code);
|
nemu_trap(code);
|
||||||
|
|
||||||
// should not reach here
|
// should not reach here
|
||||||
while (1);
|
while (1)
|
||||||
|
;
|
||||||
}
|
}
|
||||||
|
|
||||||
void _trm_init() {
|
void _trm_init() {
|
||||||
|
|
9
abstract-machine/am/src/riscv/CMakeLists.txt
Normal file
9
abstract-machine/am/src/riscv/CMakeLists.txt
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
foreach(PLATFORM IN LISTS PLATFORMS)
|
||||||
|
string(TOUPPER ${ARCH} ARCH_UPPER)
|
||||||
|
set(AM_COMMON_COMPILE_DEF
|
||||||
|
# -- Arch related
|
||||||
|
$<MAKE_C_IDENTIFIER:__ARCH_${ARCH_UPPER}__> __ISA_${ISA_UPPER}__
|
||||||
|
__PLATFORM_${PLATFORM_UPPER}__
|
||||||
|
$<$<BOOL:${NATIVE_USE_KLIB}>:__NATIVE_USE_KLIB__>)
|
||||||
|
add_subdirectory(${PLATFORM})
|
||||||
|
endforeach()
|
|
@ -1,34 +1,41 @@
|
||||||
include(nemu-settings)
|
include(nemu-settings)
|
||||||
include(riscv-settings)
|
include(riscv-settings)
|
||||||
|
|
||||||
add_library(am-${ISA}-nemu
|
add_library(am-riscv-nemu cte.c start.S trap.S vme.c ${NEMU_SOURCES})
|
||||||
cte.c
|
|
||||||
start.S
|
|
||||||
trap.S
|
|
||||||
vme.c
|
|
||||||
${NEMU_SOURCES}
|
|
||||||
)
|
|
||||||
|
|
||||||
target_compile_options(am-${ISA}-nemu PRIVATE
|
target_compile_options(am-riscv-nemu PRIVATE ${NEMU_COMPILE_OPTIONS}
|
||||||
${NEMU_COMPILE_OPTIONS}
|
|
||||||
${RISCV_COMPILE_OPTIONS})
|
${RISCV_COMPILE_OPTIONS})
|
||||||
target_link_options(am-${ISA}-nemu PRIVATE
|
|
||||||
${NEMU_LINK_OPITIONS}
|
target_link_options(am-riscv-nemu PRIVATE ${NEMU_LINK_OPITIONS}
|
||||||
${RISCV_LINK_OPTIONS})
|
${RISCV_LINK_OPTIONS})
|
||||||
target_include_directories(am-${ISA}-nemu PRIVATE
|
|
||||||
${NEMU_INCLUDE_DIRECTORIES})
|
target_include_directories(am-riscv-nemu PRIVATE ${NEMU_INCLUDE_DIRECTORIES})
|
||||||
target_link_options(am-${ISA}-nemu INTERFACE
|
|
||||||
|
target_link_options(
|
||||||
|
am-riscv-nemu
|
||||||
|
INTERFACE
|
||||||
LINKER:--defsym=_pmem_start=0x80000000
|
LINKER:--defsym=_pmem_start=0x80000000
|
||||||
LINKER:--defsym=_entry_offset=0x0
|
LINKER:--defsym=_entry_offset=0x0
|
||||||
LINKER:--gc-sections
|
LINKER:--gc-sections
|
||||||
LINKER:-e _start
|
LINKER:-e
|
||||||
|
_start
|
||||||
-nostartfiles)
|
-nostartfiles)
|
||||||
|
|
||||||
target_compile_definitions(am-${ISA}-nemu PUBLIC
|
target_link_options(
|
||||||
ARCH_H="arch/riscv.h")
|
am-riscv-nemu INTERFACE
|
||||||
target_compile_definitions(am-${ISA}-nemu PRIVATE
|
$<BUILD_INTERFACE:-T${CMAKE_SOURCE_DIR}/scripts/linker.ld>
|
||||||
ISA_H="riscv/riscv.h")
|
$<INSTALL_INTERFACE:-T${CMAKE_INSTALL_FULL_DATADIR}/linker.ld>)
|
||||||
|
|
||||||
set_target_properties(am-${ISA}-nemu PROPERTIES
|
target_link_libraries(
|
||||||
POSITION_INDEPENDENT_CODE OFF
|
am-riscv-nemu
|
||||||
|
PUBLIC am_interface klib_interface
|
||||||
|
INTERFACE m)
|
||||||
|
|
||||||
|
target_compile_definitions(am-riscv-nemu PRIVATE ISA_H=<riscv/riscv.h>)
|
||||||
|
|
||||||
|
set_target_properties(
|
||||||
|
am-riscv-nemu PROPERTIES POSITION_INDEPENDENT_CODE OFF
|
||||||
INTERFACE_POSITION_INDEPENDENT_CODE OFF)
|
INTERFACE_POSITION_INDEPENDENT_CODE OFF)
|
||||||
|
|
||||||
|
install(FILES ${CMAKE_SOURCE_DIR}/scripts/linker.ld
|
||||||
|
DESTINATION ${CMAKE_INSTALL_DATADIR})
|
||||||
|
|
46
abstract-machine/am/src/riscv/npc/CMakeLists.txt
Normal file
46
abstract-machine/am/src/riscv/npc/CMakeLists.txt
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
include(riscv-settings)
|
||||||
|
|
||||||
|
add_subdirectory(libgcc)
|
||||||
|
|
||||||
|
add_library(
|
||||||
|
am-riscv-npc
|
||||||
|
cte.c
|
||||||
|
input.c
|
||||||
|
ioe.c
|
||||||
|
mpe.c
|
||||||
|
start.S
|
||||||
|
timer.c
|
||||||
|
trap.S
|
||||||
|
trm.c
|
||||||
|
vme.c)
|
||||||
|
|
||||||
|
target_link_libraries(
|
||||||
|
am-riscv-npc
|
||||||
|
PRIVATE npcgcc
|
||||||
|
PUBLIC am_interface klib_interface)
|
||||||
|
|
||||||
|
target_link_options(
|
||||||
|
am-riscv-npc INTERFACE
|
||||||
|
$<BUILD_INTERFACE:-T${CMAKE_SOURCE_DIR}/scripts/linker.ld>
|
||||||
|
$<INSTALL_INTERFACE:-T${CMAKE_INSTALL_FULL_DATADIR}/linker.ld>)
|
||||||
|
|
||||||
|
target_link_options(
|
||||||
|
am-riscv-npc
|
||||||
|
INTERFACE
|
||||||
|
LINKER:--defsym=_pmem_start=0x80000000
|
||||||
|
LINKER:--defsym=_entry_offset=0x0
|
||||||
|
LINKER:--gc-sections
|
||||||
|
LINKER:-e
|
||||||
|
_start
|
||||||
|
-nostartfiles)
|
||||||
|
|
||||||
|
target_link_options(
|
||||||
|
am-riscv-npc INTERFACE
|
||||||
|
$<BUILD_INTERFACE:-T${CMAKE_SOURCE_DIR}/scripts/linker.ld>
|
||||||
|
$<INSTALL_INTERFACE:-T${CMAKE_INSTALL_FULL_DATADIR}/linker.ld>)
|
||||||
|
|
||||||
|
target_compile_definitions(am-riscv-npc PUBLIC ${AM_COMMON_COMPILE_DEF}
|
||||||
|
ARCH_H=<arch/riscv.h>)
|
||||||
|
|
||||||
|
install(FILES ${CMAKE_SOURCE_DIR}/scripts/linker.ld
|
||||||
|
DESTINATION ${CMAKE_INSTALL_DATADIR})
|
|
@ -7,13 +7,18 @@ void __am_timer_rtc(AM_TIMER_RTC_T *);
|
||||||
void __am_timer_uptime(AM_TIMER_UPTIME_T *);
|
void __am_timer_uptime(AM_TIMER_UPTIME_T *);
|
||||||
void __am_input_keybrd(AM_INPUT_KEYBRD_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_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_input_config(AM_INPUT_CONFIG_T *cfg) { cfg->present = true; }
|
||||||
|
static void __am_uart_config(AM_UART_CONFIG_T *cfg) { cfg->present = false; }
|
||||||
|
|
||||||
typedef void (*handler_t)(void *buf);
|
typedef void (*handler_t)(void *buf);
|
||||||
static void *lut[128] = {
|
static void *lut[128] = {
|
||||||
|
[AM_UART_CONFIG] = __am_uart_config,
|
||||||
[AM_TIMER_CONFIG] = __am_timer_config,
|
[AM_TIMER_CONFIG] = __am_timer_config,
|
||||||
[AM_TIMER_RTC ] = __am_timer_rtc,
|
[AM_TIMER_RTC] = __am_timer_rtc,
|
||||||
[AM_TIMER_UPTIME] = __am_timer_uptime,
|
[AM_TIMER_UPTIME] = __am_timer_uptime,
|
||||||
[AM_INPUT_CONFIG] = __am_input_config,
|
[AM_INPUT_CONFIG] = __am_input_config,
|
||||||
[AM_INPUT_KEYBRD] = __am_input_keybrd,
|
[AM_INPUT_KEYBRD] = __am_input_keybrd,
|
||||||
|
@ -23,10 +28,11 @@ static void fail(void *buf) { panic("access nonexist register"); }
|
||||||
|
|
||||||
bool ioe_init() {
|
bool ioe_init() {
|
||||||
for (int i = 0; i < LENGTH(lut); i++)
|
for (int i = 0; i < LENGTH(lut); i++)
|
||||||
if (!lut[i]) lut[i] = fail;
|
if (!lut[i])
|
||||||
|
lut[i] = fail;
|
||||||
__am_timer_init();
|
__am_timer_init();
|
||||||
return true;
|
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); }
|
void ioe_write(int reg, void *buf) { ((handler_t)lut[reg])(buf); }
|
||||||
|
|
9
abstract-machine/am/src/riscv/npc/libgcc/CMakeLists.txt
Normal file
9
abstract-machine/am/src/riscv/npc/libgcc/CMakeLists.txt
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
add_library(npcgcc ashldi3.c div.S muldi3.S multi3.c unused.c)
|
||||||
|
|
||||||
|
target_link_libraries(npcgcc PRIVATE klib_interface am_interface)
|
||||||
|
target_link_options(npcgcc INTERFACE -nolibc -nostdlib)
|
||||||
|
|
||||||
|
install(
|
||||||
|
TARGETS npcgcc
|
||||||
|
EXPORT amTargets-riscv-npc
|
||||||
|
LIBRARY DESTINATION lib)
|
6
abstract-machine/am/src/riscv/npc/npc.h
Normal file
6
abstract-machine/am/src/riscv/npc/npc.h
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
#ifndef _AM_NPC_NPC_H_
|
||||||
|
#define _AM_NPC_NPC_H_
|
||||||
|
#define SERIAL_PORT 0x10000000
|
||||||
|
#define RTC_ADDR 0x10001000
|
||||||
|
|
||||||
|
#endif
|
|
@ -1,10 +1,11 @@
|
||||||
|
#include "npc.h"
|
||||||
#include <am.h>
|
#include <am.h>
|
||||||
|
#include <riscv/riscv.h>
|
||||||
|
|
||||||
void __am_timer_init() {
|
void __am_timer_init() {}
|
||||||
}
|
|
||||||
|
|
||||||
void __am_timer_uptime(AM_TIMER_UPTIME_T *uptime) {
|
void __am_timer_uptime(AM_TIMER_UPTIME_T *uptime) {
|
||||||
uptime->us = 0;
|
uptime->us = ((uint64_t)inl(RTC_ADDR + 4) << 32) + inl(RTC_ADDR);
|
||||||
}
|
}
|
||||||
|
|
||||||
void __am_timer_rtc(AM_TIMER_RTC_T *rtc) {
|
void __am_timer_rtc(AM_TIMER_RTC_T *rtc) {
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
|
#include "npc.h"
|
||||||
#include <am.h>
|
#include <am.h>
|
||||||
#include <klib-macros.h>
|
#include <klib-macros.h>
|
||||||
|
#include <riscv/riscv.h>
|
||||||
|
|
||||||
extern char _heap_start;
|
extern char _heap_start;
|
||||||
int main(const char *args);
|
int main(const char *args);
|
||||||
|
@ -10,15 +12,16 @@ extern char _pmem_start;
|
||||||
|
|
||||||
Area heap = RANGE(&_heap_start, PMEM_END);
|
Area heap = RANGE(&_heap_start, PMEM_END);
|
||||||
#ifndef MAINARGS
|
#ifndef MAINARGS
|
||||||
#define MAINARGS ""
|
#define MAINARGS "3"
|
||||||
#endif
|
#endif
|
||||||
static const char mainargs[] = MAINARGS;
|
static const char mainargs[] = MAINARGS;
|
||||||
|
|
||||||
void putch(char ch) {
|
void putch(char ch) { outb(SERIAL_PORT, ch); }
|
||||||
}
|
|
||||||
|
|
||||||
void halt(int code) {
|
void halt(int code) {
|
||||||
while (1);
|
asm volatile("mv a0, %0; ebreak" : : "r"(code));
|
||||||
|
while (1)
|
||||||
|
;
|
||||||
}
|
}
|
||||||
|
|
||||||
void _trm_init() {
|
void _trm_init() {
|
||||||
|
|
|
@ -6,4 +6,5 @@ find_dependency(SDL2 REQUIRED)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
# Include the targets file
|
# Include the targets file
|
||||||
|
include("${CMAKE_CURRENT_LIST_DIR}/../interfaceTargets.cmake")
|
||||||
include("${CMAKE_CURRENT_LIST_DIR}/amTargets.cmake")
|
include("${CMAKE_CURRENT_LIST_DIR}/amTargets.cmake")
|
||||||
|
|
|
@ -3,18 +3,17 @@
|
||||||
cmake,
|
cmake,
|
||||||
SDL2,
|
SDL2,
|
||||||
isa ? "native",
|
isa ? "native",
|
||||||
platform ? "NEMU"
|
platform ? [ ]
|
||||||
}:
|
}:
|
||||||
stdenv.mkDerivation {
|
stdenv.mkDerivation {
|
||||||
pname = "abstract-machine";
|
pname = "abstract-machine";
|
||||||
version = "2024.02.18";
|
version = "2024.06.01";
|
||||||
|
|
||||||
src = ./.;
|
src = ./.;
|
||||||
|
|
||||||
cmakeFlags = [
|
cmakeFlags = [
|
||||||
(lib.cmakeFeature "ISA" isa)
|
(lib.cmakeFeature "ISA" isa)
|
||||||
(lib.cmakeBool "__PLATFORM_${lib.strings.toUpper platform}__" true)
|
] ++ map (p: (lib.cmakeBool "__PLATFORM_${lib.strings.toUpper p}__" true)) platform;
|
||||||
];
|
|
||||||
|
|
||||||
nativeBuildInputs = [
|
nativeBuildInputs = [
|
||||||
cmake
|
cmake
|
||||||
|
@ -22,5 +21,7 @@ stdenv.mkDerivation {
|
||||||
|
|
||||||
buildInputs = [
|
buildInputs = [
|
||||||
|
|
||||||
] ++ (if platform=="native" then [ SDL2 ] else [ ]);
|
] ++ (if isa=="native" then [ SDL2 ] else [ ]);
|
||||||
|
|
||||||
|
doCheck = true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,12 +1,4 @@
|
||||||
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/include)
|
install(DIRECTORY include/
|
||||||
|
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/abstract-machine)
|
||||||
add_library(klib_interface INTERFACE)
|
|
||||||
target_include_directories(klib_interface
|
|
||||||
INTERFACE
|
|
||||||
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
|
|
||||||
$<INSTALL_INTERFACE:include/abstract-machine>)
|
|
||||||
|
|
||||||
add_subdirectory(src)
|
add_subdirectory(src)
|
||||||
# add_subdirectory(tests)
|
|
||||||
|
|
||||||
install(DIRECTORY include/ DESTINATION include/abstract-machine)
|
|
||||||
|
|
|
@ -1,33 +1,30 @@
|
||||||
# find_package(FLEX)
|
# find_package(FLEX) find_package(BISON)
|
||||||
# find_package(BISON)
|
|
||||||
|
|
||||||
# FLEX_TARGET(fmt_scanner fmt_scanner.l fmt_scanner.c)
|
# FLEX_TARGET(fmt_scanner fmt_scanner.l fmt_scanner.c)
|
||||||
|
|
||||||
set(SOURCES
|
set(SOURCES cpp.c int64.c stdio.c stdlib.c string.c
|
||||||
cpp.c
|
|
||||||
int64.c
|
|
||||||
stdio.c
|
|
||||||
stdlib.c
|
|
||||||
string.c
|
|
||||||
# ${FLEX_fmt_scanner_OUTPUTS}
|
# ${FLEX_fmt_scanner_OUTPUTS}
|
||||||
)
|
)
|
||||||
|
|
||||||
add_library(klib ${SOURCES})
|
add_library(klib ${SOURCES})
|
||||||
target_include_directories(klib PUBLIC $<TARGET_PROPERTY:am_interface,INTERFACE_INCLUDE_DIRECTORIES>)
|
target_link_libraries(klib PUBLIC am_interface klib_interface)
|
||||||
target_compile_definitions(klib PUBLIC $<TARGET_PROPERTY:am-${ARCH},INTERFACE_COMPILE_DEFINITIONS>)
|
target_compile_options(klib PUBLIC -fno-builtin)
|
||||||
|
target_link_options(klib PUBLIC -nostartfiles -nolibc)
|
||||||
|
|
||||||
install(TARGETS klib
|
install(
|
||||||
|
TARGETS klib
|
||||||
EXPORT klibTargets
|
EXPORT klibTargets
|
||||||
LIBRARY DESTINATION lib)
|
LIBRARY DESTINATION lib)
|
||||||
|
|
||||||
install(EXPORT klibTargets
|
install(
|
||||||
|
EXPORT klibTargets
|
||||||
FILE klibTargets.cmake
|
FILE klibTargets.cmake
|
||||||
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/klib)
|
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
|
${CMAKE_CURRENT_BINARY_DIR}/klib-config.cmake
|
||||||
INSTALL_DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/klib)
|
INSTALL_DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/klib)
|
||||||
|
|
||||||
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/klib-config.cmake
|
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/klib-config.cmake
|
||||||
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/klib)
|
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/klib)
|
||||||
|
|
||||||
|
|
|
@ -1,16 +1,91 @@
|
||||||
#include <am.h>
|
#include <am.h>
|
||||||
#include <klib.h>
|
|
||||||
#include <klib-macros.h>
|
#include <klib-macros.h>
|
||||||
|
#include <klib.h>
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
|
|
||||||
#if !defined(__ISA_NATIVE__) || defined(__NATIVE_USE_KLIB__)
|
#if !defined(__ISA_NATIVE__) || defined(__NATIVE_USE_KLIB__)
|
||||||
|
|
||||||
int vprintf(const char *fmt, va_list ap) {
|
void print_int(int num, int width, char pad) {
|
||||||
const char *p = fmt;
|
int reverse = 0;
|
||||||
while(*p != '\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);
|
putch(*p);
|
||||||
}
|
}
|
||||||
return 0;
|
p++;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int printf(const char *fmt, ...) {
|
int printf(const char *fmt, ...) {
|
||||||
|
@ -21,12 +96,103 @@ int printf(const char *fmt, ...) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int vsprintf(char *out, const char *fmt, va_list ap) {
|
void append_to_buffer(char **buf, int *pos, char c) { (*buf)[(*pos)++] = c; }
|
||||||
panic("Not implemented");
|
|
||||||
|
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 sprintf(char *out, const char *fmt, ...) {
|
int sprintf(char *out, const char *fmt, ...) {
|
||||||
panic("Not implemented");
|
va_list args;
|
||||||
|
va_start(args, fmt);
|
||||||
|
vsprintf(out, fmt, args);
|
||||||
|
va_end(args);
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int snprintf(char *out, size_t n, const char *fmt, ...) {
|
int snprintf(char *out, size_t n, const char *fmt, ...) {
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
#include <am.h>
|
#include <am.h>
|
||||||
#include <klib.h>
|
|
||||||
#include <klib-macros.h>
|
#include <klib-macros.h>
|
||||||
|
#include <klib.h>
|
||||||
|
|
||||||
#if !defined(__ISA_NATIVE__) || defined(__NATIVE_USE_KLIB__)
|
#if !defined(__ISA_NATIVE__) || defined(__NATIVE_USE_KLIB__)
|
||||||
static unsigned long int next = 1;
|
static unsigned long int next = 1;
|
||||||
|
@ -8,23 +8,21 @@ static unsigned long int next = 1;
|
||||||
int rand(void) {
|
int rand(void) {
|
||||||
// RAND_MAX assumed to be 32767
|
// RAND_MAX assumed to be 32767
|
||||||
next = next * 1103515245 + 12345;
|
next = next * 1103515245 + 12345;
|
||||||
return (unsigned int)(next/65536) % 32768;
|
return (unsigned int)(next / 65536) % 32768;
|
||||||
}
|
}
|
||||||
|
|
||||||
void srand(unsigned int seed) {
|
void srand(unsigned int seed) { next = seed; }
|
||||||
next = seed;
|
|
||||||
}
|
|
||||||
|
|
||||||
int abs(int x) {
|
int abs(int x) { return (x < 0 ? -x : x); }
|
||||||
return (x < 0 ? -x : x);
|
|
||||||
}
|
|
||||||
|
|
||||||
int atoi(const char* nptr) {
|
int atoi(const char *nptr) {
|
||||||
int x = 0;
|
int x = 0;
|
||||||
while (*nptr == ' ') { nptr ++; }
|
while (*nptr == ' ') {
|
||||||
|
nptr++;
|
||||||
|
}
|
||||||
while (*nptr >= '0' && *nptr <= '9') {
|
while (*nptr >= '0' && *nptr <= '9') {
|
||||||
x = x * 10 + *nptr - '0';
|
x = x * 10 + *nptr - '0';
|
||||||
nptr ++;
|
nptr++;
|
||||||
}
|
}
|
||||||
return x;
|
return x;
|
||||||
}
|
}
|
||||||
|
@ -33,13 +31,19 @@ void *malloc(size_t size) {
|
||||||
// On native, malloc() will be called during initializaion of C runtime.
|
// On native, malloc() will be called during initializaion of C runtime.
|
||||||
// Therefore do not call panic() here, else it will yield a dead recursion:
|
// Therefore do not call panic() here, else it will yield a dead recursion:
|
||||||
// panic() -> putchar() -> (glibc) -> malloc() -> panic()
|
// panic() -> putchar() -> (glibc) -> malloc() -> panic()
|
||||||
#if !(defined(__ISA_NATIVE__) && defined(__NATIVE_USE_KLIB__))
|
static void *addr = NULL;
|
||||||
panic("Not implemented");
|
void *ret = NULL;
|
||||||
#endif
|
if (addr == 0) {
|
||||||
return NULL;
|
addr = heap.start;
|
||||||
|
ret = addr;
|
||||||
|
} else {
|
||||||
|
panic_on(addr + size > heap.end, "Memory space not enough");
|
||||||
|
ret = addr;
|
||||||
|
addr += size;
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
void free(void *ptr) {
|
void free(void *ptr) {}
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -1,17 +1,11 @@
|
||||||
set(TEST_SOURCES
|
set(TEST_SOURCES stdio string)
|
||||||
stdio
|
|
||||||
string
|
|
||||||
)
|
|
||||||
|
|
||||||
foreach(TEST IN LISTS TEST_SOURCES)
|
foreach(TEST IN LISTS TEST_SOURCES)
|
||||||
add_executable(${TEST} ${TEST}.c)
|
|
||||||
target_link_libraries(${TEST} am-${ARCH} klib m)
|
|
||||||
target_include_directories(${TEST}
|
|
||||||
PRIVATE $<TARGET_PROPERTY:am_interface,INTERFACE_INCLUDE_DIRECTORIES>
|
|
||||||
PRIVATE $<TARGET_PROPERTY:klib_interface,INTERFACE_INCLUDE_DIRECTORIES>
|
|
||||||
)
|
|
||||||
# TODO: Run tests in other configurations
|
# TODO: Run tests in other configurations
|
||||||
if(__PLATFORM_NATIVE__)
|
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})
|
add_test(NAME ${TEST} COMMAND ${TEST})
|
||||||
endif()
|
endif()
|
||||||
endforeach()
|
endforeach()
|
||||||
|
|
Binary file not shown.
12
flake.nix
12
flake.nix
|
@ -42,6 +42,8 @@
|
||||||
src = ./.;
|
src = ./.;
|
||||||
hooks = {
|
hooks = {
|
||||||
trim-trailing-whitespace.enable = true;
|
trim-trailing-whitespace.enable = true;
|
||||||
|
end-of-file-fixer.enable = true;
|
||||||
|
cmake-format.enable = true;
|
||||||
clang-format = {
|
clang-format = {
|
||||||
enable = true;
|
enable = true;
|
||||||
types_or = pkgs.lib.mkForce [ "c" "c++" ];
|
types_or = pkgs.lib.mkForce [ "c" "c++" ];
|
||||||
|
@ -52,7 +54,8 @@
|
||||||
|
|
||||||
packages.nemu = pkgs.callPackage ./nemu { am-kernels = self.packages.${system}.am-kernels; };
|
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.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"; };
|
packages.abstract-machine = crossPkgs.callPackage ./abstract-machine { isa = "riscv"; platform = [ "nemu" "npc" ]; };
|
||||||
|
packages.abstract-machine-native = pkgs.callPackage ./abstract-machine { isa = "native"; };
|
||||||
|
|
||||||
packages.am-kernels = crossPkgs.stdenv.mkDerivation rec {
|
packages.am-kernels = crossPkgs.stdenv.mkDerivation rec {
|
||||||
pname = "am-kernels-cmake";
|
pname = "am-kernels-cmake";
|
||||||
|
@ -67,7 +70,6 @@
|
||||||
cmakeFlags = [
|
cmakeFlags = [
|
||||||
(pkgs.lib.cmakeFeature "ISA" "riscv")
|
(pkgs.lib.cmakeFeature "ISA" "riscv")
|
||||||
(pkgs.lib.cmakeFeature "PLATFORM" "nemu")
|
(pkgs.lib.cmakeFeature "PLATFORM" "nemu")
|
||||||
(pkgs.lib.cmakeFeature "CMAKE_INSTALL_DATADIR" "share")
|
|
||||||
];
|
];
|
||||||
|
|
||||||
buildInputs = [
|
buildInputs = [
|
||||||
|
@ -84,16 +86,16 @@
|
||||||
inputsFrom = [
|
inputsFrom = [
|
||||||
self.packages.${system}.nemu
|
self.packages.${system}.nemu
|
||||||
];
|
];
|
||||||
IMAGES_PATH = "${self.packages.${system}.am-kernels}/share/binary";
|
NEMU_HOME = "/home/xin/repo/ysyx-workbench/nemu";
|
||||||
|
NEMU_IMAGES_PATH = self.packages.${system}.am-kernels + "/share/am-kernels";
|
||||||
};
|
};
|
||||||
|
|
||||||
devShells.npc = with pkgs; mkShell {
|
devShells.npc = with pkgs; mkShell.override { stdenv = ccacheStdenv; } {
|
||||||
inherit (self.checks.${system}.pre-commit-check) shellHook;
|
inherit (self.checks.${system}.pre-commit-check) shellHook;
|
||||||
CHISEL_FIRTOOL_PATH = "${nixpkgs-circt162.legacyPackages.${system}.circt}/bin";
|
CHISEL_FIRTOOL_PATH = "${nixpkgs-circt162.legacyPackages.${system}.circt}/bin";
|
||||||
packages = [
|
packages = [
|
||||||
clang-tools
|
clang-tools
|
||||||
cmake
|
cmake
|
||||||
ninja
|
|
||||||
coursier
|
coursier
|
||||||
espresso
|
espresso
|
||||||
bloop
|
bloop
|
||||||
|
|
|
@ -180,7 +180,7 @@ config ITRACE_BUFFER
|
||||||
default 10
|
default 10
|
||||||
|
|
||||||
config MTRACE
|
config MTRACE
|
||||||
depends on TRACE
|
depends on TRACE && LOG_TRACE
|
||||||
bool "Enable memory tracing"
|
bool "Enable memory tracing"
|
||||||
default n
|
default n
|
||||||
|
|
||||||
|
@ -198,7 +198,7 @@ config MTRACE_RANGE_MAX
|
||||||
default 10
|
default 10
|
||||||
|
|
||||||
config FTRACE
|
config FTRACE
|
||||||
depends on TRACE && TARGET_NATIVE_ELF && ENGINE_INTERPRETER
|
depends on TRACE && TARGET_NATIVE_ELF && ENGINE_INTERPRETER && LOG_TRACE
|
||||||
bool "Enable function tracing"
|
bool "Enable function tracing"
|
||||||
default n
|
default n
|
||||||
|
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
stdenv,
|
stdenv,
|
||||||
am-kernels,
|
am-kernels,
|
||||||
dtc,
|
dtc,
|
||||||
|
mini-gdbstub,
|
||||||
defconfig ? "alldefconfig",
|
defconfig ? "alldefconfig",
|
||||||
}:
|
}:
|
||||||
|
|
||||||
|
@ -23,6 +24,7 @@ stdenv.mkDerivation rec {
|
||||||
buildInputs = with pkgs; [
|
buildInputs = with pkgs; [
|
||||||
readline
|
readline
|
||||||
libllvm
|
libllvm
|
||||||
|
mini-gdbstub
|
||||||
];
|
];
|
||||||
|
|
||||||
checkInputs = [
|
checkInputs = [
|
||||||
|
@ -41,7 +43,7 @@ stdenv.mkDerivation rec {
|
||||||
|
|
||||||
doCheck = (defconfig == "alldefconfig");
|
doCheck = (defconfig == "alldefconfig");
|
||||||
checkPhase = if doCheck then ''
|
checkPhase = if doCheck then ''
|
||||||
export IMAGES_PATH=${am-kernels}/share/binary
|
export NEMU_IMAGES_PATH=${am-kernels}/share/am-kernels
|
||||||
make test
|
make test
|
||||||
'' else "";
|
'' else "";
|
||||||
|
|
||||||
|
|
|
@ -17,8 +17,18 @@
|
||||||
#define __CPU_CPU_H__
|
#define __CPU_CPU_H__
|
||||||
|
|
||||||
#include <common.h>
|
#include <common.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
#include <gdbstub.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
size_t addr;
|
||||||
|
bp_type_t type;
|
||||||
|
} breakpoint_t;
|
||||||
|
|
||||||
void cpu_exec(uint64_t n);
|
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 set_nemu_state(int state, vaddr_t pc, int halt_ret);
|
||||||
void invalid_inst(vaddr_t thispc);
|
void invalid_inst(vaddr_t thispc);
|
||||||
|
|
|
@ -16,22 +16,33 @@
|
||||||
#ifndef __CPU_DECODE_H__
|
#ifndef __CPU_DECODE_H__
|
||||||
#define __CPU_DECODE_H__
|
#define __CPU_DECODE_H__
|
||||||
|
|
||||||
|
#include "types.h"
|
||||||
#include <isa.h>
|
#include <isa.h>
|
||||||
|
|
||||||
|
typedef enum { INST_NORMAL, INST_MEM_WRITE, INST_MEM_READ } inst_type_t;
|
||||||
|
|
||||||
|
typedef union {
|
||||||
|
paddr_t rmem;
|
||||||
|
paddr_t wmem;
|
||||||
|
} inst_type_op;
|
||||||
|
|
||||||
typedef struct Decode {
|
typedef struct Decode {
|
||||||
vaddr_t pc;
|
vaddr_t pc;
|
||||||
vaddr_t snpc; // static next pc
|
vaddr_t snpc; // static next pc
|
||||||
vaddr_t dnpc; // dynamic next pc
|
vaddr_t dnpc; // dynamic next pc
|
||||||
|
inst_type_t inst_type;
|
||||||
|
inst_type_op inst_value;
|
||||||
ISADecodeInfo isa;
|
ISADecodeInfo isa;
|
||||||
} Decode;
|
} Decode;
|
||||||
|
|
||||||
// --- pattern matching mechanism ---
|
// --- pattern matching mechanism ---
|
||||||
__attribute__((always_inline))
|
__attribute__((always_inline)) static inline void
|
||||||
static inline void pattern_decode(const char *str, int len,
|
pattern_decode(const char *str, int len, uint64_t *key, uint64_t *mask,
|
||||||
uint64_t *key, uint64_t *mask, uint64_t *shift) {
|
uint64_t *shift) {
|
||||||
uint64_t __key = 0, __mask = 0, __shift = 0;
|
uint64_t __key = 0, __mask = 0, __shift = 0;
|
||||||
#define macro(i) \
|
#define macro(i) \
|
||||||
if ((i) >= len) goto finish; \
|
if ((i) >= len) \
|
||||||
|
goto finish; \
|
||||||
else { \
|
else { \
|
||||||
char c = str[i]; \
|
char c = str[i]; \
|
||||||
if (c != ' ') { \
|
if (c != ' ') { \
|
||||||
|
@ -43,12 +54,24 @@ static inline void pattern_decode(const char *str, int len,
|
||||||
} \
|
} \
|
||||||
}
|
}
|
||||||
|
|
||||||
#define macro2(i) macro(i); macro((i) + 1)
|
#define macro2(i) \
|
||||||
#define macro4(i) macro2(i); macro2((i) + 2)
|
macro(i); \
|
||||||
#define macro8(i) macro4(i); macro4((i) + 4)
|
macro((i) + 1)
|
||||||
#define macro16(i) macro8(i); macro8((i) + 8)
|
#define macro4(i) \
|
||||||
#define macro32(i) macro16(i); macro16((i) + 16)
|
macro2(i); \
|
||||||
#define macro64(i) macro32(i); macro32((i) + 32)
|
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);
|
macro64(0);
|
||||||
panic("pattern too long");
|
panic("pattern too long");
|
||||||
#undef macro
|
#undef macro
|
||||||
|
@ -58,18 +81,21 @@ finish:
|
||||||
*shift = __shift;
|
*shift = __shift;
|
||||||
}
|
}
|
||||||
|
|
||||||
__attribute__((always_inline))
|
__attribute__((always_inline)) static inline void
|
||||||
static inline void pattern_decode_hex(const char *str, int len,
|
pattern_decode_hex(const char *str, int len, uint64_t *key, uint64_t *mask,
|
||||||
uint64_t *key, uint64_t *mask, uint64_t *shift) {
|
uint64_t *shift) {
|
||||||
uint64_t __key = 0, __mask = 0, __shift = 0;
|
uint64_t __key = 0, __mask = 0, __shift = 0;
|
||||||
#define macro(i) \
|
#define macro(i) \
|
||||||
if ((i) >= len) goto finish; \
|
if ((i) >= len) \
|
||||||
|
goto finish; \
|
||||||
else { \
|
else { \
|
||||||
char c = str[i]; \
|
char c = str[i]; \
|
||||||
if (c != ' ') { \
|
if (c != ' ') { \
|
||||||
Assert((c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || c == '?', \
|
Assert((c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || c == '?', \
|
||||||
"invalid character '%c' in pattern string", c); \
|
"invalid character '%c' in pattern string", c); \
|
||||||
__key = (__key << 4) | (c == '?' ? 0 : (c >= '0' && c <= '9') ? c - '0' : c - 'a' + 10); \
|
__key = (__key << 4) | (c == '?' ? 0 \
|
||||||
|
: (c >= '0' && c <= '9') ? c - '0' \
|
||||||
|
: c - 'a' + 10); \
|
||||||
__mask = (__mask << 4) | (c == '?' ? 0 : 0xf); \
|
__mask = (__mask << 4) | (c == '?' ? 0 : 0xf); \
|
||||||
__shift = (c == '?' ? __shift + 4 : 0); \
|
__shift = (c == '?' ? __shift + 4 : 0); \
|
||||||
} \
|
} \
|
||||||
|
@ -84,18 +110,22 @@ finish:
|
||||||
*shift = __shift;
|
*shift = __shift;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// --- pattern matching wrappers for decode ---
|
// --- pattern matching wrappers for decode ---
|
||||||
#define INSTPAT(pattern, ...) do { \
|
#define INSTPAT(pattern, ...) \
|
||||||
|
do { \
|
||||||
uint64_t key, mask, shift; \
|
uint64_t key, mask, shift; \
|
||||||
pattern_decode(pattern, STRLEN(pattern), &key, &mask, &shift); \
|
pattern_decode(pattern, STRLEN(pattern), &key, &mask, &shift); \
|
||||||
if ((((uint64_t)INSTPAT_INST(s) >> shift) & mask) == key) { \
|
if ((((uint64_t)INSTPAT_INST(s) >> shift) & mask) == key) { \
|
||||||
INSTPAT_MATCH(s, ##__VA_ARGS__); \
|
INSTPAT_MATCH(s, ##__VA_ARGS__); \
|
||||||
goto *(__instpat_end); \
|
goto *(__instpat_end); \
|
||||||
} \
|
} \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
#define INSTPAT_START(name) { const void ** __instpat_end = &&concat(__instpat_end_, name);
|
#define INSTPAT_START(name) \
|
||||||
#define INSTPAT_END(name) concat(__instpat_end_, name): ; }
|
{ \
|
||||||
|
const void **__instpat_end = &&concat(__instpat_end_, name);
|
||||||
|
#define INSTPAT_END(name) \
|
||||||
|
concat(__instpat_end_, name) :; \
|
||||||
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
#define __ISA_H__
|
#define __ISA_H__
|
||||||
|
|
||||||
// Located at src/isa/$(GUEST_ISA)/include/isa-def.h
|
// Located at src/isa/$(GUEST_ISA)/include/isa-def.h
|
||||||
|
#include <gdbstub.h>
|
||||||
#include <isa-def.h>
|
#include <isa-def.h>
|
||||||
|
|
||||||
// The macro `__GUEST_ISA__` is defined in $(CFLAGS).
|
// The macro `__GUEST_ISA__` is defined in $(CFLAGS).
|
||||||
|
@ -30,8 +31,11 @@ void init_isa();
|
||||||
|
|
||||||
// reg
|
// reg
|
||||||
extern CPU_state cpu;
|
extern CPU_state cpu;
|
||||||
|
extern arch_info_t isa_arch_info;
|
||||||
void isa_reg_display();
|
void isa_reg_display();
|
||||||
word_t isa_reg_str2val(const char *name, bool *success);
|
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
|
// exec
|
||||||
struct Decode;
|
struct Decode;
|
||||||
|
|
|
@ -22,7 +22,7 @@ CXX := g++
|
||||||
endif
|
endif
|
||||||
LD := $(CXX)
|
LD := $(CXX)
|
||||||
INCLUDES = $(addprefix -I, $(INC_PATH))
|
INCLUDES = $(addprefix -I, $(INC_PATH))
|
||||||
CFLAGS := -O2 -MMD -Wall -Werror $(INCLUDES) $(CFLAGS)
|
CFLAGS := -O2 -MMD -Wall $(INCLUDES) $(CFLAGS)
|
||||||
LDFLAGS := -O2 $(LDFLAGS)
|
LDFLAGS := -O2 $(LDFLAGS)
|
||||||
|
|
||||||
OBJS = $(SRCS:%.c=$(OBJ_DIR)/%.o) $(CXXSRC:%.cc=$(OBJ_DIR)/%.o)
|
OBJS = $(SRCS:%.c=$(OBJ_DIR)/%.o) $(CXXSRC:%.cc=$(OBJ_DIR)/%.o)
|
||||||
|
|
|
@ -13,11 +13,12 @@
|
||||||
* See the Mulan PSL v2 for more details.
|
* See the Mulan PSL v2 for more details.
|
||||||
***************************************************************************************/
|
***************************************************************************************/
|
||||||
|
|
||||||
#include <utils.h>
|
#include "gdbstub.h"
|
||||||
#include <cpu/cpu.h>
|
#include <cpu/cpu.h>
|
||||||
#include <cpu/decode.h>
|
#include <cpu/decode.h>
|
||||||
#include <cpu/difftest.h>
|
#include <cpu/difftest.h>
|
||||||
#include <locale.h>
|
#include <locale.h>
|
||||||
|
#include <utils.h>
|
||||||
|
|
||||||
/* The assembly code of instructions executed is only output to the screen
|
/* The assembly code of instructions executed is only output to the screen
|
||||||
* when the number of instructions executed is less than this value.
|
* when the number of instructions executed is less than this value.
|
||||||
|
@ -34,13 +35,16 @@ IFDEF(CONFIG_ITRACE, extern char logbuf[CONFIG_ITRACE_BUFFER][128]);
|
||||||
IFDEF(CONFIG_ITRACE, extern int logbuf_rear);
|
IFDEF(CONFIG_ITRACE, extern int logbuf_rear);
|
||||||
|
|
||||||
void device_update();
|
void device_update();
|
||||||
bool wp_eval_all();
|
|
||||||
|
|
||||||
static void trace_and_difftest(Decode *_this, vaddr_t dnpc) {
|
static void trace_and_difftest(Decode *_this, vaddr_t dnpc) {
|
||||||
#ifdef CONFIG_ITRACE_COND
|
#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
|
#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));
|
IFDEF(CONFIG_DIFFTEST, difftest_step(_this->pc, dnpc));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -56,12 +60,13 @@ static void exec_once(Decode *s, vaddr_t pc) {
|
||||||
int ilen = s->snpc - s->pc;
|
int ilen = s->snpc - s->pc;
|
||||||
int i;
|
int i;
|
||||||
uint8_t *inst = (uint8_t *)&s->isa.inst.val;
|
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]);
|
p += snprintf(p, 4, " %02x", inst[i]);
|
||||||
}
|
}
|
||||||
int ilen_max = MUXDEF(CONFIG_ISA_x86, 8, 4);
|
int ilen_max = MUXDEF(CONFIG_ISA_x86, 8, 4);
|
||||||
int space_len = ilen_max - ilen;
|
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;
|
space_len = space_len * 3 + 1;
|
||||||
memset(p, ' ', space_len);
|
memset(p, ' ', space_len);
|
||||||
p += space_len;
|
p += space_len;
|
||||||
|
@ -69,7 +74,8 @@ static void exec_once(Decode *s, vaddr_t pc) {
|
||||||
#ifndef CONFIG_ISA_loongarch32r
|
#ifndef CONFIG_ISA_loongarch32r
|
||||||
void disassemble(char *str, int size, uint64_t pc, uint8_t *code, int nbyte);
|
void disassemble(char *str, int size, uint64_t pc, uint8_t *code, int nbyte);
|
||||||
disassemble(p, logbuf[logbuf_rear] + sizeof(logbuf[logbuf_rear]) - p,
|
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
|
#else
|
||||||
p[0] = '\0'; // the upstream llvm does not support loongarch32r
|
p[0] = '\0'; // the upstream llvm does not support loongarch32r
|
||||||
#endif
|
#endif
|
||||||
|
@ -78,15 +84,12 @@ static void exec_once(Decode *s, vaddr_t pc) {
|
||||||
|
|
||||||
static void execute(uint64_t n) {
|
static void execute(uint64_t n) {
|
||||||
Decode s;
|
Decode s;
|
||||||
for (;n > 0; n --) {
|
for (; n > 0; n--) {
|
||||||
exec_once(&s, cpu.pc);
|
exec_once(&s, cpu.pc);
|
||||||
g_nr_guest_inst ++;
|
g_nr_guest_inst++;
|
||||||
trace_and_difftest(&s, cpu.pc);
|
trace_and_difftest(&s, cpu.pc);
|
||||||
if (wp_eval_all()) {
|
if (nemu_state.state != NEMU_RUNNING)
|
||||||
IFDEF(CONFIG_ITRACE, puts(logbuf[logbuf_rear]));
|
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
if (nemu_state.state != NEMU_RUNNING) break;
|
|
||||||
IFDEF(CONFIG_DEVICE, device_update());
|
IFDEF(CONFIG_DEVICE, device_update());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -96,8 +99,12 @@ static void statistic() {
|
||||||
#define NUMBERIC_FMT MUXDEF(CONFIG_TARGET_AM, "%", "%'") PRIu64
|
#define NUMBERIC_FMT MUXDEF(CONFIG_TARGET_AM, "%", "%'") PRIu64
|
||||||
Log("host time spent = " NUMBERIC_FMT " us", g_timer);
|
Log("host time spent = " NUMBERIC_FMT " us", g_timer);
|
||||||
Log("total guest instructions = " NUMBERIC_FMT, g_nr_guest_inst);
|
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);
|
if (g_timer > 0)
|
||||||
else Log("Finish running in less than 1 us and can not calculate the simulation frequency");
|
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() {
|
void assert_fail_msg() {
|
||||||
|
@ -109,10 +116,13 @@ void assert_fail_msg() {
|
||||||
void cpu_exec(uint64_t n) {
|
void cpu_exec(uint64_t n) {
|
||||||
g_print_step = (n < MAX_INST_TO_PRINT);
|
g_print_step = (n < MAX_INST_TO_PRINT);
|
||||||
switch (nemu_state.state) {
|
switch (nemu_state.state) {
|
||||||
case NEMU_END: case NEMU_ABORT:
|
case NEMU_END:
|
||||||
printf("Program execution has ended. To restart the program, exit NEMU and run again.\n");
|
case NEMU_ABORT:
|
||||||
|
printf("Program execution has ended. To restart the program, exit NEMU and "
|
||||||
|
"run again.\n");
|
||||||
return;
|
return;
|
||||||
default: nemu_state.state = NEMU_RUNNING;
|
default:
|
||||||
|
nemu_state.state = NEMU_RUNNING;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint64_t timer_start = get_time();
|
uint64_t timer_start = get_time();
|
||||||
|
@ -123,18 +133,52 @@ void cpu_exec(uint64_t n) {
|
||||||
g_timer += timer_end - timer_start;
|
g_timer += timer_end - timer_start;
|
||||||
|
|
||||||
switch (nemu_state.state) {
|
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: {
|
case NEMU_END:
|
||||||
|
case NEMU_ABORT: {
|
||||||
Log("nemu: %s at pc = " FMT_WORD,
|
Log("nemu: %s at pc = " FMT_WORD,
|
||||||
(nemu_state.state == NEMU_ABORT ? ANSI_FMT("ABORT", ANSI_FG_RED) :
|
(nemu_state.state == NEMU_ABORT
|
||||||
(nemu_state.halt_ret == 0 ? ANSI_FMT("HIT GOOD TRAP", ANSI_FG_GREEN) :
|
? ANSI_FMT("ABORT", ANSI_FG_RED)
|
||||||
ANSI_FMT("HIT BAD TRAP", 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);
|
nemu_state.halt_pc);
|
||||||
if(nemu_state.halt_ret != 0) {
|
if (nemu_state.halt_ret != 0) {
|
||||||
IFDEF(CONFIG_ITRACE, log_itrace_print());
|
IFDEF(CONFIG_ITRACE, log_itrace_print());
|
||||||
}
|
}
|
||||||
} // fall through
|
} // fall through
|
||||||
case NEMU_QUIT: statistic();
|
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;
|
||||||
|
}
|
||||||
|
|
|
@ -13,7 +13,9 @@
|
||||||
* See the Mulan PSL v2 for more details.
|
* See the Mulan PSL v2 for more details.
|
||||||
***************************************************************************************/
|
***************************************************************************************/
|
||||||
|
|
||||||
|
#include "debug.h"
|
||||||
#include <cpu/cpu.h>
|
#include <cpu/cpu.h>
|
||||||
|
#include <gdbstub.h>
|
||||||
|
|
||||||
void sdb_mainloop();
|
void sdb_mainloop();
|
||||||
|
|
||||||
|
@ -22,6 +24,10 @@ void engine_start() {
|
||||||
cpu_exec(-1);
|
cpu_exec(-1);
|
||||||
#else
|
#else
|
||||||
/* Receive commands from user. */
|
/* Receive commands from user. */
|
||||||
sdb_mainloop();
|
int nemu_gdbstub_run();
|
||||||
|
if (nemu_gdbstub_run()) {
|
||||||
|
Error("gdbstub exited abnormally");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,12 +14,12 @@
|
||||||
#**************************************************************************************/
|
#**************************************************************************************/
|
||||||
|
|
||||||
SRCS-y += src/nemu-main.c
|
SRCS-y += src/nemu-main.c
|
||||||
DIRS-y += src/cpu src/monitor src/utils
|
DIRS-y += src/cpu src/utils
|
||||||
DIRS-$(CONFIG_MODE_SYSTEM) += src/memory
|
DIRS-$(CONFIG_MODE_SYSTEM) += src/memory
|
||||||
DIRS-BLACKLIST-$(CONFIG_TARGET_AM) += src/monitor/sdb
|
DIRS-BLACKLIST-$(CONFIG_TARGET_AM) += src/monitor/sdb
|
||||||
|
|
||||||
SHARE = $(if $(CONFIG_TARGET_SHARE),1,0)
|
SHARE = $(if $(CONFIG_TARGET_SHARE),1,0)
|
||||||
LIBS += $(if $(CONFIG_TARGET_NATIVE_ELF),-lreadline -ldl -pie,)
|
LIBS += $(if $(CONFIG_TARGET_NATIVE_ELF),-lgdbstub -lreadline -ldl -pie,)
|
||||||
|
|
||||||
ifdef mainargs
|
ifdef mainargs
|
||||||
ASFLAGS += -DBIN_PATH=\"$(mainargs)\"
|
ASFLAGS += -DBIN_PATH=\"$(mainargs)\"
|
||||||
|
|
|
@ -20,6 +20,7 @@
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
word_t gpr[MUXDEF(CONFIG_RVE, 16, 32)];
|
word_t gpr[MUXDEF(CONFIG_RVE, 16, 32)];
|
||||||
|
// word_t csr[MUXDEF(CONFIG_RVE, )]
|
||||||
vaddr_t pc;
|
vaddr_t pc;
|
||||||
} MUXDEF(CONFIG_RV64, riscv64_CPU_state, riscv32_CPU_state);
|
} MUXDEF(CONFIG_RV64, riscv64_CPU_state, riscv32_CPU_state);
|
||||||
|
|
||||||
|
|
|
@ -13,31 +13,59 @@
|
||||||
* See the Mulan PSL v2 for more details.
|
* See the Mulan PSL v2 for more details.
|
||||||
***************************************************************************************/
|
***************************************************************************************/
|
||||||
|
|
||||||
#include <common.h>
|
|
||||||
#include "local-include/reg.h"
|
#include "local-include/reg.h"
|
||||||
#include "macro.h"
|
#include "macro.h"
|
||||||
|
#include "types.h"
|
||||||
|
#include <common.h>
|
||||||
#include <cpu/cpu.h>
|
#include <cpu/cpu.h>
|
||||||
#include <cpu/ifetch.h>
|
|
||||||
#include <cpu/decode.h>
|
#include <cpu/decode.h>
|
||||||
|
#include <cpu/ifetch.h>
|
||||||
#include <ftrace.h>
|
#include <ftrace.h>
|
||||||
#include <utils.h>
|
#include <utils.h>
|
||||||
|
|
||||||
#define R(i) gpr(i)
|
#define R(i) gpr(i)
|
||||||
#define Mr vaddr_read
|
|
||||||
#define Mw vaddr_write
|
|
||||||
|
|
||||||
enum {
|
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
|
TYPE_N, // none
|
||||||
};
|
};
|
||||||
|
|
||||||
#define src1R() do { *src1 = R(rs1); } while (0)
|
#define src1R() \
|
||||||
#define src2R() do { *src2 = R(rs2); } while (0)
|
do { \
|
||||||
#define immI() do { *imm = SEXT(BITS(i, 31, 20), 12); } while(0)
|
*src1 = R(rs1); \
|
||||||
#define immU() do { *imm = SEXT(BITS(i, 31, 12), 20) << 12; } while(0)
|
} while (0)
|
||||||
#define immS() do { *imm = SEXT(BITS(i, 31, 25), 7) << 5 | BITS(i, 11, 7); } while(0)
|
#define src2R() \
|
||||||
#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)
|
do { \
|
||||||
#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)
|
*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,
|
static void decode_operand(Decode *s, int *rd, word_t *src1, word_t *src2,
|
||||||
word_t *imm, int type) {
|
word_t *imm, int type) {
|
||||||
|
@ -46,12 +74,30 @@ static void decode_operand(Decode *s, int *rd, word_t *src1, word_t *src2,
|
||||||
int rs2 = BITS(i, 24, 20);
|
int rs2 = BITS(i, 24, 20);
|
||||||
*rd = BITS(i, 11, 7);
|
*rd = BITS(i, 11, 7);
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case TYPE_R: src1R(); src2R(); break;
|
case TYPE_R:
|
||||||
case TYPE_I: src1R(); immI(); break;
|
src1R();
|
||||||
case TYPE_U: immU(); break;
|
src2R();
|
||||||
case TYPE_J: immJ(); break;
|
break;
|
||||||
case TYPE_S: src1R(); src2R(); immS(); break;
|
case TYPE_I:
|
||||||
case TYPE_B: src1R(); src2R(); immB(); break;
|
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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -62,11 +108,23 @@ 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
|
#ifdef CONFIG_FTRACE
|
||||||
static void ftrace_jalr(Decode *s, int rd, vaddr_t dst) {
|
static void ftrace_jalr(Decode *s, int rd, vaddr_t dst) {
|
||||||
uint32_t i = s->isa.inst.val;
|
uint32_t i = s->isa.inst.val;
|
||||||
int rs1 = BITS(i, 19, 15);
|
int rs1 = BITS(i, 19, 15);
|
||||||
if(rs1 == 1 && rd == 0) {
|
if (rs1 == 1 && rd == 0) {
|
||||||
ftrace_return(s->pc, dst);
|
ftrace_return(s->pc, dst);
|
||||||
} else {
|
} else {
|
||||||
ftrace_call(s->pc, dst);
|
ftrace_call(s->pc, dst);
|
||||||
|
@ -80,70 +138,118 @@ static int decode_exec(Decode *s) {
|
||||||
s->dnpc = s->snpc;
|
s->dnpc = s->snpc;
|
||||||
|
|
||||||
#define INSTPAT_INST(s) ((s)->isa.inst.val)
|
#define INSTPAT_INST(s) ((s)->isa.inst.val)
|
||||||
#define INSTPAT_MATCH(s, name, type, ... /* execute body */ ) { \
|
#define INSTPAT_MATCH(s, name, type, ... /* execute body */) \
|
||||||
|
{ \
|
||||||
decode_operand(s, &rd, &src1, &src2, &imm, concat(TYPE_, type)); \
|
decode_operand(s, &rd, &src1, &src2, &imm, concat(TYPE_, type)); \
|
||||||
__VA_ARGS__ ; \
|
__VA_ARGS__; \
|
||||||
}
|
}
|
||||||
|
|
||||||
INSTPAT_START();
|
INSTPAT_START();
|
||||||
INSTPAT("??????? ????? ????? ??? ????? 01101 11", lui , U, R(rd) = imm);
|
INSTPAT("??????? ????? ????? ??? ????? 01101 11", lui, U, R(rd) = imm);
|
||||||
INSTPAT("??????? ????? ????? ??? ????? 00101 11", auipc , U, R(rd) = s->pc + imm);
|
INSTPAT("??????? ????? ????? ??? ????? 00101 11", auipc, U,
|
||||||
|
R(rd) = s->pc + imm);
|
||||||
|
|
||||||
INSTPAT("??????? ????? ????? ??? ????? 11011 11", jal , J, do {
|
INSTPAT(
|
||||||
s->dnpc = s->pc + imm; R(rd) = s->pc + 4;
|
"??????? ????? ????? ??? ????? 11011 11", jal, J, do {
|
||||||
IFDEF(CONFIG_FTRACE, ftrace_call(s->pc, s->pc + imm)); } while(0));
|
s->dnpc = s->pc + imm;
|
||||||
INSTPAT("??????? ????? ????? ??? ????? 11001 11", jalr , I, do {
|
R(rd) = s->pc + 4;
|
||||||
s->dnpc = src1 + imm; R(rd) = s->pc + 4;
|
IFDEF(CONFIG_FTRACE, ftrace_call(s->pc, s->pc + imm));
|
||||||
IFDEF(CONFIG_FTRACE, ftrace_jalr(s, rd, src1 + imm)); } while(0));
|
} while (0));
|
||||||
INSTPAT("??????? ????? ????? 000 ????? 11000 11", beq , B, do_branch(s, src1 == src2, imm));
|
INSTPAT(
|
||||||
INSTPAT("??????? ????? ????? 001 ????? 11000 11", bne , B, do_branch(s, src1 != src2, imm));
|
"??????? ????? ????? ??? ????? 11001 11", jalr, I, do {
|
||||||
INSTPAT("??????? ????? ????? 100 ????? 11000 11", blt , B, do_branch(s, (sword_t)src1 < (sword_t)src2, imm));
|
s->dnpc = src1 + imm;
|
||||||
INSTPAT("??????? ????? ????? 101 ????? 11000 11", bge , B, do_branch(s, (sword_t)src1 >= (sword_t)src2, imm));
|
R(rd) = s->pc + 4;
|
||||||
INSTPAT("??????? ????? ????? 110 ????? 11000 11", bltu , B, do_branch(s, src1 < src2, imm));
|
IFDEF(CONFIG_FTRACE, ftrace_jalr(s, rd, src1 + imm));
|
||||||
INSTPAT("??????? ????? ????? 111 ????? 11000 11", bgeu , B, do_branch(s, src1 >= src2, 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(src1 + imm, 1), 8));
|
INSTPAT("??????? ????? ????? 000 ????? 00000 11", lb, I,
|
||||||
INSTPAT("??????? ????? ????? 001 ????? 00000 11", lh , I, R(rd) = SEXT(Mr(src1 + imm, 2), 16));
|
R(rd) = SEXT(Mr(s, src1 + imm, 1), 8));
|
||||||
INSTPAT("??????? ????? ????? 010 ????? 00000 11", lw , I, R(rd) = SEXT(Mr(src1 + imm, 4), 32));
|
INSTPAT("??????? ????? ????? 001 ????? 00000 11", lh, I,
|
||||||
INSTPAT("??????? ????? ????? 100 ????? 00000 11", lbu , I, R(rd) = Mr(src1 + imm, 1));
|
R(rd) = SEXT(Mr(s, src1 + imm, 2), 16));
|
||||||
INSTPAT("??????? ????? ????? 101 ????? 00000 11", lhu , I, R(rd) = Mr(src1 + imm, 2));
|
INSTPAT("??????? ????? ????? 010 ????? 00000 11", lw, I,
|
||||||
INSTPAT("??????? ????? ????? 000 ????? 01000 11", sb , S, Mw(src1 + imm, 1, src2));
|
R(rd) = SEXT(Mr(s, src1 + imm, 4), 32));
|
||||||
INSTPAT("??????? ????? ????? 001 ????? 01000 11", sh , S, Mw(src1 + imm, 2, src2));
|
INSTPAT("??????? ????? ????? 100 ????? 00000 11", lbu, I,
|
||||||
INSTPAT("??????? ????? ????? 010 ????? 01000 11", sw , S, Mw(src1 + imm, 4, src2));
|
R(rd) = Mr(s, src1 + imm, 1));
|
||||||
|
INSTPAT("??????? ????? ????? 101 ????? 00000 11", lhu, I,
|
||||||
|
R(rd) = Mr(s, src1 + imm, 2));
|
||||||
|
INSTPAT("??????? ????? ????? 000 ????? 01000 11", sb, S,
|
||||||
|
Mw(s, src1 + imm, 1, src2));
|
||||||
|
INSTPAT("??????? ????? ????? 001 ????? 01000 11", sh, S,
|
||||||
|
Mw(s, src1 + imm, 2, src2));
|
||||||
|
INSTPAT("??????? ????? ????? 010 ????? 01000 11", sw, S,
|
||||||
|
Mw(s, src1 + imm, 4, src2));
|
||||||
|
|
||||||
INSTPAT("??????? ????? ????? 000 ????? 00100 11", addi , I, R(rd) = src1 + imm);
|
INSTPAT("??????? ????? ????? 000 ????? 00100 11", addi, I,
|
||||||
INSTPAT("??????? ????? ????? 010 ????? 00100 11", slti , I, R(rd) = (sword_t)src1 < (sword_t)imm ? 1 : 0);
|
R(rd) = src1 + imm);
|
||||||
INSTPAT("??????? ????? ????? 011 ????? 00100 11", sltiu , I, R(rd) = src1 < imm ? 1 : 0);
|
INSTPAT("??????? ????? ????? 010 ????? 00100 11", slti, I,
|
||||||
INSTPAT("??????? ????? ????? 100 ????? 00100 11", xori , I, R(rd) = src1 ^ imm);
|
R(rd) = (sword_t)src1 < (sword_t)imm ? 1 : 0);
|
||||||
INSTPAT("??????? ????? ????? 110 ????? 00100 11", ori , I, R(rd) = src1 | imm);
|
INSTPAT("??????? ????? ????? 011 ????? 00100 11", sltiu, I,
|
||||||
INSTPAT("??????? ????? ????? 111 ????? 00100 11", andi , I, R(rd) = src1 & imm);
|
R(rd) = src1 < imm ? 1 : 0);
|
||||||
INSTPAT("0000000 ????? ????? 001 ????? 00100 11", slli , I, R(rd) = src1 << imm);
|
INSTPAT("??????? ????? ????? 100 ????? 00100 11", xori, I,
|
||||||
INSTPAT("0000000 ????? ????? 101 ????? 00100 11", srli , I, R(rd) = src1 >> imm);
|
R(rd) = src1 ^ imm);
|
||||||
INSTPAT("0100000 ????? ????? 101 ????? 00100 11", srai , I, R(rd) = (sword_t)src1 >> (imm & 0x01F));
|
INSTPAT("??????? ????? ????? 110 ????? 00100 11", ori, I, R(rd) = src1 | imm);
|
||||||
INSTPAT("0000000 ????? ????? 000 ????? 01100 11", add , R, R(rd) = src1 + src2);
|
INSTPAT("??????? ????? ????? 111 ????? 00100 11", andi, I,
|
||||||
INSTPAT("0100000 ????? ????? 000 ????? 01100 11", sub , R, R(rd) = src1 - src2);
|
R(rd) = src1 & imm);
|
||||||
INSTPAT("0000000 ????? ????? 001 ????? 01100 11", sll , R, R(rd) = src1 << src2);
|
INSTPAT("0000000 ????? ????? 001 ????? 00100 11", slli, I,
|
||||||
INSTPAT("0000000 ????? ????? 010 ????? 01100 11", slt , R, R(rd) = (sword_t)src1 < (sword_t)src2 ? 1 : 0);
|
R(rd) = src1 << imm);
|
||||||
INSTPAT("0000000 ????? ????? 011 ????? 01100 11", sltu , R, R(rd) = src1 < src2 ? 1 : 0);
|
INSTPAT("0000000 ????? ????? 101 ????? 00100 11", srli, I,
|
||||||
INSTPAT("0000000 ????? ????? 100 ????? 01100 11", xor , R, R(rd) = src1 ^ src2);
|
R(rd) = src1 >> imm);
|
||||||
INSTPAT("0000000 ????? ????? 101 ????? 01100 11", srl , R, R(rd) = src1 >> src2);
|
INSTPAT("0100000 ????? ????? 101 ????? 00100 11", srai, I,
|
||||||
INSTPAT("0100000 ????? ????? 101 ????? 01100 11", sra , R, R(rd) = (sword_t)src1 >> (src2 & 0x01F));
|
R(rd) = (sword_t)src1 >> (imm & 0x01F));
|
||||||
INSTPAT("0000000 ????? ????? 110 ????? 01100 11", or , R, R(rd) = src1 | src2);
|
INSTPAT("0000000 ????? ????? 000 ????? 01100 11", add, R,
|
||||||
INSTPAT("0000000 ????? ????? 111 ????? 01100 11", and , R, R(rd) = src1 & src2);
|
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"
|
// "M"
|
||||||
INSTPAT("0000001 ????? ????? 000 ????? 01100 11", mul , R, R(rd) = src1 * src2);
|
INSTPAT("0000001 ????? ????? 000 ????? 01100 11", mul, R,
|
||||||
INSTPAT("0000001 ????? ????? 001 ????? 01100 11", mulh , R, R(rd) = (int64_t)(sword_t)src1 * (sword_t)src2 >> 32);
|
R(rd) = src1 * src2);
|
||||||
INSTPAT("0000001 ????? ????? 010 ????? 01100 11", mulhsu , R, R(rd) = (int64_t)(sword_t)src1 * (uint64_t)src2 >> 32);
|
INSTPAT("0000001 ????? ????? 001 ????? 01100 11", mulh, R,
|
||||||
INSTPAT("0000001 ????? ????? 011 ????? 01100 11", mulhu , R, R(rd) = (uint64_t)src1 * (uint64_t)src2 >> 32);
|
R(rd) = (int64_t)(sword_t)src1 * (sword_t)src2 >> 32);
|
||||||
INSTPAT("0000001 ????? ????? 100 ????? 01100 11", div , R, R(rd) = (sword_t)src1 / (sword_t)src2);
|
INSTPAT("0000001 ????? ????? 010 ????? 01100 11", mulhsu, R,
|
||||||
INSTPAT("0000001 ????? ????? 101 ????? 01100 11", divu , R, R(rd) = src1 / src2);
|
R(rd) = (int64_t)(sword_t)src1 * (uint64_t)src2 >> 32);
|
||||||
INSTPAT("0000001 ????? ????? 110 ????? 01100 11", rem , R, R(rd) = (sword_t)src1 % (sword_t)src2);
|
INSTPAT("0000001 ????? ????? 011 ????? 01100 11", mulhu, R,
|
||||||
INSTPAT("0000001 ????? ????? 111 ????? 01100 11", remu , R, R(rd) = src1 % src2);
|
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();
|
INSTPAT_END();
|
||||||
|
|
||||||
R(0) = 0; // reset $zero to 0
|
R(0) = 0; // reset $zero to 0
|
||||||
|
|
|
@ -13,20 +13,20 @@
|
||||||
* See the Mulan PSL v2 for more details.
|
* See the Mulan PSL v2 for more details.
|
||||||
***************************************************************************************/
|
***************************************************************************************/
|
||||||
|
|
||||||
#include <isa.h>
|
|
||||||
#include "local-include/reg.h"
|
#include "local-include/reg.h"
|
||||||
|
#include "gdbstub.h"
|
||||||
#include "macro.h"
|
#include "macro.h"
|
||||||
|
#include <errno.h>
|
||||||
|
#include <isa.h>
|
||||||
|
|
||||||
const char *regs[] = {
|
const char *regs[] = {"$0", "ra", "sp", "gp", "tp", "t0", "t1", "t2",
|
||||||
"$0", "ra", "sp", "gp", "tp", "t0", "t1", "t2",
|
|
||||||
"s0", "s1", "a0", "a1", "a2", "a3", "a4", "a5",
|
"s0", "s1", "a0", "a1", "a2", "a3", "a4", "a5",
|
||||||
"a6", "a7", "s2", "s3", "s4", "s5", "s6", "s7",
|
"a6", "a7", "s2", "s3", "s4", "s5", "s6", "s7",
|
||||||
"s8", "s9", "s10", "s11", "t3", "t4", "t5", "t6"
|
"s8", "s9", "s10", "s11", "t3", "t4", "t5", "t6"};
|
||||||
};
|
|
||||||
|
|
||||||
void isa_reg_display() {
|
void isa_reg_display() {
|
||||||
int colomn_per_row = 4;
|
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));
|
printf("\e[1;34m%3s\e[0m: " FMT_PADDR, reg_name(i), gpr(i));
|
||||||
if (i % colomn_per_row == 3)
|
if (i % colomn_per_row == 3)
|
||||||
putchar('\n');
|
putchar('\n');
|
||||||
|
@ -49,3 +49,33 @@ word_t isa_reg_str2val(const char *s, bool *success) {
|
||||||
|
|
||||||
return gpr(i);
|
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};
|
||||||
|
|
|
@ -1 +0,0 @@
|
||||||
riscv32
|
|
|
@ -15,10 +15,10 @@
|
||||||
|
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
#include "debug.h"
|
#include "debug.h"
|
||||||
#include <memory/host.h>
|
|
||||||
#include <memory/paddr.h>
|
|
||||||
#include <device/mmio.h>
|
#include <device/mmio.h>
|
||||||
#include <isa.h>
|
#include <isa.h>
|
||||||
|
#include <memory/host.h>
|
||||||
|
#include <memory/paddr.h>
|
||||||
|
|
||||||
#if defined(CONFIG_PMEM_MALLOC)
|
#if defined(CONFIG_PMEM_MALLOC)
|
||||||
static uint8_t *pmem = NULL;
|
static uint8_t *pmem = NULL;
|
||||||
|
@ -31,7 +31,7 @@ static word_t mtrace_end[CONFIG_MTRACE_RANGE_MAX] = {0};
|
||||||
static int range_count = 0;
|
static int range_count = 0;
|
||||||
#endif
|
#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; }
|
paddr_t host_to_guest(uint8_t *haddr) { return haddr - pmem + CONFIG_MBASE; }
|
||||||
|
|
||||||
static word_t pmem_read(paddr_t addr, int len) {
|
static word_t pmem_read(paddr_t addr, int len) {
|
||||||
|
@ -44,15 +44,17 @@ static void pmem_write(paddr_t addr, int len, word_t data) {
|
||||||
}
|
}
|
||||||
|
|
||||||
static void out_of_bound(paddr_t addr) {
|
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,
|
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);
|
addr, PMEM_LEFT, PMEM_RIGHT, cpu.pc);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_MTRACE
|
#ifdef CONFIG_MTRACE
|
||||||
static void mtrace_print(char type, word_t addr, int len, word_t data) {
|
static void mtrace_print(char type, word_t addr, int len, word_t data) {
|
||||||
for (int i = 0; i < range_count; i++)
|
for (int i = 0; i < range_count; i++)
|
||||||
if (addr <= mtrace_end[i] && addr >= mtrace_start[i] ) {
|
if (addr <= mtrace_end[i] && addr >= mtrace_start[i]) {
|
||||||
Trace("Mem %c " FMT_PADDR "%d D " FMT_PADDR, type, addr, len, data);
|
Trace("PC=" FMT_PADDR " Mem %c" FMT_PADDR " %d D " FMT_PADDR, cpu.pc,
|
||||||
|
type, addr, len, data);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -67,15 +69,17 @@ void init_mem() {
|
||||||
char range[sizeof(CONFIG_MTRACE_RANGE)] = CONFIG_MTRACE_RANGE;
|
char range[sizeof(CONFIG_MTRACE_RANGE)] = CONFIG_MTRACE_RANGE;
|
||||||
char *saveptr, *ptr;
|
char *saveptr, *ptr;
|
||||||
ptr = strtok_r(range, ",", &saveptr);
|
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;
|
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_start[range_count] = start;
|
||||||
mtrace_end[range_count] = end;
|
mtrace_end[range_count] = end;
|
||||||
|
|
||||||
range_count++;
|
range_count++;
|
||||||
ptr = strtok_r(NULL, ",", &saveptr);
|
ptr = strtok_r(NULL, ",", &saveptr);
|
||||||
if (!ptr) break;
|
if (!ptr)
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
Trace("MTRACE ranges: ");
|
Trace("MTRACE ranges: ");
|
||||||
for (int i = 0; i < range_count; i++) {
|
for (int i = 0; i < range_count; i++) {
|
||||||
|
@ -83,13 +87,17 @@ void init_mem() {
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
IFDEF(CONFIG_MEM_RANDOM, memset(pmem, rand(), CONFIG_MSIZE));
|
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 paddr_read(paddr_t addr, int len) {
|
||||||
word_t result = 0;
|
word_t result = 0;
|
||||||
if (likely(in_pmem(addr))) { result = pmem_read(addr, len); goto mtrace;}
|
if (likely(in_pmem(addr))) {
|
||||||
IFDEF(CONFIG_DEVICE, result = mmio_read(addr, len); goto mtrace)
|
result = pmem_read(addr, len);
|
||||||
|
goto mtrace;
|
||||||
|
}
|
||||||
|
IFDEF(CONFIG_DEVICE, result = mmio_read(addr, len); goto mtrace;)
|
||||||
out_of_bound(addr);
|
out_of_bound(addr);
|
||||||
|
|
||||||
mtrace:
|
mtrace:
|
||||||
|
@ -100,7 +108,10 @@ mtrace:
|
||||||
|
|
||||||
void paddr_write(paddr_t addr, int len, word_t data) {
|
void paddr_write(paddr_t addr, int len, word_t data) {
|
||||||
IFDEF(CONFIG_MTRACE, mtrace_print('W', addr, len, 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);
|
IFDEF(CONFIG_DEVICE, mmio_write(addr, len, data); return);
|
||||||
out_of_bound(addr);
|
out_of_bound(addr);
|
||||||
}
|
}
|
||||||
|
|
3
nemu/src/monitor/filelist.mk
Normal file
3
nemu/src/monitor/filelist.mk
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
DIRS-y += src/monitor
|
||||||
|
|
||||||
|
CXXSRC += src/monitor/gdbstub.cc
|
130
nemu/src/monitor/gdbstub.cc
Normal file
130
nemu/src/monitor/gdbstub.cc
Normal file
|
@ -0,0 +1,130 @@
|
||||||
|
#include "utils.h"
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
#include <cpu/cpu.h>
|
||||||
|
#include <debug.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <gdbstub.h>
|
||||||
|
#include <isa.h>
|
||||||
|
#include <memory/paddr.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
std::vector<breakpoint_t> *bp;
|
||||||
|
bool halt;
|
||||||
|
} DbgState;
|
||||||
|
|
||||||
|
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<breakpoint_t>();
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -13,8 +13,10 @@
|
||||||
* See the Mulan PSL v2 for more details.
|
* See the Mulan PSL v2 for more details.
|
||||||
***************************************************************************************/
|
***************************************************************************************/
|
||||||
|
|
||||||
|
#include <errno.h>
|
||||||
#include <isa.h>
|
#include <isa.h>
|
||||||
#include <memory/paddr.h>
|
#include <memory/paddr.h>
|
||||||
|
#include <strings.h>
|
||||||
#include <utils.h>
|
#include <utils.h>
|
||||||
|
|
||||||
void init_rand();
|
void init_rand();
|
||||||
|
@ -22,24 +24,25 @@ void init_log(const char *log_file);
|
||||||
void init_mem();
|
void init_mem();
|
||||||
void init_difftest(char *ref_so_file, long img_size, int port);
|
void init_difftest(char *ref_so_file, long img_size, int port);
|
||||||
void init_device();
|
void init_device();
|
||||||
void init_sdb();
|
|
||||||
void init_disasm(const char *triple);
|
void init_disasm(const char *triple);
|
||||||
|
int nemu_gdbstub_init();
|
||||||
|
|
||||||
static void welcome() {
|
static void welcome() {
|
||||||
Log("Trace: %s", MUXDEF(CONFIG_TRACE, ANSI_FMT("ON", ANSI_FG_GREEN), ANSI_FMT("OFF", ANSI_FG_RED)));
|
Log("Trace: %s", MUXDEF(CONFIG_TRACE, ANSI_FMT("ON", ANSI_FG_GREEN),
|
||||||
IFDEF(CONFIG_TRACE, Log("If trace is enabled, a log file will be generated "
|
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. "
|
"to record the trace. This may lead to a large log file. "
|
||||||
"If it is not necessary, you can disable it in menuconfig"));
|
"If it is not necessary, you can disable it in menuconfig"));
|
||||||
Log("Build time: %s, %s", __TIME__, __DATE__);
|
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");
|
printf("For help, type \"help\"\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef CONFIG_TARGET_AM
|
#ifndef CONFIG_TARGET_AM
|
||||||
#include <getopt.h>
|
#include <getopt.h>
|
||||||
|
|
||||||
void sdb_set_batch_mode();
|
|
||||||
|
|
||||||
static char *log_file = NULL;
|
static char *log_file = NULL;
|
||||||
static char *elf_file = NULL;
|
static char *elf_file = NULL;
|
||||||
static char *diff_so_file = NULL;
|
static char *diff_so_file = NULL;
|
||||||
|
@ -47,13 +50,50 @@ static char *img_file = NULL;
|
||||||
static int difftest_port = 1234;
|
static int difftest_port = 1234;
|
||||||
|
|
||||||
static long load_img() {
|
static long load_img() {
|
||||||
|
FILE *fp = NULL;
|
||||||
|
size_t img_filename_len = strlen(img_file);
|
||||||
if (img_file == NULL) {
|
if (img_file == NULL) {
|
||||||
Log("No image is given. Use the default build-in image.");
|
Log("No image is given. Use the default build-in image.");
|
||||||
return 4096; // built-in image size
|
return 4096; // built-in image size
|
||||||
}
|
}
|
||||||
|
|
||||||
FILE *fp = fopen(img_file, "rb");
|
// Image file is searched from paths in environment variable NEMU_IMAGES_PATH if it's a relative path
|
||||||
Assert(fp, "Can not open '%s'", img_file);
|
if (img_file[0] != '/') {
|
||||||
|
char *search_paths = getenv("NEMU_IMAGES_PATH");
|
||||||
|
if(search_paths == NULL) search_paths = "./";
|
||||||
|
search_paths = strdup(search_paths);
|
||||||
|
Trace("NEMU_IMAGES_PATH=%s", search_paths);
|
||||||
|
|
||||||
|
char *paths_end = strchr(search_paths, '\0');
|
||||||
|
char *p_start = search_paths;
|
||||||
|
do {
|
||||||
|
char *p = strchr(p_start, ':');
|
||||||
|
if (p != NULL) *p = '\0';
|
||||||
|
else p = paths_end;
|
||||||
|
|
||||||
|
char *file_path = malloc(p - p_start + img_filename_len + 2);
|
||||||
|
strcpy(file_path, p_start);
|
||||||
|
strcat(file_path, "/");
|
||||||
|
strcat(file_path, img_file);
|
||||||
|
|
||||||
|
fp = fopen(file_path, "rb");
|
||||||
|
free(file_path);
|
||||||
|
|
||||||
|
if (fp) {
|
||||||
|
Log("Found '%s' in '%s'", img_file, p_start);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
Assert(fp != NULL || errno == ENOENT, "Cannot open '%s'", img_file);
|
||||||
|
p_start = p + 1;
|
||||||
|
} while(p_start < paths_end);
|
||||||
|
free(search_paths);
|
||||||
|
|
||||||
|
Assert(fp, "Cannot find '%s'", img_file);
|
||||||
|
} else {
|
||||||
|
fp = fopen(img_file, "rb");
|
||||||
|
Assert(fp, "Cannot open '%s'", img_file);
|
||||||
|
}
|
||||||
|
|
||||||
fseek(fp, 0, SEEK_END);
|
fseek(fp, 0, SEEK_END);
|
||||||
long size = ftell(fp);
|
long size = ftell(fp);
|
||||||
|
@ -70,23 +110,32 @@ static long load_img() {
|
||||||
|
|
||||||
static int parse_args(int argc, char *argv[]) {
|
static int parse_args(int argc, char *argv[]) {
|
||||||
const struct option table[] = {
|
const struct option table[] = {
|
||||||
{"batch" , no_argument , NULL, 'b'},
|
{"batch", no_argument, NULL, 'b'},
|
||||||
{"log" , required_argument, NULL, 'l'},
|
{"log", required_argument, NULL, 'l'},
|
||||||
{"diff" , required_argument, NULL, 'd'},
|
{"diff", required_argument, NULL, 'd'},
|
||||||
{"port" , required_argument, NULL, 'p'},
|
{"port", required_argument, NULL, 'p'},
|
||||||
{"elf" , required_argument, NULL, 'f'},
|
{"elf", required_argument, NULL, 'f'},
|
||||||
{"help" , no_argument , NULL, 'h'},
|
{"help", no_argument, NULL, 'h'},
|
||||||
{0 , 0 , NULL, 0 },
|
{0, 0, NULL, 0},
|
||||||
};
|
};
|
||||||
int o;
|
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) {
|
switch (o) {
|
||||||
case 'b': sdb_set_batch_mode(); break;
|
case 'p':
|
||||||
case 'p': sscanf(optarg, "%d", &difftest_port); break;
|
sscanf(optarg, "%d", &difftest_port);
|
||||||
case 'l': log_file = optarg; break;
|
break;
|
||||||
case 'd': diff_so_file = optarg; break;
|
case 'l':
|
||||||
case 'f': elf_file = optarg; break;
|
log_file = optarg;
|
||||||
case 1: img_file = optarg; return 0;
|
break;
|
||||||
|
case 'd':
|
||||||
|
diff_so_file = optarg;
|
||||||
|
break;
|
||||||
|
case 'f':
|
||||||
|
elf_file = optarg;
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
img_file = optarg;
|
||||||
|
return 0;
|
||||||
default:
|
default:
|
||||||
printf("Usage: %s [OPTION...] IMAGE [args]\n\n", argv[0]);
|
printf("Usage: %s [OPTION...] IMAGE [args]\n\n", argv[0]);
|
||||||
printf("\t-b,--batch run with batch mode\n");
|
printf("\t-b,--batch run with batch mode\n");
|
||||||
|
@ -128,11 +177,14 @@ void init_monitor(int argc, char *argv[]) {
|
||||||
/* Initialize differential testing. */
|
/* Initialize differential testing. */
|
||||||
init_difftest(diff_so_file, img_size, difftest_port);
|
init_difftest(diff_so_file, img_size, difftest_port);
|
||||||
|
|
||||||
/* Initialize the simple debugger. */
|
/* Initialize debugger */
|
||||||
init_sdb();
|
if (nemu_gdbstub_init()) {
|
||||||
|
Error("Failed to init");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
// printf("elf_file: %s\n", elf_file);
|
// printf("elf_file: %s\n", elf_file);
|
||||||
if(elf_file != NULL) {
|
if (elf_file != NULL) {
|
||||||
#ifdef CONFIG_FTRACE
|
#ifdef CONFIG_FTRACE
|
||||||
void init_elf(const char *path);
|
void init_elf(const char *path);
|
||||||
init_elf(elf_file);
|
init_elf(elf_file);
|
||||||
|
@ -142,14 +194,13 @@ void init_monitor(int argc, char *argv[]) {
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef CONFIG_ISA_loongarch32r
|
#ifndef CONFIG_ISA_loongarch32r
|
||||||
IFDEF(CONFIG_ITRACE, init_disasm(
|
IFDEF(CONFIG_ITRACE,
|
||||||
|
init_disasm(
|
||||||
MUXDEF(CONFIG_ISA_x86, "i686",
|
MUXDEF(CONFIG_ISA_x86, "i686",
|
||||||
MUXDEF(CONFIG_ISA_mips32, "mipsel",
|
MUXDEF(CONFIG_ISA_mips32, "mipsel",
|
||||||
MUXDEF(CONFIG_ISA_riscv,
|
MUXDEF(CONFIG_ISA_riscv,
|
||||||
MUXDEF(CONFIG_RV64, "riscv64",
|
MUXDEF(CONFIG_RV64, "riscv64", "riscv32"),
|
||||||
"riscv32"),
|
"bad"))) "-pc-linux-gnu"));
|
||||||
"bad"))) "-pc-linux-gnu"
|
|
||||||
));
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Display welcome message. */
|
/* Display welcome message. */
|
||||||
|
|
|
@ -1,24 +0,0 @@
|
||||||
%{
|
|
||||||
#include <isa.h>
|
|
||||||
#include <addrexp.h>
|
|
||||||
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; }
|
|
||||||
%%
|
|
|
@ -1,60 +0,0 @@
|
||||||
%code requires {
|
|
||||||
#include <common.h>
|
|
||||||
#include <memory/vaddr.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
extern int yylex(void);
|
|
||||||
}
|
|
||||||
%{
|
|
||||||
#include <common.h>
|
|
||||||
#include <utils.h>
|
|
||||||
#include <isa.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
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
|
|
||||||
|
|
||||||
%%
|
|
|
@ -1,2 +0,0 @@
|
||||||
SRCS-y += src/monitor/sdb/addrexp.tag.c src/monitor/sdb/addrexp.yy.c
|
|
||||||
LFLAGS += -DYY_NO_UNPUT -DYY_NO_INPUT
|
|
|
@ -1,361 +0,0 @@
|
||||||
/***************************************************************************************
|
|
||||||
* Copyright (c) 2014-2022 Zihao Yu, Nanjing University
|
|
||||||
*
|
|
||||||
* NEMU is licensed under Mulan PSL v2.
|
|
||||||
* You can use this software according to the terms and conditions of the Mulan
|
|
||||||
*PSL v2. You may obtain a copy of Mulan PSL v2 at:
|
|
||||||
* http://license.coscl.org.cn/MulanPSL2
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY
|
|
||||||
*KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
|
|
||||||
*NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
|
|
||||||
*
|
|
||||||
* See the Mulan PSL v2 for more details.
|
|
||||||
***************************************************************************************/
|
|
||||||
|
|
||||||
#include "sdb.h"
|
|
||||||
#include "common.h"
|
|
||||||
#include "sys/types.h"
|
|
||||||
#include <addrexp.h>
|
|
||||||
#include <addrexp_lex.h>
|
|
||||||
#include <cpu/cpu.h>
|
|
||||||
#include <errno.h>
|
|
||||||
#include <isa.h>
|
|
||||||
#include <memory/vaddr.h>
|
|
||||||
#include <readline/history.h>
|
|
||||||
#include <readline/readline.h>
|
|
||||||
#include <stdint.h>
|
|
||||||
|
|
||||||
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: <expr>]\n");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int cmd_q(char *args) {
|
|
||||||
nemu_state.state = NEMU_QUIT;
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Single stepping
|
|
||||||
* <step>: execute <step> 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: <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();
|
|
||||||
}
|
|
|
@ -1,25 +0,0 @@
|
||||||
/***************************************************************************************
|
|
||||||
* Copyright (c) 2014-2022 Zihao Yu, Nanjing University
|
|
||||||
*
|
|
||||||
* NEMU is licensed under Mulan PSL v2.
|
|
||||||
* You can use this software according to the terms and conditions of the Mulan PSL v2.
|
|
||||||
* You may obtain a copy of Mulan PSL v2 at:
|
|
||||||
* http://license.coscl.org.cn/MulanPSL2
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
|
|
||||||
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
|
|
||||||
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
|
|
||||||
*
|
|
||||||
* See the Mulan PSL v2 for more details.
|
|
||||||
***************************************************************************************/
|
|
||||||
|
|
||||||
#ifndef __SDB_H__
|
|
||||||
#define __SDB_H__
|
|
||||||
|
|
||||||
#include <common.h>
|
|
||||||
|
|
||||||
word_t parse_expr(const char *arg, bool *success);
|
|
||||||
int wp_add(char * expr);
|
|
||||||
int wp_remove_by_number(int number);
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,150 +0,0 @@
|
||||||
/***************************************************************************************
|
|
||||||
* Copyright (c) 2014-2022 Zihao Yu, Nanjing University
|
|
||||||
*
|
|
||||||
* NEMU is licensed under Mulan PSL v2.
|
|
||||||
* You can use this software according to the terms and conditions of the Mulan
|
|
||||||
*PSL v2. You may obtain a copy of Mulan PSL v2 at:
|
|
||||||
* http://license.coscl.org.cn/MulanPSL2
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY
|
|
||||||
*KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
|
|
||||||
*NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
|
|
||||||
*
|
|
||||||
* See the Mulan PSL v2 for more details.
|
|
||||||
***************************************************************************************/
|
|
||||||
|
|
||||||
#include "sdb.h"
|
|
||||||
#include <common.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
|
|
||||||
#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;
|
|
||||||
}
|
|
|
@ -14,7 +14,7 @@
|
||||||
#**************************************************************************************/
|
#**************************************************************************************/
|
||||||
|
|
||||||
ifneq ($(CONFIG_ITRACE)$(CONFIG_IQUEUE),)
|
ifneq ($(CONFIG_ITRACE)$(CONFIG_IQUEUE),)
|
||||||
CXXSRC = src/utils/disasm.cc
|
CXXSRC += src/utils/disasm.cc
|
||||||
CXXFLAGS += $(shell llvm-config --cxxflags) -fPIE
|
CXXFLAGS += $(shell llvm-config --cxxflags) -fPIE
|
||||||
LIBS += $(shell llvm-config --libs)
|
LIBS += $(shell llvm-config --libs)
|
||||||
endif
|
endif
|
||||||
|
|
Loading…
Reference in a new issue