diff --git a/JJSH3.g1a b/JJSH3.g1a deleted file mode 100644 index c597819..0000000 Binary files a/JJSH3.g1a and /dev/null differ diff --git a/fx9860-emulator/headers/display.h b/fx9860-emulator/headers/display.h index 47aa1d2..2b2d866 100644 --- a/fx9860-emulator/headers/display.h +++ b/fx9860-emulator/headers/display.h @@ -7,9 +7,13 @@ #define SCREEN_HEIGHT 64 // VRAM Size & Address -#define VRAM_SIZE (SCREEN_WIDTH * SCREEN_HEIGHT / 8) // 1024 for 128*64 monochrome -#define VRAM_ADDRESS (RAM_ADDRESS_P1 + RAM_SIZE + 2048) // Arbitrary address relative to start of RAM (TODO: check if correct) - +// 1024 for 128*64 monochrome +// + 1 to prevent out of bounds access on Gravity Duck +#define VRAM_SIZE (SCREEN_WIDTH * SCREEN_HEIGHT / 8 + 1) +// Arbitrary address relative to start of RAM +// + needs to be un-aligned (+1) for correct behavior with MonochromeLib +#define VRAM_ADDRESS (RAM_ADDRESS_P1 + RAM_SIZE + 2048 + 1) + // LCD registers addresses #define LCD_SELECT_REGISTER 0xB4000000 #define LCD_DATA_REGISTER 0xB4010000 @@ -37,7 +41,7 @@ typedef struct { int8_t col; // starts at 1 int8_t row; // starts at 1 - int16_t flash_style; // -1 if not flashing + int16_t flash_style; // flashing icon style int8_t flash_mode; // 0: no flashing cursor, 1: flashing cursor int8_t blink_state; // (used when cursor is flashing) 0: not visible, 1: visible } cursor_t; diff --git a/fx9860-emulator/headers/syscalls/bdisp.h b/fx9860-emulator/headers/syscalls/bdisp.h index 6a03373..7ad9543 100644 --- a/fx9860-emulator/headers/syscalls/bdisp.h +++ b/fx9860-emulator/headers/syscalls/bdisp.h @@ -9,6 +9,11 @@ #define IMB_WRITEMODIFY_NORMAL 0x01 #define IMB_WRITEMODIFY_REVERSE 0x02 +#define IMB_WRITEKIND_OVER 0x01 +#define IMB_WRITEKIND_OR 0x02 +#define IMB_WRITEKIND_AND 0x03 +#define IMB_WRITEKIND_XOR 0x04 + void syscall_Bdisp_AllClr_DD(cpu_t* cpu); void syscall_Bdisp_AllClr_VRAM(cpu_t* cpu); void syscall_Bdisp_AllClr_DDVRAM(cpu_t* cpu); diff --git a/fx9860-emulator/headers/syscalls/filesystem.h b/fx9860-emulator/headers/syscalls/filesystem.h index 7e57134..1252d65 100644 --- a/fx9860-emulator/headers/syscalls/filesystem.h +++ b/fx9860-emulator/headers/syscalls/filesystem.h @@ -50,6 +50,8 @@ struct fs_t { // MCS Handle const char* mcs_filename; int32_t mcs_filesize; + + uint8_t needs_sync; // Tells javascript to persist the files to the local storage }; // https://bible.planet-casio.com/simlo/chm/v20/fx_legacy_Bfile.htm diff --git a/fx9860-emulator/headers/syscalls/keyboard.h b/fx9860-emulator/headers/syscalls/keyboard.h index 5d32e8c..17a8b4a 100644 --- a/fx9860-emulator/headers/syscalls/keyboard.h +++ b/fx9860-emulator/headers/syscalls/keyboard.h @@ -9,7 +9,11 @@ #define KB_PORTB 0xA4000122 #define KB_PORTM 0xA4000138 #define KB_SIZE (0xA4000138 - 0xA4000102 + 1) // Max - min address + 1 (insclusive) -#define KB_START KB_PORTB_CTRL +#define KB_ADDRESS KB_PORTB_CTRL + +// Keyboard register addresses (SH4-specific) +#define KEYSC_ADDRESS 0xA44B0000 +#define KEYSC_SIZE (6 * 2) // GetKey codes #define KEY_EXIT 30002 @@ -23,7 +27,7 @@ #define DEFAULT_REPEAT_TIME_NEXT_COUNT 5 struct keyboard_t { - uint8_t row_state[10]; // Keyboard rows state (1 = key not pressed) + uint8_t row_state[10]; // Keyboard rows state uint8_t keyboard_registers[KB_SIZE]; // Keyboard registers // Buffered keys that are waiting to be read diff --git a/fx9860-emulator/headers/syscalls/malloc.h b/fx9860-emulator/headers/syscalls/malloc.h index 2663bca..a077a54 100644 --- a/fx9860-emulator/headers/syscalls/malloc.h +++ b/fx9860-emulator/headers/syscalls/malloc.h @@ -2,8 +2,8 @@ #include "syscalls.h" -#define MALLOC_START 0x22220000 -#define MALLOC_SIZE (128 * 1024) +#define MALLOC_ADDRESS 0x22220000 +#define MALLOC_SIZE (256 * 1024) // Ugly malloc manager that works for testing struct malloc_manager_t { diff --git a/fx9860-emulator/headers/syscalls/text.h b/fx9860-emulator/headers/syscalls/text.h index d948aa3..c0a16dc 100644 --- a/fx9860-emulator/headers/syscalls/text.h +++ b/fx9860-emulator/headers/syscalls/text.h @@ -24,6 +24,7 @@ void syscall_Locate(cpu_t* cpu, int x, int y); void syscall_Cursor_SetPosition(cpu_t* cpu, uint32_t column, uint32_t row); void syscall_Cursor_GetFlashStyle(cpu_t* cpu); void syscall_Cursor_SetFlashOn(cpu_t* cpu, uint32_t flash_style); +void syscall_Cursor_SetFlashOff(cpu_t* cpu); void syscall_Cursor_SetFlashMode(cpu_t* cpu, uint32_t flashmode); void draw_cursor(cpu_t* cpu); \ No newline at end of file diff --git a/fx9860-emulator/main.c b/fx9860-emulator/main.c index 892ee5e..d11f213 100644 --- a/fx9860-emulator/main.c +++ b/fx9860-emulator/main.c @@ -62,7 +62,6 @@ display_t* init_display(memory_t* memory) { // Init cursor disp->cursor.row = 1; disp->cursor.col = 1; - disp->cursor.flash_style = -1; // Init useful SDK data load_data_file("CharacterSet.data", CHARACTER_SET_SIZE, disp->character_set); @@ -92,7 +91,6 @@ cpu_t* init_cpu(memory_t* mem, display_t* disp) { cpu->keyboard = calloc(1, sizeof(keyboard_t)); cpu->keyboard->repeat_time_first = DEFAULT_REPEAT_TIME_FIRST_COUNT; cpu->keyboard->repeat_time_next = DEFAULT_REPEAT_TIME_NEXT_COUNT; - for (int i = 0; i < 10; i++) cpu->keyboard->row_state[i] = 0xFF; cpu->malloc_manager = calloc(1, sizeof(malloc_manager_t)); cpu->malloc_manager->mallocs = malloc(MALLOC_SIZE * sizeof(int8_t)); @@ -183,7 +181,8 @@ void init_loop_html(cpu_t* cpu) { window.instructionPerFrame = $3; window.instructionCount = $4; window.rtcTicksPointer = $5; - window.cpuPointer = $6; + window.fsNeedsSyncPointer = $6; + window.cpuPointer = $7; }, &cpu->disp->vram, &cpu->disp->lcd, @@ -191,6 +190,7 @@ void init_loop_html(cpu_t* cpu) { &cpu->instruction_per_frame, &cpu->instruction_count, &cpu->RTC_Ticks, + &cpu->fs->needs_sync, cpu ); @@ -216,6 +216,7 @@ void reset_execution(cpu_t* cpu) { for (int i = 0; i < VRAM_SIZE; i++) { cpu->disp->vram[i] = 0; + cpu->disp->lcd[i] = 0; } free(cpu->fs); @@ -223,6 +224,10 @@ void reset_execution(cpu_t* cpu) { cpu->malloc_manager->currentSize = 0; cpu->malloc_manager->mallocCount = 0; + + cpu->disp->cursor.row = 1; + cpu->disp->cursor.col = 1; + cpu->disp->cursor.flash_mode = 0; } void load_new_g1a(cpu_t* cpu, uint8_t* g1a_content, uint32_t g1a_size) { diff --git a/fx9860-emulator/memory.c b/fx9860-emulator/memory.c index f134c54..3d05627 100644 --- a/fx9860-emulator/memory.c +++ b/fx9860-emulator/memory.c @@ -20,9 +20,8 @@ uint8_t* get_memory_for_address(cpu_t* cpu, uint32_t address) { if (check_memory_bounds(address, RAM_ADDRESS_P1, RAM_SIZE, cpu->mem->ram, &memory)) return memory; if (check_memory_bounds(address, RAM_ADDRESS_P2, RAM_SIZE, cpu->mem->ram, &memory)) return memory; if (check_memory_bounds(address, VRAM_ADDRESS, VRAM_SIZE, cpu->disp->vram, &memory)) return memory; - if (check_memory_bounds(address, VRAM_ADDRESS + VRAM_SIZE, 1, cpu->disp->vram, &memory)) return memory; // TODO: Check why Gravity Duck crash without this 1025th/1024 byte - if (check_memory_bounds(address, KB_START, KB_SIZE, cpu->keyboard->keyboard_registers, &memory)) return memory; - if (check_memory_bounds(address, MALLOC_START, MALLOC_SIZE, cpu->malloc_manager->mallocs, &memory)) return memory; + if (check_memory_bounds(address, KB_ADDRESS, KB_SIZE, cpu->keyboard->keyboard_registers, &memory)) return memory; + if (check_memory_bounds(address, MALLOC_ADDRESS, MALLOC_SIZE, cpu->malloc_manager->mallocs, &memory)) return memory; if (check_memory_bounds(address, FKEYICON_ADDRESS, FKEYICON_SIZE, cpu->disp->fkey_icons, &memory)) return memory; if (check_memory_bounds(address, 0xFFFFFE00, 511, cpu->mem->tmp, &memory)) { printf("[Warning] Access to interrupt registers at 0x%08X\n", address); @@ -62,10 +61,22 @@ void mem_write(cpu_t* cpu, uint32_t address, uint32_t data, uint8_t bytes) { // Read from the memory uint32_t mem_read(cpu_t* cpu, uint32_t address, uint8_t bytes) { - // Keyboard output register + // SH3 keyboard emulation if (address == KB_PORTA) { return emulate_keyboard_register_read(cpu); } + // SH4 keyboard emulation + else if (address >= KEYSC_ADDRESS && address < KEYSC_ADDRESS + KEYSC_SIZE) { + int row = address - KEYSC_ADDRESS; + int val; + + if (bytes == 1) + val = cpu->keyboard->row_state[row + (row % 2 == 0 ? 1 : -1)]; + else + val = cpu->keyboard->row_state[row] | (cpu->keyboard->row_state[row+1] << 8); + + return val; + } // Address that stores the model of the calculator (0 for emulator) else if (address == 0x80000300) { return 0; @@ -123,37 +134,49 @@ uint32_t emulate_keyboard_register_read(cpu_t* cpu) { } else { // printf("Keyboard row %d: 0x%08X\n", row, cpu->keyboard->row_state[row]); - return cpu->keyboard->row_state[row]; + return ~cpu->keyboard->row_state[row]; } } -// Keep track of current row and column set in the LCD selector register -// and write data to the LCD buffer. -// Refresh the HTML canvas when the last row is written. -// Works well for MonochromeLib's DisplayVRAM() function, but might -// not work for more specific register accesses. +// Emulate register selection and data write to the LCD screen +// Register 1: Set counter (Graph 35+) +// Register 4/8: Set row (Graph 35+/35+eII) +// Register 6: Set contrast (Graph 35+) +// Register 7/10: Write data (Graph 35+/35+eII) +// https://bible.planet-casio.com/common/hardware/lcd/T6K11.pdf void emulate_lcd_register_write(cpu_t* cpu, uint32_t address, uint32_t data) { - static int row = -1; + static int selected_register = 0; static int col = 0; - static int write_data = 0; + static int row = 0; - // Setup LCD row + // Register selection if (address == LCD_SELECT_REGISTER) { - if (data == 7) { // New row - write_data = 1; - col = 0; - if (++row >= 64) row = 0; - // printf("Set row: %d\n", row); + selected_register = data; + + if (data != 1 && data != 4 && data != 6 && data != 7 && data != 8 && data != 10) { + printf("[Warning] write to LCD_SELECT_REGISTER %d not implemented\n", data); } - else { - write_data = 0; - } - // printf("LCD_SELECT_REGISTER Write: 0x%08X, set row: %d\n", data, row); } - // Write data to LCD row - else if (address == LCD_DATA_REGISTER) { - if (write_data) { - cpu->disp->lcd[row * 16 + col++] = data; // Update LCD buffer + // Data write + else if (address == LCD_DATA_REGISTER) { + // Graph 35+ (4), Graph 35+ E II (8) + if (selected_register == 4 || selected_register == 8) { + static int counter = 1; + if (counter) { + // Set new row + col = 0; + row = data & 0x3F; + } + counter = !counter; + } + // Graph 35+ (7), Graph 35+ E II (10) + else if (selected_register == 7 || selected_register == 10) { + if (row * 16 + col >= VRAM_SIZE) { + printf("[Warning] LCD_DATA_REGISTER write to invalid position col: %d, row: %d\n", col, row); + return; + } + // Write row to LCD buffer + cpu->disp->lcd[row * 16 + col++] = data; } } } \ No newline at end of file diff --git a/fx9860-emulator/syscalls/bdisp.c b/fx9860-emulator/syscalls/bdisp.c index fc8b241..706996c 100644 --- a/fx9860-emulator/syscalls/bdisp.c +++ b/fx9860-emulator/syscalls/bdisp.c @@ -1,13 +1,5 @@ #include "../headers/syscalls/bdisp.h" -// Refresh the HTML canvas with the current -// content of the LCD buffer. -void refresh_lcd_screen() { -#ifdef USE_EMSCRIPT - EM_ASM({ window.refreshScreen(); }); -#endif -} - // Set the pixel at the specified position in the LCD buffer. void set_lcd_pixel(cpu_t* cpu, int x, int y, int pixel) { if (x < 0 || x >= SCREEN_WIDTH || y < 0 || y >= SCREEN_HEIGHT) return; @@ -22,7 +14,6 @@ void syscall_Bdisp_AllClr_DD(cpu_t* cpu) { for (int i = 0; i < VRAM_SIZE; i++) { cpu->disp->lcd[i] = 0; } - refresh_lcd_screen(); } // Clear the content of the VRAM @@ -45,11 +36,10 @@ void syscall_Bdisp_PutDisp_DD(cpu_t* cpu) { for (int i = 0; i < VRAM_SIZE; i++) { cpu->disp->lcd[i] = cpu->disp->vram[i]; } - refresh_lcd_screen(); } void syscall_Bdisp_GetDisp_VRAM(cpu_t* cpu, uint32_t data_ptr) { - printf("Run syscall: Bdisp_GetDisp_VRAM (0x%08X)\n", data_ptr); + // printf("Run syscall: Bdisp_GetDisp_VRAM (0x%08X)\n", data_ptr); uint8_t* data = get_memory_for_address(cpu, data_ptr); @@ -72,7 +62,7 @@ void syscall_Bdisp_SetPoint_VRAM(cpu_t* cpu, uint32_t x, uint32_t y, uint32_t po uint32_t vramID = x/8 + y * 16; uint8_t bit = 7 - x % 8; - cpu->disp->vram[vramID] = (cpu->disp->vram[vramID] & ~(1 << bit)) | (point << bit); + update_bit(cpu->disp->vram[vramID], bit, point); } /** @@ -130,13 +120,13 @@ void syscall_Bdisp_DrawLine_VRAM(cpu_t* cpu, uint32_t x1, uint32_t y1, uint32_t // Draws a white line to VRAM. void syscall_Bdisp_ClearLine_VRAM(cpu_t* cpu, uint32_t x1, uint32_t y1, uint32_t x2, uint32_t y2) { - printf("Run syscall: Bdisp_ClearLine_VRAM (%d %d %d %d)\n", x1, y1, x2, y2); + // printf("Run syscall: Bdisp_ClearLine_VRAM (%d %d %d %d)\n", x1, y1, x2, y2); draw_line(cpu, x1, y1, x2, y2, 0); } // Reverses the specified area of VRAM. void syscall_Bdisp_AreaReverseVRAM(cpu_t* cpu, uint32_t x1, uint32_t y1, uint32_t x2, uint32_t y2) { - printf("Run syscall: Bdisp_AreaReverseVRAM (%d %d %d %d)\n", x1, y1, x2, y2); + // printf("Run syscall: Bdisp_AreaReverseVRAM (%d %d %d %d)\n", x1, y1, x2, y2); for (int y = y1; y <= y2; y++) { for (int x = x1; x <= x2; x++) { @@ -166,7 +156,7 @@ void syscall_Bdisp_WriteGraph_VRAM(cpu_t* cpu, uint32_t graph_ptr) { uint8_t write_modify = mem_read(cpu, graph_ptr + 20, 1); uint8_t write_kind = mem_read(cpu, graph_ptr + 21, 1); - if ((write_modify != IMB_WRITEMODIFY_NORMAL && write_modify != IMB_WRITEMODIFY_REVERSE) || write_kind != 1) { + if ((write_modify != IMB_WRITEMODIFY_NORMAL && write_modify != IMB_WRITEMODIFY_REVERSE) || (write_kind != IMB_WRITEKIND_OVER && write_kind != IMB_WRITEKIND_OR)) { printf("[Warning] In syscall Bdisp_WriteGraph_VRAM: write_modify or write_kind not implemented (%d, %d)\n", write_modify, write_kind); return; } @@ -174,14 +164,23 @@ void syscall_Bdisp_WriteGraph_VRAM(cpu_t* cpu, uint32_t graph_ptr) { // printf("Run syscall: Bdisp_WriteGraph_VRAM (x: %d, y: %d, w: %d, h: %d, modify: %d, kind: %d)\n", start_x, start_y, width, height, write_modify, write_kind); uint8_t* bitmap_data = get_memory_for_address(cpu, bitmap_ptr); - + for (int y = 0; y < height; y++) { for (int x = 0; x < width; x++) { - int id = y * 8 + x; + int id = y * (width < 8 ? 8 : width) + x; int packed_id = id / 8; int bit = 7 - id % 8; int val = get_bit(bitmap_data[packed_id], bit); if (write_modify == IMB_WRITEMODIFY_REVERSE) val = !val; + + if (write_kind == IMB_WRITEKIND_OR) { + int vram_id = (y + start_y) * 16 + (x + start_x) / 8; + int vram_bit = 7 - (x + start_x) % 8; + if (vram_id < 0 || vram_id >= VRAM_SIZE) continue; + + int vram_pixel = get_bit(cpu->disp->vram[vram_id], vram_bit); + val |= vram_pixel; + } syscall_Bdisp_SetPoint_VRAM(cpu, x + start_x, y + start_y, val); } } @@ -195,7 +194,7 @@ void syscall_Bdisp_WriteGraph_VRAM(cpu_t* cpu, uint32_t graph_ptr) { void syscall_SaveDisp(cpu_t* cpu, unsigned char num) { num = num == SAVEDISP_PAGE1 ? num - 1 : num - 4; - printf("Run syscall: SaveDisp (%d)\n", num); + // printf("Run syscall: SaveDisp (%d)\n", num); memcpy(cpu->disp->saved_disps + VRAM_SIZE*num, cpu->disp->vram, VRAM_SIZE); } @@ -208,7 +207,7 @@ void syscall_SaveDisp(cpu_t* cpu, unsigned char num) { void syscall_RestoreDisp(cpu_t* cpu, unsigned char num) { num = num == SAVEDISP_PAGE1 ? num - 1 : num - 4; - printf("Run syscall: RestoreDisp (%d)\n", num); + // printf("Run syscall: RestoreDisp (%d)\n", num); memcpy(cpu->disp->vram, cpu->disp->saved_disps + VRAM_SIZE*num, VRAM_SIZE); } diff --git a/fx9860-emulator/syscalls/filesystem.c b/fx9860-emulator/syscalls/filesystem.c index 5deec80..1b5de72 100644 --- a/fx9860-emulator/syscalls/filesystem.c +++ b/fx9860-emulator/syscalls/filesystem.c @@ -1,5 +1,6 @@ #include "../headers/syscalls/filesystem.h" #include +#include const char* permanent_path(const char* filename) { char* path = malloc(sizeof(char) * (strlen(filename) + 7)); @@ -8,6 +9,17 @@ const char* permanent_path(const char* filename) { return (const char*)path; } +// Lowercase the file extension +const char* lower_extension(const char* str) { + char* new_str = strdup(str); + int ext = 0; + for (int i = 0; i < strlen(new_str); i++) { + if (new_str[i] == '.') ext = 1; + else if (ext) new_str[i] = tolower(new_str[i]); + } + return (const char*)new_str; +} + const char* convertFileName(const char* filename, int trim) { char name[40]; char ch; @@ -48,6 +60,7 @@ void syscall_Bfile_CreateEntry(cpu_t* cpu, uint32_t filename_ptr, int mode, uint fwrite(data, 1, size, file); fclose(file); + cpu->fs->needs_sync = 1; R0 = 0; // Success printf("Run syscall: Bfile_CreateEntry %s (0x%X, size: %d)\n", name, mode, mem_read(cpu, size_ptr, 4)); @@ -72,6 +85,7 @@ void syscall_Bfile_DeleteEntry(cpu_t* cpu, uint32_t filename_ptr, int mode) { const char* name = convertFileName(filename, 1); if (remove(permanent_path(name)) == 0) { + cpu->fs->needs_sync = 1; R0 = 0; // Success printf("Run syscall: Bfile_DeleteEntry %s\n", name); } @@ -84,7 +98,7 @@ void syscall_Bfile_DeleteEntry(cpu_t* cpu, uint32_t filename_ptr, int mode) { // Used by Bfile_FindFirst and Bfile_FindNext // Search an entry matching a search string starting from the specified index // Writes the entry name to foundfile_ptr and the entry infos to fileinfo_ptr -int search_file(cpu_t* cpu, const char* search_str, uint32_t foundfile_ptr, uint32_t fileinfo_ptr, int index) { +int search_file(cpu_t* cpu, const char* search_string, uint32_t foundfile_ptr, uint32_t fileinfo_ptr, int index) { // Open root directory struct dirent *dir; DIR *d = opendir("/idbfs"); @@ -97,10 +111,13 @@ int search_file(cpu_t* cpu, const char* search_str, uint32_t foundfile_ptr, uint int file_index = 0; int found_type = -1; char* found_name; + + // Lowercase the file extension + const char* search_str = lower_extension(search_string); // Loop through each file - while ((dir = readdir(d)) != NULL) { - if ((strcmp(search_str, "*.*") == 0 || strcmp(dir->d_name, search_str) == 0) && file_index >= index) { + while ((dir = readdir(d)) != NULL) { + if (((strcmp(search_str, "*.*") == 0 || strcmp(lower_extension(dir->d_name), search_str) == 0)) && file_index >= index) { // Matching file found found_type = dir->d_type; found_name = strdup(dir->d_name); @@ -385,6 +402,7 @@ void syscall_Bfile_WriteFile(cpu_t* cpu, int handle, uint32_t buf_ptr, int size) fwrite(&byte, 1, 1, file->file_handle); } + cpu->fs->needs_sync = 1; R0 = file->seek_pos; } @@ -631,6 +649,7 @@ void syscall_MCSPutVar2(cpu_t* cpu, int32_t dir_ptr, int32_t item_ptr, int32_t d fwrite(data, 1, data_len, file); fclose(file); + cpu->fs->needs_sync = 1; R0 = 0; } @@ -668,6 +687,7 @@ void syscall_MCSOvwDat2(cpu_t* cpu, int32_t dir_ptr, int32_t item_ptr, int32_t b fwrite(data + write_offset, 1, bytes_to_write, file); fclose(file); + cpu->fs->needs_sync = 1; R0 = 0; } @@ -687,6 +707,7 @@ void syscall_MCSDelVar2(cpu_t* cpu, int32_t dir_ptr, int32_t item_ptr) { // Delete file if (remove(file_path) == 0) { cpu->fs->mcs_filename = NULL; + cpu->fs->needs_sync = 1; printf("Run syscall: MCSDelVar2, deleted file %s. MCS cleared\n", file_path); R0 = 0; } @@ -736,14 +757,29 @@ void syscall_MCS_SearchDirectoryItem(cpu_t* cpu, int32_t dir_ptr, int32_t item_n // Get file size fseek(file, 0, SEEK_END); int32_t file_size = ftell(file); - fclose(file); - - mem_write(cpu, data_ptr, 0x00000000, 4); // ??? - mem_write(cpu, item_ptr, 0x00000000, 4); // ??? - mem_write(cpu, len_ptr, file_size, 4); + fseek(file, 0, SEEK_SET); printf("Run syscall: MCS_SearchDirectoryItem %s (0x%8X, 0x%8X, 0x%8X, 0x%8X) => %d\n", item_path, flags_ptr, item_ptr, data_ptr, len_ptr, file_size); + // TODO: Improve this (quick hack) + static int mcs_storage = 0; + if (mcs_storage == 0) { + syscall_Malloc(cpu, 32 * 1024, 0); + mcs_storage = R0; + } + + for (int i = 0; i < file_size; i++) { + uint8_t byte; + fread(&byte, 1, 1, file); + mem_write(cpu, mcs_storage + i, byte, 1); + } + + fclose(file); + + mem_write(cpu, data_ptr, mcs_storage, 4); + mem_write(cpu, item_ptr, 0x000000bb, 4); // ??? + mem_write(cpu, len_ptr, file_size, 4); + R0 = 0; } @@ -755,9 +791,41 @@ void syscall_MCS_SearchDirectoryItem(cpu_t* cpu, int32_t dir_ptr, int32_t item_n void syscall_MCS_OverwriteData(cpu_t* cpu, int32_t dir_ptr, int32_t item_ptr, int32_t write_offset, int32_t bytes_to_write, int32_t buffer_ptr) { const char* item_path = getFilePath(cpu, dir_ptr, item_ptr); - printf("[Warning]: Skipped syscall MCS_OverwriteData %s (offset: %d, bytes: %d, buffer: 0x%8X)\n", item_path, write_offset, bytes_to_write, buffer_ptr); + printf("[Warning]: Run syscall MCS_OverwriteData %s (offset: %d, bytes: %d, buffer: 0x%8X)\n", item_path, write_offset, bytes_to_write, buffer_ptr); - R0 = 0x13; + FILE* file = fopen(item_path, "rb"); + + if (file == NULL) { + printf("[Warning] In syscall MCS_OverwriteData: File does not exist: %s\n", item_path); + R0 = 0x40; + return; + } + + // Get file size + fseek(file, 0, SEEK_END); + int32_t file_size = ftell(file); + fclose(file); + + if (write_offset + bytes_to_write > file_size) { + printf("[Warning] In syscall MCS_OverwriteData: Write offset + bytes to write exceeds file size: %s\n", item_path); + R0 = bytes_to_write > file_size ? 0x13 : 0x14; + return; + } + + // Open file for writing + file = fopen(item_path, "wb"); + fseek(file, write_offset, SEEK_SET); + + for (int i = 0; i < bytes_to_write; i++) { + uint8_t byte = mem_read(cpu, buffer_ptr + i, 1); + fwrite(&byte, 1, 1, file); + } + fclose(file); + + // fwrite(get_memory_for_address(cpu, buffer_ptr) + write_offset, 1, bytes_to_write, file); + + cpu->fs->needs_sync = 1; + R0 = 0; } // Deletes dir.item. diff --git a/fx9860-emulator/syscalls/keyboard.c b/fx9860-emulator/syscalls/keyboard.c index 6442ab1..c871c65 100644 --- a/fx9860-emulator/syscalls/keyboard.c +++ b/fx9860-emulator/syscalls/keyboard.c @@ -44,19 +44,29 @@ EM_ASYNC_JS(int*, async_browser_getkey, (), { // Used to resolve the promise when loading a new .g1a file (blocking otherwise) window.getkeyEventResolve = resolve; - const onClick = (event) => { - const res = window.keyboardEvent(event, 'getkey'); - - if (res != null) { - // Valid key pressed, remove the event listener and return the key - document.getElementById("keyboard").removeEventListener("pointerdown", onClick); + const try_resolve_key = (key) => { + if (key != null) { + // Valid key pressed, remove the event listeners and return the key + window.removeEventListener("keydown", onKeyboardEvent); + document.getElementById("keyboard").removeEventListener("pointerdown", onClickEvent); window.getkeyEventResolve = null; - resolve(res); + resolve(key); } }; + const onClickEvent = (event) => { + const res = window.handleKeyboardEvent(event, "getkey"); + try_resolve_key(res); + }; + + const onKeyboardEvent = (event) => { + const res = window.onKeyUpdate(event, "getkey"); + try_resolve_key(res); + }; + // Add a click event listener to the keyboard - document.getElementById("keyboard").addEventListener("pointerdown", onClick); + window.addEventListener("keydown", onKeyboardEvent); + document.getElementById("keyboard").addEventListener("pointerdown", onClickEvent); }); }) #endif @@ -108,6 +118,7 @@ void syscall_GetKey(cpu_t* cpu, unsigned int keycode_address) { void syscall_KeyBoard_GetKeyWait(cpu_t* cpu, uint32_t column_ptr, uint32_t row_ptr, uint32_t type_of_waiting, uint32_t timeout_period, uint32_t menu, uint32_t keycode_ptr) { printf("[Warning]: Skipped syscall KeyBoard_GetKeyWait (wait type: %d, timeout: %d, menu: %d)X\n", type_of_waiting, timeout_period, menu); + syscall_Bdisp_PutDisp_DD(cpu); mem_write(cpu, keycode_ptr, 0, 2); R0 = 0; diff --git a/fx9860-emulator/syscalls/malloc.c b/fx9860-emulator/syscalls/malloc.c index 64b9706..64a38d8 100644 --- a/fx9860-emulator/syscalls/malloc.c +++ b/fx9860-emulator/syscalls/malloc.c @@ -9,7 +9,7 @@ void syscall_Malloc(cpu_t* cpu, uint32_t size, uint8_t clear_data) { // 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; + R0 = MALLOC_ADDRESS + m->currentSize + 4; // Clear the data for (int i = 0; i < size; i++) { @@ -19,7 +19,7 @@ void syscall_Malloc(cpu_t* cpu, uint32_t size, uint8_t clear_data) { 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); + 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*4); } void syscall_Realloc(cpu_t* cpu, uint32_t ptr, uint32_t size) { @@ -30,11 +30,11 @@ void syscall_Realloc(cpu_t* cpu, uint32_t ptr, uint32_t size) { 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]); + uint32_t prev_size = *(uint32_t*)(&mallocs[ptr - MALLOC_ADDRESS - 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]; + mallocs[R0 - MALLOC_ADDRESS + i] = mallocs[ptr - MALLOC_ADDRESS + i]; } syscall_Free(cpu, ptr); diff --git a/fx9860-emulator/syscalls/misc.c b/fx9860-emulator/syscalls/misc.c index e5984f7..53b2d87 100644 --- a/fx9860-emulator/syscalls/misc.c +++ b/fx9860-emulator/syscalls/misc.c @@ -75,10 +75,10 @@ void syscall_OpcodeToStr(cpu_t* cpu, uint32_t opcode, uint32_t string_ptr) { printf("[Warning] In syscall OpcodeToStr: Invalid opcode: %d\n", opcode); return; } - if (opcode >= 63745) opcode -= 63745 - 1201; + if (opcode >= 63745) opcode -= 63745 - 1202; else if (opcode >= 63232) opcode -= 63232 - 981; - else if (opcode >= 58624) opcode -= 58624 - 501; - else if (opcode >= 32512) opcode -= 32512 - 256; + else if (opcode >= 58624) opcode -= 58624 - 500; + else if (opcode >= 32512) opcode -= 32512 - 255; for (int i = 0; i <= 15; i++) { char current = cpu->disp->opcodes[opcode * 15 + i]; diff --git a/fx9860-emulator/syscalls/syscalls.c b/fx9860-emulator/syscalls/syscalls.c index 710288c..ae1f05f 100644 --- a/fx9860-emulator/syscalls/syscalls.c +++ b/fx9860-emulator/syscalls/syscalls.c @@ -37,6 +37,7 @@ void run_syscall(cpu_t* cpu) { else if (syscall_code == 0x138) syscall_Cursor_SetPosition(cpu, R4, R5); else if (syscall_code == 0x80E) syscall_Cursor_GetFlashStyle(cpu); else if (syscall_code == 0x811) syscall_Cursor_SetFlashOn(cpu, R4); + else if (syscall_code == 0x812) syscall_Cursor_SetFlashOff(cpu); else if (syscall_code == 0x13A) syscall_Cursor_SetFlashMode(cpu, R4); else if (syscall_code == 0xACD) syscall_Malloc(cpu, R4, 0); @@ -90,6 +91,7 @@ void run_syscall(cpu_t* cpu) { 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", R5); + cpu->execution_finished = 1; } // Can be ignored else if (syscall_code == 0x494) printf("Ignored syscall: SetQuitHandler\n"); diff --git a/fx9860-emulator/syscalls/text.c b/fx9860-emulator/syscalls/text.c index bcde792..6584b5a 100644 --- a/fx9860-emulator/syscalls/text.c +++ b/fx9860-emulator/syscalls/text.c @@ -273,42 +273,32 @@ void syscall_Cursor_SetPosition(cpu_t* cpu, uint32_t column, uint32_t row) { // Returns the current cursor flash style void syscall_Cursor_GetFlashStyle(cpu_t* cpu) { - // printf("Run syscall: Cursor_GetFlashStyle (%d)\n", cpu->disp->cursor.flash_style); - R0 = cpu->disp->cursor.flash_style; - - // printf("Cursor style: %d, mode: %d\n", cpu->disp->cursor.flash_style, cpu->disp->cursor.flash_mode); + // printf("Run syscall: Cursor_GetFlashStyle => %d\n", cpu->disp->cursor.flash_style); + R0 = cpu->disp->cursor.flash_mode == 0 ? -1 : cpu->disp->cursor.flash_style; } // Sets the cursor flash style -// Remarks: // - Sets flashmode on -// - Resets to cursor-textmode +// - Resets to cursor-textmode (?) void syscall_Cursor_SetFlashOn(cpu_t* cpu, uint32_t flash_style) { - uint32_t mapped_style; - // printf("Run syscall: Cursor_SetFlashOn (%d)\n", flash_style); - cpu->disp->cursor.flash_style = flash_style; cpu->disp->cursor.flash_mode = 1; cpu->disp->cursor.blink_state = 0; draw_cursor(cpu); +} - // printf("Cursor style: %d, mode: %d\n", cpu->disp->cursor.flash_style, cpu->disp->cursor.flash_mode); +// Disables cursor flashing +void syscall_Cursor_SetFlashOff(cpu_t* cpu) { + // printf("Run syscall: Cursor_SetFlashOff\n"); + cpu->disp->cursor.flash_mode = 0; } // If flashmode is 0, the Flash mode is set to 0 and cursor flashing is turned off. // If flashmode is nonzero, Flash mode is set to 1, and cursor flashing is turned on. void syscall_Cursor_SetFlashMode(cpu_t* cpu, uint32_t flashmode) { // printf("Run syscall: Cursor_SetFlashMode (%d)\n", flashmode); - - if (flashmode == 0) { - cpu->disp->cursor.flash_mode = 0; - } - else { - cpu->disp->cursor.flash_mode = 1; - } - - // printf("Cursor style: %d, mode: %d\n", cpu->disp->cursor.flash_style, cpu->disp->cursor.flash_mode); + cpu->disp->cursor.flash_mode = flashmode; } // Draw the cursor on the LCD screen