3 Commits

Author SHA1 Message Date
8158d35065 Fix the scaling and add nonthreaded 2025-02-22 16:35:53 +01:00
274c99f98b Add non multithread mode 2025-02-22 16:15:05 +01:00
f184204be7 Windows update 2025-02-18 19:40:56 +01:00
6 changed files with 140 additions and 60 deletions

View File

@@ -20,8 +20,33 @@ message(STATUS "Target platform: ${TARGET_PLATFORM}")
# Detect build type and configure SDL2 paths accordingly # Detect build type and configure SDL2 paths accordingly
if (TARGET_PLATFORM STREQUAL "windows") if (TARGET_PLATFORM STREQUAL "windows")
include_directories(${SDL2_INCLUDE_DIR}) find_package(SDL2 REQUIRED)
find_package(SDL2_ttf REQUIRED)
include_directories(${SDL2_INCLUDE_DIRS})
link_directories(${SDL2_LIBRARY_DIRS})
add_definitions(${SDL2_CFLAGS_OTHER})
elseif (TARGET_PLATFORM STREQUAL "windows-static")
# Cross-compile static Windows build using MinGW
set(CMAKE_C_COMPILER x86_64-w64-mingw32-gcc)
set(CMAKE_RC_COMPILER x86_64-w64-mingw32-windres)
set(CMAKE_FIND_ROOT_PATH /usr/local/x86_64-w64-mingw32)
# Ensure static linking
set(CMAKE_EXE_LINKER_FLAGS "-static -static-libgcc -static-libstdc++ -mwindows")
include_directories(
/usr/local/x86_64-w64-mingw32/include
/usr/local/x86_64-w64-mingw32/include/SDL2
)
link_directories(
/usr/local/x86_64-w64-mingw32/lib
)
add_definitions(-DSDL_MAIN_HANDLED)
elseif (TARGET_PLATFORM STREQUAL "mingw") elseif (TARGET_PLATFORM STREQUAL "mingw")
# Cross-compile dynamically linked Windows build
set(CMAKE_C_COMPILER x86_64-w64-mingw32-gcc) set(CMAKE_C_COMPILER x86_64-w64-mingw32-gcc)
set(CMAKE_RC_COMPILER x86_64-w64-mingw32-windres) set(CMAKE_RC_COMPILER x86_64-w64-mingw32-windres)
find_package(SDL2 REQUIRED) find_package(SDL2 REQUIRED)
@@ -29,11 +54,13 @@ elseif (TARGET_PLATFORM STREQUAL "mingw")
include_directories(${SDL2_INCLUDE_DIRS}) include_directories(${SDL2_INCLUDE_DIRS})
link_directories(${SDL2_LIBRARY_DIRS}) link_directories(${SDL2_LIBRARY_DIRS})
add_definitions(${SDL2_CFLAGS_OTHER}) add_definitions(${SDL2_CFLAGS_OTHER})
elseif (TARGET_PLATFORM STREQUAL "linux") elseif (TARGET_PLATFORM STREQUAL "linux")
pkg_check_modules(SDL2 REQUIRED sdl2) pkg_check_modules(SDL2 REQUIRED sdl2)
pkg_check_modules(SDL2_TTF REQUIRED SDL2_ttf) pkg_check_modules(SDL2_TTF REQUIRED SDL2_ttf)
include_directories(${SDL2_INCLUDE_DIRS}) include_directories(${SDL2_INCLUDE_DIRS})
add_definitions(${SDL2_CFLAGS_OTHER}) add_definitions(${SDL2_CFLAGS_OTHER})
else () else ()
message(FATAL_ERROR "Unsupported TARGET_PLATFORM: ${TARGET_PLATFORM}") message(FATAL_ERROR "Unsupported TARGET_PLATFORM: ${TARGET_PLATFORM}")
endif () endif ()
@@ -60,14 +87,18 @@ set(SOURCE_FILES
# Build the target executable # Build the target executable
add_executable(RISCB ${SOURCE_FILES}) add_executable(RISCB ${SOURCE_FILES})
target_link_libraries(RISCB SDL2 SDL2_ttf m)
# Link libraries
if (TARGET_PLATFORM STREQUAL "windows-static")
target_link_libraries(RISCB mingw32 SDL2main SDL2 SDL2_ttf freetype -static)
else ()
target_link_libraries(RISCB SDL2 SDL2_ttf m)
endif ()
# Cross-compile Windows executable on Unix # Cross-compile Windows executable on Unix
if (UNIX AND TARGET_PLATFORM STREQUAL "mingw") if (UNIX AND TARGET_PLATFORM STREQUAL "windows-static")
add_executable(RISCB_WIN32 ${SOURCE_FILES}) add_executable(RISCB_WIN32 ${SOURCE_FILES})
set_target_properties(RISCB_WIN32 PROPERTIES COMPILE_FLAGS "-mwindows") set_target_properties(RISCB_WIN32 PROPERTIES COMPILE_FLAGS "-mwindows")
set(CMAKE_C_COMPILER x86_64-w64-mingw32-gcc)
set(CMAKE_RC_COMPILER x86_64-w64-mingw32-windres)
add_definitions(-DSDL_MAIN_HANDLED) add_definitions(-DSDL_MAIN_HANDLED)
target_link_libraries(RISCB_WIN32 mingw32 SDL2main SDL2 SDL2_ttf -static-libgcc -static-libstdc++) target_link_libraries(RISCB mingw32 /usr/local/x86_64-w64-mingw32/lib/libSDL2main.a /usr/local/x86_64-w64-mingw32/lib/libSDL2.a /usr/local/x86_64-w64-mingw32/lib/libSDL2_ttf.dll.a /usr/local/x86_64-w64-mingw32/lib/libfreetype.a /usr/local/x86_64-w64-mingw32/lib/libSDL2_test.a -static setupapi rpcrt4 imm32 oleaut32 version ole32 winmm )
endif () endif ()

View File

@@ -210,9 +210,9 @@ int resolveMOV(const char *dest, const char *src) {
} }
} }
int resolveALU(int baseOpcode, const char *src) { int resolveALU(int baseOpcode, const char *src, const char *dest) {
// baseOpcode is one of our special negative values for ADD, SUB, etc. // baseOpcode is one of our special negative values for ADD, SUB, etc.
if (src[0] == 'R' || src[0] == 'r') { if (dest[0] == 'R' || dest[0] == 'r') {
switch (baseOpcode) { switch (baseOpcode) {
case -3: case -3:
return ADD_RN_RM; return ADD_RN_RM;
@@ -230,6 +230,11 @@ int resolveALU(int baseOpcode, const char *src) {
return OR_RN_RM; return OR_RN_RM;
case -10: case -10:
return XOR_RN_RM; return XOR_RN_RM;
default:
return -1;
}
} else if (src[0] == 'r' || src[0] == 'R' && baseOpcode < -11) {
switch (baseOpcode) {
case -12: case -12:
return INC_RN; return INC_RN;
case -13: case -13:
@@ -467,7 +472,7 @@ uint32_t completePass(const char *source, CPU *cpu, bool erase) {
fprintf(stderr, "Error: %s requires one operand.\n", mnemonic); fprintf(stderr, "Error: %s requires one operand.\n", mnemonic);
return 1; return 1;
} }
int resolvedOpcode = resolveALU(baseOpcode, operand1); int resolvedOpcode = resolveALU(baseOpcode, operand1, operand2);
cpu->memory[addr++] = resolvedOpcode; cpu->memory[addr++] = resolvedOpcode;
if (operand1[0] == 'R' || operand1[0] == 'r') { if (operand1[0] == 'R' || operand1[0] == 'r') {
int reg = parseRegister(operand1); int reg = parseRegister(operand1);
@@ -491,7 +496,7 @@ uint32_t completePass(const char *source, CPU *cpu, bool erase) {
fprintf(stderr, "Error: %s requires two operands.\n", mnemonic); fprintf(stderr, "Error: %s requires two operands.\n", mnemonic);
return 1; return 1;
} }
int resolvedOpcode = resolveALU(baseOpcode, operand1); int resolvedOpcode = resolveALU(baseOpcode, operand1, operand2);
cpu->memory[addr++] = resolvedOpcode; cpu->memory[addr++] = resolvedOpcode;
int regDest = parseRegister(operand1); int regDest = parseRegister(operand1);
cpu->memory[addr++] = regDest; cpu->memory[addr++] = regDest;
@@ -509,7 +514,7 @@ uint32_t completePass(const char *source, CPU *cpu, bool erase) {
fprintf(stderr, "Error: JMP requires one operand.\n"); fprintf(stderr, "Error: JMP requires one operand.\n");
return 1; return 1;
} }
int resolvedOpcode = resolveALU(baseOpcode, operand1); int resolvedOpcode = resolveALU(baseOpcode, operand1, operand2);
cpu->memory[addr++] = resolvedOpcode; cpu->memory[addr++] = resolvedOpcode;
if (operand1[0] == '+' || operand1[0] == '-') { if (operand1[0] == '+' || operand1[0] == '-') {
// Relative jump: one-byte offset. // Relative jump: one-byte offset.
@@ -529,7 +534,7 @@ uint32_t completePass(const char *source, CPU *cpu, bool erase) {
fprintf(stderr, "Error: %s requires three operands.\n", mnemonic); fprintf(stderr, "Error: %s requires three operands.\n", mnemonic);
return 1; return 1;
} }
int resolvedOpcode = resolveALU(baseOpcode, operand1); int resolvedOpcode = resolveALU(baseOpcode, operand1, operand2);
cpu->memory[addr++] = resolvedOpcode; cpu->memory[addr++] = resolvedOpcode;
// Encode the source operand (register or memory). // Encode the source operand (register or memory).
if (operand1[0] == 'R' || operand1[0] == 'r') { if (operand1[0] == 'R' || operand1[0] == 'r') {

View File

@@ -70,7 +70,7 @@ int getOpcode(char *mnemonic);
// //
int resolveMOV(const char *dest, const char *src); int resolveMOV(const char *dest, const char *src);
int resolveALU(int baseOpcode, const char *src); int resolveALU(int baseOpcode, const char *src, const char *dest);
// //
// The first pass scans the assembly source file to record all labels and their addresses. // The first pass scans the assembly source file to record all labels and their addresses.

114
main.c
View File

@@ -28,6 +28,8 @@ SDL_Renderer *renderer = NULL;
#define smallFont fonts[1] #define smallFont fonts[1]
#define smallerFont fonts[2] #define smallerFont fonts[2]
//#define CPU_THREADED
#define fontCount 3 #define fontCount 3
BitmapFont fonts[fontCount]; BitmapFont fonts[fontCount];
@@ -49,8 +51,10 @@ TextEditor editors[editorCount];
unsigned long frames = 0; unsigned long frames = 0;
bool cursor = true; bool cursor = true;
#ifdef CPU_THREADED
pthread_t cpu_thread; pthread_t cpu_thread;
pthread_mutex_t cpu_mutex = PTHREAD_MUTEX_INITIALIZER; pthread_mutex_t cpu_mutex = PTHREAD_MUTEX_INITIALIZER;
#endif
void msleep(unsigned int milliseconds) { void msleep(unsigned int milliseconds) {
struct timespec ts; struct timespec ts;
@@ -59,32 +63,54 @@ void msleep(unsigned int milliseconds) {
nanosleep(&ts, NULL); nanosleep(&ts, NULL);
} }
void *cpu_loop(void *arg) { static uint64_t last_tick = 0;
uint64_t last_tick = SDL_GetTicks64();
while (running) {
pthread_mutex_lock(&cpu_mutex);
if (!(cpu.mode & (CPU_MODE_PAUSED | CPU_MODE_HALTED | CPU_MODE_ERROR))) { // This function executes one iteration of the CPU loop (non-blocking)
step(&cpu); void cpu_step(void) {
} else { if (last_tick == 0) {
pthread_mutex_unlock(&cpu_mutex); last_tick = SDL_GetTicks64();
msleep(10); }
}
if (cpu.mode & CPU_MODE_SECOND) { #ifdef CPU_THREADED
pthread_mutex_unlock(&cpu_mutex); pthread_mutex_lock(&cpu_mutex);
msleep(1000); #endif
continue;
} else if (cpu.mode & CPU_MODE_FRAME) { if (!(cpu.mode & (CPU_MODE_PAUSED | CPU_MODE_HALTED | CPU_MODE_ERROR))) {
uint64_t frame_duration = SDL_GetTicks64() - last_tick; step(&cpu);
if (frame_duration < delayNeeded) { } else {
pthread_mutex_unlock(&cpu_mutex); #ifdef CPU_THREADED
msleep(delayNeeded - frame_duration);
continue;
}
last_tick = SDL_GetTicks64();
}
pthread_mutex_unlock(&cpu_mutex); pthread_mutex_unlock(&cpu_mutex);
#endif
return;
}
if (cpu.mode & CPU_MODE_SECOND) {
#ifdef CPU_THREADED
pthread_mutex_unlock(&cpu_mutex);
#endif
msleep(1000);
return;
} else if (cpu.mode & CPU_MODE_FRAME) {
uint64_t frame_duration = SDL_GetTicks64() - last_tick;
if (frame_duration < delayNeeded) {
#ifdef CPU_THREADED
pthread_mutex_unlock(&cpu_mutex);
#endif
msleep(delayNeeded - frame_duration);
return;
}
last_tick = SDL_GetTicks64();
}
#ifdef CPU_THREADED
pthread_mutex_unlock(&cpu_mutex);
#endif
}
// Blocking loop for running as a thread
void *cpu_loop(void *arg) {
while (running) {
cpu_step();
} }
return NULL; return NULL;
} }
@@ -192,15 +218,15 @@ int init() {
SDL_PauseAudioDevice(dev, 0); SDL_PauseAudioDevice(dev, 0);
init_seven_segment(&displayA, renderer, 480, 240, 60, 120); init_seven_segment(&displayA, renderer, 477, 240, 60, 120);
init_seven_segment(&displayB, renderer, 545, 240, 60, 120); init_seven_segment(&displayB, renderer, 542, 240, 60, 120);
init_seven_segment(&displayC, renderer, 610, 240, 60, 120); init_seven_segment(&displayC, renderer, 607, 240, 60, 120);
init_seven_segment(&displayD, renderer, 675, 240, 60, 120); init_seven_segment(&displayD, renderer, 672, 240, 60, 120);
init_seven_segment(&displayE, renderer, 480, 375, 60, 120); init_seven_segment(&displayE, renderer, 477, 375, 60, 120);
init_seven_segment(&displayF, renderer, 545, 375, 60, 120); init_seven_segment(&displayF, renderer, 542, 375, 60, 120);
init_seven_segment(&displayG, renderer, 610, 375, 60, 120); init_seven_segment(&displayG, renderer, 607, 375, 60, 120);
init_seven_segment(&displayH, renderer, 675, 375, 60, 120); init_seven_segment(&displayH, renderer, 672, 375, 60, 120);
init_switches(&switchesA, renderer, 500, 500, 100, 100); init_switches(&switchesA, renderer, 500, 500, 100, 100);
init_switches(&switchesB, renderer, 625, 500, 100, 100); init_switches(&switchesB, renderer, 625, 500, 100, 100);
@@ -415,8 +441,6 @@ SDL_Keycode ConvertKPToNonKP(SDL_Keycode keycode) {
} }
} }
uint8_t cpuSpeedTemp = 0;
int processEvent(SDL_Event e) { int processEvent(SDL_Event e) {
if (e.type == SDL_QUIT) { return 0; } if (e.type == SDL_QUIT) { return 0; }
else if (e.type == SDL_WINDOWEVENT && e.window.event == SDL_WINDOWEVENT_RESIZED) { else if (e.type == SDL_WINDOWEVENT && e.window.event == SDL_WINDOWEVENT_RESIZED) {
@@ -620,10 +644,19 @@ int processEvent(SDL_Event e) {
} }
} }
} else if (e.type == SDL_MOUSEBUTTONDOWN) { } else if (e.type == SDL_MOUSEBUTTONDOWN) {
SDL_Rect viewport;
SDL_RenderGetViewport(renderer, &viewport);
SDL_Rect mouset;
mouset.w = 1;
mouset.h = 1;
SDL_GetMouseState(&mouset.x, &mouset.y);
// Translate mouse coordinates to viewport space
SDL_Rect mouse; SDL_Rect mouse;
mouse.w = 1; mouse.w = 1;
mouse.h = 1; mouse.h = 1;
SDL_GetMouseState(&mouse.x, &mouse.y); mouse.x = ((mouset.x - viewport.x) * SCREEN_WIDTH) / viewport.w;
mouse.y = (mouset.y - viewport.y) * SCREEN_HEIGHT / viewport.h;
toggle_switch(mouse, &switchesA); toggle_switch(mouse, &switchesA);
toggle_switch(mouse, &switchesB); toggle_switch(mouse, &switchesB);
toggle_switch(mouse, &switchesC); toggle_switch(mouse, &switchesC);
@@ -642,10 +675,18 @@ int main(__attribute__((unused)) int argc, __attribute__((unused)) char *args[])
SDL_Event e; SDL_Event e;
Uint64 start; Uint64 start;
Uint64 end; Uint64 end;
#ifdef CPU_THREADED
pthread_create(&cpu_thread, NULL, cpu_loop, NULL); pthread_create(&cpu_thread, NULL, cpu_loop, NULL);
#endif
while (running) { while (running) {
start = SDL_GetTicks64(); start = SDL_GetTicks64();
#ifndef CPU_THREADED
cpu_step();
#endif
#ifdef CPU_THREADED
pthread_mutex_lock(&cpu_mutex); pthread_mutex_lock(&cpu_mutex);
#endif
while (SDL_PollEvent(&e)) { while (SDL_PollEvent(&e)) {
running = processEvent(e); running = processEvent(e);
} }
@@ -671,7 +712,9 @@ int main(__attribute__((unused)) int argc, __attribute__((unused)) char *args[])
updateState(false); updateState(false);
} }
} }
#ifdef CPU_THREADED
pthread_mutex_unlock(&cpu_mutex); pthread_mutex_unlock(&cpu_mutex);
#endif
end = SDL_GetTicks64(); end = SDL_GetTicks64();
const unsigned long timeNeeded = end - start; const unsigned long timeNeeded = end - start;
if (timeNeeded < delayNeeded) { if (timeNeeded < delayNeeded) {
@@ -706,8 +749,9 @@ int main(__attribute__((unused)) int argc, __attribute__((unused)) char *args[])
destroy_seven_segment(&displayF); destroy_seven_segment(&displayF);
destroy_seven_segment(&displayG); destroy_seven_segment(&displayG);
destroy_seven_segment(&displayH); destroy_seven_segment(&displayH);
#ifdef CPU_THREADED
pthread_join(cpu_thread, NULL); pthread_join(cpu_thread, NULL);
#endif
if (renderer) SDL_DestroyRenderer(renderer); if (renderer) SDL_DestroyRenderer(renderer);
if (window) SDL_DestroyWindow(window); if (window) SDL_DestroyWindow(window);

View File

@@ -72,20 +72,20 @@ void init_switches(Switches *switches, SDL_Renderer *renderer, int x, int y, int
switches->rect->x = 0; switches->rect->x = 0;
switches->rect->y = 0; switches->rect->y = 0;
switches->rect->w = width; switches->rect->w = width + 2;
switches->rect->h = height; switches->rect->h = height + 2;
switches->outRect->x = x; switches->outRect->x = x;
switches->outRect->y = y; switches->outRect->y = y;
switches->outRect->w = width; switches->outRect->w = width + 2;
switches->outRect->h = height; switches->outRect->h = height + 2;
switches->texture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET, width, height); switches->texture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET, width + 2, height + 2);
if (!switches->texture) { if (!switches->texture) {
fprintf(stderr, "Failed to create texture: %s\n", SDL_GetError()); fprintf(stderr, "Failed to create texture: %s\n", SDL_GetError());
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
switches->value = (1 << 0) | (1 << 1); switches->value = 0;
generate_switch_rects(switches); generate_switch_rects(switches);
update_switches_texture(renderer, switches); update_switches_texture(renderer, switches);
} }

View File

@@ -77,7 +77,7 @@ void init_editor(TextEditor *editor, BitmapFont *font, int x, int y, SDL_Rendere
editor->highlightedLineRect->x = 2; editor->highlightedLineRect->x = 2;
editor->highlightedLineRect->y = 2; editor->highlightedLineRect->y = 2;
editor->highlightedLineRect->w = editor->outRect->w - (2 * editor->highlightedLineRect->x); editor->highlightedLineRect->w = editor->outRect->w - (2 * editor->highlightedLineRect->x);
editor->highlightedLineRect->h = editor->font->size; editor->highlightedLineRect->h = editor->font->size + 1;
editor->cursorRect->x = 3 + editor->cursor_pos * font->size + editor->outRect->x; editor->cursorRect->x = 3 + editor->cursor_pos * font->size + editor->outRect->x;
editor->cursorRect->y = editor->cursorRect->y =
@@ -333,16 +333,16 @@ void editor_render(TextEditor *editor, SDL_Renderer *renderer, CPU *cpu, uint8_t
if (editorIndex == 0) { if (editorIndex == 0) {
targetLine = cpu->addrToLineMapper[instrLine] - editor->cursor_line_offset; targetLine = cpu->addrToLineMapper[instrLine] - editor->cursor_line_offset;
editor->highlightedLineRect->w = editor->rect->w - 1; editor->highlightedLineRect->w = editor->rect->w - 1;
editor->highlightedLineRect->x = 2; editor->highlightedLineRect->x = 0;
} }
if (editorIndex == 1) { if (editorIndex == 1) {
targetLine = (instrLine / 2) - editor->cursor_line_offset; targetLine = (instrLine / 2) - editor->cursor_line_offset;
editor->highlightedLineRect->w = (editor->rect->w / 5 * 2) - 2; editor->highlightedLineRect->w = (editor->rect->w / 5 * 2) - 8;
editor->highlightedLineRect->x = editor->highlightedLineRect->x =
2 + (11 * editor->font->size) + (instrLine % 2 ? (28 * editor->font->size) : 0); 4 + (11 * editor->font->size) + (instrLine % 2 ? (28 * editor->font->size) : 0);
} }
editor->highlightedLineRect->y = 2 + ((editor->font->size + 1) * targetLine); editor->highlightedLineRect->y = 1 + ((editor->font->size + 1) * targetLine);
SDL_Rect highlightedLineAbs = *editor->highlightedLineRect; SDL_Rect highlightedLineAbs = *editor->highlightedLineRect;
highlightedLineAbs.x += editor->outRect->x; highlightedLineAbs.x += editor->outRect->x;
highlightedLineAbs.y += editor->outRect->y; highlightedLineAbs.y += editor->outRect->y;