diff --git a/CMakeLists.txt b/CMakeLists.txt index 0737d71..c4e76f4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,11 +1,11 @@ cmake_minimum_required(VERSION 3.24) -project(HansTheGatherer) +set(CMAKE_TOOLCHAIN_FILE ${CMAKE_CURRENT_SOURCE_DIR}/cmake/riscv-toolchain.cmake) + +project(HansTheGatherer C CXX ASM) set(CMAKE_EXPORT_COMPILE_COMMANDS ON) -# Option to switch real platform vs. SDL implementation... - include(FetchContent) FetchContent_Declare( @@ -14,8 +14,24 @@ FetchContent_Declare( OVERRIDE_FIND_PACKAGE ) FetchContent_MakeAvailable(entt) + find_package(entt CONFIG REQUIRED) +add_library(RISCV_Options INTERFACE) +target_compile_options(RISCV_Options INTERFACE + -fno-exceptions + -fno-unwind-tables + -fno-rtti + -fno-pic # PIC? + -mno-relax + -march=rv32im + -mabi=ilp32 + -std=c++20 +) + +add_subdirectory(lib) +add_subdirectory(wuehans) + add_executable(HansTheGatherer src/main.cpp src/audio.cpp @@ -25,6 +41,20 @@ add_executable(HansTheGatherer src/render.cpp ) -target_link_libraries(HansTheGatherer EnTT) +target_link_options(HansTheGatherer PRIVATE + -nostartfiles + -Wl,--gc-sections + -march=rv32im + -mabi=ilp32 + -lstdc++ + -lc + -lgcc + -mcmodel=medany +) -set_property(TARGET HansTheGatherer PROPERTY CXX_STANDARD 20) +target_link_libraries(HansTheGatherer PRIVATE + RISCV_Options + WueHans + Hall + EnTT +) diff --git a/cmake/riscv-toolchain.cmake b/cmake/riscv-toolchain.cmake new file mode 100644 index 0000000..91fa1dc --- /dev/null +++ b/cmake/riscv-toolchain.cmake @@ -0,0 +1,19 @@ +set(CMAKE_SYSTEM_NAME Generic) +set(CMAKE_SYSTEM_PROCESSOR riscv) + +set(RISCV_PREFIX riscv32-unknown-elf) +set(CMAKE_C_COMPILER ${RISCV_PREFIX}-gcc) +set(CMAKE_CXX_COMPILER ${RISCV_PREFIX}-g++) +set(CMAKE_ASM_COMPILER ${RISCV_PREFIX}-gcc) + +set(CMAKE_FIND_ROOT_PATH root) + +# Don't run the linker on compiler check +set(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY) + +# adjust the default behavior of the FIND_XXX() commands: +# search programs in the host environment +set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) +# search headers and libraries in the target environment +set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) +set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt new file mode 100644 index 0000000..62032de --- /dev/null +++ b/lib/CMakeLists.txt @@ -0,0 +1 @@ +add_subdirectory(Hall) diff --git a/lib/Hall/CMakeLists.txt b/lib/Hall/CMakeLists.txt new file mode 100644 index 0000000..435cd42 --- /dev/null +++ b/lib/Hall/CMakeLists.txt @@ -0,0 +1,11 @@ +add_library(Hall STATIC + source/Audio.cpp + source/System.cpp + source/Video.cpp +) + +target_include_directories(Hall + PUBLIC SYSTEM include +) + +target_link_libraries(Hall PRIVATE RISCV_Options) diff --git a/lib/Hall/README.md b/lib/Hall/README.md new file mode 100644 index 0000000..790ef60 --- /dev/null +++ b/lib/Hall/README.md @@ -0,0 +1,2 @@ +# Hall +Hallo, hier ist Hall diff --git a/lib/Hall/include/Hall/Audio.h b/lib/Hall/include/Hall/Audio.h new file mode 100644 index 0000000..b3a7cb3 --- /dev/null +++ b/lib/Hall/include/Hall/Audio.h @@ -0,0 +1,63 @@ +#pragma once + +namespace Hall +{ + /// + /// Sets the global volume. 0 is muted, 128 is the default, 255 is max + /// + /// 0 is muted, 128 is the default, 255 is max + void SetGlobalVolume(unsigned char volume); + + /// + /// Prepares a channel to be used to play a non-looped single-channel audio + /// + /// The ID of the channel. Must be within [0,7] + /// A pointer to the first sample of the audio data + /// The total number of samples in the audio data + /// The channel's local volume. 0 is muted, 128 is the default, 255 is max + void SetupMono(int channelID, short* data, int sampleCount, unsigned char volume = 128); + + /// + /// Prepares a channel to be used to play a looped single-channel audio + /// + /// The ID of the channel. Must be within [0,7] + /// A pointer to the first sample of the audio data + /// The total number of samples in the audio data + /// The index of the first sample of the loop (inclusive) + /// The index of the last sample of the loop (exclusive?) + /// The channel's local volume. 0 is muted, 128 is the default, 255 is max + void SetupMono(int channelID, short* data, int sampleCount, unsigned int loopStart, unsigned int loopEnd, unsigned char volume = 128); + + /// + /// Prepares two channels to be used to play a non-looped stereo audio + /// + /// The ID of the channel for the left audio. Must be within [0,7] + /// The ID of the channel for the right audio. Must be within [0,7] + /// A pointer to the first sample of the audio data + /// The total number of samples PER CHANNEL in the audio data + /// The channel's local volume. 0 is muted, 128 is the default, 255 is max + void SetupStereo(int channelID_left, int channelID_right, short* data, int sampleCount, unsigned char volume = 128); + + /// + /// Prepares two channels to be used to play a looped stereo audio + /// + /// The ID of the channel for the left audio. Must be within [0,7] + /// The ID of the channel for the right audio. Must be within [0,7] + /// A pointer to the first sample of the audio data + /// The total number of samples PER CHANNEL in the audio data + /// The index of the first sample of the loop (inclusive) + /// The index of the last sample of the loop (exclusive?) + /// The channel's local volume. 0 is muted, 128 is the default, 255 is max + void SetupStereo(int channelID_left, int channelID_right, short* data, int sampleCount, unsigned int loopStart, unsigned int loopEnd, unsigned char volume = 128); + + + void Play(unsigned char channelSelect); + void Pause(unsigned char channelSelect); + void SetData(unsigned char channelSelect, short* data); + void SetLoop(unsigned char channelSelect, bool isLooping); + void SetLoopBoundaries(unsigned char channelSelect, int start, int end); + void SetPosition(unsigned char channelSelect, int position); + void SetSample(unsigned char channelSelect, short sample); + void SetVolume(unsigned char channelSelect, unsigned char volume); + +} diff --git a/lib/Hall/include/Hall/Hall.h b/lib/Hall/include/Hall/Hall.h new file mode 100644 index 0000000..673d7f8 --- /dev/null +++ b/lib/Hall/include/Hall/Hall.h @@ -0,0 +1,5 @@ +#pragma once + +#include +#include +#include diff --git a/lib/Hall/include/Hall/System.h b/lib/Hall/include/Hall/System.h new file mode 100644 index 0000000..41de630 --- /dev/null +++ b/lib/Hall/include/Hall/System.h @@ -0,0 +1,36 @@ +#pragma once + +namespace Hall +{ + static const int SYSTEM_CLK_FREQUENCY = 50000000; //50 MHz + static void* const SDRAM_START = 0x0; //Start of the RAM. It is 32 MB large + static void* const BOOTLOADER_START = (void* const) 0x02010000; //Start of the bootloader. It is 32 kB large + static void* const SD_CARD_START = (void* const) 0x80000000; //Start of the SD-Card + + /// + /// Returns an 8-Byte int, that represents the number of ticks that passed since the system's boot-up. Divide by SYSTEM_CLK_FREQUENCY to get seconds + /// + /// The system time since boot-up in ticks + unsigned long long GetSystemTime(); + + /// + /// Returns the state of all buttons on the controller. + /// + /// Must be in the range [0,1] + /// Each button corresponds to one bit: 0 - B, 1 - Y, 2 - Select, 3 - Start, 4 - Up, 5 - Down, 6 - Left, 7 - Right, 8 - A, 9 - X, 10 - L, 11 - R + unsigned short GetController(int id); + + unsigned int GetSystemTimeExcerpt(int precision); + bool GetA(unsigned short controller); + bool GetB(unsigned short controller); + bool GetX(unsigned short controller); + bool GetY(unsigned short controller); + bool GetStart(unsigned short controller); + bool GetSelect(unsigned short controller); + bool GetUp(unsigned short controller); + bool GetDown(unsigned short controller); + bool GetLeft(unsigned short controller); + bool GetRight(unsigned short controller); + bool GetL(unsigned short controller); + bool GetR(unsigned short controller); +} diff --git a/lib/Hall/include/Hall/Video.h b/lib/Hall/include/Hall/Video.h new file mode 100644 index 0000000..0ce4634 --- /dev/null +++ b/lib/Hall/include/Hall/Video.h @@ -0,0 +1,43 @@ +#pragma once + +namespace Hall +{ + const int SCREEN_HEIGHT = 240; + const int SCREEN_WIDTH = 400; + + /// + /// Draws an excerpt of the given data onto the screen. All coordinates describe the top-left corner + /// + /// A pointer to the first pixel of an image + /// The x offset within that image + /// The y offset within that image + /// The x position on screen. + /// The y position on screen. + /// The width of the excerpt + /// The height of the excerpt + /// The width of the image (NOT EXCERPT) + void Draw(unsigned short* data, unsigned short xOffset, unsigned short yOffset, unsigned short screenX, unsigned short screenY, unsigned short width, unsigned short height, unsigned short dataWidth); + + /// + /// Clears the whole screen with the given color + /// + /// The format is R5G5B5A1, with the alpha bit being lsb + void Clear(unsigned short color); + + void SetData(unsigned short* data); + void SetXOffset(unsigned short xOffset); + void SetYOffset(unsigned short yOffset); + void SetImageWidth(unsigned short imageWidth); + void SetWidth(unsigned short width); + void SetHeight(unsigned short height); + void SetScreenX(unsigned short x); + void SetScreenY(unsigned short y); + void SetClearColor(unsigned short color); + void SetCommandDraw(); + void SetCommandClear(); + void SetCommandSwapBuffers(); + + bool GetIsGPUBusy(); + bool GetVSync(); + bool GetHSync(); +} diff --git a/lib/Hall/source/Audio.cpp b/lib/Hall/source/Audio.cpp new file mode 100644 index 0000000..2537289 --- /dev/null +++ b/lib/Hall/source/Audio.cpp @@ -0,0 +1,132 @@ +#include + +volatile char* AUDIO_START = (char*) 0x2000100; +volatile short** AUDIO_START_ADDRESS = (volatile short**)(AUDIO_START + 4); +volatile int* AUDIO_SAMPLE_COUNT = (volatile int*)(AUDIO_START + 8); +volatile int* AUDIO_LOOP_START = (volatile int*)(AUDIO_START + 12); +volatile int* AUDIO_LOOP_END = (volatile int*)(AUDIO_START + 16); +volatile int* AUDIO_CURRENT_POSITION = (volatile int*)(AUDIO_START + 20); +volatile short* AUDIO_LAST_SAMPLE = (volatile short*)(AUDIO_START + 24); +volatile unsigned char* AUDIO_VOLUME = (volatile unsigned char*)(AUDIO_START + 28); +volatile bool* AUDIO_IS_LOOPING = (volatile bool*)(AUDIO_START + 32); +volatile bool* AUDIO_IS_PLAYING = (volatile bool*)(AUDIO_START + 36); +volatile bool* AUDIO_IS_MONO = (volatile bool*)(AUDIO_START + 40); +volatile bool* AUDIO_IS_RIGHT = (volatile bool*)(AUDIO_START + 44); +unsigned char* AUDIO_GLOBAL_VOLUME = (unsigned char*)(AUDIO_START + 48); //I think we can skip volatile for these two +unsigned char* AUDIO_CHANNEL_SELECT = (unsigned char*)(AUDIO_START + 52); //Because they will never change and always address the same value + + +void Hall::SetGlobalVolume(unsigned char volume) +{ + *AUDIO_GLOBAL_VOLUME = volume; +} + +void Hall::SetupMono(int channelID, short* data, int sampleCount, unsigned char volume) +{ + *AUDIO_CHANNEL_SELECT = 1 << channelID; + *AUDIO_START_ADDRESS = data; + *AUDIO_SAMPLE_COUNT = sampleCount; + *AUDIO_CURRENT_POSITION = 0; + *AUDIO_VOLUME = volume; + *AUDIO_IS_LOOPING = false; + *AUDIO_IS_PLAYING = false; + *AUDIO_IS_MONO = true; +} + +void Hall::SetupMono(int channelID, short* data, int sampleCount, unsigned int loopStart, unsigned int loopEnd, unsigned char volume) +{ + *AUDIO_CHANNEL_SELECT = 1 << channelID; + *AUDIO_START_ADDRESS = data; + *AUDIO_SAMPLE_COUNT = sampleCount; + *AUDIO_CURRENT_POSITION = 0; + *AUDIO_VOLUME = volume; + *AUDIO_IS_LOOPING = true; + *AUDIO_LOOP_START = loopStart; + *AUDIO_LOOP_END = loopEnd; + *AUDIO_IS_PLAYING = false; + *AUDIO_IS_MONO = true; +} + +void Hall::SetupStereo(int channelID_left, int channelID_right, short* data, int sampleCount, unsigned char volume) +{ + *AUDIO_CHANNEL_SELECT = (1 << channelID_left) | (1 << channelID_right); + *AUDIO_START_ADDRESS = data; + *AUDIO_SAMPLE_COUNT = sampleCount; + *AUDIO_CURRENT_POSITION = 0; + *AUDIO_VOLUME = volume; + *AUDIO_IS_LOOPING = false; + *AUDIO_IS_PLAYING = false; + *AUDIO_IS_MONO = false; + *AUDIO_IS_RIGHT = false; + + *AUDIO_CHANNEL_SELECT = 1 << channelID_right; + *AUDIO_IS_RIGHT = true; +} + +void Hall::SetupStereo(int channelID_left, int channelID_right, short* data, int sampleCount, unsigned int loopStart, unsigned int loopEnd, unsigned char volume) +{ + *AUDIO_CHANNEL_SELECT = (1 << channelID_left) | (1 << channelID_right); + *AUDIO_START_ADDRESS = data; + *AUDIO_SAMPLE_COUNT = sampleCount; + *AUDIO_CURRENT_POSITION = 0; + *AUDIO_VOLUME = volume; + *AUDIO_LOOP_START = loopStart; + *AUDIO_LOOP_END = loopEnd; + *AUDIO_IS_LOOPING = true; + *AUDIO_IS_PLAYING = false; + *AUDIO_IS_MONO = false; + *AUDIO_IS_RIGHT = false; + + *AUDIO_CHANNEL_SELECT = 1 << channelID_right; + *AUDIO_IS_RIGHT = true; + +} + +void Hall::Play(unsigned char channelSelect) +{ + *AUDIO_CHANNEL_SELECT = channelSelect; + *AUDIO_IS_PLAYING = true; +} + +void Hall::Pause(unsigned char channelSelect) +{ + *AUDIO_CHANNEL_SELECT = channelSelect; + *AUDIO_IS_PLAYING = false; +} + +void Hall::SetData(unsigned char channelSelect, short* data) +{ + *AUDIO_CHANNEL_SELECT = channelSelect; + *AUDIO_START_ADDRESS = data; +} + +void Hall::SetLoop(unsigned char channelSelect, bool isLooping) +{ + *AUDIO_CHANNEL_SELECT = channelSelect; + *AUDIO_IS_LOOPING; +} + +void Hall::SetLoopBoundaries(unsigned char channelSelect, int start, int end) +{ + *AUDIO_CHANNEL_SELECT = channelSelect; + *AUDIO_LOOP_START = start; + *AUDIO_LOOP_END = end; +} + +void Hall::SetPosition(unsigned char channelSelect, int position) +{ + *AUDIO_CHANNEL_SELECT = channelSelect; + *AUDIO_CURRENT_POSITION = position; +} + +void Hall::SetSample(unsigned char channelSelect, short sample) +{ + *AUDIO_CHANNEL_SELECT = channelSelect; + *AUDIO_LAST_SAMPLE = sample; +} + +void Hall::SetVolume(unsigned char channelSelect, unsigned char volume) +{ + *AUDIO_CHANNEL_SELECT = channelSelect; + *AUDIO_VOLUME = volume; +} diff --git a/lib/Hall/source/System.cpp b/lib/Hall/source/System.cpp new file mode 100644 index 0000000..5faa125 --- /dev/null +++ b/lib/Hall/source/System.cpp @@ -0,0 +1,90 @@ +#include + +volatile char* SYSTEM_TIME = (volatile char*)0x02000300; +volatile unsigned int* SYSTEM_TIME_0 = (volatile unsigned int*)(SYSTEM_TIME + 0); //Least precise +volatile unsigned int* SYSTEM_TIME_1 = (volatile unsigned int*)(SYSTEM_TIME + 4); +volatile unsigned int* SYSTEM_TIME_2 = (volatile unsigned int*)(SYSTEM_TIME + 8); +volatile unsigned int* SYSTEM_TIME_3 = (volatile unsigned int*)(SYSTEM_TIME + 12); +volatile unsigned int* SYSTEM_TIME_4 = (volatile unsigned int*)(SYSTEM_TIME + 16);//Most precise + +volatile char* CONTROLLER_START = (volatile char*)0x02000200; +volatile unsigned short* CONTROLLER_0 = (volatile unsigned short*)(CONTROLLER_START + 0); +volatile unsigned short* CONTROLLER_1 = (volatile unsigned short*)(CONTROLLER_START + 2); + +unsigned long long Hall::GetSystemTime() +{ + unsigned long long result = *SYSTEM_TIME_0; + result = result << 32; + result += *SYSTEM_TIME_4; + return result; +} + +unsigned int Hall::GetSystemTimeExcerpt(int precision) +{ + return *(SYSTEM_TIME_0 + precision); +} + +unsigned short Hall::GetController(int id) +{ + return *(CONTROLLER_0 + id); +} + +bool Hall::GetA(unsigned short controller) +{ + return controller & (1 << 8); +} + +bool Hall::GetB(unsigned short controller) +{ + return controller & (1 << 0); +} + +bool Hall::GetX(unsigned short controller) +{ + return controller & (1 << 9); +} + +bool Hall::GetY(unsigned short controller) +{ + return controller & (1 << 1); +} + +bool Hall::GetStart(unsigned short controller) +{ + return controller & (1 << 3); +} + +bool Hall::GetSelect(unsigned short controller) +{ + return controller & (1 << 2); +} + +bool Hall::GetUp(unsigned short controller) +{ + return controller & (1 << 4); +} + +bool Hall::GetDown(unsigned short controller) +{ + return controller & (1 << 5); +} + +bool Hall::GetLeft(unsigned short controller) +{ + return controller & (1 << 6); +} + +bool Hall::GetRight(unsigned short controller) +{ + return controller & (1 << 7); +} + +bool Hall::GetL(unsigned short controller) +{ + return controller & (1 << 10); +} + +bool Hall::GetR(unsigned short controller) +{ + return controller & (1 << 11); +} diff --git a/lib/Hall/source/Video.cpp b/lib/Hall/source/Video.cpp new file mode 100644 index 0000000..532d855 --- /dev/null +++ b/lib/Hall/source/Video.cpp @@ -0,0 +1,117 @@ +#include + +volatile char* GPU_START = (char*)0x02000000; +volatile unsigned short** GPU_IMAGE_START = (volatile unsigned short**)(GPU_START + 0); +volatile unsigned short* GPU_IMAGE_X_OFFSET = (volatile unsigned short*)(GPU_START + 4); +volatile unsigned short* GPU_IMAGE_Y_OFFSET = (volatile unsigned short*)(GPU_START + 8); +volatile unsigned short* GPU_IMAGE_WIDTH = (volatile unsigned short*)(GPU_START + 12); +volatile unsigned short* GPU_WIDTH = (volatile unsigned short*)(GPU_START + 16); +volatile unsigned short* GPU_HEIGHT = (volatile unsigned short*)(GPU_START + 20); +volatile unsigned short* GPU_SCREEN_X = (volatile unsigned short*)(GPU_START + 24); +volatile unsigned short* GPU_SCREEN_Y = (volatile unsigned short*)(GPU_START + 28); +volatile unsigned short* GPU_CLEAR_COLOR = (volatile unsigned short*)(GPU_START + 32); +volatile bool* GPU_COMMAND_DRAW = (volatile bool*)(GPU_START + 36); +volatile bool* GPU_COMMAND_CLEAR = (volatile bool*)(GPU_START + 40); +volatile bool* GPU_IS_BUSY = (volatile bool*)(GPU_START + 44); +volatile bool* GPU_VSYNC = (volatile bool*)(GPU_START + 48); +volatile bool* GPU_HSYNC = (volatile bool*)(GPU_START + 52); +volatile bool* GPU_COMMAND_SWAP_BUFFERS = (volatile bool*)(GPU_START + 56); +volatile bool* VSYNC_BUFFER_SWAP = (volatile bool*)(GPU_START + 60); + + +void Hall::Draw(unsigned short* data, unsigned short xOffset, unsigned short yOffset, unsigned short screenX, unsigned short screenY, unsigned short width, unsigned short height, unsigned short dataWidth) +{ + *GPU_IMAGE_START = data; + *GPU_IMAGE_X_OFFSET = xOffset; + *GPU_IMAGE_Y_OFFSET = yOffset; + *GPU_IMAGE_WIDTH = dataWidth; + *GPU_WIDTH = width; + *GPU_HEIGHT = height; + *GPU_SCREEN_X = screenX; + *GPU_SCREEN_Y = screenY; + *GPU_COMMAND_DRAW = true; +} + + +void Hall::Clear(unsigned short color) +{ + *GPU_CLEAR_COLOR = color; + *GPU_COMMAND_CLEAR = true; +} + +void Hall::SetData(unsigned short* data) +{ + *GPU_IMAGE_START = data; +} + +void Hall::SetXOffset(unsigned short xOffset) +{ + *GPU_IMAGE_X_OFFSET = xOffset; +} + +void Hall::SetYOffset(unsigned short yOffset) +{ + *GPU_IMAGE_Y_OFFSET = yOffset; +} + +void Hall::SetImageWidth(unsigned short imageWidth) +{ + *GPU_IMAGE_WIDTH = imageWidth; +} + +void Hall::SetWidth(unsigned short width) +{ + *GPU_WIDTH = width; +} + +void Hall::SetHeight(unsigned short height) +{ + *GPU_HEIGHT = height; +} + + +void Hall::SetScreenX(unsigned short x) +{ + *GPU_SCREEN_X = x; +} + + +void Hall::SetScreenY(unsigned short y) +{ + *GPU_SCREEN_Y = y; +} + +void Hall::SetClearColor(unsigned short color) +{ + *GPU_CLEAR_COLOR = color; +} + +void Hall::SetCommandDraw() +{ + *GPU_COMMAND_DRAW = true; +} + +void Hall::SetCommandClear() +{ + *GPU_COMMAND_CLEAR = true; +} + +void Hall::SetCommandSwapBuffers() +{ + *GPU_COMMAND_SWAP_BUFFERS = true; +} + +bool Hall::GetIsGPUBusy() +{ + return *GPU_IS_BUSY; +} + +bool Hall::GetVSync() +{ + return *GPU_VSYNC; +} + +bool Hall::GetHSync() +{ + return *GPU_HSYNC; +} diff --git a/wuehans/CMakeLists.txt b/wuehans/CMakeLists.txt new file mode 100644 index 0000000..2ada51e --- /dev/null +++ b/wuehans/CMakeLists.txt @@ -0,0 +1,11 @@ +add_library(WueHans STATIC start.S syscall.c) + +target_include_directories(WueHans PUBLIC + ${CMAKE_CURRENT_SOURCE_DIR} +) + +target_link_libraries(WueHans PRIVATE RISCV_Options) + +target_link_options(WueHans PUBLIC + -T ${CMAKE_CURRENT_SOURCE_DIR}/wuehans.ld +) diff --git a/wuehans/start.S b/wuehans/start.S new file mode 100644 index 0000000..bc20c74 --- /dev/null +++ b/wuehans/start.S @@ -0,0 +1,54 @@ +.section .text.startSection +.global _Z4mainv +.global _start + +_start: +/* zero-initialize all registers */ +addi x1, zero, 0 +addi x2, zero, 0 +addi x3, zero, 0 +addi x4, zero, 0 +addi x5, zero, 0 +addi x6, zero, 0 +addi x7, zero, 0 +addi x8, zero, 0 +addi x9, zero, 0 +addi x10, zero, 0 +addi x11, zero, 0 +addi x12, zero, 0 +addi x13, zero, 0 +addi x14, zero, 0 +addi x15, zero, 0 +addi x16, zero, 0 +addi x17, zero, 0 +addi x18, zero, 0 +addi x19, zero, 0 +addi x20, zero, 0 +addi x21, zero, 0 +addi x22, zero, 0 +addi x23, zero, 0 +addi x24, zero, 0 +addi x25, zero, 0 +addi x26, zero, 0 +addi x27, zero, 0 +addi x28, zero, 0 +addi x29, zero, 0 +addi x30, zero, 0 +addi x31, zero, 0 + +/* set stack pointer */ +.equ STACK_START, 0x02000000 +lui sp, %hi(STACK_START) +addi sp, sp, %lo(STACK_START) + +/* push zeros on the stack for argc and argv */ +/* (stack is aligned to 16 bytes in riscv calling convention) */ +addi sp,sp,-16 +sw zero,0(sp) +sw zero,4(sp) +sw zero,8(sp) +sw zero,12(sp) + +/* jump to libc init */ +// j _Z4mainv +j main diff --git a/wuehans/syscall.c b/wuehans/syscall.c new file mode 100644 index 0000000..5c78bf8 --- /dev/null +++ b/wuehans/syscall.c @@ -0,0 +1,186 @@ +// #include +#include +#include +#include +#include +/* #include */ + +void *__dso_handle = 0; + +// const TCHAR STDOUT[30] = "stdout.txt"; +// const TCHAR STDERR[30] = "stderr.txt"; + +// FIL fp = {0}; +// FATFS FatFs = {0}; +// BYTE is_mounted = 0; + +// struct FD_Data { +// FIL fp; +// BYTE mode; +// BYTE is_open; +// } FD_Data_default = {NULL, FA_READ, 0}; +// typedef struct FD_Data FD_Data; + +// #define FILE_AMOUNT 4 +// static FD_Data fd_data[FILE_AMOUNT]; + +// int _write(int fd, char *ptr, int len) { +// if (is_mounted == 0) { +// f_mount(&FatFs, "", 0); +// is_mounted = 1; +// } +// // stdout +// if (fd == 1) { + +// FIL write_file; +// FRESULT fr = f_open(&write_file, STDOUT, FA_OPEN_APPEND | FA_WRITE); +// if (fr != 0) { +// return fr; +// } + +// UINT written = 0; + +// fr = f_write(&write_file, ptr, len, &written); +// if (fr != 0) { +// // TODO: Set errno +// return -1; +// } + +// f_close(&write_file); + +// // HACK: Hackermann +// volatile int* x = (int*) 0x80000000; +// int b = *x; +// // HACK: Hackermann Ende + +// return written; +// } else if (fd > 2 && (fd-3) < FILE_AMOUNT && fd_data[fd-3].is_open) { +// UINT bw = 0; +// f_write(&fd_data[fd-3].fp, ptr, len, &bw); + +// return bw; +// } + +// return -1; +// } + +// int _read(int fd, char *ptr, int len) { +// if (fd > 2 && (fd-3) < FILE_AMOUNT && fd_data[fd-3].is_open) { +// UINT bytesRead = 0; +// FRESULT result = f_read(&fd_data[fd-3].fp, ptr, len, &bytesRead); +// /* ScreenPrint("_read"); */ +// return bytesRead; +// } + +// return -1; +// } + +// void *_sbrk(int incr) { +// extern int heap_begin; +// static unsigned char *heap = NULL; +// unsigned char *prev_heap; + +// if (heap == NULL) { +// heap = (unsigned char *)&heap_begin; +// } +// prev_heap = heap; + +// if ((int)heap + incr < heap_begin + HEAP_SIZE) { +// heap += incr; +// } + +// /* ScreenPrint("_sbrk"); */ +// return prev_heap; +// } + +// int _fstat(int fd, struct stat *st) { +// st->st_mode = S_IFREG; +// /* ScreenPrint("_fstat"); */ +// return 0; +// } + +// int _lseek(int fd, int offset, int whence) { +// // Invalid lseek call +// if (fd <= 2 || (fd-3) >= FILE_AMOUNT || !fd_data[fd-3].is_open) { +// return -1; +// } + +// // Calculate the correct offset for f_lseek() +// FSIZE_t ofs = 0; +// switch (whence) { +// // Set to offset directly +// case SEEK_SET: +// ofs = offset; +// break; + +// // Increment by offset +// case SEEK_CUR: +// ofs = f_tell(&fd_data[fd-3].fp) + offset; +// break; + +// // Append offset to EOF +// case SEEK_END: +// ofs = f_size(&fd_data[fd-3].fp) + offset; +// break; +// default: +// return -1; +// } + +// FRESULT result = f_lseek(&fd_data[fd-3].fp, ofs); +// return result; +// } + +// int _open(const char *name, int flags, int mode) { +// if (is_mounted == 0) { +// f_mount(&FatFs, "", 0); +// is_mounted = 1; +// } + +// int i; +// for (i = 0; i < FILE_AMOUNT; i++) { +// if (fd_data[i].is_open == 1) { +// // Entry already in use +// continue; +// } +// mode = FA_READ; +// FRESULT fr = f_open(&fd_data[i].fp, name, mode); +// if (fr != FR_OK) { +// return -1; +// } + +// fd_data[i].mode = mode; +// fd_data[i].is_open = 1; +// // Exclude stdout, stderr, stdin +// return i+3; +// } + +// return -1; +// } + +// int _close(int fd) { +// if (fd > 2 && (fd-3) < FILE_AMOUNT) { +// fd_data[fd-3].is_open = 0; +// return 0; +// } + +// return -1; +// } + +int _isatty(int fd) +{ + errno = ENOTTY; + /* ScreenPrint("isatty"); */ + return 0; +} + +void _exit(int status) { + while (1) { + } +} + +int _kill(int pid, int sig) { + errno = EINVAL; + return -1; +} + +int _getpid() { return -1; } diff --git a/wuehans/wuehans.ld b/wuehans/wuehans.ld new file mode 100644 index 0000000..abe0e1c --- /dev/null +++ b/wuehans/wuehans.ld @@ -0,0 +1,207 @@ + +/* ---- Original Script: /opt/riscv32i/riscv32-unknown-elf/lib/ldscripts/elf32lriscv.x ---- */ +/* Default linker script, for normal executables */ +/* Copyright (C) 2014-2017 Free Software Foundation, Inc. +Copying and distribution of this script, with or without modification, +are permitted in any medium without royalty provided the copyright +notice and this notice are preserved. */ +OUTPUT_FORMAT("elf32-littleriscv", "elf32-littleriscv", +"elf32-littleriscv") +OUTPUT_ARCH(riscv) +ENTRY(_start) +SECTIONS +{ + . = 0x00000000; + + .startSection : + { + KEEP(*(.text.startSection)) + } + .text : + { + *(.text) + *(.text.unlikely .text.*_unlikely .text.unlikely.*) + *(.text.exit .text.exit.*) + *(.text.startup .text.startup.*) + *(.text.hot .text.hot.*) + *(.stub .text.* .gnu.linkonce.t.*) + /* .gnu.warning sections are handled specially by elf32.em. */ + *(.gnu.warning) +} +.init : +{ + KEEP (*(SORT_NONE(.init))) +} +.plt : { *(.plt) } +.iplt : { *(.iplt) } +.fini : +{ + KEEP (*(SORT_NONE(.fini))) +} +PROVIDE (__etext = .); +PROVIDE (_etext = .); +PROVIDE (etext = .); +.rodata : { *(.rodata .rodata.* .gnu.linkonce.r.*) } +.rodata1 : { *(.rodata1) } +.sdata2 : +{ + *(.sdata2 .sdata2.* .gnu.linkonce.s2.*) +} +.sbss2 : { *(.sbss2 .sbss2.* .gnu.linkonce.sb2.*) } +.eh_frame_hdr : { *(.eh_frame_hdr) *(.eh_frame_entry .eh_frame_entry.*) } +.eh_frame : ONLY_IF_RO { KEEP (*(.eh_frame)) *(.eh_frame.*) } +.gcc_except_table : ONLY_IF_RO { *(.gcc_except_table + .gcc_except_table.*) } +.gnu_extab : ONLY_IF_RO { *(.gnu_extab*) } +/* These sections are generated by the Sun/Oracle C++ compiler. */ +.exception_ranges : ONLY_IF_RO { *(.exception_ranges + .exception_ranges*) } +/* Adjust the address for the data segment. We want to adjust up to +the same address within the page on the next page up. */ +. = DATA_SEGMENT_ALIGN (CONSTANT (MAXPAGESIZE), CONSTANT (COMMONPAGESIZE)); +/* Exception handling */ +.eh_frame : ONLY_IF_RW { KEEP (*(.eh_frame)) *(.eh_frame.*) } +.gnu_extab : ONLY_IF_RW { *(.gnu_extab) } +.gcc_except_table : ONLY_IF_RW { *(.gcc_except_table .gcc_except_table.*) } +.exception_ranges : ONLY_IF_RW { *(.exception_ranges .exception_ranges*) } +/* Thread Local Storage sections */ +.tdata : { *(.tdata .tdata.* .gnu.linkonce.td.*) } +.tbss : { *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon) } +.preinit_array : +{ + PROVIDE_HIDDEN (__preinit_array_start = .); + KEEP (*(.preinit_array)) + PROVIDE_HIDDEN (__preinit_array_end = .); +} +.init_array : +{ + PROVIDE_HIDDEN (__init_array_start = .); + KEEP (*(SORT_BY_INIT_PRIORITY(.init_array.*) SORT_BY_INIT_PRIORITY(.ctors.*))) + KEEP (*(.init_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .ctors)) + PROVIDE_HIDDEN (__init_array_end = .); +} +.fini_array : +{ + PROVIDE_HIDDEN (__fini_array_start = .); + KEEP (*(SORT_BY_INIT_PRIORITY(.fini_array.*) SORT_BY_INIT_PRIORITY(.dtors.*))) + KEEP (*(.fini_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .dtors)) + PROVIDE_HIDDEN (__fini_array_end = .); +} +.ctors : +{ + /* gcc uses crtbegin.o to find the start of + the constructors, so we make sure it is + first. Because this is a wildcard, it + doesn't matter if the user does not + actually link against crtbegin.o; the + linker won't look for a file to match a + wildcard. The wildcard also means that it + doesn't matter which directory crtbegin.o + is in. */ +KEEP (*crtbegin.o(.ctors)) +KEEP (*crtbegin?.o(.ctors)) +/* We don't want to include the .ctor section from +the crtend.o file until after the sorted ctors. +The .ctor section from the crtend file contains the +end of ctors marker and it must be last */ +KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .ctors)) +KEEP (*(SORT(.ctors.*))) +KEEP (*(.ctors)) +} +.dtors : +{ + KEEP (*crtbegin.o(.dtors)) + KEEP (*crtbegin?.o(.dtors)) + KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .dtors)) + KEEP (*(SORT(.dtors.*))) + KEEP (*(.dtors)) +} +.jcr : { KEEP (*(.jcr)) } +.data.rel.ro : { *(.data.rel.ro.local* .gnu.linkonce.d.rel.ro.local.*) *(.data.rel.ro .data.rel.ro.* .gnu.linkonce.d.rel.ro.*) } +.dynamic : { *(.dynamic) } +. = DATA_SEGMENT_RELRO_END (0, .); +.data : +{ + *(.data .data.* .gnu.linkonce.d.*) + SORT(CONSTRUCTORS) +} +.data1 : { *(.data1) } +.got : { *(.got.plt) *(.igot.plt) *(.got) *(.igot) } +/* We want the small data sections together, so single-instruction offsets +can access them all, and initialized data all before uninitialized, so +we can shorten the on-disk segment size. */ +.sdata : +{ + __global_pointer$ = . + 0x800; + *(.srodata.cst16) *(.srodata.cst8) *(.srodata.cst4) *(.srodata.cst2) *(.srodata .srodata.*) + *(.sdata .sdata.* .gnu.linkonce.s.*) +} +_edata = .; PROVIDE (edata = .); +. = .; +__bss_start = .; +.sbss : +{ + *(.dynsbss) + *(.sbss .sbss.* .gnu.linkonce.sb.*) + *(.scommon) +} +.bss : +{ + *(.dynbss) + *(.bss .bss.* .gnu.linkonce.b.*) + *(COMMON) + PROVIDE(_bss_end = .); + /* Align here to ensure that the .bss section occupies space up to + _end. Align after .bss to ensure correct alignment even if the + .bss section disappears because there are no input sections. FIXME: Why do we need it? When there is no .bss section, we don't + pad the .data section. */ +. = ALIGN(. != 0 ? 32 / 8 : 1); +} +. = ALIGN(32 / 8); +. = SEGMENT_START("ldata-segment", .); +. = ALIGN(32 / 8); +_end = .; PROVIDE (end = .); +. = DATA_SEGMENT_END (.); +/* Stabs debugging sections. */ + .stab 0 : { *(.stab) } + .stabstr 0 : { *(.stabstr) } + .stab.excl 0 : { *(.stab.excl) } + .stab.exclstr 0 : { *(.stab.exclstr) } + .stab.index 0 : { *(.stab.index) } + .stab.indexstr 0 : { *(.stab.indexstr) } + .comment 0 : { *(.comment) } + /* DWARF debug sections. + Symbols in the DWARF debugging sections are relative to the beginning + of the section so we begin them at 0. */ + /* DWARF 1 */ + .debug 0 : { *(.debug) } + .line 0 : { *(.line) } + /* GNU DWARF 1 extensions */ + .debug_srcinfo 0 : { *(.debug_srcinfo) } + .debug_sfnames 0 : { *(.debug_sfnames) } + /* DWARF 1.1 and DWARF 2 */ + .debug_aranges 0 : { *(.debug_aranges) } + .debug_pubnames 0 : { *(.debug_pubnames) } + /* DWARF 2 */ + .debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) } + .debug_abbrev 0 : { *(.debug_abbrev) } + .debug_line 0 : { *(.debug_line .debug_line.* .debug_line_end ) } + .debug_frame 0 : { *(.debug_frame) } + .debug_str 0 : { *(.debug_str) } + .debug_loc 0 : { *(.debug_loc) } + .debug_macinfo 0 : { *(.debug_macinfo) } + /* SGI/MIPS DWARF 2 extensions */ + .debug_weaknames 0 : { *(.debug_weaknames) } + .debug_funcnames 0 : { *(.debug_funcnames) } + .debug_typenames 0 : { *(.debug_typenames) } + .debug_varnames 0 : { *(.debug_varnames) } + /* DWARF 3 */ + .debug_pubtypes 0 : { *(.debug_pubtypes) } + .debug_ranges 0 : { *(.debug_ranges) } + /* DWARF Extension. */ + .debug_macro 0 : { *(.debug_macro) } + .debug_addr 0 : { *(.debug_addr) } + .gnu.attributes 0 : { KEEP (*(.gnu.attributes)) } + /DISCARD/ : { *(.note.GNU-stack) *(.gnu_debuglink) *(.gnu.lto_*) } + PROVIDE(heap_begin = .); +} diff --git a/wuehans/wuehans_config.h b/wuehans/wuehans_config.h new file mode 100644 index 0000000..237a2d9 --- /dev/null +++ b/wuehans/wuehans_config.h @@ -0,0 +1,7 @@ +#ifndef WUEHANS_CONFIG_H +#define WUEHANS_CONFIG_H + +// Heap Size in Bytes +#define HEAP_SIZE 0x800000 + +#endif