load custom .g1a, add file system + many syscalls
This commit is contained in:
parent
553e0e6745
commit
daa10b58e8
23
README.md
23
README.md
|
@ -1,7 +1,6 @@
|
|||
# Casio fx-9860 SH4 emulator
|
||||
|
||||
This is a work-in-progress emulator for the Casio fx-9860 SH4 models
|
||||
It will display the content of the VRAM in the console at the end of the execution.
|
||||
|
||||
Broswser demo : https://sh4.vercel.app/
|
||||
|
||||
|
@ -12,29 +11,37 @@ All non-DSP instructions are implemented, except the following ones:
|
|||
|
||||
fx9860-emulator/ contains the source for the emulator
|
||||
|
||||
scripts/ contains the code for auto-generating the instructions code from the doc
|
||||
scripts/ contains the code for auto-generating the instructions set from the doc
|
||||
|
||||
### Browser version
|
||||
To build the browser version of the emulator, make sure you have emscripten downloaded and installed: https://emscripten.org/docs/getting_started/downloads.html
|
||||
|
||||
First, make sur `#define EMSCRIPT` is enabled in main.h (not as a comment).
|
||||
First, make sure `#define USE_EMSCRIPT` is enabled in main.h (not as a comment).
|
||||
Then:
|
||||
|
||||
cd fx9860-emulator
|
||||
mkdir build
|
||||
cd build
|
||||
emcmake make ..
|
||||
emcmake cmake ..
|
||||
emmake make
|
||||
|
||||
Then, until I find a nicer way to integrate this into the Makefile, run the following command:
|
||||
|
||||
emcc -O2 .\CMakeFiles\fx9860-emulator.dir\main.o .\CMakeFiles\fx9860-emulator.dir\utils.o .\CMakeFiles\fx9860-emulator.dir\memory.o .\CMakeFiles\fx9860-emulator.dir\instructions\instructions.o .\CMakeFiles\fx9860-emulator.dir\instructions\syscalls.o --embed-file ..\..\U+0020.png@U+0020.png --embed-file ..\..\PrintMini.bmp@PrintMini.bmp --embed-file ..\..\JJSH3.G1A@JJSH3.G1A -sASYNCIFY -sEXIT_RUNTIME -o index.js -sDEFAULT_LIBRARY_FUNCS_TO_INCLUDE='$getBoundingClientRect' -sEXPORTED_RUNTIME_METHODS='writeArrayToMemory, setValue, getValue'
|
||||
emcc -O2 ".\CMakeFiles\fx9860-emulator.dir\main.o" ".\CMakeFiles\fx9860-emulator.dir\utils.o" ".\CMakeFiles\fx9860-emulator.dir\memory.o" ".\CMakeFiles\fx9860-emulator.dir\instructions\instructions.o" ".\CMakeFiles\fx9860-emulator.dir\syscalls\syscalls.o" ".\CMakeFiles\fx9860-emulator.dir\syscalls\filesystem.o" ".\CMakeFiles\fx9860-emulator.dir\syscalls\malloc.o" ".\CMakeFiles\fx9860-emulator.dir\syscalls\misc.o" ".\CMakeFiles\fx9860-emulator.dir\syscalls\print.o" \
|
||||
--embed-file "..\..\U+0020.png@U+0020.png" \
|
||||
--embed-file "..\..\PrintMini.bmp@PrintMini.bmp" \
|
||||
--embed-file "..\..\JJSH3.G1A@JJSH3.G1A" \
|
||||
-sEXPORTED_FUNCTIONS="_main,_get_next_instruction,_reset_execution,_load_new_g1a" \
|
||||
-sASYNCIFY -sEXIT_RUNTIME -o index.js \
|
||||
-sDEFAULT_LIBRARY_FUNCS_TO_INCLUDE='$getBoundingClientRect' \
|
||||
-sEXPORTED_RUNTIME_METHODS='writeArrayToMemory, setValue, getValue'
|
||||
|
||||
After that you can server the content of the build/ folder through a local server and open index.html
|
||||
After that you can serve the content of the build/ folder through a local server and open index.html
|
||||
|
||||
### Console version
|
||||
To build the console version of the emulator (no display, only VRAM dump after 10M executions):
|
||||
To build the console version of the emulator (no display, only VRAM dump after 10M iterations):
|
||||
|
||||
First, remove (comment) `#define EMSCRIPT` in main.h
|
||||
First, remove (comment) `#define USE_EMSCRIPT` in main.h
|
||||
|
||||
cd fx9860-emulator
|
||||
mkdir build
|
||||
|
|
|
@ -1,12 +1,27 @@
|
|||
# CMakeList.txt : CMake project for fx9860-emulator, include source and define
|
||||
# project specific logic here.
|
||||
#
|
||||
|
||||
# Add source to this project's executable.
|
||||
add_executable (fx9860-emulator "main.c" "headers/main.h" "headers/instructions/instructions.h" "instructions/instructions.c" "headers/utils.h" "utils.c" "memory.c" "headers/memory.h" "instructions/syscalls.c" "headers/instructions/syscalls.h" "headers/stb_image.h" "headers/display.h" )
|
||||
# Add source to this project's executable.
|
||||
add_executable (fx9860-emulator
|
||||
"main.c"
|
||||
"headers/main.h"
|
||||
"headers/instructions/instructions.h"
|
||||
"instructions/instructions.c"
|
||||
"headers/utils.h"
|
||||
"utils.c"
|
||||
"memory.c"
|
||||
"headers/memory.h"
|
||||
"syscalls/syscalls.c"
|
||||
"syscalls/filesystem.c"
|
||||
"syscalls/malloc.c"
|
||||
"syscalls/misc.c"
|
||||
"syscalls/print.c"
|
||||
"headers/syscalls/syscalls.h"
|
||||
"headers/syscalls/filesystem.h"
|
||||
"headers/syscalls/malloc.h"
|
||||
"headers/syscalls/misc.h"
|
||||
"headers/syscalls/print.h"
|
||||
"headers/stb_image.h"
|
||||
"headers/display.h"
|
||||
)
|
||||
|
||||
if (CMAKE_VERSION VERSION_GREATER 3.12)
|
||||
set_property(TARGET fx9860-emulator PROPERTY CXX_STANDARD 20)
|
||||
endif()
|
||||
|
||||
# TODO: Add tests and install targets if needed.
|
||||
endif()
|
|
@ -14,14 +14,6 @@
|
|||
#define LCD_SELECT_REGISTER 0xB4000000
|
||||
#define LCD_DATA_REGISTER 0xB4010000
|
||||
|
||||
// Size of characters in ASCII texture
|
||||
#define ASCII_CHAR_WIDTH 7
|
||||
#define ASCII_CHAR_HEIGHT 9
|
||||
|
||||
// Size of characters on screen
|
||||
#define CHAR_WIDTH 6
|
||||
#define CHAR_HEIGHT 8
|
||||
|
||||
// https://bible.planet-casio.com/simlo/chm/v20/fx_legacy_Cursor.HTM
|
||||
typedef struct {
|
||||
int col; // starts at 1
|
||||
|
@ -33,7 +25,6 @@ struct display_t {
|
|||
uint8_t vram[VRAM_SIZE];
|
||||
|
||||
// LCD screen emulation
|
||||
uint8_t lcd[VRAM_SIZE];
|
||||
uint8_t lcd_registers; // Use for both selector & data registers
|
||||
|
||||
// Current cursor position
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
#include "../main.h"
|
||||
|
||||
void (*get_instruction_impl(uint16_t instruction))(cpu_t*, uint16_t);
|
||||
const char* get_instruction_name(uint16_t instruction);
|
||||
|
||||
#define R0 cpu->r[0]
|
||||
|
||||
|
@ -162,5 +163,4 @@ void XORM(cpu_t* cpu, uint16_t instruction);
|
|||
void XTRCT(cpu_t* cpu, uint16_t instruction);
|
||||
void BSR(cpu_t* cpu, uint16_t instruction);
|
||||
void BSRF(cpu_t* cpu, uint16_t instruction);
|
||||
void JSR(cpu_t* cpu, uint16_t instruction);
|
||||
|
||||
void JSR(cpu_t* cpu, uint16_t instruction);
|
|
@ -1,25 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include "../main.h"
|
||||
|
||||
void run_syscall(cpu_t* cpu);
|
||||
|
||||
void syscall_GetVRAMAddress(cpu_t* cpu);
|
||||
void syscall_Bdisp_AllClr_DD(cpu_t* cpu);
|
||||
void syscall_Bdisp_AllClr_VRAM(cpu_t* cpu);
|
||||
void syscall_Bdisp_AllClr_DDVRAM(cpu_t* cpu);
|
||||
|
||||
void syscall_GetKey(cpu_t* cpu, unsigned int keycode_address);
|
||||
|
||||
void syscall_Locate(cpu_t* cpu, int x, int y);
|
||||
void syscall_Print(cpu_t* cpu, const unsigned char* str);
|
||||
void syscall_PrintXY(cpu_t* cpu, int x, int y, const unsigned char* str, int mode);
|
||||
void syscall_PrintMiniSd(cpu_t* cpu, int x, int y, const unsigned char* str, int mode);
|
||||
|
||||
void syscall_GetAppName(cpu_t* cpu, char* dest);
|
||||
void syscall_GlibGetAddinLibInf(cpu_t* cpu, uint32_t a_ptr, uint32_t b_ptr, uint32_t c_ptr);
|
||||
void syscall_GlibGetOSVersionInfo(cpu_t* cpu, uint32_t a_ptr, uint32_t b_ptr, uint32_t c_ptr, uint32_t d_ptr);
|
||||
void syscall_Malloc(cpu_t* cpu, uint32_t size, uint8_t clear_data);
|
||||
|
||||
void syscall_Bfile_OpenFile_OS(cpu_t* cpu, const char* filename, int mode, int mode2);
|
||||
void syscall_Bfile_CreateEntry_OS(cpu_t* cpu, const char* filename, int mode, int size_ptr);
|
|
@ -4,6 +4,8 @@
|
|||
typedef struct memory_t memory_t;
|
||||
typedef struct cpu_t cpu_t;
|
||||
typedef struct display_t display_t;
|
||||
typedef struct fs_t fs_t;
|
||||
typedef struct malloc_manager_t malloc_manager_t;
|
||||
|
||||
#define USE_EMSCRIPT
|
||||
|
||||
|
@ -19,7 +21,7 @@ typedef struct display_t display_t;
|
|||
#include "display.h"
|
||||
#include "utils.h"
|
||||
#include "instructions/instructions.h"
|
||||
#include "instructions/syscalls.h"
|
||||
#include "syscalls/syscalls.h"
|
||||
|
||||
// Initialization
|
||||
#define PC_PROGRAM_START 0x00300200 // Execution starting address
|
||||
|
@ -34,30 +36,36 @@ struct cpu_t {
|
|||
int32_t r[16];
|
||||
|
||||
// Control registers
|
||||
uint32_t gbr; // Global base register
|
||||
uint32_t sr; // Status register
|
||||
uint32_t ssr; // Saved status register
|
||||
uint32_t spc; // Saved program counter
|
||||
uint32_t vbr; // Vector base register
|
||||
uint32_t sgr; // Saved general register
|
||||
uint32_t dbr; // Debug base register
|
||||
uint32_t gbr; // Global base register
|
||||
uint32_t sr; // Status register
|
||||
uint32_t ssr; // Saved status register
|
||||
uint32_t spc; // Saved program counter
|
||||
uint32_t vbr; // Vector base register
|
||||
uint32_t sgr; // Saved general register
|
||||
uint32_t dbr; // Debug base register
|
||||
|
||||
// System registers
|
||||
uint32_t pc; // Program counter
|
||||
uint32_t pr; // Procedure register
|
||||
uint32_t mach; // Multiply-accumulate high
|
||||
uint32_t macl; // Multiply-accumulate low
|
||||
|
||||
// Custom variables
|
||||
uint8_t isExecutionFinished; // Set to true when PR == PC_PROGRAM_START
|
||||
uint32_t pc; // Program counter
|
||||
uint32_t pr; // Procedure register
|
||||
uint32_t mach; // Multiply-accumulate high
|
||||
uint32_t macl; // Multiply-accumulate low
|
||||
|
||||
// Debug
|
||||
uint32_t instruction_count;
|
||||
uint32_t instruction_per_frame;
|
||||
uint32_t instruction_count; // Number of instructions executed
|
||||
uint32_t instruction_per_frame; // Number of instructions to execute each frame
|
||||
uint32_t execution_paused; // Whether the execution is paused
|
||||
uint32_t execution_finished; // Whether the program has reached the end
|
||||
uint32_t execute_one_step; // Whether to execute only one step
|
||||
uint32_t next_breakpoint; // The execution will pause when reaching this address
|
||||
|
||||
// External Components
|
||||
memory_t* mem; // Memory
|
||||
display_t* disp; // Display
|
||||
memory_t* mem; // Memory
|
||||
display_t* disp; // Display
|
||||
|
||||
fs_t* fs; // Custom file system
|
||||
malloc_manager_t* malloc_manager; // malloc/realloc/free manager
|
||||
|
||||
int32_t RTC_Ticks; // 1/128 second ticks (updated from javascript)
|
||||
|
||||
// (Temporary) Character sets
|
||||
uint8_t* asciiTexture;
|
||||
|
|
|
@ -41,9 +41,9 @@ struct memory_t {
|
|||
uint8_t keyboard[10]; // Keyboard rows state
|
||||
uint8_t keyboard_registers[KB_SIZE]; // Keyboard registers
|
||||
|
||||
uint32_t* tmp;
|
||||
uint8_t* tmp;
|
||||
|
||||
// uint8_t xram[XRAM_SIZE];
|
||||
// uint8_t xram[XRAM_SIZE]; // TODO: add (gint support)
|
||||
// uint8_t yram[YRAM_SIZE];
|
||||
// uint8_t ilram[ILRAM_SIZE];
|
||||
|
||||
|
|
|
@ -0,0 +1,30 @@
|
|||
#pragma once
|
||||
|
||||
#include "syscalls.h"
|
||||
|
||||
typedef struct {
|
||||
char name[40];
|
||||
FILE* file_handle;
|
||||
int32_t handle;
|
||||
int32_t seek_pos;
|
||||
int32_t size;
|
||||
} file_t;
|
||||
|
||||
struct fs_t {
|
||||
file_t files[4]; // Only 4 files can be opened at the same time on real hardware
|
||||
uint8_t open_files_count;
|
||||
};
|
||||
|
||||
void syscall_Bfile_CreateEntry(cpu_t* cpu, uint32_t filename_ptr, int mode, uint32_t size_ptr);
|
||||
void syscall_Bfile_DeleteEntry(cpu_t* cpu, uint32_t filename_ptr, int mode);
|
||||
void syscall_Bfile_OpenFile(cpu_t* cpu, uint32_t filename_ptr, int mode, int mode2);
|
||||
void syscall_Bfile_CloseFile(cpu_t* cpu, int handle);
|
||||
void syscall_Bfile_WriteFile(cpu_t* cpu, int handle, uint32_t buf_ptr, int size);
|
||||
void syscall_Bfile_ReadFile(cpu_t* cpu, int handle, uint32_t buf_ptr, int size, int readpos);
|
||||
void syscall_Bfile_SeekFile(cpu_t* cpu, int handle, int pos);
|
||||
|
||||
// Not implemented
|
||||
void syscall_MCSGetDlen2(cpu_t* cpu, int32_t dir_ptr, int32_t item_ptr, int32_t len_ptr);
|
||||
void syscall_MCSGetData1(cpu_t* cpu, int32_t offset, int32_t len_to_copy, int32_t buffer_ptr);
|
||||
void syscall_MCSPutVar2(cpu_t* cpu, int32_t dir_ptr, int32_t item_ptr, int32_t data_len, int32_t buffer_ptr);
|
||||
void syscall_MCSOvwDat2(cpu_t* cpu, int32_t dir_ptr, int32_t item_ptr, int32_t bytes_to_write, int32_t buffer_ptr, int32_t write_offset);
|
|
@ -0,0 +1,17 @@
|
|||
#pragma once
|
||||
|
||||
#include "syscalls.h"
|
||||
|
||||
#define MALLOC_START 0x22220000
|
||||
#define MALLOC_SIZE (128 * 1024)
|
||||
|
||||
// Ugly malloc manager that works for testing
|
||||
struct malloc_manager_t {
|
||||
uint8_t* mallocs;
|
||||
uint32_t mallocCount;
|
||||
uint32_t currentSize;
|
||||
};
|
||||
|
||||
void syscall_Malloc(cpu_t* cpu, uint32_t size, uint8_t clear_data);
|
||||
void syscall_Realloc(cpu_t* cpu, uint32_t ptr, uint32_t size);
|
||||
void syscall_Free(cpu_t* cpu, uint32_t ptr);
|
|
@ -0,0 +1,12 @@
|
|||
#pragma once
|
||||
|
||||
#include "syscalls.h"
|
||||
|
||||
void syscall_GetVRAMAddress(cpu_t* cpu);
|
||||
void syscall_GetAppName(cpu_t* cpu, uint32_t dest_ptr);
|
||||
void syscall_GlibGetAddinLibInf(cpu_t* cpu, uint32_t a_ptr, uint32_t b_ptr, uint32_t c_ptr);
|
||||
void syscall_GlibGetOSVersionInfo(cpu_t* cpu, uint32_t a_ptr, uint32_t b_ptr, uint32_t c_ptr, uint32_t d_ptr);
|
||||
|
||||
void syscall_RTC_GetTicks(cpu_t* cpu);
|
||||
void syscall_OS_inner_Sleep(cpu_t* cpu, uint32_t ms);
|
||||
void syscall_GetKey(cpu_t* cpu, unsigned int keycode_address);
|
|
@ -0,0 +1,22 @@
|
|||
#pragma once
|
||||
|
||||
#include "syscalls.h"
|
||||
|
||||
// Size of characters in ASCII texture
|
||||
#define ASCII_CHAR_WIDTH 7
|
||||
#define ASCII_CHAR_HEIGHT 9
|
||||
|
||||
// Size of characters on screen
|
||||
#define CHAR_WIDTH 6
|
||||
#define CHAR_HEIGHT 8
|
||||
|
||||
void syscall_Bdisp_AllClr_DD(cpu_t* cpu);
|
||||
void syscall_Bdisp_AllClr_VRAM(cpu_t* cpu);
|
||||
void syscall_Bdisp_AllClr_DDVRAM(cpu_t* cpu);
|
||||
void syscall_Bdisp_PutDisp_DD(cpu_t* cpu);
|
||||
void syscall_Bdisp_SetPoint_VRAM(cpu_t* cpu, uint32_t x, uint32_t y, uint32_t point);
|
||||
|
||||
void syscall_Locate(cpu_t* cpu, int x, int y);
|
||||
void syscall_Print(cpu_t* cpu, uint32_t str_ptr);
|
||||
void syscall_PrintXY(cpu_t* cpu, int x, int y, uint32_t str_ptr, int mode);
|
||||
void syscall_PrintMiniSd(cpu_t* cpu, int x, int y, uint32_t str_ptr, int mode);
|
|
@ -0,0 +1,9 @@
|
|||
#pragma once
|
||||
|
||||
#include "../main.h"
|
||||
#include "filesystem.h"
|
||||
#include "print.h"
|
||||
#include "malloc.h"
|
||||
#include "misc.h"
|
||||
|
||||
void run_syscall(cpu_t* cpu);
|
|
@ -14,4 +14,5 @@ void print_binary(uint32_t x, int n);
|
|||
uint8_t* load_character_set(const char* path);
|
||||
|
||||
void cpu_debug(cpu_t* cpu);
|
||||
void vram_debug(cpu_t* cpu);
|
||||
void vram_debug(cpu_t* cpu);
|
||||
char* get_next_instruction(cpu_t* cpu);
|
|
@ -181,53 +181,205 @@ void (*get_instruction_impl(uint16_t instruction))(cpu_t*, uint16_t) {
|
|||
|
||||
print_binary(instruction, 16);
|
||||
critical_error(" => Unknown instruction: 0x%04X\n", instruction);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// #include <stdint.h>
|
||||
const char* get_instruction_name(uint16_t instruction) {
|
||||
uint8_t high = (instruction >> 12) & 0x0F;
|
||||
uint8_t high8 = instruction >> 8;
|
||||
uint8_t low = instruction & 0x0F;
|
||||
uint8_t low8 = instruction & 0xFF;
|
||||
|
||||
// typedef struct cpu_t cpu_t;
|
||||
if (instruction == 0b0000000000101000) return "CLRMAC";
|
||||
if (instruction == 0b0000000001001000) return "CLRS";
|
||||
if (instruction == 0b0000000000001000) return "CLRT";
|
||||
if (instruction == 0b0000000000011001) return "DIV0U";
|
||||
if (instruction == 0b0000000000001001) return "NOP";
|
||||
if (instruction == 0b0000000000101011) return "RTE";
|
||||
if (instruction == 0b0000000000001011) return "RTS";
|
||||
if (instruction == 0b0000000001011000) return "SETS";
|
||||
if (instruction == 0b0000000000011000) return "SETT";
|
||||
if (high8 == 0b11001001) return "ANDI";
|
||||
if (high8 == 0b11001101) return "ANDM";
|
||||
if (high8 == 0b10001011) return "BF";
|
||||
if (high8 == 0b10001111) return "BFS";
|
||||
if (high8 == 0b10001001) return "BT";
|
||||
if (high8 == 0b10001101) return "BTS";
|
||||
if (high8 == 0b10001000) return "CMPIM";
|
||||
if (high8 == 0b11000100) return "MOVBLG";
|
||||
if (high8 == 0b11000101) return "MOVWLG";
|
||||
if (high8 == 0b11000110) return "MOVLLG";
|
||||
if (high8 == 0b11000000) return "MOVBSG";
|
||||
if (high8 == 0b11000001) return "MOVWSG";
|
||||
if (high8 == 0b11000010) return "MOVLSG";
|
||||
if (high8 == 0b10000000) return "MOVBS4";
|
||||
if (high8 == 0b10000001) return "MOVWS4";
|
||||
if (high8 == 0b10000100) return "MOVBL4";
|
||||
if (high8 == 0b10000101) return "MOVWL4";
|
||||
if (high8 == 0b11000111) return "MOVA";
|
||||
if (high8 == 0b11001011) return "ORI";
|
||||
if (high8 == 0b11001111) return "ORM";
|
||||
if (high8 == 0b11001000) return "TSTI";
|
||||
if (high8 == 0b11001100) return "TSTM";
|
||||
if (high8 == 0b11001010) return "XORI";
|
||||
if (high8 == 0b11001110) return "XORM";
|
||||
if (high == 0b0111) return "ADDI";
|
||||
if (high == 0b1010) return "BRA";
|
||||
if (high == 0b1110) return "MOVI";
|
||||
if (high == 0b1001) return "MOVWI";
|
||||
if (high == 0b1101) return "MOVLI";
|
||||
if (high == 0b0001) return "MOVLS4";
|
||||
if (high == 0b0101) return "MOVLL4";
|
||||
if (high == 0b1011) return "BSR";
|
||||
if (high == 0b0100) {
|
||||
if (low8 == 0b00010101) return "CMPPL";
|
||||
if (low8 == 0b00010001) return "CMPPZ";
|
||||
if (low8 == 0b00010000) return "DT";
|
||||
if (low8 == 0b00101011) return "JMP";
|
||||
if (low8 == 0b00011110) return "LDCGBR";
|
||||
if (low8 == 0b00101110) return "LDCVBR";
|
||||
if (low8 == 0b00111010) return "LDCSGR";
|
||||
if (low8 == 0b00111110) return "LDCSSR";
|
||||
if (low8 == 0b01001110) return "LDCSPC";
|
||||
if (low8 == 0b11111010) return "LDCDBR";
|
||||
if (low8 == 0b00010111) return "LDCMGBR";
|
||||
if (low8 == 0b00100111) return "LDCMVBR";
|
||||
if (low8 == 0b00110110) return "LDCMSGR";
|
||||
if (low8 == 0b00110111) return "LDCMSSR";
|
||||
if (low8 == 0b01000111) return "LDCMSPC";
|
||||
if (low8 == 0b11110110) return "LDCMDBR";
|
||||
if (low8 == 0b00001010) return "LDSMACH";
|
||||
if (low8 == 0b00011010) return "LDSMACL";
|
||||
if (low8 == 0b00101010) return "LDSPR";
|
||||
if (low8 == 0b00000110) return "LDSMMACH";
|
||||
if (low8 == 0b00010110) return "LDSMMACL";
|
||||
if (low8 == 0b00100110) return "LDSMPR";
|
||||
if (low8 == 0b00100100) return "ROTCL";
|
||||
if (low8 == 0b00100101) return "ROTCR";
|
||||
if (low8 == 0b00000100) return "ROTL";
|
||||
if (low8 == 0b00000101) return "ROTR";
|
||||
if (low8 == 0b00100000) return "SHAL";
|
||||
if (low8 == 0b00100001) return "SHAR";
|
||||
if (low8 == 0b00000000) return "SHLL";
|
||||
if (low8 == 0b00001000) return "SHLL2";
|
||||
if (low8 == 0b00011000) return "SHLL8";
|
||||
if (low8 == 0b00101000) return "SHLL16";
|
||||
if (low8 == 0b00000001) return "SHLR";
|
||||
if (low8 == 0b00001001) return "SHLR2";
|
||||
if (low8 == 0b00011001) return "SHLR8";
|
||||
if (low8 == 0b00101001) return "SHLR16";
|
||||
if (low8 == 0b00010011) return "STCMGBR";
|
||||
if (low8 == 0b00100011) return "STCMVBR";
|
||||
if (low8 == 0b00110011) return "STCMSSR";
|
||||
if (low8 == 0b01000011) return "STCMSPC";
|
||||
if (low8 == 0b00110010) return "STCMSGR";
|
||||
if (low8 == 0b11110010) return "STCMDBR";
|
||||
if (low8 == 0b00000010) return "STSMMACH";
|
||||
if (low8 == 0b00010010) return "STSMMACL";
|
||||
if (low8 == 0b00100010) return "STSMPR";
|
||||
if (low8 == 0b00011011) return "TAS";
|
||||
if (low8 == 0b00001011) return "JSR";
|
||||
}
|
||||
if (high == 0b0000) {
|
||||
if (low8 == 0b00100011) return "BRAF";
|
||||
if (low8 == 0b00101001) return "MOVT";
|
||||
if (low8 == 0b10000011) return "PREF";
|
||||
if (low8 == 0b00010010) return "STCGBR";
|
||||
if (low8 == 0b00100010) return "STCVBR";
|
||||
if (low8 == 0b00110010) return "STCSSR";
|
||||
if (low8 == 0b01000010) return "STCSPC";
|
||||
if (low8 == 0b00111010) return "STCSGR";
|
||||
if (low8 == 0b11111010) return "STCDBR";
|
||||
if (low8 == 0b00001010) return "STSMACH";
|
||||
if (low8 == 0b00011010) return "STSMACL";
|
||||
if (low8 == 0b00101010) return "STSPR";
|
||||
if (low8 == 0b00000011) return "BSRF";
|
||||
}
|
||||
if (high == 0b0110) {
|
||||
if (low == 0b1110) return "EXTSB";
|
||||
if (low == 0b1111) return "EXTSW";
|
||||
if (low == 0b1100) return "EXTUB";
|
||||
if (low == 0b1101) return "EXTUW";
|
||||
if (low == 0b0011) return "MOV";
|
||||
if (low == 0b0000) return "MOVBL";
|
||||
if (low == 0b0001) return "MOVWL";
|
||||
if (low == 0b0010) return "MOVLL";
|
||||
if (low == 0b0100) return "MOVBP";
|
||||
if (low == 0b0101) return "MOVWP";
|
||||
if (low == 0b0110) return "MOVLP";
|
||||
if (low == 0b1011) return "NEG";
|
||||
if (low == 0b1010) return "NEGC";
|
||||
if (low == 0b0111) return "NOT";
|
||||
if (low == 0b1000) return "SWAPB";
|
||||
if (low == 0b1001) return "SWAPW";
|
||||
}
|
||||
if (high == 0b0010) {
|
||||
if (low == 0b1001) return "AND";
|
||||
if (low == 0b1100) return "CMPSTR";
|
||||
if (low == 0b0111) return "DIV0S";
|
||||
if (low == 0b0000) return "MOVBS";
|
||||
if (low == 0b0001) return "MOVWS";
|
||||
if (low == 0b0010) return "MOVLS";
|
||||
if (low == 0b0100) return "MOVBM";
|
||||
if (low == 0b0101) return "MOVWM";
|
||||
if (low == 0b0110) return "MOVLM";
|
||||
if (low == 0b1111) return "MULS";
|
||||
if (low == 0b1110) return "MULU";
|
||||
if (low == 0b1011) return "OR";
|
||||
if (low == 0b1000) return "TST";
|
||||
if (low == 0b1010) return "XOR";
|
||||
if (low == 0b1101) return "XTRCT";
|
||||
}
|
||||
if (high == 0b0011) {
|
||||
if (low == 0b1100) return "ADD";
|
||||
if (low == 0b1110) return "ADDC";
|
||||
if (low == 0b1111) return "ADDV";
|
||||
if (low == 0b0000) return "CMPEQ";
|
||||
if (low == 0b0011) return "CMPGE";
|
||||
if (low == 0b0111) return "CMPGT";
|
||||
if (low == 0b0110) return "CMPHI";
|
||||
if (low == 0b0010) return "CMPHS";
|
||||
if (low == 0b0100) return "DIV1";
|
||||
if (low == 0b1101) return "DMULS";
|
||||
if (low == 0b0101) return "DMULU";
|
||||
if (low == 0b1000) return "SUB";
|
||||
if (low == 0b1010) return "SUBC";
|
||||
if (low == 0b1011) return "SUBV";
|
||||
}
|
||||
if (high == 0b0000) {
|
||||
if (low == 0b1111) return "MACL_";
|
||||
if (low == 0b0100) return "MOVBS0";
|
||||
if (low == 0b0101) return "MOVWS0";
|
||||
if (low == 0b0110) return "MOVLS0";
|
||||
if (low == 0b1100) return "MOVBL0";
|
||||
if (low == 0b1101) return "MOVWL0";
|
||||
if (low == 0b1110) return "MOVLL0";
|
||||
if (low == 0b0111) return "MULL";
|
||||
}
|
||||
if (high == 0b0100) {
|
||||
if (low == 0b1111) return "MACW";
|
||||
if (low == 0b1100) return "SHAD";
|
||||
if (low == 0b1101) return "SHLD";
|
||||
}
|
||||
|
||||
// struct cpu_t {
|
||||
// // General registers R0 - R15
|
||||
// int32_t r[16];
|
||||
|
||||
// // Control registers
|
||||
// uint32_t gbr; // Global base register
|
||||
// uint32_t sr; // Status register (0: T Bit)
|
||||
|
||||
// // System registers
|
||||
// uint32_t pc; // Program counter
|
||||
// uint32_t pr; // Procedure register
|
||||
// uint32_t mach; // Multiply-accumulate high
|
||||
// uint32_t macl; // Multiply-accumulate low
|
||||
|
||||
// // To sort
|
||||
// uint32_t vbr; // Vector base register
|
||||
// uint32_t ssr; // Saved status register
|
||||
// uint32_t sgr; // Saved general register
|
||||
// uint32_t spc; // Saved program counter
|
||||
// uint32_t dbr; // Debug base register
|
||||
|
||||
// // Custom variables
|
||||
// uint8_t isExecutionFinished; // Set to true when PR == PC_PROGRAM_START
|
||||
|
||||
// // Debug
|
||||
// uint32_t instruction_count;
|
||||
// uint8_t* asciiTexture;
|
||||
|
||||
// // External Components
|
||||
// //memory_t* mem; // Memory
|
||||
// //display_t* disp; // Display
|
||||
// };
|
||||
print_binary(instruction, 16);
|
||||
critical_error(" => Unknown instruction: 0x%04X\n", instruction);
|
||||
return "";
|
||||
}
|
||||
|
||||
struct SR0 {
|
||||
unsigned long dummy0 : 22;
|
||||
unsigned long M0 : 1;
|
||||
unsigned long Q0 : 1;
|
||||
unsigned long I0 : 4;
|
||||
unsigned long dummy1 : 2;
|
||||
unsigned long S0 : 1;
|
||||
unsigned long T0 : 1;
|
||||
|
||||
unsigned long S0 : 1;
|
||||
|
||||
unsigned long dummy1 : 2;
|
||||
|
||||
unsigned long I0 : 4;
|
||||
|
||||
unsigned long Q0 : 1;
|
||||
|
||||
unsigned long M0 : 1;
|
||||
unsigned long dummy0 : 22;
|
||||
};
|
||||
#define M ((*(struct SR0 *)(&SR)).M0)
|
||||
#define Q ((*(struct SR0 *)(&SR)).Q0)
|
||||
|
|
|
@ -1,453 +0,0 @@
|
|||
#include "../headers/instructions/syscalls.h"
|
||||
|
||||
// Syscall entry point
|
||||
void run_syscall(cpu_t* cpu) {
|
||||
uint32_t syscall_code = R0;
|
||||
|
||||
// printf("run_syscall 0x%03X, args: 0x%X 0x%X 0x%X 0x%X\n", syscall_code, cpu->r[4], cpu->r[5], cpu->r[6], cpu->r[7]);
|
||||
|
||||
int arg1 = cpu->r[4];
|
||||
int arg2 = cpu->r[5];
|
||||
int arg3 = cpu->r[6];
|
||||
int arg4 = cpu->r[7];
|
||||
|
||||
if (syscall_code == 0x135) { // GetVRAMAddress
|
||||
syscall_GetVRAMAddress(cpu);
|
||||
}
|
||||
else if (syscall_code == 0x144) { // Bdisp_AllClr_DDVRAM
|
||||
printf("Run Syscall: Bdisp_AllClr_DDVRAM\n");
|
||||
syscall_Bdisp_AllClr_DDVRAM(cpu);
|
||||
}
|
||||
else if (syscall_code == 0x807) { // locate
|
||||
syscall_Locate(cpu, arg1, arg2);
|
||||
}
|
||||
else if (syscall_code == 0x808) { // Print
|
||||
uint8_t* mem = get_memory_for_address(cpu, arg1);
|
||||
const unsigned char* str = (const unsigned char*)mem;
|
||||
// printf("Run Syscall: syscall_Print (%s)\n", str);
|
||||
syscall_Print(cpu, str);
|
||||
}
|
||||
else if (syscall_code == 0x9AD) { // PrintXY
|
||||
uint8_t* mem = get_memory_for_address(cpu, arg3);
|
||||
const unsigned char* str = (const unsigned char*)mem;
|
||||
// printf("Run Syscall: syscall_PrintXY (%d %d %s %d)\n", arg1, arg2, str, arg4);
|
||||
syscall_PrintXY(cpu, arg1, arg2, str, arg4);
|
||||
}
|
||||
else if (syscall_code == 0xC4F) { // PrintMiniSd
|
||||
uint8_t* mem = get_memory_for_address(cpu, arg3);
|
||||
const unsigned char* str = (const unsigned char*)mem;
|
||||
// printf("Run Syscall: PrintMiniSd (%d %d %s %d)\n", arg1, arg2, str, arg4);
|
||||
syscall_PrintMiniSd(cpu, arg1, arg2, str, arg4);
|
||||
}
|
||||
else if (syscall_code == 0xACD) { // malloc
|
||||
syscall_Malloc(cpu, arg1, 0);
|
||||
}
|
||||
else if (syscall_code == 0xE6B) { // calloc
|
||||
syscall_Malloc(cpu, arg1, 1);
|
||||
}
|
||||
else if (syscall_code == 0xE6D) { // realloc
|
||||
printf("Skipped syscall: realloc\n");
|
||||
}
|
||||
else if (syscall_code == 0xACC) { // free
|
||||
printf("Skipped syscall: free\n");
|
||||
}
|
||||
else if (syscall_code == 0x462) { // GetAppName
|
||||
syscall_GetAppName(cpu, (char*)arg1);
|
||||
}
|
||||
else if (syscall_code == 0x014) { // GlibGetAddinLibInf
|
||||
syscall_GlibGetAddinLibInf(cpu, arg1, arg2, arg3);
|
||||
}
|
||||
else if (syscall_code == 0x015) { // GlibGetOSVersionInfo
|
||||
syscall_GlibGetOSVersionInfo(cpu, arg1, arg2, arg3, arg4);
|
||||
}
|
||||
|
||||
else if (syscall_code == 0x90F) { // GetKey
|
||||
printf("Skipped syscall: GetKey\n");
|
||||
// syscall_GetKey(cpu, arg1);
|
||||
// printf("Run Syscall: GetKey (0x%08X: %d)\n", arg1, R0);
|
||||
// cpu->isExecutionFinished = 1;
|
||||
}
|
||||
else if (syscall_code == 0x24C) { // Keyboard_IsSpecialKeyDown
|
||||
printf("Skipped syscall: Keyboard_IsSpecialKeyDown\n");
|
||||
}
|
||||
else if (syscall_code == 0x03B) { // RTC_GetTicks
|
||||
R0 = cpu->instruction_count / 7812;
|
||||
// printf("Run Syscall: RTC_GetTicks %d\n", R0);
|
||||
}
|
||||
|
||||
else if (syscall_code == 0x434) { // Bfile_CreateEntry_OS
|
||||
uint8_t* mem = get_memory_for_address(cpu, arg1);
|
||||
const char* str = (const char*)mem;
|
||||
// syscall_Bfile_CreateEntry_OS(cpu, str, arg2, arg3);
|
||||
printf("Skipped syscall: Bfile_CreateEntry_OS\n");
|
||||
}
|
||||
else if (syscall_code == 0x42C) { // Bfile_OpenFile_OS
|
||||
uint8_t* mem = get_memory_for_address(cpu, arg1);
|
||||
const char* str = (const char*)mem;
|
||||
// syscall_Bfile_OpenFile_OS(cpu, str, arg2, arg3);
|
||||
printf("Skipped syscall: Bfile_OpenFile_OS\n");
|
||||
}
|
||||
else if (syscall_code == 0x432) { // Bfile_ReadFile_OS
|
||||
printf("Skipped syscall: Bfile_ReadFile_OS\n");
|
||||
}
|
||||
else if (syscall_code == 0x435) { // Bfile_WriteFile_OS
|
||||
printf("Skipped syscall: Bfile_WriteFile_OS\n");
|
||||
}
|
||||
else if (syscall_code == 0x42D) { // Bfile_CloseFile_OS
|
||||
printf("Skipped syscall: Bfile_CloseFile_OS\n");
|
||||
}
|
||||
else if (syscall_code == 0x43B) { // Bfile_FindFirst
|
||||
printf("Skipped syscall: Bfile_FindFirst\n");
|
||||
}
|
||||
else if (syscall_code == 0x439) { // Bfile_DeleteEntry
|
||||
printf("Skipped syscall: Bfile_DeleteEntry\n");
|
||||
}
|
||||
else if (syscall_code == 0x82B) { // MCSPutVar2
|
||||
printf("Skipped syscall: MCSPutVar2\n");
|
||||
}
|
||||
else if (syscall_code == 0x840) { // MCSGetDlen2
|
||||
printf("Skipped syscall: MCSGetDlen2\n");
|
||||
}
|
||||
|
||||
else if (syscall_code == 0x420) { // OS_inner_Sleep
|
||||
// https://bible.planet-casio.com/simlo/chm/v20/fx_legacy_Sleep.HTM
|
||||
// printf("Skipped syscall: OS_inner_Sleep\n");
|
||||
}
|
||||
else if (syscall_code == 0x494) { // void SetQuitHandler( void (*callback)(void) );
|
||||
printf("Skipped syscall: SetQuitHandler\n");
|
||||
}
|
||||
else if (syscall_code == 0x3ED) { // Interrupt_SetOrClrStatusFlags
|
||||
// https://bible.planet-casio.com/simlo/chm/v20/fx_legacy_INTERRUPT.HTM
|
||||
printf("Skipped syscall: Interrupt_SetOrClrStatusFlags\n");
|
||||
}
|
||||
// Can be ignored
|
||||
else if (syscall_code == 0x013) { // GlibAddinAplExecutionCheck
|
||||
printf("Ignored syscall: GlibAddinAplExecutionCheck\n");
|
||||
}
|
||||
else if (syscall_code == 0x3FA) { // Hmem_SetMMU
|
||||
printf("Ignored syscall: Hmem_SetMMU\n");
|
||||
}
|
||||
// else if (syscall_code == 0x1032) { // return a pointer to a matrixcode/keycode mapping table
|
||||
// // https://bible.planet-casio.com/simlo/chm/v20/fx_legacy_keyboard.htm
|
||||
// printf("Skipped syscall: 0x1032\n");
|
||||
// }
|
||||
else {
|
||||
printf("Syscall not implemented: 0x%03X\n", syscall_code);
|
||||
cpu->isExecutionFinished = 1;
|
||||
}
|
||||
|
||||
cpu->pc = cpu->pr;
|
||||
}
|
||||
|
||||
// These functions clear the specified area of VRAM and/or DD (Display Driver).
|
||||
|
||||
void syscall_Bdisp_AllClr_DD(cpu_t* cpu) {
|
||||
// TODO
|
||||
}
|
||||
|
||||
void syscall_Bdisp_AllClr_VRAM(cpu_t* cpu) {
|
||||
for (int i = 0; i < VRAM_SIZE; i++) {
|
||||
cpu->disp->vram[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void syscall_Bdisp_AllClr_DDVRAM(cpu_t* cpu) {
|
||||
syscall_Bdisp_AllClr_DD(cpu);
|
||||
syscall_Bdisp_AllClr_VRAM(cpu);
|
||||
}
|
||||
|
||||
// Sets the position of the display cursor
|
||||
// x: [1-21], y: [1-8]
|
||||
void syscall_Locate(cpu_t* cpu, int x, int y) {
|
||||
cpu->disp->cursor.col = x;
|
||||
cpu->disp->cursor.row = y;
|
||||
printf("Run Syscall: locate (%d %d)\n", x, y);
|
||||
}
|
||||
|
||||
void draw_character_mini(cpu_t* cpu, const char c, int pixel_start_x, int pixel_start_y, int mode) {
|
||||
// Character x,y in ASCII texture (16x16)
|
||||
int char_x = c / 16;
|
||||
int char_y = c % 16;
|
||||
|
||||
if (char_x < 0 || char_x >= 16 || char_y < 0) return;
|
||||
|
||||
// Pixel start x, y in ASCII texture (128x128)
|
||||
char_x = char_x * 7;
|
||||
char_y = char_y * 7;
|
||||
|
||||
for (int y = 0; y < 7; y++) {
|
||||
for (int x = 0; x < 7; x++) {
|
||||
// Current pixel position in ASCII texture
|
||||
int ascii_x = char_x + x;
|
||||
int ascii_y = char_y + y;
|
||||
int ascii_id = ascii_x + ascii_y * 128; // Pixel index
|
||||
if (ascii_id < 0 || ascii_id >= 128 * 128) break;
|
||||
|
||||
// Current pixel position on-screen
|
||||
int vram_x = pixel_start_x + x;
|
||||
int vram_y = pixel_start_y + y;
|
||||
int vram_id = (vram_x + vram_y * SCREEN_WIDTH) / 8; // index in VRAM
|
||||
if (vram_id < 0 || vram_id >= VRAM_SIZE) break;
|
||||
|
||||
int ascii_bit = cpu->printMiniTexture[ascii_id] ^ mode; // Pixel value
|
||||
int vram_bit = 7 - vram_x % 8; // Current bit
|
||||
|
||||
// Change one single bit in the VRAM
|
||||
if (ascii_bit)
|
||||
cpu->disp->vram[vram_id] = (cpu->disp->vram[vram_id] & ~(1 << vram_bit)) | (1 << vram_bit);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void syscall_PrintMiniSd(cpu_t* cpu, int x, int y, const unsigned char* str, int mode) {
|
||||
int i = 0;
|
||||
while (x < SCREEN_WIDTH) {
|
||||
const char c = str[i++]; // Current character
|
||||
|
||||
if (c == 0x00) break; // Line terminator
|
||||
|
||||
draw_character_mini(cpu, c, x, y, mode);
|
||||
|
||||
x += 4; // Move the cursor the the right
|
||||
}
|
||||
}
|
||||
|
||||
// Draw a character on screen
|
||||
// pixel_start_x and y represent the top left pixel of the character
|
||||
void draw_character(cpu_t* cpu, const char c, int pixel_start_x, int pixel_start_y, int mode) {
|
||||
int offset = c - 0x0020;
|
||||
|
||||
// Character x,y in ASCII texture (16x16)
|
||||
int char_x = offset % 16;
|
||||
int char_y = offset / 16;
|
||||
// Pixel start x, y in ASCII texture (112x54)
|
||||
char_x = char_x * ASCII_CHAR_WIDTH;
|
||||
char_y = char_y * ASCII_CHAR_HEIGHT;
|
||||
|
||||
for (int y = 0; y < ASCII_CHAR_HEIGHT; y++) {
|
||||
for (int x = 0; x < ASCII_CHAR_WIDTH; x++) {
|
||||
// Current pixel position in ASCII texture
|
||||
int ascii_x = char_x + x;
|
||||
int ascii_y = char_y + y;
|
||||
int ascii_id = ascii_x + ascii_y * 112; // Pixel index
|
||||
|
||||
if (ascii_id < 0 || ascii_id >= 112 * 54) break; // critical_error("ASCII Texture Access out of bounds: %d %d (%d)", ascii_x, ascii_y, ascii_id);
|
||||
|
||||
// Current pixel position on-screen
|
||||
int vram_x = pixel_start_x + x;
|
||||
int vram_y = pixel_start_y + y;
|
||||
int vram_id = (vram_x + vram_y * SCREEN_WIDTH) / 8; // index in VRAM
|
||||
int vram_bit = 7 - vram_x % 8; // Current bit
|
||||
|
||||
if (vram_id < 0 || vram_id >= VRAM_SIZE) break; // critical_error("VRAM Access out of bounds: %d %d (%d)", vram_x, vram_y, vram_id);
|
||||
|
||||
// Change one single bit in the VRAM
|
||||
int ascii_bit = cpu->asciiTexture[ascii_id] ^ mode; // Pixel value
|
||||
|
||||
if (ascii_bit)
|
||||
cpu->disp->vram[vram_id] = (cpu->disp->vram[vram_id] & ~(1 << vram_bit)) | (ascii_bit << vram_bit);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Display a string at the current position of the display cursor
|
||||
void syscall_Print(cpu_t* cpu, const unsigned char* str) {
|
||||
printf("syscall_print: %s\n", str);
|
||||
|
||||
int i = 0;
|
||||
while(cpu->disp->cursor.col < 21) {
|
||||
const char c = str[i++]; // Current character
|
||||
|
||||
if (c == 0x00) break; // Line terminator
|
||||
|
||||
// Character x,y on screen (21x7)
|
||||
int screen_x = cpu->disp->cursor.col;
|
||||
int screen_y = cpu->disp->cursor.row;
|
||||
// Pixel start x,y on screen (128x64)
|
||||
screen_x = screen_x * CHAR_WIDTH + 1;
|
||||
screen_y = screen_y * CHAR_HEIGHT;
|
||||
|
||||
draw_character(cpu, c, screen_x, screen_y, 0);
|
||||
|
||||
// Move the cursor the the right
|
||||
cpu->disp->cursor.col++;
|
||||
}
|
||||
}
|
||||
|
||||
void syscall_PrintXY(cpu_t* cpu, int x, int y, const unsigned char* str, int mode) {
|
||||
int i = 0;
|
||||
while (x < SCREEN_WIDTH) {
|
||||
const char c = str[i++]; // Current character
|
||||
|
||||
if (c == 0x00) break; // Line terminator
|
||||
|
||||
draw_character(cpu, c, x, y, mode);
|
||||
|
||||
x += CHAR_WIDTH; // Move the cursor the the right
|
||||
}
|
||||
}
|
||||
|
||||
#define MALLOC_MEM_LOW RAM_START_MMU_ALIAS + (32 * 1024)
|
||||
#define MALLOC_MEM_HIGH RAM_START_MMU_ALIAS + RAM_SIZE - (16 * 1024)
|
||||
#define MALLOC_MARGIN 0x200
|
||||
|
||||
// Allocate memory and return the address of the allocated memory in r0
|
||||
void syscall_Malloc(cpu_t* cpu, uint32_t size, uint8_t clear_data) {
|
||||
memory_t* mem = cpu->mem;
|
||||
|
||||
// Initialize with the lowest address
|
||||
int addr = MALLOC_MEM_LOW;
|
||||
|
||||
// If there are mallocs, start at the end of the last malloc
|
||||
if (mem->mallocCount > 0) {
|
||||
addr = mem->mallocs[mem->mallocCount - 1].addr +
|
||||
mem->mallocs[mem->mallocCount - 1].size + MALLOC_MARGIN;
|
||||
}
|
||||
|
||||
// Update malloc manager
|
||||
mem->mallocCount++;
|
||||
mem->mallocs = realloc(mem->mallocs, mem->mallocCount * sizeof(malloc_info_t));
|
||||
|
||||
if (clear_data) {
|
||||
for (int i = 0; i < size; i++) {
|
||||
mem_write(cpu, addr + i, 0, 4);
|
||||
}
|
||||
}
|
||||
|
||||
if (mem->mallocs == 0) {
|
||||
critical_error("syscall_malloc(): Could not allocate memory");
|
||||
}
|
||||
|
||||
if (clear_data)
|
||||
printf("Run Syscall: Calloc #%d (size: %d)\n", mem->mallocCount - 1, size);
|
||||
else
|
||||
printf("Run Syscall: Malloc #%d (size: %d)\n", mem->mallocCount - 1, size);
|
||||
|
||||
mem->mallocs[mem->mallocCount - 1] = (malloc_info_t){size, addr};
|
||||
|
||||
// Return the address of the allocated memory
|
||||
R0 = addr;
|
||||
}
|
||||
|
||||
// https://bible.planet-casio.com/simlo/chm/v20/fx_legacy_AppName.HTM
|
||||
// Copies the registered name for the running application into the character array dest.
|
||||
// dest must be able to hold 9 bytes. dest is returned.
|
||||
void syscall_GetAppName(cpu_t* cpu, char* dest) {
|
||||
// Copies the app name to the new buffer
|
||||
for (int i = 0; i < 9; i++) {
|
||||
mem_write(cpu, (uint32_t)dest + i, cpu->mem->rom[0x20 + i], 1);
|
||||
}
|
||||
|
||||
printf("Run Syscall: GetAppName (%s)\n", (const char*)get_memory_for_address(cpu, (uint32_t)dest));
|
||||
|
||||
R0 = (int32_t)dest; // Return the buffer
|
||||
}
|
||||
|
||||
void syscall_GetVRAMAddress(cpu_t* cpu) {
|
||||
R0 = VRAM_ADDRESS;
|
||||
// printf("Run Syscall: GetVRAMAddress (-> 0x%08X)\n", R0);
|
||||
}
|
||||
|
||||
void syscall_GlibGetAddinLibInf(cpu_t* cpu, uint32_t a_ptr, uint32_t b_ptr, uint32_t c_ptr) {
|
||||
// Mimic Casio SDK Emulator
|
||||
mem_write(cpu, a_ptr, 0x0, 4);
|
||||
mem_write(cpu, b_ptr, 0x1, 4);
|
||||
mem_write(cpu, c_ptr, 0x1, 4);
|
||||
|
||||
cpu->r[0] = 0x1;// 0x0;
|
||||
cpu->r[2] = 0xA0151F28;
|
||||
cpu->r[3] = 0x0;
|
||||
cpu->r[4] = 0x1;
|
||||
|
||||
printf("Run Syscall: GlibGetAddinLibInf\n");
|
||||
}
|
||||
|
||||
void syscall_GlibGetOSVersionInfo(cpu_t* cpu, uint32_t a_ptr, uint32_t b_ptr, uint32_t c_ptr, uint32_t d_ptr) {
|
||||
// Mimic Casio SDK Emulator
|
||||
mem_write(cpu, a_ptr, 0x1, 1);
|
||||
mem_write(cpu, b_ptr, 0x3, 1);
|
||||
mem_write(cpu, c_ptr, 0x0, 2);
|
||||
mem_write(cpu, d_ptr, 0x0, 2);
|
||||
|
||||
cpu->r[0] = 0x1;
|
||||
cpu->r[2] = 0x3;
|
||||
cpu->r[3] = 0x1;
|
||||
cpu->r[4] = 0x0;
|
||||
|
||||
// printf("Run Syscall: GlibGetOSVersionInfo\n");
|
||||
}
|
||||
|
||||
const char* convertFileName(const char* filename) {
|
||||
char name[40];
|
||||
char ch;
|
||||
int i;
|
||||
|
||||
// Convert filename from { 0x00, 0xXX, 0x00, 0xXX, ... } to { 0xXX, 0xXX, ... }
|
||||
for (i = 0; i < 40; i++) {
|
||||
uint16_t ch = *(uint16_t*) &filename[i * 2 + 1];
|
||||
name[i] = ch;
|
||||
if (ch == 0x00) break;
|
||||
}
|
||||
|
||||
// Remove '\\fls0\'
|
||||
i -= 6;
|
||||
char* final_name = malloc(sizeof(char) * i);
|
||||
memcpy(final_name, name + 7, i);
|
||||
|
||||
return (const char*)final_name;
|
||||
}
|
||||
|
||||
// mode: 1 = read, 2 = write
|
||||
void syscall_Bfile_OpenFile_OS(cpu_t* cpu, const char* filename, int mode, int mode2) {
|
||||
const char* name = convertFileName(filename);
|
||||
|
||||
FILE* handle = fopen(name, mode == 1 ? "rb" : "wb");
|
||||
|
||||
printf("Run Syscall: Bfile_OpenFile_OS (%s, 0x%X, 0x%X) handle: 0x%X\n", name, mode, mode2, (uint32_t)handle);
|
||||
|
||||
R0 = handle == NULL ? -1 : (int32_t)handle;
|
||||
}
|
||||
|
||||
void syscall_Bfile_CreateEntry_OS(cpu_t* cpu, const char* filename, int mode, int size_ptr) {
|
||||
const char* name = convertFileName(filename);
|
||||
|
||||
FILE* handle;
|
||||
|
||||
if (mode == 0x1) { // Create file
|
||||
handle = fopen(name, "wb");
|
||||
fclose(handle);
|
||||
}
|
||||
// else if (mode == 0x5) { } // Create folder
|
||||
else printf("[Warning] CreateEntry mode not implemented\n");
|
||||
|
||||
printf("Run Syscall: Bfile_CreateEntry_OS (%s, 0x%X) size: %d, handle: 0x%X\n", name, mode, mem_read(cpu, size_ptr, 4), (uint32_t)handle);
|
||||
|
||||
R0 = handle == NULL ? -1 : (int32_t)handle;
|
||||
}
|
||||
|
||||
// #ifdef USE_EMSCRIPT
|
||||
// EM_ASYNC_JS(int, async_browser_getkey, (), {
|
||||
// return await new Promise((resolve, reject) => {
|
||||
// const onClick = (event) => {
|
||||
// const res = window.keyboardEvent(event);
|
||||
// if (res != null) {
|
||||
// document.getElementById("keyboard").removeEventListener("click", onClick);
|
||||
// resolve(res);
|
||||
// }
|
||||
// };
|
||||
// document.getElementById("keyboard").addEventListener("click", onClick);
|
||||
// });
|
||||
// })
|
||||
// #else
|
||||
// int async_browser_getkey() {
|
||||
// return 0;
|
||||
// }
|
||||
// #endif
|
||||
|
||||
// void syscall_GetKey(cpu_t* cpu, unsigned int keycode_address) {
|
||||
// int key = async_browser_getkey();
|
||||
|
||||
// mem_write(cpu, keycode_address, key, 4);
|
||||
|
||||
// R0 = key;
|
||||
// }
|
|
@ -74,6 +74,10 @@ cpu_t* init_cpu(memory_t* mem, display_t* disp) {
|
|||
|
||||
cpu->mem = mem;
|
||||
cpu->disp = disp;
|
||||
cpu->fs = calloc(1, sizeof(fs_t));
|
||||
|
||||
cpu->malloc_manager = calloc(1, sizeof(malloc_manager_t));
|
||||
cpu->malloc_manager->mallocs = malloc(MALLOC_SIZE * sizeof(int8_t));
|
||||
|
||||
return cpu;
|
||||
}
|
||||
|
@ -83,6 +87,7 @@ cpu_t* init_cpu(memory_t* mem, display_t* disp) {
|
|||
void run_next_instruction(cpu_t* cpu) {
|
||||
// Current instruction address
|
||||
uint32_t address = cpu->pc;
|
||||
cpu->instruction_count++;
|
||||
|
||||
// Handle system calls
|
||||
if (address == SYSCALL_ADDRESS) {
|
||||
|
@ -92,13 +97,13 @@ void run_next_instruction(cpu_t* cpu) {
|
|||
// Handle program execution finish
|
||||
if (address == PR_INIT_VALUE) {
|
||||
printf("Program execution finished!\n");
|
||||
cpu->isExecutionFinished = 1;
|
||||
cpu->execution_finished = 1;
|
||||
return;
|
||||
}
|
||||
|
||||
if (address % 2 != 0) {
|
||||
critical_error("Address is not a multiple of 2 bytes! (0x%08X)", address);
|
||||
}
|
||||
// if (address % 2 != 0) {
|
||||
// critical_error("Address is not a multiple of 2 bytes! (0x%08X)", address);
|
||||
// }
|
||||
|
||||
// Extract 16bits instruction code
|
||||
uint16_t instruction = (mem_read(cpu, address, 1) << 8) | mem_read(cpu, address + 1, 1);
|
||||
|
@ -134,21 +139,23 @@ int main() {
|
|||
// Init the HTML version of the emulator
|
||||
void init_loop_html(cpu_t* cpu) {
|
||||
#ifdef USE_EMSCRIPT
|
||||
cpu->instruction_per_frame = 10000;
|
||||
cpu->instruction_per_frame = 50000;
|
||||
|
||||
// Pass useful pointers to javascript
|
||||
EM_ASM({
|
||||
window.lcdImage = $0;
|
||||
window.vramPointer = $0;
|
||||
window.keyboardPointer = $1;
|
||||
window.instructionPerFrame = $2;
|
||||
window.instructionCount = $3;
|
||||
window.cpuPointer = $4;
|
||||
window.rtcTicksPointer = $4;
|
||||
window.cpuPointer = $5;
|
||||
window.initGUI();
|
||||
},
|
||||
},
|
||||
&cpu->disp->vram,
|
||||
&cpu->mem->keyboard,
|
||||
&cpu->instruction_per_frame,
|
||||
&cpu->instruction_count,
|
||||
&cpu->RTC_Ticks,
|
||||
cpu
|
||||
);
|
||||
|
||||
|
@ -161,14 +168,15 @@ void init_loop_html(cpu_t* cpu) {
|
|||
void main_loop_html(void* arg) {
|
||||
cpu_t* cpu = (cpu_t*)arg;
|
||||
|
||||
if (cpu->isExecutionFinished) return;
|
||||
if ((cpu->execution_paused && !cpu->execute_one_step) || cpu->execution_finished) return;
|
||||
|
||||
for (int i = 0; i < cpu->instruction_per_frame; i++) {
|
||||
run_next_instruction(cpu);
|
||||
cpu->instruction_count++;
|
||||
|
||||
if (cpu->isExecutionFinished) break;
|
||||
if (cpu->execution_paused || cpu->execution_finished) break;
|
||||
}
|
||||
|
||||
if (cpu->execute_one_step) cpu->execute_one_step = 0;
|
||||
}
|
||||
|
||||
// Run the console version of the emulator
|
||||
|
@ -177,9 +185,8 @@ void init_loop_c(cpu_t* cpu) {
|
|||
// Run up to 10M instructions
|
||||
for (int i = 0; i < 1e7; i++) {
|
||||
run_next_instruction(cpu);
|
||||
cpu->instruction_count++;
|
||||
|
||||
if (cpu->isExecutionFinished) break;
|
||||
if (cpu->execution_finished) break;
|
||||
}
|
||||
|
||||
vram_debug(cpu);
|
||||
|
@ -191,4 +198,36 @@ void init_loop_c(cpu_t* cpu) {
|
|||
free(cpu->asciiTexture);
|
||||
free(cpu->printMiniTexture);
|
||||
free(cpu);
|
||||
}
|
||||
|
||||
// Functions called from javascript
|
||||
|
||||
void reset_execution(cpu_t* cpu) {
|
||||
cpu->pc = PC_PROGRAM_START;
|
||||
cpu->pr = PR_INIT_VALUE;
|
||||
cpu->sr = SR_INIT_VALUE;
|
||||
cpu->r[15] = RAM_START + RAM_SIZE;
|
||||
|
||||
cpu->instruction_count = 0;
|
||||
cpu->execution_finished = 0;
|
||||
|
||||
for (int i = 0; i < VRAM_SIZE; i++) {
|
||||
cpu->disp->vram[i] = 0;
|
||||
}
|
||||
|
||||
free(cpu->fs);
|
||||
cpu->fs = calloc(1, sizeof(fs_t));
|
||||
|
||||
cpu->malloc_manager->currentSize = 0;
|
||||
cpu->malloc_manager->mallocCount = 0;
|
||||
}
|
||||
|
||||
void load_new_g1a(cpu_t* cpu, uint8_t* g1a_content, uint32_t g1a_size) {
|
||||
reset_execution(cpu);
|
||||
|
||||
printf("Loading new G1A file %d\n", g1a_size);
|
||||
|
||||
free(cpu->mem->rom);
|
||||
cpu->mem->rom = g1a_content;
|
||||
cpu->mem->rom_size = g1a_size;
|
||||
}
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
// Returns a pointer to the buffer (memory)
|
||||
// corresponding to the `address` parameter
|
||||
uint8_t* get_memory_for_address(cpu_t* cpu, uint32_t address) {
|
||||
uint8_t* get_memory_for_address(cpu_t* cpu, uint32_t address) {
|
||||
if (address >= ROM_START && address < ROM_START + cpu->mem->rom_size) { // ROM - (MMU)
|
||||
return &cpu->mem->rom[address - ROM_START];
|
||||
}
|
||||
|
@ -15,18 +15,26 @@ uint8_t* get_memory_for_address(cpu_t* cpu, uint32_t address) {
|
|||
else if (address >= VRAM_ADDRESS && address < VRAM_ADDRESS + VRAM_SIZE) { // VRAM
|
||||
return &cpu->disp->vram[address - VRAM_ADDRESS];
|
||||
}
|
||||
else if (address == VRAM_ADDRESS + VRAM_SIZE) {
|
||||
// printf("Prevent OOB Ram access\n");
|
||||
// TODO: Check why Gravity Duck doesnt crash when exceeding this margin
|
||||
return &cpu->mem->tmp[0];
|
||||
}
|
||||
else if (address == LCD_SELECT_REGISTER || address == LCD_DATA_REGISTER) { // LCD registers
|
||||
return &cpu->disp->lcd_registers;
|
||||
}
|
||||
else if (address >= KB_START && address < KB_START + KB_SIZE) { // Keyboard registers
|
||||
return &cpu->mem->keyboard_registers[address - KB_START];
|
||||
}
|
||||
else if (address >= 0xFFFFFEE0 && address < 0xFFFFFFFF) { // Temporary memory
|
||||
else if (address >= MALLOC_START && address < MALLOC_START + MALLOC_SIZE) { // Malloc
|
||||
return &cpu->malloc_manager->mallocs[address - MALLOC_START];
|
||||
}
|
||||
else if (address >= 0xFFFFFEE0 && address < 0xFFFFFFFF) { // Interrupt registers
|
||||
return &cpu->mem->tmp[address - 0xFFFFFEE0];
|
||||
}
|
||||
else {
|
||||
// cpu_debug(cpu);
|
||||
critical_error("Request for memory at address 0x%08X is out of bounds\n", address);
|
||||
printf("[Error] Request for memory at address 0x%08X is out of bounds\n", address);
|
||||
return &cpu->mem->tmp[0];
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -37,9 +45,11 @@ void mem_write(cpu_t* cpu, uint32_t address, uint32_t data, uint8_t bytes) {
|
|||
emulate_lcd_register_write(cpu, address, data);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
uint8_t* mem = get_memory_for_address(cpu, address);
|
||||
|
||||
// printf("Memory write [0x%08X]: : 0x%X\n", address, data);
|
||||
|
||||
if (bytes == 1) {
|
||||
*mem = data & 0xFF;
|
||||
}
|
||||
|
@ -79,6 +89,7 @@ uint32_t mem_read(cpu_t* cpu, uint32_t address, uint8_t bytes) {
|
|||
data = (*mem << 24) | (*(mem + 1) << 16) | (*(mem + 2) << 8) | (*(mem + 3));
|
||||
}
|
||||
|
||||
// if (address != cpu->pc && address != cpu->pc + 1)
|
||||
// printf("Memory read [0x%08X]: : 0x%X\n", address, data);
|
||||
|
||||
return data;
|
||||
|
@ -108,6 +119,7 @@ uint32_t emulate_keyboard_register_read(cpu_t* cpu) {
|
|||
return 0xffffffff;
|
||||
}
|
||||
else {
|
||||
// printf("Keyboard row %d: 0x%08X\n", row, cpu->mem->keyboard[row]);
|
||||
return cpu->mem->keyboard[row];
|
||||
}
|
||||
}
|
||||
|
@ -136,15 +148,12 @@ void emulate_lcd_register_write(cpu_t* cpu, uint32_t address, uint32_t data) {
|
|||
// Write data to LCD row
|
||||
else if (address == LCD_DATA_REGISTER) {
|
||||
if (row >= 0) {
|
||||
cpu->disp->lcd[row * 16 + col++] = data; // Update LCD buffer
|
||||
col++; // cpu->disp->lcd[row * 16 + col++] = data; // Update LCD buffer
|
||||
|
||||
#ifdef EMSCRIPTEN
|
||||
if (row == 63 && col == 16) { // Refresh HTML canvas
|
||||
EM_ASM({
|
||||
window.refreshScreen();
|
||||
});
|
||||
syscall_Bdisp_PutDisp_DD(cpu);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (col >= 16) {
|
||||
col = 0;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,285 @@
|
|||
#include "../headers/syscalls/filesystem.h"
|
||||
|
||||
const char* convertFileName(const char* filename) {
|
||||
char name[40];
|
||||
char ch;
|
||||
int i;
|
||||
|
||||
// Convert filename from { 0x00, 0xXX, 0x00, 0xXX, ... } to { 0xXX, 0xXX, ... }
|
||||
for (i = 0; i < 40; i++) {
|
||||
uint16_t ch = *(uint16_t*)&filename[i * 2 + 1];
|
||||
name[i] = ch;
|
||||
if (ch == 0x00) break;
|
||||
}
|
||||
|
||||
// Remove '\\fls0\'
|
||||
i -= 6;
|
||||
char* final_name = malloc(sizeof(char) * i);
|
||||
memcpy(final_name, name + 7, i);
|
||||
|
||||
return (const char*)final_name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a file/directory
|
||||
* @param filename This is the pointer to a null-terminated string that names the file/directory to be created.
|
||||
* @param size This is the size of the file to be created. This parameter is only used when you create a file in Storage Memory.
|
||||
* @return If the function succeeds, the return value is 0.
|
||||
* If the function fails, the return value is an error code. It is a negative value.
|
||||
* @remarks <p>This function creates a file in Storage Memory or the SD card.
|
||||
*/
|
||||
void syscall_Bfile_CreateEntry(cpu_t* cpu, uint32_t filename_ptr, int mode, uint32_t size_ptr) {
|
||||
const char* filename = (const char*)get_memory_for_address(cpu, filename_ptr);
|
||||
const char* name = convertFileName(filename);
|
||||
|
||||
if (mode == 0x1) {
|
||||
// Create file with fixed size, initialize with 0
|
||||
uint32_t size = mem_read(cpu, size_ptr, 4);
|
||||
uint8_t* data = calloc(size, sizeof(uint8_t));
|
||||
FILE* file = fopen(name, "wb");
|
||||
fwrite(data, 1, size, file);
|
||||
fclose(file);
|
||||
|
||||
R0 = 0; // Success
|
||||
|
||||
printf("Run syscall: Bfile_CreateEntry %s (0x%X, size: %d)\n", name, mode, mem_read(cpu, size_ptr, 4));
|
||||
}
|
||||
// else if (mode == 0x5) { } // Create folder
|
||||
else {
|
||||
R0 = -1; // Error
|
||||
printf("[Warning] In syscall Bfile_CreateEntry: CreateEntry mode %d not implemented\n", mode);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes an existing file
|
||||
* @param filename This is the pointer to a null-terminated string that specifies the file to delete.
|
||||
* @param mode always should be used and set to 0.
|
||||
* @return If the function succeeds, the return value is 0.
|
||||
* If the function fails, the return value is an error code. It is a negative value.
|
||||
* @remarks <p>This function deletes a file in Storage Memory or the SD card.
|
||||
*/
|
||||
void syscall_Bfile_DeleteEntry(cpu_t* cpu, uint32_t filename_ptr, int mode) {
|
||||
const char* filename = (const char*)get_memory_for_address(cpu, filename_ptr);
|
||||
const char* name = convertFileName(filename);
|
||||
|
||||
if (remove(name) == 0) {
|
||||
R0 = 0; // Success
|
||||
printf("Run syscall: Bfile_DeleteEntry %s\n", name);
|
||||
}
|
||||
else {
|
||||
R0 = -1; // Error
|
||||
printf("[Warning] In syscall Bfile_DeleteEntry: Could not delete file %s\n", name);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Opens an existing file.
|
||||
* @param filename This is the pointer to a null-terminated string that names the file to be opened.
|
||||
* @param mode The mode parameter specifies the action to open (read/write/read_write...)
|
||||
* @return If the function succeeds, the return value specifies a file handle. It is greater than or equal to 0.
|
||||
* If the function fails, the return value is an error code. It is a negative value.
|
||||
* @remarks This function opens a file in Storage Memory or the SD card.
|
||||
* mode2 always should be used and set to 0.
|
||||
*/
|
||||
void syscall_Bfile_OpenFile(cpu_t* cpu, uint32_t filename_ptr, int mode, int mode2) {
|
||||
const char* filename = (const char*)get_memory_for_address(cpu, filename_ptr);
|
||||
const char* name = convertFileName(filename);
|
||||
fs_t* fs = cpu->fs;
|
||||
|
||||
// Only four files can be opened at the same time
|
||||
if (fs->open_files_count >= 4) {
|
||||
printf("[Warning] In syscall Bfile_OpenFile: Too many files opened! (%s, mode: %d)\n", name, mode);
|
||||
R0 = -8;
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if file exists
|
||||
FILE* file = fopen(name, "rb");
|
||||
|
||||
if (file == NULL) {
|
||||
printf("[Warning] In syscall Bfile_OpenFile: File not found: %s\n", name);
|
||||
R0 = -1;
|
||||
return;
|
||||
}
|
||||
|
||||
// Get file size
|
||||
fseek(file, 0, SEEK_END);
|
||||
int32_t file_size = ftell(file);
|
||||
fclose(file);
|
||||
|
||||
// Open file for reading/writing
|
||||
file = fopen(name, mode == 1 ? "rb" : "wb");
|
||||
|
||||
// Handle is 0x1000000 + file index
|
||||
int32_t handle = 0x01000000 + fs->open_files_count;
|
||||
|
||||
// Create file entry
|
||||
strcpy(fs->files[fs->open_files_count].name, name);
|
||||
cpu->fs->files[fs->open_files_count].handle = handle;
|
||||
cpu->fs->files[fs->open_files_count].file_handle = file;
|
||||
cpu->fs->files[fs->open_files_count].seek_pos = 0;
|
||||
cpu->fs->files[fs->open_files_count].size = file_size;
|
||||
fs->open_files_count++;
|
||||
|
||||
printf("Run syscall: Bfile_OpenFile: %s (mode: %d), handle: 0x%X\n", name, mode, handle);
|
||||
|
||||
R0 = handle;
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes an open file handle.
|
||||
* @param HANDLE This is the handle of the file to close. HANDLE should be the handle opened by the Bfile_OpenFile or
|
||||
* Bfile_OpenMainMemory function.
|
||||
* @return If the function succeeds, this function returns 0.
|
||||
* If the function fails, the return value is an error code. It is a negative value.
|
||||
* @remarks Only four files can be opened at the same time.
|
||||
*/
|
||||
void syscall_Bfile_CloseFile(cpu_t* cpu, int handle) {
|
||||
R0 = -1;
|
||||
|
||||
// Check if the handle is valid
|
||||
if (handle - 0x01000000 < 0 || handle - 0x01000000 >= 4) {
|
||||
printf("[Warning] Bfile_CloseFile: Invalid handle: 0x%X\n", handle);
|
||||
return;
|
||||
}
|
||||
|
||||
// Loop through each open file
|
||||
for (int i = 0; i < cpu->fs->open_files_count; i++) {
|
||||
// Find the corresponding file and close it
|
||||
if (cpu->fs->files[i].handle == handle) {
|
||||
fclose(cpu->fs->files[i].file_handle);
|
||||
cpu->fs->open_files_count--;
|
||||
R0 = 0;
|
||||
|
||||
printf("Run syscall: Bfile_CloseFile %s (0x%X)\n", cpu->fs->files[i].name, handle);
|
||||
}
|
||||
|
||||
// Shift the following files to the left
|
||||
if (R0 == 0 && i < 3 && i < cpu->fs->open_files_count) {
|
||||
strcpy(cpu->fs->files[i].name, cpu->fs->files[i + 1].name);
|
||||
cpu->fs->files[i].handle = cpu->fs->files[i + 1].handle;
|
||||
cpu->fs->files[i].file_handle = cpu->fs->files[i + 1].file_handle;
|
||||
cpu->fs->files[i].seek_pos = cpu->fs->files[i + 1].seek_pos;
|
||||
cpu->fs->files[i].size = cpu->fs->files[i + 1].size;
|
||||
// printf("Bfile_CloseFile: Moved file %s from %d to %d\n", cpu->fs->files[i].name, i + 1, i);
|
||||
}
|
||||
}
|
||||
|
||||
if (R0 == -1)
|
||||
printf("[Warning] In syscall Bfile_CloseFile: File not found for handle: 0x%X\n", handle);
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes data to a file. The function starts writing data to the file at the position
|
||||
* indicated by the file pointer. After the write operation has been completed, the file pointer is adjusted by the
|
||||
* number of bytes actually written (TODO)
|
||||
* @param HANDLE This is the handle of the file to write. HANDLE should be the handle opened by the Bfile_OpenFile or
|
||||
* Bfile_OpenMainMemory function.
|
||||
* @param buf This is the pointer to the buffer containing the data to be written to the file.
|
||||
* @param size This is the number of bytes to write to the file.
|
||||
* @return If the function succeeds, this function returns the position indicated by the file pointer.
|
||||
* It is greater than or equal to 0.
|
||||
* If the function fails, the return value is an error code. It is a negative value.
|
||||
* @remarks If you use a file that is written by this function on the PC, you should save the multi byte data in the Little Endian
|
||||
* format.
|
||||
*/
|
||||
void syscall_Bfile_WriteFile(cpu_t* cpu, int handle, uint32_t buf_ptr, int size) {
|
||||
// Check if the handle is valid
|
||||
if (handle - 0x01000000 < 0 || handle - 0x01000000 >= 4) {
|
||||
printf("[Warning] In syscall Bfile_WriteFile: Invalid handle: 0x%X (0x%X, %d)\n", handle, buf_ptr, size);
|
||||
R0 = -1;
|
||||
return;
|
||||
}
|
||||
|
||||
file_t* file = &cpu->fs->files[handle & 3];
|
||||
|
||||
printf("Run syscall: Bfile_WriteFile %s (0x%X, 0x%X, %d)\n", file->name, handle, buf_ptr, size);
|
||||
|
||||
// Advance the file pointer
|
||||
fseek(file->file_handle, file->seek_pos, SEEK_SET);
|
||||
file->seek_pos += size;
|
||||
|
||||
// Write the data to the file
|
||||
for (int i = 0; i < size; i++) {
|
||||
uint8_t byte = mem_read(cpu, buf_ptr + i, 1);
|
||||
fwrite(&byte, 1, 1, file->file_handle);
|
||||
}
|
||||
|
||||
R0 = file->seek_pos;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads data from a file, starting at the position indicated by the file pointer. After the
|
||||
* read operation has been completed, the file pointer is adjusted by the number of bytes actually read.
|
||||
* @param HANDLE This is the handle of the file to read. HANDLE should be the handle opened by the Bfile_OpenFile or
|
||||
* Bfile_OpenMainMemory function.
|
||||
* @param buf This is the pointer to the buffer that receives the data read from the file.
|
||||
* @param size This is the number of bytes to be read from the file.
|
||||
* @param readpos This is the starting position to read. If the readpos parameter is -1, this function reads data from the position
|
||||
* indicated by the file pointer. If the readpos parameter greater than or equal to 0, this function reads data from
|
||||
* the position indicated by the readpos parameter.
|
||||
* @return If the function succeeds, this function returns the number of bytes actually read. It is greater than or equal to 0.
|
||||
* If the function fails, the return value is an error code. It is a negative value.
|
||||
* @remarks If you read the Windows file, the multi byte data is stored in Little Endian format. To use this data, you should
|
||||
* convert the multi byte data into the Big Endian format.
|
||||
*/
|
||||
void syscall_Bfile_ReadFile(cpu_t* cpu, int handle, uint32_t buf_ptr, int size, int readpos) {
|
||||
// Check if the handle is valid
|
||||
if (handle - 0x01000000 < 0 || handle - 0x01000000 >= 4) {
|
||||
printf("[Warning] In stscall Bfile_ReadFile: Invalid handle: 0x%X (0x%X, %d, %d)\n", handle, buf_ptr, size, readpos);
|
||||
return;
|
||||
}
|
||||
|
||||
file_t* file = &cpu->fs->files[handle & 3];
|
||||
|
||||
printf("Run syscall: Bfile_ReadFile %s (0x%X, 0x%X, %d, %d)\n", file->name, handle, buf_ptr, size, readpos);
|
||||
|
||||
// Advance the file pointer
|
||||
if (readpos == -1) {
|
||||
fseek(file->file_handle, file->seek_pos, SEEK_SET);
|
||||
file->seek_pos += size;
|
||||
}
|
||||
else {
|
||||
fseek(file->file_handle, readpos, SEEK_SET);
|
||||
file->seek_pos = readpos + size;
|
||||
}
|
||||
|
||||
// Read the data from the file
|
||||
for (int i = 0; i < size; i++) {
|
||||
uint8_t byte;
|
||||
fread(&byte, 1, 1, file->file_handle);
|
||||
mem_write(cpu, buf_ptr + i, byte, 1);
|
||||
}
|
||||
|
||||
R0 = size;
|
||||
}
|
||||
|
||||
/**
|
||||
* Moves the file pointer of an open file.
|
||||
* @param HANDLE This is the file handle whose file pointer will be moved
|
||||
* @param pos This is the number of bytes to move file pointer.
|
||||
* @return If the function succeeds, this function returns the number of bytes that can continuously be read.
|
||||
* It is greater than or equal to 0.
|
||||
* If the function fails, the return value is an error code. It is a negative value.
|
||||
* @remarks The starting point for the file pointer move is the beginning of the file. The file pointer is at the head of the file
|
||||
* immediately after the file was opened.
|
||||
*/
|
||||
void syscall_Bfile_SeekFile(cpu_t* cpu, int handle, int pos) {
|
||||
// Check if the handle is valid
|
||||
if (handle - 0x01000000 < 0 || handle - 0x01000000 >= 4) {
|
||||
printf("[Warning] In syscall Bfile_SeekFile: Invalid handle: 0x%X (%d)\n", handle, pos);
|
||||
return;
|
||||
}
|
||||
|
||||
file_t* file = &cpu->fs->files[handle & 3];
|
||||
|
||||
// Advance the file pointer
|
||||
file->seek_pos = pos;
|
||||
|
||||
// Return the number of bytes left from current pos
|
||||
R0 = file->size - pos;
|
||||
|
||||
printf("Run syscall: Bfile_SeekFile %s (0x%X, %d) ret: %d\n", file->name, handle, pos, R0);
|
||||
}
|
||||
|
|
@ -0,0 +1,47 @@
|
|||
#include "../headers/syscalls/malloc.h"
|
||||
|
||||
// Allocate memory and return the address of the allocated memory
|
||||
// The data is cleared (from what I observed), so syscall Calloc
|
||||
// redirects to this function too and `clear_data` is ignored
|
||||
void syscall_Malloc(cpu_t* cpu, uint32_t size, uint8_t clear_data) {
|
||||
malloc_manager_t* m = cpu->malloc_manager;
|
||||
|
||||
// Use the first 4 bytes to store the size of the malloc
|
||||
*(uint32_t*)(&m->mallocs[m->currentSize]) = size;
|
||||
|
||||
R0 = MALLOC_START + m->currentSize + 4;
|
||||
|
||||
// Clear the data
|
||||
for (int i = 0; i < size; i++) {
|
||||
m->mallocs[m->currentSize + i + 4] = 0;
|
||||
}
|
||||
|
||||
m->currentSize += size + 4;
|
||||
m->mallocCount++;
|
||||
|
||||
printf("Run syscall: %salloc #%d (size: %d, addr: 0x%X) Total allocated: %d\n", clear_data ? clear_data == 1 ? "C" : "Re" : "M", m->mallocCount, size, R0, m->currentSize - m->mallocCount);
|
||||
}
|
||||
|
||||
void syscall_Realloc(cpu_t* cpu, uint32_t ptr, uint32_t size) {
|
||||
uint8_t* mallocs = cpu->malloc_manager->mallocs;
|
||||
|
||||
syscall_Malloc(cpu, size, 2);
|
||||
|
||||
if (ptr == 0x0) return; // No pointer to reallocate, act as a malloc only
|
||||
|
||||
// Get the size of the previous malloc
|
||||
uint32_t prev_size = *(uint32_t*)(&mallocs[ptr - MALLOC_START - 4]);
|
||||
|
||||
// Transfer data to the new malloc
|
||||
for (int i = 0; i < prev_size; i++) {
|
||||
mallocs[R0 - MALLOC_START + i] = mallocs[ptr - MALLOC_START + i];
|
||||
}
|
||||
|
||||
syscall_Free(cpu, ptr);
|
||||
}
|
||||
|
||||
void syscall_Free(cpu_t* cpu, uint32_t ptr) {
|
||||
cpu->malloc_manager->mallocCount--;
|
||||
|
||||
// printf("Run syscall: Free #%d (addr: 0x%X) Total allocated: %d\n", cpu->malloc_manager->mallocCount, ptr, cpu->malloc_manager->currentSize - cpu->malloc_manager->mallocCount);
|
||||
}
|
|
@ -0,0 +1,91 @@
|
|||
#include "../headers/syscalls/misc.h"
|
||||
|
||||
// https://bible.planet-casio.com/simlo/chm/v20/fx_legacy_AppName.HTM
|
||||
// Copies the registered name for the running application into the character array dest.
|
||||
// dest must be able to hold 9 bytes. dest is returned.
|
||||
void syscall_GetAppName(cpu_t* cpu, uint32_t dest_ptr) {
|
||||
for (int i = 0; i < 9; i++) {
|
||||
mem_write(cpu, dest_ptr + i, cpu->mem->rom[0x20 + i], 1);
|
||||
}
|
||||
|
||||
printf("Run syscall: GetAppName (%s)\n", (const char*)get_memory_for_address(cpu, dest_ptr));
|
||||
|
||||
R0 = dest_ptr; // Return the buffer
|
||||
}
|
||||
|
||||
void syscall_GetVRAMAddress(cpu_t* cpu) {
|
||||
R0 = VRAM_ADDRESS;
|
||||
// printf("Run syscall: GetVRAMAddress (-> 0x%08X)\n", R0);
|
||||
}
|
||||
|
||||
void syscall_GlibGetAddinLibInf(cpu_t* cpu, uint32_t a_ptr, uint32_t b_ptr, uint32_t c_ptr) {
|
||||
// Mimic Casio SDK Emulator
|
||||
mem_write(cpu, a_ptr, 0x0, 4);
|
||||
mem_write(cpu, b_ptr, 0x1, 4);
|
||||
mem_write(cpu, c_ptr, 0x1, 4);
|
||||
|
||||
cpu->r[0] = 0x1;// 0x0;
|
||||
cpu->r[2] = 0xA0151F28;
|
||||
cpu->r[3] = 0x0;
|
||||
cpu->r[4] = 0x1;
|
||||
|
||||
printf("Run syscall: GlibGetAddinLibInf\n");
|
||||
}
|
||||
|
||||
void syscall_GlibGetOSVersionInfo(cpu_t* cpu, uint32_t a_ptr, uint32_t b_ptr, uint32_t c_ptr, uint32_t d_ptr) {
|
||||
// Mimic Casio SDK Emulator
|
||||
mem_write(cpu, a_ptr, 0x1, 1);
|
||||
mem_write(cpu, b_ptr, 0x3, 1);
|
||||
mem_write(cpu, c_ptr, 0x0, 2);
|
||||
mem_write(cpu, d_ptr, 0x0, 2);
|
||||
|
||||
cpu->r[0] = 0x1;
|
||||
cpu->r[2] = 0x3;
|
||||
cpu->r[3] = 0x1;
|
||||
cpu->r[4] = 0x0;
|
||||
|
||||
// printf("Run syscall: GlibGetOSVersionInfo\n");
|
||||
}
|
||||
|
||||
// Returns number of 1/128 seconds since an arbitrary date.
|
||||
void syscall_RTC_GetTicks(cpu_t* cpu) {
|
||||
R0 = cpu->RTC_Ticks;
|
||||
// printf("Run syscall: RTC_GetTicks %d\n", R0);
|
||||
}
|
||||
|
||||
// https://bible.planet-casio.com/simlo/chm/v20/fx_legacy_Sleep.HTM
|
||||
void syscall_OS_inner_Sleep(cpu_t* cpu, uint32_t ms) {
|
||||
#ifdef USE_EMSCRIPT
|
||||
emscripten_sleep(ms * .75);
|
||||
#endif
|
||||
// printf("Run syscall: OS_inner_Sleep %d\n", ms);
|
||||
}
|
||||
|
||||
#ifdef USE_EMSCRIPT
|
||||
EM_ASYNC_JS(int, async_browser_getkey, (), {
|
||||
return await new Promise((resolve, reject) => {
|
||||
const onClick = (event) => {
|
||||
const res = window.keyboardEvent(event, 'getkey');
|
||||
if (res != null) {
|
||||
document.getElementById("keyboard").removeEventListener("click", onClick);
|
||||
resolve(res);
|
||||
}
|
||||
};
|
||||
document.getElementById("keyboard").addEventListener("click", onClick);
|
||||
});
|
||||
})
|
||||
#else
|
||||
int async_browser_getkey() {
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
void syscall_GetKey(cpu_t* cpu, unsigned int keycode_address) {
|
||||
printf("Run syscall: GetKey\n");
|
||||
|
||||
int key = async_browser_getkey();
|
||||
|
||||
mem_write(cpu, keycode_address, key, 4);
|
||||
|
||||
R0 = key;
|
||||
}
|
|
@ -0,0 +1,199 @@
|
|||
#include "../headers/syscalls/print.h"
|
||||
|
||||
// These functions clear the specified area of VRAM and/or DD (Display Driver).
|
||||
|
||||
void syscall_Bdisp_AllClr_DD(cpu_t* cpu) {
|
||||
// Does nothing for now
|
||||
}
|
||||
|
||||
void syscall_Bdisp_AllClr_VRAM(cpu_t* cpu) {
|
||||
for (int i = 0; i < VRAM_SIZE; i++) {
|
||||
cpu->disp->vram[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void syscall_Bdisp_AllClr_DDVRAM(cpu_t* cpu) {
|
||||
printf("Run syscall: Bdisp_AllClr_DDVRAM\n");
|
||||
syscall_Bdisp_AllClr_DD(cpu);
|
||||
syscall_Bdisp_AllClr_VRAM(cpu);
|
||||
}
|
||||
|
||||
void syscall_Bdisp_PutDisp_DD(cpu_t* cpu) {
|
||||
// printf("Run syscall: Bdisp_PutDisp_DD\n");
|
||||
#ifdef USE_EMSCRIPT
|
||||
EM_ASM({
|
||||
window.refreshScreen();
|
||||
});
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* Set or erase a dot at the specified position of VRAM and/or DD (Display Driver).
|
||||
* @param x (0~127) This is the x coordinate of the specified position.
|
||||
* @param y (0~63) This is the y coordinate of the specified position.
|
||||
* @param point If you set point to 1 then the dot is made black. If you set point to 0 then the dot is cleared.
|
||||
*/
|
||||
void syscall_Bdisp_SetPoint_VRAM(cpu_t* cpu, uint32_t x, uint32_t y, uint32_t point) {
|
||||
uint32_t vramID = x/8 + y * 16;
|
||||
uint8_t bit = 7 - x % 8; // Current bit
|
||||
cpu->disp->vram[vramID] = (cpu->disp->vram[vramID] & ~(1 << bit)) | (point << bit);
|
||||
|
||||
// printf("Run syscall: Bdisp_SetPoint_VRAM (%d, %d, %d)\n", x, y, point);
|
||||
}
|
||||
|
||||
// Sets the position of the display cursor
|
||||
// x: [1-21], y: [1-8]
|
||||
void syscall_Locate(cpu_t* cpu, int x, int y) {
|
||||
cpu->disp->cursor.col = x;
|
||||
cpu->disp->cursor.row = y;
|
||||
printf("Run syscall: locate (%d %d)\n", x, y);
|
||||
}
|
||||
|
||||
#define MINI_OVER 0
|
||||
#define MINI_OR 1
|
||||
#define MINI_REV 2
|
||||
#define MINI_REVOR 3
|
||||
void draw_character_mini(cpu_t* cpu, const char c, int pixel_start_x, int pixel_start_y, int mode) {
|
||||
// Character x,y in ASCII texture (16x16)
|
||||
int char_x = c / 16;
|
||||
int char_y = c % 16;
|
||||
|
||||
if (char_x < 0 || char_x >= 16 || char_y < 0) return;
|
||||
|
||||
// Pixel start x, y in ASCII texture (128x128)
|
||||
char_x = char_x * 7;
|
||||
char_y = char_y * 7;
|
||||
|
||||
for (int y = 0; y < 6; y++) {
|
||||
for (int x = 0; x < 6; x++) {
|
||||
// Current pixel position in ASCII texture
|
||||
int ascii_x = char_x + x;
|
||||
int ascii_y = char_y + y;
|
||||
int ascii_id = ascii_x + ascii_y * 128; // Pixel index
|
||||
if (ascii_id < 0 || ascii_id >= 128 * 128) break;
|
||||
|
||||
// Current pixel position on-screen
|
||||
int vram_x = pixel_start_x + x;
|
||||
int vram_y = pixel_start_y + y;
|
||||
int vram_id = (vram_x + vram_y * SCREEN_WIDTH) / 8; // index in VRAM
|
||||
if (vram_id < 0 || vram_id >= VRAM_SIZE) break;
|
||||
|
||||
int ascii_pixel = cpu->printMiniTexture[ascii_id]; // Pixel value
|
||||
int vram_bit = 7 - vram_x % 8; // Current bit
|
||||
int vram_pixel = (cpu->disp->vram[vram_id] >> (vram_bit)) & 1;
|
||||
|
||||
// Change one single bit in the VRAM
|
||||
if (mode == MINI_OVER)
|
||||
cpu->disp->vram[vram_id] = (cpu->disp->vram[vram_id] & ~(1 << vram_bit)) | (ascii_pixel << vram_bit);
|
||||
else if (mode == MINI_OR)
|
||||
cpu->disp->vram[vram_id] = (cpu->disp->vram[vram_id] & ~(1 << vram_bit)) | ((ascii_pixel | vram_pixel) << vram_bit);
|
||||
else if (mode == MINI_REV)
|
||||
cpu->disp->vram[vram_id] = (cpu->disp->vram[vram_id] & ~(1 << vram_bit)) | ((1 - ascii_pixel) << vram_bit);
|
||||
else
|
||||
// cpu->disp->vram[vram_id] = (cpu->disp->vram[vram_id] & ~(1 << vram_bit)) | (ascii_pixel|vram_pixel) << vram_bit; // MINI OR
|
||||
printf("[Warning] PrintMiniSd: mode not implemented: %d\n", mode);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void syscall_PrintMiniSd(cpu_t* cpu, int x, int y, uint32_t str_ptr, int mode) {
|
||||
const char* str = (const char*)get_memory_for_address(cpu, str_ptr);
|
||||
// printf("Run syscall: PrintMiniSd (%d %d %s %d)\n", x, y, str, mode);
|
||||
|
||||
mode = mode & 3; // Only keep the first 2 bits
|
||||
|
||||
int i = 0;
|
||||
while (x < SCREEN_WIDTH) {
|
||||
const char c = str[i++]; // Current character
|
||||
|
||||
if (c == 0x00) break; // Line terminator
|
||||
|
||||
draw_character_mini(cpu, c, x, y, mode);
|
||||
|
||||
// Move the cursor the the right
|
||||
if (c == 'i') x += 2;
|
||||
else if (c == 'n' || c == 'r' || c == 'K') x += 5;
|
||||
else if (c == 'm' || c == 'w' || c == 'M' || c == 'N' || c == 'W') x += 6;
|
||||
else x += 4;
|
||||
}
|
||||
}
|
||||
|
||||
// Draw a character on screen
|
||||
// pixel_start_x and y represent the top left pixel of the character
|
||||
void draw_character(cpu_t* cpu, const char c, int pixel_start_x, int pixel_start_y, int mode) {
|
||||
int offset = c - 0x0020;
|
||||
|
||||
// Character x,y in ASCII texture (16x16)
|
||||
int char_x = offset % 16;
|
||||
int char_y = offset / 16;
|
||||
// Pixel start x, y in ASCII texture (112x54)
|
||||
char_x = char_x * ASCII_CHAR_WIDTH;
|
||||
char_y = char_y * ASCII_CHAR_HEIGHT;
|
||||
|
||||
for (int y = 0; y < ASCII_CHAR_HEIGHT; y++) {
|
||||
for (int x = 0; x < ASCII_CHAR_WIDTH; x++) {
|
||||
// Current pixel position in ASCII texture
|
||||
int ascii_x = char_x + x;
|
||||
int ascii_y = char_y + y;
|
||||
int ascii_id = ascii_x + ascii_y * 112; // Pixel index
|
||||
|
||||
if (ascii_id < 0 || ascii_id >= 112 * 54) break; // critical_error("ASCII Texture Access out of bounds: %d %d (%d)", ascii_x, ascii_y, ascii_id);
|
||||
|
||||
// Current pixel position on-screen
|
||||
int vram_x = pixel_start_x + x;
|
||||
int vram_y = pixel_start_y + y;
|
||||
int vram_id = (vram_x + vram_y * SCREEN_WIDTH) / 8; // index in VRAM
|
||||
int vram_bit = 7 - vram_x % 8; // Current bit
|
||||
|
||||
if (vram_id < 0 || vram_id >= VRAM_SIZE) break; // critical_error("VRAM Access out of bounds: %d %d (%d)", vram_x, vram_y, vram_id);
|
||||
|
||||
// Change one single bit in the VRAM
|
||||
int ascii_bit = cpu->asciiTexture[ascii_id] ^ mode; // Pixel value
|
||||
|
||||
// TODO: Add modes
|
||||
if (ascii_bit)
|
||||
cpu->disp->vram[vram_id] = (cpu->disp->vram[vram_id] & ~(1 << vram_bit)) | (ascii_bit << vram_bit);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Display a string at the current position of the display cursor
|
||||
void syscall_Print(cpu_t* cpu, uint32_t str_ptr) {
|
||||
const char* str = (const char*)get_memory_for_address(cpu, str_ptr);
|
||||
// printf("Run syscall: syscall_Print (%s)\n", str);
|
||||
|
||||
int i = 0;
|
||||
while(cpu->disp->cursor.col < 21) {
|
||||
const char c = str[i++]; // Current character
|
||||
|
||||
if (c == 0x00) break; // Line terminator
|
||||
|
||||
// Character x,y on screen (21x7)
|
||||
int screen_x = cpu->disp->cursor.col;
|
||||
int screen_y = cpu->disp->cursor.row;
|
||||
// Pixel start x,y on screen (128x64)
|
||||
screen_x = screen_x * CHAR_WIDTH + 1;
|
||||
screen_y = screen_y * CHAR_HEIGHT;
|
||||
|
||||
draw_character(cpu, c, screen_x, screen_y, 0);
|
||||
|
||||
// Move the cursor the the right
|
||||
cpu->disp->cursor.col++;
|
||||
}
|
||||
}
|
||||
|
||||
void syscall_PrintXY(cpu_t* cpu, int x, int y, uint32_t str_ptr, int mode) {
|
||||
const char* str = (const char*)get_memory_for_address(cpu, str_ptr);
|
||||
// printf("Run syscall: syscall_PrintXY (%d %d %s %d)\n", x, y, str, mode);
|
||||
|
||||
int i = 0;
|
||||
while (x < SCREEN_WIDTH) {
|
||||
const char c = str[i++]; // Current character
|
||||
|
||||
if (c == 0x00) break; // Line terminator
|
||||
|
||||
draw_character(cpu, c, x, y, mode);
|
||||
|
||||
x += CHAR_WIDTH; // Move the cursor the the right
|
||||
}
|
||||
}
|
|
@ -0,0 +1,70 @@
|
|||
#include "../headers/syscalls/syscalls.h"
|
||||
|
||||
// Syscall entry point
|
||||
void run_syscall(cpu_t* cpu) {
|
||||
uint32_t syscall_code = R0;
|
||||
|
||||
int arg1 = cpu->r[4];
|
||||
int arg2 = cpu->r[5];
|
||||
int arg3 = cpu->r[6];
|
||||
int arg4 = cpu->r[7];
|
||||
|
||||
if (syscall_code == 0x135) syscall_GetVRAMAddress(cpu);
|
||||
else if (syscall_code == 0x144) syscall_Bdisp_AllClr_DDVRAM(cpu);
|
||||
else if (syscall_code == 0x028) syscall_Bdisp_PutDisp_DD(cpu);
|
||||
else if (syscall_code == 0x146) syscall_Bdisp_SetPoint_VRAM(cpu, arg1, arg2, arg3);
|
||||
else if (syscall_code == 0x807) syscall_Locate(cpu, arg1, arg2);
|
||||
else if (syscall_code == 0x808) syscall_Print(cpu, arg1);
|
||||
else if (syscall_code == 0x9AD) syscall_PrintXY(cpu, arg1, arg2, arg3, arg4);
|
||||
else if (syscall_code == 0xC4F) syscall_PrintMiniSd(cpu, arg1, arg2, arg3, arg4);
|
||||
|
||||
else if (syscall_code == 0xACD) syscall_Malloc(cpu, arg1, 0);
|
||||
else if (syscall_code == 0xE6B) syscall_Malloc(cpu, arg1, 1); // Calloc
|
||||
else if (syscall_code == 0xE6D) syscall_Realloc(cpu, arg1, arg2);
|
||||
else if (syscall_code == 0xACC) syscall_Free(cpu, arg1);
|
||||
|
||||
else if (syscall_code == 0x462) syscall_GetAppName(cpu, arg1);
|
||||
else if (syscall_code == 0x014) syscall_GlibGetAddinLibInf(cpu, arg1, arg2, arg3);
|
||||
else if (syscall_code == 0x015) syscall_GlibGetOSVersionInfo(cpu, arg1, arg2, arg3, arg4);
|
||||
else if (syscall_code == 0x90F) syscall_GetKey(cpu, arg1);
|
||||
else if (syscall_code == 0x03B) syscall_RTC_GetTicks(cpu);
|
||||
else if (syscall_code == 0x420) syscall_OS_inner_Sleep(cpu, arg1);
|
||||
|
||||
else if (syscall_code == 0x434) syscall_Bfile_CreateEntry(cpu, arg1, arg2, arg3);
|
||||
else if (syscall_code == 0x439) syscall_Bfile_DeleteEntry(cpu, arg1, arg2);
|
||||
else if (syscall_code == 0x42C) syscall_Bfile_OpenFile(cpu, arg1, arg2, arg3);
|
||||
else if (syscall_code == 0x42D) syscall_Bfile_CloseFile(cpu, arg1);
|
||||
else if (syscall_code == 0x435) syscall_Bfile_WriteFile(cpu, arg1, arg2, arg3);
|
||||
else if (syscall_code == 0x432) syscall_Bfile_ReadFile(cpu, arg1, arg2, arg3, arg4);
|
||||
else if (syscall_code == 0x431) syscall_Bfile_SeekFile(cpu, arg1, arg2);
|
||||
else if (syscall_code == 0x43B) { // Bfile_FindFirst
|
||||
printf("Skipped syscall: Bfile_FindFirst\n");
|
||||
}
|
||||
// else if (syscall_code == 0x840) syscall_MCSGetDlen2(cpu, arg1, arg2, arg3);
|
||||
// else if (syscall_code == 0x841) syscall_MCSGetData1(cpu, arg1, arg2, arg3);
|
||||
// else if (syscall_code == 0x82B) syscall_MCSPutVar2(cpu, arg1, arg2, arg3, arg4);
|
||||
// else if (syscall_code == 0x830) syscall_MCSOvwDat2(cpu, arg1, arg2, arg3, arg4, cpu->r[15]);
|
||||
|
||||
else if (syscall_code == 0x24C) { // Keyboard_IsSpecialKeyDown
|
||||
printf("Skipped syscall: Keyboard_IsSpecialKeyDown\n");
|
||||
}
|
||||
else if (syscall_code == 0x3ED) { // Interrupt_SetOrClrStatusFlags
|
||||
// https://bible.planet-casio.com/simlo/chm/v20/fx_legacy_INTERRUPT.HTM
|
||||
printf("[Error] Blocking syscall not implemented: Interrupt_SetOrClrStatusFlags 0x%X\n", arg2);
|
||||
}
|
||||
// Can be ignored
|
||||
else if (syscall_code == 0x494) { // void SetQuitHandler( void (*callback)(void) );
|
||||
printf("Ignored syscall: SetQuitHandler\n");
|
||||
}
|
||||
else if (syscall_code == 0x013) { // GlibAddinAplExecutionCheck
|
||||
printf("Ignored syscall: GlibAddinAplExecutionCheck\n");
|
||||
}
|
||||
else if (syscall_code == 0x3FA) { // Hmem_SetMMU
|
||||
printf("Ignored syscall: Hmem_SetMMU\n");
|
||||
}
|
||||
else {
|
||||
printf("[Warning] Syscall not implemented, skipping: 0x%03X\n", syscall_code);
|
||||
}
|
||||
|
||||
cpu->pc = cpu->pr;
|
||||
}
|
|
@ -68,21 +68,24 @@ void cpu_debug(cpu_t* cpu) {
|
|||
uint8_t low = instruction & 0x0F;
|
||||
uint8_t low8 = instruction & 0xFF;
|
||||
|
||||
printf("[%d][0x%08X] instruction: 0x%04X -", cpu->instruction_count, cpu->pc, instruction);
|
||||
printf("[%d][0x%08X] instruction: %s 0x%04X -", cpu->instruction_count, cpu->pc, get_instruction_name(instruction), instruction);
|
||||
print_binary(instruction, 16);
|
||||
print_binary(high, 4);
|
||||
print_binary(low, 4);
|
||||
// print_binary(high, 4);
|
||||
// print_binary(low, 4);
|
||||
printf("\n");
|
||||
}
|
||||
else printf("[%d][0x%08X] instruction: syscall\n", cpu->instruction_count, cpu->pc);
|
||||
|
||||
for (int i = 0; i < 16; i++) {
|
||||
int r = cpu->r[i];
|
||||
if (r != 0)
|
||||
printf("r%d: 0x%08X, ", i, r);
|
||||
}
|
||||
// for (int i = 0; i < 16; i++) {
|
||||
// int r = cpu->r[i];
|
||||
// if (r != 0)
|
||||
// printf("r%d: 0x%08X, ", i, r);
|
||||
// }
|
||||
|
||||
printf("pr: 0x%08X, cursor: %d-%d, T: %d\n", cpu->pr, cpu->disp->cursor.col, cpu->disp->cursor.row, (cpu->sr >> 31) & 1);
|
||||
// printf("pr: 0x%08X, cursor: %d-%d, T: %d\n", cpu->pr, cpu->disp->cursor.col, cpu->disp->cursor.row, (cpu->sr >> 31) & 1);
|
||||
// printf("pr: 0x%08X\n", cpu->pr);
|
||||
// print_binary(cpu->sr, 32);
|
||||
// printf("\n");
|
||||
// printf("pr: 0x%08X, macl: 0x%08X, gbr: 0x%08X, T: %d\n", cpu->pr, cpu->macl, cpu->gbr, cpu->disp->cursor.col, cpu->disp->cursor.row, (cpu->sr >> 31) & 1);
|
||||
// printf("mem: 0x%02X 0x%02X 0x%02X 0x%02X\n", mem_read(cpu, 0x00300670, 1), mem_read(cpu, 0x00300670 + 1, 1), mem_read(cpu, 0x00300670 + 2, 1), mem_read(cpu, 0x00300670 + 3, 1));
|
||||
}
|
||||
|
@ -102,4 +105,22 @@ void vram_debug(cpu_t* cpu) {
|
|||
printf("\n");
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
// Debug function called from javascript
|
||||
char* get_next_instruction(cpu_t* cpu) {
|
||||
if (cpu->pc == cpu->pr) return "<EOF>";
|
||||
if (cpu->pc == SYSCALL_ADDRESS) return "<syscall>";
|
||||
|
||||
uint16_t instruction = (mem_read(cpu, cpu->pc, 1) << 8) | mem_read(cpu, cpu->pc + 1, 1);
|
||||
char* instruction_name = calloc(64, sizeof(char));
|
||||
|
||||
strcpy(instruction_name, get_instruction_name(instruction));
|
||||
strcat(instruction_name, " 0x");
|
||||
char* instruction_hex = calloc(5, sizeof(char));
|
||||
sprintf(instruction_hex, "%04X", instruction);
|
||||
strcat(instruction_name, instruction_hex);
|
||||
free(instruction_hex);
|
||||
|
||||
return instruction_name;
|
||||
}
|
Loading…
Reference in New Issue