Compare commits

...

105 commits

Author SHA1 Message Date
4c540bd109
nemu,build: build libnemu with nix
All checks were successful
Build abstract machine with nix / build-packages (abstract-machine) (push) Successful in 9s
Build abstract machine with nix / build-packages (nemu) (push) Successful in 20s
Build abstract machine with nix / build-packages (nemu-lib) (push) Successful in 9s
Build abstract machine with nix / build-packages (rv32Cross.abstract-machine) (push) Successful in 8s
Build npc tests / npc-build (flow) (push) Successful in 8s
Build npc tests / npc-build (flow-simlib) (push) Successful in 9s
2024-08-15 18:36:23 +08:00
0e408882b2
am,fix: printf cannot correctly handle trailing zeros
All checks were successful
Build abstract machine with nix / build-packages (abstract-machine) (push) Successful in 16s
Build abstract machine with nix / build-packages (nemu) (push) Successful in 7s
Build abstract machine with nix / build-packages (nemu-lib) (push) Successful in 7s
Build abstract machine with nix / build-packages (rv32Cross.abstract-machine) (push) Successful in 12s
Build npc tests / npc-build (flow) (push) Successful in 8s
Build npc tests / npc-build (flow-simlib) (push) Successful in 9s
2024-08-15 17:38:12 +08:00
3d64dbd200
am,build: put libm into am-native export interface
All checks were successful
Build abstract machine with nix / build-packages (abstract-machine) (push) Successful in 16s
Build abstract machine with nix / build-packages (nemu) (push) Successful in 7s
Build abstract machine with nix / build-packages (nemu-lib) (push) Successful in 7s
Build abstract machine with nix / build-packages (rv32Cross.abstract-machine) (push) Successful in 11s
Build npc tests / npc-build (flow) (push) Successful in 8s
Build npc tests / npc-build (flow-simlib) (push) Successful in 9s
- TODO: don't no why libm is needed, need further investigation.
2024-08-15 16:38:56 +08:00
1f3e64bb37
am,build: fix typo
All checks were successful
Build abstract machine with nix / build-packages (abstract-machine) (push) Successful in 16s
Build abstract machine with nix / build-packages (nemu) (push) Successful in 7s
Build abstract machine with nix / build-packages (nemu-lib) (push) Successful in 7s
Build abstract machine with nix / build-packages (rv32Cross.abstract-machine) (push) Successful in 12s
Build npc tests / npc-build (flow) (push) Successful in 7s
Build npc tests / npc-build (flow-simlib) (push) Successful in 9s
2024-08-15 16:13:42 +08:00
bc04c05081
am,build: propagate SDL to dependents 2024-08-15 16:13:15 +08:00
b403f8a40b
ci: fix am native tests
All checks were successful
Build abstract machine with nix / build-packages (abstract-machine) (push) Successful in 17s
Build abstract machine with nix / build-packages (nemu) (push) Successful in 8s
Build abstract machine with nix / build-packages (nemu-lib) (push) Successful in 7s
Build abstract machine with nix / build-packages (rv32Cross.abstract-machine) (push) Successful in 12s
Build npc tests / npc-build (flow) (push) Successful in 8s
Build npc tests / npc-build (flow-simlib) (push) Successful in 10s
2024-08-15 14:55:51 +08:00
5ba306c74e
npc,ci: fix wrong working directory
Some checks failed
Build abstract machine with nix / build-packages (abstract-machine) (push) Failing after 13s
Build abstract machine with nix / build-packages (nemu) (push) Successful in 8s
Build abstract machine with nix / build-packages (nemu-lib) (push) Successful in 8s
Build abstract machine with nix / build-packages (rv32Cross.abstract-machine) (push) Successful in 8s
Build npc tests / npc-build (flow) (push) Successful in 2m29s
Build npc tests / npc-build (flow-simlib) (push) Successful in 1m45s
2024-08-14 17:18:07 +08:00
64aee9ae21
npc,ci: add npc to nix packages
Some checks failed
Run CTests within npc / npc-test (flow) (push) Failing after 8s
Build abstract machine with nix / build-packages (abstract-machine) (push) Failing after 14s
Build abstract machine with nix / build-packages (nemu) (push) Successful in 41s
Build abstract machine with nix / build-packages (nemu-lib) (push) Successful in 9s
Build abstract machine with nix / build-packages (rv32Cross.abstract-machine) (push) Successful in 8s
Run CTests within npc / npc-test (flow-simlib) (push) Failing after 7s
2024-08-14 17:01:37 +08:00
8ee1551dc2
refactor: remove submodules
Some checks failed
Run CTests within npc / npc-test (push) Failing after 9m51s
Build abstract machine with nix / build-abstract-machine (push) Failing after 11m41s
2024-08-13 20:11:38 +08:00
96ae890632
nemu,chore: reformat c/c++ code 2024-08-13 18:49:08 +08:00
a5790308f0
npc,feat: add csr
Some checks failed
Build abstract machine with nix / build-abstract-machine (push) Failing after 1m1s
Run CTests within npc / npc-test (push) Failing after 56s
2024-08-11 20:25:42 +08:00
ba18436c6c
npc,chore: reformat scala code 2024-08-09 19:58:28 +08:00
d9efde7a44
npc: add cmake-format for verilate macro
Some checks failed
Build abstract machine with nix / build-abstract-machine (push) Failing after 40s
Run CTests within npc / npc-test (push) Failing after 42s
2024-08-02 12:08:03 +08:00
de9f770d08
npc,refactor: remove original difftest wrapper, cleanup code
Some checks failed
Build abstract machine with nix / build-abstract-machine (push) Failing after 53s
Run CTests within npc / npc-test (push) Failing after 48s
2024-08-02 11:18:52 +08:00
85d7840804
npc: split gdbstub api into seperate file 2024-08-01 18:53:17 +08:00
fed4ac225d
abstract-machine,nemu: add keyboard support
Some checks failed
Build abstract machine with nix / build-abstract-machine (push) Failing after 49s
Run CTests within npc / npc-test (push) Failing after 54s
2024-07-26 13:44:52 +08:00
c9ad69a32d
nemu: break before executing instruction
Some checks failed
Build abstract machine with nix / build-abstract-machine (push) Failing after 45s
Run CTests within npc / npc-test (push) Failing after 47s
2024-07-25 17:56:30 +08:00
385d448746
abstract-machine(nemu): support context switch 2024-07-25 17:16:41 +08:00
ef51673020
refactor: move cross compile to seperate flake attribute
Some checks failed
Build abstract machine with nix / build-abstract-machine (push) Failing after 46s
Run CTests within npc / npc-test (push) Failing after 48s
2024-07-23 17:16:40 +08:00
422ff9e006
refactor: drop internal difftest support 2024-07-23 17:15:35 +08:00
f852ee8689
chore: update dependency
Some checks failed
Build abstract machine with nix / build-abstract-machine (push) Failing after 7m12s
Run CTests within npc / npc-test (push) Failing after 6m24s
2024-07-22 18:37:31 +08:00
b317827c3c
chore: clang format 2024-07-22 17:45:49 +08:00
f5ea31f676
chore(nemu): default to use unix socket for gdbstub 2024-07-18 19:21:17 +08:00
d46cd7b4ae
feat(npc): port to export gdbstub api 2024-07-18 19:16:15 +08:00
8ffab061ed
feat: export gdbstub api to be used by difftest
Some checks failed
Build abstract machine with nix / build-abstract-machine (push) Failing after 1m41s
Run CTests within npc / npc-test (push) Failing after 2m25s
2024-07-16 14:40:01 +08:00
5a97fab28f
feat: add diffu as submodule 2024-07-16 14:35:35 +08:00
2ab098d181
npc: drop sdb, use gdb as frontend 2024-07-10 20:27:09 +08:00
7c982b238b
nemu: update devShell deps
Some checks failed
Build abstract machine with nix / build-abstract-machine (push) Failing after 1m10s
Run CTests within npc / npc-test (push) Failing after 1m37s
2024-07-09 20:43:47 +08:00
3acab0a751
npc: wip, cannot build 2024-07-09 20:42:01 +08:00
29a9850210
chore: update gitignore and submodules
Some checks failed
Build abstract machine with nix / build-abstract-machine (push) Failing after 2m30s
Run CTests within npc / npc-test (push) Failing after 2m40s
2024-07-09 18:44:26 +08:00
955f1f2d79
klib: printf support 2024-07-09 17:26:11 +08:00
f38674ce79
nemu: use NEMU_IMAGES_PATH as image search paths 2024-07-09 17:06:15 +08:00
7f0d1ba75a
feat(nemu): gdb remote debug 2024-04-25 16:54:27 +08:00
a54c0d6480
build: build am for multiple platform in parallel 2024-04-14 14:39:57 +08:00
6ab5d4c156
build: fix rules and dependencies
Some checks failed
Build abstract machine with nix / build-abstract-machine (push) Failing after 14m31s
Run CTests within npc / npc-test (push) Failing after 15m23s
2024-04-12 16:39:50 +08:00
4bc4c34af4
build: pin sbt version 2024-04-12 15:22:47 +08:00
8665aaf7d2
fix(npc): fix branch, load memory and slt related instructions 2024-04-12 14:10:32 +08:00
9f64a88f8d
feat(npc): add mtrace 2024-04-12 09:35:41 +08:00
4c07b66093
build: fix ysyx tracker
The git tracker for npc is not working since I refactor build system at commit f02d5eb2.
2024-04-11 14:07:05 +08:00
e99236f711
feat(npc): ebreak support through external inst matching 2024-04-11 11:44:54 +08:00
55230247b2
fix(npc): jalr wrong imm 2024-04-11 09:21:17 +08:00
89847cfdb4
feat(npc): difftest execution abstraction layer 2024-04-10 20:12:41 +08:00
e828e140cd
feat(sdb): support sdb
Some checks failed
Build abstract machine with nix / build-abstract-machine (push) Successful in 2m41s
Run CTests within npc / npc-test (push) Has been cancelled
2024-04-09 17:03:21 +08:00
8500df8a6e
feat(npc): implement all riscv32i intructions (untested) 2024-04-08 22:51:51 +08:00
50f7d4d7b9
ci: fix action cache
All checks were successful
Build abstract machine with nix / build-abstract-machine (push) Successful in 1m48s
Run CTests within npc / npc-test (push) Successful in 2m34s
2024-04-05 14:53:20 +08:00
xin
ca06354f16 Merge pull request 'Add difftest support to npc' (#3) from npc-debug-tools into master
Some checks failed
Build abstract machine with nix / build-abstract-machine (push) Successful in 3m58s
Run CTests within npc / npc-test (push) Failing after 8m21s
Reviewed-on: #3
2024-04-05 05:14:44 +00:00
e1438e25ed
ci: add npc difftest
All checks were successful
Run CTests within npc / npc-test (push) Successful in 8m53s
Build abstract machine with nix / build-abstract-machine (pull_request) Successful in 4m37s
2024-04-05 12:58:16 +08:00
6f7d7ba383
chore: move components to seperate folder 2024-04-05 10:40:55 +08:00
c242e8c507
chore: move npc devshell to root directory 2024-04-05 10:23:28 +08:00
f02d5eb2f1
build: split CMakeLists
- Put add_custom_command into seperate ChiselBuild module. Otherwise
  final target cannot correctly depends on scala sources.
2024-04-05 02:12:30 +08:00
849f2bb5f3
feat: difftest framework 2024-04-05 00:16:58 +08:00
97cf418c86
refactor: move to dpi module for memory access 2024-04-03 22:42:39 +08:00
a478ef7639
export memory read and write functions 2024-04-02 16:15:16 +08:00
a91adb3a7d
wrap verilated model 2024-04-02 14:30:14 +08:00
db66021248
Class wrapper for regiters 2024-04-02 13:35:29 +08:00
84c8de8461
npc: reg file access through vpi 2024-03-29 10:35:49 +08:00
dc2cb010ce
ci: run only on push to master
All checks were successful
Build abstract machine with nix / build-abstract-machine (push) Successful in 1m21s
2024-03-26 13:34:52 +08:00
e2602b5bad
ci: fix push to cachix
All checks were successful
Build abstract machine with nix / build-abstract-machine (push) Successful in 8m25s
2024-03-26 13:06:25 +08:00
2209c26dce
nemu: fix some memory bug
All checks were successful
Build abstract machine with nix / build-abstract-machine (push) Successful in 8m7s
2024-03-26 12:43:03 +08:00
b02b1d2e37
ci: build with submodules turned on for nix
Some checks failed
Build abstract machine with nix / build-abstract-machine (push) Failing after 8m23s
2024-03-26 11:39:49 +08:00
xin
c29cbf8090 Merge pull request 'npc: basic architecture implementation' (#2) from npc into master
Some checks failed
Build abstract machine with nix / build-abstract-machine (push) Failing after 7m45s
Reviewed-on: #2
2024-03-26 03:12:58 +00:00
xin
642444b384 Merge branch 'master' into npc
Some checks failed
Build abstract machine with nix / build-abstract-machine (push) Has been cancelled
2024-03-26 03:12:30 +00:00
xin
1cd55fb7cb Merge pull request 'pa2.2: klib and difftest' (#1) from pa2 into master
Some checks failed
Build abstract machine with nix / build-abstract-machine (push) Has been cancelled
Reviewed-on: #1
2024-03-26 03:00:49 +00:00
d5feb71b50
nemu: try difftest
Some checks failed
Build abstract machine with nix / build-abstract-machine (push) Failing after 7m47s
2024-03-26 01:53:17 +08:00
d5521806d9
ci: init
Some checks failed
Build abstract machine with nix / build-abstract-machine (push) Failing after 7m49s
2024-03-26 00:23:13 +08:00
2cc992a181
am: build with nix 2024-03-25 17:33:04 +08:00
8545a92c1f
pa2.2: nemu small fixes 2024-03-25 17:02:12 +08:00
da0c42422d
build: init cmake build system for am 2024-03-25 16:56:16 +08:00
18db852763 pa2.2: fix ftrace switch 2024-03-20 20:11:21 +08:00
a62a132587 pa2.2: cleanup includes 2024-03-20 20:07:28 +08:00
9229e4318e pa2.2: add ftrace 2024-03-20 19:46:54 +08:00
0f7c6fd508
pa2.2: add memory tracer 2024-03-13 18:14:17 +08:00
c917083554
pa2.2: add ITRACE buffer 2024-03-13 16:54:00 +08:00
f1a575b2fd
npc: basic architecture implementation 2024-03-13 14:53:31 +08:00
d67fb1138a
npc: Register File 2024-03-11 21:41:45 +08:00
tracer-ysyx
64f891308e > configure(npc)
ysyx_22040000 李心杨
 Linux calcite 6.6.19 #1-NixOS SMP PREEMPT_DYNAMIC Fri Mar  1 12:35:11 UTC 2024 x86_64 GNU/Linux
  18:16:48  up   3:36,  2 users,  load average: 0.28, 0.25, 0.34
2024-03-07 18:16:48 +08:00
833cf7b6d1
pa2.1: add M extension support, finish pa2.1 2024-03-07 13:19:12 +08:00
e764133868
pa2.1: support RV32I instructions 2024-03-06 12:50:56 +08:00
3c7c5f060e
build: initial support for building nemu, am-kernels with nix 2024-03-04 12:05:43 +08:00
f9808d0a40
before pa2 2024-03-04 11:57:52 +08:00
86ba43a25b
fix: see NJU-ProjectN/nemu#85 2024-03-03 20:58:29 +08:00
12f5ba0897
NJU-ProjectN/am-kernels ics2021 initialized without tracing
NJU-ProjectN/am-kernels bb725d6f8223dd7de831c3b692e8c4531e9d01af kernels,demo,donut: only clear screen before drawing
2024-03-03 11:26:08 +08:00
504d270947 pa1.3: watchpoint support 2024-02-08 20:07:03 +08:00
2675a647b0
fix: change x paddr to vaddr 2024-02-05 22:53:39 +08:00
4aa536e1ef
pa1.2: fix include and word type 2024-01-13 11:42:35 +08:00
ebece52aec
pa1.2: remove unused expr parsing code 2024-01-13 10:39:51 +08:00
e19e89f70e
pa1.2: add unit tests 2024-01-13 10:38:20 +08:00
9cca9de2a8
pa1.2: use flex and bason to implement expr parser 2024-01-12 22:16:35 +08:00
69264e69c6
pa1.1: add handler for x, info, si 2024-01-11 23:00:49 +08:00
4770b4ce97
fix: failed at quit 2024-01-11 17:36:00 +08:00
1af1dbcd20
fix: always false assertion 2024-01-11 17:29:23 +08:00
096cc220d1
nemu: basic devShell 2024-01-11 17:14:41 +08:00
fd3838a61d
fix: unnecessary chisel test 2024-01-11 15:15:33 +08:00
4a38cb566b
refactor: clean SegControllerGenerator 2024-01-10 21:45:50 +08:00
674702b552
fix counter error 2024-01-10 20:54:34 +08:00
1118f64668
Add ps/2 keyboard module 2024-01-10 20:20:45 +08:00
0b34b19bdf
implement keyboard controller 2024-01-08 18:29:28 +08:00
a2986aab78 build: tracking to git when build and configure 2024-01-06 01:01:02 +08:00
ccbcbabb27 fix: missing files from git 2024-01-05 23:57:11 +08:00
77ea7e3b8c fix: add constrain file to git 2024-01-05 23:52:54 +08:00
1702da0a0a build: move to cmake 2024-01-05 23:50:26 +08:00
38818f6f66 build: add nvboard support to led light 2024-01-01 14:57:55 +08:00
8e861a43fb NJU-ProjectN/nvboard master initialized without tracing
NJU-ProjectN/nvboard ea8f0c15cc5ece3e6a0790dcff727dfa36503557 Merge pull request #23 from NJU-ProjectN/macOS
2023-12-23 20:23:56 +08:00
97df569747 create Makefile for example in verilator manual 2023-12-23 20:23:18 +08:00
f6803239c7 nix flake for npc 2023-12-23 19:26:57 +08:00
185 changed files with 8696 additions and 1330 deletions

4
.clang-format Normal file
View file

@ -0,0 +1,4 @@
---
Language: Cpp
BasedOnStyle: LLVM
ReflowComments: false

View 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 }}

View file

@ -0,0 +1,21 @@
name: Build npc tests
on: [push]
jobs:
npc-build:
strategy:
matrix:
package: [ "flow", "flow-simlib"]
runs-on: nix
defaults:
run:
working-directory: ./npc
steps:
- uses: https://github.com/cachix/cachix-action@v14
with:
name: ysyx
authToken: '${{ secrets.CACHIX_SIGNING_KEY }}'
- uses: actions/checkout@v4
- name: Build package
run: |
nix build -L .#${{ matrix.package }}

19
.gitignore vendored
View file

@ -1,13 +1,8 @@
*.*
*
!*/
!/nemu/*
!/nexus-am/*
!/nanos-lite/*
!/navy-apps/*
!/npc/*
!Makefile
!README.md
!.gitignore
!init.sh
*/.gdbinit
difftest/
/fceux-am
/nvboard
**/.cache
**/result
/.pre-commit-config.yaml
**/.vscode/

7
.gitmodules vendored Normal file
View file

@ -0,0 +1,7 @@
[submodule "am-kernels"]
path = am-kernels
url = https://git.xinyang.life/xin/am-kernels.git
branch = dev
[submodule "diffu"]
path = diffu
url = git@github.com:xinyangli/diffu.git

2
.scalafmt.conf Normal file
View file

@ -0,0 +1,2 @@
version = 3.7.17
runner.dialect = scala213source3

View file

@ -4,7 +4,7 @@ STUNAME = 李心杨
# DO NOT modify the following code!!!
TRACER = tracer-ysyx
GITFLAGS = -q --author='$(TRACER) <tracer@ysyx.org>' --no-verify --allow-empty
GITFLAGS = -q --author='$(TRACER) <tracer@ysyx.org>' --no-verify --allow-empty --no-gpg-sign
YSYX_HOME = $(NEMU_HOME)/..
WORK_BRANCH = $(shell git rev-parse --abbrev-ref HEAD)

View file

@ -1,19 +1,8 @@
*
!*/
!*.h
!*.c
!*.cc
!*.S
!*.ld
!*.sh
!*.py
!*.mk
!Makefile
!README
!LICENSE
.*
_*
*~
build/
!.gitignore
**/.direnv/
**/build/
**/.envrc
**/.cache
out/
.vscode
compile_commands.json
cmakeUserh

View file

@ -0,0 +1,126 @@
cmake_minimum_required(VERSION 3.22)
project(abstract-machine)
enable_language(CXX C ASM)
set(CMAKE_C_STANDARD 11)
set(CMAKE_CXX_STANDARD 11)
include(CMakeDependentOption)
include(CMakePackageConfigHelpers) # Used to find libcheck
include(CTest)
include(GNUInstallDirs)
# -- General options
set(ISA CACHE STRING "Target ISA")
set_property(CACHE ISA PROPERTY STRINGS "riscv" "x86" "x86_64" "native")
string(TOUPPER ${ISA} ISA_UPPER)
cmake_dependent_option(__PLATFORM_NEMU__ "Run on NEMU" ON
"ISA MATCHES \"(riscv | x86)\"" OFF)
cmake_dependent_option(__PLATFORM_NPC__ "Run on NPC" ON "ISA MATCHES riscv" OFF)
cmake_dependent_option(__PLATFORM_NATIVE__ "Run on native" ON
"ISA MATCHES native" OFF)
# -- Set PLATFORM according to options
set(MATCH_PLATFORM_PATTERN "^__PLATFORM_([A-Z]*)__$")
get_cmake_property(CACHE_VARS CACHE_VARIABLES)
message(STATUS "ISA: ${ISA}")
foreach(VAR IN LISTS CACHE_VARS)
if(VAR MATCHES ${MATCH_PLATFORM_PATTERN})
# Retrieve the value of the cache variable
get_property(
VAR_VALUE
CACHE ${VAR}
PROPERTY VALUE)
set(PLATFORM_UPPER ${CMAKE_MATCH_1})
string(TOLOWER ${PLATFORM_UPPER} PLATFORM)
list(APPEND PLATFORMS ${PLATFORM})
message(STATUS "Variable: ${VAR}=${VAR_VALUE}, Platform: ${PLATFORM}")
endif()
endforeach()
if((NOT PLATFORM) AND (NOT ISA MATCHES native))
message(FATAL_ERROR "Platform not given!")
endif()
set(SUPPORTED_ARCH "riscv-nemu" "riscv-npc" "native")
foreach(PLATFORM IN LISTS PLATFORMS)
if(${ISA} MATCHES "native")
set(ARCH "native")
else()
set(ARCH ${ISA}-${PLATFORM})
endif()
if(NOT ARCH IN_LIST SUPPORTED_ARCH)
message(
FATAL_ERROR
"Given ISA-PLATFORM (${ISA}-${PLATFORM}) does not match one of the following: ${SUPPORTED_ARCH}"
)
endif()
endforeach()
# -- Target specific options
cmake_dependent_option(NATIVE_USE_KLIB "Use Klib even if on native" ON
"NOT __ISA_NATIVE__" OFF)
# -- Add compile definitions based on options
list(APPEND CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake")
# NOTE: klib and am include header files in each other, so we need to create
# interface libraries for correct dependency
add_library(am_interface INTERFACE)
target_include_directories(
am_interface
INTERFACE $<BUILD_INTERFACE:${CMAKE_SOURCE_DIR}/am/include>
$<BUILD_INTERFACE:${CMAKE_SOURCE_DIR}/am/src>
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>)
target_compile_definitions(am_interface INTERFACE ARCH_H=<arch/${ISA}.h>
"__ISA__=\"${ISA}\"")
file(GLOB_RECURSE AM_HEADERS "${CMAKE_SOURCE_DIR}/am/include/*.h")
target_sources(
am_interface
PUBLIC FILE_SET
am_headers
TYPE
HEADERS
BASE_DIRS
${CMAKE_SOURCE_DIR}/am/include
FILES
${AM_HEADERS})
add_library(klib_interface INTERFACE)
target_include_directories(
klib_interface
INTERFACE $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/klib/include>
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>)
file(GLOB_RECURSE KLIB_HEADERS "${CMAKE_SOURCE_DIR}/klib/include/*.h")
target_sources(
klib_interface
PUBLIC FILE_SET
klib_headers
TYPE
HEADERS
BASE_DIRS
${CMAKE_SOURCE_DIR}/klib/include
FILES
${KLIB_HEADERS})
install(
TARGETS am_interface klib_interface
EXPORT interfaceTargets
FILE_SET klib_headers FILE_SET am_headers
INCLUDES
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})
install(
EXPORT interfaceTargets
FILE interfaceTargets.cmake
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake)
add_subdirectory(klib)
add_subdirectory(am)
# -- Test depends on klib and am should be added last.
add_subdirectory(klib/tests)

View file

@ -0,0 +1,29 @@
{
"version": 6,
"configurePresets": [
{
"name": "native",
"displayName": "Native",
"generator": "Unix Makefiles",
"binaryDir": "${sourceDir}/out/build/${presetName}",
"cacheVariables": {
"CMAKE_BUILD_TYPE": "RelWithDebInfo",
"ISA": "native",
"__PLATFORM_NATIVE__": true,
"NATIVE_USE_KLIB": true
}
},
{
"name": "riscv",
"displayName": "RV32 all platform",
"generator": "Unix Makefiles",
"binaryDir": "${sourceDir}/out/build/${presetName}",
"cacheVariables": {
"CMAKE_BUILD_TYPE": "RelWithDebInfo",
"ISA": "riscv",
"__PLATFORM_NPC__": true,
"__PLATFORM_NEMU__": true
}
}
]
}

View 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"
}
]
}

View file

@ -47,33 +47,32 @@ endif
### Create the destination directory (`build/$ARCH`)
WORK_DIR = $(shell pwd)
DST_DIR = $(WORK_DIR)/build/$(ARCH)
BUILD_DIR ?= $(WORK_DIR)/build
DST_DIR = $(BUILD_DIR)/$(ARCH)
$(shell mkdir -p $(DST_DIR))
### Compilation targets (a binary image or archive)
IMAGE_REL = build/$(NAME)-$(ARCH)
IMAGE_REL = $(DST_DIR)/$(NAME)-$(ARCH)
IMAGE = $(abspath $(IMAGE_REL))
ARCHIVE = $(WORK_DIR)/build/$(NAME)-$(ARCH).a
ARCHIVE = $(BUILD_DIR)/$(NAME)-$(ARCH).a
### Collect the files to be linked: object files (`.o`) and libraries (`.a`)
OBJS = $(addprefix $(DST_DIR)/, $(addsuffix .o, $(basename $(SRCS))))
LIBS := $(sort $(LIBS) am klib) # lazy evaluation ("=") causes infinite recursions
LINKAGE = $(OBJS) \
$(addsuffix -$(ARCH).a, $(join \
$(addsuffix /build/, $(addprefix $(AM_HOME)/, $(LIBS))), \
$(LIBS) ))
$(addsuffix -$(ARCH).a, $(addprefix $(BUILD_DIR)/, $(LIBS)))
## 3. General Compilation Flags
### (Cross) compilers, e.g., mips-linux-gnu-g++
AS = $(CROSS_COMPILE)gcc
CC = $(CROSS_COMPILE)gcc
CXX = $(CROSS_COMPILE)g++
LD = $(CROSS_COMPILE)ld
AR = $(CROSS_COMPILE)ar
OBJDUMP = $(CROSS_COMPILE)objdump
OBJCOPY = $(CROSS_COMPILE)objcopy
READELF = $(CROSS_COMPILE)readelf
AS ?= $(CROSS_COMPILE)gcc
CC ?= $(CROSS_COMPILE)gcc
CXX ?= $(CROSS_COMPILE)g++
LD ?= $(CROSS_COMPILE)ld
AR ?= $(CROSS_COMPILE)ar
OBJDUMP ?= $(CROSS_COMPILE)objdump
OBJCOPY ?= $(CROSS_COMPILE)objcopy
READELF ?= $(CROSS_COMPILE)readelf
### Compilation flags
INC_PATH += $(WORK_DIR)/include $(addsuffix /include/, $(addprefix $(AM_HOME)/, $(LIBS)))

View file

@ -0,0 +1,26 @@
add_subdirectory(src)
foreach(PLATFORM IN LISTS PLATFORMS)
if(ISA MATCHES "native")
set(ARCH "native")
else()
set(ARCH ${ISA}-${PLATFORM})
endif()
install(
TARGETS am-${ARCH}
EXPORT amTargets-${ARCH}
LIBRARY DESTINATION lib)
install(
EXPORT amTargets-${ARCH}
FILE amTargets.cmake
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/am-${ARCH})
configure_package_config_file(
${CMAKE_SOURCE_DIR}/cmake/am-config.cmake.in
${CMAKE_CURRENT_BINARY_DIR}/am-${ARCH}-config.cmake
INSTALL_DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/am-${ARCH})
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/am-${ARCH}-config.cmake
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/am-${ARCH})
endforeach()

View file

@ -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

View file

@ -0,0 +1 @@
add_subdirectory(${ISA})

View file

@ -0,0 +1,25 @@
set(SOURCES
trap.S
cte.c
ioe.c
mpe.c
platform.c
trm.c
vme.c
ioe/audio.c
ioe/disk.c
ioe/gpu.c
ioe/input.c
ioe/timer.c)
add_library(am-native ${SOURCES})
# FIXME: get free(): invalid address when user program compiled without pie
set_target_properties(
am-native PROPERTIES POSITION_INDEPENDENT_CODE TRUE
INTERFACE_POSITION_INDEPENDENT_CODE TRUE)
find_package(SDL2 REQUIRED)
target_link_libraries(
am-native
PUBLIC SDL2::SDL2 dl m
PRIVATE klib_interface am_interface)

View file

@ -1,5 +1,5 @@
#include <stdatomic.h>
#include "platform.h"
#include <stdatomic.h>
int __am_mpe_init = 0;
extern bool __am_has_ioe;
@ -16,7 +16,8 @@ bool mpe_init(void (*entry)()) {
char ch;
assert(read(sync_pipe[0], &ch, 1) == 1);
assert(ch == '+');
close(sync_pipe[0]); close(sync_pipe[1]);
close(sync_pipe[0]);
close(sync_pipe[1]);
thiscpu->cpuid = i;
__am_init_timer_irq();
@ -31,7 +32,8 @@ bool mpe_init(void (*entry)()) {
for (int i = 1; i < cpu_count(); i++) {
assert(write(sync_pipe[1], "+", 1) == 1);
}
close(sync_pipe[0]); close(sync_pipe[1]);
close(sync_pipe[0]);
close(sync_pipe[1]);
entry();
panic("MP entry should not return\n");
@ -42,9 +44,7 @@ int cpu_count() {
return __am_ncpu;
}
int cpu_current() {
return thiscpu->cpuid;
}
int cpu_current() { return thiscpu->cpuid; }
int atomic_xchg(int *addr, int newval) {
return atomic_exchange((int *)addr, newval);

View file

@ -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
@ -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);
@ -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() {}

View file

@ -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);
}

View file

@ -1,11 +1,10 @@
#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) {

View file

@ -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() {

View 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()

View file

@ -0,0 +1,41 @@
include(nemu-settings)
include(riscv-settings)
add_library(am-riscv-nemu cte.c start.S trap.S vme.c ${NEMU_SOURCES})
target_compile_options(am-riscv-nemu PRIVATE ${NEMU_COMPILE_OPTIONS}
${RISCV_COMPILE_OPTIONS})
target_link_options(am-riscv-nemu INTERFACE ${NEMU_LINK_OPITIONS}
${RISCV_LINK_OPTIONS})
target_include_directories(am-riscv-nemu PRIVATE ${NEMU_INCLUDE_DIRECTORIES})
target_link_options(
am-riscv-nemu
INTERFACE
LINKER:--defsym=_pmem_start=0x80000000
LINKER:--defsym=_entry_offset=0x0
LINKER:--gc-sections
LINKER:-e
_start
-nostartfiles)
target_link_options(
am-riscv-nemu INTERFACE
$<BUILD_INTERFACE:-T${CMAKE_SOURCE_DIR}/scripts/linker.ld>
$<INSTALL_INTERFACE:-T${CMAKE_INSTALL_FULL_DATADIR}/linker.ld>)
target_link_libraries(
am-riscv-nemu
PUBLIC am_interface klib_interface
INTERFACE m)
target_compile_definitions(am-riscv-nemu PRIVATE ISA_H=<riscv/riscv.h>)
set_target_properties(
am-riscv-nemu PROPERTIES POSITION_INDEPENDENT_CODE OFF
INTERFACE_POSITION_INDEPENDENT_CODE OFF)
install(FILES ${CMAKE_SOURCE_DIR}/scripts/linker.ld
DESTINATION ${CMAKE_INSTALL_DATADIR})

View file

@ -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) {}

View file

@ -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

View 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})

View file

@ -7,13 +7,18 @@ 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_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_UART_CONFIG] = __am_uart_config,
[AM_TIMER_CONFIG] = __am_timer_config,
[AM_TIMER_RTC ] = __am_timer_rtc,
[AM_TIMER_RTC] = __am_timer_rtc,
[AM_TIMER_UPTIME] = __am_timer_uptime,
[AM_INPUT_CONFIG] = __am_input_config,
[AM_INPUT_KEYBRD] = __am_input_keybrd,
@ -23,10 +28,11 @@ 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); }

View 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)

View file

@ -0,0 +1,6 @@
#ifndef _AM_NPC_NPC_H_
#define _AM_NPC_NPC_H_
#define SERIAL_PORT 0x10000000
#define RTC_ADDR 0x10001000
#endif

View file

@ -1,10 +1,11 @@
#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) {

View file

@ -1,5 +1,7 @@
#include "npc.h"
#include <am.h>
#include <klib-macros.h>
#include <riscv/riscv.h>
extern char _heap_start;
int main(const char *args);
@ -10,15 +12,16 @@ extern char _pmem_start;
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() {

View file

@ -0,0 +1,10 @@
@PACKAGE_INIT@
include(CMakeFindDependencyMacro)
if(${ARCH} MATCHES "native")
find_dependency(SDL2 REQUIRED)
endif()
# Include the targets file
include("${CMAKE_CURRENT_LIST_DIR}/../interfaceTargets.cmake")
include("${CMAKE_CURRENT_LIST_DIR}/amTargets.cmake")

View file

@ -0,0 +1,6 @@
@PACKAGE_INIT@
include(CMakeFindDependencyMacro)
# Include the targets file
include("${CMAKE_CURRENT_LIST_DIR}/klibTargets.cmake")

View file

@ -0,0 +1,12 @@
set(NEMU_COMPILE_OPTIONS -fdata-sections -ffunction-sections)
set(NEMU_LINK_OPTIONS
-nostartfiles
-nolibc
--defsym=_pmem_start=0x80000000
--defsym=_entry_offset=0x0
--gc-sections
-e
_start)
set(NEMU_INCLUDE_DIRECTORIES ${CMAKE_SOURCE_DIR}/am/src/platform/nemu/include)
file(GLOB_RECURSE NEMU_SOURCES ${CMAKE_SOURCE_DIR}/am/src/platform/nemu/*.[cS])
set(INCLUDE_LINKER_SCRIPT ON)

View file

@ -0,0 +1,2 @@
set(RISCV_COMPILE_OPTIONS)
set(RISCV_LINK_OPTIONS)

View file

@ -0,0 +1,34 @@
{ stdenv
, lib
, cmake
, SDL2
, glibc
, isa ? "native"
, platform ? [ ]
}:
stdenv.mkDerivation {
pname = "abstract-machine";
version = "2024.06.01";
src = ./.;
cmakeFlags = [
(lib.cmakeFeature "ISA" isa)
] ++ map (p: (lib.cmakeBool "__PLATFORM_${lib.strings.toUpper p}__" true)) platform;
cmakeBuildType = "Debug";
dontStrip = true;
nativeBuildInputs = [
cmake
];
buildInputs = [
] ++ (if isa == "native" then [ SDL2 ] else [ ]);
propagatedBuildInputs = [
] ++ (if isa == "native" then [ SDL2 ] else [ ]);
doCheck = true;
}

View file

@ -0,0 +1,4 @@
install(DIRECTORY include/
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/abstract-machine)
add_subdirectory(src)

View file

@ -35,6 +35,7 @@ int atoi (const char *nptr);
int printf (const char *format, ...);
int sprintf (char *str, const char *format, ...);
int snprintf (char *str, size_t size, const char *format, ...);
int vprintf (const char *format, va_list ap);
int vsprintf (char *str, const char *format, va_list ap);
int vsnprintf (char *str, size_t size, const char *format, va_list ap);

View file

@ -0,0 +1,29 @@
# find_package(FLEX) find_package(BISON)
# FLEX_TARGET(fmt_scanner fmt_scanner.l fmt_scanner.c)
set(SOURCES cpp.c int64.c stdio.c stdlib.c string.c
# ${FLEX_fmt_scanner_OUTPUTS}
)
add_library(klib ${SOURCES})
target_link_libraries(klib PUBLIC am_interface klib_interface)
target_compile_options(klib PUBLIC -fno-builtin)
install(
TARGETS klib
EXPORT klibTargets
LIBRARY DESTINATION lib)
install(
EXPORT klibTargets
FILE klibTargets.cmake
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/klib)
configure_package_config_file(
${CMAKE_SOURCE_DIR}/cmake/klib-config.cmake.in
${CMAKE_CURRENT_BINARY_DIR}/klib-config.cmake
INSTALL_DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/klib)
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/klib-config.cmake
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/klib)

View file

@ -1,20 +1,194 @@
#include <am.h>
#include <klib.h>
#include <klib-macros.h>
#include <klib.h>
#include <stdarg.h>
#if !defined(__ISA_NATIVE__) || defined(__NATIVE_USE_KLIB__)
int printf(const char *fmt, ...) {
panic("Not implemented");
void print_int(int num, int width, char pad) {
int reverse = 0;
int count = 0;
if (num == 0) {
reverse = 0;
count = 1;
} else {
if (num < 0) {
putch('-');
num = -num;
}
while (num != 0) {
reverse = reverse * 10 + (num % 10);
num /= 10;
count++;
}
}
while (width > count) {
putch(pad);
width--;
}
if (reverse == 0) {
putch('0');
} else {
while (reverse != 0) {
putch('0' + (reverse % 10));
reverse /= 10;
}
}
}
int vsprintf(char *out, const char *fmt, va_list ap) {
panic("Not implemented");
int vprintf(const char *format, va_list args) {
const char *p = format;
while (*p) {
if (*p == '%') {
p++; // Skip the '%'
char pad = ' ';
int width = 0;
if (*p == '0') {
pad = '0';
p++;
}
while (*p >= '0' && *p <= '9') {
width = width * 10 + (*p - '0');
p++;
}
switch (*p) {
case 'd': { // Integer
int ival = va_arg(args, int);
print_int(ival, width, pad);
break;
}
case 'c': { // Character
char c = (char)va_arg(args, int);
putch(c);
break;
}
case 's': { // String
char *s = va_arg(args, char *);
putstr(s);
break;
}
case '%': {
putch('%');
break;
}
default:
panic("Wrong formatter provided to printf");
}
} else {
putch(*p);
}
p++;
}
}
int printf(const char *fmt, ...) {
va_list args;
va_start(args, fmt);
vprintf(fmt, args);
va_end(args);
return 0;
}
void append_to_buffer(char **buf, int *pos, char c) { (*buf)[(*pos)++] = c; }
void print_int_to_buf(char **buf, int *pos, int num, int width, char pad) {
int reverse = 0, count = 0, neg = 0;
if (num == 0) {
reverse = 0;
count = 1;
} else {
if (num < 0) {
append_to_buffer(buf, pos, '-');
num = -num;
neg = 1;
}
while (num != 0) {
reverse = reverse * 10 + (num % 10);
num /= 10;
count++;
}
}
width -= neg;
while (width > count) {
append_to_buffer(buf, pos, pad);
width--;
}
for (int i = 0; i < count; i++) {
append_to_buffer(buf, pos, '0' + (reverse % 10));
reverse /= 10;
}
}
int vsprintf(char *buf, const char *format, va_list args) {
const char *p = format;
int pos = 0; // Position in buf
while (*p) {
if (*p == '%') {
p++; // Skip the '%'
char pad = ' ';
int width = 0;
if (*p == '0') {
pad = '0';
p++;
}
while (*p >= '0' && *p <= '9') {
width = width * 10 + (*p - '0');
p++;
}
switch (*p) {
case 'd': { // Integer
int ival = va_arg(args, int);
print_int_to_buf(&buf, &pos, ival, width, pad);
break;
}
case 'c': { // Character
char c = (char)va_arg(args, int);
append_to_buffer(&buf, &pos, c);
break;
}
case 's': { // String
char *s = va_arg(args, char *);
while (*s) {
append_to_buffer(&buf, &pos, *s++);
}
break;
}
case '%': {
append_to_buffer(&buf, &pos, '%');
break;
}
default:
panic("Unsupported format specifier");
}
} else {
append_to_buffer(&buf, &pos, *p);
}
p++;
}
buf[pos] = '\0'; // Null-terminate the string
return pos;
}
int sprintf(char *out, const char *fmt, ...) {
panic("Not implemented");
va_list args;
va_start(args, fmt);
vsprintf(out, fmt, args);
va_end(args);
return 0;
}
int snprintf(char *out, size_t n, const char *fmt, ...) {

View file

@ -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

View file

@ -1,47 +1,124 @@
#include <klib.h>
#include <klib-macros.h>
#include <klib.h>
#include <stdint.h>
#if !defined(__ISA_NATIVE__) || defined(__NATIVE_USE_KLIB__)
size_t strlen(const char *s) {
panic("Not implemented");
const char *p = s;
size_t len = 0;
while (*(p++) != '\0')
len++;
return len;
}
char *strcpy(char *dst, const char *src) {
panic("Not implemented");
char *p_dst = dst;
const char *p_src = src;
for (; *p_src != '\0'; p_src++, p_dst++) {
*p_dst = *p_src;
}
*p_dst = '\0';
return dst;
}
char *strncpy(char *dst, const char *src, size_t n) {
panic("Not implemented");
int i = 0;
for (; i < n && src[i] != '\0'; i++) {
dst[i] = src[i];
}
for (; i < n; i++) {
dst[i] = '\0';
}
return dst;
}
char *strcat(char *dst, const char *src) {
panic("Not implemented");
char *p_dst = dst;
const char *p_src = src;
while (*p_dst != '\0')
p_dst++;
for (; *p_src != '\0'; p_src++, p_dst++) {
*p_dst = *p_src;
}
*p_dst = '\0';
return dst;
}
int strcmp(const char *s1, const char *s2) {
panic("Not implemented");
const char *p_s1 = s1, *p_s2 = s2;
for (; *p_s1 == *p_s2; p_s1++, p_s2++) {
if (*p_s1 == '\0' || *p_s2 == '\0') {
break;
}
}
return *p_s1 - *p_s2;
}
int strncmp(const char *s1, const char *s2, size_t n) {
panic("Not implemented");
const char *p_s1 = s1, *p_s2 = s2;
int i = 0;
for (i = 0; i < n - 1; i++) {
if (s1[i] == '\0' || s2[i] == '\0')
break;
}
return s1[i] - s2[i];
}
void *memset(void *s, int c, size_t n) {
panic("Not implemented");
uint8_t *p = s;
for (int i = 0; i < n; i++) {
p[i] = c;
}
return s;
}
void *memmove(void *dst, const void *src, size_t n) {
panic("Not implemented");
if (src + n > dst && src < dst) {
size_t len = dst - src;
void *p_dst = (void *)src + n;
const void *p_src = src + n - len;
while (p_dst >= dst) {
memcpy(p_dst, p_src, len);
p_src -= len;
p_dst -= len;
}
if (n % len)
memcpy(dst, src, n % len);
} else if (dst < src && dst + n > src) {
size_t len = src - dst;
void *p_dst = dst;
const void *p_src = src;
while (p_src < src + n) {
memcpy(p_dst, p_src, len);
p_src += len;
p_dst += len;
}
if (n % len)
memcpy(p_dst, p_src, n % len);
} else {
memcpy(dst, src, n);
}
return dst;
}
void *memcpy(void *out, const void *in, size_t n) {
panic("Not implemented");
for (size_t i = 0; i < n; i++) {
*(uint8_t *)(out + i) = *(uint8_t *)(in + i);
}
return out;
}
int memcmp(const void *s1, const void *s2, size_t n) {
panic("Not implemented");
const uint8_t *p1 = s1, *p2 = s2;
for (int i = 0; i < n; i++) {
if (*p1 != *p2)
return p1 - p2;
p1++;
p2++;
}
return 0;
}
#endif

View file

@ -0,0 +1,11 @@
set(TEST_SOURCES stdio string)
foreach(TEST IN LISTS TEST_SOURCES)
# TODO: Run tests in other configurations
if(__PLATFORM_NATIVE__)
add_executable(${TEST} ${TEST}.c)
target_link_libraries(${TEST} PRIVATE am_interface klib_interface klib)
target_link_libraries(${TEST} PRIVATE am-native)
add_test(NAME ${TEST} COMMAND ${TEST})
endif()
endforeach()

View file

@ -0,0 +1,5 @@
#include <klib.h>
int main(void) {
return 0;
}

View file

@ -0,0 +1,75 @@
#include <klib.h>
#include <klib-macros.h>
#include <stdint.h>
void test_strcpy() {
char b[32];
char *s;
b[16]='a'; b[17]='b'; b[18]='c'; b[19]=0;
panic_on((s = strcpy(b, b+16)) != b, "strcpy wrong return value");
panic_on(strcmp(s, "abc") != 0, "strcpy gave incorrect string");
panic_on((s = strcpy(b+1, b+16)) != b+1, "strcpy wrong return value");
panic_on(strcmp(s, "abc") != 0, "strcpy gave incorrect string");
panic_on((s = strcpy(b+1, b+17)) != b+1, "strcpy wrong return value");
panic_on(strcmp(s, "bc") != 0, "strcpy gave incorrect string");
}
void test_strncpy() {
char b[32];
char *s;
int i;
b[3] = 'x'; b[4] = 0;
panic_on((s = strncpy(b, "abc", 3)) != b, "strncpy wrong return value");
panic_on(b[2] != 'c', "strncpy fails to copy last byte");
panic_on(b[3] != 'x', "strncpy overruns buffer to null-terminate");
}
void test_strncmp() {
panic_on(strncmp("abcd", "abce", 3) != 0, "strncmp compares past n");
panic_on(strncmp("abc", "abd", 3) == 0, "strncmp fails to compare n-1st byte");
}
void test_memset() {
uint8_t arr[128];
arr[120] = 0xd;
panic_on(memset(arr, 0xf, 120) != arr, "memset wrong return value");
panic_on(arr[7] != 0xf, "memset fails to set value in range");
panic_on(arr[120] != 0xd, "memset set value past n");
}
void test_memcpy() {
const uint8_t src[] = { 0x0, 0x0, 0x1, 0x2, 0x3, 0x4, 0x0, 0x0 };
uint8_t dst[8] = {0};
memcpy(dst, src, 8);
panic_on(memcmp(dst, src, 8) != 0, "memcpy fails to copy memory");
}
void test_memmove() {
const uint8_t ref[] = { 0x0, 0x0, 0x1, 0x2, 0x3, 0x4, 0x0, 0x0 };
uint8_t dst[8] = {0};
const uint8_t ans1[] = { 0x1, 0x2, 0x3, 0x4, 0x3, 0x4, 0x0, 0x0 };
const uint8_t ans2[] = { 0x1, 0x2, 0x2, 0x3, 0x4, 0x3, 0x0, 0x0 };
const uint8_t ans3[] = { 0x1, 0x2, 0x2, 0x1, 0x2, 0x2, 0x3, 0x4 };
memmove(dst, ref, 8);
panic_on(memcmp(dst, ref, 8) != 0, "memmove fails to copy non-overlapping memory");
memmove(dst, dst + 2, 4);
panic_on(memcmp(dst, ans1, 8) != 0, "memmove fails to copy overlapping memory (dst < src)");
memmove(dst + 2, dst + 1, 4);
panic_on(memcmp(dst, ans2, 8) != 0, "memmove fails to copy overlapping memory (src < dst)");
memmove(dst + 3, dst, 5);
panic_on(memcmp(dst, ans3, 8) != 0, "memmove fails to copy overlapping memory (src < dst)");
}
int main(void) {
test_strcpy();
test_strncpy();
test_strncmp();
test_memset();
test_memcpy();
test_memmove();
return 0;
}

808
flake.lock Normal file
View file

@ -0,0 +1,808 @@
{
"nodes": {
"am-kernels": {
"inputs": {
"flake-utils": "flake-utils",
"nixpkgs": "nixpkgs",
"pre-commit-hooks": "pre-commit-hooks",
"ysyx-workbench": "ysyx-workbench"
},
"locked": {
"lastModified": 1723617032,
"narHash": "sha256-oL5Vx933Jhn+T9jn67wFbh8vy7w8OJNCn4DOOlX/r0U=",
"ref": "dev",
"rev": "3ee527c3de481e38767fffbd9e16bf48359fc638",
"revCount": 78,
"type": "git",
"url": "https://git.xinyang.life/xin/am-kernels.git"
},
"original": {
"ref": "dev",
"type": "git",
"url": "https://git.xinyang.life/xin/am-kernels.git"
}
},
"diffu": {
"inputs": {
"flake-utils": "flake-utils_5",
"nixpkgs": "nixpkgs_2",
"nur-xin": "nur-xin_2",
"pre-commit-hooks": "pre-commit-hooks_3"
},
"locked": {
"lastModified": 1723627842,
"narHash": "sha256-+Ovf1e5ESap4sGMsH945SkZLhyYUxGE7shKVl3Ue1CQ=",
"ref": "refs/heads/master",
"rev": "7b3881a9712bcb7bfea90614a44888ae5df6e849",
"revCount": 17,
"type": "git",
"url": "https://git.xinyang.life/xin/diffu.git"
},
"original": {
"type": "git",
"url": "https://git.xinyang.life/xin/diffu.git"
}
},
"flake-compat": {
"flake": false,
"locked": {
"lastModified": 1696426674,
"narHash": "sha256-kvjfFW7WAETZlt09AgDn1MrtKzP7t90Vf7vypd3OL1U=",
"owner": "edolstra",
"repo": "flake-compat",
"rev": "0f9255e01c2351cc7d116c072cb317785dd33b33",
"type": "github"
},
"original": {
"owner": "edolstra",
"repo": "flake-compat",
"type": "github"
}
},
"flake-compat_2": {
"flake": false,
"locked": {
"lastModified": 1696426674,
"narHash": "sha256-kvjfFW7WAETZlt09AgDn1MrtKzP7t90Vf7vypd3OL1U=",
"owner": "edolstra",
"repo": "flake-compat",
"rev": "0f9255e01c2351cc7d116c072cb317785dd33b33",
"type": "github"
},
"original": {
"owner": "edolstra",
"repo": "flake-compat",
"type": "github"
}
},
"flake-compat_3": {
"flake": false,
"locked": {
"lastModified": 1696426674,
"narHash": "sha256-kvjfFW7WAETZlt09AgDn1MrtKzP7t90Vf7vypd3OL1U=",
"owner": "edolstra",
"repo": "flake-compat",
"rev": "0f9255e01c2351cc7d116c072cb317785dd33b33",
"type": "github"
},
"original": {
"owner": "edolstra",
"repo": "flake-compat",
"type": "github"
}
},
"flake-compat_4": {
"flake": false,
"locked": {
"lastModified": 1696426674,
"narHash": "sha256-kvjfFW7WAETZlt09AgDn1MrtKzP7t90Vf7vypd3OL1U=",
"owner": "edolstra",
"repo": "flake-compat",
"rev": "0f9255e01c2351cc7d116c072cb317785dd33b33",
"type": "github"
},
"original": {
"owner": "edolstra",
"repo": "flake-compat",
"type": "github"
}
},
"flake-utils": {
"inputs": {
"systems": "systems"
},
"locked": {
"lastModified": 1709126324,
"narHash": "sha256-q6EQdSeUZOG26WelxqkmR7kArjgWCdw5sfJVHPH/7j8=",
"owner": "numtide",
"repo": "flake-utils",
"rev": "d465f4819400de7c8d874d50b982301f28a84605",
"type": "github"
},
"original": {
"owner": "numtide",
"repo": "flake-utils",
"type": "github"
}
},
"flake-utils_2": {
"inputs": {
"systems": "systems_2"
},
"locked": {
"lastModified": 1710146030,
"narHash": "sha256-SZ5L6eA7HJ/nmkzGG7/ISclqe6oZdOZTNoesiInkXPQ=",
"owner": "numtide",
"repo": "flake-utils",
"rev": "b1d9ab70662946ef0850d488da1c9019f3a9752a",
"type": "github"
},
"original": {
"owner": "numtide",
"repo": "flake-utils",
"type": "github"
}
},
"flake-utils_3": {
"inputs": {
"systems": "systems_3"
},
"locked": {
"lastModified": 1709126324,
"narHash": "sha256-q6EQdSeUZOG26WelxqkmR7kArjgWCdw5sfJVHPH/7j8=",
"owner": "numtide",
"repo": "flake-utils",
"rev": "d465f4819400de7c8d874d50b982301f28a84605",
"type": "github"
},
"original": {
"owner": "numtide",
"repo": "flake-utils",
"type": "github"
}
},
"flake-utils_4": {
"inputs": {
"systems": "systems_4"
},
"locked": {
"lastModified": 1710146030,
"narHash": "sha256-SZ5L6eA7HJ/nmkzGG7/ISclqe6oZdOZTNoesiInkXPQ=",
"owner": "numtide",
"repo": "flake-utils",
"rev": "b1d9ab70662946ef0850d488da1c9019f3a9752a",
"type": "github"
},
"original": {
"owner": "numtide",
"repo": "flake-utils",
"type": "github"
}
},
"flake-utils_5": {
"inputs": {
"systems": "systems_5"
},
"locked": {
"lastModified": 1710146030,
"narHash": "sha256-SZ5L6eA7HJ/nmkzGG7/ISclqe6oZdOZTNoesiInkXPQ=",
"owner": "numtide",
"repo": "flake-utils",
"rev": "b1d9ab70662946ef0850d488da1c9019f3a9752a",
"type": "github"
},
"original": {
"owner": "numtide",
"repo": "flake-utils",
"type": "github"
}
},
"flake-utils_6": {
"inputs": {
"systems": "systems_6"
},
"locked": {
"lastModified": 1710146030,
"narHash": "sha256-SZ5L6eA7HJ/nmkzGG7/ISclqe6oZdOZTNoesiInkXPQ=",
"owner": "numtide",
"repo": "flake-utils",
"rev": "b1d9ab70662946ef0850d488da1c9019f3a9752a",
"type": "github"
},
"original": {
"owner": "numtide",
"repo": "flake-utils",
"type": "github"
}
},
"flake-utils_7": {
"inputs": {
"systems": "systems_7"
},
"locked": {
"lastModified": 1709126324,
"narHash": "sha256-q6EQdSeUZOG26WelxqkmR7kArjgWCdw5sfJVHPH/7j8=",
"owner": "numtide",
"repo": "flake-utils",
"rev": "d465f4819400de7c8d874d50b982301f28a84605",
"type": "github"
},
"original": {
"owner": "numtide",
"repo": "flake-utils",
"type": "github"
}
},
"flake-utils_8": {
"inputs": {
"systems": "systems_8"
},
"locked": {
"lastModified": 1710146030,
"narHash": "sha256-SZ5L6eA7HJ/nmkzGG7/ISclqe6oZdOZTNoesiInkXPQ=",
"owner": "numtide",
"repo": "flake-utils",
"rev": "b1d9ab70662946ef0850d488da1c9019f3a9752a",
"type": "github"
},
"original": {
"owner": "numtide",
"repo": "flake-utils",
"type": "github"
}
},
"gitignore": {
"inputs": {
"nixpkgs": [
"am-kernels",
"pre-commit-hooks",
"nixpkgs"
]
},
"locked": {
"lastModified": 1709087332,
"narHash": "sha256-HG2cCnktfHsKV0s4XW83gU3F57gaTljL9KNSuG6bnQs=",
"owner": "hercules-ci",
"repo": "gitignore.nix",
"rev": "637db329424fd7e46cf4185293b9cc8c88c95394",
"type": "github"
},
"original": {
"owner": "hercules-ci",
"repo": "gitignore.nix",
"type": "github"
}
},
"gitignore_2": {
"inputs": {
"nixpkgs": [
"am-kernels",
"ysyx-workbench",
"pre-commit-hooks",
"nixpkgs"
]
},
"locked": {
"lastModified": 1709087332,
"narHash": "sha256-HG2cCnktfHsKV0s4XW83gU3F57gaTljL9KNSuG6bnQs=",
"owner": "hercules-ci",
"repo": "gitignore.nix",
"rev": "637db329424fd7e46cf4185293b9cc8c88c95394",
"type": "github"
},
"original": {
"owner": "hercules-ci",
"repo": "gitignore.nix",
"type": "github"
}
},
"gitignore_3": {
"inputs": {
"nixpkgs": [
"diffu",
"pre-commit-hooks",
"nixpkgs"
]
},
"locked": {
"lastModified": 1709087332,
"narHash": "sha256-HG2cCnktfHsKV0s4XW83gU3F57gaTljL9KNSuG6bnQs=",
"owner": "hercules-ci",
"repo": "gitignore.nix",
"rev": "637db329424fd7e46cf4185293b9cc8c88c95394",
"type": "github"
},
"original": {
"owner": "hercules-ci",
"repo": "gitignore.nix",
"type": "github"
}
},
"gitignore_4": {
"inputs": {
"nixpkgs": [
"pre-commit-hooks",
"nixpkgs"
]
},
"locked": {
"lastModified": 1709087332,
"narHash": "sha256-HG2cCnktfHsKV0s4XW83gU3F57gaTljL9KNSuG6bnQs=",
"owner": "hercules-ci",
"repo": "gitignore.nix",
"rev": "637db329424fd7e46cf4185293b9cc8c88c95394",
"type": "github"
},
"original": {
"owner": "hercules-ci",
"repo": "gitignore.nix",
"type": "github"
}
},
"nixpkgs": {
"locked": {
"lastModified": 1709237383,
"narHash": "sha256-cy6ArO4k5qTx+l5o+0mL9f5fa86tYUX3ozE1S+Txlds=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "1536926ef5621b09bba54035ae2bb6d806d72ac8",
"type": "github"
},
"original": {
"owner": "NixOS",
"ref": "nixos-unstable",
"repo": "nixpkgs",
"type": "github"
}
},
"nixpkgs-circt162": {
"locked": {
"lastModified": 1705645507,
"narHash": "sha256-tX3vipIAmNDBA8WNWG4oY4KyTfnm2YieTHO2BhG8ISA=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "7995cae3ad60e3d6931283d650d7f43d31aaa5c7",
"type": "github"
},
"original": {
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "7995cae3ad60e3d6931283d650d7f43d31aaa5c7",
"type": "github"
}
},
"nixpkgs-circt162_2": {
"locked": {
"lastModified": 1705645507,
"narHash": "sha256-tX3vipIAmNDBA8WNWG4oY4KyTfnm2YieTHO2BhG8ISA=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "7995cae3ad60e3d6931283d650d7f43d31aaa5c7",
"type": "github"
},
"original": {
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "7995cae3ad60e3d6931283d650d7f43d31aaa5c7",
"type": "github"
}
},
"nixpkgs-stable": {
"locked": {
"lastModified": 1710695816,
"narHash": "sha256-3Eh7fhEID17pv9ZxrPwCLfqXnYP006RKzSs0JptsN84=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "614b4613980a522ba49f0d194531beddbb7220d3",
"type": "github"
},
"original": {
"owner": "NixOS",
"ref": "nixos-23.11",
"repo": "nixpkgs",
"type": "github"
}
},
"nixpkgs-stable_2": {
"locked": {
"lastModified": 1710695816,
"narHash": "sha256-3Eh7fhEID17pv9ZxrPwCLfqXnYP006RKzSs0JptsN84=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "614b4613980a522ba49f0d194531beddbb7220d3",
"type": "github"
},
"original": {
"owner": "NixOS",
"ref": "nixos-23.11",
"repo": "nixpkgs",
"type": "github"
}
},
"nixpkgs-stable_3": {
"locked": {
"lastModified": 1710695816,
"narHash": "sha256-3Eh7fhEID17pv9ZxrPwCLfqXnYP006RKzSs0JptsN84=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "614b4613980a522ba49f0d194531beddbb7220d3",
"type": "github"
},
"original": {
"owner": "NixOS",
"ref": "nixos-23.11",
"repo": "nixpkgs",
"type": "github"
}
},
"nixpkgs-stable_4": {
"locked": {
"lastModified": 1710695816,
"narHash": "sha256-3Eh7fhEID17pv9ZxrPwCLfqXnYP006RKzSs0JptsN84=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "614b4613980a522ba49f0d194531beddbb7220d3",
"type": "github"
},
"original": {
"owner": "NixOS",
"ref": "nixos-23.11",
"repo": "nixpkgs",
"type": "github"
}
},
"nixpkgs_2": {
"locked": {
"lastModified": 1711703276,
"narHash": "sha256-iMUFArF0WCatKK6RzfUJknjem0H9m4KgorO/p3Dopkk=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "d8fe5e6c92d0d190646fb9f1056741a229980089",
"type": "github"
},
"original": {
"owner": "NixOS",
"ref": "nixos-unstable",
"repo": "nixpkgs",
"type": "github"
}
},
"nixpkgs_3": {
"locked": {
"lastModified": 1709237383,
"narHash": "sha256-cy6ArO4k5qTx+l5o+0mL9f5fa86tYUX3ozE1S+Txlds=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "1536926ef5621b09bba54035ae2bb6d806d72ac8",
"type": "github"
},
"original": {
"owner": "NixOS",
"ref": "nixos-unstable",
"repo": "nixpkgs",
"type": "github"
}
},
"nur-xin": {
"inputs": {
"nixpkgs": [
"am-kernels",
"ysyx-workbench",
"nixpkgs"
]
},
"locked": {
"lastModified": 1721891452,
"narHash": "sha256-2c9nDuXXARzoRXE67lte5kKBeFb1XmTNsvdiIbRUEgE=",
"ref": "refs/heads/master",
"rev": "de8ad578fc4fe527772cec23a7f660bde14c8570",
"revCount": 152,
"type": "git",
"url": "https://git.xinyang.life/xin/nur.git"
},
"original": {
"type": "git",
"url": "https://git.xinyang.life/xin/nur.git"
}
},
"nur-xin_2": {
"inputs": {
"nixpkgs": [
"diffu",
"nixpkgs"
]
},
"locked": {
"lastModified": 1721891452,
"narHash": "sha256-2c9nDuXXARzoRXE67lte5kKBeFb1XmTNsvdiIbRUEgE=",
"ref": "refs/heads/master",
"rev": "de8ad578fc4fe527772cec23a7f660bde14c8570",
"revCount": 152,
"type": "git",
"url": "https://git.xinyang.life/xin/nur.git"
},
"original": {
"type": "git",
"url": "https://git.xinyang.life/xin/nur.git"
}
},
"nur-xin_3": {
"inputs": {
"nixpkgs": [
"nixpkgs"
]
},
"locked": {
"lastModified": 1721891452,
"narHash": "sha256-2c9nDuXXARzoRXE67lte5kKBeFb1XmTNsvdiIbRUEgE=",
"ref": "refs/heads/master",
"rev": "de8ad578fc4fe527772cec23a7f660bde14c8570",
"revCount": 152,
"type": "git",
"url": "https://git.xinyang.life/xin/nur.git"
},
"original": {
"type": "git",
"url": "https://git.xinyang.life/xin/nur.git"
}
},
"pre-commit-hooks": {
"inputs": {
"flake-compat": "flake-compat",
"flake-utils": "flake-utils_2",
"gitignore": "gitignore",
"nixpkgs": [
"am-kernels",
"nixpkgs"
],
"nixpkgs-stable": "nixpkgs-stable"
},
"locked": {
"lastModified": 1712055707,
"narHash": "sha256-4XLvuSIDZJGS17xEwSrNuJLL7UjDYKGJSbK1WWX2AK8=",
"owner": "cachix",
"repo": "pre-commit-hooks.nix",
"rev": "e35aed5fda3cc79f88ed7f1795021e559582093a",
"type": "github"
},
"original": {
"owner": "cachix",
"repo": "pre-commit-hooks.nix",
"type": "github"
}
},
"pre-commit-hooks_2": {
"inputs": {
"flake-compat": "flake-compat_2",
"flake-utils": "flake-utils_4",
"gitignore": "gitignore_2",
"nixpkgs": [
"am-kernels",
"ysyx-workbench",
"nixpkgs"
],
"nixpkgs-stable": "nixpkgs-stable_2"
},
"locked": {
"lastModified": 1712055707,
"narHash": "sha256-4XLvuSIDZJGS17xEwSrNuJLL7UjDYKGJSbK1WWX2AK8=",
"owner": "cachix",
"repo": "pre-commit-hooks.nix",
"rev": "e35aed5fda3cc79f88ed7f1795021e559582093a",
"type": "github"
},
"original": {
"owner": "cachix",
"repo": "pre-commit-hooks.nix",
"type": "github"
}
},
"pre-commit-hooks_3": {
"inputs": {
"flake-compat": "flake-compat_3",
"flake-utils": "flake-utils_6",
"gitignore": "gitignore_3",
"nixpkgs": [
"diffu",
"nixpkgs"
],
"nixpkgs-stable": "nixpkgs-stable_3"
},
"locked": {
"lastModified": 1712055707,
"narHash": "sha256-4XLvuSIDZJGS17xEwSrNuJLL7UjDYKGJSbK1WWX2AK8=",
"owner": "cachix",
"repo": "pre-commit-hooks.nix",
"rev": "e35aed5fda3cc79f88ed7f1795021e559582093a",
"type": "github"
},
"original": {
"owner": "cachix",
"repo": "pre-commit-hooks.nix",
"type": "github"
}
},
"pre-commit-hooks_4": {
"inputs": {
"flake-compat": "flake-compat_4",
"flake-utils": "flake-utils_8",
"gitignore": "gitignore_4",
"nixpkgs": [
"nixpkgs"
],
"nixpkgs-stable": "nixpkgs-stable_4"
},
"locked": {
"lastModified": 1712055707,
"narHash": "sha256-4XLvuSIDZJGS17xEwSrNuJLL7UjDYKGJSbK1WWX2AK8=",
"owner": "cachix",
"repo": "pre-commit-hooks.nix",
"rev": "e35aed5fda3cc79f88ed7f1795021e559582093a",
"type": "github"
},
"original": {
"owner": "cachix",
"repo": "pre-commit-hooks.nix",
"type": "github"
}
},
"root": {
"inputs": {
"am-kernels": "am-kernels",
"diffu": "diffu",
"flake-utils": "flake-utils_7",
"nixpkgs": "nixpkgs_3",
"nixpkgs-circt162": "nixpkgs-circt162_2",
"nur-xin": "nur-xin_3",
"pre-commit-hooks": "pre-commit-hooks_4"
}
},
"systems": {
"locked": {
"lastModified": 1681028828,
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
"owner": "nix-systems",
"repo": "default",
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
"type": "github"
},
"original": {
"owner": "nix-systems",
"repo": "default",
"type": "github"
}
},
"systems_2": {
"locked": {
"lastModified": 1681028828,
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
"owner": "nix-systems",
"repo": "default",
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
"type": "github"
},
"original": {
"owner": "nix-systems",
"repo": "default",
"type": "github"
}
},
"systems_3": {
"locked": {
"lastModified": 1681028828,
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
"owner": "nix-systems",
"repo": "default",
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
"type": "github"
},
"original": {
"owner": "nix-systems",
"repo": "default",
"type": "github"
}
},
"systems_4": {
"locked": {
"lastModified": 1681028828,
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
"owner": "nix-systems",
"repo": "default",
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
"type": "github"
},
"original": {
"owner": "nix-systems",
"repo": "default",
"type": "github"
}
},
"systems_5": {
"locked": {
"lastModified": 1681028828,
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
"owner": "nix-systems",
"repo": "default",
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
"type": "github"
},
"original": {
"owner": "nix-systems",
"repo": "default",
"type": "github"
}
},
"systems_6": {
"locked": {
"lastModified": 1681028828,
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
"owner": "nix-systems",
"repo": "default",
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
"type": "github"
},
"original": {
"owner": "nix-systems",
"repo": "default",
"type": "github"
}
},
"systems_7": {
"locked": {
"lastModified": 1681028828,
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
"owner": "nix-systems",
"repo": "default",
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
"type": "github"
},
"original": {
"owner": "nix-systems",
"repo": "default",
"type": "github"
}
},
"systems_8": {
"locked": {
"lastModified": 1681028828,
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
"owner": "nix-systems",
"repo": "default",
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
"type": "github"
},
"original": {
"owner": "nix-systems",
"repo": "default",
"type": "github"
}
},
"ysyx-workbench": {
"inputs": {
"flake-utils": "flake-utils_3",
"nixpkgs": [
"am-kernels",
"nixpkgs"
],
"nixpkgs-circt162": "nixpkgs-circt162",
"nur-xin": "nur-xin",
"pre-commit-hooks": "pre-commit-hooks_2"
},
"locked": {
"lastModified": 1723551098,
"narHash": "sha256-/AnVxufgQoAuvNBSKm0BG+tTS++/HuaNoW+loroSQig=",
"ref": "refs/heads/master",
"rev": "8ee1551dc2857091fca6456c1367aab7090899fe",
"revCount": 119,
"type": "git",
"url": "https://git.xinyang.life/xin/ysyx-workbench"
},
"original": {
"type": "git",
"url": "https://git.xinyang.life/xin/ysyx-workbench"
}
}
},
"root": "root",
"version": 7
}

148
flake.nix Normal file
View file

@ -0,0 +1,148 @@
{
inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
nixpkgs-circt162.url = "github:NixOS/nixpkgs/7995cae3ad60e3d6931283d650d7f43d31aaa5c7";
flake-utils.url = "github:numtide/flake-utils";
pre-commit-hooks = {
url = "github:cachix/pre-commit-hooks.nix";
inputs.nixpkgs.follows = "nixpkgs";
};
nur-xin = {
url = "git+https://git.xinyang.life/xin/nur.git";
inputs.nixpkgs.follows = "nixpkgs";
};
diffu.url = "git+https://git.xinyang.life/xin/diffu.git";
am-kernels.url = "git+https://git.xinyang.life/xin/am-kernels.git?ref=dev";
};
outputs = { self, flake-utils, nixpkgs, nixpkgs-circt162, pre-commit-hooks, nur-xin, diffu, am-kernels }@inputs:
flake-utils.lib.eachDefaultSystem (system:
let
pkgs = import nixpkgs {
inherit system;
config.allowUnfree = true;
overlays = [
(self: super: {
nvboard = nur-xin.legacyPackages.${system}.nvboard;
mini-gdbstub = nur-xin.legacyPackages.${system}.mini-gdbstub;
})
];
};
rv32CrossConfig = import nixpkgs {
localSystem = system;
crossSystem = {
config = "riscv32-none-elf";
gcc = {
abi = "ilp32";
arch = "rv32if";
};
};
};
in
{
checks = {
pre-commit-check = pre-commit-hooks.lib.${system}.run {
src = ./.;
hooks = {
trim-trailing-whitespace.enable = true;
end-of-file-fixer.enable = true;
cmake-format.enable = true;
clang-format = {
enable = true;
types_or = pkgs.lib.mkForce [ "c" "c++" ];
};
scalafmt = {
enable = true;
package = pkgs.scalafmt;
name = "Scalafmt";
types = [ "scala" ];
entry = "${pkgs.scalafmt}/bin/scalafmt --non-interactive";
};
};
};
};
packages = rec {
abstract-machine = pkgs.callPackage ./abstract-machine { isa = "native"; };
nemu = pkgs.callPackage ./nemu { };
nemu-lib = pkgs.callPackage ./nemu { };
rv32Cross = rec {
abstract-machine = rv32CrossConfig.callPackage ./abstract-machine { isa = "riscv"; platform = [ "nemu" "npc" ]; };
};
};
devShells.nemu = pkgs.mkShell {
packages = with pkgs; [
clang-tools
gef
SDL2
gnumake
pkg-config
flex
bison
dtc
readline
libllvm
mini-gdbstub
];
inputsFrom = [
self.packages.${system}.nemu
];
NEMU_HOME = "/home/xin/repo/ysyx-workbench/nemu";
# NEMU_IMAGES_PATH = self.packages.${system}.rv32Cross.am-kernels-nemu + "/share/am-kernels";
};
devShells.npc = pkgs.mkShell.override { stdenv = pkgs.ccacheStdenv; } {
inherit (self.checks.${system}.pre-commit-check) shellHook;
CHISEL_FIRTOOL_PATH = "${nixpkgs-circt162.legacyPackages.${system}.circt}/bin";
# NPC_IMAGES_PATH = "${self.packages.${system}.rv32Cross.am-kernels-npc}/share/am-kernels";
packages = with pkgs; [
clang-tools
cmake
coursier
espresso
bloop
gdb
jre
gtkwave
];
nativeBuildInputs = with pkgs; [
cmake
ninja
sbt
nvboard
nixpkgs-circt162.legacyPackages.${system}.circt
yosys
cli11
flex
bison
verilator
];
buildInputs = with pkgs; [
spdlog
nvboard
openssl
libllvm
libxml2
readline
mini-gdbstub
] ++ self.checks.${system}.pre-commit-check.enabledPackages;
};
devShells.difftest = pkgs.mkShell {
packages = [
diffu.packages.${system}.default
am-kernels.packages.${system}.rv32Cross.am-kernels-npc
self.packages.${system}.nemu-lib
];
};
}
);
}

41
git_commit.sh Executable file
View file

@ -0,0 +1,41 @@
#/usr/bin/env bash
STUID=ysyx_22040000
STUNAME=李心杨
TRACER=tracer-ysyx
GITFLAGS="-q --author=$TRACER<tracer@ysyx.org> --no-verify --allow-empty --no-gpg-sign"
WORK_BRANCH=$(git rev-parse --abbrev-ref HEAD)
WORK_INDEX=.git/index.${WORK_BRANCH}
TRACER_BRANCH=$TRACER
LOCK_DIR=.git/
git_soft_checkout () {
git checkout --detach -q && git reset --soft $1 -q -- && git checkout $1 -q -- ;
}
git_commit () {
# create tracer branch if not existent
git branch $TRACER_BRANCH -q 2>/dev/null || true
# backup git index
cp -a .git/index $WORK_INDEX
# switch to tracer branch
git_soft_checkout "$TRACER_BRANCH"
# add files to commit
git add . -A --ignore-errors
# generate commit msg, commit changes in tracer branch
printf "> $1 \n $STUID $STUNAME \n $(uname -a) \n $(uptime)\n" | git commit -F - $GITFLAGS
git_soft_checkout "$WORK_BRANCH"
mv $WORK_INDEX .git/index
}
git_commit $1
if [ $? -eq 0 ]; then
echo "[OK] Git commit track"
else
echo "[FAIL] Git commit track" && false
fi

75
nemu/.gitignore vendored
View file

@ -1,12 +1,67 @@
*.*
*
!*/
!Makefile
!*.mk
!*.[cSh]
!*.cc
!.gitignore
!README.md
!Kconfig
include/config
include/generated
configs/defconfig
build/
.cache/
.direnv/
.config
.config.old
.envrc
.metals/
.vscode/
.zed/
compile_commands.json
### C ###
# Prerequisites
*.d
# Object files
*.o
*.ko
*.obj
*.elf
# Linker output
*.ilk
*.map
*.exp
# Precompiled Headers
*.gch
*.pch
# Libraries
*.lib
*.a
*.la
*.lo
# Shared objects (inc. Windows DLLs)
*.dll
*.so
*.so.*
*.dylib
# Executables
*.exe
*.out
*.app
*.i*86
*.x86_64
*.hex
# Debug files
*.dSYM/
*.su
*.idb
*.pdb
# Kernel Module Compile Results
*.mod*
*.cmd
.tmp_versions/
modules.order
Module.symvers
Mkfile.old
dkms.conf

0
nemu/.result.tmp Normal file
View file

View file

@ -126,6 +126,26 @@ endmenu
menu "Testing and Debugging"
choice
prompt "Choose log level"
default LOG_TRACE
config LOG_TRACE
bool "trace"
config LOG_INFO
bool "info"
config LOG_WARNING
bool "warning"
config LOG_ERROR
bool "error"
endchoice
config LOG_LEVEL
int
default 1 if LOG_ERROR
default 2 if LOG_WARNING
default 3 if LOG_INFO
default 4 if LOG_TRACE
default 0
config TRACE
bool "Enable tracer"
@ -143,14 +163,54 @@ config TRACE_END
config ITRACE
depends on TRACE && TARGET_NATIVE_ELF && ENGINE_INTERPRETER
bool "Enable instruction tracer"
bool "Enable instruction tracing"
default y
help
Instraction tracing will log past instructions into a ring buffer
and print them when NEMU exit unexpectedly.
config ITRACE_COND
depends on ITRACE
string "Only trace instructions when the condition is true"
default "true"
config ITRACE_BUFFER
depends on ITRACE
int "Buffer size for intruction trace (unit: number of instructions)"
default 10
config MTRACE
depends on TRACE && LOG_TRACE
bool "Enable memory tracing"
default n
config MTRACE_RANGE
depends on MTRACE
string "Memory trace active range"
default "0x0-0xfffffff"
help
Memory tracer will only print memory access in these ranges.
Use comma to seperate between ranges.
config MTRACE_RANGE_MAX
depends on MTRACE
int "Max range count in MTRACE_RANGE"
default 10
config FTRACE
depends on TRACE && TARGET_NATIVE_ELF && ENGINE_INTERPRETER && LOG_TRACE
bool "Enable function tracing"
default n
config FTRACE_STACK_SIZE
depends on FTRACE
int "Max function track stack size"
default 256
config FTRACE_LOG
depends on FTRACE
bool "Print log when entering a funciton"
default n
config DIFFTEST
depends on TARGET_NATIVE_ELF

127
nemu/LICENSE Normal file
View file

@ -0,0 +1,127 @@
木兰宽松许可证, 第2版
木兰宽松许可证, 第2版
2020年1月 http://license.coscl.org.cn/MulanPSL2
您对“软件”的复制、使用、修改及分发受木兰宽松许可证第2版“本许可证”的如下条款的约束
0. 定义
“软件”是指由“贡献”构成的许可在“本许可证”下的程序和相关文档的集合。
“贡献”是指由任一“贡献者”许可在“本许可证”下的受版权法保护的作品。
“贡献者”是指将受版权法保护的作品许可在“本许可证”下的自然人或“法人实体”。
“法人实体”是指提交贡献的机构及其“关联实体”。
“关联实体”是指对“本许可证”下的行为方而言控制、受控制或与其共同受控制的机构此处的控制是指有受控方或共同受控方至少50%直接或间接的投票权、资金或其他有价证券。
1. 授予版权许可
每个“贡献者”根据“本许可证”授予您永久性的、全球性的、免费的、非独占的、不可撤销的版权许可,您可以复制、使用、修改、分发其“贡献”,不论修改与否。
2. 授予专利许可
每个“贡献者”根据“本许可证”授予您永久性的、全球性的、免费的、非独占的、不可撤销的(根据本条规定撤销除外)专利许可,供您制造、委托制造、使用、许诺销售、销售、进口其“贡献”或以其他方式转移其“贡献”。前述专利许可仅限于“贡献者”现在或将来拥有或控制的其“贡献”本身或其“贡献”与许可“贡献”时的“软件”结合而将必然会侵犯的专利权利要求,不包括对“贡献”的修改或包含“贡献”的其他结合。如果您或您的“关联实体”直接或间接地,就“软件”或其中的“贡献”对任何人发起专利侵权诉讼(包括反诉或交叉诉讼)或其他专利维权行动,指控其侵犯专利权,则“本许可证”授予您对“软件”的专利许可自您提起诉讼或发起维权行动之日终止。
3. 无商标许可
“本许可证”不提供对“贡献者”的商品名称、商标、服务标志或产品名称的商标许可但您为满足第4条规定的声明义务而必须使用除外。
4. 分发限制
您可以在任何媒介中将“软件”以源程序形式或可执行形式重新分发,不论修改与否,但您必须向接收者提供“本许可证”的副本,并保留“软件”中的版权、商标、专利及免责声明。
5. 免责声明与责任限制
“软件”及其中的“贡献”在提供时不带任何明示或默示的担保。在任何情况下,“贡献者”或版权所有者不对任何人因使用“软件”或其中的“贡献”而引发的任何直接或间接损失承担责任,不论因何种原因导致或者基于何种法律理论,即使其曾被建议有此种损失的可能性。
6. 语言
“本许可证”以中英文双语表述,中英文版本具有同等法律效力。如果中英文版本存在任何冲突不一致,以中文版为准。
条款结束
如何将木兰宽松许可证第2版应用到您的软件
如果您希望将木兰宽松许可证第2版应用到您的新软件为了方便接收者查阅建议您完成如下三步
1 请您补充如下声明中的空白,包括软件名、软件的首次发表年份以及您作为版权人的名字;
2 请您在软件包的一级目录下创建以“LICENSE”为名的文件将整个许可证文本放入该文件中
3 请将如下声明文本放入每个源文件的头部注释中。
Copyright (c) 2014-2022 Zihao Yu, Nanjing University
NEMU is licensed under Mulan PSL v2.
You can use this software according to the terms and conditions of the Mulan PSL v2.
You may obtain a copy of Mulan PSL v2 at:
http://license.coscl.org.cn/MulanPSL2
THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
See the Mulan PSL v2 for more details.
Mulan Permissive Software LicenseVersion 2
Mulan Permissive Software LicenseVersion 2 (Mulan PSL v2)
January 2020 http://license.coscl.org.cn/MulanPSL2
Your reproduction, use, modification and distribution of the Software shall be subject to Mulan PSL v2 (this License) with the following terms and conditions:
0. Definition
Software means the program and related documents which are licensed under this License and comprise all Contribution(s).
Contribution means the copyrightable work licensed by a particular Contributor under this License.
Contributor means the Individual or Legal Entity who licenses its copyrightable work under this License.
Legal Entity means the entity making a Contribution and all its Affiliates.
Affiliates means entities that control, are controlled by, or are under common control with the acting entity under this License, control means direct or indirect ownership of at least fifty percent (50%) of the voting power, capital or other securities of controlled or commonly controlled entity.
1. Grant of Copyright License
Subject to the terms and conditions of this License, each Contributor hereby grants to you a perpetual, worldwide, royalty-free, non-exclusive, irrevocable copyright license to reproduce, use, modify, or distribute its Contribution, with modification or not.
2. Grant of Patent License
Subject to the terms and conditions of this License, each Contributor hereby grants to you a perpetual, worldwide, royalty-free, non-exclusive, irrevocable (except for revocation under this Section) patent license to make, have made, use, offer for sale, sell, import or otherwise transfer its Contribution, where such patent license is only limited to the patent claims owned or controlled by such Contributor now or in future which will be necessarily infringed by its Contribution alone, or by combination of the Contribution with the Software to which the Contribution was contributed. The patent license shall not apply to any modification of the Contribution, and any other combination which includes the Contribution. If you or your Affiliates directly or indirectly institute patent litigation (including a cross claim or counterclaim in a litigation) or other patent enforcement activities against any individual or entity by alleging that the Software or any Contribution in it infringes patents, then any patent license granted to you under this License for the Software shall terminate as of the date such litigation or activity is filed or taken.
3. No Trademark License
No trademark license is granted to use the trade names, trademarks, service marks, or product names of Contributor, except as required to fulfill notice requirements in Section 4.
4. Distribution Restriction
You may distribute the Software in any medium with or without modification, whether in source or executable forms, provided that you provide recipients with a copy of this License and retain copyright, patent, trademark and disclaimer statements in the Software.
5. Disclaimer of Warranty and Limitation of Liability
THE SOFTWARE AND CONTRIBUTION IN IT ARE PROVIDED WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED. IN NO EVENT SHALL ANY CONTRIBUTOR OR COPYRIGHT HOLDER BE LIABLE TO YOU FOR ANY DAMAGES, INCLUDING, BUT NOT LIMITED TO ANY DIRECT, OR INDIRECT, SPECIAL OR CONSEQUENTIAL DAMAGES ARISING FROM YOUR USE OR INABILITY TO USE THE SOFTWARE OR THE CONTRIBUTION IN IT, NO MATTER HOW ITS CAUSED OR BASED ON WHICH LEGAL THEORY, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
6. Language
THIS LICENSE IS WRITTEN IN BOTH CHINESE AND ENGLISH, AND THE CHINESE VERSION AND ENGLISH VERSION SHALL HAVE THE SAME LEGAL EFFECT. IN THE CASE OF DIVERGENCE BETWEEN THE CHINESE AND ENGLISH VERSIONS, THE CHINESE VERSION SHALL PREVAIL.
END OF THE TERMS AND CONDITIONS
How to Apply the Mulan Permissive Software LicenseVersion 2 (Mulan PSL v2) to Your Software
To apply the Mulan PSL v2 to your work, for easy identification by recipients, you are suggested to complete following three steps:
i Fill in the blanks in following statement, including insert your software name, the year of the first publication of your software, and your name identified as the copyright owner;
ii Create a file named “LICENSE” which contains the whole context of this License in the first directory of your software package;
iii Attach the statement to the appropriate annotated syntax at the beginning of each source file.
Copyright (c) 2014-2022 Zihao Yu, Nanjing University
NEMU is licensed under Mulan PSL v2.
You can use this software according to the terms and conditions of the Mulan PSL v2.
You may obtain a copy of Mulan PSL v2 at:
http://license.coscl.org.cn/MulanPSL2
THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
See the Mulan PSL v2 for more details.

View file

@ -40,7 +40,9 @@ SRCS-y += $(shell find -L $(DIRS-y) -name "*.c")
SRCS = $(filter-out $(SRCS-BLACKLIST-y),$(SRCS-y))
# Extract compiler and options from menuconfig
ifneq ($(CONFIG_CC),)
CC = $(call remove_quote,$(CONFIG_CC))
endif
CFLAGS_BUILD += $(call remove_quote,$(CONFIG_CC_OPT))
CFLAGS_BUILD += $(if $(CONFIG_CC_LTO),-flto,)
CFLAGS_BUILD += $(if $(CONFIG_CC_DEBUG),-Og -ggdb3,)
@ -48,6 +50,7 @@ CFLAGS_BUILD += $(if $(CONFIG_CC_ASAN),-fsanitize=address,)
CFLAGS_TRACE += -DITRACE_COND=$(if $(CONFIG_ITRACE_COND),$(call remove_quote,$(CONFIG_ITRACE_COND)),true)
CFLAGS += $(CFLAGS_BUILD) $(CFLAGS_TRACE) -D__GUEST_ISA__=$(GUEST_ISA)
LDFLAGS += $(CFLAGS_BUILD)
INC_PATH += $(NEMU_HOME)/src/isa/$(GUEST_ISA)/local-include
# Include rules for menuconfig
include $(NEMU_HOME)/scripts/config.mk
@ -59,3 +62,36 @@ else
# Include rules to build NEMU
include $(NEMU_HOME)/scripts/native.mk
endif
include $(NEMU_HOME)/tests/Makefile
unit-tests: TEST_OBJS = $(filter-out $(OBJ_DIR)/src/nemu-main.o, $(OBJS))
unit-tests: CFLAGS += $(shell pkg-config --cflags check)
unit-tests: LDFLAGS += $(shell pkg-config --libs check)
unit-tests: $(TEST_SRCS:%.c=$(OBJ_DIR)/%)
IMAGES = $(patsubst %.bin, %, $(shell find $(IMAGES_PATH) -type f -name '*.bin'))
COLOR_RED = \033[1;31m
COLOR_GREEN = \033[1;32m
COLOR_BLUE = \033[1;34m
COLOR_NONE = \033[0m
RESULT = .result.tmp
$(shell > $(RESULT)) # Clear result file
$(IMAGES): %: %.bin $(BINARY)
@echo + TEST $(notdir $<)
@$(BINARY) -b $< >/dev/null 2>&1 || printf "\t%14s\n" $(notdir $<) >> $(RESULT)
integration-tests: $(IMAGES)
@printf "$(COLOR_BLUE)INTEGRATION TEST:$(COLOR_NONE)\n\tALL: %s\n\tFAILED: %s\n" $(words $(IMAGES)) $(shell wc -l $(RESULT) | cut -f1 -d' ')
@test ! -s $(RESULT) || printf "$(COLOR_RED)FAILED:$(COLOR_NONE)\n"
@cat $(RESULT)
@test ! -s $(RESULT); \
r=$$?; \
$(RM) $(RESULT); \
test $$r -eq 0
test: unit-tests integration-tests
.PHONY: test unit-tests integration-tests

87
nemu/configs/libdefconfig Normal file
View 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

View 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

View file

@ -0,0 +1,74 @@
#
# Automatically generated file; DO NOT EDIT.
# NEMU Configuration Menu
#
# CONFIG_ISA_x86 is not set
# CONFIG_ISA_mips32 is not set
CONFIG_ISA_riscv=y
# CONFIG_ISA_loongarch32r is not set
CONFIG_ISA="riscv32"
#
# ISA-dependent Options for riscv
#
# CONFIG_RV64 is not set
# CONFIG_RVE is not set
# end of ISA-dependent Options for riscv
CONFIG_ENGINE_INTERPRETER=y
CONFIG_ENGINE="interpreter"
CONFIG_MODE_SYSTEM=y
CONFIG_TARGET_NATIVE_ELF=y
# CONFIG_TARGET_SHARE is not set
# CONFIG_TARGET_AM is not set
#
# Build Options
#
CONFIG_CC_GCC=y
# CONFIG_CC_GPP is not set
# CONFIG_CC_CLANG is not set
CONFIG_CC="gcc"
# CONFIG_CC_O0 is not set
# CONFIG_CC_O1 is not set
CONFIG_CC_O2=y
# CONFIG_CC_O3 is not set
CONFIG_CC_OPT="-O2"
# CONFIG_CC_LTO is not set
# CONFIG_CC_DEBUG is not set
CONFIG_CC_ASAN=y
# end of Build Options
#
# Testing and Debugging
#
CONFIG_TRACE=y
CONFIG_TRACE_START=0
CONFIG_TRACE_END=10000
CONFIG_ITRACE=y
CONFIG_ITRACE_COND="true"
# CONFIG_DIFFTEST is not set
CONFIG_DIFFTEST_REF_PATH="none"
CONFIG_DIFFTEST_REF_NAME="none"
# end of Testing and Debugging
#
# Memory Configuration
#
CONFIG_MBASE=0x80000000
CONFIG_MSIZE=0x8000000
CONFIG_PC_RESET_OFFSET=0
# CONFIG_PMEM_MALLOC is not set
CONFIG_PMEM_GARRAY=y
CONFIG_MEM_RANDOM=y
# end of Memory Configuration
# CONFIG_DEVICE is not set
#
# Miscellaneous
#
CONFIG_TIMER_GETTIMEOFDAY=y
# CONFIG_TIMER_CLOCK_GETTIME is not set
CONFIG_RT_CHECK=y
# end of Miscellaneous

71
nemu/default.nix Normal file
View file

@ -0,0 +1,71 @@
{ stdenv
, lib
, gnumake
, pkg-config
, bison
, flex
, dtc
, check
, mini-gdbstub
, readline
, libllvm
, SDL2
, am-kernels ? ""
, defconfig ? "alldefconfig"
}:
stdenv.mkDerivation rec {
pname = "nemu";
version = "2024-08-15";
src = ./.;
nativeBuildInputs = [
gnumake
pkg-config
flex
bison
dtc
];
buildInputs = [
SDL2
readline
libllvm
mini-gdbstub
];
checkInputs = [
check
am-kernels
];
configurePhase = ''
export NEMU_HOME=$(pwd)
make ${defconfig}
'';
buildPhase = ''
make
'';
doCheck = (am-kernels != "");
checkPhase = ''
export NEMU_IMAGES_PATH=${am-kernels}/share/am-kernels
make test
'';
installPhase = ''
if [ -d "./lib" ] && [ "$(ls -A ./lib)" ]; then
mkdir -p "$out/lib"
fi
if [ -d "./bin" ] && [ "$(ls -A ./bin)" ]; then
mkdir -p $out/bin
fi
make PREFIX=$out install
'';
shellHook = ''
export NEMU_HOME=$(pwd)
'';
}

View file

@ -17,12 +17,12 @@
#define __COMMON_H__
#include <stdint.h>
#include <inttypes.h>
#include <stdbool.h>
#include <string.h>
#include <generated/autoconf.h>
#include <macro.h>
#include <types.h>
#ifdef CONFIG_TARGET_AM
#include <klib.h>
@ -31,19 +31,6 @@
#include <stdlib.h>
#endif
#if CONFIG_MBASE + CONFIG_MSIZE > 0x100000000ul
#define PMEM64 1
#endif
typedef MUXDEF(CONFIG_ISA64, uint64_t, uint32_t) word_t;
typedef MUXDEF(CONFIG_ISA64, int64_t, int32_t) sword_t;
#define FMT_WORD MUXDEF(CONFIG_ISA64, "0x%016" PRIx64, "0x%08" PRIx32)
typedef word_t vaddr_t;
typedef MUXDEF(PMEM64, uint64_t, uint32_t) paddr_t;
#define FMT_PADDR MUXDEF(PMEM64, "0x%016" PRIx64, "0x%08" PRIx32)
typedef uint16_t ioaddr_t;
#include <debug.h>
#endif

9
nemu/include/config.h Normal file
View 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__

View file

@ -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);

View file

@ -16,23 +16,33 @@
#ifndef __CPU_DECODE_H__
#define __CPU_DECODE_H__
#include "types.h"
#include <isa.h>
typedef enum { INST_NORMAL, INST_MEM_WRITE, INST_MEM_READ } inst_type_t;
typedef union {
paddr_t rmem;
paddr_t wmem;
} inst_type_op;
typedef struct Decode {
vaddr_t pc;
vaddr_t snpc; // static next pc
vaddr_t dnpc; // dynamic next pc
inst_type_t inst_type;
inst_type_op inst_value;
ISADecodeInfo isa;
IFDEF(CONFIG_ITRACE, char logbuf[128]);
} Decode;
// --- pattern matching mechanism ---
__attribute__((always_inline))
static inline void pattern_decode(const char *str, int len,
uint64_t *key, uint64_t *mask, uint64_t *shift) {
__attribute__((always_inline)) static inline void
pattern_decode(const char *str, int len, uint64_t *key, uint64_t *mask,
uint64_t *shift) {
uint64_t __key = 0, __mask = 0, __shift = 0;
#define macro(i) \
if ((i) >= len) goto finish; \
if ((i) >= len) \
goto finish; \
else { \
char c = str[i]; \
if (c != ' ') { \
@ -44,12 +54,24 @@ static inline void pattern_decode(const char *str, int len,
} \
}
#define macro2(i) macro(i); macro((i) + 1)
#define macro4(i) macro2(i); macro2((i) + 2)
#define macro8(i) macro4(i); macro4((i) + 4)
#define macro16(i) macro8(i); macro8((i) + 8)
#define macro32(i) macro16(i); macro16((i) + 16)
#define macro64(i) macro32(i); macro32((i) + 32)
#define macro2(i) \
macro(i); \
macro((i) + 1)
#define macro4(i) \
macro2(i); \
macro2((i) + 2)
#define macro8(i) \
macro4(i); \
macro4((i) + 4)
#define macro16(i) \
macro8(i); \
macro8((i) + 8)
#define macro32(i) \
macro16(i); \
macro16((i) + 16)
#define macro64(i) \
macro32(i); \
macro32((i) + 32)
macro64(0);
panic("pattern too long");
#undef macro
@ -59,18 +81,21 @@ finish:
*shift = __shift;
}
__attribute__((always_inline))
static inline void pattern_decode_hex(const char *str, int len,
uint64_t *key, uint64_t *mask, uint64_t *shift) {
__attribute__((always_inline)) static inline void
pattern_decode_hex(const char *str, int len, uint64_t *key, uint64_t *mask,
uint64_t *shift) {
uint64_t __key = 0, __mask = 0, __shift = 0;
#define macro(i) \
if ((i) >= len) goto finish; \
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); \
__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); \
} \
@ -85,18 +110,22 @@ finish:
*shift = __shift;
}
// --- pattern matching wrappers for decode ---
#define INSTPAT(pattern, ...) do { \
#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)
} 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

View file

@ -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

View file

@ -16,27 +16,59 @@
#ifndef __DEBUG_H__
#define __DEBUG_H__
#include <common.h>
#include <macro.h>
#include <stdio.h>
#include <utils.h>
IFDEF(CONFIG_ITRACE, void log_itrace_print());
#if (CONFIG_LOG_LEVEL >= 4)
#define Trace(format, ...) _Log("[TRACE] " format "\n", ##__VA_ARGS__)
#else
#define Trace(format, ...)
#endif
#if (CONFIG_LOG_LEVEL >= 3)
#define Log(format, ...) \
_Log(ANSI_FMT("[%s:%d %s] " format, ANSI_FG_BLUE) "\n", \
__FILE__, __LINE__, __func__, ## __VA_ARGS__)
_Log(ANSI_FMT("[INFO] %s:%d %s() ", ANSI_FG_BLUE) format "\n", __FILE__, \
__LINE__, __func__, ##__VA_ARGS__)
#else
#define Log(format, ...)
#endif
#if (CONFIG_LOG_LEVEL >= 2)
#define Warning(format, ...) \
_Log(ANSI_FMT("[WARNING] %s:%d %s() ", ANSI_FG_YELLOW) format "\n", \
__FILE__, __LINE__, __func__, ##__VA_ARGS__)
#else
#define Warning(format, ...)
#endif
#if (CONFIG_LOG_LEVEL >= 1)
#define Error(format, ...) \
_Log(ANSI_FMT("[ERROR] %s:%d %s() ", ANSI_FG_RED) format "\n", __FILE__, \
__LINE__, __func__, ##__VA_ARGS__)
#else
#define Error(format, ...)
#endif
#define Assert(cond, format, ...) \
do { \
if (!(cond)) { \
MUXDEF(CONFIG_TARGET_AM, printf(ANSI_FMT(format, ANSI_FG_RED) "\n", ## __VA_ARGS__), \
(fflush(stdout), fprintf(stderr, ANSI_FMT(format, ANSI_FG_RED) "\n", ## __VA_ARGS__))); \
IFNDEF(CONFIG_TARGET_AM, extern FILE* log_fp; fflush(log_fp)); \
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")

View file

@ -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);

View file

@ -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
View file

@ -0,0 +1,8 @@
#ifndef __NEMU_DIFFTEST_H__
#define __NEMU_DIFFTEST_H__
#include <stdbool.h>
extern bool nemu_do_difftest;
#endif // __NEMU_DIFFTEST_H__

18
nemu/include/ftrace.h Normal file
View file

@ -0,0 +1,18 @@
#ifndef __FUNC_DEF_H__
#define __FUNC_DEF_H__
#include <common.h>
#ifdef CONFIG_FTRACE
typedef struct {
vaddr_t start;
vaddr_t len;
char * name;
} func_t;
extern func_t *func_table;
void ftrace_call(vaddr_t, vaddr_t);
void ftrace_return(vaddr_t, vaddr_t);
// const char *get_func_name(vaddr_t addr);
#endif
#endif

View file

@ -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;

View file

@ -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,7 +39,8 @@
// 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,
@ -49,7 +50,7 @@
#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 MUXZERO(macro, X, Y) MUX_MACRO_PROPERTY(__P_ZERO_, macro, X, Y)
// test if a boolean macro is defined
#define ISDEF(macro) MUXDEF(macro, 1, 0)
@ -84,27 +85,46 @@
#define MAP(c, f) c(f)
#define BITMASK(bits) ((1ull << (bits)) - 1)
#define BITS(x, hi, lo) (((x) >> (lo)) & BITMASK((hi) - (lo) + 1)) // similar to x[hi:lo] in verilog
#define SEXT(x, len) ({ struct { int64_t n : len; } __x = { .n = x }; (uint64_t)__x.n; })
#define BITS(x, hi, lo) \
(((x) >> (lo)) & BITMASK((hi) - (lo) + 1)) // similar to x[hi:lo] in verilog
#define SEXT(x, len) \
({ \
struct { \
int64_t n : len; \
} __x = {.n = x}; \
(uint64_t) __x.n; \
})
#define ROUNDUP(a, sz) ((((uintptr_t)a) + (sz) - 1) & ~((sz) - 1))
#define ROUNDDOWN(a, sz) ((((uintptr_t)a)) & ~((sz) - 1))
#define ROUNDUP(a, sz) ((((uintptr_t)a) + (sz)-1) & ~((sz)-1))
#define ROUNDDOWN(a, sz) ((((uintptr_t)a)) & ~((sz)-1))
#define PG_ALIGN __attribute((aligned(4096)))
#define FAILED_GOTO(tag, exp) \
do { \
if ((exp)) \
goto tag; \
} while (0)
#if !defined(likely)
#define likely(cond) __builtin_expect(cond, 1)
#define unlikely(cond) __builtin_expect(cond, 0)
#endif
#define __EXPORT __attribute__((visibility("default")))
// for AM IOE
#define io_read(reg) \
({ reg##_T __io_param; \
({ \
reg##_T __io_param; \
ioe_read(reg, &__io_param); \
__io_param; })
__io_param; \
})
#define io_write(reg, ...) \
({ reg##_T __io_param = (reg##_T) { __VA_ARGS__ }; \
ioe_write(reg, &__io_param); })
({ \
reg##_T __io_param = (reg##_T){__VA_ARGS__}; \
ioe_write(reg, &__io_param); \
})
#endif

28
nemu/include/nemu.h Normal file
View file

@ -0,0 +1,28 @@
#ifndef __NEMU_HEADER__
#define __NEMU_HEADER__
#include <stddef.h>
#ifdef __cplusplus
extern "C" {
#endif
#include <gdbstub.h>
#ifdef __cplusplus
}
#endif
int nemu_read_mem(void *args, size_t addr, size_t len, void *val);
int nemu_write_mem(void *args, size_t addr, size_t len, void *val);
void nemu_cont(void *args, gdb_action_t *res);
void nemu_stepi(void *args, gdb_action_t *res);
bool nemu_set_bp(void *args, size_t addr, bp_type_t type);
bool nemu_del_bp(void *args, size_t addr, bp_type_t type);
void nemu_on_interrupt(void *args);
int nemu_read_reg(void *args, int regno, size_t *data);
int nemu_write_reg(void *args, int regno, size_t data);
void nemu_init(void *args);
extern arch_info_t nemu_isa_arch_info;
extern bool nemu_do_difftest;
extern bool nemu_dbg_state_size;
#endif // __NEMU_HEADER__

21
nemu/include/types.h Normal file
View file

@ -0,0 +1,21 @@
#ifndef __TYPES_H__
#define __TYPES_H__
#include <inttypes.h>
#include <macro.h>
#if CONFIG_MBASE + CONFIG_MSIZE > 0x100000000ul
#define PMEM64 1
#endif
typedef MUXDEF(CONFIG_ISA64, uint64_t, uint32_t) word_t;
typedef MUXDEF(CONFIG_ISA64, int64_t, int32_t) sword_t;
static const word_t WORD_T_MAX = MUXDEF(CONFIG_ISA64, UINT64_MAX, UINT32_MAX);
static const sword_t SWORD_T_MAX = MUXDEF(CONFIG_ISA64, INT64_MAX, INT32_MAX);
static const sword_t SWORD_T_MIN = MUXDEF(CONFIG_ISA64, INT64_MIN, INT32_MIN);
#define WORD_BYTES MUXDEF(CONFIG_ISA64, 8, 4)
#define FMT_WORD MUXDEF(CONFIG_ISA64, "0x%016" PRIx64, "0x%08" PRIx32)
typedef word_t vaddr_t;
typedef MUXDEF(PMEM64, uint64_t, uint32_t) paddr_t;
#define FMT_PADDR MUXDEF(PMEM64, "0x%016" PRIx64, "0x%08" PRIx32)
typedef uint16_t ioaddr_t;
#endif

View file

@ -16,11 +16,18 @@
#ifndef __UTILS_H__
#define __UTILS_H__
#include <common.h>
#include <types.h>
// ----------- state -----------
enum { NEMU_RUNNING, NEMU_STOP, NEMU_END, NEMU_ABORT, NEMU_QUIT };
enum {
NEMU_RUNNING,
NEMU_GDB_INTERRUPT,
NEMU_STOP,
NEMU_END,
NEMU_ABORT,
NEMU_QUIT
};
typedef struct {
int state;
@ -56,16 +63,16 @@ uint64_t get_time();
#define ANSI_FMT(str, fmt) fmt str ANSI_NONE
#define log_write(...) IFDEF(CONFIG_TARGET_NATIVE_ELF, \
do { \
extern FILE* log_fp; \
#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) \
)
} while (0))
#define _Log(...) \
do { \
@ -73,5 +80,4 @@ uint64_t get_time();
log_write(__VA_ARGS__); \
} while (0)
#endif

View file

@ -10,7 +10,7 @@ endif
WORK_DIR = $(shell pwd)
BUILD_DIR = $(WORK_DIR)/build
INC_PATH := $(WORK_DIR)/include $(INC_PATH)
INC_PATH := $(WORK_DIR)/include $(BUILD_DIR)/include $(INC_PATH)
OBJ_DIR = $(BUILD_DIR)/obj-$(NAME)$(SO)
BINARY = $(BUILD_DIR)/$(NAME)$(SO)
@ -22,7 +22,7 @@ CXX := g++
endif
LD := $(CXX)
INCLUDES = $(addprefix -I, $(INC_PATH))
CFLAGS := -O2 -MMD -Wall -Werror $(INCLUDES) $(CFLAGS)
CFLAGS := -O2 -MMD -Wall $(INCLUDES) $(CFLAGS)
LDFLAGS := -O2 $(LDFLAGS)
OBJS = $(SRCS:%.c=$(OBJ_DIR)/%.o) $(CXXSRC:%.cc=$(OBJ_DIR)/%.o)
@ -40,12 +40,34 @@ $(OBJ_DIR)/%.o: %.cc
@$(CXX) $(CFLAGS) $(CXXFLAGS) -c -o $@ $<
$(call call_fixdep, $(@:.o=.d), $@)
$(OBJ_DIR)/%.tag.c: %.y
@echo + YACC $<
@mkdir -p $(dir $@) $(BUILD_DIR)/include
@$(YACC) $(YFLAGS) --header=$(BUILD_DIR)/include/$(notdir $(<:.y=.h)) -o $@ $<
$(OBJ_DIR)/%.yy.c: %.l $(OBJ_DIR)/%.tag.c
@echo + LEX $<
@mkdir -p $(dir $@) $(BUILD_DIR)/include
@$(LEX) $(LFLAGS) --header=$(BUILD_DIR)/include/$(notdir $(<:.l=_lex.h)) -o $@ $<
$(OBJ_DIR)/%.tag.o: $(OBJ_DIR)/%.tag.c
@echo + CC $<
@mkdir -p $(dir $@)
@$(CC) $(CFLAGS) -c -o $@ $<
$(call call_fixdep, $(@:.o=.d), $@)
$(OBJ_DIR)/%.yy.o: $(OBJ_DIR)/%.yy.c
@echo + CC $<
@mkdir -p $(dir $@)
@$(CC) $(CFLAGS) -c -o $@ $<
$(call call_fixdep, $(@:.o=.d), $@)
# Depencies
-include $(OBJS:.o=.d)
# Some convenient rules
.PHONY: app clean
.PHONY: app install clean
app: $(BINARY)
@ -53,5 +75,14 @@ $(BINARY):: $(OBJS) $(ARCHIVES)
@echo + LD $@
@$(LD) -o $@ $(OBJS) $(LDFLAGS) $(ARCHIVES) $(LIBS)
install: $(BINARY)
ifeq ($(SHARE),1)
@mkdir -p $(PREFIX)/lib
@cp $(BINARY) $(PREFIX)/lib/
else
@mkdir -p $(PREFIX)/bin
@cp $(BINARY) $(PREFIX)/bin/
endif
clean:
-rm -rf $(BUILD_DIR)

View file

@ -48,6 +48,9 @@ menuconfig: $(MCONF) $(CONF) $(FIXDEP)
savedefconfig: $(CONF)
$(Q)$< $(silent) --$@=configs/defconfig $(Kconfig)
alldefconfig: $(CONF) $(FIXDEP)
$(Q)$(CONF) $(silent) --$@ $(Kconfig)
%defconfig: $(CONF) $(FIXDEP)
$(Q)$< $(silent) --defconfig=configs/$@ $(Kconfig)
$(Q)$< $(silent) --syncconfig $(Kconfig)
@ -60,7 +63,7 @@ help:
@echo ' savedefconfig - Save current config as configs/defconfig (minimal config)'
distclean: clean
-@rm -rf $(rm-distclean)
-rm -rf $(rm-distclean)
.PHONY: help distclean

View file

@ -13,10 +13,11 @@
* See the Mulan PSL v2 for more details.
***************************************************************************************/
#include "gdbstub.h"
#include <cpu/cpu.h>
#include <cpu/decode.h>
#include <cpu/difftest.h>
#include <locale.h>
#include <utils.h>
/* The assembly code of instructions executed is only output to the screen
* when the number of instructions executed is less than this value.
@ -29,14 +30,20 @@ CPU_state cpu = {};
uint64_t g_nr_guest_inst = 0;
static uint64_t g_timer = 0; // unit: us
static bool g_print_step = false;
IFDEF(CONFIG_ITRACE, extern char logbuf[CONFIG_ITRACE_BUFFER][128]);
IFDEF(CONFIG_ITRACE, extern int logbuf_rear);
void device_update();
static void trace_and_difftest(Decode *_this, vaddr_t dnpc) {
#ifdef CONFIG_ITRACE_COND
if (ITRACE_COND) { log_write("%s\n", _this->logbuf); }
if (ITRACE_COND) {
log_write("%s\n", logbuf[logbuf_rear]);
}
#endif
if (g_print_step) { IFDEF(CONFIG_ITRACE, puts(_this->logbuf)); }
if (g_print_step) {
IFDEF(CONFIG_ITRACE, puts(logbuf[logbuf_rear]));
}
IFDEF(CONFIG_DIFFTEST, difftest_step(_this->pc, dnpc));
}
@ -46,25 +53,28 @@ static void exec_once(Decode *s, vaddr_t pc) {
isa_exec_once(s);
cpu.pc = s->dnpc;
#ifdef CONFIG_ITRACE
char *p = s->logbuf;
p += snprintf(p, sizeof(s->logbuf), FMT_WORD ":", s->pc);
logbuf_rear = (logbuf_rear + 1) % CONFIG_ITRACE_BUFFER;
char *p = logbuf[logbuf_rear];
p += snprintf(p, sizeof(logbuf[logbuf_rear]), FMT_WORD ":", s->pc);
int ilen = s->snpc - s->pc;
int i;
uint8_t *inst = (uint8_t *)&s->isa.inst.val;
for (i = ilen - 1; i >= 0; i --) {
for (i = ilen - 1; i >= 0; i--) {
p += snprintf(p, 4, " %02x", inst[i]);
}
int ilen_max = MUXDEF(CONFIG_ISA_x86, 8, 4);
int space_len = ilen_max - ilen;
if (space_len < 0) space_len = 0;
if (space_len < 0)
space_len = 0;
space_len = space_len * 3 + 1;
memset(p, ' ', space_len);
p += space_len;
#ifndef CONFIG_ISA_loongarch32r
void disassemble(char *str, int size, uint64_t pc, uint8_t *code, int nbyte);
disassemble(p, s->logbuf + sizeof(s->logbuf) - p,
MUXDEF(CONFIG_ISA_x86, s->snpc, s->pc), (uint8_t *)&s->isa.inst.val, ilen);
disassemble(p, logbuf[logbuf_rear] + sizeof(logbuf[logbuf_rear]) - p,
MUXDEF(CONFIG_ISA_x86, s->snpc, s->pc),
(uint8_t *)&s->isa.inst.val, ilen);
#else
p[0] = '\0'; // the upstream llvm does not support loongarch32r
#endif
@ -73,11 +83,12 @@ static void exec_once(Decode *s, vaddr_t pc) {
static void execute(uint64_t n) {
Decode s;
for (;n > 0; n --) {
for (; n > 0; n--) {
exec_once(&s, cpu.pc);
g_nr_guest_inst ++;
g_nr_guest_inst++;
trace_and_difftest(&s, cpu.pc);
if (nemu_state.state != NEMU_RUNNING) break;
if (nemu_state.state != NEMU_RUNNING)
break;
IFDEF(CONFIG_DEVICE, device_update());
}
}
@ -87,8 +98,12 @@ static void statistic() {
#define NUMBERIC_FMT MUXDEF(CONFIG_TARGET_AM, "%", "%'") PRIu64
Log("host time spent = " NUMBERIC_FMT " us", g_timer);
Log("total guest instructions = " NUMBERIC_FMT, g_nr_guest_inst);
if (g_timer > 0) Log("simulation frequency = " NUMBERIC_FMT " inst/s", g_nr_guest_inst * 1000000 / g_timer);
else Log("Finish running in less than 1 us and can not calculate the simulation frequency");
if (g_timer > 0)
Log("simulation frequency = " NUMBERIC_FMT " inst/s",
g_nr_guest_inst * 1000000 / g_timer);
else
Log("Finish running in less than 1 us and can not calculate the simulation "
"frequency");
}
void assert_fail_msg() {
@ -100,10 +115,13 @@ void assert_fail_msg() {
void cpu_exec(uint64_t n) {
g_print_step = (n < MAX_INST_TO_PRINT);
switch (nemu_state.state) {
case NEMU_END: case NEMU_ABORT:
printf("Program execution has ended. To restart the program, exit NEMU and run again.\n");
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;
default:
nemu_state.state = NEMU_RUNNING;
}
uint64_t timer_start = get_time();
@ -114,15 +132,53 @@ void cpu_exec(uint64_t n) {
g_timer += timer_end - timer_start;
switch (nemu_state.state) {
case NEMU_RUNNING: nemu_state.state = NEMU_STOP; break;
case NEMU_RUNNING:
nemu_state.state = NEMU_STOP;
break;
case NEMU_END: case NEMU_ABORT:
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.state == NEMU_ABORT
? ANSI_FMT("ABORT", ANSI_FG_RED)
: (nemu_state.halt_ret == 0
? ANSI_FMT("HIT GOOD TRAP", ANSI_FG_GREEN)
: ANSI_FMT("HIT BAD TRAP", ANSI_FG_RED))),
nemu_state.halt_pc);
// fall through
case NEMU_QUIT: statistic();
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;
}

View file

@ -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

View file

@ -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();
}

View file

@ -1,5 +1,4 @@
menuconfig DEVICE
depends on !TARGET_SHARE
bool "Devices"
default n
help

View file

@ -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,
"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() {

View file

@ -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 */

View file

@ -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
@ -23,27 +26,26 @@
// 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)
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());
}

View file

@ -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));
}
@ -33,19 +35,21 @@ static void serial_io_handler(uint32_t offset, int len, bool is_write) {
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");
if (is_write)
serial_putc(serial_base[0]);
else
panic("do not support read");
break;
default: panic("do not support offset = %d", offset);
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
}

View file

@ -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

View file

@ -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);
@ -36,16 +35,22 @@ void invalid_inst(vaddr_t thispc) {
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]);
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);
"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);
"* Every line of untested code is always wrong!\n\n",
ANSI_FG_RED),
isa_logo);
set_nemu_state(NEMU_ABORT, thispc, -1);
}

View file

@ -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
}

View file

@ -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)\"

View file

@ -74,5 +74,4 @@ unsigned char isa_logo[] = {
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 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, 0x0a, '\0'};

View 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];
}
}

View file

@ -1,25 +0,0 @@
/***************************************************************************************
* Copyright (c) 2014-2022 Zihao Yu, Nanjing University
*
* NEMU is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
* http://license.coscl.org.cn/MulanPSL2
*
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
*
* See the Mulan PSL v2 for more details.
***************************************************************************************/
#include <isa.h>
#include <cpu/difftest.h>
#include "../local-include/reg.h"
bool isa_difftest_checkregs(CPU_state *ref_r, vaddr_t pc) {
return false;
}
void isa_difftest_attach() {
}

View file

@ -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);

View file

@ -1,68 +1,294 @@
/***************************************************************************************
* Copyright (c) 2014-2022 Zihao Yu, Nanjing University
*
* NEMU is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
* http://license.coscl.org.cn/MulanPSL2
*
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
*
* See the Mulan PSL v2 for more details.
***************************************************************************************/
* Copyright (c) 2014-2022 Zihao Yu, Nanjing University
*
* NEMU is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan
*PSL v2. You may obtain a copy of Mulan PSL v2 at:
* http://license.coscl.org.cn/MulanPSL2
*
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY
*KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
*NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
*
* See the Mulan PSL v2 for more details.
***************************************************************************************/
#include "isa.h"
#include "local-include/reg.h"
#include "macro.h"
#include "types.h"
#include <common.h>
#include <cpu/cpu.h>
#include <cpu/ifetch.h>
#include <cpu/decode.h>
#include <cpu/ifetch.h>
#include <csr.h>
#include <ftrace.h>
#include <utils.h>
#define R(i) gpr(i)
#define Mr vaddr_read
#define Mw vaddr_write
enum {
TYPE_I, TYPE_U, TYPE_S,
TYPE_R,
TYPE_I,
TYPE_I_SHIFT,
TYPE_U,
TYPE_S,
TYPE_B,
TYPE_J,
TYPE_CSR,
TYPE_CSRI,
TYPE_N, // none
};
#define src1R() do { *src1 = R(rs1); } while (0)
#define src2R() do { *src2 = R(rs2); } while (0)
#define immI() do { *imm = SEXT(BITS(i, 31, 20), 12); } while(0)
#define immU() do { *imm = SEXT(BITS(i, 31, 12), 20) << 12; } while(0)
#define immS() do { *imm = (SEXT(BITS(i, 31, 25), 7) << 5) | BITS(i, 11, 7); } while(0)
#define src1R() \
do { \
*src1 = R(rs1); \
} while (0)
#define src2R() \
do { \
*src2 = R(rs2); \
} while (0)
#define immI() \
do { \
*imm = SEXT(BITS(i, 31, 20), 12); \
} while (0)
#define immU() \
do { \
*imm = SEXT(BITS(i, 31, 12), 20) << 12; \
} while (0)
#define immS() \
do { \
*imm = SEXT(BITS(i, 31, 25), 7) << 5 | BITS(i, 11, 7); \
} while (0)
#define immB() \
do { \
*imm = SEXT(BITS(i, 31, 31), 1) << 12 | BITS(i, 30, 25) << 5 | \
BITS(i, 11, 8) << 1 | BITS(i, 7, 7) << 11; \
} while (0)
#define immJ() \
do { \
*imm = SEXT(BITS(i, 31, 31), 1) << 20 | BITS(i, 30, 21) << 1 | \
BITS(i, 20, 20) << 11 | BITS(i, 19, 12) << 12; \
} while (0)
#define csr() \
do { \
*src2 = BITS(i, 31, 20); \
} while (0)
#define uimm() \
do { \
*imm = BITS(i, 19, 15); \
} while (0)
static void decode_operand(Decode *s, int *rd, word_t *src1, word_t *src2, word_t *imm, int type) {
static void decode_operand(Decode *s, int *rd, word_t *src1, word_t *src2,
word_t *imm, int type) {
uint32_t i = s->isa.inst.val;
int rs1 = BITS(i, 19, 15);
int rs2 = BITS(i, 24, 20);
*rd = BITS(i, 11, 7);
switch (type) {
// clang-format off
case TYPE_R: src1R(); src2R(); break;
case TYPE_I: src1R(); immI(); break;
case TYPE_U: immU(); break;
case TYPE_J: immJ(); break;
case TYPE_S: src1R(); src2R(); immS(); break;
case TYPE_B: src1R(); src2R(); immB(); break;
case TYPE_CSR: src1R(); csr(); break;
case TYPE_CSRI: csr(); uimm(); break;
// clang-format on
}
}
static void do_branch(Decode *s, bool condition, word_t offset) {
if (condition) {
// puts(s->logbuf[s->logbuf_rear]);
s->dnpc = s->pc + offset;
}
}
static inline word_t Mr(Decode *s, vaddr_t addr, int len) {
s->inst_type = INST_MEM_READ;
s->inst_value.rmem = addr & ~0x3;
return vaddr_read(addr, len);
}
static inline void Mw(Decode *s, vaddr_t addr, int len, word_t data) {
vaddr_write(addr, len, data);
s->inst_type = INST_MEM_WRITE;
s->inst_value.wmem = addr & ~0x3;
}
#ifdef CONFIG_FTRACE
static void ftrace_jalr(Decode *s, int rd, vaddr_t dst) {
uint32_t i = s->isa.inst.val;
int rs1 = BITS(i, 19, 15);
if (rs1 == 1 && rd == 0) {
ftrace_return(s->pc, dst);
} else {
ftrace_call(s->pc, dst);
}
}
#endif
static int decode_exec(Decode *s) {
int rd = 0;
word_t src1 = 0, src2 = 0, imm = 0;
s->dnpc = s->snpc;
#define INSTPAT_INST(s) ((s)->isa.inst.val)
#define INSTPAT_MATCH(s, name, type, ... /* execute body */ ) { \
#define INSTPAT_MATCH(s, name, type, ... /* execute body */) \
{ \
decode_operand(s, &rd, &src1, &src2, &imm, concat(TYPE_, type)); \
__VA_ARGS__ ; \
}
__VA_ARGS__; \
}
INSTPAT_START();
INSTPAT("??????? ????? ????? ??? ????? 00101 11", auipc , U, R(rd) = s->pc + imm);
INSTPAT("??????? ????? ????? 100 ????? 00000 11", lbu , I, R(rd) = Mr(src1 + imm, 1));
INSTPAT("??????? ????? ????? 000 ????? 01000 11", sb , S, Mw(src1 + imm, 1, src2));
INSTPAT("??????? ????? ????? ??? ????? 01101 11", lui, U, R(rd) = imm);
INSTPAT("??????? ????? ????? ??? ????? 00101 11", auipc, U,
R(rd) = s->pc + imm);
INSTPAT("0000000 00001 00000 000 00000 11100 11", ebreak , N, NEMUTRAP(s->pc, R(10))); // R(10) is $a0
INSTPAT("??????? ????? ????? ??? ????? ????? ??", inv , N, INV(s->pc));
INSTPAT(
"??????? ????? ????? ??? ????? 11011 11", jal, J, do {
s->dnpc = s->pc + imm;
R(rd) = s->pc + 4;
IFDEF(CONFIG_FTRACE, ftrace_call(s->pc, s->pc + imm));
} while (0));
INSTPAT(
"??????? ????? ????? ??? ????? 11001 11", jalr, I, do {
s->dnpc = src1 + imm;
R(rd) = s->pc + 4;
IFDEF(CONFIG_FTRACE, ftrace_jalr(s, rd, src1 + imm));
} while (0));
INSTPAT("??????? ????? ????? 000 ????? 11000 11", beq, B,
do_branch(s, src1 == src2, imm));
INSTPAT("??????? ????? ????? 001 ????? 11000 11", bne, B,
do_branch(s, src1 != src2, imm));
INSTPAT("??????? ????? ????? 100 ????? 11000 11", blt, B,
do_branch(s, (sword_t)src1 < (sword_t)src2, imm));
INSTPAT("??????? ????? ????? 101 ????? 11000 11", bge, B,
do_branch(s, (sword_t)src1 >= (sword_t)src2, imm));
INSTPAT("??????? ????? ????? 110 ????? 11000 11", bltu, B,
do_branch(s, src1 < src2, imm));
INSTPAT("??????? ????? ????? 111 ????? 11000 11", bgeu, B,
do_branch(s, src1 >= src2, imm));
INSTPAT("??????? ????? ????? 000 ????? 00000 11", lb, I,
R(rd) = SEXT(Mr(s, src1 + imm, 1), 8));
INSTPAT("??????? ????? ????? 001 ????? 00000 11", lh, I,
R(rd) = SEXT(Mr(s, src1 + imm, 2), 16));
INSTPAT("??????? ????? ????? 010 ????? 00000 11", lw, I,
R(rd) = SEXT(Mr(s, src1 + imm, 4), 32));
INSTPAT("??????? ????? ????? 100 ????? 00000 11", lbu, I,
R(rd) = Mr(s, src1 + imm, 1));
INSTPAT("??????? ????? ????? 101 ????? 00000 11", lhu, I,
R(rd) = Mr(s, src1 + imm, 2));
INSTPAT("??????? ????? ????? 000 ????? 01000 11", sb, S,
Mw(s, src1 + imm, 1, src2));
INSTPAT("??????? ????? ????? 001 ????? 01000 11", sh, S,
Mw(s, src1 + imm, 2, src2));
INSTPAT("??????? ????? ????? 010 ????? 01000 11", sw, S,
Mw(s, src1 + imm, 4, src2));
INSTPAT("??????? ????? ????? 000 ????? 00100 11", addi, I,
R(rd) = src1 + imm);
INSTPAT("??????? ????? ????? 010 ????? 00100 11", slti, I,
R(rd) = (sword_t)src1 < (sword_t)imm ? 1 : 0);
INSTPAT("??????? ????? ????? 011 ????? 00100 11", sltiu, I,
R(rd) = src1 < imm ? 1 : 0);
INSTPAT("??????? ????? ????? 100 ????? 00100 11", xori, I,
R(rd) = src1 ^ imm);
INSTPAT("??????? ????? ????? 110 ????? 00100 11", ori, I, R(rd) = src1 | imm);
INSTPAT("??????? ????? ????? 111 ????? 00100 11", andi, I,
R(rd) = src1 & imm);
INSTPAT("0000000 ????? ????? 001 ????? 00100 11", slli, I,
R(rd) = src1 << imm);
INSTPAT("0000000 ????? ????? 101 ????? 00100 11", srli, I,
R(rd) = src1 >> imm);
INSTPAT("0100000 ????? ????? 101 ????? 00100 11", srai, I,
R(rd) = (sword_t)src1 >> (imm & 0x01F));
INSTPAT("0000000 ????? ????? 000 ????? 01100 11", add, R,
R(rd) = src1 + src2);
INSTPAT("0100000 ????? ????? 000 ????? 01100 11", sub, R,
R(rd) = src1 - src2);
INSTPAT("0000000 ????? ????? 001 ????? 01100 11", sll, R,
R(rd) = src1 << src2);
INSTPAT("0000000 ????? ????? 010 ????? 01100 11", slt, R,
R(rd) = (sword_t)src1 < (sword_t)src2 ? 1 : 0);
INSTPAT("0000000 ????? ????? 011 ????? 01100 11", sltu, R,
R(rd) = src1 < src2 ? 1 : 0);
INSTPAT("0000000 ????? ????? 100 ????? 01100 11", xor, R,
R(rd) = src1 ^ src2);
INSTPAT("0000000 ????? ????? 101 ????? 01100 11", srl, R,
R(rd) = src1 >> src2);
INSTPAT("0100000 ????? ????? 101 ????? 01100 11", sra, R,
R(rd) = (sword_t)src1 >> (src2 & 0x01F));
INSTPAT("0000000 ????? ????? 110 ????? 01100 11", or, R, R(rd) = src1 | src2);
INSTPAT("0000000 ????? ????? 111 ????? 01100 11", and, R,
R(rd) = src1 & src2);
INSTPAT("0000000 00001 00000 000 00000 11100 11", ebreak, N,
NEMUTRAP(s->pc, R(10))); // R(10) is $a0
// "M"
INSTPAT("0000001 ????? ????? 000 ????? 01100 11", mul, R,
R(rd) = src1 * src2);
INSTPAT("0000001 ????? ????? 001 ????? 01100 11", mulh, R,
R(rd) = (int64_t)(sword_t)src1 * (sword_t)src2 >> 32);
INSTPAT("0000001 ????? ????? 010 ????? 01100 11", mulhsu, R,
R(rd) = (int64_t)(sword_t)src1 * (uint64_t)src2 >> 32);
INSTPAT("0000001 ????? ????? 011 ????? 01100 11", mulhu, R,
R(rd) = (uint64_t)src1 * (uint64_t)src2 >> 32);
INSTPAT("0000001 ????? ????? 100 ????? 01100 11", div, R,
R(rd) = (sword_t)src1 / (sword_t)src2);
INSTPAT("0000001 ????? ????? 101 ????? 01100 11", divu, R,
R(rd) = src1 / src2);
INSTPAT("0000001 ????? ????? 110 ????? 01100 11", rem, R,
R(rd) = (sword_t)src1 % (sword_t)src2);
INSTPAT("0000001 ????? ????? 111 ????? 01100 11", remu, R,
R(rd) = src1 % src2);
// "Previledge"
// -- CSR instructions
// src2: R(read register)
// src1: R(write source)
// imm: write data()
INSTPAT(
"??????? ????? ????? 001 ????? 11100 11", csrrw, CSR, do {
R(rd) = read_csr(cpu.csr, src2);
write_csr(cpu.csr, src2, src1);
} while (0););
INSTPAT(
"??????? ????? ????? 010 ????? 11100 11", csrrs, CSR, do {
R(rd) = read_csr(cpu.csr, src2);
set_csr_bits(cpu.csr, src2, src1);
} while (0););
INSTPAT(
"??????? ????? ????? 011 ????? 11100 11", csrrc, CSR, do {
R(rd) = read_csr(cpu.csr, src2);
clear_csr_bits(cpu.csr, src2, src1);
} while (0););
INSTPAT(
"??????? ????? ????? 101 ????? 11100 11", csrrwi, CSRI, do {
R(rd) = read_csr(cpu.csr, src2);
write_csr(cpu.csr, src2, imm);
} while (0););
INSTPAT(
"??????? ????? ????? 110 ????? 11100 11", csrrsi, CSRI, do {
R(rd) = read_csr(cpu.csr, src2);
set_csr_bits(cpu.csr, src2, imm);
} while (0););
INSTPAT(
"??????? ????? ????? 111 ????? 11100 11", csrrci, CSRI, do {
R(rd) = read_csr(cpu.csr, src2);
clear_csr_bits(cpu.csr, src2, imm);
} while (0););
// -- Machine level
INSTPAT("0000000 00000 00000 000 00000 11100 11", ecall, N,
s->dnpc = isa_raise_intr(CauseEnvironmentCallFromMMode, cpu.pc));
INSTPAT("0011000 00010 00000 000 00000 11100 11", mret, N,
s->dnpc = read_csr(cpu.csr, MEPC));
INSTPAT("??????? ????? ????? ??? ????? ????? ??", inv, N, INV(s->pc));
INSTPAT_END();
R(0) = 0; // reset $zero to 0

View 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__

View file

@ -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! */
};

View file

@ -13,19 +13,70 @@
* See the Mulan PSL v2 for more details.
***************************************************************************************/
#include <isa.h>
#include "local-include/reg.h"
#include "csr.h"
#include "macro.h"
#include <errno.h>
#include <gdbstub.h>
#include <isa.h>
const char *regs[] = {
"$0", "ra", "sp", "gp", "tp", "t0", "t1", "t2",
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"
};
"s8", "s9", "s10", "s11", "t3", "t4", "t5", "t6"};
void isa_reg_display() {
int colomn_per_row = 4;
for (int i = 0; i < ARRLEN(regs); i++) {
printf("\e[1;34m%3s\e[0m: " FMT_PADDR, reg_name(i), gpr(i));
if (i % colomn_per_row == 3)
putchar('\n');
else
putchar('|');
}
}
word_t isa_reg_str2val(const char *s, bool *success) {
assert(s);
int i;
for (i = 0; i < 32 && strcmp(s, regs[i]) != 0; i++)
;
if (i == 32) {
*success = false;
return 0;
}
*success = true;
return gpr(i);
}
int isa_read_reg(void *args, int regno, size_t *reg_value) {
if (regno > 32) {
return EFAULT;
}
if (regno == 32) {
*reg_value = cpu.pc;
} else {
*reg_value = cpu.gpr[regno];
}
return 0;
}
int isa_write_reg(void *args, int regno, size_t data) {
if (regno > 32) {
return EFAULT;
}
if (regno == 32) {
cpu.pc = data;
} else {
cpu.gpr[regno] = data;
}
return 0;
}
__EXPORT arch_info_t isa_arch_info = {.reg_num = 32,
.reg_byte = MUXDEF(CONFIG_RV64, 8, 4),
.target_desc = TARGET_RV32};

View file

@ -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; }

View file

@ -13,18 +13,26 @@
* See the Mulan PSL v2 for more details.
***************************************************************************************/
#include <memory/host.h>
#include <memory/paddr.h>
#include "common.h"
#include "debug.h"
#include "utils.h"
#include <device/mmio.h>
#include <isa.h>
#include <memory/host.h>
#include <memory/paddr.h>
#if defined(CONFIG_PMEM_MALLOC)
static uint8_t *pmem = NULL;
#else // CONFIG_PMEM_GARRAY
static uint8_t pmem[CONFIG_MSIZE] PG_ALIGN = {};
#endif
#ifdef CONFIG_MTRACE
static word_t mtrace_start[CONFIG_MTRACE_RANGE_MAX] = {0};
static word_t mtrace_end[CONFIG_MTRACE_RANGE_MAX] = {0};
static int range_count = 0;
#endif
uint8_t* guest_to_host(paddr_t paddr) { return pmem + paddr - CONFIG_MBASE; }
uint8_t *guest_to_host(paddr_t paddr) { return pmem + paddr - CONFIG_MBASE; }
paddr_t host_to_guest(uint8_t *haddr) { return haddr - pmem + CONFIG_MBASE; }
static word_t pmem_read(paddr_t addr, int len) {
@ -37,28 +45,79 @@ static void pmem_write(paddr_t addr, int len, word_t data) {
}
static void out_of_bound(paddr_t addr) {
panic("address = " FMT_PADDR " is out of bound of pmem [" FMT_PADDR ", " FMT_PADDR "] at pc = " FMT_WORD,
#ifdef CONFIG_TARGET_SHARE
// Do not panic when used as a library. Give an error in log
Error("Out of bound at 0x%x", addr);
#else
panic("address = " FMT_PADDR " is out of bound of pmem [" FMT_PADDR
", " FMT_PADDR "] at pc = " FMT_WORD,
addr, PMEM_LEFT, PMEM_RIGHT, cpu.pc);
#endif
}
#ifdef CONFIG_MTRACE
static void mtrace_print(char type, word_t addr, int len, word_t data) {
for (int i = 0; i < range_count; i++)
if (addr <= mtrace_end[i] && addr >= mtrace_start[i]) {
Trace("PC=" FMT_PADDR " Mem %c" FMT_PADDR " %d D " FMT_PADDR, cpu.pc,
type, addr, len, data);
break;
}
}
#endif
void init_mem() {
#if defined(CONFIG_PMEM_MALLOC)
pmem = malloc(CONFIG_MSIZE);
assert(pmem);
#endif
#ifdef CONFIG_MTRACE
char range[sizeof(CONFIG_MTRACE_RANGE)] = CONFIG_MTRACE_RANGE;
char *saveptr, *ptr;
ptr = strtok_r(range, ",", &saveptr);
for (range_count = 0; range_count < CONFIG_MTRACE_RANGE_MAX;) {
word_t start, end;
Assert(sscanf(ptr, FMT_PADDR "-" FMT_PADDR, &start, &end) == 2,
"Config option MTRACE_RANGE has wrong format");
mtrace_start[range_count] = start;
mtrace_end[range_count] = end;
range_count++;
ptr = strtok_r(NULL, ",", &saveptr);
if (!ptr)
break;
}
Trace("MTRACE ranges: ");
for (int i = 0; i < range_count; i++) {
Trace("[0x%x, 0x%x]", mtrace_start[i], mtrace_end[i]);
}
#endif
IFDEF(CONFIG_MEM_RANDOM, memset(pmem, rand(), CONFIG_MSIZE));
Log("physical memory area [" FMT_PADDR ", " FMT_PADDR "]", PMEM_LEFT, PMEM_RIGHT);
Log("physical memory area [" FMT_PADDR ", " FMT_PADDR "]", PMEM_LEFT,
PMEM_RIGHT);
}
word_t paddr_read(paddr_t addr, int len) {
if (likely(in_pmem(addr))) return pmem_read(addr, len);
IFDEF(CONFIG_DEVICE, return mmio_read(addr, len));
word_t result = 0;
if (likely(in_pmem(addr))) {
result = pmem_read(addr, len);
goto mtrace;
}
IFDEF(CONFIG_DEVICE, result = mmio_read(addr, len); goto mtrace;)
out_of_bound(addr);
return 0;
mtrace:
IFDEF(CONFIG_MTRACE, mtrace_print('R', addr, len, result));
return result;
}
void paddr_write(paddr_t addr, int len, word_t data) {
if (likely(in_pmem(addr))) { pmem_write(addr, len, data); return; }
IFDEF(CONFIG_MTRACE, mtrace_print('W', addr, len, data));
if (likely(in_pmem(addr))) {
pmem_write(addr, len, data);
return;
}
IFDEF(CONFIG_DEVICE, mmio_write(addr, len, data); return);
out_of_bound(addr);
}

View file

@ -0,0 +1,4 @@
DIRS-y += src/monitor
CXXSRC += src/monitor/gdbstub.cc
LIBS += -lgdbstub

170
nemu/src/monitor/gdbstub.cc Normal file
View 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;
}
}

View file

@ -13,47 +13,90 @@
* See the Mulan PSL v2 for more details.
***************************************************************************************/
#include <cpu/cpu.h>
#include <errno.h>
#include <isa.h>
#include <memory/paddr.h>
#include <nemu.h>
#include <strings.h>
#include <utils.h>
void init_rand();
void init_log(const char *log_file);
void init_mem();
void init_difftest(char *ref_so_file, long img_size, int port);
void init_device();
void init_sdb();
void init_disasm(const char *triple);
char *log_file = NULL;
char *elf_file = NULL;
char *img_file = NULL;
bool enable_gdbstub = false;
static void welcome() {
Log("Trace: %s", MUXDEF(CONFIG_TRACE, ANSI_FMT("ON", ANSI_FG_GREEN), ANSI_FMT("OFF", ANSI_FG_RED)));
IFDEF(CONFIG_TRACE, Log("If trace is enabled, a log file will be generated "
Log("Trace: %s", MUXDEF(CONFIG_TRACE, ANSI_FMT("ON", ANSI_FG_GREEN),
ANSI_FMT("OFF", ANSI_FG_RED)));
IFDEF(CONFIG_TRACE,
Log("If trace is enabled, a log file will be generated "
"to record the trace. This may lead to a large log file. "
"If it is not necessary, you can disable it in menuconfig"));
Log("Build time: %s, %s", __TIME__, __DATE__);
printf("Welcome to %s-NEMU!\n", ANSI_FMT(str(__GUEST_ISA__), ANSI_FG_YELLOW ANSI_BG_RED));
printf("Welcome to %s-NEMU!\n",
ANSI_FMT(str(__GUEST_ISA__), ANSI_FG_YELLOW ANSI_BG_RED));
printf("For help, type \"help\"\n");
Log("Exercise: Please remove me in the source code and compile NEMU again.");
assert(0);
}
#ifndef CONFIG_TARGET_AM
#include <getopt.h>
void sdb_set_batch_mode();
static char *log_file = NULL;
static char *diff_so_file = NULL;
static char *img_file = NULL;
static int difftest_port = 1234;
static long load_img() {
FILE *fp = NULL;
size_t img_filename_len = strlen(img_file);
if (img_file == NULL) {
Log("No image is given. Use the default build-in image.");
return 4096; // built-in image size
}
FILE *fp = fopen(img_file, "rb");
Assert(fp, "Can not open '%s'", img_file);
// Image file is searched from paths in environment variable NEMU_IMAGES_PATH if it's a relative path
if (img_file[0] != '/') {
char *search_paths = getenv("NEMU_IMAGES_PATH");
if (search_paths == NULL)
search_paths = "./";
search_paths = strdup(search_paths);
Trace("NEMU_IMAGES_PATH=%s", search_paths);
char *paths_end = strchr(search_paths, '\0');
char *p_start = search_paths;
do {
char *p = strchr(p_start, ':');
if (p != NULL)
*p = '\0';
else
p = paths_end;
char *file_path = malloc(p - p_start + img_filename_len + 2);
strcpy(file_path, p_start);
strcat(file_path, "/");
strcat(file_path, img_file);
fp = fopen(file_path, "rb");
free(file_path);
if (fp) {
Log("Found '%s' in '%s'", img_file, p_start);
break;
}
Assert(fp != NULL || errno == ENOENT, "Cannot open '%s'", img_file);
p_start = p + 1;
} while (p_start < paths_end);
free(search_paths);
Assert(fp, "Cannot find '%s'", img_file);
} else {
fp = fopen(img_file, "rb");
Assert(fp, "Cannot open '%s'", img_file);
}
fseek(fp, 0, SEEK_END);
long size = ftell(fp);
@ -70,27 +113,31 @@ static long load_img() {
static int parse_args(int argc, char *argv[]) {
const struct option table[] = {
{"batch" , no_argument , NULL, 'b'},
{"log" , required_argument, NULL, 'l'},
{"diff" , required_argument, NULL, 'd'},
{"port" , required_argument, NULL, 'p'},
{"help" , no_argument , NULL, 'h'},
{0 , 0 , NULL, 0 },
{"batch", no_argument, NULL, 'b'}, {"log", required_argument, NULL, 'l'},
{"debug", no_argument, NULL, 'g'}, {"elf", required_argument, NULL, 'f'},
{"help", no_argument, NULL, 'h'}, {0, 0, NULL, 0},
};
int o;
while ( (o = getopt_long(argc, argv, "-bhl:d:p:", table, NULL)) != -1) {
while ((o = getopt_long(argc, argv, "-bhl:d:p:", table, NULL)) != -1) {
switch (o) {
case 'b': sdb_set_batch_mode(); break;
case 'p': sscanf(optarg, "%d", &difftest_port); break;
case 'l': log_file = optarg; break;
case 'd': diff_so_file = optarg; break;
case 1: img_file = optarg; return 0;
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-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);
}
@ -99,44 +146,37 @@ static int parse_args(int argc, char *argv[]) {
}
void init_monitor(int argc, char *argv[]) {
/* Perform some global initialization. */
/* Parse arguments. */
parse_args(argc, argv);
/* Set random seed. */
init_rand();
void init_log(const char *log_file);
/* Open the log file. */
init_log(log_file);
/* Initialize memory. */
init_mem();
/* Initialize devices. */
IFDEF(CONFIG_DEVICE, init_device());
/* Perform ISA dependent initialization. */
init_isa();
/* Perform some global initialization. */
nemu_init(malloc(nemu_dbg_state_size));
/* Load the image to memory. This will overwrite the built-in image. */
long img_size = load_img();
load_img();
/* Initialize differential testing. */
init_difftest(diff_so_file, img_size, difftest_port);
/* Initialize the simple debugger. */
init_sdb();
// printf("elf_file: %s\n", elf_file);
if (elf_file != NULL) {
#ifdef CONFIG_FTRACE
void init_elf(const char *path);
init_elf(elf_file);
#else
Warning("Elf file provided, but ftrace not turned on. Ignoring elf file.");
#endif
}
#ifndef CONFIG_ISA_loongarch32r
IFDEF(CONFIG_ITRACE, init_disasm(
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"
));
MUXDEF(CONFIG_RV64, "riscv64", "riscv32"),
"bad"))) "-pc-linux-gnu"));
#endif
/* Display welcome message. */

View file

@ -1,125 +0,0 @@
/***************************************************************************************
* Copyright (c) 2014-2022 Zihao Yu, Nanjing University
*
* NEMU is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
* http://license.coscl.org.cn/MulanPSL2
*
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
*
* See the Mulan PSL v2 for more details.
***************************************************************************************/
#include <isa.h>
/* We use the POSIX regex functions to process regular expressions.
* Type 'man regex' for more information about POSIX regex functions.
*/
#include <regex.h>
enum {
TK_NOTYPE = 256, TK_EQ,
/* TODO: Add more token types */
};
static struct rule {
const char *regex;
int token_type;
} rules[] = {
/* TODO: Add more rules.
* Pay attention to the precedence level of different rules.
*/
{" +", TK_NOTYPE}, // spaces
{"\\+", '+'}, // plus
{"==", TK_EQ}, // equal
};
#define NR_REGEX ARRLEN(rules)
static regex_t re[NR_REGEX] = {};
/* Rules are used for many times.
* Therefore we compile them only once before any usage.
*/
void init_regex() {
int i;
char error_msg[128];
int ret;
for (i = 0; i < NR_REGEX; i ++) {
ret = regcomp(&re[i], rules[i].regex, REG_EXTENDED);
if (ret != 0) {
regerror(ret, &re[i], error_msg, 128);
panic("regex compilation failed: %s\n%s", error_msg, rules[i].regex);
}
}
}
typedef struct token {
int type;
char str[32];
} Token;
static Token tokens[32] __attribute__((used)) = {};
static int nr_token __attribute__((used)) = 0;
static bool make_token(char *e) {
int position = 0;
int i;
regmatch_t pmatch;
nr_token = 0;
while (e[position] != '\0') {
/* Try all rules one by one. */
for (i = 0; i < NR_REGEX; i ++) {
if (regexec(&re[i], e + position, 1, &pmatch, 0) == 0 && pmatch.rm_so == 0) {
char *substr_start = e + position;
int substr_len = pmatch.rm_eo;
Log("match rules[%d] = \"%s\" at position %d with len %d: %.*s",
i, rules[i].regex, position, substr_len, substr_len, substr_start);
position += substr_len;
/* TODO: Now a new token is recognized with rules[i]. Add codes
* to record the token in the array `tokens'. For certain types
* of tokens, some extra actions should be performed.
*/
switch (rules[i].token_type) {
default: TODO();
}
break;
}
}
if (i == NR_REGEX) {
printf("no match at position %d\n%s\n%*.s^\n", position, e, position, "");
return false;
}
}
return true;
}
word_t expr(char *e, bool *success) {
if (!make_token(e)) {
*success = false;
return 0;
}
/* TODO: Insert codes to evaluate the expression. */
TODO();
return 0;
}

Some files were not shown because too many files have changed in this diff Show more