Compare commits
105 commits
tracer-ysy
...
master
Author | SHA1 | Date | |
---|---|---|---|
4c540bd109 | |||
0e408882b2 | |||
3d64dbd200 | |||
1f3e64bb37 | |||
bc04c05081 | |||
b403f8a40b | |||
5ba306c74e | |||
64aee9ae21 | |||
8ee1551dc2 | |||
96ae890632 | |||
a5790308f0 | |||
ba18436c6c | |||
d9efde7a44 | |||
de9f770d08 | |||
85d7840804 | |||
fed4ac225d | |||
c9ad69a32d | |||
385d448746 | |||
ef51673020 | |||
422ff9e006 | |||
f852ee8689 | |||
b317827c3c | |||
f5ea31f676 | |||
d46cd7b4ae | |||
8ffab061ed | |||
5a97fab28f | |||
2ab098d181 | |||
7c982b238b | |||
3acab0a751 | |||
29a9850210 | |||
955f1f2d79 | |||
f38674ce79 | |||
7f0d1ba75a | |||
a54c0d6480 | |||
6ab5d4c156 | |||
4bc4c34af4 | |||
8665aaf7d2 | |||
9f64a88f8d | |||
4c07b66093 | |||
e99236f711 | |||
55230247b2 | |||
89847cfdb4 | |||
e828e140cd | |||
8500df8a6e | |||
50f7d4d7b9 | |||
ca06354f16 | |||
e1438e25ed | |||
6f7d7ba383 | |||
c242e8c507 | |||
f02d5eb2f1 | |||
849f2bb5f3 | |||
97cf418c86 | |||
a478ef7639 | |||
a91adb3a7d | |||
db66021248 | |||
84c8de8461 | |||
dc2cb010ce | |||
e2602b5bad | |||
2209c26dce | |||
b02b1d2e37 | |||
c29cbf8090 | |||
642444b384 | |||
1cd55fb7cb | |||
d5feb71b50 | |||
d5521806d9 | |||
2cc992a181 | |||
8545a92c1f | |||
da0c42422d | |||
18db852763 | |||
a62a132587 | |||
9229e4318e | |||
0f7c6fd508 | |||
c917083554 | |||
f1a575b2fd | |||
d67fb1138a | |||
|
64f891308e | ||
833cf7b6d1 | |||
e764133868 | |||
3c7c5f060e | |||
f9808d0a40 | |||
86ba43a25b | |||
12f5ba0897 | |||
504d270947 | |||
2675a647b0 | |||
4aa536e1ef | |||
ebece52aec | |||
e19e89f70e | |||
9cca9de2a8 | |||
69264e69c6 | |||
4770b4ce97 | |||
1af1dbcd20 | |||
096cc220d1 | |||
fd3838a61d | |||
4a38cb566b | |||
674702b552 | |||
1118f64668 | |||
0b34b19bdf | |||
a2986aab78 | |||
ccbcbabb27 | |||
77ea7e3b8c | |||
1702da0a0a | |||
38818f6f66 | |||
8e861a43fb | |||
97df569747 | |||
f6803239c7 |
167 changed files with 6897 additions and 2734 deletions
4
.clang-format
Normal file
4
.clang-format
Normal file
|
@ -0,0 +1,4 @@
|
|||
---
|
||||
Language: Cpp
|
||||
BasedOnStyle: LLVM
|
||||
ReflowComments: false
|
|
@ -1,21 +0,0 @@
|
|||
name: Build abstract machine with nix
|
||||
on: [push]
|
||||
|
||||
jobs:
|
||||
build-abstract-machine:
|
||||
runs-on: nix
|
||||
steps:
|
||||
- uses: https://github.com/cachix/cachix-action@v14
|
||||
with:
|
||||
name: ysyx
|
||||
signingKey: '${{ secrets.CACHIX_SIGNING_KEY }}'
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: true
|
||||
- name: Build abstract-machine
|
||||
run: |
|
||||
nix build .?submodules=1#abstract-machine
|
||||
- name: Build nemu
|
||||
run: |
|
||||
nix build .?submodules=1#nemu
|
||||
|
28
.gitea/workflows/build-nix-package.yml
Normal file
28
.gitea/workflows/build-nix-package.yml
Normal file
|
@ -0,0 +1,28 @@
|
|||
name: Build abstract machine with nix
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
pull_request:
|
||||
branches:
|
||||
- master
|
||||
|
||||
jobs:
|
||||
build-packages:
|
||||
runs-on: nix
|
||||
strategy:
|
||||
matrix:
|
||||
package:
|
||||
- "abstract-machine"
|
||||
- "nemu"
|
||||
- "nemu-lib"
|
||||
- "rv32Cross.abstract-machine"
|
||||
steps:
|
||||
- uses: https://github.com/cachix/cachix-action@v14
|
||||
with:
|
||||
name: ysyx
|
||||
authToken: '${{ secrets.CACHIX_SIGNING_KEY }}'
|
||||
- uses: actions/checkout@v4
|
||||
- name: Build package
|
||||
run: |
|
||||
nix build -L .#${{ matrix.package }}
|
21
.gitea/workflows/build-npc.yml
Normal file
21
.gitea/workflows/build-npc.yml
Normal file
|
@ -0,0 +1,21 @@
|
|||
name: Build npc tests
|
||||
on: [push]
|
||||
|
||||
jobs:
|
||||
npc-build:
|
||||
strategy:
|
||||
matrix:
|
||||
package: [ "flow", "flow-simlib"]
|
||||
runs-on: nix
|
||||
defaults:
|
||||
run:
|
||||
working-directory: ./npc
|
||||
steps:
|
||||
- uses: https://github.com/cachix/cachix-action@v14
|
||||
with:
|
||||
name: ysyx
|
||||
authToken: '${{ secrets.CACHIX_SIGNING_KEY }}'
|
||||
- uses: actions/checkout@v4
|
||||
- name: Build package
|
||||
run: |
|
||||
nix build -L .#${{ matrix.package }}
|
14
.gitignore
vendored
14
.gitignore
vendored
|
@ -1,14 +1,8 @@
|
|||
!*/
|
||||
!/nemu/*
|
||||
!/nexus-am/*
|
||||
!/nanos-lite/*
|
||||
!/navy-apps/*
|
||||
!/npc/*
|
||||
!Makefile
|
||||
!README.md
|
||||
!.gitignore
|
||||
!init.sh
|
||||
*/.gdbinit
|
||||
difftest/
|
||||
/fceux-am
|
||||
/nvboard
|
||||
**/.cache
|
||||
**/result
|
||||
/.pre-commit-config.yaml
|
||||
**/.vscode/
|
||||
|
|
4
.gitmodules
vendored
4
.gitmodules
vendored
|
@ -1,3 +1,7 @@
|
|||
[submodule "am-kernels"]
|
||||
path = am-kernels
|
||||
url = https://git.xinyang.life/xin/am-kernels.git
|
||||
branch = dev
|
||||
[submodule "diffu"]
|
||||
path = diffu
|
||||
url = git@github.com:xinyangli/diffu.git
|
||||
|
|
2
.scalafmt.conf
Normal file
2
.scalafmt.conf
Normal file
|
@ -0,0 +1,2 @@
|
|||
version = 3.7.17
|
||||
runner.dialect = scala213source3
|
2
abstract-machine/.gitignore
vendored
2
abstract-machine/.gitignore
vendored
|
@ -2,5 +2,7 @@
|
|||
**/build/
|
||||
**/.envrc
|
||||
**/.cache
|
||||
out/
|
||||
.vscode
|
||||
compile_commands.json
|
||||
cmakeUserh
|
||||
|
|
|
@ -6,82 +6,121 @@ set(CMAKE_C_STANDARD 11)
|
|||
set(CMAKE_CXX_STANDARD 11)
|
||||
|
||||
include(CMakeDependentOption)
|
||||
include(CMakePackageConfigHelpers) # Used to find libcheck
|
||||
include(CMakePackageConfigHelpers) # Used to find libcheck
|
||||
include(CTest)
|
||||
include(GNUInstallDirs)
|
||||
|
||||
# -- General options
|
||||
set(ISA CACHE STRING "Target ISA")
|
||||
set_property(CACHE ISA PROPERTY STRINGS "riscv" "x86" "x86_64" "native")
|
||||
string(TOUPPER ${ISA} ISA_UPPER)
|
||||
|
||||
cmake_dependent_option(
|
||||
__PLATFORM_NEMU__ "Run on NEMU"
|
||||
ON "ISA MATCHES \"(riscv | x86)\"" OFF)
|
||||
cmake_dependent_option(
|
||||
__PLATFORM_NATIVE__ "Run on native"
|
||||
ON "ISA MATCHES native" OFF)
|
||||
cmake_dependent_option(__PLATFORM_NEMU__ "Run on NEMU" ON
|
||||
"ISA MATCHES \"(riscv | x86)\"" OFF)
|
||||
cmake_dependent_option(__PLATFORM_NPC__ "Run on NPC" ON "ISA MATCHES riscv" OFF)
|
||||
cmake_dependent_option(__PLATFORM_NATIVE__ "Run on native" ON
|
||||
"ISA MATCHES native" OFF)
|
||||
|
||||
# -- Set PLATFORM according to options
|
||||
set(MATCH_PLATFORM_PATTERN "^__PLATFORM_([A-Z]*)__")
|
||||
set(MATCH_PLATFORM_PATTERN "^__PLATFORM_([A-Z]*)__$")
|
||||
get_cmake_property(CACHE_VARS CACHE_VARIABLES)
|
||||
|
||||
message(STATUS "ISA: ${ISA}")
|
||||
foreach(VAR IN LISTS CACHE_VARS)
|
||||
if(VAR MATCHES ${MATCH_PLATFORM_PATTERN})
|
||||
# Retrieve the value of the cache variable
|
||||
get_property(VAR_VALUE CACHE ${VAR} PROPERTY VALUE)
|
||||
set(PLATFORM_UPPER ${CMAKE_MATCH_1})
|
||||
string(TOLOWER ${PLATFORM_UPPER} PLATFORM)
|
||||
message(STATUS "Variable: ${VAR}=${VAR_VALUE}, Platform: ${PLATFORM}")
|
||||
endif()
|
||||
if(VAR MATCHES ${MATCH_PLATFORM_PATTERN})
|
||||
# Retrieve the value of the cache variable
|
||||
get_property(
|
||||
VAR_VALUE
|
||||
CACHE ${VAR}
|
||||
PROPERTY VALUE)
|
||||
set(PLATFORM_UPPER ${CMAKE_MATCH_1})
|
||||
string(TOLOWER ${PLATFORM_UPPER} PLATFORM)
|
||||
list(APPEND PLATFORMS ${PLATFORM})
|
||||
message(STATUS "Variable: ${VAR}=${VAR_VALUE}, Platform: ${PLATFORM}")
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
if(${PLATFORM} MATCHES "native")
|
||||
set(ARCH "native")
|
||||
else()
|
||||
set(ARCH ${ISA}-${PLATFORM})
|
||||
if((NOT PLATFORM) AND (NOT ISA MATCHES native))
|
||||
message(FATAL_ERROR "Platform not given!")
|
||||
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
|
||||
cmake_dependent_option(
|
||||
NATIVE_USE_KLIB "Use Klib even if on native"
|
||||
ON "NOT __ISA_NATIVE__" OFF)
|
||||
cmake_dependent_option(NATIVE_USE_KLIB "Use Klib even if on native" ON
|
||||
"NOT __ISA_NATIVE__" OFF)
|
||||
|
||||
# -- Add compile definitions based on options
|
||||
add_compile_definitions(
|
||||
$<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")
|
||||
|
||||
add_compile_options(-march=rv32if -mabi=ilp32)
|
||||
add_link_options(-march=rv32if -mabi=ilp32)
|
||||
# NOTE: klib and am include header files in each other, so we need to create
|
||||
# interface libraries for correct dependency
|
||||
add_library(am_interface INTERFACE)
|
||||
target_include_directories(
|
||||
am_interface
|
||||
INTERFACE $<BUILD_INTERFACE:${CMAKE_SOURCE_DIR}/am/include>
|
||||
$<BUILD_INTERFACE:${CMAKE_SOURCE_DIR}/am/src>
|
||||
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>)
|
||||
target_compile_definitions(am_interface INTERFACE ARCH_H=<arch/${ISA}.h>
|
||||
"__ISA__=\"${ISA}\"")
|
||||
file(GLOB_RECURSE AM_HEADERS "${CMAKE_SOURCE_DIR}/am/include/*.h")
|
||||
target_sources(
|
||||
am_interface
|
||||
PUBLIC FILE_SET
|
||||
am_headers
|
||||
TYPE
|
||||
HEADERS
|
||||
BASE_DIRS
|
||||
${CMAKE_SOURCE_DIR}/am/include
|
||||
FILES
|
||||
${AM_HEADERS})
|
||||
|
||||
add_library(klib_interface INTERFACE)
|
||||
target_include_directories(
|
||||
klib_interface
|
||||
INTERFACE $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/klib/include>
|
||||
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>)
|
||||
file(GLOB_RECURSE KLIB_HEADERS "${CMAKE_SOURCE_DIR}/klib/include/*.h")
|
||||
target_sources(
|
||||
klib_interface
|
||||
PUBLIC FILE_SET
|
||||
klib_headers
|
||||
TYPE
|
||||
HEADERS
|
||||
BASE_DIRS
|
||||
${CMAKE_SOURCE_DIR}/klib/include
|
||||
FILES
|
||||
${KLIB_HEADERS})
|
||||
|
||||
install(
|
||||
TARGETS am_interface klib_interface
|
||||
EXPORT interfaceTargets
|
||||
FILE_SET klib_headers FILE_SET am_headers
|
||||
INCLUDES
|
||||
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})
|
||||
|
||||
install(
|
||||
EXPORT interfaceTargets
|
||||
FILE interfaceTargets.cmake
|
||||
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake)
|
||||
|
||||
add_subdirectory(klib)
|
||||
add_subdirectory(am)
|
||||
|
||||
# -- Test depends on klib and am should be added last.
|
||||
add_subdirectory(klib/tests)
|
||||
|
|
|
@ -7,23 +7,23 @@
|
|||
"generator": "Unix Makefiles",
|
||||
"binaryDir": "${sourceDir}/out/build/${presetName}",
|
||||
"cacheVariables": {
|
||||
"CMAKE_BUILD_TYPE": "Debug",
|
||||
"CMAKE_BUILD_TYPE": "RelWithDebInfo",
|
||||
"ISA": "native",
|
||||
"__PLATFORM_NATIVE__": true,
|
||||
"NATIVE_USE_KLIB": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "riscv-nemu",
|
||||
"displayName": "Riscv32 NEMU",
|
||||
"name": "riscv",
|
||||
"displayName": "RV32 all platform",
|
||||
"generator": "Unix Makefiles",
|
||||
"binaryDir": "${sourceDir}/out/build/${presetName}",
|
||||
"installDir": "/home/xin/repo/ysyx-workbench/abstract-machine/out/install",
|
||||
"cacheVariables": {
|
||||
"CMAKE_BUILD_TYPE": "Debug",
|
||||
"CMAKE_BUILD_TYPE": "RelWithDebInfo",
|
||||
"ISA": "riscv",
|
||||
"__PLATFORM_NPC__": true,
|
||||
"__PLATFORM_NEMU__": true
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
|
15
abstract-machine/CMakeUserPresets.json
Normal file
15
abstract-machine/CMakeUserPresets.json
Normal file
|
@ -0,0 +1,15 @@
|
|||
{
|
||||
"version": 6,
|
||||
"configurePresets": [
|
||||
{
|
||||
"name": "Native install",
|
||||
"inherits": "native",
|
||||
"installDir": "/home/xin/repo/ysyx-workbench/abstract-machine/out/install"
|
||||
},
|
||||
{
|
||||
"name": "RISCV install",
|
||||
"inherits": "riscv",
|
||||
"installDir": "/home/xin/repo/ysyx-workbench/abstract-machine/out/install"
|
||||
}
|
||||
]
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
AbstractMachine is a minimal, modularized, and machine-independent
|
||||
AbstractMachine is a minimal, modularized, and machine-independent
|
||||
abstraction layer of the computer hardware:
|
||||
|
||||
* physical memory and direct execution (The "Turing Machine");
|
||||
|
@ -9,5 +9,5 @@ abstraction layer of the computer hardware:
|
|||
|
||||
CONTACTS
|
||||
|
||||
Bug reports and suggestions go to Yanyan Jiang (jyy@nju.edu.cn) and Zihao
|
||||
Bug reports and suggestions go to Yanyan Jiang (jyy@nju.edu.cn) and Zihao
|
||||
Yu (yuzihao@ict.ac.cn).
|
||||
|
|
|
@ -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)
|
||||
|
||||
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,5 +1,6 @@
|
|||
#ifndef ARCH_H__
|
||||
#define ARCH_H__
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef __riscv_e
|
||||
#define NR_REGS 16
|
||||
|
@ -9,10 +10,13 @@
|
|||
|
||||
struct Context {
|
||||
// TODO: fix the order of these members to match trap.S
|
||||
uintptr_t mepc, mcause, gpr[NR_REGS], mstatus;
|
||||
uintptr_t gpr[NR_REGS];
|
||||
uintptr_t mcause, mstatus, mepc;
|
||||
void *pdir;
|
||||
};
|
||||
|
||||
enum Cause { CauseEnvironmentCallFromMMode = 11 };
|
||||
|
||||
#ifdef __riscv_e
|
||||
#define GPR1 gpr[15] // a5
|
||||
#else
|
||||
|
|
|
@ -1,53 +1 @@
|
|||
if(ISA MATCHES "native")
|
||||
set(SOURCEDIR "./${PLATFORM}")
|
||||
else()
|
||||
set(SOURCEDIR "./${ISA}/${PLATFORM}")
|
||||
endif()
|
||||
|
||||
add_subdirectory(${SOURCEDIR})
|
||||
|
||||
target_include_directories(am-${ARCH}
|
||||
PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}
|
||||
PUBLIC
|
||||
$<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})
|
||||
add_subdirectory(${ISA})
|
||||
|
|
|
@ -1,6 +1,3 @@
|
|||
include(CheckPIESupported)
|
||||
check_pie_supported()
|
||||
|
||||
set(SOURCES
|
||||
trap.S
|
||||
cte.c
|
||||
|
@ -13,14 +10,16 @@ set(SOURCES
|
|||
ioe/disk.c
|
||||
ioe/gpu.c
|
||||
ioe/input.c
|
||||
ioe/timer.c
|
||||
)
|
||||
ioe/timer.c)
|
||||
add_library(am-native ${SOURCES})
|
||||
|
||||
# FIXME: get free(): invalid address when user program compiled without pie
|
||||
set_target_properties(am-native PROPERTIES
|
||||
POSITION_INDEPENDENT_CODE TRUE
|
||||
INTERFACE_POSITION_INDEPENDENT_CODE TRUE)
|
||||
set_target_properties(
|
||||
am-native PROPERTIES POSITION_INDEPENDENT_CODE TRUE
|
||||
INTERFACE_POSITION_INDEPENDENT_CODE TRUE)
|
||||
|
||||
find_package(SDL2 REQUIRED)
|
||||
target_link_libraries(am-${ARCH} PUBLIC SDL2::SDL2)
|
||||
target_link_libraries(
|
||||
am-native
|
||||
PUBLIC SDL2::SDL2 dl m
|
||||
PRIVATE klib_interface am_interface)
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
#include <stdatomic.h>
|
||||
#include "platform.h"
|
||||
#include <stdatomic.h>
|
||||
|
||||
int __am_mpe_init = 0;
|
||||
extern bool __am_has_ioe;
|
||||
|
@ -16,7 +16,8 @@ bool mpe_init(void (*entry)()) {
|
|||
char ch;
|
||||
assert(read(sync_pipe[0], &ch, 1) == 1);
|
||||
assert(ch == '+');
|
||||
close(sync_pipe[0]); close(sync_pipe[1]);
|
||||
close(sync_pipe[0]);
|
||||
close(sync_pipe[1]);
|
||||
|
||||
thiscpu->cpuid = i;
|
||||
__am_init_timer_irq();
|
||||
|
@ -31,8 +32,9 @@ bool mpe_init(void (*entry)()) {
|
|||
for (int i = 1; i < cpu_count(); i++) {
|
||||
assert(write(sync_pipe[1], "+", 1) == 1);
|
||||
}
|
||||
close(sync_pipe[0]); close(sync_pipe[1]);
|
||||
|
||||
close(sync_pipe[0]);
|
||||
close(sync_pipe[1]);
|
||||
|
||||
entry();
|
||||
panic("MP entry should not return\n");
|
||||
}
|
||||
|
@ -42,9 +44,7 @@ int cpu_count() {
|
|||
return __am_ncpu;
|
||||
}
|
||||
|
||||
int cpu_current() {
|
||||
return thiscpu->cpuid;
|
||||
}
|
||||
int cpu_current() { return thiscpu->cpuid; }
|
||||
|
||||
int atomic_xchg(int *addr, int newval) {
|
||||
return atomic_exchange((int *)addr, newval);
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
#define _GNU_SOURCE
|
||||
#include <sys/mman.h>
|
||||
#include <sys/auxv.h>
|
||||
#include "platform.h"
|
||||
#include <dlfcn.h>
|
||||
#include <elf.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include "platform.h"
|
||||
#include <stdlib.h>
|
||||
#include <sys/auxv.h>
|
||||
#include <sys/mman.h>
|
||||
|
||||
#define MAX_CPU 16
|
||||
#define TRAP_PAGE_START (void *)0x100000
|
||||
|
@ -70,12 +70,12 @@ static void init_platform() {
|
|||
assert(ret2 == 0);
|
||||
|
||||
pmem = mmap(PMEM_START, PMEM_SIZE, PROT_READ | PROT_WRITE | PROT_EXEC,
|
||||
MAP_SHARED | MAP_FIXED, pmem_fd, 0);
|
||||
MAP_SHARED | MAP_FIXED, pmem_fd, 0);
|
||||
assert(pmem != (void *)-1);
|
||||
|
||||
// allocate private per-cpu structure
|
||||
thiscpu = mmap(NULL, sizeof(*thiscpu), PROT_READ | PROT_WRITE,
|
||||
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
|
||||
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
|
||||
assert(thiscpu != (void *)-1);
|
||||
thiscpu->cpuid = 0;
|
||||
thiscpu->vm_head = NULL;
|
||||
|
@ -83,7 +83,7 @@ static void init_platform() {
|
|||
// create trap page to receive syscall and yield by SIGSEGV
|
||||
int sys_pgsz = sysconf(_SC_PAGESIZE);
|
||||
void *ret = mmap(TRAP_PAGE_START, sys_pgsz, PROT_NONE,
|
||||
MAP_SHARED | MAP_ANONYMOUS | MAP_FIXED, -1, 0);
|
||||
MAP_SHARED | MAP_ANONYMOUS | MAP_FIXED, -1, 0);
|
||||
assert(ret != (void *)-1);
|
||||
|
||||
// save the address of memcpy() in glibc, since it may be linked with klib
|
||||
|
@ -94,7 +94,7 @@ static void init_platform() {
|
|||
Elf64_Phdr *phdr = (void *)getauxval(AT_PHDR);
|
||||
int phnum = (int)getauxval(AT_PHNUM);
|
||||
int i;
|
||||
for (i = 0; i < phnum; i ++) {
|
||||
for (i = 0; i < phnum; i++) {
|
||||
if (phdr[i].p_type == PT_LOAD && (phdr[i].p_flags & PF_W)) {
|
||||
// allocate temporary memory
|
||||
extern char end;
|
||||
|
@ -102,7 +102,8 @@ static void init_platform() {
|
|||
uintptr_t pad = (uintptr_t)vaddr & 0xfff;
|
||||
void *vaddr_align = vaddr - pad;
|
||||
uintptr_t size = phdr[i].p_memsz + pad;
|
||||
void *temp_mem = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
|
||||
void *temp_mem = mmap(NULL, size, PROT_READ | PROT_WRITE,
|
||||
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
|
||||
assert(temp_mem != (void *)-1);
|
||||
|
||||
// save data and bss sections
|
||||
|
@ -110,11 +111,13 @@ static void init_platform() {
|
|||
|
||||
// save the address of mmap() which will be used after munamp(),
|
||||
// since calling the library functions requires accessing GOT, which will be unmapped
|
||||
void *(*mmap_libc)(void *, size_t, int, int, int, off_t) = dlsym(RTLD_NEXT, "mmap");
|
||||
void *(*mmap_libc)(void *, size_t, int, int, int, off_t) =
|
||||
dlsym(RTLD_NEXT, "mmap");
|
||||
assert(mmap_libc != NULL);
|
||||
// load the address of memcpy() on stack, which can still be accessed
|
||||
// after the data section is unmapped
|
||||
void *(*volatile memcpy_libc_temp)(void *, const void *, size_t) = memcpy_libc;
|
||||
void *(*volatile memcpy_libc_temp)(void *, const void *, size_t) =
|
||||
memcpy_libc;
|
||||
|
||||
// unmap the data and bss sections
|
||||
ret2 = munmap(vaddr_align, size);
|
||||
|
@ -122,7 +125,7 @@ static void init_platform() {
|
|||
|
||||
// map the sections again with MAP_SHARED, which will be shared across fork()
|
||||
ret = mmap_libc(vaddr_align, size, PROT_READ | PROT_WRITE | PROT_EXEC,
|
||||
MAP_SHARED | MAP_FIXED | MAP_ANONYMOUS, -1, 0);
|
||||
MAP_SHARED | MAP_FIXED | MAP_ANONYMOUS, -1, 0);
|
||||
assert(ret == vaddr_align);
|
||||
|
||||
// restore the data in the sections
|
||||
|
@ -176,7 +179,8 @@ static void init_platform() {
|
|||
void __am_exit_platform(int code) {
|
||||
// let Linux clean up other resource
|
||||
extern int __am_mpe_init;
|
||||
if (__am_mpe_init && cpu_count() > 1) kill(0, SIGKILL);
|
||||
if (__am_mpe_init && cpu_count() > 1)
|
||||
kill(0, SIGKILL);
|
||||
exit(code);
|
||||
}
|
||||
|
||||
|
@ -185,10 +189,12 @@ void __am_pmem_map(void *va, void *pa, int prot) {
|
|||
int mmap_prot = PROT_NONE;
|
||||
// we do not support executable bit, so mark
|
||||
// all readable pages executable as well
|
||||
if (prot & MMAP_READ) mmap_prot |= PROT_READ | PROT_EXEC;
|
||||
if (prot & MMAP_WRITE) mmap_prot |= PROT_WRITE;
|
||||
void *ret = mmap(va, __am_pgsize, mmap_prot,
|
||||
MAP_SHARED | MAP_FIXED, pmem_fd, (uintptr_t)(pa - pmem));
|
||||
if (prot & MMAP_READ)
|
||||
mmap_prot |= PROT_READ | PROT_EXEC;
|
||||
if (prot & MMAP_WRITE)
|
||||
mmap_prot |= PROT_WRITE;
|
||||
void *ret = mmap(va, __am_pgsize, mmap_prot, MAP_SHARED | MAP_FIXED, pmem_fd,
|
||||
(uintptr_t)(pa - pmem));
|
||||
assert(ret != (void *)-1);
|
||||
}
|
||||
|
||||
|
@ -205,26 +211,21 @@ void __am_get_intr_sigmask(sigset_t *s) {
|
|||
memcpy_libc(s, &__am_intr_sigmask, sizeof(__am_intr_sigmask));
|
||||
}
|
||||
|
||||
int __am_is_sigmask_sti(sigset_t *s) {
|
||||
return !sigismember(s, SIGVTALRM);
|
||||
}
|
||||
int __am_is_sigmask_sti(sigset_t *s) { return !sigismember(s, SIGVTALRM); }
|
||||
|
||||
void __am_send_kbd_intr() {
|
||||
kill(getpid(), SIGUSR1);
|
||||
}
|
||||
void __am_send_kbd_intr() { kill(getpid(), SIGUSR1); }
|
||||
|
||||
void __am_pmem_protect() {
|
||||
// int ret = mprotect(PMEM_START, PMEM_SIZE, PROT_NONE);
|
||||
// assert(ret == 0);
|
||||
// int ret = mprotect(PMEM_START, PMEM_SIZE, PROT_NONE);
|
||||
// assert(ret == 0);
|
||||
}
|
||||
|
||||
void __am_pmem_unprotect() {
|
||||
// int ret = mprotect(PMEM_START, PMEM_SIZE, PROT_READ | PROT_WRITE | PROT_EXEC);
|
||||
// assert(ret == 0);
|
||||
// int ret = mprotect(PMEM_START, PMEM_SIZE, PROT_READ | PROT_WRITE | PROT_EXEC);
|
||||
// assert(ret == 0);
|
||||
}
|
||||
|
||||
// This dummy function will be called in trm.c.
|
||||
// The purpose of this dummy function is to let linker add this file to the object
|
||||
// file set. Without it, the constructor of @_init_platform will not be linked.
|
||||
void __am_platform_dummy() {
|
||||
}
|
||||
void __am_platform_dummy() {}
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
#define KEYDOWN_MASK 0x8000
|
||||
|
||||
void __am_input_keybrd(AM_INPUT_KEYBRD_T *kbd) {
|
||||
kbd->keydown = 0;
|
||||
kbd->keycode = AM_KEY_NONE;
|
||||
uint32_t keycode = inl(KBD_ADDR);
|
||||
kbd->keydown = ((keycode & KEYDOWN_MASK) != 0);
|
||||
kbd->keycode = keycode & (~KEYDOWN_MASK);
|
||||
}
|
||||
|
|
|
@ -1,18 +1,17 @@
|
|||
#include <am.h>
|
||||
#include <nemu.h>
|
||||
|
||||
void __am_timer_init() {
|
||||
}
|
||||
void __am_timer_init() {}
|
||||
|
||||
void __am_timer_uptime(AM_TIMER_UPTIME_T *uptime) {
|
||||
uptime->us = 0;
|
||||
uptime->us = ((uint64_t)inl(RTC_ADDR + 4) << 32) + inl(RTC_ADDR);
|
||||
}
|
||||
|
||||
void __am_timer_rtc(AM_TIMER_RTC_T *rtc) {
|
||||
rtc->second = 0;
|
||||
rtc->minute = 0;
|
||||
rtc->hour = 0;
|
||||
rtc->day = 0;
|
||||
rtc->month = 0;
|
||||
rtc->year = 1900;
|
||||
rtc->hour = 0;
|
||||
rtc->day = 0;
|
||||
rtc->month = 0;
|
||||
rtc->year = 1900;
|
||||
}
|
||||
|
|
|
@ -6,19 +6,18 @@ int main(const char *args);
|
|||
|
||||
Area heap = RANGE(&_heap_start, PMEM_END);
|
||||
#ifndef MAINARGS
|
||||
#define MAINARGS ""
|
||||
#define MAINARGS "i"
|
||||
#endif
|
||||
static const char mainargs[] = MAINARGS;
|
||||
|
||||
void putch(char ch) {
|
||||
outb(SERIAL_PORT, ch);
|
||||
}
|
||||
void putch(char ch) { outb(SERIAL_PORT, ch); }
|
||||
|
||||
void halt(int code) {
|
||||
nemu_trap(code);
|
||||
|
||||
// should not reach here
|
||||
while (1);
|
||||
while (1)
|
||||
;
|
||||
}
|
||||
|
||||
void _trm_init() {
|
||||
|
|
9
abstract-machine/am/src/riscv/CMakeLists.txt
Normal file
9
abstract-machine/am/src/riscv/CMakeLists.txt
Normal file
|
@ -0,0 +1,9 @@
|
|||
foreach(PLATFORM IN LISTS PLATFORMS)
|
||||
string(TOUPPER ${ARCH} ARCH_UPPER)
|
||||
set(AM_COMMON_COMPILE_DEF
|
||||
# -- Arch related
|
||||
$<MAKE_C_IDENTIFIER:__ARCH_${ARCH_UPPER}__> __ISA_${ISA_UPPER}__
|
||||
__PLATFORM_${PLATFORM_UPPER}__
|
||||
$<$<BOOL:${NATIVE_USE_KLIB}>:__NATIVE_USE_KLIB__>)
|
||||
add_subdirectory(${PLATFORM})
|
||||
endforeach()
|
|
@ -1,34 +1,41 @@
|
|||
include(nemu-settings)
|
||||
include(riscv-settings)
|
||||
|
||||
add_library(am-${ISA}-nemu
|
||||
cte.c
|
||||
start.S
|
||||
trap.S
|
||||
vme.c
|
||||
${NEMU_SOURCES}
|
||||
)
|
||||
add_library(am-riscv-nemu cte.c start.S trap.S vme.c ${NEMU_SOURCES})
|
||||
|
||||
target_compile_options(am-${ISA}-nemu PRIVATE
|
||||
${NEMU_COMPILE_OPTIONS}
|
||||
${RISCV_COMPILE_OPTIONS})
|
||||
target_link_options(am-${ISA}-nemu PRIVATE
|
||||
${NEMU_LINK_OPITIONS}
|
||||
${RISCV_LINK_OPTIONS})
|
||||
target_include_directories(am-${ISA}-nemu PRIVATE
|
||||
${NEMU_INCLUDE_DIRECTORIES})
|
||||
target_link_options(am-${ISA}-nemu INTERFACE
|
||||
LINKER:--defsym=_pmem_start=0x80000000
|
||||
LINKER:--defsym=_entry_offset=0x0
|
||||
LINKER:--gc-sections
|
||||
LINKER:-e _start
|
||||
-nostartfiles)
|
||||
target_compile_options(am-riscv-nemu PRIVATE ${NEMU_COMPILE_OPTIONS}
|
||||
${RISCV_COMPILE_OPTIONS})
|
||||
|
||||
target_compile_definitions(am-${ISA}-nemu PUBLIC
|
||||
ARCH_H="arch/riscv.h")
|
||||
target_compile_definitions(am-${ISA}-nemu PRIVATE
|
||||
ISA_H="riscv/riscv.h")
|
||||
target_link_options(am-riscv-nemu INTERFACE ${NEMU_LINK_OPITIONS}
|
||||
${RISCV_LINK_OPTIONS})
|
||||
|
||||
set_target_properties(am-${ISA}-nemu PROPERTIES
|
||||
POSITION_INDEPENDENT_CODE OFF
|
||||
INTERFACE_POSITION_INDEPENDENT_CODE OFF)
|
||||
target_include_directories(am-riscv-nemu PRIVATE ${NEMU_INCLUDE_DIRECTORIES})
|
||||
|
||||
target_link_options(
|
||||
am-riscv-nemu
|
||||
INTERFACE
|
||||
LINKER:--defsym=_pmem_start=0x80000000
|
||||
LINKER:--defsym=_entry_offset=0x0
|
||||
LINKER:--gc-sections
|
||||
LINKER:-e
|
||||
_start
|
||||
-nostartfiles)
|
||||
|
||||
target_link_options(
|
||||
am-riscv-nemu INTERFACE
|
||||
$<BUILD_INTERFACE:-T${CMAKE_SOURCE_DIR}/scripts/linker.ld>
|
||||
$<INSTALL_INTERFACE:-T${CMAKE_INSTALL_FULL_DATADIR}/linker.ld>)
|
||||
|
||||
target_link_libraries(
|
||||
am-riscv-nemu
|
||||
PUBLIC am_interface klib_interface
|
||||
INTERFACE m)
|
||||
|
||||
target_compile_definitions(am-riscv-nemu PRIVATE ISA_H=<riscv/riscv.h>)
|
||||
|
||||
set_target_properties(
|
||||
am-riscv-nemu PROPERTIES POSITION_INDEPENDENT_CODE OFF
|
||||
INTERFACE_POSITION_INDEPENDENT_CODE OFF)
|
||||
|
||||
install(FILES ${CMAKE_SOURCE_DIR}/scripts/linker.ld
|
||||
DESTINATION ${CMAKE_INSTALL_DATADIR})
|
||||
|
|
|
@ -1,14 +1,21 @@
|
|||
#include "arch/riscv.h"
|
||||
#include <am.h>
|
||||
#include <riscv/riscv.h>
|
||||
#include <klib.h>
|
||||
#include <riscv/riscv.h>
|
||||
#include <stdint.h>
|
||||
|
||||
static Context* (*user_handler)(Event, Context*) = NULL;
|
||||
static Context *(*user_handler)(Event, Context *) = NULL;
|
||||
|
||||
Context* __am_irq_handle(Context *c) {
|
||||
Context *__am_irq_handle(Context *c) {
|
||||
if (user_handler) {
|
||||
Event ev = {0};
|
||||
switch (c->mcause) {
|
||||
default: ev.event = EVENT_ERROR; break;
|
||||
case CauseEnvironmentCallFromMMode:
|
||||
ev.event = EVENT_YIELD;
|
||||
break;
|
||||
default:
|
||||
ev.event = EVENT_ERROR;
|
||||
break;
|
||||
}
|
||||
|
||||
c = user_handler(ev, c);
|
||||
|
@ -20,7 +27,7 @@ Context* __am_irq_handle(Context *c) {
|
|||
|
||||
extern void __am_asm_trap(void);
|
||||
|
||||
bool cte_init(Context*(*handler)(Event, Context*)) {
|
||||
bool cte_init(Context *(*handler)(Event, Context *)) {
|
||||
// initialize exception entry
|
||||
asm volatile("csrw mtvec, %0" : : "r"(__am_asm_trap));
|
||||
|
||||
|
@ -31,7 +38,10 @@ bool cte_init(Context*(*handler)(Event, Context*)) {
|
|||
}
|
||||
|
||||
Context *kcontext(Area kstack, void (*entry)(void *), void *arg) {
|
||||
return NULL;
|
||||
Context *c = kstack.end - sizeof(Context);
|
||||
c->mepc = (uintptr_t)entry;
|
||||
c->gpr[10] = (uintptr_t)arg;
|
||||
return c;
|
||||
}
|
||||
|
||||
void yield() {
|
||||
|
@ -42,9 +52,6 @@ void yield() {
|
|||
#endif
|
||||
}
|
||||
|
||||
bool ienabled() {
|
||||
return false;
|
||||
}
|
||||
bool ienabled() { return false; }
|
||||
|
||||
void iset(bool enable) {
|
||||
}
|
||||
void iset(bool enable) {}
|
||||
|
|
|
@ -60,6 +60,8 @@ __am_asm_trap:
|
|||
mv a0, sp
|
||||
jal __am_irq_handle
|
||||
|
||||
mv sp, a0
|
||||
|
||||
LOAD t1, OFFSET_STATUS(sp)
|
||||
LOAD t2, OFFSET_EPC(sp)
|
||||
csrw mstatus, t1
|
||||
|
|
46
abstract-machine/am/src/riscv/npc/CMakeLists.txt
Normal file
46
abstract-machine/am/src/riscv/npc/CMakeLists.txt
Normal file
|
@ -0,0 +1,46 @@
|
|||
include(riscv-settings)
|
||||
|
||||
add_subdirectory(libgcc)
|
||||
|
||||
add_library(
|
||||
am-riscv-npc
|
||||
cte.c
|
||||
input.c
|
||||
ioe.c
|
||||
mpe.c
|
||||
start.S
|
||||
timer.c
|
||||
trap.S
|
||||
trm.c
|
||||
vme.c)
|
||||
|
||||
target_link_libraries(
|
||||
am-riscv-npc
|
||||
PRIVATE npcgcc
|
||||
PUBLIC am_interface klib_interface)
|
||||
|
||||
target_link_options(
|
||||
am-riscv-npc INTERFACE
|
||||
$<BUILD_INTERFACE:-T${CMAKE_SOURCE_DIR}/scripts/linker.ld>
|
||||
$<INSTALL_INTERFACE:-T${CMAKE_INSTALL_FULL_DATADIR}/linker.ld>)
|
||||
|
||||
target_link_options(
|
||||
am-riscv-npc
|
||||
INTERFACE
|
||||
LINKER:--defsym=_pmem_start=0x80000000
|
||||
LINKER:--defsym=_entry_offset=0x0
|
||||
LINKER:--gc-sections
|
||||
LINKER:-e
|
||||
_start
|
||||
-nostartfiles)
|
||||
|
||||
target_link_options(
|
||||
am-riscv-npc INTERFACE
|
||||
$<BUILD_INTERFACE:-T${CMAKE_SOURCE_DIR}/scripts/linker.ld>
|
||||
$<INSTALL_INTERFACE:-T${CMAKE_INSTALL_FULL_DATADIR}/linker.ld>)
|
||||
|
||||
target_compile_definitions(am-riscv-npc PUBLIC ${AM_COMMON_COMPILE_DEF}
|
||||
ARCH_H=<arch/riscv.h>)
|
||||
|
||||
install(FILES ${CMAKE_SOURCE_DIR}/scripts/linker.ld
|
||||
DESTINATION ${CMAKE_INSTALL_DATADIR})
|
|
@ -7,26 +7,32 @@ void __am_timer_rtc(AM_TIMER_RTC_T *);
|
|||
void __am_timer_uptime(AM_TIMER_UPTIME_T *);
|
||||
void __am_input_keybrd(AM_INPUT_KEYBRD_T *);
|
||||
|
||||
static void __am_timer_config(AM_TIMER_CONFIG_T *cfg) { cfg->present = true; cfg->has_rtc = true; }
|
||||
static void __am_input_config(AM_INPUT_CONFIG_T *cfg) { cfg->present = true; }
|
||||
static void __am_timer_config(AM_TIMER_CONFIG_T *cfg) {
|
||||
cfg->present = true;
|
||||
cfg->has_rtc = true;
|
||||
}
|
||||
static void __am_input_config(AM_INPUT_CONFIG_T *cfg) { cfg->present = true; }
|
||||
static void __am_uart_config(AM_UART_CONFIG_T *cfg) { cfg->present = false; }
|
||||
|
||||
typedef void (*handler_t)(void *buf);
|
||||
static void *lut[128] = {
|
||||
[AM_TIMER_CONFIG] = __am_timer_config,
|
||||
[AM_TIMER_RTC ] = __am_timer_rtc,
|
||||
[AM_TIMER_UPTIME] = __am_timer_uptime,
|
||||
[AM_INPUT_CONFIG] = __am_input_config,
|
||||
[AM_INPUT_KEYBRD] = __am_input_keybrd,
|
||||
[AM_UART_CONFIG] = __am_uart_config,
|
||||
[AM_TIMER_CONFIG] = __am_timer_config,
|
||||
[AM_TIMER_RTC] = __am_timer_rtc,
|
||||
[AM_TIMER_UPTIME] = __am_timer_uptime,
|
||||
[AM_INPUT_CONFIG] = __am_input_config,
|
||||
[AM_INPUT_KEYBRD] = __am_input_keybrd,
|
||||
};
|
||||
|
||||
static void fail(void *buf) { panic("access nonexist register"); }
|
||||
|
||||
bool ioe_init() {
|
||||
for (int i = 0; i < LENGTH(lut); i++)
|
||||
if (!lut[i]) lut[i] = fail;
|
||||
if (!lut[i])
|
||||
lut[i] = fail;
|
||||
__am_timer_init();
|
||||
return true;
|
||||
}
|
||||
|
||||
void ioe_read (int reg, void *buf) { ((handler_t)lut[reg])(buf); }
|
||||
void ioe_read(int reg, void *buf) { ((handler_t)lut[reg])(buf); }
|
||||
void ioe_write(int reg, void *buf) { ((handler_t)lut[reg])(buf); }
|
||||
|
|
9
abstract-machine/am/src/riscv/npc/libgcc/CMakeLists.txt
Normal file
9
abstract-machine/am/src/riscv/npc/libgcc/CMakeLists.txt
Normal file
|
@ -0,0 +1,9 @@
|
|||
add_library(npcgcc ashldi3.c div.S muldi3.S multi3.c unused.c)
|
||||
|
||||
target_link_libraries(npcgcc PRIVATE klib_interface am_interface)
|
||||
target_link_options(npcgcc INTERFACE -nolibc -nostdlib)
|
||||
|
||||
install(
|
||||
TARGETS npcgcc
|
||||
EXPORT amTargets-riscv-npc
|
||||
LIBRARY DESTINATION lib)
|
6
abstract-machine/am/src/riscv/npc/npc.h
Normal file
6
abstract-machine/am/src/riscv/npc/npc.h
Normal file
|
@ -0,0 +1,6 @@
|
|||
#ifndef _AM_NPC_NPC_H_
|
||||
#define _AM_NPC_NPC_H_
|
||||
#define SERIAL_PORT 0x10000000
|
||||
#define RTC_ADDR 0x10001000
|
||||
|
||||
#endif
|
|
@ -1,17 +1,18 @@
|
|||
#include "npc.h"
|
||||
#include <am.h>
|
||||
#include <riscv/riscv.h>
|
||||
|
||||
void __am_timer_init() {
|
||||
}
|
||||
void __am_timer_init() {}
|
||||
|
||||
void __am_timer_uptime(AM_TIMER_UPTIME_T *uptime) {
|
||||
uptime->us = 0;
|
||||
uptime->us = ((uint64_t)inl(RTC_ADDR + 4) << 32) + inl(RTC_ADDR);
|
||||
}
|
||||
|
||||
void __am_timer_rtc(AM_TIMER_RTC_T *rtc) {
|
||||
rtc->second = 0;
|
||||
rtc->minute = 0;
|
||||
rtc->hour = 0;
|
||||
rtc->day = 0;
|
||||
rtc->month = 0;
|
||||
rtc->year = 1900;
|
||||
rtc->hour = 0;
|
||||
rtc->day = 0;
|
||||
rtc->month = 0;
|
||||
rtc->year = 1900;
|
||||
}
|
||||
|
|
|
@ -1,24 +1,27 @@
|
|||
#include "npc.h"
|
||||
#include <am.h>
|
||||
#include <klib-macros.h>
|
||||
#include <riscv/riscv.h>
|
||||
|
||||
extern char _heap_start;
|
||||
int main(const char *args);
|
||||
|
||||
extern char _pmem_start;
|
||||
#define PMEM_SIZE (128 * 1024 * 1024)
|
||||
#define PMEM_END ((uintptr_t)&_pmem_start + PMEM_SIZE)
|
||||
#define PMEM_END ((uintptr_t)&_pmem_start + PMEM_SIZE)
|
||||
|
||||
Area heap = RANGE(&_heap_start, PMEM_END);
|
||||
#ifndef MAINARGS
|
||||
#define MAINARGS ""
|
||||
#define MAINARGS "3"
|
||||
#endif
|
||||
static const char mainargs[] = MAINARGS;
|
||||
|
||||
void putch(char ch) {
|
||||
}
|
||||
void putch(char ch) { outb(SERIAL_PORT, ch); }
|
||||
|
||||
void halt(int code) {
|
||||
while (1);
|
||||
asm volatile("mv a0, %0; ebreak" : : "r"(code));
|
||||
while (1)
|
||||
;
|
||||
}
|
||||
|
||||
void _trm_init() {
|
||||
|
|
|
@ -55,25 +55,25 @@ __am_iret:
|
|||
popl %edi
|
||||
popl %ebp
|
||||
iret
|
||||
|
||||
|
||||
.kernel_iret:
|
||||
popl %eax
|
||||
popl %ebx
|
||||
popl %ecx
|
||||
popl %edx
|
||||
addl $4, %esp
|
||||
|
||||
|
||||
/* stack frame:
|
||||
28 ss
|
||||
24 esp (not popped by iret when returning to ring0)
|
||||
20 eflags ---> move to new-esp
|
||||
16 cs
|
||||
12 eip
|
||||
8 ebp
|
||||
4 edi
|
||||
8 ebp
|
||||
4 edi
|
||||
0 esi <--- %esp
|
||||
*/
|
||||
|
||||
|
||||
movl %esp, %ebp
|
||||
movl 24(%ebp), %edi // %edi is new-esp
|
||||
|
||||
|
|
|
@ -6,4 +6,5 @@ find_dependency(SDL2 REQUIRED)
|
|||
endif()
|
||||
|
||||
# Include the targets file
|
||||
include("${CMAKE_CURRENT_LIST_DIR}/../interfaceTargets.cmake")
|
||||
include("${CMAKE_CURRENT_LIST_DIR}/amTargets.cmake")
|
||||
|
|
|
@ -1,11 +1,12 @@
|
|||
set(NEMU_COMPILE_OPTIONS -fdata-sections -ffunction-sections)
|
||||
set(NEMU_LINK_OPTIONS
|
||||
-nostartfiles
|
||||
-nolibc
|
||||
--defsym=_pmem_start=0x80000000
|
||||
--defsym=_entry_offset=0x0
|
||||
--gc-sections
|
||||
-e _start)
|
||||
set(NEMU_INCLUDE_DIRECTORIES
|
||||
${CMAKE_SOURCE_DIR}/am/src/platform/nemu/include)
|
||||
file(GLOB_RECURSE NEMU_SOURCES
|
||||
${CMAKE_SOURCE_DIR}/am/src/platform/nemu/*.[cS])
|
||||
-e
|
||||
_start)
|
||||
set(NEMU_INCLUDE_DIRECTORIES ${CMAKE_SOURCE_DIR}/am/src/platform/nemu/include)
|
||||
file(GLOB_RECURSE NEMU_SOURCES ${CMAKE_SOURCE_DIR}/am/src/platform/nemu/*.[cS])
|
||||
set(INCLUDE_LINKER_SCRIPT ON)
|
||||
|
|
|
@ -1,20 +1,23 @@
|
|||
{ stdenv,
|
||||
lib,
|
||||
cmake,
|
||||
SDL2,
|
||||
isa ? "native",
|
||||
platform ? "NEMU"
|
||||
{ stdenv
|
||||
, lib
|
||||
, cmake
|
||||
, SDL2
|
||||
, glibc
|
||||
, isa ? "native"
|
||||
, platform ? [ ]
|
||||
}:
|
||||
stdenv.mkDerivation {
|
||||
pname = "abstract-machine";
|
||||
version = "2024.02.18";
|
||||
version = "2024.06.01";
|
||||
|
||||
src = ./.;
|
||||
|
||||
cmakeFlags = [
|
||||
cmakeFlags = [
|
||||
(lib.cmakeFeature "ISA" isa)
|
||||
(lib.cmakeBool "__PLATFORM_${lib.strings.toUpper platform}__" true)
|
||||
];
|
||||
] ++ map (p: (lib.cmakeBool "__PLATFORM_${lib.strings.toUpper p}__" true)) platform;
|
||||
|
||||
cmakeBuildType = "Debug";
|
||||
dontStrip = true;
|
||||
|
||||
nativeBuildInputs = [
|
||||
cmake
|
||||
|
@ -22,5 +25,10 @@ stdenv.mkDerivation {
|
|||
|
||||
buildInputs = [
|
||||
|
||||
] ++ (if platform=="native" then [ SDL2 ] else [ ]);
|
||||
] ++ (if isa == "native" then [ SDL2 ] else [ ]);
|
||||
propagatedBuildInputs = [
|
||||
|
||||
] ++ (if isa == "native" then [ SDL2 ] else [ ]);
|
||||
|
||||
doCheck = true;
|
||||
}
|
||||
|
|
|
@ -1,12 +1,4 @@
|
|||
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/include)
|
||||
|
||||
add_library(klib_interface INTERFACE)
|
||||
target_include_directories(klib_interface
|
||||
INTERFACE
|
||||
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
|
||||
$<INSTALL_INTERFACE:include/abstract-machine>)
|
||||
install(DIRECTORY include/
|
||||
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/abstract-machine)
|
||||
|
||||
add_subdirectory(src)
|
||||
# add_subdirectory(tests)
|
||||
|
||||
install(DIRECTORY include/ DESTINATION include/abstract-machine)
|
||||
|
|
|
@ -1,33 +1,29 @@
|
|||
# find_package(FLEX)
|
||||
# find_package(BISON)
|
||||
# find_package(FLEX) find_package(BISON)
|
||||
|
||||
# FLEX_TARGET(fmt_scanner fmt_scanner.l fmt_scanner.c)
|
||||
|
||||
set(SOURCES
|
||||
cpp.c
|
||||
int64.c
|
||||
stdio.c
|
||||
stdlib.c
|
||||
string.c
|
||||
# ${FLEX_fmt_scanner_OUTPUTS}
|
||||
set(SOURCES cpp.c int64.c stdio.c stdlib.c string.c
|
||||
# ${FLEX_fmt_scanner_OUTPUTS}
|
||||
)
|
||||
|
||||
add_library(klib ${SOURCES})
|
||||
target_include_directories(klib PUBLIC $<TARGET_PROPERTY:am_interface,INTERFACE_INCLUDE_DIRECTORIES>)
|
||||
target_compile_definitions(klib PUBLIC $<TARGET_PROPERTY:am-${ARCH},INTERFACE_COMPILE_DEFINITIONS>)
|
||||
target_link_libraries(klib PUBLIC am_interface klib_interface)
|
||||
target_compile_options(klib PUBLIC -fno-builtin)
|
||||
|
||||
install(TARGETS klib
|
||||
EXPORT klibTargets
|
||||
LIBRARY DESTINATION lib)
|
||||
install(
|
||||
TARGETS klib
|
||||
EXPORT klibTargets
|
||||
LIBRARY DESTINATION lib)
|
||||
|
||||
install(EXPORT klibTargets
|
||||
FILE klibTargets.cmake
|
||||
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/klib)
|
||||
install(
|
||||
EXPORT klibTargets
|
||||
FILE klibTargets.cmake
|
||||
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/klib)
|
||||
|
||||
configure_package_config_file(${CMAKE_SOURCE_DIR}/cmake/klib-config.cmake.in
|
||||
configure_package_config_file(
|
||||
${CMAKE_SOURCE_DIR}/cmake/klib-config.cmake.in
|
||||
${CMAKE_CURRENT_BINARY_DIR}/klib-config.cmake
|
||||
INSTALL_DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/klib)
|
||||
|
||||
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/klib-config.cmake
|
||||
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/klib)
|
||||
|
||||
|
|
|
@ -1,16 +1,91 @@
|
|||
#include <am.h>
|
||||
#include <klib.h>
|
||||
#include <klib-macros.h>
|
||||
#include <klib.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
#if !defined(__ISA_NATIVE__) || defined(__NATIVE_USE_KLIB__)
|
||||
|
||||
int vprintf(const char *fmt, va_list ap) {
|
||||
const char *p = fmt;
|
||||
while(*p != '\0') {
|
||||
putch(*p);
|
||||
void print_int(int num, int width, char pad) {
|
||||
int reverse = 0;
|
||||
int count = 0;
|
||||
|
||||
if (num == 0) {
|
||||
reverse = 0;
|
||||
count = 1;
|
||||
} else {
|
||||
if (num < 0) {
|
||||
putch('-');
|
||||
num = -num;
|
||||
}
|
||||
while (num != 0) {
|
||||
reverse = reverse * 10 + (num % 10);
|
||||
num /= 10;
|
||||
count++;
|
||||
}
|
||||
}
|
||||
|
||||
while (width > count) {
|
||||
putch(pad);
|
||||
width--;
|
||||
}
|
||||
|
||||
if (reverse == 0) {
|
||||
putch('0');
|
||||
} else {
|
||||
while (reverse != 0) {
|
||||
putch('0' + (reverse % 10));
|
||||
reverse /= 10;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int vprintf(const char *format, va_list args) {
|
||||
const char *p = format;
|
||||
|
||||
while (*p) {
|
||||
if (*p == '%') {
|
||||
p++; // Skip the '%'
|
||||
char pad = ' ';
|
||||
int width = 0;
|
||||
|
||||
if (*p == '0') {
|
||||
pad = '0';
|
||||
p++;
|
||||
}
|
||||
|
||||
while (*p >= '0' && *p <= '9') {
|
||||
width = width * 10 + (*p - '0');
|
||||
p++;
|
||||
}
|
||||
|
||||
switch (*p) {
|
||||
case 'd': { // Integer
|
||||
int ival = va_arg(args, int);
|
||||
print_int(ival, width, pad);
|
||||
break;
|
||||
}
|
||||
case 'c': { // Character
|
||||
char c = (char)va_arg(args, int);
|
||||
putch(c);
|
||||
break;
|
||||
}
|
||||
case 's': { // String
|
||||
char *s = va_arg(args, char *);
|
||||
putstr(s);
|
||||
break;
|
||||
}
|
||||
case '%': {
|
||||
putch('%');
|
||||
break;
|
||||
}
|
||||
default:
|
||||
panic("Wrong formatter provided to printf");
|
||||
}
|
||||
} else {
|
||||
putch(*p);
|
||||
}
|
||||
p++;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int printf(const char *fmt, ...) {
|
||||
|
@ -21,12 +96,99 @@ int printf(const char *fmt, ...) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
int vsprintf(char *out, const char *fmt, va_list ap) {
|
||||
panic("Not implemented");
|
||||
void append_to_buffer(char **buf, int *pos, char c) { (*buf)[(*pos)++] = c; }
|
||||
|
||||
void print_int_to_buf(char **buf, int *pos, int num, int width, char pad) {
|
||||
int reverse = 0, count = 0, neg = 0;
|
||||
|
||||
if (num == 0) {
|
||||
reverse = 0;
|
||||
count = 1;
|
||||
} else {
|
||||
if (num < 0) {
|
||||
append_to_buffer(buf, pos, '-');
|
||||
num = -num;
|
||||
neg = 1;
|
||||
}
|
||||
while (num != 0) {
|
||||
reverse = reverse * 10 + (num % 10);
|
||||
num /= 10;
|
||||
count++;
|
||||
}
|
||||
}
|
||||
|
||||
width -= neg;
|
||||
while (width > count) {
|
||||
append_to_buffer(buf, pos, pad);
|
||||
width--;
|
||||
}
|
||||
|
||||
for (int i = 0; i < count; i++) {
|
||||
append_to_buffer(buf, pos, '0' + (reverse % 10));
|
||||
reverse /= 10;
|
||||
}
|
||||
}
|
||||
|
||||
int vsprintf(char *buf, const char *format, va_list args) {
|
||||
const char *p = format;
|
||||
int pos = 0; // Position in buf
|
||||
|
||||
while (*p) {
|
||||
if (*p == '%') {
|
||||
p++; // Skip the '%'
|
||||
char pad = ' ';
|
||||
int width = 0;
|
||||
|
||||
if (*p == '0') {
|
||||
pad = '0';
|
||||
p++;
|
||||
}
|
||||
|
||||
while (*p >= '0' && *p <= '9') {
|
||||
width = width * 10 + (*p - '0');
|
||||
p++;
|
||||
}
|
||||
|
||||
switch (*p) {
|
||||
case 'd': { // Integer
|
||||
int ival = va_arg(args, int);
|
||||
print_int_to_buf(&buf, &pos, ival, width, pad);
|
||||
break;
|
||||
}
|
||||
case 'c': { // Character
|
||||
char c = (char)va_arg(args, int);
|
||||
append_to_buffer(&buf, &pos, c);
|
||||
break;
|
||||
}
|
||||
case 's': { // String
|
||||
char *s = va_arg(args, char *);
|
||||
while (*s) {
|
||||
append_to_buffer(&buf, &pos, *s++);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case '%': {
|
||||
append_to_buffer(&buf, &pos, '%');
|
||||
break;
|
||||
}
|
||||
default:
|
||||
panic("Unsupported format specifier");
|
||||
}
|
||||
} else {
|
||||
append_to_buffer(&buf, &pos, *p);
|
||||
}
|
||||
p++;
|
||||
}
|
||||
buf[pos] = '\0'; // Null-terminate the string
|
||||
return pos;
|
||||
}
|
||||
|
||||
int sprintf(char *out, const char *fmt, ...) {
|
||||
panic("Not implemented");
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
vsprintf(out, fmt, args);
|
||||
va_end(args);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int snprintf(char *out, size_t n, const char *fmt, ...) {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
#include <am.h>
|
||||
#include <klib.h>
|
||||
#include <klib-macros.h>
|
||||
#include <klib.h>
|
||||
|
||||
#if !defined(__ISA_NATIVE__) || defined(__NATIVE_USE_KLIB__)
|
||||
static unsigned long int next = 1;
|
||||
|
@ -8,23 +8,21 @@ static unsigned long int next = 1;
|
|||
int rand(void) {
|
||||
// RAND_MAX assumed to be 32767
|
||||
next = next * 1103515245 + 12345;
|
||||
return (unsigned int)(next/65536) % 32768;
|
||||
return (unsigned int)(next / 65536) % 32768;
|
||||
}
|
||||
|
||||
void srand(unsigned int seed) {
|
||||
next = seed;
|
||||
}
|
||||
void srand(unsigned int seed) { next = seed; }
|
||||
|
||||
int abs(int x) {
|
||||
return (x < 0 ? -x : x);
|
||||
}
|
||||
int abs(int x) { return (x < 0 ? -x : x); }
|
||||
|
||||
int atoi(const char* nptr) {
|
||||
int atoi(const char *nptr) {
|
||||
int x = 0;
|
||||
while (*nptr == ' ') { nptr ++; }
|
||||
while (*nptr == ' ') {
|
||||
nptr++;
|
||||
}
|
||||
while (*nptr >= '0' && *nptr <= '9') {
|
||||
x = x * 10 + *nptr - '0';
|
||||
nptr ++;
|
||||
nptr++;
|
||||
}
|
||||
return x;
|
||||
}
|
||||
|
@ -33,13 +31,19 @@ void *malloc(size_t size) {
|
|||
// On native, malloc() will be called during initializaion of C runtime.
|
||||
// Therefore do not call panic() here, else it will yield a dead recursion:
|
||||
// panic() -> putchar() -> (glibc) -> malloc() -> panic()
|
||||
#if !(defined(__ISA_NATIVE__) && defined(__NATIVE_USE_KLIB__))
|
||||
panic("Not implemented");
|
||||
#endif
|
||||
return NULL;
|
||||
static void *addr = NULL;
|
||||
void *ret = NULL;
|
||||
if (addr == 0) {
|
||||
addr = heap.start;
|
||||
ret = addr;
|
||||
} else {
|
||||
panic_on(addr + size > heap.end, "Memory space not enough");
|
||||
ret = addr;
|
||||
addr += size;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
void free(void *ptr) {
|
||||
}
|
||||
void free(void *ptr) {}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
#include <klib.h>
|
||||
#include <klib-macros.h>
|
||||
#include <klib.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#if !defined(__ISA_NATIVE__) || defined(__NATIVE_USE_KLIB__)
|
||||
|
@ -7,14 +7,15 @@
|
|||
size_t strlen(const char *s) {
|
||||
const char *p = s;
|
||||
size_t len = 0;
|
||||
while(*(p++) != '\0') len++;
|
||||
while (*(p++) != '\0')
|
||||
len++;
|
||||
return len;
|
||||
}
|
||||
|
||||
char *strcpy(char *dst, const char *src) {
|
||||
char *p_dst = dst;
|
||||
const char *p_src = src;
|
||||
for(; *p_src != '\0'; p_src++, p_dst++) {
|
||||
for (; *p_src != '\0'; p_src++, p_dst++) {
|
||||
*p_dst = *p_src;
|
||||
}
|
||||
*p_dst = '\0';
|
||||
|
@ -23,10 +24,10 @@ char *strcpy(char *dst, const char *src) {
|
|||
|
||||
char *strncpy(char *dst, const char *src, size_t n) {
|
||||
int i = 0;
|
||||
for(; i < n && src[i] != '\0'; i++) {
|
||||
for (; i < n && src[i] != '\0'; i++) {
|
||||
dst[i] = src[i];
|
||||
}
|
||||
for(; i < n; i++) {
|
||||
for (; i < n; i++) {
|
||||
dst[i] = '\0';
|
||||
}
|
||||
return dst;
|
||||
|
@ -35,8 +36,9 @@ char *strncpy(char *dst, const char *src, size_t n) {
|
|||
char *strcat(char *dst, const char *src) {
|
||||
char *p_dst = dst;
|
||||
const char *p_src = src;
|
||||
while(*p_dst != '\0') p_dst++;
|
||||
for(; *p_src != '\0'; p_src++, p_dst++) {
|
||||
while (*p_dst != '\0')
|
||||
p_dst++;
|
||||
for (; *p_src != '\0'; p_src++, p_dst++) {
|
||||
*p_dst = *p_src;
|
||||
}
|
||||
*p_dst = '\0';
|
||||
|
@ -45,54 +47,56 @@ char *strcat(char *dst, const char *src) {
|
|||
|
||||
int strcmp(const char *s1, const char *s2) {
|
||||
const char *p_s1 = s1, *p_s2 = s2;
|
||||
for(; *p_s1 == *p_s2; p_s1++, p_s2++) {
|
||||
if(*p_s1 == '\0' || *p_s2 == '\0') {
|
||||
for (; *p_s1 == *p_s2; p_s1++, p_s2++) {
|
||||
if (*p_s1 == '\0' || *p_s2 == '\0') {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return *p_s1 - *p_s2;
|
||||
}
|
||||
|
||||
int strncmp(const char *s1, const char *s2, size_t n) {
|
||||
const char *p_s1 = s1, *p_s2 = s2;
|
||||
int i = 0;
|
||||
for(i = 0; i < n - 1; i++) {
|
||||
if(s1[i] == '\0' || s2[i] == '\0')
|
||||
for (i = 0; i < n - 1; i++) {
|
||||
if (s1[i] == '\0' || s2[i] == '\0')
|
||||
break;
|
||||
}
|
||||
}
|
||||
return s1[i] - s2[i];
|
||||
}
|
||||
|
||||
void *memset(void *s, int c, size_t n) {
|
||||
uint8_t *p = s;
|
||||
for(int i = 0; i < n; i++) {
|
||||
for (int i = 0; i < n; i++) {
|
||||
p[i] = c;
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
void *memmove(void *dst, const void *src, size_t n) {
|
||||
if (src + n > dst && src < dst) {
|
||||
if (src + n > dst && src < dst) {
|
||||
size_t len = dst - src;
|
||||
void *p_dst = (void *)src + n;
|
||||
const void *p_src = src + n - len;
|
||||
while(p_dst >= dst) {
|
||||
while (p_dst >= dst) {
|
||||
memcpy(p_dst, p_src, len);
|
||||
p_src -= len;
|
||||
p_dst -= len;
|
||||
}
|
||||
if(n % len) memcpy(dst, src, n % len);
|
||||
if (n % len)
|
||||
memcpy(dst, src, n % len);
|
||||
} else if (dst < src && dst + n > src) {
|
||||
size_t len = src - dst;
|
||||
void *p_dst = dst;
|
||||
const void *p_src = src;
|
||||
while(p_src < src + n) {
|
||||
while (p_src < src + n) {
|
||||
memcpy(p_dst, p_src, len);
|
||||
p_src += len;
|
||||
p_dst += len;
|
||||
}
|
||||
if(n % len) memcpy(p_dst, p_src, n % len);
|
||||
} else {
|
||||
if (n % len)
|
||||
memcpy(p_dst, p_src, n % len);
|
||||
} else {
|
||||
memcpy(dst, src, n);
|
||||
}
|
||||
|
||||
|
@ -100,7 +104,7 @@ void *memmove(void *dst, const void *src, size_t n) {
|
|||
}
|
||||
|
||||
void *memcpy(void *out, const void *in, size_t n) {
|
||||
for (size_t i = 0 ; i < n ; i++) {
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
*(uint8_t *)(out + i) = *(uint8_t *)(in + i);
|
||||
}
|
||||
return out;
|
||||
|
@ -109,9 +113,10 @@ void *memcpy(void *out, const void *in, size_t n) {
|
|||
int memcmp(const void *s1, const void *s2, size_t n) {
|
||||
const uint8_t *p1 = s1, *p2 = s2;
|
||||
for (int i = 0; i < n; i++) {
|
||||
if(*p1 != *p2)
|
||||
if (*p1 != *p2)
|
||||
return p1 - p2;
|
||||
p1++; p2++;
|
||||
p1++;
|
||||
p2++;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -1,17 +1,11 @@
|
|||
set(TEST_SOURCES
|
||||
stdio
|
||||
string
|
||||
)
|
||||
set(TEST_SOURCES stdio string)
|
||||
|
||||
foreach(TEST IN LISTS TEST_SOURCES)
|
||||
# TODO: Run tests in other configurations
|
||||
if(__PLATFORM_NATIVE__)
|
||||
add_executable(${TEST} ${TEST}.c)
|
||||
target_link_libraries(${TEST} 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
|
||||
if(__PLATFORM_NATIVE__)
|
||||
add_test(NAME ${TEST} COMMAND ${TEST})
|
||||
endif()
|
||||
target_link_libraries(${TEST} PRIVATE am_interface klib_interface klib)
|
||||
target_link_libraries(${TEST} PRIVATE am-native)
|
||||
add_test(NAME ${TEST} COMMAND ${TEST})
|
||||
endif()
|
||||
endforeach()
|
||||
|
|
Binary file not shown.
|
@ -1 +0,0 @@
|
|||
Subproject commit 2f559823a63cf6909d5a9e32dee47d6891caf553
|
751
flake.lock
751
flake.lock
|
@ -1,5 +1,112 @@
|
|||
{
|
||||
"nodes": {
|
||||
"am-kernels": {
|
||||
"inputs": {
|
||||
"flake-utils": "flake-utils",
|
||||
"nixpkgs": "nixpkgs",
|
||||
"pre-commit-hooks": "pre-commit-hooks",
|
||||
"ysyx-workbench": "ysyx-workbench"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1723617032,
|
||||
"narHash": "sha256-oL5Vx933Jhn+T9jn67wFbh8vy7w8OJNCn4DOOlX/r0U=",
|
||||
"ref": "dev",
|
||||
"rev": "3ee527c3de481e38767fffbd9e16bf48359fc638",
|
||||
"revCount": 78,
|
||||
"type": "git",
|
||||
"url": "https://git.xinyang.life/xin/am-kernels.git"
|
||||
},
|
||||
"original": {
|
||||
"ref": "dev",
|
||||
"type": "git",
|
||||
"url": "https://git.xinyang.life/xin/am-kernels.git"
|
||||
}
|
||||
},
|
||||
"diffu": {
|
||||
"inputs": {
|
||||
"flake-utils": "flake-utils_5",
|
||||
"nixpkgs": "nixpkgs_2",
|
||||
"nur-xin": "nur-xin_2",
|
||||
"pre-commit-hooks": "pre-commit-hooks_3"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1723627842,
|
||||
"narHash": "sha256-+Ovf1e5ESap4sGMsH945SkZLhyYUxGE7shKVl3Ue1CQ=",
|
||||
"ref": "refs/heads/master",
|
||||
"rev": "7b3881a9712bcb7bfea90614a44888ae5df6e849",
|
||||
"revCount": 17,
|
||||
"type": "git",
|
||||
"url": "https://git.xinyang.life/xin/diffu.git"
|
||||
},
|
||||
"original": {
|
||||
"type": "git",
|
||||
"url": "https://git.xinyang.life/xin/diffu.git"
|
||||
}
|
||||
},
|
||||
"flake-compat": {
|
||||
"flake": false,
|
||||
"locked": {
|
||||
"lastModified": 1696426674,
|
||||
"narHash": "sha256-kvjfFW7WAETZlt09AgDn1MrtKzP7t90Vf7vypd3OL1U=",
|
||||
"owner": "edolstra",
|
||||
"repo": "flake-compat",
|
||||
"rev": "0f9255e01c2351cc7d116c072cb317785dd33b33",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "edolstra",
|
||||
"repo": "flake-compat",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"flake-compat_2": {
|
||||
"flake": false,
|
||||
"locked": {
|
||||
"lastModified": 1696426674,
|
||||
"narHash": "sha256-kvjfFW7WAETZlt09AgDn1MrtKzP7t90Vf7vypd3OL1U=",
|
||||
"owner": "edolstra",
|
||||
"repo": "flake-compat",
|
||||
"rev": "0f9255e01c2351cc7d116c072cb317785dd33b33",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "edolstra",
|
||||
"repo": "flake-compat",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"flake-compat_3": {
|
||||
"flake": false,
|
||||
"locked": {
|
||||
"lastModified": 1696426674,
|
||||
"narHash": "sha256-kvjfFW7WAETZlt09AgDn1MrtKzP7t90Vf7vypd3OL1U=",
|
||||
"owner": "edolstra",
|
||||
"repo": "flake-compat",
|
||||
"rev": "0f9255e01c2351cc7d116c072cb317785dd33b33",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "edolstra",
|
||||
"repo": "flake-compat",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"flake-compat_4": {
|
||||
"flake": false,
|
||||
"locked": {
|
||||
"lastModified": 1696426674,
|
||||
"narHash": "sha256-kvjfFW7WAETZlt09AgDn1MrtKzP7t90Vf7vypd3OL1U=",
|
||||
"owner": "edolstra",
|
||||
"repo": "flake-compat",
|
||||
"rev": "0f9255e01c2351cc7d116c072cb317785dd33b33",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "edolstra",
|
||||
"repo": "flake-compat",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"flake-utils": {
|
||||
"inputs": {
|
||||
"systems": "systems"
|
||||
|
@ -18,6 +125,220 @@
|
|||
"type": "github"
|
||||
}
|
||||
},
|
||||
"flake-utils_2": {
|
||||
"inputs": {
|
||||
"systems": "systems_2"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1710146030,
|
||||
"narHash": "sha256-SZ5L6eA7HJ/nmkzGG7/ISclqe6oZdOZTNoesiInkXPQ=",
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"rev": "b1d9ab70662946ef0850d488da1c9019f3a9752a",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"flake-utils_3": {
|
||||
"inputs": {
|
||||
"systems": "systems_3"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1709126324,
|
||||
"narHash": "sha256-q6EQdSeUZOG26WelxqkmR7kArjgWCdw5sfJVHPH/7j8=",
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"rev": "d465f4819400de7c8d874d50b982301f28a84605",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"flake-utils_4": {
|
||||
"inputs": {
|
||||
"systems": "systems_4"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1710146030,
|
||||
"narHash": "sha256-SZ5L6eA7HJ/nmkzGG7/ISclqe6oZdOZTNoesiInkXPQ=",
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"rev": "b1d9ab70662946ef0850d488da1c9019f3a9752a",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"flake-utils_5": {
|
||||
"inputs": {
|
||||
"systems": "systems_5"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1710146030,
|
||||
"narHash": "sha256-SZ5L6eA7HJ/nmkzGG7/ISclqe6oZdOZTNoesiInkXPQ=",
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"rev": "b1d9ab70662946ef0850d488da1c9019f3a9752a",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"flake-utils_6": {
|
||||
"inputs": {
|
||||
"systems": "systems_6"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1710146030,
|
||||
"narHash": "sha256-SZ5L6eA7HJ/nmkzGG7/ISclqe6oZdOZTNoesiInkXPQ=",
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"rev": "b1d9ab70662946ef0850d488da1c9019f3a9752a",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"flake-utils_7": {
|
||||
"inputs": {
|
||||
"systems": "systems_7"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1709126324,
|
||||
"narHash": "sha256-q6EQdSeUZOG26WelxqkmR7kArjgWCdw5sfJVHPH/7j8=",
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"rev": "d465f4819400de7c8d874d50b982301f28a84605",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"flake-utils_8": {
|
||||
"inputs": {
|
||||
"systems": "systems_8"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1710146030,
|
||||
"narHash": "sha256-SZ5L6eA7HJ/nmkzGG7/ISclqe6oZdOZTNoesiInkXPQ=",
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"rev": "b1d9ab70662946ef0850d488da1c9019f3a9752a",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"gitignore": {
|
||||
"inputs": {
|
||||
"nixpkgs": [
|
||||
"am-kernels",
|
||||
"pre-commit-hooks",
|
||||
"nixpkgs"
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1709087332,
|
||||
"narHash": "sha256-HG2cCnktfHsKV0s4XW83gU3F57gaTljL9KNSuG6bnQs=",
|
||||
"owner": "hercules-ci",
|
||||
"repo": "gitignore.nix",
|
||||
"rev": "637db329424fd7e46cf4185293b9cc8c88c95394",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "hercules-ci",
|
||||
"repo": "gitignore.nix",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"gitignore_2": {
|
||||
"inputs": {
|
||||
"nixpkgs": [
|
||||
"am-kernels",
|
||||
"ysyx-workbench",
|
||||
"pre-commit-hooks",
|
||||
"nixpkgs"
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1709087332,
|
||||
"narHash": "sha256-HG2cCnktfHsKV0s4XW83gU3F57gaTljL9KNSuG6bnQs=",
|
||||
"owner": "hercules-ci",
|
||||
"repo": "gitignore.nix",
|
||||
"rev": "637db329424fd7e46cf4185293b9cc8c88c95394",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "hercules-ci",
|
||||
"repo": "gitignore.nix",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"gitignore_3": {
|
||||
"inputs": {
|
||||
"nixpkgs": [
|
||||
"diffu",
|
||||
"pre-commit-hooks",
|
||||
"nixpkgs"
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1709087332,
|
||||
"narHash": "sha256-HG2cCnktfHsKV0s4XW83gU3F57gaTljL9KNSuG6bnQs=",
|
||||
"owner": "hercules-ci",
|
||||
"repo": "gitignore.nix",
|
||||
"rev": "637db329424fd7e46cf4185293b9cc8c88c95394",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "hercules-ci",
|
||||
"repo": "gitignore.nix",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"gitignore_4": {
|
||||
"inputs": {
|
||||
"nixpkgs": [
|
||||
"pre-commit-hooks",
|
||||
"nixpkgs"
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1709087332,
|
||||
"narHash": "sha256-HG2cCnktfHsKV0s4XW83gU3F57gaTljL9KNSuG6bnQs=",
|
||||
"owner": "hercules-ci",
|
||||
"repo": "gitignore.nix",
|
||||
"rev": "637db329424fd7e46cf4185293b9cc8c88c95394",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "hercules-ci",
|
||||
"repo": "gitignore.nix",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixpkgs": {
|
||||
"locked": {
|
||||
"lastModified": 1709237383,
|
||||
|
@ -34,10 +355,306 @@
|
|||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixpkgs-circt162": {
|
||||
"locked": {
|
||||
"lastModified": 1705645507,
|
||||
"narHash": "sha256-tX3vipIAmNDBA8WNWG4oY4KyTfnm2YieTHO2BhG8ISA=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "7995cae3ad60e3d6931283d650d7f43d31aaa5c7",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "7995cae3ad60e3d6931283d650d7f43d31aaa5c7",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixpkgs-circt162_2": {
|
||||
"locked": {
|
||||
"lastModified": 1705645507,
|
||||
"narHash": "sha256-tX3vipIAmNDBA8WNWG4oY4KyTfnm2YieTHO2BhG8ISA=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "7995cae3ad60e3d6931283d650d7f43d31aaa5c7",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "7995cae3ad60e3d6931283d650d7f43d31aaa5c7",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixpkgs-stable": {
|
||||
"locked": {
|
||||
"lastModified": 1710695816,
|
||||
"narHash": "sha256-3Eh7fhEID17pv9ZxrPwCLfqXnYP006RKzSs0JptsN84=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "614b4613980a522ba49f0d194531beddbb7220d3",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "NixOS",
|
||||
"ref": "nixos-23.11",
|
||||
"repo": "nixpkgs",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixpkgs-stable_2": {
|
||||
"locked": {
|
||||
"lastModified": 1710695816,
|
||||
"narHash": "sha256-3Eh7fhEID17pv9ZxrPwCLfqXnYP006RKzSs0JptsN84=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "614b4613980a522ba49f0d194531beddbb7220d3",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "NixOS",
|
||||
"ref": "nixos-23.11",
|
||||
"repo": "nixpkgs",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixpkgs-stable_3": {
|
||||
"locked": {
|
||||
"lastModified": 1710695816,
|
||||
"narHash": "sha256-3Eh7fhEID17pv9ZxrPwCLfqXnYP006RKzSs0JptsN84=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "614b4613980a522ba49f0d194531beddbb7220d3",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "NixOS",
|
||||
"ref": "nixos-23.11",
|
||||
"repo": "nixpkgs",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixpkgs-stable_4": {
|
||||
"locked": {
|
||||
"lastModified": 1710695816,
|
||||
"narHash": "sha256-3Eh7fhEID17pv9ZxrPwCLfqXnYP006RKzSs0JptsN84=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "614b4613980a522ba49f0d194531beddbb7220d3",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "NixOS",
|
||||
"ref": "nixos-23.11",
|
||||
"repo": "nixpkgs",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixpkgs_2": {
|
||||
"locked": {
|
||||
"lastModified": 1711703276,
|
||||
"narHash": "sha256-iMUFArF0WCatKK6RzfUJknjem0H9m4KgorO/p3Dopkk=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "d8fe5e6c92d0d190646fb9f1056741a229980089",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "NixOS",
|
||||
"ref": "nixos-unstable",
|
||||
"repo": "nixpkgs",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixpkgs_3": {
|
||||
"locked": {
|
||||
"lastModified": 1709237383,
|
||||
"narHash": "sha256-cy6ArO4k5qTx+l5o+0mL9f5fa86tYUX3ozE1S+Txlds=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "1536926ef5621b09bba54035ae2bb6d806d72ac8",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "NixOS",
|
||||
"ref": "nixos-unstable",
|
||||
"repo": "nixpkgs",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nur-xin": {
|
||||
"inputs": {
|
||||
"nixpkgs": [
|
||||
"am-kernels",
|
||||
"ysyx-workbench",
|
||||
"nixpkgs"
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1721891452,
|
||||
"narHash": "sha256-2c9nDuXXARzoRXE67lte5kKBeFb1XmTNsvdiIbRUEgE=",
|
||||
"ref": "refs/heads/master",
|
||||
"rev": "de8ad578fc4fe527772cec23a7f660bde14c8570",
|
||||
"revCount": 152,
|
||||
"type": "git",
|
||||
"url": "https://git.xinyang.life/xin/nur.git"
|
||||
},
|
||||
"original": {
|
||||
"type": "git",
|
||||
"url": "https://git.xinyang.life/xin/nur.git"
|
||||
}
|
||||
},
|
||||
"nur-xin_2": {
|
||||
"inputs": {
|
||||
"nixpkgs": [
|
||||
"diffu",
|
||||
"nixpkgs"
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1721891452,
|
||||
"narHash": "sha256-2c9nDuXXARzoRXE67lte5kKBeFb1XmTNsvdiIbRUEgE=",
|
||||
"ref": "refs/heads/master",
|
||||
"rev": "de8ad578fc4fe527772cec23a7f660bde14c8570",
|
||||
"revCount": 152,
|
||||
"type": "git",
|
||||
"url": "https://git.xinyang.life/xin/nur.git"
|
||||
},
|
||||
"original": {
|
||||
"type": "git",
|
||||
"url": "https://git.xinyang.life/xin/nur.git"
|
||||
}
|
||||
},
|
||||
"nur-xin_3": {
|
||||
"inputs": {
|
||||
"nixpkgs": [
|
||||
"nixpkgs"
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1721891452,
|
||||
"narHash": "sha256-2c9nDuXXARzoRXE67lte5kKBeFb1XmTNsvdiIbRUEgE=",
|
||||
"ref": "refs/heads/master",
|
||||
"rev": "de8ad578fc4fe527772cec23a7f660bde14c8570",
|
||||
"revCount": 152,
|
||||
"type": "git",
|
||||
"url": "https://git.xinyang.life/xin/nur.git"
|
||||
},
|
||||
"original": {
|
||||
"type": "git",
|
||||
"url": "https://git.xinyang.life/xin/nur.git"
|
||||
}
|
||||
},
|
||||
"pre-commit-hooks": {
|
||||
"inputs": {
|
||||
"flake-compat": "flake-compat",
|
||||
"flake-utils": "flake-utils_2",
|
||||
"gitignore": "gitignore",
|
||||
"nixpkgs": [
|
||||
"am-kernels",
|
||||
"nixpkgs"
|
||||
],
|
||||
"nixpkgs-stable": "nixpkgs-stable"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1712055707,
|
||||
"narHash": "sha256-4XLvuSIDZJGS17xEwSrNuJLL7UjDYKGJSbK1WWX2AK8=",
|
||||
"owner": "cachix",
|
||||
"repo": "pre-commit-hooks.nix",
|
||||
"rev": "e35aed5fda3cc79f88ed7f1795021e559582093a",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "cachix",
|
||||
"repo": "pre-commit-hooks.nix",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"pre-commit-hooks_2": {
|
||||
"inputs": {
|
||||
"flake-compat": "flake-compat_2",
|
||||
"flake-utils": "flake-utils_4",
|
||||
"gitignore": "gitignore_2",
|
||||
"nixpkgs": [
|
||||
"am-kernels",
|
||||
"ysyx-workbench",
|
||||
"nixpkgs"
|
||||
],
|
||||
"nixpkgs-stable": "nixpkgs-stable_2"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1712055707,
|
||||
"narHash": "sha256-4XLvuSIDZJGS17xEwSrNuJLL7UjDYKGJSbK1WWX2AK8=",
|
||||
"owner": "cachix",
|
||||
"repo": "pre-commit-hooks.nix",
|
||||
"rev": "e35aed5fda3cc79f88ed7f1795021e559582093a",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "cachix",
|
||||
"repo": "pre-commit-hooks.nix",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"pre-commit-hooks_3": {
|
||||
"inputs": {
|
||||
"flake-compat": "flake-compat_3",
|
||||
"flake-utils": "flake-utils_6",
|
||||
"gitignore": "gitignore_3",
|
||||
"nixpkgs": [
|
||||
"diffu",
|
||||
"nixpkgs"
|
||||
],
|
||||
"nixpkgs-stable": "nixpkgs-stable_3"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1712055707,
|
||||
"narHash": "sha256-4XLvuSIDZJGS17xEwSrNuJLL7UjDYKGJSbK1WWX2AK8=",
|
||||
"owner": "cachix",
|
||||
"repo": "pre-commit-hooks.nix",
|
||||
"rev": "e35aed5fda3cc79f88ed7f1795021e559582093a",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "cachix",
|
||||
"repo": "pre-commit-hooks.nix",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"pre-commit-hooks_4": {
|
||||
"inputs": {
|
||||
"flake-compat": "flake-compat_4",
|
||||
"flake-utils": "flake-utils_8",
|
||||
"gitignore": "gitignore_4",
|
||||
"nixpkgs": [
|
||||
"nixpkgs"
|
||||
],
|
||||
"nixpkgs-stable": "nixpkgs-stable_4"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1712055707,
|
||||
"narHash": "sha256-4XLvuSIDZJGS17xEwSrNuJLL7UjDYKGJSbK1WWX2AK8=",
|
||||
"owner": "cachix",
|
||||
"repo": "pre-commit-hooks.nix",
|
||||
"rev": "e35aed5fda3cc79f88ed7f1795021e559582093a",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "cachix",
|
||||
"repo": "pre-commit-hooks.nix",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"root": {
|
||||
"inputs": {
|
||||
"flake-utils": "flake-utils",
|
||||
"nixpkgs": "nixpkgs"
|
||||
"am-kernels": "am-kernels",
|
||||
"diffu": "diffu",
|
||||
"flake-utils": "flake-utils_7",
|
||||
"nixpkgs": "nixpkgs_3",
|
||||
"nixpkgs-circt162": "nixpkgs-circt162_2",
|
||||
"nur-xin": "nur-xin_3",
|
||||
"pre-commit-hooks": "pre-commit-hooks_4"
|
||||
}
|
||||
},
|
||||
"systems": {
|
||||
|
@ -54,6 +671,136 @@
|
|||
"repo": "default",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"systems_2": {
|
||||
"locked": {
|
||||
"lastModified": 1681028828,
|
||||
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
|
||||
"owner": "nix-systems",
|
||||
"repo": "default",
|
||||
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "nix-systems",
|
||||
"repo": "default",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"systems_3": {
|
||||
"locked": {
|
||||
"lastModified": 1681028828,
|
||||
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
|
||||
"owner": "nix-systems",
|
||||
"repo": "default",
|
||||
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "nix-systems",
|
||||
"repo": "default",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"systems_4": {
|
||||
"locked": {
|
||||
"lastModified": 1681028828,
|
||||
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
|
||||
"owner": "nix-systems",
|
||||
"repo": "default",
|
||||
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "nix-systems",
|
||||
"repo": "default",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"systems_5": {
|
||||
"locked": {
|
||||
"lastModified": 1681028828,
|
||||
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
|
||||
"owner": "nix-systems",
|
||||
"repo": "default",
|
||||
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "nix-systems",
|
||||
"repo": "default",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"systems_6": {
|
||||
"locked": {
|
||||
"lastModified": 1681028828,
|
||||
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
|
||||
"owner": "nix-systems",
|
||||
"repo": "default",
|
||||
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "nix-systems",
|
||||
"repo": "default",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"systems_7": {
|
||||
"locked": {
|
||||
"lastModified": 1681028828,
|
||||
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
|
||||
"owner": "nix-systems",
|
||||
"repo": "default",
|
||||
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "nix-systems",
|
||||
"repo": "default",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"systems_8": {
|
||||
"locked": {
|
||||
"lastModified": 1681028828,
|
||||
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
|
||||
"owner": "nix-systems",
|
||||
"repo": "default",
|
||||
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "nix-systems",
|
||||
"repo": "default",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"ysyx-workbench": {
|
||||
"inputs": {
|
||||
"flake-utils": "flake-utils_3",
|
||||
"nixpkgs": [
|
||||
"am-kernels",
|
||||
"nixpkgs"
|
||||
],
|
||||
"nixpkgs-circt162": "nixpkgs-circt162",
|
||||
"nur-xin": "nur-xin",
|
||||
"pre-commit-hooks": "pre-commit-hooks_2"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1723551098,
|
||||
"narHash": "sha256-/AnVxufgQoAuvNBSKm0BG+tTS++/HuaNoW+loroSQig=",
|
||||
"ref": "refs/heads/master",
|
||||
"rev": "8ee1551dc2857091fca6456c1367aab7090899fe",
|
||||
"revCount": 119,
|
||||
"type": "git",
|
||||
"url": "https://git.xinyang.life/xin/ysyx-workbench"
|
||||
},
|
||||
"original": {
|
||||
"type": "git",
|
||||
"url": "https://git.xinyang.life/xin/ysyx-workbench"
|
||||
}
|
||||
}
|
||||
},
|
||||
"root": "root",
|
||||
|
|
145
flake.nix
145
flake.nix
|
@ -1,14 +1,35 @@
|
|||
{
|
||||
inputs = {
|
||||
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
|
||||
nixpkgs-circt162.url = "github:NixOS/nixpkgs/7995cae3ad60e3d6931283d650d7f43d31aaa5c7";
|
||||
flake-utils.url = "github:numtide/flake-utils";
|
||||
pre-commit-hooks = {
|
||||
url = "github:cachix/pre-commit-hooks.nix";
|
||||
inputs.nixpkgs.follows = "nixpkgs";
|
||||
};
|
||||
nur-xin = {
|
||||
url = "git+https://git.xinyang.life/xin/nur.git";
|
||||
inputs.nixpkgs.follows = "nixpkgs";
|
||||
};
|
||||
diffu.url = "git+https://git.xinyang.life/xin/diffu.git";
|
||||
am-kernels.url = "git+https://git.xinyang.life/xin/am-kernels.git?ref=dev";
|
||||
};
|
||||
|
||||
outputs = { self, ... }@inputs: with inputs;
|
||||
outputs = { self, flake-utils, nixpkgs, nixpkgs-circt162, pre-commit-hooks, nur-xin, diffu, am-kernels }@inputs:
|
||||
flake-utils.lib.eachDefaultSystem (system:
|
||||
let
|
||||
pkgs = nixpkgs.legacyPackages.${system};
|
||||
crossPkgs = import nixpkgs {
|
||||
pkgs = import nixpkgs {
|
||||
inherit system;
|
||||
config.allowUnfree = true;
|
||||
overlays = [
|
||||
(self: super: {
|
||||
nvboard = nur-xin.legacyPackages.${system}.nvboard;
|
||||
mini-gdbstub = nur-xin.legacyPackages.${system}.mini-gdbstub;
|
||||
})
|
||||
];
|
||||
};
|
||||
|
||||
rv32CrossConfig = import nixpkgs {
|
||||
localSystem = system;
|
||||
crossSystem = {
|
||||
config = "riscv32-none-elf";
|
||||
|
@ -20,39 +41,107 @@
|
|||
};
|
||||
in
|
||||
{
|
||||
packages.nemu = pkgs.callPackage ./nemu { am-kernels = self.packages.${system}.am-kernels; };
|
||||
packages.abstract-machine = crossPkgs.callPackage ./abstract-machine { isa = "riscv"; platform = "nemu"; };
|
||||
|
||||
packages.am-kernels = crossPkgs.stdenv.mkDerivation rec {
|
||||
pname = "am-kernels-cmake";
|
||||
version = "2024.02.18";
|
||||
|
||||
src = ./am-kernels;
|
||||
|
||||
nativeBuildInputs = [
|
||||
pkgs.cmake
|
||||
];
|
||||
|
||||
cmakeFlags = [
|
||||
(pkgs.lib.cmakeFeature "ISA" "riscv")
|
||||
(pkgs.lib.cmakeFeature "PLATFORM" "nemu")
|
||||
(pkgs.lib.cmakeFeature "CMAKE_INSTALL_DATADIR" "share")
|
||||
];
|
||||
|
||||
buildInputs = [
|
||||
# SDL2
|
||||
self.packages.${system}.abstract-machine
|
||||
];
|
||||
checks = {
|
||||
pre-commit-check = pre-commit-hooks.lib.${system}.run {
|
||||
src = ./.;
|
||||
hooks = {
|
||||
trim-trailing-whitespace.enable = true;
|
||||
end-of-file-fixer.enable = true;
|
||||
cmake-format.enable = true;
|
||||
clang-format = {
|
||||
enable = true;
|
||||
types_or = pkgs.lib.mkForce [ "c" "c++" ];
|
||||
};
|
||||
scalafmt = {
|
||||
enable = true;
|
||||
package = pkgs.scalafmt;
|
||||
name = "Scalafmt";
|
||||
types = [ "scala" ];
|
||||
entry = "${pkgs.scalafmt}/bin/scalafmt --non-interactive";
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
packages = rec {
|
||||
abstract-machine = pkgs.callPackage ./abstract-machine { isa = "native"; };
|
||||
nemu = pkgs.callPackage ./nemu { };
|
||||
nemu-lib = pkgs.callPackage ./nemu { };
|
||||
|
||||
rv32Cross = rec {
|
||||
abstract-machine = rv32CrossConfig.callPackage ./abstract-machine { isa = "riscv"; platform = [ "nemu" "npc" ]; };
|
||||
};
|
||||
};
|
||||
|
||||
devShells.nemu = pkgs.mkShell {
|
||||
packages = with pkgs; [
|
||||
clang-tools
|
||||
gdb
|
||||
gef
|
||||
SDL2
|
||||
gnumake
|
||||
pkg-config
|
||||
flex
|
||||
bison
|
||||
dtc
|
||||
|
||||
readline
|
||||
libllvm
|
||||
mini-gdbstub
|
||||
];
|
||||
inputsFrom = [
|
||||
self.packages.${system}.nemu
|
||||
];
|
||||
NEMU_HOME = "/home/xin/repo/ysyx-workbench/nemu";
|
||||
# NEMU_IMAGES_PATH = self.packages.${system}.rv32Cross.am-kernels-nemu + "/share/am-kernels";
|
||||
};
|
||||
|
||||
devShells.npc = pkgs.mkShell.override { stdenv = pkgs.ccacheStdenv; } {
|
||||
inherit (self.checks.${system}.pre-commit-check) shellHook;
|
||||
CHISEL_FIRTOOL_PATH = "${nixpkgs-circt162.legacyPackages.${system}.circt}/bin";
|
||||
# NPC_IMAGES_PATH = "${self.packages.${system}.rv32Cross.am-kernels-npc}/share/am-kernels";
|
||||
packages = with pkgs; [
|
||||
clang-tools
|
||||
cmake
|
||||
coursier
|
||||
espresso
|
||||
bloop
|
||||
|
||||
gdb
|
||||
jre
|
||||
|
||||
gtkwave
|
||||
];
|
||||
|
||||
nativeBuildInputs = with pkgs; [
|
||||
cmake
|
||||
ninja
|
||||
sbt
|
||||
nvboard
|
||||
nixpkgs-circt162.legacyPackages.${system}.circt
|
||||
yosys
|
||||
cli11
|
||||
flex
|
||||
bison
|
||||
verilator
|
||||
];
|
||||
|
||||
buildInputs = with pkgs; [
|
||||
spdlog
|
||||
nvboard
|
||||
openssl
|
||||
libllvm
|
||||
libxml2
|
||||
readline
|
||||
mini-gdbstub
|
||||
] ++ self.checks.${system}.pre-commit-check.enabledPackages;
|
||||
};
|
||||
|
||||
devShells.difftest = pkgs.mkShell {
|
||||
packages = [
|
||||
diffu.packages.${system}.default
|
||||
am-kernels.packages.${system}.rv32Cross.am-kernels-npc
|
||||
self.packages.${system}.nemu-lib
|
||||
];
|
||||
};
|
||||
}
|
||||
);
|
||||
|
|
|
@ -1,3 +0,0 @@
|
|||
---
|
||||
Language: Cpp
|
||||
BasedOnStyle: LLVM
|
1
nemu/.gitignore
vendored
1
nemu/.gitignore
vendored
|
@ -9,6 +9,7 @@ build/
|
|||
.envrc
|
||||
.metals/
|
||||
.vscode/
|
||||
.zed/
|
||||
compile_commands.json
|
||||
|
||||
### C ###
|
||||
|
|
24
nemu/Kconfig
24
nemu/Kconfig
|
@ -126,6 +126,26 @@ endmenu
|
|||
|
||||
menu "Testing and Debugging"
|
||||
|
||||
choice
|
||||
prompt "Choose log level"
|
||||
default LOG_TRACE
|
||||
config LOG_TRACE
|
||||
bool "trace"
|
||||
config LOG_INFO
|
||||
bool "info"
|
||||
config LOG_WARNING
|
||||
bool "warning"
|
||||
config LOG_ERROR
|
||||
bool "error"
|
||||
endchoice
|
||||
|
||||
config LOG_LEVEL
|
||||
int
|
||||
default 1 if LOG_ERROR
|
||||
default 2 if LOG_WARNING
|
||||
default 3 if LOG_INFO
|
||||
default 4 if LOG_TRACE
|
||||
default 0
|
||||
|
||||
config TRACE
|
||||
bool "Enable tracer"
|
||||
|
@ -160,7 +180,7 @@ config ITRACE_BUFFER
|
|||
default 10
|
||||
|
||||
config MTRACE
|
||||
depends on TRACE && TARGET_NATIVE_ELF && ENGINE_INTERPRETER
|
||||
depends on TRACE && LOG_TRACE
|
||||
bool "Enable memory tracing"
|
||||
default n
|
||||
|
||||
|
@ -178,7 +198,7 @@ config MTRACE_RANGE_MAX
|
|||
default 10
|
||||
|
||||
config FTRACE
|
||||
depends on TRACE && TARGET_NATIVE_ELF && ENGINE_INTERPRETER
|
||||
depends on TRACE && TARGET_NATIVE_ELF && ENGINE_INTERPRETER && LOG_TRACE
|
||||
bool "Enable function tracing"
|
||||
default n
|
||||
|
||||
|
|
|
@ -83,7 +83,7 @@ $(IMAGES): %: %.bin $(BINARY)
|
|||
@echo + TEST $(notdir $<)
|
||||
@$(BINARY) -b $< >/dev/null 2>&1 || printf "\t%14s\n" $(notdir $<) >> $(RESULT)
|
||||
|
||||
integration-tests: $(IMAGES)
|
||||
integration-tests: $(IMAGES)
|
||||
@printf "$(COLOR_BLUE)INTEGRATION TEST:$(COLOR_NONE)\n\tALL: %s\n\tFAILED: %s\n" $(words $(IMAGES)) $(shell wc -l $(RESULT) | cut -f1 -d' ')
|
||||
@test ! -s $(RESULT) || printf "$(COLOR_RED)FAILED:$(COLOR_NONE)\n"
|
||||
@cat $(RESULT)
|
||||
|
|
87
nemu/configs/libdefconfig
Normal file
87
nemu/configs/libdefconfig
Normal file
|
@ -0,0 +1,87 @@
|
|||
#
|
||||
# Automatically generated file; DO NOT EDIT.
|
||||
# NEMU Configuration Menu
|
||||
#
|
||||
# CONFIG_ISA_x86 is not set
|
||||
# CONFIG_ISA_mips32 is not set
|
||||
CONFIG_ISA_riscv=y
|
||||
# CONFIG_ISA_loongarch32r is not set
|
||||
CONFIG_ISA="riscv32"
|
||||
|
||||
#
|
||||
# ISA-dependent Options for riscv
|
||||
#
|
||||
# CONFIG_RV64 is not set
|
||||
# CONFIG_RVE is not set
|
||||
# end of ISA-dependent Options for riscv
|
||||
|
||||
CONFIG_ENGINE_INTERPRETER=y
|
||||
CONFIG_ENGINE="interpreter"
|
||||
CONFIG_MODE_SYSTEM=y
|
||||
# CONFIG_TARGET_NATIVE_ELF is not set
|
||||
CONFIG_TARGET_SHARE=y
|
||||
# CONFIG_TARGET_AM is not set
|
||||
|
||||
#
|
||||
# Build Options
|
||||
#
|
||||
CONFIG_CC_GCC=y
|
||||
# CONFIG_CC_GPP is not set
|
||||
# CONFIG_CC_CLANG is not set
|
||||
CONFIG_CC="gcc"
|
||||
# CONFIG_CC_O0 is not set
|
||||
# CONFIG_CC_O1 is not set
|
||||
CONFIG_CC_O2=y
|
||||
# CONFIG_CC_O3 is not set
|
||||
CONFIG_CC_OPT="-O2"
|
||||
# CONFIG_CC_LTO is not set
|
||||
# CONFIG_CC_DEBUG is not set
|
||||
# CONFIG_CC_ASAN is not set
|
||||
# end of Build Options
|
||||
|
||||
#
|
||||
# Testing and Debugging
|
||||
#
|
||||
CONFIG_LOG_TRACE=y
|
||||
# CONFIG_LOG_INFO is not set
|
||||
# CONFIG_LOG_WARNING is not set
|
||||
# CONFIG_LOG_ERROR is not set
|
||||
CONFIG_LOG_LEVEL=4
|
||||
CONFIG_TRACE=y
|
||||
CONFIG_TRACE_START=0
|
||||
CONFIG_TRACE_END=10000
|
||||
# CONFIG_MTRACE is not set
|
||||
CONFIG_DIFFTEST_REF_PATH="none"
|
||||
CONFIG_DIFFTEST_REF_NAME="none"
|
||||
# end of Testing and Debugging
|
||||
|
||||
#
|
||||
# Memory Configuration
|
||||
#
|
||||
CONFIG_MBASE=0x80000000
|
||||
CONFIG_MSIZE=0x8000000
|
||||
CONFIG_PC_RESET_OFFSET=0
|
||||
# CONFIG_PMEM_MALLOC is not set
|
||||
CONFIG_PMEM_GARRAY=y
|
||||
CONFIG_MEM_RANDOM=y
|
||||
# end of Memory Configuration
|
||||
|
||||
CONFIG_DEVICE=y
|
||||
CONFIG_HAS_SERIAL=y
|
||||
CONFIG_SERIAL_MMIO=0x10000000
|
||||
# CONFIG_SERIAL_INPUT_FIFO is not set
|
||||
CONFIG_HAS_TIMER=y
|
||||
CONFIG_RTC_MMIO=0x10001000
|
||||
# CONFIG_HAS_KEYBOARD is not set
|
||||
# CONFIG_HAS_VGA is not set
|
||||
# CONFIG_HAS_AUDIO is not set
|
||||
# CONFIG_HAS_DISK is not set
|
||||
# CONFIG_HAS_SDCARD is not set
|
||||
|
||||
#
|
||||
# Miscellaneous
|
||||
#
|
||||
CONFIG_TIMER_GETTIMEOFDAY=y
|
||||
# CONFIG_TIMER_CLOCK_GETTIME is not set
|
||||
CONFIG_RT_CHECK=y
|
||||
# end of Miscellaneous
|
72
nemu/configs/riscv32-lib_defconfig
Normal file
72
nemu/configs/riscv32-lib_defconfig
Normal file
|
@ -0,0 +1,72 @@
|
|||
#
|
||||
# Automatically generated file; DO NOT EDIT.
|
||||
# NEMU Configuration Menu
|
||||
#
|
||||
# CONFIG_ISA_x86 is not set
|
||||
# CONFIG_ISA_mips32 is not set
|
||||
CONFIG_ISA_riscv=y
|
||||
# CONFIG_ISA_loongarch32r is not set
|
||||
CONFIG_ISA="riscv32"
|
||||
|
||||
#
|
||||
# ISA-dependent Options for riscv
|
||||
#
|
||||
# CONFIG_RV64 is not set
|
||||
# CONFIG_RVE is not set
|
||||
# end of ISA-dependent Options for riscv
|
||||
|
||||
CONFIG_ENGINE_INTERPRETER=y
|
||||
CONFIG_ENGINE="interpreter"
|
||||
CONFIG_MODE_SYSTEM=y
|
||||
# CONFIG_TARGET_NATIVE_ELF is not set
|
||||
CONFIG_TARGET_SHARE=y
|
||||
# CONFIG_TARGET_AM is not set
|
||||
|
||||
#
|
||||
# Build Options
|
||||
#
|
||||
CONFIG_CC_GCC=y
|
||||
# CONFIG_CC_GPP is not set
|
||||
# CONFIG_CC_CLANG is not set
|
||||
CONFIG_CC="gcc"
|
||||
# CONFIG_CC_O0 is not set
|
||||
# CONFIG_CC_O1 is not set
|
||||
CONFIG_CC_O2=y
|
||||
# CONFIG_CC_O3 is not set
|
||||
CONFIG_CC_OPT="-O2"
|
||||
CONFIG_CC_LTO=y
|
||||
CONFIG_CC_DEBUG=y
|
||||
# CONFIG_CC_ASAN is not set
|
||||
# end of Build Options
|
||||
|
||||
#
|
||||
# Testing and Debugging
|
||||
#
|
||||
CONFIG_LOG_TRACE=y
|
||||
# CONFIG_LOG_INFO is not set
|
||||
# CONFIG_LOG_WARNING is not set
|
||||
# CONFIG_LOG_ERROR is not set
|
||||
CONFIG_LOG_LEVEL=4
|
||||
# CONFIG_TRACE is not set
|
||||
CONFIG_DIFFTEST_REF_PATH="none"
|
||||
CONFIG_DIFFTEST_REF_NAME="none"
|
||||
# end of Testing and Debugging
|
||||
|
||||
#
|
||||
# Memory Configuration
|
||||
#
|
||||
CONFIG_MBASE=0x80000000
|
||||
CONFIG_MSIZE=0x8000000
|
||||
CONFIG_PC_RESET_OFFSET=0
|
||||
# CONFIG_PMEM_MALLOC is not set
|
||||
CONFIG_PMEM_GARRAY=y
|
||||
CONFIG_MEM_RANDOM=y
|
||||
# end of Memory Configuration
|
||||
|
||||
#
|
||||
# Miscellaneous
|
||||
#
|
||||
CONFIG_TIMER_GETTIMEOFDAY=y
|
||||
# CONFIG_TIMER_CLOCK_GETTIME is not set
|
||||
CONFIG_RT_CHECK=y
|
||||
# end of Miscellaneous
|
|
@ -1,17 +1,26 @@
|
|||
{ pkgs,
|
||||
lib,
|
||||
stdenv,
|
||||
am-kernels,
|
||||
dtc
|
||||
{ stdenv
|
||||
, lib
|
||||
, gnumake
|
||||
, pkg-config
|
||||
, bison
|
||||
, flex
|
||||
, dtc
|
||||
, check
|
||||
, mini-gdbstub
|
||||
, readline
|
||||
, libllvm
|
||||
, SDL2
|
||||
, am-kernels ? ""
|
||||
, defconfig ? "alldefconfig"
|
||||
}:
|
||||
|
||||
stdenv.mkDerivation rec {
|
||||
pname = "nemu";
|
||||
version = "2024-03-02";
|
||||
version = "2024-08-15";
|
||||
|
||||
src = ./.;
|
||||
|
||||
nativeBuildInputs = with pkgs; [
|
||||
nativeBuildInputs = [
|
||||
gnumake
|
||||
pkg-config
|
||||
flex
|
||||
|
@ -19,45 +28,44 @@ stdenv.mkDerivation rec {
|
|||
dtc
|
||||
];
|
||||
|
||||
buildInputs = with pkgs; [
|
||||
buildInputs = [
|
||||
SDL2
|
||||
readline
|
||||
libllvm
|
||||
mini-gdbstub
|
||||
];
|
||||
|
||||
checkInputs = [
|
||||
pkgs.check
|
||||
check
|
||||
am-kernels
|
||||
];
|
||||
|
||||
configurePhase = ''
|
||||
export NEMU_HOME=$(pwd)
|
||||
make alldefconfig
|
||||
make ${defconfig}
|
||||
'';
|
||||
|
||||
buildPhase = ''
|
||||
make
|
||||
'';
|
||||
|
||||
doCheck = true;
|
||||
doCheck = (am-kernels != "");
|
||||
checkPhase = ''
|
||||
export IMAGES_PATH=${am-kernels}/share/binary
|
||||
export NEMU_IMAGES_PATH=${am-kernels}/share/am-kernels
|
||||
make test
|
||||
'';
|
||||
|
||||
installPhase = ''
|
||||
mkdir -p $out/bin
|
||||
if [ -d "./lib" ] && [ "$(ls -A ./lib)" ]; then
|
||||
mkdir -p "$out/lib"
|
||||
fi
|
||||
if [ -d "./bin" ] && [ "$(ls -A ./bin)" ]; then
|
||||
mkdir -p $out/bin
|
||||
fi
|
||||
make PREFIX=$out install
|
||||
'';
|
||||
|
||||
shellHook = ''
|
||||
export NEMU_HOME=$(pwd)
|
||||
export IMAGES_PATH=${am-kernels}/share/binary
|
||||
'';
|
||||
|
||||
meta = with lib; {
|
||||
description = "NJU EMUlator, a full system x86/mips32/riscv32/riscv64 emulator for teaching";
|
||||
homepage = "https://github.com/NJU-ProjectN/nemu.git";
|
||||
license = with licenses; [ ];
|
||||
maintainers = with maintainers; [ ];
|
||||
};
|
||||
}
|
||||
|
|
9
nemu/include/config.h
Normal file
9
nemu/include/config.h
Normal file
|
@ -0,0 +1,9 @@
|
|||
#ifndef __NEMU_CONFIG_H__
|
||||
#define __NEMU_CONFIG_H__
|
||||
|
||||
extern char *log_file = NULL;
|
||||
extern char *elf_file = NULL;
|
||||
extern char *img_file = NULL;
|
||||
extern bool enable_gdbstub = false;
|
||||
|
||||
#endif // __NEMU_CONFIG_H__
|
|
@ -17,8 +17,18 @@
|
|||
#define __CPU_CPU_H__
|
||||
|
||||
#include <common.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#include <gdbstub.h>
|
||||
#include <stddef.h>
|
||||
|
||||
typedef struct {
|
||||
size_t addr;
|
||||
bp_type_t type;
|
||||
} breakpoint_t;
|
||||
|
||||
void cpu_exec(uint64_t n);
|
||||
breakpoint_t *cpu_exec_with_bp(uint64_t n, breakpoint_t *bp, size_t len);
|
||||
|
||||
void set_nemu_state(int state, vaddr_t pc, int halt_ret);
|
||||
void invalid_inst(vaddr_t thispc);
|
||||
|
|
|
@ -16,39 +16,62 @@
|
|||
#ifndef __CPU_DECODE_H__
|
||||
#define __CPU_DECODE_H__
|
||||
|
||||
#include "types.h"
|
||||
#include <isa.h>
|
||||
|
||||
typedef enum { INST_NORMAL, INST_MEM_WRITE, INST_MEM_READ } inst_type_t;
|
||||
|
||||
typedef union {
|
||||
paddr_t rmem;
|
||||
paddr_t wmem;
|
||||
} inst_type_op;
|
||||
|
||||
typedef struct Decode {
|
||||
vaddr_t pc;
|
||||
vaddr_t snpc; // static next pc
|
||||
vaddr_t dnpc; // dynamic next pc
|
||||
inst_type_t inst_type;
|
||||
inst_type_op inst_value;
|
||||
ISADecodeInfo isa;
|
||||
} Decode;
|
||||
|
||||
// --- pattern matching mechanism ---
|
||||
__attribute__((always_inline))
|
||||
static inline void pattern_decode(const char *str, int len,
|
||||
uint64_t *key, uint64_t *mask, uint64_t *shift) {
|
||||
__attribute__((always_inline)) static inline void
|
||||
pattern_decode(const char *str, int len, uint64_t *key, uint64_t *mask,
|
||||
uint64_t *shift) {
|
||||
uint64_t __key = 0, __mask = 0, __shift = 0;
|
||||
#define macro(i) \
|
||||
if ((i) >= len) goto finish; \
|
||||
else { \
|
||||
char c = str[i]; \
|
||||
if (c != ' ') { \
|
||||
Assert(c == '0' || c == '1' || c == '?', \
|
||||
"invalid character '%c' in pattern string", c); \
|
||||
__key = (__key << 1) | (c == '1' ? 1 : 0); \
|
||||
__mask = (__mask << 1) | (c == '?' ? 0 : 1); \
|
||||
__shift = (c == '?' ? __shift + 1 : 0); \
|
||||
} \
|
||||
#define macro(i) \
|
||||
if ((i) >= len) \
|
||||
goto finish; \
|
||||
else { \
|
||||
char c = str[i]; \
|
||||
if (c != ' ') { \
|
||||
Assert(c == '0' || c == '1' || c == '?', \
|
||||
"invalid character '%c' in pattern string", c); \
|
||||
__key = (__key << 1) | (c == '1' ? 1 : 0); \
|
||||
__mask = (__mask << 1) | (c == '?' ? 0 : 1); \
|
||||
__shift = (c == '?' ? __shift + 1 : 0); \
|
||||
} \
|
||||
}
|
||||
|
||||
#define macro2(i) macro(i); macro((i) + 1)
|
||||
#define macro4(i) macro2(i); macro2((i) + 2)
|
||||
#define macro8(i) macro4(i); macro4((i) + 4)
|
||||
#define macro16(i) macro8(i); macro8((i) + 8)
|
||||
#define macro32(i) macro16(i); macro16((i) + 16)
|
||||
#define macro64(i) macro32(i); macro32((i) + 32)
|
||||
#define macro2(i) \
|
||||
macro(i); \
|
||||
macro((i) + 1)
|
||||
#define macro4(i) \
|
||||
macro2(i); \
|
||||
macro2((i) + 2)
|
||||
#define macro8(i) \
|
||||
macro4(i); \
|
||||
macro4((i) + 4)
|
||||
#define macro16(i) \
|
||||
macro8(i); \
|
||||
macro8((i) + 8)
|
||||
#define macro32(i) \
|
||||
macro16(i); \
|
||||
macro16((i) + 16)
|
||||
#define macro64(i) \
|
||||
macro32(i); \
|
||||
macro32((i) + 32)
|
||||
macro64(0);
|
||||
panic("pattern too long");
|
||||
#undef macro
|
||||
|
@ -58,21 +81,24 @@ finish:
|
|||
*shift = __shift;
|
||||
}
|
||||
|
||||
__attribute__((always_inline))
|
||||
static inline void pattern_decode_hex(const char *str, int len,
|
||||
uint64_t *key, uint64_t *mask, uint64_t *shift) {
|
||||
__attribute__((always_inline)) static inline void
|
||||
pattern_decode_hex(const char *str, int len, uint64_t *key, uint64_t *mask,
|
||||
uint64_t *shift) {
|
||||
uint64_t __key = 0, __mask = 0, __shift = 0;
|
||||
#define macro(i) \
|
||||
if ((i) >= len) goto finish; \
|
||||
else { \
|
||||
char c = str[i]; \
|
||||
if (c != ' ') { \
|
||||
Assert((c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || c == '?', \
|
||||
"invalid character '%c' in pattern string", c); \
|
||||
__key = (__key << 4) | (c == '?' ? 0 : (c >= '0' && c <= '9') ? c - '0' : c - 'a' + 10); \
|
||||
__mask = (__mask << 4) | (c == '?' ? 0 : 0xf); \
|
||||
__shift = (c == '?' ? __shift + 4 : 0); \
|
||||
} \
|
||||
#define macro(i) \
|
||||
if ((i) >= len) \
|
||||
goto finish; \
|
||||
else { \
|
||||
char c = str[i]; \
|
||||
if (c != ' ') { \
|
||||
Assert((c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || c == '?', \
|
||||
"invalid character '%c' in pattern string", c); \
|
||||
__key = (__key << 4) | (c == '?' ? 0 \
|
||||
: (c >= '0' && c <= '9') ? c - '0' \
|
||||
: c - 'a' + 10); \
|
||||
__mask = (__mask << 4) | (c == '?' ? 0 : 0xf); \
|
||||
__shift = (c == '?' ? __shift + 4 : 0); \
|
||||
} \
|
||||
}
|
||||
|
||||
macro16(0);
|
||||
|
@ -84,18 +110,22 @@ finish:
|
|||
*shift = __shift;
|
||||
}
|
||||
|
||||
|
||||
// --- pattern matching wrappers for decode ---
|
||||
#define INSTPAT(pattern, ...) do { \
|
||||
uint64_t key, mask, shift; \
|
||||
pattern_decode(pattern, STRLEN(pattern), &key, &mask, &shift); \
|
||||
if ((((uint64_t)INSTPAT_INST(s) >> shift) & mask) == key) { \
|
||||
INSTPAT_MATCH(s, ##__VA_ARGS__); \
|
||||
goto *(__instpat_end); \
|
||||
} \
|
||||
} while (0)
|
||||
#define INSTPAT(pattern, ...) \
|
||||
do { \
|
||||
uint64_t key, mask, shift; \
|
||||
pattern_decode(pattern, STRLEN(pattern), &key, &mask, &shift); \
|
||||
if ((((uint64_t)INSTPAT_INST(s) >> shift) & mask) == key) { \
|
||||
INSTPAT_MATCH(s, ##__VA_ARGS__); \
|
||||
goto *(__instpat_end); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define INSTPAT_START(name) { const void ** __instpat_end = &&concat(__instpat_end_, name);
|
||||
#define INSTPAT_END(name) concat(__instpat_end_, name): ; }
|
||||
#define INSTPAT_START(name) \
|
||||
{ \
|
||||
const void **__instpat_end = &&concat(__instpat_end_, name);
|
||||
#define INSTPAT_END(name) \
|
||||
concat(__instpat_end_, name) :; \
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,53 +0,0 @@
|
|||
/***************************************************************************************
|
||||
* Copyright (c) 2014-2022 Zihao Yu, Nanjing University
|
||||
*
|
||||
* NEMU is licensed under Mulan PSL v2.
|
||||
* You can use this software according to the terms and conditions of the Mulan PSL v2.
|
||||
* You may obtain a copy of Mulan PSL v2 at:
|
||||
* http://license.coscl.org.cn/MulanPSL2
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
|
||||
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
|
||||
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
|
||||
*
|
||||
* See the Mulan PSL v2 for more details.
|
||||
***************************************************************************************/
|
||||
|
||||
#ifndef __CPU_DIFFTEST_H__
|
||||
#define __CPU_DIFFTEST_H__
|
||||
|
||||
#include <common.h>
|
||||
#include <difftest-def.h>
|
||||
|
||||
#ifdef CONFIG_DIFFTEST
|
||||
void difftest_skip_ref();
|
||||
void difftest_skip_dut(int nr_ref, int nr_dut);
|
||||
void difftest_set_patch(void (*fn)(void *arg), void *arg);
|
||||
void difftest_step(vaddr_t pc, vaddr_t npc);
|
||||
void difftest_detach();
|
||||
void difftest_attach();
|
||||
#else
|
||||
static inline void difftest_skip_ref() {}
|
||||
static inline void difftest_skip_dut(int nr_ref, int nr_dut) {}
|
||||
static inline void difftest_set_patch(void (*fn)(void *arg), void *arg) {}
|
||||
static inline void difftest_step(vaddr_t pc, vaddr_t npc) {}
|
||||
static inline void difftest_detach() {}
|
||||
static inline void difftest_attach() {}
|
||||
#endif
|
||||
|
||||
extern void (*ref_difftest_memcpy)(paddr_t addr, void *buf, size_t n, bool direction);
|
||||
extern void (*ref_difftest_regcpy)(void *dut, bool direction);
|
||||
extern void (*ref_difftest_exec)(uint64_t n);
|
||||
extern void (*ref_difftest_raise_intr)(uint64_t NO);
|
||||
|
||||
static inline bool difftest_check_reg(const char *name, vaddr_t pc, word_t ref, word_t dut) {
|
||||
if (ref != dut) {
|
||||
Log("%s is different after executing instruction at pc = " FMT_WORD
|
||||
", right = " FMT_WORD ", wrong = " FMT_WORD ", diff = " FMT_WORD,
|
||||
name, pc, ref, dut, ref ^ dut);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
#endif
|
|
@ -16,41 +16,59 @@
|
|||
#ifndef __DEBUG_H__
|
||||
#define __DEBUG_H__
|
||||
|
||||
#include <macro.h>
|
||||
#include <stdio.h>
|
||||
#include <utils.h>
|
||||
#include <macro.h>
|
||||
|
||||
IFDEF(CONFIG_ITRACE, void log_itrace_print());
|
||||
|
||||
#define Trace(format, ...) \
|
||||
_Log("[TRACE] " format "\n", ## __VA_ARGS__)
|
||||
#if (CONFIG_LOG_LEVEL >= 4)
|
||||
#define Trace(format, ...) _Log("[TRACE] " format "\n", ##__VA_ARGS__)
|
||||
#else
|
||||
#define Trace(format, ...)
|
||||
#endif
|
||||
|
||||
#define Log(format, ...) \
|
||||
_Log(ANSI_FMT("[INFO] %s:%d %s() ", ANSI_FG_BLUE) format "\n", \
|
||||
__FILE__, __LINE__, __func__, ## __VA_ARGS__)
|
||||
#if (CONFIG_LOG_LEVEL >= 3)
|
||||
#define Log(format, ...) \
|
||||
_Log(ANSI_FMT("[INFO] %s:%d %s() ", ANSI_FG_BLUE) format "\n", __FILE__, \
|
||||
__LINE__, __func__, ##__VA_ARGS__)
|
||||
#else
|
||||
#define Log(format, ...)
|
||||
#endif
|
||||
|
||||
#define Warning(format, ...) \
|
||||
_Log(ANSI_FMT("[WARNING] %s:%d %s() ", ANSI_FG_YELLOW) format "\n", \
|
||||
__FILE__, __LINE__, __func__, ## __VA_ARGS__)
|
||||
#if (CONFIG_LOG_LEVEL >= 2)
|
||||
#define Warning(format, ...) \
|
||||
_Log(ANSI_FMT("[WARNING] %s:%d %s() ", ANSI_FG_YELLOW) format "\n", \
|
||||
__FILE__, __LINE__, __func__, ##__VA_ARGS__)
|
||||
#else
|
||||
#define Warning(format, ...)
|
||||
#endif
|
||||
|
||||
#define Error(format, ...) \
|
||||
_Log(ANSI_FMT("[ERROR] %s:%d %s() ", ANSI_FG_RED) format "\n", \
|
||||
__FILE__, __LINE__, __func__, ## __VA_ARGS__)
|
||||
#if (CONFIG_LOG_LEVEL >= 1)
|
||||
#define Error(format, ...) \
|
||||
_Log(ANSI_FMT("[ERROR] %s:%d %s() ", ANSI_FG_RED) format "\n", __FILE__, \
|
||||
__LINE__, __func__, ##__VA_ARGS__)
|
||||
#else
|
||||
#define Error(format, ...)
|
||||
#endif
|
||||
|
||||
#define Assert(cond, format, ...) \
|
||||
do { \
|
||||
if (!(cond)) { \
|
||||
MUXDEF(CONFIG_TARGET_AM, printf(ANSI_FMT(format, ANSI_FG_RED) "\n", ## __VA_ARGS__), \
|
||||
(fflush(stdout), fprintf(stderr, ANSI_FMT(format, ANSI_FG_RED) "\n", ## __VA_ARGS__))); \
|
||||
IFNDEF(CONFIG_TARGET_AM, extern FILE* log_fp; fflush(log_fp)); \
|
||||
IFDEF(CONFIG_ITRACE, log_itrace_print()); \
|
||||
extern void assert_fail_msg(); \
|
||||
assert_fail_msg(); \
|
||||
assert(cond); \
|
||||
} \
|
||||
#define Assert(cond, format, ...) \
|
||||
do { \
|
||||
if (!(cond)) { \
|
||||
MUXDEF( \
|
||||
CONFIG_TARGET_AM, \
|
||||
printf(ANSI_FMT(format, ANSI_FG_RED) "\n", ##__VA_ARGS__), \
|
||||
(fflush(stdout), fprintf(stderr, ANSI_FMT(format, ANSI_FG_RED) "\n", \
|
||||
##__VA_ARGS__))); \
|
||||
IFNDEF(CONFIG_TARGET_AM, extern FILE *log_fp; fflush(log_fp)); \
|
||||
IFDEF(CONFIG_ITRACE, log_itrace_print()); \
|
||||
extern void assert_fail_msg(); \
|
||||
assert_fail_msg(); \
|
||||
assert(cond); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define panic(format, ...) Assert(0, format, ## __VA_ARGS__)
|
||||
#define panic(format, ...) Assert(0, format, ##__VA_ARGS__)
|
||||
|
||||
#define TODO() panic("please implement me")
|
||||
|
||||
|
|
|
@ -16,10 +16,12 @@
|
|||
#ifndef __DEVICE_MAP_H__
|
||||
#define __DEVICE_MAP_H__
|
||||
|
||||
#include <cpu/difftest.h>
|
||||
#include <difftest.h>
|
||||
#include <stdbool.h>
|
||||
#include <types.h>
|
||||
|
||||
typedef void(*io_callback_t)(uint32_t, int, bool);
|
||||
uint8_t* new_space(int size);
|
||||
typedef void (*io_callback_t)(uint32_t, int, bool);
|
||||
uint8_t *new_space(int size);
|
||||
|
||||
typedef struct {
|
||||
const char *name;
|
||||
|
@ -36,19 +38,19 @@ static inline bool map_inside(IOMap *map, paddr_t addr) {
|
|||
|
||||
static inline int find_mapid_by_addr(IOMap *maps, int size, paddr_t addr) {
|
||||
int i;
|
||||
for (i = 0; i < size; i ++) {
|
||||
for (i = 0; i < size; i++) {
|
||||
if (map_inside(maps + i, addr)) {
|
||||
difftest_skip_ref();
|
||||
nemu_do_difftest = false;
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
void add_pio_map(const char *name, ioaddr_t addr,
|
||||
void *space, uint32_t len, io_callback_t callback);
|
||||
void add_mmio_map(const char *name, paddr_t addr,
|
||||
void *space, uint32_t len, io_callback_t callback);
|
||||
void add_pio_map(const char *name, ioaddr_t addr, void *space, uint32_t len,
|
||||
io_callback_t callback);
|
||||
void add_mmio_map(const char *name, paddr_t addr, void *space, uint32_t len,
|
||||
io_callback_t callback);
|
||||
|
||||
word_t map_read(paddr_t addr, int len, IOMap *map);
|
||||
void map_write(paddr_t addr, int len, word_t data, IOMap *map);
|
||||
|
|
|
@ -1,40 +0,0 @@
|
|||
/***************************************************************************************
|
||||
* Copyright (c) 2014-2022 Zihao Yu, Nanjing University
|
||||
*
|
||||
* NEMU is licensed under Mulan PSL v2.
|
||||
* You can use this software according to the terms and conditions of the Mulan PSL v2.
|
||||
* You may obtain a copy of Mulan PSL v2 at:
|
||||
* http://license.coscl.org.cn/MulanPSL2
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
|
||||
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
|
||||
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
|
||||
*
|
||||
* See the Mulan PSL v2 for more details.
|
||||
***************************************************************************************/
|
||||
|
||||
#ifndef __DIFFTEST_DEF_H__
|
||||
#define __DIFFTEST_DEF_H__
|
||||
|
||||
#include <stdint.h>
|
||||
#include <macro.h>
|
||||
#include <generated/autoconf.h>
|
||||
|
||||
#define __EXPORT __attribute__((visibility("default")))
|
||||
enum { DIFFTEST_TO_DUT, DIFFTEST_TO_REF };
|
||||
|
||||
#if defined(CONFIG_ISA_x86)
|
||||
# define DIFFTEST_REG_SIZE (sizeof(uint32_t) * 9) // GPRs + pc
|
||||
#elif defined(CONFIG_ISA_mips32)
|
||||
# define DIFFTEST_REG_SIZE (sizeof(uint32_t) * 38) // GPRs + status + lo + hi + badvaddr + cause + pc
|
||||
#elif defined(CONFIG_ISA_riscv)
|
||||
#define RISCV_GPR_TYPE MUXDEF(CONFIG_RV64, uint64_t, uint32_t)
|
||||
#define RISCV_GPR_NUM MUXDEF(CONFIG_RVE , 16, 32)
|
||||
#define DIFFTEST_REG_SIZE (sizeof(RISCV_GPR_TYPE) * (RISCV_GPR_NUM + 1)) // GPRs + pc
|
||||
#elif defined(CONFIG_ISA_loongarch32r)
|
||||
# define DIFFTEST_REG_SIZE (sizeof(uint32_t) * 33) // GPRs + pc
|
||||
#else
|
||||
# error Unsupport ISA
|
||||
#endif
|
||||
|
||||
#endif
|
8
nemu/include/difftest.h
Normal file
8
nemu/include/difftest.h
Normal file
|
@ -0,0 +1,8 @@
|
|||
#ifndef __NEMU_DIFFTEST_H__
|
||||
#define __NEMU_DIFFTEST_H__
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
extern bool nemu_do_difftest;
|
||||
|
||||
#endif // __NEMU_DIFFTEST_H__
|
|
@ -17,6 +17,7 @@
|
|||
#define __ISA_H__
|
||||
|
||||
// Located at src/isa/$(GUEST_ISA)/include/isa-def.h
|
||||
#include <gdbstub.h>
|
||||
#include <isa-def.h>
|
||||
|
||||
// The macro `__GUEST_ISA__` is defined in $(CFLAGS).
|
||||
|
@ -30,8 +31,11 @@ void init_isa();
|
|||
|
||||
// reg
|
||||
extern CPU_state cpu;
|
||||
extern arch_info_t isa_arch_info;
|
||||
void isa_reg_display();
|
||||
word_t isa_reg_str2val(const char *name, bool *success);
|
||||
int isa_read_reg(void *args, int regno, size_t *reg_value);
|
||||
int isa_write_reg(void *args, int regno, size_t data);
|
||||
|
||||
// exec
|
||||
struct Decode;
|
||||
|
|
|
@ -29,7 +29,7 @@
|
|||
#define ARRLEN(arr) (int)(sizeof(arr) / sizeof(arr[0]))
|
||||
|
||||
// macro concatenation
|
||||
#define concat_temp(x, y) x ## y
|
||||
#define concat_temp(x, y) x##y
|
||||
#define concat(x, y) concat_temp(x, y)
|
||||
#define concat3(x, y, z) concat(concat(x, y), z)
|
||||
#define concat4(x, y, z, w) concat3(concat(x, y), z, w)
|
||||
|
@ -39,17 +39,18 @@
|
|||
// See https://stackoverflow.com/questions/26099745/test-if-preprocessor-symbol-is-defined-inside-macro
|
||||
#define CHOOSE2nd(a, b, ...) b
|
||||
#define MUX_WITH_COMMA(contain_comma, a, b) CHOOSE2nd(contain_comma a, b)
|
||||
#define MUX_MACRO_PROPERTY(p, macro, a, b) MUX_WITH_COMMA(concat(p, macro), a, b)
|
||||
#define MUX_MACRO_PROPERTY(p, macro, a, b) \
|
||||
MUX_WITH_COMMA(concat(p, macro), a, b)
|
||||
// define placeholders for some property
|
||||
#define __P_DEF_0 X,
|
||||
#define __P_DEF_1 X,
|
||||
#define __P_ONE_1 X,
|
||||
#define __P_DEF_0 X,
|
||||
#define __P_DEF_1 X,
|
||||
#define __P_ONE_1 X,
|
||||
#define __P_ZERO_0 X,
|
||||
// define some selection functions based on the properties of BOOLEAN macro
|
||||
#define MUXDEF(macro, X, Y) MUX_MACRO_PROPERTY(__P_DEF_, macro, X, Y)
|
||||
#define MUXDEF(macro, X, Y) MUX_MACRO_PROPERTY(__P_DEF_, macro, X, Y)
|
||||
#define MUXNDEF(macro, X, Y) MUX_MACRO_PROPERTY(__P_DEF_, macro, Y, X)
|
||||
#define MUXONE(macro, X, Y) MUX_MACRO_PROPERTY(__P_ONE_, macro, X, Y)
|
||||
#define MUXZERO(macro, X, Y) MUX_MACRO_PROPERTY(__P_ZERO_,macro, X, Y)
|
||||
#define MUXONE(macro, X, Y) MUX_MACRO_PROPERTY(__P_ONE_, macro, X, Y)
|
||||
#define MUXZERO(macro, X, Y) MUX_MACRO_PROPERTY(__P_ZERO_, macro, X, Y)
|
||||
|
||||
// test if a boolean macro is defined
|
||||
#define ISDEF(macro) MUXDEF(macro, 1, 0)
|
||||
|
@ -84,29 +85,46 @@
|
|||
#define MAP(c, f) c(f)
|
||||
|
||||
#define BITMASK(bits) ((1ull << (bits)) - 1)
|
||||
#define BITS(x, hi, lo) (((x) >> (lo)) & BITMASK((hi) - (lo) + 1)) // similar to x[hi:lo] in verilog
|
||||
#define SEXT(x, len) ({ struct { int64_t n : len; } __x = { .n = x }; (uint64_t)__x.n; })
|
||||
#define BITS(x, hi, lo) \
|
||||
(((x) >> (lo)) & BITMASK((hi) - (lo) + 1)) // similar to x[hi:lo] in verilog
|
||||
#define SEXT(x, len) \
|
||||
({ \
|
||||
struct { \
|
||||
int64_t n : len; \
|
||||
} __x = {.n = x}; \
|
||||
(uint64_t) __x.n; \
|
||||
})
|
||||
|
||||
#define ROUNDUP(a, sz) ((((uintptr_t)a) + (sz) - 1) & ~((sz) - 1))
|
||||
#define ROUNDDOWN(a, sz) ((((uintptr_t)a)) & ~((sz) - 1))
|
||||
#define ROUNDUP(a, sz) ((((uintptr_t)a) + (sz)-1) & ~((sz)-1))
|
||||
#define ROUNDDOWN(a, sz) ((((uintptr_t)a)) & ~((sz)-1))
|
||||
|
||||
#define PG_ALIGN __attribute((aligned(4096)))
|
||||
|
||||
#define FAILED_GOTO(tag, exp) do {if((exp)) goto tag;} while(0)
|
||||
#define FAILED_GOTO(tag, exp) \
|
||||
do { \
|
||||
if ((exp)) \
|
||||
goto tag; \
|
||||
} while (0)
|
||||
|
||||
#if !defined(likely)
|
||||
#define likely(cond) __builtin_expect(cond, 1)
|
||||
#define likely(cond) __builtin_expect(cond, 1)
|
||||
#define unlikely(cond) __builtin_expect(cond, 0)
|
||||
#endif
|
||||
|
||||
// for AM IOE
|
||||
#define io_read(reg) \
|
||||
({ reg##_T __io_param; \
|
||||
ioe_read(reg, &__io_param); \
|
||||
__io_param; })
|
||||
#define __EXPORT __attribute__((visibility("default")))
|
||||
|
||||
#define io_write(reg, ...) \
|
||||
({ reg##_T __io_param = (reg##_T) { __VA_ARGS__ }; \
|
||||
ioe_write(reg, &__io_param); })
|
||||
// for AM IOE
|
||||
#define io_read(reg) \
|
||||
({ \
|
||||
reg##_T __io_param; \
|
||||
ioe_read(reg, &__io_param); \
|
||||
__io_param; \
|
||||
})
|
||||
|
||||
#define io_write(reg, ...) \
|
||||
({ \
|
||||
reg##_T __io_param = (reg##_T){__VA_ARGS__}; \
|
||||
ioe_write(reg, &__io_param); \
|
||||
})
|
||||
|
||||
#endif
|
||||
|
|
28
nemu/include/nemu.h
Normal file
28
nemu/include/nemu.h
Normal file
|
@ -0,0 +1,28 @@
|
|||
#ifndef __NEMU_HEADER__
|
||||
#define __NEMU_HEADER__
|
||||
|
||||
#include <stddef.h>
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
#include <gdbstub.h>
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
int nemu_read_mem(void *args, size_t addr, size_t len, void *val);
|
||||
int nemu_write_mem(void *args, size_t addr, size_t len, void *val);
|
||||
void nemu_cont(void *args, gdb_action_t *res);
|
||||
void nemu_stepi(void *args, gdb_action_t *res);
|
||||
bool nemu_set_bp(void *args, size_t addr, bp_type_t type);
|
||||
bool nemu_del_bp(void *args, size_t addr, bp_type_t type);
|
||||
void nemu_on_interrupt(void *args);
|
||||
int nemu_read_reg(void *args, int regno, size_t *data);
|
||||
int nemu_write_reg(void *args, int regno, size_t data);
|
||||
void nemu_init(void *args);
|
||||
|
||||
extern arch_info_t nemu_isa_arch_info;
|
||||
extern bool nemu_do_difftest;
|
||||
extern bool nemu_dbg_state_size;
|
||||
|
||||
#endif // __NEMU_HEADER__
|
|
@ -20,7 +20,14 @@
|
|||
|
||||
// ----------- state -----------
|
||||
|
||||
enum { NEMU_RUNNING, NEMU_STOP, NEMU_END, NEMU_ABORT, NEMU_QUIT };
|
||||
enum {
|
||||
NEMU_RUNNING,
|
||||
NEMU_GDB_INTERRUPT,
|
||||
NEMU_STOP,
|
||||
NEMU_END,
|
||||
NEMU_ABORT,
|
||||
NEMU_QUIT
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
int state;
|
||||
|
@ -36,42 +43,41 @@ uint64_t get_time();
|
|||
|
||||
// ----------- log -----------
|
||||
|
||||
#define ANSI_FG_BLACK "\33[1;30m"
|
||||
#define ANSI_FG_RED "\33[1;31m"
|
||||
#define ANSI_FG_GREEN "\33[1;32m"
|
||||
#define ANSI_FG_YELLOW "\33[1;33m"
|
||||
#define ANSI_FG_BLUE "\33[1;34m"
|
||||
#define ANSI_FG_BLACK "\33[1;30m"
|
||||
#define ANSI_FG_RED "\33[1;31m"
|
||||
#define ANSI_FG_GREEN "\33[1;32m"
|
||||
#define ANSI_FG_YELLOW "\33[1;33m"
|
||||
#define ANSI_FG_BLUE "\33[1;34m"
|
||||
#define ANSI_FG_MAGENTA "\33[1;35m"
|
||||
#define ANSI_FG_CYAN "\33[1;36m"
|
||||
#define ANSI_FG_WHITE "\33[1;37m"
|
||||
#define ANSI_BG_BLACK "\33[1;40m"
|
||||
#define ANSI_BG_RED "\33[1;41m"
|
||||
#define ANSI_BG_GREEN "\33[1;42m"
|
||||
#define ANSI_BG_YELLOW "\33[1;43m"
|
||||
#define ANSI_BG_BLUE "\33[1;44m"
|
||||
#define ANSI_FG_CYAN "\33[1;36m"
|
||||
#define ANSI_FG_WHITE "\33[1;37m"
|
||||
#define ANSI_BG_BLACK "\33[1;40m"
|
||||
#define ANSI_BG_RED "\33[1;41m"
|
||||
#define ANSI_BG_GREEN "\33[1;42m"
|
||||
#define ANSI_BG_YELLOW "\33[1;43m"
|
||||
#define ANSI_BG_BLUE "\33[1;44m"
|
||||
#define ANSI_BG_MAGENTA "\33[1;35m"
|
||||
#define ANSI_BG_CYAN "\33[1;46m"
|
||||
#define ANSI_BG_WHITE "\33[1;47m"
|
||||
#define ANSI_NONE "\33[0m"
|
||||
#define ANSI_BG_CYAN "\33[1;46m"
|
||||
#define ANSI_BG_WHITE "\33[1;47m"
|
||||
#define ANSI_NONE "\33[0m"
|
||||
|
||||
#define ANSI_FMT(str, fmt) fmt str ANSI_NONE
|
||||
|
||||
#define log_write(...) IFDEF(CONFIG_TARGET_NATIVE_ELF, \
|
||||
do { \
|
||||
extern FILE* log_fp; \
|
||||
extern bool log_enable(); \
|
||||
if (log_enable()) { \
|
||||
fprintf(log_fp, __VA_ARGS__); \
|
||||
fflush(log_fp); \
|
||||
} \
|
||||
} while (0) \
|
||||
)
|
||||
#define log_write(...) \
|
||||
IFDEF( \
|
||||
CONFIG_TARGET_NATIVE_ELF, do { \
|
||||
extern FILE *log_fp; \
|
||||
extern bool log_enable(); \
|
||||
if (log_enable()) { \
|
||||
fprintf(log_fp, __VA_ARGS__); \
|
||||
fflush(log_fp); \
|
||||
} \
|
||||
} while (0))
|
||||
|
||||
#define _Log(...) \
|
||||
do { \
|
||||
printf(__VA_ARGS__); \
|
||||
log_write(__VA_ARGS__); \
|
||||
#define _Log(...) \
|
||||
do { \
|
||||
printf(__VA_ARGS__); \
|
||||
log_write(__VA_ARGS__); \
|
||||
} while (0)
|
||||
|
||||
|
||||
#endif
|
||||
|
|
|
@ -38,15 +38,15 @@
|
|||
@@ -983,6 +983,7 @@ static int card_busy_detect(struct mmc_card *card, unsigned int timeout_ms,
|
||||
int err = 0;
|
||||
u32 status;
|
||||
|
||||
|
||||
+ return err;
|
||||
do {
|
||||
bool done = time_after(jiffies, timeout);
|
||||
|
||||
|
||||
--- linux/drivers/mmc/core/core.h
|
||||
+++ linux/drivers/mmc/core/core.h
|
||||
@@ -64,6 +64,7 @@ void mmc_set_initial_state(struct mmc_host *host);
|
||||
|
||||
|
||||
static inline void mmc_delay(unsigned int ms)
|
||||
{
|
||||
+ return;
|
||||
|
|
|
@ -22,7 +22,7 @@ CXX := g++
|
|||
endif
|
||||
LD := $(CXX)
|
||||
INCLUDES = $(addprefix -I, $(INC_PATH))
|
||||
CFLAGS := -O2 -MMD -Wall -Werror $(INCLUDES) $(CFLAGS)
|
||||
CFLAGS := -O2 -MMD -Wall $(INCLUDES) $(CFLAGS)
|
||||
LDFLAGS := -O2 $(LDFLAGS)
|
||||
|
||||
OBJS = $(SRCS:%.c=$(OBJ_DIR)/%.o) $(CXXSRC:%.cc=$(OBJ_DIR)/%.o)
|
||||
|
@ -76,8 +76,13 @@ $(BINARY):: $(OBJS) $(ARCHIVES)
|
|||
@$(LD) -o $@ $(OBJS) $(LDFLAGS) $(ARCHIVES) $(LIBS)
|
||||
|
||||
install: $(BINARY)
|
||||
ifeq ($(SHARE),1)
|
||||
@mkdir -p $(PREFIX)/lib
|
||||
@cp $(BINARY) $(PREFIX)/lib/
|
||||
else
|
||||
@mkdir -p $(PREFIX)/bin
|
||||
@cp $(BINARY) $(PREFIX)/bin/
|
||||
endif
|
||||
|
||||
clean:
|
||||
-rm -rf $(BUILD_DIR)
|
||||
|
|
|
@ -13,11 +13,11 @@
|
|||
* See the Mulan PSL v2 for more details.
|
||||
***************************************************************************************/
|
||||
|
||||
#include <utils.h>
|
||||
#include "gdbstub.h"
|
||||
#include <cpu/cpu.h>
|
||||
#include <cpu/decode.h>
|
||||
#include <cpu/difftest.h>
|
||||
#include <locale.h>
|
||||
#include <utils.h>
|
||||
|
||||
/* The assembly code of instructions executed is only output to the screen
|
||||
* when the number of instructions executed is less than this value.
|
||||
|
@ -34,13 +34,16 @@ IFDEF(CONFIG_ITRACE, extern char logbuf[CONFIG_ITRACE_BUFFER][128]);
|
|||
IFDEF(CONFIG_ITRACE, extern int logbuf_rear);
|
||||
|
||||
void device_update();
|
||||
bool wp_eval_all();
|
||||
|
||||
static void trace_and_difftest(Decode *_this, vaddr_t dnpc) {
|
||||
#ifdef CONFIG_ITRACE_COND
|
||||
if (ITRACE_COND) { log_write("%s\n", logbuf[logbuf_rear]); }
|
||||
if (ITRACE_COND) {
|
||||
log_write("%s\n", logbuf[logbuf_rear]);
|
||||
}
|
||||
#endif
|
||||
if (g_print_step) { IFDEF(CONFIG_ITRACE, puts(logbuf[logbuf_rear])); }
|
||||
if (g_print_step) {
|
||||
IFDEF(CONFIG_ITRACE, puts(logbuf[logbuf_rear]));
|
||||
}
|
||||
IFDEF(CONFIG_DIFFTEST, difftest_step(_this->pc, dnpc));
|
||||
}
|
||||
|
||||
|
@ -56,12 +59,13 @@ static void exec_once(Decode *s, vaddr_t pc) {
|
|||
int ilen = s->snpc - s->pc;
|
||||
int i;
|
||||
uint8_t *inst = (uint8_t *)&s->isa.inst.val;
|
||||
for (i = ilen - 1; i >= 0; i --) {
|
||||
for (i = ilen - 1; i >= 0; i--) {
|
||||
p += snprintf(p, 4, " %02x", inst[i]);
|
||||
}
|
||||
int ilen_max = MUXDEF(CONFIG_ISA_x86, 8, 4);
|
||||
int space_len = ilen_max - ilen;
|
||||
if (space_len < 0) space_len = 0;
|
||||
if (space_len < 0)
|
||||
space_len = 0;
|
||||
space_len = space_len * 3 + 1;
|
||||
memset(p, ' ', space_len);
|
||||
p += space_len;
|
||||
|
@ -69,7 +73,8 @@ static void exec_once(Decode *s, vaddr_t pc) {
|
|||
#ifndef CONFIG_ISA_loongarch32r
|
||||
void disassemble(char *str, int size, uint64_t pc, uint8_t *code, int nbyte);
|
||||
disassemble(p, logbuf[logbuf_rear] + sizeof(logbuf[logbuf_rear]) - p,
|
||||
MUXDEF(CONFIG_ISA_x86, s->snpc, s->pc), (uint8_t *)&s->isa.inst.val, ilen);
|
||||
MUXDEF(CONFIG_ISA_x86, s->snpc, s->pc),
|
||||
(uint8_t *)&s->isa.inst.val, ilen);
|
||||
#else
|
||||
p[0] = '\0'; // the upstream llvm does not support loongarch32r
|
||||
#endif
|
||||
|
@ -78,15 +83,12 @@ static void exec_once(Decode *s, vaddr_t pc) {
|
|||
|
||||
static void execute(uint64_t n) {
|
||||
Decode s;
|
||||
for (;n > 0; n --) {
|
||||
for (; n > 0; n--) {
|
||||
exec_once(&s, cpu.pc);
|
||||
g_nr_guest_inst ++;
|
||||
g_nr_guest_inst++;
|
||||
trace_and_difftest(&s, cpu.pc);
|
||||
if (wp_eval_all()) {
|
||||
puts(logbuf[logbuf_rear]);
|
||||
if (nemu_state.state != NEMU_RUNNING)
|
||||
break;
|
||||
}
|
||||
if (nemu_state.state != NEMU_RUNNING) break;
|
||||
IFDEF(CONFIG_DEVICE, device_update());
|
||||
}
|
||||
}
|
||||
|
@ -96,8 +98,12 @@ static void statistic() {
|
|||
#define NUMBERIC_FMT MUXDEF(CONFIG_TARGET_AM, "%", "%'") PRIu64
|
||||
Log("host time spent = " NUMBERIC_FMT " us", g_timer);
|
||||
Log("total guest instructions = " NUMBERIC_FMT, g_nr_guest_inst);
|
||||
if (g_timer > 0) Log("simulation frequency = " NUMBERIC_FMT " inst/s", g_nr_guest_inst * 1000000 / g_timer);
|
||||
else Log("Finish running in less than 1 us and can not calculate the simulation frequency");
|
||||
if (g_timer > 0)
|
||||
Log("simulation frequency = " NUMBERIC_FMT " inst/s",
|
||||
g_nr_guest_inst * 1000000 / g_timer);
|
||||
else
|
||||
Log("Finish running in less than 1 us and can not calculate the simulation "
|
||||
"frequency");
|
||||
}
|
||||
|
||||
void assert_fail_msg() {
|
||||
|
@ -109,10 +115,13 @@ void assert_fail_msg() {
|
|||
void cpu_exec(uint64_t n) {
|
||||
g_print_step = (n < MAX_INST_TO_PRINT);
|
||||
switch (nemu_state.state) {
|
||||
case NEMU_END: case NEMU_ABORT:
|
||||
printf("Program execution has ended. To restart the program, exit NEMU and run again.\n");
|
||||
return;
|
||||
default: nemu_state.state = NEMU_RUNNING;
|
||||
case NEMU_END:
|
||||
case NEMU_ABORT:
|
||||
printf("Program execution has ended. To restart the program, exit NEMU and "
|
||||
"run again.\n");
|
||||
return;
|
||||
default:
|
||||
nemu_state.state = NEMU_RUNNING;
|
||||
}
|
||||
|
||||
uint64_t timer_start = get_time();
|
||||
|
@ -123,18 +132,53 @@ void cpu_exec(uint64_t n) {
|
|||
g_timer += timer_end - timer_start;
|
||||
|
||||
switch (nemu_state.state) {
|
||||
case NEMU_RUNNING: nemu_state.state = NEMU_STOP; break;
|
||||
case NEMU_RUNNING:
|
||||
nemu_state.state = NEMU_STOP;
|
||||
break;
|
||||
|
||||
case NEMU_END: case NEMU_ABORT: {
|
||||
Log("nemu: %s at pc = " FMT_WORD,
|
||||
(nemu_state.state == NEMU_ABORT ? ANSI_FMT("ABORT", ANSI_FG_RED) :
|
||||
(nemu_state.halt_ret == 0 ? ANSI_FMT("HIT GOOD TRAP", ANSI_FG_GREEN) :
|
||||
ANSI_FMT("HIT BAD TRAP", ANSI_FG_RED))),
|
||||
nemu_state.halt_pc);
|
||||
if(nemu_state.halt_ret != 0) {
|
||||
log_itrace_print();
|
||||
}
|
||||
} // fall through
|
||||
case NEMU_QUIT: statistic();
|
||||
case NEMU_END:
|
||||
case NEMU_ABORT: {
|
||||
Log("nemu: %s at pc = " FMT_WORD,
|
||||
(nemu_state.state == NEMU_ABORT
|
||||
? ANSI_FMT("ABORT", ANSI_FG_RED)
|
||||
: (nemu_state.halt_ret == 0
|
||||
? ANSI_FMT("HIT GOOD TRAP", ANSI_FG_GREEN)
|
||||
: ANSI_FMT("HIT BAD TRAP", ANSI_FG_RED))),
|
||||
nemu_state.halt_pc);
|
||||
if (nemu_state.halt_ret != 0) {
|
||||
IFDEF(CONFIG_ITRACE, log_itrace_print());
|
||||
}
|
||||
} // fall through
|
||||
case NEMU_QUIT:
|
||||
statistic();
|
||||
}
|
||||
}
|
||||
|
||||
breakpoint_t *cpu_exec_with_bp(uint64_t n, breakpoint_t *bp, size_t len) {
|
||||
static Decode s;
|
||||
nemu_state.state = NEMU_RUNNING;
|
||||
do {
|
||||
for (int i = 0; i < len; i++) {
|
||||
size_t addr = bp[i].addr;
|
||||
bp_type_t bptype = bp[i].type;
|
||||
if (bptype == BP_SOFTWARE && cpu.pc == addr) {
|
||||
return bp + i;
|
||||
}
|
||||
bool is_write = (bptype == BP_WRITE) || (bptype == BP_ACCESS);
|
||||
bool is_read = (bptype == BP_READ) || (bptype == BP_ACCESS);
|
||||
if (s.inst_type == INST_MEM_READ && s.inst_value.rmem == addr &&
|
||||
is_write) {
|
||||
return bp + i;
|
||||
} else if (s.inst_type == INST_MEM_WRITE && s.inst_value.wmem == addr &&
|
||||
is_read) {
|
||||
return bp + i;
|
||||
}
|
||||
}
|
||||
exec_once(&s, cpu.pc);
|
||||
g_nr_guest_inst++;
|
||||
IFDEF(CONFIG_DEVICE, device_update());
|
||||
if (nemu_state.state != NEMU_RUNNING)
|
||||
return NULL;
|
||||
} while (--n);
|
||||
return NULL;
|
||||
}
|
||||
|
|
|
@ -1,132 +0,0 @@
|
|||
/***************************************************************************************
|
||||
* Copyright (c) 2014-2022 Zihao Yu, Nanjing University
|
||||
*
|
||||
* NEMU is licensed under Mulan PSL v2.
|
||||
* You can use this software according to the terms and conditions of the Mulan PSL v2.
|
||||
* You may obtain a copy of Mulan PSL v2 at:
|
||||
* http://license.coscl.org.cn/MulanPSL2
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
|
||||
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
|
||||
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
|
||||
*
|
||||
* See the Mulan PSL v2 for more details.
|
||||
***************************************************************************************/
|
||||
|
||||
#include <dlfcn.h>
|
||||
|
||||
#include <isa.h>
|
||||
#include <cpu/cpu.h>
|
||||
#include <memory/paddr.h>
|
||||
#include <utils.h>
|
||||
#include <difftest-def.h>
|
||||
|
||||
void (*ref_difftest_memcpy)(paddr_t addr, void *buf, size_t n, bool direction) = NULL;
|
||||
void (*ref_difftest_regcpy)(void *dut, bool direction) = NULL;
|
||||
void (*ref_difftest_exec)(uint64_t n) = NULL;
|
||||
void (*ref_difftest_raise_intr)(uint64_t NO) = NULL;
|
||||
|
||||
#ifdef CONFIG_DIFFTEST
|
||||
|
||||
static bool is_skip_ref = false;
|
||||
static int skip_dut_nr_inst = 0;
|
||||
|
||||
// this is used to let ref skip instructions which
|
||||
// can not produce consistent behavior with NEMU
|
||||
void difftest_skip_ref() {
|
||||
is_skip_ref = true;
|
||||
// If such an instruction is one of the instruction packing in QEMU
|
||||
// (see below), we end the process of catching up with QEMU's pc to
|
||||
// keep the consistent behavior in our best.
|
||||
// Note that this is still not perfect: if the packed instructions
|
||||
// already write some memory, and the incoming instruction in NEMU
|
||||
// will load that memory, we will encounter false negative. But such
|
||||
// situation is infrequent.
|
||||
skip_dut_nr_inst = 0;
|
||||
}
|
||||
|
||||
// this is used to deal with instruction packing in QEMU.
|
||||
// Sometimes letting QEMU step once will execute multiple instructions.
|
||||
// We should skip checking until NEMU's pc catches up with QEMU's pc.
|
||||
// The semantic is
|
||||
// Let REF run `nr_ref` instructions first.
|
||||
// We expect that DUT will catch up with REF within `nr_dut` instructions.
|
||||
void difftest_skip_dut(int nr_ref, int nr_dut) {
|
||||
skip_dut_nr_inst += nr_dut;
|
||||
|
||||
while (nr_ref -- > 0) {
|
||||
ref_difftest_exec(1);
|
||||
}
|
||||
}
|
||||
|
||||
void init_difftest(char *ref_so_file, long img_size, int port) {
|
||||
assert(ref_so_file != NULL);
|
||||
|
||||
void *handle;
|
||||
handle = dlopen(ref_so_file, RTLD_LAZY);
|
||||
assert(handle);
|
||||
|
||||
ref_difftest_memcpy = dlsym(handle, "difftest_memcpy");
|
||||
assert(ref_difftest_memcpy);
|
||||
|
||||
ref_difftest_regcpy = dlsym(handle, "difftest_regcpy");
|
||||
assert(ref_difftest_regcpy);
|
||||
|
||||
ref_difftest_exec = dlsym(handle, "difftest_exec");
|
||||
assert(ref_difftest_exec);
|
||||
|
||||
ref_difftest_raise_intr = dlsym(handle, "difftest_raise_intr");
|
||||
assert(ref_difftest_raise_intr);
|
||||
|
||||
void (*ref_difftest_init)(int) = dlsym(handle, "difftest_init");
|
||||
assert(ref_difftest_init);
|
||||
|
||||
Log("Differential testing: %s", ANSI_FMT("ON", ANSI_FG_GREEN));
|
||||
Log("The result of every instruction will be compared with %s. "
|
||||
"This will help you a lot for debugging, but also significantly reduce the performance. "
|
||||
"If it is not necessary, you can turn it off in menuconfig.", ref_so_file);
|
||||
|
||||
ref_difftest_init(port);
|
||||
ref_difftest_memcpy(RESET_VECTOR, guest_to_host(RESET_VECTOR), img_size, DIFFTEST_TO_REF);
|
||||
ref_difftest_regcpy(&cpu, DIFFTEST_TO_REF);
|
||||
}
|
||||
|
||||
static void checkregs(CPU_state *ref, vaddr_t pc) {
|
||||
if (!isa_difftest_checkregs(ref, pc)) {
|
||||
nemu_state.state = NEMU_ABORT;
|
||||
nemu_state.halt_pc = pc;
|
||||
isa_reg_display();
|
||||
}
|
||||
}
|
||||
|
||||
void difftest_step(vaddr_t pc, vaddr_t npc) {
|
||||
CPU_state ref_r;
|
||||
|
||||
if (skip_dut_nr_inst > 0) {
|
||||
ref_difftest_regcpy(&ref_r, DIFFTEST_TO_DUT);
|
||||
if (ref_r.pc == npc) {
|
||||
skip_dut_nr_inst = 0;
|
||||
checkregs(&ref_r, npc);
|
||||
return;
|
||||
}
|
||||
skip_dut_nr_inst --;
|
||||
if (skip_dut_nr_inst == 0)
|
||||
panic("can not catch up with ref.pc = " FMT_WORD " at pc = " FMT_WORD, ref_r.pc, pc);
|
||||
return;
|
||||
}
|
||||
|
||||
if (is_skip_ref) {
|
||||
// to skip the checking of an instruction, just copy the reg state to reference design
|
||||
ref_difftest_regcpy(&cpu, DIFFTEST_TO_REF);
|
||||
is_skip_ref = false;
|
||||
return;
|
||||
}
|
||||
|
||||
ref_difftest_exec(1);
|
||||
ref_difftest_regcpy(&ref_r, DIFFTEST_TO_DUT);
|
||||
|
||||
checkregs(&ref_r, pc);
|
||||
}
|
||||
#else
|
||||
void init_difftest(char *ref_so_file, long img_size, int port) { }
|
||||
#endif
|
|
@ -1,42 +0,0 @@
|
|||
/***************************************************************************************
|
||||
* Copyright (c) 2014-2022 Zihao Yu, Nanjing University
|
||||
*
|
||||
* NEMU is licensed under Mulan PSL v2.
|
||||
* You can use this software according to the terms and conditions of the Mulan PSL v2.
|
||||
* You may obtain a copy of Mulan PSL v2 at:
|
||||
* http://license.coscl.org.cn/MulanPSL2
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
|
||||
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
|
||||
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
|
||||
*
|
||||
* See the Mulan PSL v2 for more details.
|
||||
***************************************************************************************/
|
||||
|
||||
#include <isa.h>
|
||||
#include <cpu/cpu.h>
|
||||
#include <difftest-def.h>
|
||||
#include <memory/paddr.h>
|
||||
|
||||
__EXPORT void difftest_memcpy(paddr_t addr, void *buf, size_t n, bool direction) {
|
||||
assert(0);
|
||||
}
|
||||
|
||||
__EXPORT void difftest_regcpy(void *dut, bool direction) {
|
||||
assert(0);
|
||||
}
|
||||
|
||||
__EXPORT void difftest_exec(uint64_t n) {
|
||||
assert(0);
|
||||
}
|
||||
|
||||
__EXPORT void difftest_raise_intr(word_t NO) {
|
||||
assert(0);
|
||||
}
|
||||
|
||||
__EXPORT void difftest_init(int port) {
|
||||
void init_mem();
|
||||
init_mem();
|
||||
/* Perform ISA dependent initialization. */
|
||||
init_isa();
|
||||
}
|
|
@ -1,5 +1,4 @@
|
|||
menuconfig DEVICE
|
||||
depends on !TARGET_SHARE
|
||||
bool "Devices"
|
||||
default n
|
||||
help
|
||||
|
|
|
@ -13,17 +13,17 @@
|
|||
* See the Mulan PSL v2 for more details.
|
||||
***************************************************************************************/
|
||||
|
||||
#include <device/map.h>
|
||||
#include <isa.h>
|
||||
#include <memory/host.h>
|
||||
#include <memory/vaddr.h>
|
||||
#include <device/map.h>
|
||||
|
||||
#define IO_SPACE_MAX (2 * 1024 * 1024)
|
||||
|
||||
static uint8_t *io_space = NULL;
|
||||
static uint8_t *p_space = NULL;
|
||||
|
||||
uint8_t* new_space(int size) {
|
||||
uint8_t *new_space(int size) {
|
||||
uint8_t *p = p_space;
|
||||
// page aligned;
|
||||
size = (size + (PAGE_SIZE - 1)) & ~PAGE_MASK;
|
||||
|
@ -33,17 +33,25 @@ uint8_t* new_space(int size) {
|
|||
}
|
||||
|
||||
static void check_bound(IOMap *map, paddr_t addr) {
|
||||
#ifndef CONFIG_TARGET_SHARE
|
||||
if (map == NULL) {
|
||||
Assert(map != NULL, "address (" FMT_PADDR ") is out of bound at pc = " FMT_WORD, addr, cpu.pc);
|
||||
Assert(map != NULL,
|
||||
"address (" FMT_PADDR ") is out of bound at pc = " FMT_WORD, addr,
|
||||
cpu.pc);
|
||||
} else {
|
||||
Assert(addr <= map->high && addr >= map->low,
|
||||
"address (" FMT_PADDR ") is out of bound {%s} [" FMT_PADDR ", " FMT_PADDR "] at pc = " FMT_WORD,
|
||||
addr, map->name, map->low, map->high, cpu.pc);
|
||||
"address (" FMT_PADDR ") is out of bound {%s} [" FMT_PADDR
|
||||
", " FMT_PADDR "] at pc = " FMT_WORD,
|
||||
addr, map->name, map->low, map->high, cpu.pc);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
static void invoke_callback(io_callback_t c, paddr_t offset, int len, bool is_write) {
|
||||
if (c != NULL) { c(offset, len, is_write); }
|
||||
static void invoke_callback(io_callback_t c, paddr_t offset, int len,
|
||||
bool is_write) {
|
||||
if (c != NULL) {
|
||||
c(offset, len, is_write);
|
||||
}
|
||||
}
|
||||
|
||||
void init_map() {
|
||||
|
|
|
@ -13,6 +13,8 @@
|
|||
* See the Mulan PSL v2 for more details.
|
||||
***************************************************************************************/
|
||||
|
||||
#include <assert.h>
|
||||
#include <debug.h>
|
||||
#include <device/map.h>
|
||||
|
||||
#define PORT_IO_SPACE_MAX 65535
|
||||
|
@ -22,15 +24,19 @@ static IOMap maps[NR_MAP] = {};
|
|||
static int nr_map = 0;
|
||||
|
||||
/* device interface */
|
||||
void add_pio_map(const char *name, ioaddr_t addr, void *space, uint32_t len, io_callback_t callback) {
|
||||
void add_pio_map(const char *name, ioaddr_t addr, void *space, uint32_t len,
|
||||
io_callback_t callback) {
|
||||
assert(nr_map < NR_MAP);
|
||||
assert(addr + len <= PORT_IO_SPACE_MAX);
|
||||
maps[nr_map] = (IOMap){ .name = name, .low = addr, .high = addr + len - 1,
|
||||
.space = space, .callback = callback };
|
||||
maps[nr_map] = (IOMap){.name = name,
|
||||
.low = addr,
|
||||
.high = addr + len - 1,
|
||||
.space = space,
|
||||
.callback = callback};
|
||||
Log("Add port-io map '%s' at [" FMT_PADDR ", " FMT_PADDR "]",
|
||||
maps[nr_map].name, maps[nr_map].low, maps[nr_map].high);
|
||||
|
||||
nr_map ++;
|
||||
nr_map++;
|
||||
}
|
||||
|
||||
/* CPU interface */
|
||||
|
|
|
@ -13,7 +13,10 @@
|
|||
* See the Mulan PSL v2 for more details.
|
||||
***************************************************************************************/
|
||||
|
||||
#include <assert.h>
|
||||
#include <debug.h>
|
||||
#include <device/map.h>
|
||||
#include <generated/autoconf.h>
|
||||
#include <utils.h>
|
||||
|
||||
#define KEYDOWN_MASK 0x8000
|
||||
|
@ -22,28 +25,27 @@
|
|||
#include <SDL2/SDL.h>
|
||||
|
||||
// Note that this is not the standard
|
||||
#define NEMU_KEYS(f) \
|
||||
f(ESCAPE) f(F1) f(F2) f(F3) f(F4) f(F5) f(F6) f(F7) f(F8) f(F9) f(F10) f(F11) f(F12) \
|
||||
f(GRAVE) f(1) f(2) f(3) f(4) f(5) f(6) f(7) f(8) f(9) f(0) f(MINUS) f(EQUALS) f(BACKSPACE) \
|
||||
f(TAB) f(Q) f(W) f(E) f(R) f(T) f(Y) f(U) f(I) f(O) f(P) f(LEFTBRACKET) f(RIGHTBRACKET) f(BACKSLASH) \
|
||||
f(CAPSLOCK) f(A) f(S) f(D) f(F) f(G) f(H) f(J) f(K) f(L) f(SEMICOLON) f(APOSTROPHE) f(RETURN) \
|
||||
f(LSHIFT) f(Z) f(X) f(C) f(V) f(B) f(N) f(M) f(COMMA) f(PERIOD) f(SLASH) f(RSHIFT) \
|
||||
f(LCTRL) f(APPLICATION) f(LALT) f(SPACE) f(RALT) f(RCTRL) \
|
||||
f(UP) f(DOWN) f(LEFT) f(RIGHT) f(INSERT) f(DELETE) f(HOME) f(END) f(PAGEUP) f(PAGEDOWN)
|
||||
#define NEMU_KEYS(f) \
|
||||
f(ESCAPE) f(F1) f(F2) f(F3) f(F4) f(F5) f(F6) f(F7) f(F8) f(F9) f(F10) \
|
||||
f(F11) f(F12) f(GRAVE) f(1) f(2) f(3) f(4) f(5) f(6) f(7) f(8) f(9) f(0) \
|
||||
f(MINUS) f(EQUALS) f(BACKSPACE) f(TAB) f(Q) f(W) f(E) f(R) f(T) f(Y) \
|
||||
f(U) f(I) f(O) f(P) f(LEFTBRACKET) f(RIGHTBRACKET) f(BACKSLASH) \
|
||||
f(CAPSLOCK) f(A) f(S) f(D) f(F) f(G) f(H) f(J) f(K) f(L) \
|
||||
f(SEMICOLON) f(APOSTROPHE) f(RETURN) f(LSHIFT) f(Z) f(X) \
|
||||
f(C) f(V) f(B) f(N) f(M) f(COMMA) f(PERIOD) f(SLASH) \
|
||||
f(RSHIFT) f(LCTRL) f(APPLICATION) f(LALT) \
|
||||
f(SPACE) f(RALT) f(RCTRL) f(UP) f(DOWN) \
|
||||
f(LEFT) f(RIGHT) f(INSERT) f(DELETE) \
|
||||
f(HOME) f(END) f(PAGEUP) f(PAGEDOWN)
|
||||
|
||||
#define NEMU_KEY_NAME(k) NEMU_KEY_ ## k,
|
||||
#define NEMU_KEY_NAME(k) NEMU_KEY_##k,
|
||||
|
||||
enum {
|
||||
NEMU_KEY_NONE = 0,
|
||||
MAP(NEMU_KEYS, NEMU_KEY_NAME)
|
||||
};
|
||||
enum { NEMU_KEY_NONE = 0, MAP(NEMU_KEYS, NEMU_KEY_NAME) };
|
||||
|
||||
#define SDL_KEYMAP(k) keymap[SDL_SCANCODE_ ## k] = NEMU_KEY_ ## k;
|
||||
#define SDL_KEYMAP(k) keymap[SDL_SCANCODE_##k] = NEMU_KEY_##k;
|
||||
static uint32_t keymap[256] = {};
|
||||
|
||||
static void init_keymap() {
|
||||
MAP(NEMU_KEYS, SDL_KEYMAP)
|
||||
}
|
||||
static void init_keymap() { MAP(NEMU_KEYS, SDL_KEYMAP) }
|
||||
|
||||
#define KEY_QUEUE_LEN 1024
|
||||
static int key_queue[KEY_QUEUE_LEN] = {};
|
||||
|
@ -92,9 +94,11 @@ void init_i8042() {
|
|||
i8042_data_port_base = (uint32_t *)new_space(4);
|
||||
i8042_data_port_base[0] = NEMU_KEY_NONE;
|
||||
#ifdef CONFIG_HAS_PORT_IO
|
||||
add_pio_map ("keyboard", CONFIG_I8042_DATA_PORT, i8042_data_port_base, 4, i8042_data_io_handler);
|
||||
add_pio_map("keyboard", CONFIG_I8042_DATA_PORT, i8042_data_port_base, 4,
|
||||
i8042_data_io_handler);
|
||||
#else
|
||||
add_mmio_map("keyboard", CONFIG_I8042_DATA_MMIO, i8042_data_port_base, 4, i8042_data_io_handler);
|
||||
add_mmio_map("keyboard", CONFIG_I8042_DATA_MMIO, i8042_data_port_base, 4,
|
||||
i8042_data_io_handler);
|
||||
#endif
|
||||
IFNDEF(CONFIG_TARGET_AM, init_keymap());
|
||||
}
|
||||
|
|
|
@ -13,8 +13,11 @@
|
|||
* See the Mulan PSL v2 for more details.
|
||||
***************************************************************************************/
|
||||
|
||||
#include <utils.h>
|
||||
#include <assert.h>
|
||||
#include <debug.h>
|
||||
#include <device/map.h>
|
||||
#include <generated/autoconf.h>
|
||||
#include <utils.h>
|
||||
|
||||
/* http://en.wikibooks.org/wiki/Serial_Programming/8250_UART_Programming */
|
||||
// NOTE: this is compatible to 16550
|
||||
|
@ -23,7 +26,6 @@
|
|||
|
||||
static uint8_t *serial_base = NULL;
|
||||
|
||||
|
||||
static void serial_putc(char ch) {
|
||||
MUXDEF(CONFIG_TARGET_AM, putch(ch), putc(ch, stderr));
|
||||
}
|
||||
|
@ -31,21 +33,23 @@ static void serial_putc(char ch) {
|
|||
static void serial_io_handler(uint32_t offset, int len, bool is_write) {
|
||||
assert(len == 1);
|
||||
switch (offset) {
|
||||
/* We bind the serial port with the host stderr in NEMU. */
|
||||
case CH_OFFSET:
|
||||
if (is_write) serial_putc(serial_base[0]);
|
||||
else panic("do not support read");
|
||||
break;
|
||||
default: panic("do not support offset = %d", offset);
|
||||
/* We bind the serial port with the host stderr in NEMU. */
|
||||
case CH_OFFSET:
|
||||
if (is_write)
|
||||
serial_putc(serial_base[0]);
|
||||
else
|
||||
panic("do not support read");
|
||||
break;
|
||||
default:
|
||||
panic("do not support offset = %d", offset);
|
||||
}
|
||||
}
|
||||
|
||||
void init_serial() {
|
||||
serial_base = new_space(8);
|
||||
#ifdef CONFIG_HAS_PORT_IO
|
||||
add_pio_map ("serial", CONFIG_SERIAL_PORT, serial_base, 8, serial_io_handler);
|
||||
add_pio_map("serial", CONFIG_SERIAL_PORT, serial_base, 8, serial_io_handler);
|
||||
#else
|
||||
add_mmio_map("serial", CONFIG_SERIAL_MMIO, serial_base, 8, serial_io_handler);
|
||||
#endif
|
||||
|
||||
}
|
||||
|
|
|
@ -13,8 +13,10 @@
|
|||
* See the Mulan PSL v2 for more details.
|
||||
***************************************************************************************/
|
||||
|
||||
#include <device/map.h>
|
||||
#include <assert.h>
|
||||
#include <device/alarm.h>
|
||||
#include <device/map.h>
|
||||
#include <generated/autoconf.h>
|
||||
#include <utils.h>
|
||||
|
||||
static uint32_t *rtc_port_base = NULL;
|
||||
|
@ -40,7 +42,7 @@ static void timer_intr() {
|
|||
void init_timer() {
|
||||
rtc_port_base = (uint32_t *)new_space(8);
|
||||
#ifdef CONFIG_HAS_PORT_IO
|
||||
add_pio_map ("rtc", CONFIG_RTC_PORT, rtc_port_base, 8, rtc_io_handler);
|
||||
add_pio_map("rtc", CONFIG_RTC_PORT, rtc_port_base, 8, rtc_io_handler);
|
||||
#else
|
||||
add_mmio_map("rtc", CONFIG_RTC_MMIO, rtc_port_base, 8, rtc_io_handler);
|
||||
#endif
|
||||
|
|
|
@ -13,20 +13,19 @@
|
|||
* See the Mulan PSL v2 for more details.
|
||||
***************************************************************************************/
|
||||
|
||||
#include <utils.h>
|
||||
#include <cpu/ifetch.h>
|
||||
#include <difftest.h>
|
||||
#include <isa.h>
|
||||
#include <cpu/difftest.h>
|
||||
#include <utils.h>
|
||||
|
||||
void set_nemu_state(int state, vaddr_t pc, int halt_ret) {
|
||||
difftest_skip_ref();
|
||||
nemu_do_difftest = false;
|
||||
nemu_state.state = state;
|
||||
nemu_state.halt_pc = pc;
|
||||
nemu_state.halt_ret = halt_ret;
|
||||
}
|
||||
|
||||
__attribute__((noinline))
|
||||
void invalid_inst(vaddr_t thispc) {
|
||||
__attribute__((noinline)) void invalid_inst(vaddr_t thispc) {
|
||||
uint32_t temp[2];
|
||||
vaddr_t pc = thispc;
|
||||
temp[0] = inst_fetch(&pc, 4);
|
||||
|
@ -34,18 +33,24 @@ void invalid_inst(vaddr_t thispc) {
|
|||
|
||||
uint8_t *p = (uint8_t *)temp;
|
||||
printf("invalid opcode(PC = " FMT_WORD "):\n"
|
||||
"\t%02x %02x %02x %02x %02x %02x %02x %02x ...\n"
|
||||
"\t%08x %08x...\n",
|
||||
thispc, p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7], temp[0], temp[1]);
|
||||
"\t%02x %02x %02x %02x %02x %02x %02x %02x ...\n"
|
||||
"\t%08x %08x...\n",
|
||||
thispc, p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7], temp[0],
|
||||
temp[1]);
|
||||
|
||||
printf("There are two cases which will trigger this unexpected exception:\n"
|
||||
"1. The instruction at PC = " FMT_WORD " is not implemented.\n"
|
||||
"2. Something is implemented incorrectly.\n", thispc);
|
||||
printf("Find this PC(" FMT_WORD ") in the disassembling result to distinguish which case it is.\n\n", thispc);
|
||||
"1. The instruction at PC = " FMT_WORD " is not implemented.\n"
|
||||
"2. Something is implemented incorrectly.\n",
|
||||
thispc);
|
||||
printf("Find this PC(" FMT_WORD
|
||||
") in the disassembling result to distinguish which case it is.\n\n",
|
||||
thispc);
|
||||
printf(ANSI_FMT("If it is the first case, see\n%s\nfor more details.\n\n"
|
||||
"If it is the second case, remember:\n"
|
||||
"* The machine is always right!\n"
|
||||
"* Every line of untested code is always wrong!\n\n", ANSI_FG_RED), isa_logo);
|
||||
"If it is the second case, remember:\n"
|
||||
"* The machine is always right!\n"
|
||||
"* Every line of untested code is always wrong!\n\n",
|
||||
ANSI_FG_RED),
|
||||
isa_logo);
|
||||
|
||||
set_nemu_state(NEMU_ABORT, thispc, -1);
|
||||
}
|
||||
|
|
|
@ -13,15 +13,26 @@
|
|||
* See the Mulan PSL v2 for more details.
|
||||
***************************************************************************************/
|
||||
|
||||
#include "debug.h"
|
||||
#include <cpu/cpu.h>
|
||||
#include <gdbstub.h>
|
||||
|
||||
void sdb_mainloop();
|
||||
int gdbstub_loop();
|
||||
extern bool enable_gdbstub;
|
||||
|
||||
void engine_start() {
|
||||
#ifdef CONFIG_TARGET_AM
|
||||
cpu_exec(-1);
|
||||
#else
|
||||
/* Receive commands from user. */
|
||||
sdb_mainloop();
|
||||
int ret = 0;
|
||||
if (enable_gdbstub) {
|
||||
if ((ret = gdbstub_loop())) {
|
||||
Error("gdbstub exited abnormally");
|
||||
exit(ret);
|
||||
}
|
||||
} else {
|
||||
cpu_exec(-1);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
|
|
@ -14,12 +14,12 @@
|
|||
#**************************************************************************************/
|
||||
|
||||
SRCS-y += src/nemu-main.c
|
||||
DIRS-y += src/cpu src/monitor src/utils
|
||||
DIRS-y += src/cpu src/utils
|
||||
DIRS-$(CONFIG_MODE_SYSTEM) += src/memory
|
||||
DIRS-BLACKLIST-$(CONFIG_TARGET_AM) += src/monitor/sdb
|
||||
|
||||
SHARE = $(if $(CONFIG_TARGET_SHARE),1,0)
|
||||
LIBS += $(if $(CONFIG_TARGET_NATIVE_ELF),-lreadline -ldl -pie,)
|
||||
LIBS += $(if $(CONFIG_TARGET_NATIVE_ELF),-lgdbstub -lreadline -ldl -pie,)
|
||||
|
||||
ifdef mainargs
|
||||
ASFLAGS += -DBIN_PATH=\"$(mainargs)\"
|
||||
|
|
|
@ -16,63 +16,62 @@
|
|||
// refer to http://www.patorjk.com/software/taag/#p=display&f=Big&t=Type%20Something%20
|
||||
|
||||
/*
|
||||
_ ____ ___ __ __ _
|
||||
_ ____ ___ __ __ _
|
||||
(_) |___ \__ \ | \/ | | |
|
||||
_ __ ___ _ _ __ ___ __) | ) | | \ / | __ _ _ __ _ _ __ _| |
|
||||
| '_ ` _ \| | '_ \/ __||__ < / / | |\/| |/ _` | '_ \| | | |/ _` | |
|
||||
| | | | | | | |_) \__ \___) / /_ | | | | (_| | | | | |_| | (_| | |
|
||||
|_| |_| |_|_| .__/|___/____/____| |_| |_|\__,_|_| |_|\__,_|\__,_|_|
|
||||
| |
|
||||
|_|
|
||||
| |
|
||||
|_|
|
||||
|
||||
*/
|
||||
|
||||
unsigned char isa_logo[] = {
|
||||
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
|
||||
0x5f, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
|
||||
0x5f, 0x5f, 0x5f, 0x5f, 0x20, 0x5f, 0x5f, 0x5f, 0x20, 0x20, 0x20, 0x20,
|
||||
0x5f, 0x5f, 0x20, 0x20, 0x5f, 0x5f, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
|
||||
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
|
||||
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x5f, 0x20, 0x0a, 0x20, 0x20,
|
||||
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x28, 0x5f, 0x29,
|
||||
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7c, 0x5f, 0x5f,
|
||||
0x5f, 0x20, 0x5c, 0x5f, 0x5f, 0x20, 0x5c, 0x20, 0x20, 0x7c, 0x20, 0x20,
|
||||
0x5c, 0x2f, 0x20, 0x20, 0x7c, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
|
||||
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
|
||||
0x20, 0x20, 0x20, 0x20, 0x7c, 0x20, 0x7c, 0x0a, 0x20, 0x20, 0x5f, 0x20,
|
||||
0x5f, 0x5f, 0x20, 0x5f, 0x5f, 0x5f, 0x20, 0x20, 0x5f, 0x20, 0x5f, 0x20,
|
||||
0x5f, 0x5f, 0x20, 0x20, 0x5f, 0x5f, 0x5f, 0x20, 0x20, 0x5f, 0x5f, 0x29,
|
||||
0x20, 0x7c, 0x20, 0x29, 0x20, 0x7c, 0x20, 0x7c, 0x20, 0x5c, 0x20, 0x20,
|
||||
0x2f, 0x20, 0x7c, 0x20, 0x5f, 0x5f, 0x20, 0x5f, 0x20, 0x5f, 0x20, 0x5f,
|
||||
0x5f, 0x20, 0x20, 0x5f, 0x20, 0x20, 0x20, 0x5f, 0x20, 0x20, 0x5f, 0x5f,
|
||||
0x20, 0x5f, 0x7c, 0x20, 0x7c, 0x0a, 0x20, 0x7c, 0x20, 0x27, 0x5f, 0x20,
|
||||
0x60, 0x20, 0x5f, 0x20, 0x5c, 0x7c, 0x20, 0x7c, 0x20, 0x27, 0x5f, 0x20,
|
||||
0x5c, 0x2f, 0x20, 0x5f, 0x5f, 0x7c, 0x7c, 0x5f, 0x5f, 0x20, 0x3c, 0x20,
|
||||
0x2f, 0x20, 0x2f, 0x20, 0x20, 0x7c, 0x20, 0x7c, 0x5c, 0x2f, 0x7c, 0x20,
|
||||
0x7c, 0x2f, 0x20, 0x5f, 0x60, 0x20, 0x7c, 0x20, 0x27, 0x5f, 0x20, 0x5c,
|
||||
0x7c, 0x20, 0x7c, 0x20, 0x7c, 0x20, 0x7c, 0x2f, 0x20, 0x5f, 0x60, 0x20,
|
||||
0x7c, 0x20, 0x7c, 0x0a, 0x20, 0x7c, 0x20, 0x7c, 0x20, 0x7c, 0x20, 0x7c,
|
||||
0x20, 0x7c, 0x20, 0x7c, 0x20, 0x7c, 0x20, 0x7c, 0x5f, 0x29, 0x20, 0x5c,
|
||||
0x5f, 0x5f, 0x20, 0x5c, 0x5f, 0x5f, 0x5f, 0x29, 0x20, 0x2f, 0x20, 0x2f,
|
||||
0x5f, 0x20, 0x20, 0x7c, 0x20, 0x7c, 0x20, 0x20, 0x7c, 0x20, 0x7c, 0x20,
|
||||
0x28, 0x5f, 0x7c, 0x20, 0x7c, 0x20, 0x7c, 0x20, 0x7c, 0x20, 0x7c, 0x20,
|
||||
0x7c, 0x5f, 0x7c, 0x20, 0x7c, 0x20, 0x28, 0x5f, 0x7c, 0x20, 0x7c, 0x20,
|
||||
0x7c, 0x0a, 0x20, 0x7c, 0x5f, 0x7c, 0x20, 0x7c, 0x5f, 0x7c, 0x20, 0x7c,
|
||||
0x5f, 0x7c, 0x5f, 0x7c, 0x20, 0x2e, 0x5f, 0x5f, 0x2f, 0x7c, 0x5f, 0x5f,
|
||||
0x5f, 0x2f, 0x5f, 0x5f, 0x5f, 0x5f, 0x2f, 0x5f, 0x5f, 0x5f, 0x5f, 0x7c,
|
||||
0x20, 0x7c, 0x5f, 0x7c, 0x20, 0x20, 0x7c, 0x5f, 0x7c, 0x5c, 0x5f, 0x5f,
|
||||
0x2c, 0x5f, 0x7c, 0x5f, 0x7c, 0x20, 0x7c, 0x5f, 0x7c, 0x5c, 0x5f, 0x5f,
|
||||
0x2c, 0x5f, 0x7c, 0x5c, 0x5f, 0x5f, 0x2c, 0x5f, 0x7c, 0x5f, 0x7c, 0x0a,
|
||||
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
|
||||
0x20, 0x7c, 0x20, 0x7c, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
|
||||
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
|
||||
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
|
||||
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
|
||||
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x0a, 0x20, 0x20,
|
||||
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7c,
|
||||
0x5f, 0x7c, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
|
||||
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
|
||||
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
|
||||
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
|
||||
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x0a, '\0'
|
||||
};
|
||||
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
|
||||
0x5f, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
|
||||
0x5f, 0x5f, 0x5f, 0x5f, 0x20, 0x5f, 0x5f, 0x5f, 0x20, 0x20, 0x20, 0x20,
|
||||
0x5f, 0x5f, 0x20, 0x20, 0x5f, 0x5f, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
|
||||
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
|
||||
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x5f, 0x20, 0x0a, 0x20, 0x20,
|
||||
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x28, 0x5f, 0x29,
|
||||
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7c, 0x5f, 0x5f,
|
||||
0x5f, 0x20, 0x5c, 0x5f, 0x5f, 0x20, 0x5c, 0x20, 0x20, 0x7c, 0x20, 0x20,
|
||||
0x5c, 0x2f, 0x20, 0x20, 0x7c, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
|
||||
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
|
||||
0x20, 0x20, 0x20, 0x20, 0x7c, 0x20, 0x7c, 0x0a, 0x20, 0x20, 0x5f, 0x20,
|
||||
0x5f, 0x5f, 0x20, 0x5f, 0x5f, 0x5f, 0x20, 0x20, 0x5f, 0x20, 0x5f, 0x20,
|
||||
0x5f, 0x5f, 0x20, 0x20, 0x5f, 0x5f, 0x5f, 0x20, 0x20, 0x5f, 0x5f, 0x29,
|
||||
0x20, 0x7c, 0x20, 0x29, 0x20, 0x7c, 0x20, 0x7c, 0x20, 0x5c, 0x20, 0x20,
|
||||
0x2f, 0x20, 0x7c, 0x20, 0x5f, 0x5f, 0x20, 0x5f, 0x20, 0x5f, 0x20, 0x5f,
|
||||
0x5f, 0x20, 0x20, 0x5f, 0x20, 0x20, 0x20, 0x5f, 0x20, 0x20, 0x5f, 0x5f,
|
||||
0x20, 0x5f, 0x7c, 0x20, 0x7c, 0x0a, 0x20, 0x7c, 0x20, 0x27, 0x5f, 0x20,
|
||||
0x60, 0x20, 0x5f, 0x20, 0x5c, 0x7c, 0x20, 0x7c, 0x20, 0x27, 0x5f, 0x20,
|
||||
0x5c, 0x2f, 0x20, 0x5f, 0x5f, 0x7c, 0x7c, 0x5f, 0x5f, 0x20, 0x3c, 0x20,
|
||||
0x2f, 0x20, 0x2f, 0x20, 0x20, 0x7c, 0x20, 0x7c, 0x5c, 0x2f, 0x7c, 0x20,
|
||||
0x7c, 0x2f, 0x20, 0x5f, 0x60, 0x20, 0x7c, 0x20, 0x27, 0x5f, 0x20, 0x5c,
|
||||
0x7c, 0x20, 0x7c, 0x20, 0x7c, 0x20, 0x7c, 0x2f, 0x20, 0x5f, 0x60, 0x20,
|
||||
0x7c, 0x20, 0x7c, 0x0a, 0x20, 0x7c, 0x20, 0x7c, 0x20, 0x7c, 0x20, 0x7c,
|
||||
0x20, 0x7c, 0x20, 0x7c, 0x20, 0x7c, 0x20, 0x7c, 0x5f, 0x29, 0x20, 0x5c,
|
||||
0x5f, 0x5f, 0x20, 0x5c, 0x5f, 0x5f, 0x5f, 0x29, 0x20, 0x2f, 0x20, 0x2f,
|
||||
0x5f, 0x20, 0x20, 0x7c, 0x20, 0x7c, 0x20, 0x20, 0x7c, 0x20, 0x7c, 0x20,
|
||||
0x28, 0x5f, 0x7c, 0x20, 0x7c, 0x20, 0x7c, 0x20, 0x7c, 0x20, 0x7c, 0x20,
|
||||
0x7c, 0x5f, 0x7c, 0x20, 0x7c, 0x20, 0x28, 0x5f, 0x7c, 0x20, 0x7c, 0x20,
|
||||
0x7c, 0x0a, 0x20, 0x7c, 0x5f, 0x7c, 0x20, 0x7c, 0x5f, 0x7c, 0x20, 0x7c,
|
||||
0x5f, 0x7c, 0x5f, 0x7c, 0x20, 0x2e, 0x5f, 0x5f, 0x2f, 0x7c, 0x5f, 0x5f,
|
||||
0x5f, 0x2f, 0x5f, 0x5f, 0x5f, 0x5f, 0x2f, 0x5f, 0x5f, 0x5f, 0x5f, 0x7c,
|
||||
0x20, 0x7c, 0x5f, 0x7c, 0x20, 0x20, 0x7c, 0x5f, 0x7c, 0x5c, 0x5f, 0x5f,
|
||||
0x2c, 0x5f, 0x7c, 0x5f, 0x7c, 0x20, 0x7c, 0x5f, 0x7c, 0x5c, 0x5f, 0x5f,
|
||||
0x2c, 0x5f, 0x7c, 0x5c, 0x5f, 0x5f, 0x2c, 0x5f, 0x7c, 0x5f, 0x7c, 0x0a,
|
||||
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
|
||||
0x20, 0x7c, 0x20, 0x7c, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
|
||||
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
|
||||
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
|
||||
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
|
||||
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x0a, 0x20, 0x20,
|
||||
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7c,
|
||||
0x5f, 0x7c, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
|
||||
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
|
||||
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
|
||||
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
|
||||
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x0a, '\0'};
|
||||
|
|
18
nemu/src/isa/riscv32/csr.c
Normal file
18
nemu/src/isa/riscv32/csr.c
Normal file
|
@ -0,0 +1,18 @@
|
|||
#include <csr.h>
|
||||
|
||||
void init_csr(csr_t csr) { memset(csr, 0, sizeof(word_t)); }
|
||||
|
||||
void write_csr(csr_t csr, csr_addr_t csrnum, word_t value) {
|
||||
switch (csrnum) {
|
||||
default:
|
||||
csr[csrnum] = value;
|
||||
}
|
||||
}
|
||||
|
||||
word_t read_csr(csr_t csr, csr_addr_t csrnum) {
|
||||
switch (csrnum) {
|
||||
// TODO: Implement csr read checks
|
||||
default:
|
||||
return csr[csrnum];
|
||||
}
|
||||
}
|
|
@ -1,28 +0,0 @@
|
|||
/***************************************************************************************
|
||||
* Copyright (c) 2014-2022 Zihao Yu, Nanjing University
|
||||
*
|
||||
* NEMU is licensed under Mulan PSL v2.
|
||||
* You can use this software according to the terms and conditions of the Mulan PSL v2.
|
||||
* You may obtain a copy of Mulan PSL v2 at:
|
||||
* http://license.coscl.org.cn/MulanPSL2
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
|
||||
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
|
||||
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
|
||||
*
|
||||
* See the Mulan PSL v2 for more details.
|
||||
***************************************************************************************/
|
||||
|
||||
#include <isa.h>
|
||||
#include <cpu/difftest.h>
|
||||
#include "../local-include/reg.h"
|
||||
|
||||
bool isa_difftest_checkregs(CPU_state *ref_r, vaddr_t pc) {
|
||||
for(int i = 0; i < MUXDEF(CONFIG_RVE, 16, 32); i++) {
|
||||
if(!difftest_check_reg(reg_name(i), pc, ref_r->gpr[i], gpr(i))) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void isa_difftest_attach() {
|
||||
}
|
|
@ -18,8 +18,13 @@
|
|||
|
||||
#include <common.h>
|
||||
|
||||
#define CSR_SIZE (0x1000)
|
||||
|
||||
typedef word_t csr_t[CSR_SIZE];
|
||||
|
||||
typedef struct {
|
||||
word_t gpr[MUXDEF(CONFIG_RVE, 16, 32)];
|
||||
csr_t csr;
|
||||
vaddr_t pc;
|
||||
} MUXDEF(CONFIG_RV64, riscv64_CPU_state, riscv32_CPU_state);
|
||||
|
||||
|
|
|
@ -13,45 +13,89 @@
|
|||
* See the Mulan PSL v2 for more details.
|
||||
***************************************************************************************/
|
||||
|
||||
#include <common.h>
|
||||
#include "isa.h"
|
||||
#include "local-include/reg.h"
|
||||
#include "macro.h"
|
||||
#include "types.h"
|
||||
#include <common.h>
|
||||
#include <cpu/cpu.h>
|
||||
#include <cpu/ifetch.h>
|
||||
#include <cpu/decode.h>
|
||||
#include <cpu/ifetch.h>
|
||||
#include <csr.h>
|
||||
#include <ftrace.h>
|
||||
#include <utils.h>
|
||||
|
||||
#define R(i) gpr(i)
|
||||
#define Mr vaddr_read
|
||||
#define Mw vaddr_write
|
||||
|
||||
enum {
|
||||
TYPE_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_CSR,
|
||||
TYPE_CSRI,
|
||||
TYPE_N, // none
|
||||
};
|
||||
|
||||
#define src1R() do { *src1 = R(rs1); } while (0)
|
||||
#define src2R() do { *src2 = R(rs2); } while (0)
|
||||
#define immI() do { *imm = SEXT(BITS(i, 31, 20), 12); } while(0)
|
||||
#define immU() do { *imm = SEXT(BITS(i, 31, 12), 20) << 12; } while(0)
|
||||
#define immS() do { *imm = SEXT(BITS(i, 31, 25), 7) << 5 | BITS(i, 11, 7); } while(0)
|
||||
#define immB() do { *imm = SEXT(BITS(i, 31, 31), 1) << 12 | BITS(i, 30, 25) << 5 | BITS(i, 11, 8) << 1 | BITS(i, 7, 7) << 11; } while(0)
|
||||
#define immJ() do { *imm = SEXT(BITS(i, 31, 31), 1) << 20 | BITS(i, 30, 21) << 1 | BITS(i, 20, 20) << 11 | BITS(i, 19, 12) << 12; } while(0)
|
||||
#define src1R() \
|
||||
do { \
|
||||
*src1 = R(rs1); \
|
||||
} while (0)
|
||||
#define src2R() \
|
||||
do { \
|
||||
*src2 = R(rs2); \
|
||||
} while (0)
|
||||
#define immI() \
|
||||
do { \
|
||||
*imm = SEXT(BITS(i, 31, 20), 12); \
|
||||
} while (0)
|
||||
#define immU() \
|
||||
do { \
|
||||
*imm = SEXT(BITS(i, 31, 12), 20) << 12; \
|
||||
} while (0)
|
||||
#define immS() \
|
||||
do { \
|
||||
*imm = SEXT(BITS(i, 31, 25), 7) << 5 | BITS(i, 11, 7); \
|
||||
} while (0)
|
||||
#define immB() \
|
||||
do { \
|
||||
*imm = SEXT(BITS(i, 31, 31), 1) << 12 | BITS(i, 30, 25) << 5 | \
|
||||
BITS(i, 11, 8) << 1 | BITS(i, 7, 7) << 11; \
|
||||
} while (0)
|
||||
#define immJ() \
|
||||
do { \
|
||||
*imm = SEXT(BITS(i, 31, 31), 1) << 20 | BITS(i, 30, 21) << 1 | \
|
||||
BITS(i, 20, 20) << 11 | BITS(i, 19, 12) << 12; \
|
||||
} while (0)
|
||||
#define csr() \
|
||||
do { \
|
||||
*src2 = BITS(i, 31, 20); \
|
||||
} while (0)
|
||||
#define uimm() \
|
||||
do { \
|
||||
*imm = BITS(i, 19, 15); \
|
||||
} while (0)
|
||||
|
||||
static void decode_operand(Decode *s, int *rd, word_t *src1, word_t *src2,
|
||||
word_t *imm, int type) {
|
||||
uint32_t i = s->isa.inst.val;
|
||||
int rs1 = BITS(i, 19, 15);
|
||||
int rs2 = BITS(i, 24, 20);
|
||||
*rd = BITS(i, 11, 7);
|
||||
*rd = BITS(i, 11, 7);
|
||||
switch (type) {
|
||||
case TYPE_R: src1R(); src2R(); break;
|
||||
case TYPE_I: src1R(); immI(); break;
|
||||
case TYPE_U: immU(); break;
|
||||
case TYPE_J: immJ(); break;
|
||||
case TYPE_S: src1R(); src2R(); immS(); break;
|
||||
case TYPE_B: src1R(); src2R(); immB(); break;
|
||||
// clang-format off
|
||||
case TYPE_R: src1R(); src2R(); break;
|
||||
case TYPE_I: src1R(); immI(); break;
|
||||
case TYPE_U: immU(); break;
|
||||
case TYPE_J: immJ(); break;
|
||||
case TYPE_S: src1R(); src2R(); immS(); break;
|
||||
case TYPE_B: src1R(); src2R(); immB(); break;
|
||||
case TYPE_CSR: src1R(); csr(); break;
|
||||
case TYPE_CSRI: csr(); uimm(); break;
|
||||
// clang-format on
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -62,11 +106,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
|
||||
static void ftrace_jalr(Decode *s, int rd, vaddr_t dst) {
|
||||
uint32_t i = s->isa.inst.val;
|
||||
int rs1 = BITS(i, 19, 15);
|
||||
if(rs1 == 1 && rd == 0) {
|
||||
if (rs1 == 1 && rd == 0) {
|
||||
ftrace_return(s->pc, dst);
|
||||
} else {
|
||||
ftrace_call(s->pc, dst);
|
||||
|
@ -80,70 +136,159 @@ static int decode_exec(Decode *s) {
|
|||
s->dnpc = s->snpc;
|
||||
|
||||
#define INSTPAT_INST(s) ((s)->isa.inst.val)
|
||||
#define INSTPAT_MATCH(s, name, type, ... /* execute body */ ) { \
|
||||
decode_operand(s, &rd, &src1, &src2, &imm, concat(TYPE_, type)); \
|
||||
__VA_ARGS__ ; \
|
||||
}
|
||||
#define INSTPAT_MATCH(s, name, type, ... /* execute body */) \
|
||||
{ \
|
||||
decode_operand(s, &rd, &src1, &src2, &imm, concat(TYPE_, type)); \
|
||||
__VA_ARGS__; \
|
||||
}
|
||||
|
||||
INSTPAT_START();
|
||||
INSTPAT("??????? ????? ????? ??? ????? 01101 11", lui , U, R(rd) = imm);
|
||||
INSTPAT("??????? ????? ????? ??? ????? 00101 11", auipc , U, R(rd) = s->pc + imm);
|
||||
INSTPAT("??????? ????? ????? ??? ????? 01101 11", lui, U, R(rd) = imm);
|
||||
INSTPAT("??????? ????? ????? ??? ????? 00101 11", auipc, U,
|
||||
R(rd) = s->pc + imm);
|
||||
|
||||
INSTPAT("??????? ????? ????? ??? ????? 11011 11", jal , J, do {
|
||||
s->dnpc = s->pc + imm; R(rd) = s->pc + 4;
|
||||
IFDEF(CONFIG_FTRACE, ftrace_call(s->pc, s->pc + imm)); } while(0));
|
||||
INSTPAT("??????? ????? ????? ??? ????? 11001 11", jalr , I, do {
|
||||
s->dnpc = src1 + imm; R(rd) = s->pc + 4;
|
||||
IFDEF(CONFIG_FTRACE, ftrace_jalr(s, rd, src1 + imm)); } while(0));
|
||||
INSTPAT("??????? ????? ????? 000 ????? 11000 11", beq , B, do_branch(s, src1 == src2, imm));
|
||||
INSTPAT("??????? ????? ????? 001 ????? 11000 11", bne , B, do_branch(s, src1 != src2, imm));
|
||||
INSTPAT("??????? ????? ????? 100 ????? 11000 11", blt , B, do_branch(s, (sword_t)src1 < (sword_t)src2, imm));
|
||||
INSTPAT("??????? ????? ????? 101 ????? 11000 11", bge , B, do_branch(s, (sword_t)src1 >= (sword_t)src2, imm));
|
||||
INSTPAT("??????? ????? ????? 110 ????? 11000 11", bltu , B, do_branch(s, src1 < src2, imm));
|
||||
INSTPAT("??????? ????? ????? 111 ????? 11000 11", bgeu , B, do_branch(s, src1 >= src2, imm));
|
||||
INSTPAT(
|
||||
"??????? ????? ????? ??? ????? 11011 11", jal, J, do {
|
||||
s->dnpc = s->pc + imm;
|
||||
R(rd) = s->pc + 4;
|
||||
IFDEF(CONFIG_FTRACE, ftrace_call(s->pc, s->pc + imm));
|
||||
} while (0));
|
||||
INSTPAT(
|
||||
"??????? ????? ????? ??? ????? 11001 11", jalr, I, do {
|
||||
s->dnpc = src1 + imm;
|
||||
R(rd) = s->pc + 4;
|
||||
IFDEF(CONFIG_FTRACE, ftrace_jalr(s, rd, src1 + imm));
|
||||
} while (0));
|
||||
INSTPAT("??????? ????? ????? 000 ????? 11000 11", beq, B,
|
||||
do_branch(s, src1 == src2, imm));
|
||||
INSTPAT("??????? ????? ????? 001 ????? 11000 11", bne, B,
|
||||
do_branch(s, src1 != src2, imm));
|
||||
INSTPAT("??????? ????? ????? 100 ????? 11000 11", blt, B,
|
||||
do_branch(s, (sword_t)src1 < (sword_t)src2, imm));
|
||||
INSTPAT("??????? ????? ????? 101 ????? 11000 11", bge, B,
|
||||
do_branch(s, (sword_t)src1 >= (sword_t)src2, imm));
|
||||
INSTPAT("??????? ????? ????? 110 ????? 11000 11", bltu, B,
|
||||
do_branch(s, src1 < src2, imm));
|
||||
INSTPAT("??????? ????? ????? 111 ????? 11000 11", bgeu, B,
|
||||
do_branch(s, src1 >= src2, imm));
|
||||
|
||||
INSTPAT("??????? ????? ????? 000 ????? 00000 11", lb , I, R(rd) = SEXT(Mr(src1 + imm, 1), 8));
|
||||
INSTPAT("??????? ????? ????? 001 ????? 00000 11", lh , I, R(rd) = SEXT(Mr(src1 + imm, 2), 16));
|
||||
INSTPAT("??????? ????? ????? 010 ????? 00000 11", lw , I, R(rd) = SEXT(Mr(src1 + imm, 4), 32));
|
||||
INSTPAT("??????? ????? ????? 100 ????? 00000 11", lbu , I, R(rd) = Mr(src1 + imm, 1));
|
||||
INSTPAT("??????? ????? ????? 101 ????? 00000 11", lhu , I, R(rd) = Mr(src1 + imm, 2));
|
||||
INSTPAT("??????? ????? ????? 000 ????? 01000 11", sb , S, Mw(src1 + imm, 1, src2));
|
||||
INSTPAT("??????? ????? ????? 001 ????? 01000 11", sh , S, Mw(src1 + imm, 2, src2));
|
||||
INSTPAT("??????? ????? ????? 010 ????? 01000 11", sw , S, Mw(src1 + imm, 4, src2));
|
||||
INSTPAT("??????? ????? ????? 000 ????? 00000 11", lb, I,
|
||||
R(rd) = SEXT(Mr(s, src1 + imm, 1), 8));
|
||||
INSTPAT("??????? ????? ????? 001 ????? 00000 11", lh, I,
|
||||
R(rd) = SEXT(Mr(s, src1 + imm, 2), 16));
|
||||
INSTPAT("??????? ????? ????? 010 ????? 00000 11", lw, I,
|
||||
R(rd) = SEXT(Mr(s, src1 + imm, 4), 32));
|
||||
INSTPAT("??????? ????? ????? 100 ????? 00000 11", lbu, I,
|
||||
R(rd) = Mr(s, src1 + imm, 1));
|
||||
INSTPAT("??????? ????? ????? 101 ????? 00000 11", lhu, I,
|
||||
R(rd) = Mr(s, src1 + imm, 2));
|
||||
INSTPAT("??????? ????? ????? 000 ????? 01000 11", sb, S,
|
||||
Mw(s, src1 + imm, 1, src2));
|
||||
INSTPAT("??????? ????? ????? 001 ????? 01000 11", sh, S,
|
||||
Mw(s, src1 + imm, 2, src2));
|
||||
INSTPAT("??????? ????? ????? 010 ????? 01000 11", sw, S,
|
||||
Mw(s, src1 + imm, 4, src2));
|
||||
|
||||
INSTPAT("??????? ????? ????? 000 ????? 00100 11", addi , I, R(rd) = src1 + imm);
|
||||
INSTPAT("??????? ????? ????? 010 ????? 00100 11", slti , I, R(rd) = (sword_t)src1 < (sword_t)imm ? 1 : 0);
|
||||
INSTPAT("??????? ????? ????? 011 ????? 00100 11", sltiu , I, R(rd) = src1 < imm ? 1 : 0);
|
||||
INSTPAT("??????? ????? ????? 100 ????? 00100 11", xori , I, R(rd) = src1 ^ imm);
|
||||
INSTPAT("??????? ????? ????? 110 ????? 00100 11", ori , I, R(rd) = src1 | imm);
|
||||
INSTPAT("??????? ????? ????? 111 ????? 00100 11", andi , I, R(rd) = src1 & imm);
|
||||
INSTPAT("0000000 ????? ????? 001 ????? 00100 11", slli , I, R(rd) = src1 << imm);
|
||||
INSTPAT("0000000 ????? ????? 101 ????? 00100 11", srli , I, R(rd) = src1 >> imm);
|
||||
INSTPAT("0100000 ????? ????? 101 ????? 00100 11", srai , I, R(rd) = (sword_t)src1 >> (imm & 0x01F));
|
||||
INSTPAT("0000000 ????? ????? 000 ????? 01100 11", add , R, R(rd) = src1 + src2);
|
||||
INSTPAT("0100000 ????? ????? 000 ????? 01100 11", sub , R, R(rd) = src1 - src2);
|
||||
INSTPAT("0000000 ????? ????? 001 ????? 01100 11", sll , R, R(rd) = src1 << src2);
|
||||
INSTPAT("0000000 ????? ????? 010 ????? 01100 11", slt , R, R(rd) = (sword_t)src1 < (sword_t)src2 ? 1 : 0);
|
||||
INSTPAT("0000000 ????? ????? 011 ????? 01100 11", sltu , R, R(rd) = src1 < src2 ? 1 : 0);
|
||||
INSTPAT("0000000 ????? ????? 100 ????? 01100 11", xor , R, R(rd) = src1 ^ src2);
|
||||
INSTPAT("0000000 ????? ????? 101 ????? 01100 11", srl , R, R(rd) = src1 >> src2);
|
||||
INSTPAT("0100000 ????? ????? 101 ????? 01100 11", sra , R, R(rd) = (sword_t)src1 >> (src2 & 0x01F));
|
||||
INSTPAT("0000000 ????? ????? 110 ????? 01100 11", or , R, R(rd) = src1 | src2);
|
||||
INSTPAT("0000000 ????? ????? 111 ????? 01100 11", and , R, R(rd) = src1 & src2);
|
||||
INSTPAT("??????? ????? ????? 000 ????? 00100 11", addi, I,
|
||||
R(rd) = src1 + imm);
|
||||
INSTPAT("??????? ????? ????? 010 ????? 00100 11", slti, I,
|
||||
R(rd) = (sword_t)src1 < (sword_t)imm ? 1 : 0);
|
||||
INSTPAT("??????? ????? ????? 011 ????? 00100 11", sltiu, I,
|
||||
R(rd) = src1 < imm ? 1 : 0);
|
||||
INSTPAT("??????? ????? ????? 100 ????? 00100 11", xori, I,
|
||||
R(rd) = src1 ^ imm);
|
||||
INSTPAT("??????? ????? ????? 110 ????? 00100 11", ori, I, R(rd) = src1 | imm);
|
||||
INSTPAT("??????? ????? ????? 111 ????? 00100 11", andi, I,
|
||||
R(rd) = src1 & imm);
|
||||
INSTPAT("0000000 ????? ????? 001 ????? 00100 11", slli, I,
|
||||
R(rd) = src1 << imm);
|
||||
INSTPAT("0000000 ????? ????? 101 ????? 00100 11", srli, I,
|
||||
R(rd) = src1 >> imm);
|
||||
INSTPAT("0100000 ????? ????? 101 ????? 00100 11", srai, I,
|
||||
R(rd) = (sword_t)src1 >> (imm & 0x01F));
|
||||
INSTPAT("0000000 ????? ????? 000 ????? 01100 11", add, R,
|
||||
R(rd) = src1 + src2);
|
||||
INSTPAT("0100000 ????? ????? 000 ????? 01100 11", sub, R,
|
||||
R(rd) = src1 - src2);
|
||||
INSTPAT("0000000 ????? ????? 001 ????? 01100 11", sll, R,
|
||||
R(rd) = src1 << src2);
|
||||
INSTPAT("0000000 ????? ????? 010 ????? 01100 11", slt, R,
|
||||
R(rd) = (sword_t)src1 < (sword_t)src2 ? 1 : 0);
|
||||
INSTPAT("0000000 ????? ????? 011 ????? 01100 11", sltu, R,
|
||||
R(rd) = src1 < src2 ? 1 : 0);
|
||||
INSTPAT("0000000 ????? ????? 100 ????? 01100 11", xor, R,
|
||||
R(rd) = src1 ^ src2);
|
||||
INSTPAT("0000000 ????? ????? 101 ????? 01100 11", srl, R,
|
||||
R(rd) = src1 >> src2);
|
||||
INSTPAT("0100000 ????? ????? 101 ????? 01100 11", sra, R,
|
||||
R(rd) = (sword_t)src1 >> (src2 & 0x01F));
|
||||
INSTPAT("0000000 ????? ????? 110 ????? 01100 11", or, R, R(rd) = src1 | src2);
|
||||
INSTPAT("0000000 ????? ????? 111 ????? 01100 11", and, R,
|
||||
R(rd) = src1 & src2);
|
||||
|
||||
INSTPAT("0000000 00001 00000 000 00000 11100 11", ebreak , N, NEMUTRAP(s->pc, R(10))); // R(10) is $a0
|
||||
INSTPAT("0000000 00001 00000 000 00000 11100 11", ebreak, N,
|
||||
NEMUTRAP(s->pc, R(10))); // R(10) is $a0
|
||||
|
||||
// "M"
|
||||
INSTPAT("0000001 ????? ????? 000 ????? 01100 11", mul , R, R(rd) = src1 * src2);
|
||||
INSTPAT("0000001 ????? ????? 001 ????? 01100 11", mulh , R, R(rd) = (int64_t)(sword_t)src1 * (sword_t)src2 >> 32);
|
||||
INSTPAT("0000001 ????? ????? 010 ????? 01100 11", mulhsu , R, R(rd) = (int64_t)(sword_t)src1 * (uint64_t)src2 >> 32);
|
||||
INSTPAT("0000001 ????? ????? 011 ????? 01100 11", mulhu , R, R(rd) = (uint64_t)src1 * (uint64_t)src2 >> 32);
|
||||
INSTPAT("0000001 ????? ????? 100 ????? 01100 11", div , R, R(rd) = (sword_t)src1 / (sword_t)src2);
|
||||
INSTPAT("0000001 ????? ????? 101 ????? 01100 11", divu , R, R(rd) = src1 / src2);
|
||||
INSTPAT("0000001 ????? ????? 110 ????? 01100 11", rem , R, R(rd) = (sword_t)src1 % (sword_t)src2);
|
||||
INSTPAT("0000001 ????? ????? 111 ????? 01100 11", remu , R, R(rd) = src1 % src2);
|
||||
INSTPAT("0000001 ????? ????? 000 ????? 01100 11", mul, R,
|
||||
R(rd) = src1 * src2);
|
||||
INSTPAT("0000001 ????? ????? 001 ????? 01100 11", mulh, R,
|
||||
R(rd) = (int64_t)(sword_t)src1 * (sword_t)src2 >> 32);
|
||||
INSTPAT("0000001 ????? ????? 010 ????? 01100 11", mulhsu, R,
|
||||
R(rd) = (int64_t)(sword_t)src1 * (uint64_t)src2 >> 32);
|
||||
INSTPAT("0000001 ????? ????? 011 ????? 01100 11", mulhu, R,
|
||||
R(rd) = (uint64_t)src1 * (uint64_t)src2 >> 32);
|
||||
INSTPAT("0000001 ????? ????? 100 ????? 01100 11", div, R,
|
||||
R(rd) = (sword_t)src1 / (sword_t)src2);
|
||||
INSTPAT("0000001 ????? ????? 101 ????? 01100 11", divu, R,
|
||||
R(rd) = src1 / src2);
|
||||
INSTPAT("0000001 ????? ????? 110 ????? 01100 11", rem, R,
|
||||
R(rd) = (sword_t)src1 % (sword_t)src2);
|
||||
INSTPAT("0000001 ????? ????? 111 ????? 01100 11", remu, R,
|
||||
R(rd) = src1 % src2);
|
||||
|
||||
INSTPAT("??????? ????? ????? ??? ????? ????? ??", inv , N, INV(s->pc));
|
||||
// "Previledge"
|
||||
// -- CSR instructions
|
||||
// src2: R(read register)
|
||||
// src1: R(write source)
|
||||
// imm: write data()
|
||||
INSTPAT(
|
||||
"??????? ????? ????? 001 ????? 11100 11", csrrw, CSR, do {
|
||||
R(rd) = read_csr(cpu.csr, src2);
|
||||
write_csr(cpu.csr, src2, src1);
|
||||
} while (0););
|
||||
INSTPAT(
|
||||
"??????? ????? ????? 010 ????? 11100 11", csrrs, CSR, do {
|
||||
R(rd) = read_csr(cpu.csr, src2);
|
||||
set_csr_bits(cpu.csr, src2, src1);
|
||||
} while (0););
|
||||
INSTPAT(
|
||||
"??????? ????? ????? 011 ????? 11100 11", csrrc, CSR, do {
|
||||
R(rd) = read_csr(cpu.csr, src2);
|
||||
clear_csr_bits(cpu.csr, src2, src1);
|
||||
} while (0););
|
||||
INSTPAT(
|
||||
"??????? ????? ????? 101 ????? 11100 11", csrrwi, CSRI, do {
|
||||
R(rd) = read_csr(cpu.csr, src2);
|
||||
write_csr(cpu.csr, src2, imm);
|
||||
} while (0););
|
||||
INSTPAT(
|
||||
"??????? ????? ????? 110 ????? 11100 11", csrrsi, CSRI, do {
|
||||
R(rd) = read_csr(cpu.csr, src2);
|
||||
set_csr_bits(cpu.csr, src2, imm);
|
||||
} while (0););
|
||||
INSTPAT(
|
||||
"??????? ????? ????? 111 ????? 11100 11", csrrci, CSRI, do {
|
||||
R(rd) = read_csr(cpu.csr, src2);
|
||||
clear_csr_bits(cpu.csr, src2, imm);
|
||||
} while (0););
|
||||
// -- Machine level
|
||||
INSTPAT("0000000 00000 00000 000 00000 11100 11", ecall, N,
|
||||
s->dnpc = isa_raise_intr(CauseEnvironmentCallFromMMode, cpu.pc));
|
||||
INSTPAT("0011000 00010 00000 000 00000 11100 11", mret, N,
|
||||
s->dnpc = read_csr(cpu.csr, MEPC));
|
||||
|
||||
INSTPAT("??????? ????? ????? ??? ????? ????? ??", inv, N, INV(s->pc));
|
||||
INSTPAT_END();
|
||||
|
||||
R(0) = 0; // reset $zero to 0
|
||||
|
|
29
nemu/src/isa/riscv32/local-include/csr.h
Normal file
29
nemu/src/isa/riscv32/local-include/csr.h
Normal file
|
@ -0,0 +1,29 @@
|
|||
#ifndef __NEMU_CSR_H__
|
||||
#define __NEMU_CSR_H__
|
||||
#include <isa-def.h>
|
||||
#include <types.h>
|
||||
|
||||
#define MSTATUS 0x300
|
||||
#define MISA 0x301
|
||||
#define MIE 0x304
|
||||
#define MTVEC 0x305
|
||||
#define MEPC 0x341
|
||||
#define MCAUSE 0x342
|
||||
|
||||
enum { CauseEnvironmentCallFromMMode = 11 };
|
||||
|
||||
typedef uint16_t csr_addr_t;
|
||||
|
||||
void init_csr(csr_t csr);
|
||||
|
||||
/* macro for setting and clearing csr bits */
|
||||
#define set_csr_bits(csr, reg, mask) \
|
||||
write_csr(csr, reg, read_csr(csr, reg) | (mask))
|
||||
|
||||
#define clear_csr_bits(csr, reg, mask) \
|
||||
write_csr(csr, reg, read_csr(csr, reg) & ~(mask))
|
||||
|
||||
void write_csr(csr_t csr, csr_addr_t csrnum, word_t value);
|
||||
word_t read_csr(csr_t csr, csr_addr_t csrnum);
|
||||
|
||||
#endif // __NEMU_CSR_H__
|
|
@ -16,7 +16,7 @@
|
|||
// refer to http://www.patorjk.com/software/taag/#p=display&f=Big&t=Type%20Something%20
|
||||
|
||||
/*
|
||||
_ __ __ _
|
||||
_ __ __ _
|
||||
(_) | \/ | | |
|
||||
_ __ _ ___ ___ ________ __ | \ / | __ _ _ __ _ _ __ _| |
|
||||
| '__| / __|/ __|______\ \ / / | |\/| |/ _` | '_ \| | | |/ _` | |
|
||||
|
@ -25,39 +25,49 @@
|
|||
|
||||
*/
|
||||
|
||||
unsigned char isa_logo[] = {
|
||||
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x5f, 0x20, 0x20, 0x20, 0x20,
|
||||
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
|
||||
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x5f, 0x5f, 0x20,
|
||||
0x20, 0x5f, 0x5f, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
|
||||
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
|
||||
0x20, 0x20, 0x20, 0x20, 0x5f, 0x20, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20,
|
||||
0x20, 0x28, 0x5f, 0x29, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
|
||||
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
|
||||
0x20, 0x20, 0x20, 0x7c, 0x20, 0x20, 0x5c, 0x2f, 0x20, 0x20, 0x7c, 0x20,
|
||||
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
|
||||
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7c, 0x20,
|
||||
0x7c, 0x0a, 0x20, 0x20, 0x5f, 0x20, 0x5f, 0x5f, 0x20, 0x5f, 0x20, 0x5f,
|
||||
0x5f, 0x5f, 0x20, 0x20, 0x5f, 0x5f, 0x5f, 0x20, 0x5f, 0x5f, 0x5f, 0x5f,
|
||||
0x5f, 0x5f, 0x5f, 0x5f, 0x20, 0x20, 0x20, 0x5f, 0x5f, 0x20, 0x7c, 0x20,
|
||||
0x5c, 0x20, 0x20, 0x2f, 0x20, 0x7c, 0x20, 0x5f, 0x5f, 0x20, 0x5f, 0x20,
|
||||
0x5f, 0x20, 0x5f, 0x5f, 0x20, 0x20, 0x5f, 0x20, 0x20, 0x20, 0x5f, 0x20,
|
||||
0x20, 0x5f, 0x5f, 0x20, 0x5f, 0x7c, 0x20, 0x7c, 0x0a, 0x20, 0x7c, 0x20,
|
||||
0x27, 0x5f, 0x5f, 0x7c, 0x20, 0x2f, 0x20, 0x5f, 0x5f, 0x7c, 0x2f, 0x20,
|
||||
0x5f, 0x5f, 0x7c, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5c, 0x20, 0x5c,
|
||||
0x20, 0x2f, 0x20, 0x2f, 0x20, 0x7c, 0x20, 0x7c, 0x5c, 0x2f, 0x7c, 0x20,
|
||||
0x7c, 0x2f, 0x20, 0x5f, 0x60, 0x20, 0x7c, 0x20, 0x27, 0x5f, 0x20, 0x5c,
|
||||
0x7c, 0x20, 0x7c, 0x20, 0x7c, 0x20, 0x7c, 0x2f, 0x20, 0x5f, 0x60, 0x20,
|
||||
0x7c, 0x20, 0x7c, 0x0a, 0x20, 0x7c, 0x20, 0x7c, 0x20, 0x20, 0x7c, 0x20,
|
||||
0x5c, 0x5f, 0x5f, 0x20, 0x5c, 0x20, 0x28, 0x5f, 0x5f, 0x20, 0x20, 0x20,
|
||||
0x20, 0x20, 0x20, 0x20, 0x20, 0x5c, 0x20, 0x56, 0x20, 0x2f, 0x20, 0x20,
|
||||
0x7c, 0x20, 0x7c, 0x20, 0x20, 0x7c, 0x20, 0x7c, 0x20, 0x28, 0x5f, 0x7c,
|
||||
0x20, 0x7c, 0x20, 0x7c, 0x20, 0x7c, 0x20, 0x7c, 0x20, 0x7c, 0x5f, 0x7c,
|
||||
0x20, 0x7c, 0x20, 0x28, 0x5f, 0x7c, 0x20, 0x7c, 0x20, 0x7c, 0x0a, 0x20,
|
||||
0x7c, 0x5f, 0x7c, 0x20, 0x20, 0x7c, 0x5f, 0x7c, 0x5f, 0x5f, 0x5f, 0x2f,
|
||||
0x5c, 0x5f, 0x5f, 0x5f, 0x7c, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
|
||||
0x20, 0x5c, 0x5f, 0x2f, 0x20, 0x20, 0x20, 0x7c, 0x5f, 0x7c, 0x20, 0x20,
|
||||
0x7c, 0x5f, 0x7c, 0x5c, 0x5f, 0x5f, 0x2c, 0x5f, 0x7c, 0x5f, 0x7c, 0x20,
|
||||
0x7c, 0x5f, 0x7c, 0x5c, 0x5f, 0x5f, 0x2c, 0x5f, 0x7c, 0x5c, 0x5f, 0x5f,
|
||||
0x2c, 0x5f, 0x7c, 0x5f, 0x7c, 0x0a, '\0' /* Termination Character is indispensable! */
|
||||
unsigned char
|
||||
isa_logo
|
||||
[] =
|
||||
{
|
||||
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x5f, 0x20, 0x20,
|
||||
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
|
||||
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
|
||||
0x20, 0x20, 0x20, 0x5f, 0x5f, 0x20, 0x20, 0x5f, 0x5f, 0x20,
|
||||
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
|
||||
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
|
||||
0x20, 0x20, 0x20, 0x20, 0x5f, 0x20, 0x0a, 0x20, 0x20, 0x20,
|
||||
0x20, 0x20, 0x20, 0x28, 0x5f, 0x29, 0x20, 0x20, 0x20, 0x20,
|
||||
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
|
||||
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7c,
|
||||
0x20, 0x20, 0x5c, 0x2f, 0x20, 0x20, 0x7c, 0x20, 0x20, 0x20,
|
||||
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
|
||||
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
|
||||
0x7c, 0x20, 0x7c, 0x0a, 0x20, 0x20, 0x5f, 0x20, 0x5f, 0x5f,
|
||||
0x20, 0x5f, 0x20, 0x5f, 0x5f, 0x5f, 0x20, 0x20, 0x5f, 0x5f,
|
||||
0x5f, 0x20, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f,
|
||||
0x20, 0x20, 0x20, 0x5f, 0x5f, 0x20, 0x7c, 0x20, 0x5c, 0x20,
|
||||
0x20, 0x2f, 0x20, 0x7c, 0x20, 0x5f, 0x5f, 0x20, 0x5f, 0x20,
|
||||
0x5f, 0x20, 0x5f, 0x5f, 0x20, 0x20, 0x5f, 0x20, 0x20, 0x20,
|
||||
0x5f, 0x20, 0x20, 0x5f, 0x5f, 0x20, 0x5f, 0x7c, 0x20, 0x7c,
|
||||
0x0a, 0x20, 0x7c, 0x20, 0x27, 0x5f, 0x5f, 0x7c, 0x20, 0x2f,
|
||||
0x20, 0x5f, 0x5f, 0x7c, 0x2f, 0x20, 0x5f, 0x5f, 0x7c, 0x5f,
|
||||
0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5c, 0x20, 0x5c, 0x20, 0x2f,
|
||||
0x20, 0x2f, 0x20, 0x7c, 0x20, 0x7c, 0x5c, 0x2f, 0x7c, 0x20,
|
||||
0x7c, 0x2f, 0x20, 0x5f, 0x60, 0x20, 0x7c, 0x20, 0x27, 0x5f,
|
||||
0x20, 0x5c, 0x7c, 0x20, 0x7c, 0x20, 0x7c, 0x20, 0x7c, 0x2f,
|
||||
0x20, 0x5f, 0x60, 0x20, 0x7c, 0x20, 0x7c, 0x0a, 0x20, 0x7c,
|
||||
0x20, 0x7c, 0x20, 0x20, 0x7c, 0x20, 0x5c, 0x5f, 0x5f, 0x20,
|
||||
0x5c, 0x20, 0x28, 0x5f, 0x5f, 0x20, 0x20, 0x20, 0x20, 0x20,
|
||||
0x20, 0x20, 0x20, 0x5c, 0x20, 0x56, 0x20, 0x2f, 0x20, 0x20,
|
||||
0x7c, 0x20, 0x7c, 0x20, 0x20, 0x7c, 0x20, 0x7c, 0x20, 0x28,
|
||||
0x5f, 0x7c, 0x20, 0x7c, 0x20, 0x7c, 0x20, 0x7c, 0x20, 0x7c,
|
||||
0x20, 0x7c, 0x5f, 0x7c, 0x20, 0x7c, 0x20, 0x28, 0x5f, 0x7c,
|
||||
0x20, 0x7c, 0x20, 0x7c, 0x0a, 0x20, 0x7c, 0x5f, 0x7c, 0x20,
|
||||
0x20, 0x7c, 0x5f, 0x7c, 0x5f, 0x5f, 0x5f, 0x2f, 0x5c, 0x5f,
|
||||
0x5f, 0x5f, 0x7c, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
|
||||
0x20, 0x5c, 0x5f, 0x2f, 0x20, 0x20, 0x20, 0x7c, 0x5f, 0x7c,
|
||||
0x20, 0x20, 0x7c, 0x5f, 0x7c, 0x5c, 0x5f, 0x5f, 0x2c, 0x5f,
|
||||
0x7c, 0x5f, 0x7c, 0x20, 0x7c, 0x5f, 0x7c, 0x5c, 0x5f, 0x5f,
|
||||
0x2c, 0x5f, 0x7c, 0x5c, 0x5f, 0x5f, 0x2c, 0x5f, 0x7c, 0x5f,
|
||||
0x7c, 0x0a, '\0' /* Termination Character is indispensable! */
|
||||
};
|
||||
|
|
|
@ -13,20 +13,21 @@
|
|||
* See the Mulan PSL v2 for more details.
|
||||
***************************************************************************************/
|
||||
|
||||
#include <isa.h>
|
||||
#include "local-include/reg.h"
|
||||
#include "csr.h"
|
||||
#include "macro.h"
|
||||
#include <errno.h>
|
||||
#include <gdbstub.h>
|
||||
#include <isa.h>
|
||||
|
||||
const char *regs[] = {
|
||||
"$0", "ra", "sp", "gp", "tp", "t0", "t1", "t2",
|
||||
"s0", "s1", "a0", "a1", "a2", "a3", "a4", "a5",
|
||||
"a6", "a7", "s2", "s3", "s4", "s5", "s6", "s7",
|
||||
"s8", "s9", "s10", "s11", "t3", "t4", "t5", "t6"
|
||||
};
|
||||
const char *regs[] = {"$0", "ra", "sp", "gp", "tp", "t0", "t1", "t2",
|
||||
"s0", "s1", "a0", "a1", "a2", "a3", "a4", "a5",
|
||||
"a6", "a7", "s2", "s3", "s4", "s5", "s6", "s7",
|
||||
"s8", "s9", "s10", "s11", "t3", "t4", "t5", "t6"};
|
||||
|
||||
void isa_reg_display() {
|
||||
int colomn_per_row = 4;
|
||||
for(int i = 0; i < ARRLEN(regs); i++) {
|
||||
for (int i = 0; i < ARRLEN(regs); i++) {
|
||||
printf("\e[1;34m%3s\e[0m: " FMT_PADDR, reg_name(i), gpr(i));
|
||||
if (i % colomn_per_row == 3)
|
||||
putchar('\n');
|
||||
|
@ -49,3 +50,33 @@ word_t isa_reg_str2val(const char *s, bool *success) {
|
|||
|
||||
return gpr(i);
|
||||
}
|
||||
|
||||
int isa_read_reg(void *args, int regno, size_t *reg_value) {
|
||||
if (regno > 32) {
|
||||
return EFAULT;
|
||||
}
|
||||
|
||||
if (regno == 32) {
|
||||
*reg_value = cpu.pc;
|
||||
} else {
|
||||
*reg_value = cpu.gpr[regno];
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int isa_write_reg(void *args, int regno, size_t data) {
|
||||
if (regno > 32) {
|
||||
return EFAULT;
|
||||
}
|
||||
|
||||
if (regno == 32) {
|
||||
cpu.pc = data;
|
||||
} else {
|
||||
cpu.gpr[regno] = data;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
__EXPORT arch_info_t isa_arch_info = {.reg_num = 32,
|
||||
.reg_byte = MUXDEF(CONFIG_RV64, 8, 4),
|
||||
.target_desc = TARGET_RV32};
|
||||
|
|
|
@ -13,16 +13,14 @@
|
|||
* See the Mulan PSL v2 for more details.
|
||||
***************************************************************************************/
|
||||
|
||||
#include <csr.h>
|
||||
#include <isa.h>
|
||||
|
||||
word_t isa_raise_intr(word_t NO, vaddr_t epc) {
|
||||
/* TODO: Trigger an interrupt/exception with ``NO''.
|
||||
* Then return the address of the interrupt/exception vector.
|
||||
*/
|
||||
write_csr(cpu.csr, MEPC, epc);
|
||||
write_csr(cpu.csr, MCAUSE, NO);
|
||||
|
||||
return 0;
|
||||
return read_csr(cpu.csr, MTVEC);
|
||||
}
|
||||
|
||||
word_t isa_query_intr() {
|
||||
return INTR_EMPTY;
|
||||
}
|
||||
word_t isa_query_intr() { return INTR_EMPTY; }
|
||||
|
|
|
@ -1 +0,0 @@
|
|||
riscv32
|
|
@ -15,12 +15,13 @@
|
|||
|
||||
#include "common.h"
|
||||
#include "debug.h"
|
||||
#include <memory/host.h>
|
||||
#include <memory/paddr.h>
|
||||
#include "utils.h"
|
||||
#include <device/mmio.h>
|
||||
#include <isa.h>
|
||||
#include <memory/host.h>
|
||||
#include <memory/paddr.h>
|
||||
|
||||
#if defined(CONFIG_PMEM_MALLOC)
|
||||
#if defined(CONFIG_PMEM_MALLOC)
|
||||
static uint8_t *pmem = NULL;
|
||||
#else // CONFIG_PMEM_GARRAY
|
||||
static uint8_t pmem[CONFIG_MSIZE] PG_ALIGN = {};
|
||||
|
@ -31,7 +32,7 @@ static word_t mtrace_end[CONFIG_MTRACE_RANGE_MAX] = {0};
|
|||
static int range_count = 0;
|
||||
#endif
|
||||
|
||||
uint8_t* guest_to_host(paddr_t paddr) { return pmem + paddr - CONFIG_MBASE; }
|
||||
uint8_t *guest_to_host(paddr_t paddr) { return pmem + paddr - CONFIG_MBASE; }
|
||||
paddr_t host_to_guest(uint8_t *haddr) { return haddr - pmem + CONFIG_MBASE; }
|
||||
|
||||
static word_t pmem_read(paddr_t addr, int len) {
|
||||
|
@ -44,22 +45,29 @@ static void pmem_write(paddr_t addr, int len, word_t data) {
|
|||
}
|
||||
|
||||
static void out_of_bound(paddr_t addr) {
|
||||
panic("address = " FMT_PADDR " is out of bound of pmem [" FMT_PADDR ", " FMT_PADDR "] at pc = " FMT_WORD,
|
||||
addr, PMEM_LEFT, PMEM_RIGHT, cpu.pc);
|
||||
#ifdef CONFIG_TARGET_SHARE
|
||||
// Do not panic when used as a library. Give an error in log
|
||||
Error("Out of bound at 0x%x", addr);
|
||||
#else
|
||||
panic("address = " FMT_PADDR " is out of bound of pmem [" FMT_PADDR
|
||||
", " FMT_PADDR "] at pc = " FMT_WORD,
|
||||
addr, PMEM_LEFT, PMEM_RIGHT, cpu.pc);
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef CONFIG_MTRACE
|
||||
static void mtrace_print(char type, word_t addr, int len, word_t data) {
|
||||
for (int i = 0; i < range_count; i++)
|
||||
if (addr <= mtrace_end[i] && addr >= mtrace_start[i] ) {
|
||||
Trace("Mem %c " FMT_PADDR "%d D " FMT_PADDR, type, addr, len, data);
|
||||
if (addr <= mtrace_end[i] && addr >= mtrace_start[i]) {
|
||||
Trace("PC=" FMT_PADDR " Mem %c" FMT_PADDR " %d D " FMT_PADDR, cpu.pc,
|
||||
type, addr, len, data);
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
void init_mem() {
|
||||
#if defined(CONFIG_PMEM_MALLOC)
|
||||
#if defined(CONFIG_PMEM_MALLOC)
|
||||
pmem = malloc(CONFIG_MSIZE);
|
||||
assert(pmem);
|
||||
#endif
|
||||
|
@ -67,15 +75,17 @@ void init_mem() {
|
|||
char range[sizeof(CONFIG_MTRACE_RANGE)] = CONFIG_MTRACE_RANGE;
|
||||
char *saveptr, *ptr;
|
||||
ptr = strtok_r(range, ",", &saveptr);
|
||||
for (range_count = 0; range_count < CONFIG_MTRACE_RANGE_MAX; ) {
|
||||
for (range_count = 0; range_count < CONFIG_MTRACE_RANGE_MAX;) {
|
||||
word_t start, end;
|
||||
Assert(sscanf(ptr, FMT_PADDR "-" FMT_PADDR, &start, &end) == 2, "Config option MTRACE_RANGE has wrong format");
|
||||
Assert(sscanf(ptr, FMT_PADDR "-" FMT_PADDR, &start, &end) == 2,
|
||||
"Config option MTRACE_RANGE has wrong format");
|
||||
mtrace_start[range_count] = start;
|
||||
mtrace_end[range_count] = end;
|
||||
|
||||
range_count++;
|
||||
ptr = strtok_r(NULL, ",", &saveptr);
|
||||
if (!ptr) break;
|
||||
if (!ptr)
|
||||
break;
|
||||
}
|
||||
Trace("MTRACE ranges: ");
|
||||
for (int i = 0; i < range_count; i++) {
|
||||
|
@ -83,24 +93,31 @@ void init_mem() {
|
|||
}
|
||||
#endif
|
||||
IFDEF(CONFIG_MEM_RANDOM, memset(pmem, rand(), CONFIG_MSIZE));
|
||||
Log("physical memory area [" FMT_PADDR ", " FMT_PADDR "]", PMEM_LEFT, PMEM_RIGHT);
|
||||
Log("physical memory area [" FMT_PADDR ", " FMT_PADDR "]", PMEM_LEFT,
|
||||
PMEM_RIGHT);
|
||||
}
|
||||
|
||||
word_t paddr_read(paddr_t addr, int len) {
|
||||
word_t result = 0;
|
||||
if (likely(in_pmem(addr))) { result = pmem_read(addr, len); goto mtrace;}
|
||||
IFDEF(CONFIG_DEVICE, result = mmio_read(addr, len); goto mtrace)
|
||||
if (likely(in_pmem(addr))) {
|
||||
result = pmem_read(addr, len);
|
||||
goto mtrace;
|
||||
}
|
||||
IFDEF(CONFIG_DEVICE, result = mmio_read(addr, len); goto mtrace;)
|
||||
out_of_bound(addr);
|
||||
|
||||
mtrace:
|
||||
IFDEF(CONFIG_MTRACE, mtrace_print('R', addr, len, result));
|
||||
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void paddr_write(paddr_t addr, int len, word_t data) {
|
||||
IFDEF(CONFIG_MTRACE, mtrace_print('W', addr, len, data));
|
||||
if (likely(in_pmem(addr))) { pmem_write(addr, len, data); return; }
|
||||
if (likely(in_pmem(addr))) {
|
||||
pmem_write(addr, len, data);
|
||||
return;
|
||||
}
|
||||
IFDEF(CONFIG_DEVICE, mmio_write(addr, len, data); return);
|
||||
out_of_bound(addr);
|
||||
}
|
||||
|
|
4
nemu/src/monitor/filelist.mk
Normal file
4
nemu/src/monitor/filelist.mk
Normal file
|
@ -0,0 +1,4 @@
|
|||
DIRS-y += src/monitor
|
||||
|
||||
CXXSRC += src/monitor/gdbstub.cc
|
||||
LIBS += -lgdbstub
|
170
nemu/src/monitor/gdbstub.cc
Normal file
170
nemu/src/monitor/gdbstub.cc
Normal file
|
@ -0,0 +1,170 @@
|
|||
#include "types.h"
|
||||
#include "utils.h"
|
||||
#include <vector>
|
||||
|
||||
extern "C" {
|
||||
#include <cpu/cpu.h>
|
||||
#include <debug.h>
|
||||
#include <errno.h>
|
||||
#include <gdbstub.h>
|
||||
#include <isa.h>
|
||||
#include <memory/paddr.h>
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
typedef struct {
|
||||
std::vector<breakpoint_t> *bp;
|
||||
bool halt;
|
||||
} DbgState;
|
||||
|
||||
__EXPORT size_t nemu_dbg_state_size = sizeof(DbgState);
|
||||
__EXPORT bool nemu_do_difftest = true;
|
||||
__EXPORT arch_info_t nemu_isa_arch_info = isa_arch_info;
|
||||
|
||||
__EXPORT int nemu_read_mem(void *args, size_t addr, size_t len, void *val) {
|
||||
if (!in_pmem(addr))
|
||||
return EINVAL;
|
||||
memcpy(val, guest_to_host(addr), len);
|
||||
return 0;
|
||||
}
|
||||
|
||||
__EXPORT int nemu_write_mem(void *args, size_t addr, size_t len, void *val) {
|
||||
if (!in_pmem(addr))
|
||||
return EINVAL;
|
||||
memcpy(guest_to_host(addr), val, len);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void nemu_is_stopped(gdb_action_t *act, breakpoint_t *stopped_at) {
|
||||
switch (nemu_state.state) {
|
||||
case NEMU_RUNNING:
|
||||
nemu_state.state = NEMU_STOP;
|
||||
if (stopped_at == NULL) {
|
||||
act->reason = gdb_action_t::ACT_NONE;
|
||||
} else {
|
||||
switch (stopped_at->type) {
|
||||
case BP_SOFTWARE:
|
||||
act->reason = gdb_action_t::ACT_BREAKPOINT;
|
||||
break;
|
||||
case BP_ACCESS:
|
||||
act->reason = gdb_action_t::ACT_WATCH;
|
||||
break;
|
||||
case BP_WRITE:
|
||||
act->reason = gdb_action_t::ACT_WWATCH;
|
||||
break;
|
||||
case BP_READ:
|
||||
act->reason = gdb_action_t::ACT_RWATCH;
|
||||
break;
|
||||
}
|
||||
act->data = stopped_at->addr;
|
||||
}
|
||||
break;
|
||||
|
||||
case NEMU_GDB_INTERRUPT:
|
||||
act->reason = gdb_action_t::ACT_BREAKPOINT;
|
||||
act->data = cpu.pc;
|
||||
break;
|
||||
|
||||
default:
|
||||
act->reason = gdb_action_t::ACT_SHUTDOWN;
|
||||
act->data = nemu_state.halt_ret;
|
||||
}
|
||||
}
|
||||
|
||||
__EXPORT void nemu_cont(void *args, gdb_action_t *res) {
|
||||
DbgState *dbg_state = (DbgState *)args;
|
||||
breakpoint_t *stopped_at =
|
||||
cpu_exec_with_bp(-1, dbg_state->bp->data(), dbg_state->bp->size());
|
||||
nemu_is_stopped(res, stopped_at);
|
||||
}
|
||||
|
||||
__EXPORT void nemu_stepi(void *args, gdb_action_t *res) {
|
||||
DbgState *dbg_state = (DbgState *)args;
|
||||
breakpoint_t *stopped_at =
|
||||
cpu_exec_with_bp(1, dbg_state->bp->data(), dbg_state->bp->size());
|
||||
nemu_is_stopped(res, stopped_at);
|
||||
}
|
||||
|
||||
__EXPORT bool nemu_set_bp(void *args, size_t addr, bp_type_t type) {
|
||||
DbgState *dbg_state = (DbgState *)args;
|
||||
for (const auto &bp : *dbg_state->bp) {
|
||||
if (bp.addr == addr && bp.type == type) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
dbg_state->bp->push_back({.addr = addr, .type = type});
|
||||
return true;
|
||||
}
|
||||
|
||||
__EXPORT bool nemu_del_bp(void *args, size_t addr, bp_type_t type) {
|
||||
DbgState *dbg_state = (DbgState *)args;
|
||||
for (auto it = dbg_state->bp->begin(); it != dbg_state->bp->end(); it++) {
|
||||
if (it->addr == addr && it->type == type) {
|
||||
std::swap(*it, *dbg_state->bp->rbegin());
|
||||
dbg_state->bp->pop_back();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
__EXPORT void nemu_on_interrupt(void *args) {
|
||||
nemu_state.state = NEMU_GDB_INTERRUPT;
|
||||
}
|
||||
|
||||
__EXPORT int nemu_read_reg(void *args, int regno, size_t *data) {
|
||||
return isa_read_reg(args, regno, data);
|
||||
}
|
||||
__EXPORT int nemu_write_reg(void *args, int regno, size_t data) {
|
||||
return isa_write_reg(args, regno, data);
|
||||
}
|
||||
|
||||
static struct target_ops nemu_gdbstub_ops = {.cont = nemu_cont,
|
||||
.stepi = nemu_stepi,
|
||||
.read_reg = nemu_read_reg,
|
||||
.write_reg = nemu_write_reg,
|
||||
.read_mem = nemu_read_mem,
|
||||
.write_mem = nemu_write_mem,
|
||||
.set_bp = nemu_set_bp,
|
||||
.del_bp = nemu_del_bp,
|
||||
.on_interrupt = nemu_on_interrupt,
|
||||
.monitor = NULL};
|
||||
static DbgState *pdbg;
|
||||
static gdbstub_t gdbstub_priv;
|
||||
const char SOCKET_ADDR[] = "/tmp/gdbstub-nemu.sock";
|
||||
|
||||
static void init_remote_gdbstub(void *args) {
|
||||
DbgState *dbg_state = (DbgState *)args;
|
||||
pdbg = (DbgState *)args;
|
||||
dbg_state->bp = new std::vector<breakpoint_t>();
|
||||
dbg_state->halt = 0;
|
||||
Assert(dbg_state->bp != NULL, "Failed to allocate breakpoint");
|
||||
}
|
||||
|
||||
__EXPORT void nemu_init(void *args) {
|
||||
init_remote_gdbstub(args);
|
||||
|
||||
void init_rand();
|
||||
void init_mem();
|
||||
|
||||
IFDEF(CONFIG_DEVICE, void init_device());
|
||||
|
||||
init_rand();
|
||||
init_mem();
|
||||
IFDEF(CONFIG_DEVICE, init_device());
|
||||
|
||||
/* Perform ISA dependent initialization. */
|
||||
init_isa();
|
||||
}
|
||||
|
||||
int gdbstub_loop() {
|
||||
if (!gdbstub_init(&gdbstub_priv, &nemu_gdbstub_ops,
|
||||
(arch_info_t)isa_arch_info, NULL, SOCKET_ADDR)) {
|
||||
return EINVAL;
|
||||
}
|
||||
printf("Waiting for gdb connection at %s", SOCKET_ADDR);
|
||||
bool success = gdbstub_run(&gdbstub_priv, pdbg);
|
||||
// gdbstub_close(&gdbstub_priv);
|
||||
return !success;
|
||||
}
|
||||
}
|
|
@ -13,8 +13,12 @@
|
|||
* See the Mulan PSL v2 for more details.
|
||||
***************************************************************************************/
|
||||
|
||||
#include <cpu/cpu.h>
|
||||
#include <errno.h>
|
||||
#include <isa.h>
|
||||
#include <memory/paddr.h>
|
||||
#include <nemu.h>
|
||||
#include <strings.h>
|
||||
#include <utils.h>
|
||||
|
||||
void init_rand();
|
||||
|
@ -22,38 +26,77 @@ void init_log(const char *log_file);
|
|||
void init_mem();
|
||||
void init_difftest(char *ref_so_file, long img_size, int port);
|
||||
void init_device();
|
||||
void init_sdb();
|
||||
void init_disasm(const char *triple);
|
||||
|
||||
char *log_file = NULL;
|
||||
char *elf_file = NULL;
|
||||
char *img_file = NULL;
|
||||
bool enable_gdbstub = false;
|
||||
|
||||
static void welcome() {
|
||||
Log("Trace: %s", MUXDEF(CONFIG_TRACE, ANSI_FMT("ON", ANSI_FG_GREEN), ANSI_FMT("OFF", ANSI_FG_RED)));
|
||||
IFDEF(CONFIG_TRACE, Log("If trace is enabled, a log file will be generated "
|
||||
"to record the trace. This may lead to a large log file. "
|
||||
"If it is not necessary, you can disable it in menuconfig"));
|
||||
Log("Trace: %s", MUXDEF(CONFIG_TRACE, ANSI_FMT("ON", ANSI_FG_GREEN),
|
||||
ANSI_FMT("OFF", ANSI_FG_RED)));
|
||||
IFDEF(CONFIG_TRACE,
|
||||
Log("If trace is enabled, a log file will be generated "
|
||||
"to record the trace. This may lead to a large log file. "
|
||||
"If it is not necessary, you can disable it in menuconfig"));
|
||||
Log("Build time: %s, %s", __TIME__, __DATE__);
|
||||
printf("Welcome to %s-NEMU!\n", ANSI_FMT(str(__GUEST_ISA__), ANSI_FG_YELLOW ANSI_BG_RED));
|
||||
printf("Welcome to %s-NEMU!\n",
|
||||
ANSI_FMT(str(__GUEST_ISA__), ANSI_FG_YELLOW ANSI_BG_RED));
|
||||
printf("For help, type \"help\"\n");
|
||||
}
|
||||
|
||||
#ifndef CONFIG_TARGET_AM
|
||||
#include <getopt.h>
|
||||
|
||||
void sdb_set_batch_mode();
|
||||
|
||||
static char *log_file = NULL;
|
||||
static char *elf_file = NULL;
|
||||
static char *diff_so_file = NULL;
|
||||
static char *img_file = NULL;
|
||||
static int difftest_port = 1234;
|
||||
|
||||
static long load_img() {
|
||||
FILE *fp = NULL;
|
||||
size_t img_filename_len = strlen(img_file);
|
||||
if (img_file == NULL) {
|
||||
Log("No image is given. Use the default build-in image.");
|
||||
return 4096; // built-in image size
|
||||
}
|
||||
|
||||
FILE *fp = fopen(img_file, "rb");
|
||||
Assert(fp, "Can not open '%s'", img_file);
|
||||
// Image file is searched from paths in environment variable NEMU_IMAGES_PATH if it's a relative path
|
||||
if (img_file[0] != '/') {
|
||||
char *search_paths = getenv("NEMU_IMAGES_PATH");
|
||||
if (search_paths == NULL)
|
||||
search_paths = "./";
|
||||
search_paths = strdup(search_paths);
|
||||
Trace("NEMU_IMAGES_PATH=%s", search_paths);
|
||||
|
||||
char *paths_end = strchr(search_paths, '\0');
|
||||
char *p_start = search_paths;
|
||||
do {
|
||||
char *p = strchr(p_start, ':');
|
||||
if (p != NULL)
|
||||
*p = '\0';
|
||||
else
|
||||
p = paths_end;
|
||||
|
||||
char *file_path = malloc(p - p_start + img_filename_len + 2);
|
||||
strcpy(file_path, p_start);
|
||||
strcat(file_path, "/");
|
||||
strcat(file_path, img_file);
|
||||
|
||||
fp = fopen(file_path, "rb");
|
||||
free(file_path);
|
||||
|
||||
if (fp) {
|
||||
Log("Found '%s' in '%s'", img_file, p_start);
|
||||
break;
|
||||
}
|
||||
|
||||
Assert(fp != NULL || errno == ENOENT, "Cannot open '%s'", img_file);
|
||||
p_start = p + 1;
|
||||
} while (p_start < paths_end);
|
||||
free(search_paths);
|
||||
|
||||
Assert(fp, "Cannot find '%s'", img_file);
|
||||
} else {
|
||||
fp = fopen(img_file, "rb");
|
||||
Assert(fp, "Cannot open '%s'", img_file);
|
||||
}
|
||||
|
||||
fseek(fp, 0, SEEK_END);
|
||||
long size = ftell(fp);
|
||||
|
@ -70,69 +113,54 @@ static long load_img() {
|
|||
|
||||
static int parse_args(int argc, char *argv[]) {
|
||||
const struct option table[] = {
|
||||
{"batch" , no_argument , NULL, 'b'},
|
||||
{"log" , required_argument, NULL, 'l'},
|
||||
{"diff" , required_argument, NULL, 'd'},
|
||||
{"port" , required_argument, NULL, 'p'},
|
||||
{"elf" , required_argument, NULL, 'f'},
|
||||
{"help" , no_argument , NULL, 'h'},
|
||||
{0 , 0 , NULL, 0 },
|
||||
{"batch", no_argument, NULL, 'b'}, {"log", required_argument, NULL, 'l'},
|
||||
{"debug", no_argument, NULL, 'g'}, {"elf", required_argument, NULL, 'f'},
|
||||
{"help", no_argument, NULL, 'h'}, {0, 0, NULL, 0},
|
||||
};
|
||||
int o;
|
||||
while ( (o = getopt_long(argc, argv, "-bhl:d:p:", table, NULL)) != -1) {
|
||||
while ((o = getopt_long(argc, argv, "-bhl:d:p:", table, NULL)) != -1) {
|
||||
switch (o) {
|
||||
case 'b': sdb_set_batch_mode(); break;
|
||||
case 'p': sscanf(optarg, "%d", &difftest_port); break;
|
||||
case 'l': log_file = optarg; break;
|
||||
case 'd': diff_so_file = optarg; break;
|
||||
case 'f': elf_file = optarg; break;
|
||||
case 1: img_file = optarg; return 0;
|
||||
default:
|
||||
printf("Usage: %s [OPTION...] IMAGE [args]\n\n", argv[0]);
|
||||
printf("\t-b,--batch run with batch mode\n");
|
||||
printf("\t-l,--log=FILE output log to FILE\n");
|
||||
printf("\t-d,--diff=REF_SO run DiffTest with reference REF_SO\n");
|
||||
printf("\t-p,--port=PORT run DiffTest with port PORT\n");
|
||||
printf("\t-f,--elf=FILE elf file with debug info\n");
|
||||
printf("\n");
|
||||
exit(0);
|
||||
case 'l':
|
||||
log_file = optarg;
|
||||
break;
|
||||
case 'f':
|
||||
elf_file = optarg;
|
||||
break;
|
||||
case 'g':
|
||||
enable_gdbstub = true;
|
||||
break;
|
||||
case 1:
|
||||
img_file = optarg;
|
||||
return 0;
|
||||
default:
|
||||
printf("Usage: %s [OPTION...] IMAGE [args]\n\n", argv[0]);
|
||||
printf("\t-b,--batch run with batch mode\n");
|
||||
printf("\t-g,--debug enable gdb remote server\n");
|
||||
printf("\t-l,--log=FILE output log to FILE\n");
|
||||
printf("\t-f,--elf=FILE elf file with debug info\n");
|
||||
printf("\n");
|
||||
exit(0);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void init_monitor(int argc, char *argv[]) {
|
||||
/* Perform some global initialization. */
|
||||
|
||||
/* Parse arguments. */
|
||||
parse_args(argc, argv);
|
||||
|
||||
/* Set random seed. */
|
||||
init_rand();
|
||||
|
||||
void init_log(const char *log_file);
|
||||
/* Open the log file. */
|
||||
init_log(log_file);
|
||||
|
||||
/* Initialize memory. */
|
||||
init_mem();
|
||||
|
||||
/* Initialize devices. */
|
||||
IFDEF(CONFIG_DEVICE, init_device());
|
||||
|
||||
/* Perform ISA dependent initialization. */
|
||||
init_isa();
|
||||
/* Perform some global initialization. */
|
||||
nemu_init(malloc(nemu_dbg_state_size));
|
||||
|
||||
/* Load the image to memory. This will overwrite the built-in image. */
|
||||
long img_size = load_img();
|
||||
|
||||
/* Initialize differential testing. */
|
||||
init_difftest(diff_so_file, img_size, difftest_port);
|
||||
|
||||
/* Initialize the simple debugger. */
|
||||
init_sdb();
|
||||
load_img();
|
||||
|
||||
// printf("elf_file: %s\n", elf_file);
|
||||
if(elf_file != NULL) {
|
||||
if (elf_file != NULL) {
|
||||
#ifdef CONFIG_FTRACE
|
||||
void init_elf(const char *path);
|
||||
init_elf(elf_file);
|
||||
|
@ -142,14 +170,13 @@ void init_monitor(int argc, char *argv[]) {
|
|||
}
|
||||
|
||||
#ifndef CONFIG_ISA_loongarch32r
|
||||
IFDEF(CONFIG_ITRACE, init_disasm(
|
||||
MUXDEF(CONFIG_ISA_x86, "i686",
|
||||
MUXDEF(CONFIG_ISA_mips32, "mipsel",
|
||||
MUXDEF(CONFIG_ISA_riscv,
|
||||
MUXDEF(CONFIG_RV64, "riscv64",
|
||||
"riscv32"),
|
||||
"bad"))) "-pc-linux-gnu"
|
||||
));
|
||||
IFDEF(CONFIG_ITRACE,
|
||||
init_disasm(
|
||||
MUXDEF(CONFIG_ISA_x86, "i686",
|
||||
MUXDEF(CONFIG_ISA_mips32, "mipsel",
|
||||
MUXDEF(CONFIG_ISA_riscv,
|
||||
MUXDEF(CONFIG_RV64, "riscv64", "riscv32"),
|
||||
"bad"))) "-pc-linux-gnu"));
|
||||
#endif
|
||||
|
||||
/* Display welcome message. */
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -59,7 +59,8 @@ extern "C" void init_disasm(const char *triple) {
|
|||
llvm::MCRegisterInfo *gMRI = nullptr;
|
||||
auto target = llvm::TargetRegistry::lookupTarget(gTriple, errstr);
|
||||
if (!target) {
|
||||
llvm::errs() << "Can't find target for " << gTriple << ": " << errstr << "\n";
|
||||
llvm::errs() << "Can't find target for " << gTriple << ": " << errstr
|
||||
<< "\n";
|
||||
assert(0);
|
||||
}
|
||||
|
||||
|
@ -77,22 +78,24 @@ extern "C" void init_disasm(const char *triple) {
|
|||
gMRI = target->createMCRegInfo(gTriple);
|
||||
auto AsmInfo = target->createMCAsmInfo(*gMRI, gTriple, MCOptions);
|
||||
#if LLVM_VERSION_MAJOR >= 13
|
||||
auto llvmTripleTwine = Twine(triple);
|
||||
auto llvmtriple = llvm::Triple(llvmTripleTwine);
|
||||
auto Ctx = new llvm::MCContext(llvmtriple,AsmInfo, gMRI, nullptr);
|
||||
auto llvmTripleTwine = Twine(triple);
|
||||
auto llvmtriple = llvm::Triple(llvmTripleTwine);
|
||||
auto Ctx = new llvm::MCContext(llvmtriple, AsmInfo, gMRI, nullptr);
|
||||
#else
|
||||
auto Ctx = new llvm::MCContext(AsmInfo, gMRI, nullptr);
|
||||
auto Ctx = new llvm::MCContext(AsmInfo, gMRI, nullptr);
|
||||
#endif
|
||||
gDisassembler = target->createMCDisassembler(*gSTI, *Ctx);
|
||||
gIP = target->createMCInstPrinter(llvm::Triple(gTriple),
|
||||
AsmInfo->getAssemblerDialect(), *AsmInfo, *gMII, *gMRI);
|
||||
AsmInfo->getAssemblerDialect(), *AsmInfo,
|
||||
*gMII, *gMRI);
|
||||
gIP->setPrintImmHex(true);
|
||||
gIP->setPrintBranchImmAsAddress(true);
|
||||
if (isa == "riscv32" || isa == "riscv64")
|
||||
gIP->applyTargetSpecificCLOption("no-aliases");
|
||||
}
|
||||
|
||||
extern "C" void disassemble(char *str, int size, uint64_t pc, uint8_t *code, int nbyte) {
|
||||
extern "C" void disassemble(char *str, int size, uint64_t pc, uint8_t *code,
|
||||
int nbyte) {
|
||||
MCInst inst;
|
||||
llvm::ArrayRef<uint8_t> arr(code, nbyte);
|
||||
uint64_t dummy_size = 0;
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
#**************************************************************************************/
|
||||
|
||||
ifneq ($(CONFIG_ITRACE)$(CONFIG_IQUEUE),)
|
||||
CXXSRC = src/utils/disasm.cc
|
||||
CXXSRC += src/utils/disasm.cc
|
||||
CXXFLAGS += $(shell llvm-config --cxxflags) -fPIE
|
||||
LIBS += $(shell llvm-config --libs)
|
||||
endif
|
||||
|
|
|
@ -17,10 +17,12 @@ static int cmp_func_t(const void *a, const void *b) {
|
|||
|
||||
static func_t *get_func(vaddr_t addr) {
|
||||
int l = 0, r = func_table_len - 1;
|
||||
while(l <= r) {
|
||||
while (l <= r) {
|
||||
int mid = (l + r) / 2;
|
||||
if(func_table[mid].start <= addr) l = mid + 1;
|
||||
else r = mid - 1;
|
||||
if (func_table[mid].start <= addr)
|
||||
l = mid + 1;
|
||||
else
|
||||
r = mid - 1;
|
||||
}
|
||||
return l == 0 ? NULL : &func_table[l - 1];
|
||||
}
|
||||
|
@ -33,20 +35,27 @@ void init_elf(const char *path) {
|
|||
func_table = (func_t *)calloc(func_table_size, sizeof(func_t));
|
||||
assert(func_table);
|
||||
|
||||
FAILED_GOTO(failed_header, fread(&header, sizeof(Elf32_Ehdr), 1, elf_file) <= 0);
|
||||
FAILED_GOTO(failed_header,
|
||||
fread(&header, sizeof(Elf32_Ehdr), 1, elf_file) <= 0);
|
||||
FAILED_GOTO(failed_header, fseek(elf_file, header.e_shoff, SEEK_SET) != 0);
|
||||
FAILED_GOTO(failed_header, fread(section_header, header.e_shentsize, header.e_shnum, elf_file) <= 0);
|
||||
FAILED_GOTO(failed_header, fread(section_header, header.e_shentsize,
|
||||
header.e_shnum, elf_file) <= 0);
|
||||
|
||||
char *shstrtab = calloc(1, section_header[header.e_shstrndx].sh_size);
|
||||
FAILED_GOTO(failed_shstrtab, fseek(elf_file, section_header[header.e_shstrndx].sh_offset, SEEK_SET) != 0);
|
||||
FAILED_GOTO(failed_shstrtab, fread(shstrtab, section_header[header.e_shstrndx].sh_size, 1, elf_file) <= 0);
|
||||
FAILED_GOTO(failed_shstrtab,
|
||||
fseek(elf_file, section_header[header.e_shstrndx].sh_offset,
|
||||
SEEK_SET) != 0);
|
||||
FAILED_GOTO(failed_shstrtab,
|
||||
fread(shstrtab, section_header[header.e_shstrndx].sh_size, 1,
|
||||
elf_file) <= 0);
|
||||
|
||||
Elf32_Shdr *symtab = NULL, *strtab = NULL;
|
||||
for(int i = 0; i < header.e_shnum; i++) {
|
||||
for (int i = 0; i < header.e_shnum; i++) {
|
||||
psh = section_header + i;
|
||||
if (psh->sh_type == SHT_SYMTAB) {
|
||||
symtab = psh;
|
||||
} else if (psh->sh_type == SHT_STRTAB && strncmp(shstrtab + psh->sh_name, ".strtab", 8) == 0) {
|
||||
} else if (psh->sh_type == SHT_STRTAB &&
|
||||
strncmp(shstrtab + psh->sh_name, ".strtab", 8) == 0) {
|
||||
strtab = psh;
|
||||
}
|
||||
}
|
||||
|
@ -54,22 +63,28 @@ void init_elf(const char *path) {
|
|||
int sym_length = symtab->sh_size / sizeof(Elf32_Sym);
|
||||
Elf32_Sym *sym = calloc(sym_length, sizeof(Elf32_Sym));
|
||||
assert(sym);
|
||||
FAILED_GOTO(failed_funcname, fseek(elf_file, symtab->sh_offset, SEEK_SET) != 0);
|
||||
FAILED_GOTO(failed_funcname, fread(sym, sizeof(Elf32_Sym), sym_length, elf_file) <= 0);
|
||||
|
||||
for(int j = 0; j < sym_length; j++) {
|
||||
if(ELF32_ST_TYPE(sym[j].st_info) != STT_FUNC) continue;
|
||||
FAILED_GOTO(failed_funcname,
|
||||
fseek(elf_file, symtab->sh_offset, SEEK_SET) != 0);
|
||||
FAILED_GOTO(failed_funcname,
|
||||
fread(sym, sizeof(Elf32_Sym), sym_length, elf_file) <= 0);
|
||||
|
||||
for (int j = 0; j < sym_length; j++) {
|
||||
if (ELF32_ST_TYPE(sym[j].st_info) != STT_FUNC)
|
||||
continue;
|
||||
// Only read function type symbol
|
||||
func_t *f = &func_table[func_table_len];
|
||||
char *func = (char *)malloc(30);
|
||||
FAILED_GOTO(failed_funcname, fseek(elf_file, strtab->sh_offset + sym[j].st_name, SEEK_SET) != 0);
|
||||
FAILED_GOTO(failed_funcname,
|
||||
fseek(elf_file, strtab->sh_offset + sym[j].st_name, SEEK_SET) !=
|
||||
0);
|
||||
FAILED_GOTO(failed_funcname, fgets(func, 30, elf_file) <= 0);
|
||||
f->start = sym[j].st_value;
|
||||
f->len = sym[j].st_size;
|
||||
f->name = func;
|
||||
++func_table_len;
|
||||
if(func_table_len >= func_table_size) {
|
||||
Assert(func_table_size * 2 > func_table_size, "Function table exceed memory limit");
|
||||
if (func_table_len >= func_table_size) {
|
||||
Assert(func_table_size * 2 > func_table_size,
|
||||
"Function table exceed memory limit");
|
||||
func_table_size *= 2;
|
||||
func_table = realloc(func_table, func_table_size * sizeof(func_t));
|
||||
Assert(func_table, "Function table exceed memory limit");
|
||||
|
@ -88,10 +103,12 @@ failed_funcname:
|
|||
failed_shstrtab:
|
||||
free(shstrtab);
|
||||
failed_header:
|
||||
for(int i = 0; i < func_table_len; i++) {
|
||||
for (int i = 0; i < func_table_len; i++) {
|
||||
func_t *f = &func_table[i];
|
||||
if(f->name) { free(f->name); }
|
||||
}
|
||||
if (f->name) {
|
||||
free(f->name);
|
||||
}
|
||||
}
|
||||
free(func_table);
|
||||
Error("Failed reading elf file");
|
||||
return;
|
||||
|
@ -114,11 +131,12 @@ void ftrace_return(vaddr_t pc, vaddr_t addr) {
|
|||
ftrace_stack_len--) {
|
||||
vaddr_t tco_addr = ftrace_stack[ftrace_stack_len];
|
||||
func_t *f = get_func(tco_addr);
|
||||
Trace("%*s0x%x ret 0x%x <%s+0x%x> (TCO)", ftrace_stack_len, "", pc, tco_addr,
|
||||
f == NULL ? "???" : f->name, f == NULL ? addr : addr - f->start);
|
||||
Trace("%*s0x%x ret 0x%x <%s+0x%x> (TCO)", ftrace_stack_len, "", pc,
|
||||
tco_addr, f == NULL ? "???" : f->name,
|
||||
f == NULL ? addr : addr - f->start);
|
||||
}
|
||||
func_t *f = get_func(addr);
|
||||
Trace("%*s0x%x ret 0x%x <%s+0x%x>", ftrace_stack_len, "", pc, addr,
|
||||
Trace("%*s0x%x ret 0x%x <%s+0x%x>", ftrace_stack_len, "", pc, addr,
|
||||
f == NULL ? "???" : f->name, f == NULL ? addr : addr - f->start);
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -1,10 +1,9 @@
|
|||
TEST_SRCS += tests/expr_test.c
|
||||
YACC = bison
|
||||
TEST_SRCS +=
|
||||
|
||||
$(OBJ_DIR)/%: %.c $(TEST_OBJS) app
|
||||
@mkdir -p $(dir $@)
|
||||
@echo + CC $<
|
||||
@$(CC) $(CFLAGS) -o $@.o -c $<
|
||||
@$(CC) $(CFLAGS) -o $@.o -c $<
|
||||
@echo + LD $@
|
||||
@$(LD) $(LIBS) $(LDFLAGS) -o $@ $(TEST_OBJS) $@.o
|
||||
@$@
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue