Skip to content

Commit 0801d0f

Browse files
committed
Add initial support for Ubuntu-provided GCC that uses glibc
1 parent dc7efda commit 0801d0f

File tree

13 files changed

+70
-24
lines changed

13 files changed

+70
-24
lines changed

.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
**/build_*/
33
**/riscv32-unknown-elf/
44
**/riscv64-unknown-elf/
5+
**/riscv64-linux-gnu/
56
*.elf
67
.vscode/
78
engine/engine

README.md

+16-4
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,21 @@ This project has no external dependencies outside of libriscv and libfmt. libris
3939

4040
Running the engine is only half the equation as you will also want to be able to modify the scripts themselves. To do that you need a RISC-V compiler.
4141

42-
## Getting a RISC-V compiler
42+
## Using a RISC-V toolchain from system package
43+
44+
This is the simplest option. Run [build.sh](/engine/build.sh) with `--glibc`. Right now it assumes you have installed `gcc-12-riscv64-linux-gnu`, however it may be possible to auto-detect this in the future.
45+
46+
```sh
47+
sudo apt install gcc-12-riscv64-linux-gnu
48+
cd engine
49+
./build.sh --glibc
50+
```
51+
52+
The C-library that is used by this toolchain, glibc, will use its own POSIX multi-threading, and it will be required that it works in order for C++ exceptions to work. So, be careful with mixing microthread and C++ exceptions.
53+
54+
The GCC compiler is built using the C-extension (compressed instructions), which is now default enabled in the build script. It has a known minor performance impact.
55+
56+
## Getting a newlib RISC-V compiler
4357

4458
There are several ways to do this. However for now one requirement is to build the newlib variant in the riscv-gnu-toolchain for RISC-V. Install it like this:
4559

@@ -65,7 +79,7 @@ $ riscv64-unknown-elf-g++ --version
6579
riscv64-unknown-elf-g++ (g5964b5cd7) 11.1.0
6680
```
6781

68-
While 32-bit RISC-V is faster to emulate than 64-bit, I prefer it when the sizes match between the address spaces.
82+
While 32-bit RISC-V is faster to emulate than 64-bit, I prefer it when the sizes match between the address spaces. It makes passing objects and structs very easy.
6983

7084
## Building script files
7185

@@ -245,5 +259,3 @@ See `libriscv/memory.hpp` for a list of helper functions, each with a specific p
245259
- Definitely. I already support a few 256-bit operations, but it is not near completion.
246260
- I have real-time requirements.
247261
- As long as pausing the script to continue later is an option, you will not have any trouble. Just don't pause the script while it's in a thread and then accidentally vmcall into it from somewhere else. This will clobber all registers and you will have trouble later. You can use preempt provided that it returns to the same thread again (although you are able to yield back to a thread manually). There are many options where things will be OK. In my own engine all long-running tasks are running on separate machines to simplify things.
248-
- My program is jumping to a misaligned instruction. Something is very wrong!
249-
- Try enabling the RISCV_EXT_C CMake option and see if perhaps your RISC-V programs are built with compressed instructions enabled. They are the most performant in libriscv, but they are pretty standard. For example the standard 64-bit RISC-V architecture is RV64GC, while the most performant in libriscv is RV64G.

engine/build.sh

+2-2
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,13 @@ export CC="ccache $CC"
66
# Build the game
77
mkdir -p build
88
pushd build
9-
cmake .. -DCMAKE_BUILD_TYPE=Release -DFLTO=ON -DSANITIZE=OFF
9+
cmake .. -DCMAKE_BUILD_TYPE=Release -DFLTO=ON -DSANITIZE=OFF -DRISCV_EXT_C=ON
1010
make -j4
1111
popd
1212

1313
# Build the script
1414
pushd ../programs
15-
source build.sh
15+
source build.sh $@
1616
popd
1717

1818
# gsettings set org.gnome.mutter center-new-windows true

engine/scripts/src/gameplay.cpp

+5-5
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ static void opaque_dyncall_handler()
3333
sys_empty();
3434
sys_empty();
3535
sys_empty();
36-
// return_fast();
36+
return_fast();
3737
}
3838

3939
static void inline_dyncall_handler()
@@ -42,7 +42,7 @@ static void inline_dyncall_handler()
4242
isys_empty();
4343
isys_empty();
4444
isys_empty();
45-
// return_fast();
45+
return_fast();
4646
}
4747

4848
static void opaque_dyncall_args_x4()
@@ -55,7 +55,7 @@ static void opaque_dyncall_args_x4()
5555
sys_testing123(1, 2, 3);
5656
sys_empty();
5757
sys_testing123(1, 2, 3);
58-
// return_fast();
58+
return_fast();
5959
}
6060

6161
static void inline_dyncall_args_x4()
@@ -68,7 +68,7 @@ static void inline_dyncall_args_x4()
6868
isys_testing123(1, 2, 3);
6969
isys_empty();
7070
isys_testing123(1, 2, 3);
71-
// return_fast();
71+
return_fast();
7272
}
7373

7474
PUBLIC(void public_donothing())
@@ -94,7 +94,7 @@ PUBLIC(void benchmarks())
9494
while preserving registers, and then prints some statistics. */
9595
measure("VM function call overhead",
9696
[] {
97-
//return_fast();
97+
return_fast();
9898
});
9999
measure("Full thread creation overhead", full_thread_function);
100100
measure("Oneshot thread creation overhead", oneshot_thread_function);

engine/scripts/src/level1_threads.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ void do_threads_stuff()
7777
[](std::string mt)
7878
{
7979
print("Hello ", mt, " World!\n");
80-
sleep(1.0);
80+
Timer::sleep(1.0);
8181
print("Hello Belated Microthread World! 1 second passed.\n");
8282
/* add_remote_work is implemented in events.hpp
8383
NOTE: We cannot pass "anything" we want here,

engine/src/script/script.cpp

+8-1
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,10 @@ bool Script::reset()
5151
// setup system calls and traps
5252
this->machine_setup();
5353
// setup program argv *after* setting new stack pointer
54-
machine().setup_argv({name()});
54+
static const std::vector<std::string> env = {
55+
"LC_CTYPE=C", "LC_ALL=C", "USER=groot"
56+
};
57+
machine().setup_linux({name()}, env);
5558
}
5659
catch (std::exception& e)
5760
{
@@ -161,6 +164,10 @@ void Script::machine_setup()
161164
{
162165
this->m_heap_area = machine().memory.mmap_allocate(MAX_HEAP);
163166
}
167+
168+
// Add POSIX system call interfaces
169+
machine().setup_linux_syscalls();
170+
machine().setup_posix_threads();
164171
// Add native system call interfaces
165172
machine().setup_native_heap(HEAP_SYSCALLS_BASE, heap_area(), MAX_HEAP);
166173
machine().setup_native_memory(MEMORY_SYSCALLS_BASE);

ext/libriscv

programs/build.sh

+25-5
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,32 @@
22
set -e
33
GCC_TRIPLE="riscv64-unknown-elf"
44
export CXX="ccache $GCC_TRIPLE-g++"
5+
CDEBUG="-DGCSECTIONS=ON -DLTO=OFF -DCMAKE_BUILD_TYPE=Release"
56

6-
if [[ -z "${DEBUG}" ]]; then
7-
CDEBUG="-DGCSECTIONS=ON -DLTO=OFF -DCMAKE_BUILD_TYPE=Release"
8-
else
9-
CDEBUG="-DGCSECTIONS=OFF -DLTO=OFF -DCMAKE_BUILD_TYPE=Debug"
10-
fi
7+
for i in "$@"; do
8+
case $i in
9+
# -e=*|--extension=*)
10+
# EXTENSION="${i#*=}"
11+
# shift # past argument=value
12+
# ;;
13+
--debug)
14+
CDEBUG="-DGCSECTIONS=OFF -DLTO=OFF -DCMAKE_BUILD_TYPE=Debug"
15+
shift # past argument with no value
16+
;;
17+
--glibc)
18+
GCC_VERSION=12
19+
GCC_TRIPLE="riscv64-linux-gnu"
20+
export CXX="ccache $GCC_TRIPLE-g++-$GCC_VERSION"
21+
shift # past argument with no value
22+
;;
23+
-*|--*)
24+
echo "Unknown option $i"
25+
exit 1
26+
;;
27+
*)
28+
;;
29+
esac
30+
done
1131

1232
mkdir -p $GCC_TRIPLE
1333
pushd $GCC_TRIPLE

programs/micro/api/api.h

+3
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,9 @@ namespace api
7676
static Timer periodic(float period, Callback);
7777
static Timer periodic(float time, float period, Callback);
7878
void stop() const;
79+
80+
static long sleep(float seconds);
81+
7982
const int id;
8083
};
8184

programs/micro/api/api_impl.h

+5-3
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ template <typename T> inline long measure(const char* testname, T testfunc)
7575

7676
inline uint32_t Game::current_machine()
7777
{
78-
return syscall(ECALL_MACHINE_HASH);
78+
return syscall1(ECALL_MACHINE_HASH);
7979
}
8080

8181
#define RUNNING_ON(mach) (api::current_machine() == crc32(mach))
@@ -107,7 +107,7 @@ inline void each_tick(const T& func, Args&&... args)
107107

108108
inline void Game::exit()
109109
{
110-
(void)syscall(ECALL_GAME_EXIT);
110+
(void)syscall1(ECALL_GAME_EXIT);
111111
}
112112

113113
inline void Game::breakpoint(std::source_location sl)
@@ -178,7 +178,7 @@ inline void Timer::stop() const
178178
sys_timer_stop(this->id);
179179
}
180180

181-
inline long sleep(float seconds)
181+
inline long Timer::sleep(float seconds)
182182
{
183183
const int tid = microthread::gettid();
184184
Timer::oneshot(
@@ -309,11 +309,13 @@ dynamic_call(const uint32_t hash, const char* name, Args&&... args)
309309
{
310310
if (type[i] == 0b001)
311311
{
312+
#ifdef __OPTIMIZE__
312313
if ((int64_t)gpr[i] >= -4096 && (int64_t)gpr[i] < 4096)
313314
{
314315
asm(".insn i 0b0001011, 0, x0, x0, %0" ::"I"(gpr[i]));
315316
}
316317
else
318+
#endif
317319
{
318320
a0 = gpr[i];
319321
asm(".word 0b001000000001011" : : "r"(a0));

programs/micro/libc/assert.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ inline void print(Args&&... args)
1414

1515
inline void print_backtrace()
1616
{
17-
syscall(SYSCALL_BACKTRACE);
17+
syscall1(SYSCALL_BACKTRACE);
1818
}
1919

2020
extern "C"

programs/micro/libc/write.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ int fputc (int c, FILE*)
3333
return sys_write(&c, 1);
3434
}
3535
extern "C"
36-
wint_t fputwc(wchar_t ch, FILE*)
36+
uint8_t fputwc(wchar_t ch, FILE*)
3737
{
3838
char c = ch;
3939
sys_write(&c, 1);

programs/micro/micro.cmake

+1
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ function (add_micro_binary NAME ORG)
6060
target_link_libraries(${NAME} -static -Wl,--whole-archive libc -Wl,--no-whole-archive)
6161
target_link_libraries(${NAME} frozen::frozen)
6262
target_link_libraries(${NAME} "-Wl,-Ttext-segment=${ORG}")
63+
target_link_libraries(${NAME} "-Wl,--wrap=exit")
6364
# place ELF into the sub-projects source folder
6465
set_target_properties(${NAME}
6566
PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"

0 commit comments

Comments
 (0)