From b23d52737e669836f7c1847beb64cbc838d6a867 Mon Sep 17 00:00:00 2001 From: Matthew Laux Date: Wed, 20 Jul 2022 22:21:36 -0500 Subject: [PATCH] draw for system 6. it's slow --- cli/imgui_example.cpp | 7 ++-- src/cpu.c | 17 ++++++++- src/dmg.c | 40 ++++++++++++++++--- src/dmg.h | 1 + src/lcd.c | 15 ++------ src/lcd.h | 3 ++ src/rom.c | 1 + src/rom.h | 2 +- system6/CMakeLists.txt | 2 + system6/emulator.c | 87 ++++++++++++++++++++++++++++++++++-------- system6/emulator.h | 8 ---- system6/lcd_mac.c | 1 - 12 files changed, 137 insertions(+), 47 deletions(-) diff --git a/cli/imgui_example.cpp b/cli/imgui_example.cpp index ba39374..a2da6e0 100644 --- a/cli/imgui_example.cpp +++ b/cli/imgui_example.cpp @@ -54,8 +54,8 @@ GLuint make_output_texture() { glGenTextures(1, &image_texture); glBindTexture(GL_TEXTURE_2D, image_texture); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); return image_texture; } @@ -66,7 +66,8 @@ void convert_output(struct lcd *lcd) { for (y = 0; y < 256; y++) { for (x = 0; x < 256; x++) { int val = lcd->buf[y * 256 + x]; - int fill = val ? 255 : 0; + int fill = 255 - val * 85; + //int fill = val ? 255 : 0; output_image[out_index++] = fill; output_image[out_index++] = fill; output_image[out_index++] = fill; diff --git a/src/cpu.c b/src/cpu.c index aeae573..5b37d80 100644 --- a/src/cpu.c +++ b/src/cpu.c @@ -174,7 +174,16 @@ static u8 shift_right(struct cpu *cpu, u8 value) static u8 swap(struct cpu *cpu, u8 value) { - return ((value & 0xf0) >> 4) | ((value & 0x0f) << 4); + u8 ret = ((value & 0xf0) >> 4) | ((value & 0x0f) << 4); + if(ret == 0) { + set_flag(cpu, FLAG_ZERO); + } else { + clear_flag(cpu, FLAG_ZERO); + } + clear_flag(cpu, FLAG_SIGN); + clear_flag(cpu, FLAG_HALF_CARRY); + clear_flag(cpu, FLAG_CARRY); + return ret; } static void xor(struct cpu *regs, u8 value) @@ -634,6 +643,8 @@ void cpu_step(struct cpu *cpu) break; case 0x2f: // CPL cpu->a = ~cpu->a; + set_flag(cpu, FLAG_SIGN); + set_flag(cpu, FLAG_HALF_CARRY); break; case 0x31: // LD SP,d16 cpu->sp = read16(cpu, cpu->pc); @@ -756,6 +767,10 @@ void cpu_step(struct cpu *cpu) case 0xb5: or(cpu, cpu->l); break; case 0xb6: or(cpu, read8(cpu, read_hl(cpu))); break; case 0xb7: or(cpu, cpu->a); break; + case 0xf6: + or(cpu, read8(cpu, cpu->pc)); + cpu->pc++; + break; // CP case 0xb8: subtract(cpu, cpu->b, 0, 1); break; diff --git a/src/dmg.c b/src/dmg.c index decc845..b7f6bde 100644 --- a/src/dmg.c +++ b/src/dmg.c @@ -39,9 +39,18 @@ void dmg_set_button(struct dmg *dmg, int field, int button, int pressed) static u8 get_button_state(struct dmg *dmg) { - return dmg->action_selected ? dmg->action_buttons : dmg->joypad; + u8 ret = 0; + if (dmg->action_selected) { + ret |= dmg->action_buttons; + } + if (dmg->joypad_selected) { + ret |= dmg->joypad; + } + return ret; } +static int counter; + u8 dmg_read(void *_dmg, u16 address) { struct dmg *dmg = (struct dmg *) _dmg; @@ -66,6 +75,9 @@ u8 dmg_read(void *_dmg, u16 address) return dmg->zero_page[address - 0xff80]; } else if (address == 0xff00) { return get_button_state(dmg); + } else if (address == 0xff04) { + counter++; + return counter; } else if (address == 0xff0f) { return dmg->interrupt_requested; } else if (address == 0xffff) { @@ -93,12 +105,21 @@ void dmg_write(void *_dmg, u16 address, u8 data) } else if (address < 0xc000) { // TODO switchable ram bank } else if (address < 0xe000) { + // printf("write ram %04x %02x\n", address, data); dmg->main_ram[address - 0xc000] = data; + } else if (address == 0xFF46) { + u16 src = data << 8; + int k = 0; + // printf("oam dma %04x\n", src); + for (u16 addr = src; addr < src + 0xa0; addr++) { + dmg->lcd->oam[k++] = dmg_read(dmg, addr); + } } else if (lcd_is_valid_addr(address)) { lcd_write(dmg->lcd, address, data); } else if (address >= 0xff80 && address <= 0xfffe) { dmg->zero_page[address - 0xff80] = data; } else if (address == 0xff00) { + dmg->joypad_selected = data & (1 << 4); dmg->action_selected = data & (1 << 5); } else if (address == 0xff0f) { dmg->interrupt_requested = data; @@ -126,9 +147,19 @@ void dmg_step(void *_dmg) if (dmg->cpu->cycle_count - dmg->last_lcd_update >= 456) { dmg->last_lcd_update = dmg->cpu->cycle_count; int next_scanline = lcd_step(dmg->lcd); + + // update LYC + if (next_scanline == lcd_read(dmg->lcd, REG_LYC)) { + lcd_set_bit(dmg->lcd, REG_STAT, STAT_FLAG_MATCH); + dmg_request_interrupt(dmg, INT_LCDSTAT); + } else { + lcd_clear_bit(dmg->lcd, REG_STAT, STAT_FLAG_MATCH); + } + if (next_scanline == 144) { // vblank has started, draw all the stuff from ram into the lcd dmg_request_interrupt(dmg, INT_VBLANK); + dmg_request_interrupt(dmg, INT_SERIAL); int lcdc = lcd_read(dmg->lcd, REG_LCDC); int bg_base = (lcdc & LCDC_BG_TILE_MAP) ? 0x9c00 : 0x9800; @@ -136,7 +167,7 @@ void dmg_step(void *_dmg) int use_unsigned = lcdc & LCDC_BG_TILE_DATA; int tilebase = use_unsigned ? 0x8000 : 0x9000; - printf("%04x %04x %04x\n", bg_base, window_base, tilebase); + //printf("%04x %04x %04x\n", bg_base, window_base, tilebase); int k = 0, off = 0; int tile_y = 0, tile_x = 0; @@ -155,9 +186,8 @@ void dmg_step(void *_dmg) int data1 = dmg_read(dmg, eff_addr + b); int data2 = dmg_read(dmg, eff_addr + b + 1); for (i = 7; i >= 0; i--) { - // monochrome for now - dmg->lcd->buf[off] = (data1 & (1 << i)) ? 1 : 0; - //dmg->lcd->buf[off] |= (data2 & (1 << i)) ? 1 : 0; + dmg->lcd->buf[off] = ((data1 & (1 << i)) ? 1 : 0);// << 1; + //dmg->lcd->buf[off] |= (data1 & (1 << i)) ? 1 : 0; off++; } off += 248; diff --git a/src/dmg.h b/src/dmg.h index ca48da2..2ae02b0 100644 --- a/src/dmg.h +++ b/src/dmg.h @@ -25,6 +25,7 @@ struct dmg { u8 video_ram[0x2000]; u8 zero_page[0x80]; u32 last_lcd_update; + int joypad_selected; int action_selected; // non-0 if A/B/start/select selected, 0 for directions u8 interrupt_enabled; u8 interrupt_requested; diff --git a/src/lcd.c b/src/lcd.c index 85f8afe..c2a7a1d 100644 --- a/src/lcd.c +++ b/src/lcd.c @@ -5,12 +5,12 @@ #include "types.h" #include "lcd.h" -static void set_bit(struct lcd *lcd, u16 addr, u8 bit) +void lcd_set_bit(struct lcd *lcd, u16 addr, u8 bit) { lcd_write(lcd, addr, lcd_read(lcd, addr) | (1 << bit)); } -static void clear_bit(struct lcd *lcd, u16 addr, u8 bit) +void lcd_clear_bit(struct lcd *lcd, u16 addr, u8 bit) { lcd_write(lcd, addr, lcd_read(lcd, addr) & ~(1 << bit)); } @@ -18,6 +18,7 @@ static void clear_bit(struct lcd *lcd, u16 addr, u8 bit) void lcd_new(struct lcd *lcd) { lcd->buf = malloc(256 * 256); + memset(lcd->buf, 0, 256 * 256); // todo < 8 bpp lcd->pixels = malloc(LCD_WIDTH * LCD_HEIGHT); } @@ -41,9 +42,6 @@ void lcd_write(struct lcd *lcd, u16 addr, u8 value) lcd->oam[addr - 0xfe00] = value; } else { lcd->regs[addr - REG_LCD_BASE] = value; - if (addr == 0xFF46) { - // OAM DMA - } } } @@ -64,13 +62,6 @@ void lcd_copy(struct lcd *lcd) int lcd_step(struct lcd *lcd) { - // update LYC - if (lcd_read(lcd, REG_LY) == lcd_read(lcd, REG_LYC)) { - set_bit(lcd, REG_STAT, STAT_FLAG_MATCH); - } else { - clear_bit(lcd, REG_STAT, STAT_FLAG_MATCH); - } - // step to next scanline 0-153 u8 next_scanline = (lcd_read(lcd, REG_LY) + 1) % 154; lcd_write(lcd, REG_LY, next_scanline); diff --git a/src/lcd.h b/src/lcd.h index 3562645..cb9e9b4 100644 --- a/src/lcd.h +++ b/src/lcd.h @@ -48,6 +48,9 @@ void lcd_write(struct lcd *lcd, u16 addr, u8 value); void lcd_put_pixel(struct lcd *lcd, u8 x, u8 y, u8 value); +void lcd_set_bit(struct lcd *lcd, u16 addr, u8 bit); +void lcd_clear_bit(struct lcd *lcd, u16 addr, u8 bit); + // i feel like i'm going to need to call this every cycle and update regs int lcd_step(struct lcd *lcd); void lcd_copy(struct lcd *lcd); diff --git a/src/rom.c b/src/rom.c index 7eaa1e2..86b4349 100644 --- a/src/rom.c +++ b/src/rom.c @@ -19,6 +19,7 @@ int rom_load(struct rom *rom, const char *filename) rom->type = 0; // TODO read type from cart rom->data = malloc(len); + rom->length = len; if (fread(rom->data, 1, len, fp) < len) { return 0; } diff --git a/src/rom.h b/src/rom.h index 97e1cfc..4bcb1f5 100644 --- a/src/rom.h +++ b/src/rom.h @@ -4,11 +4,11 @@ #include "types.h" struct rom { + u32 length; int type; u8 *data; }; - int rom_load(struct rom *rom, const char *filename); void rom_free(struct rom *rom); diff --git a/system6/CMakeLists.txt b/system6/CMakeLists.txt index 7b54d41..b757930 100644 --- a/system6/CMakeLists.txt +++ b/system6/CMakeLists.txt @@ -3,6 +3,8 @@ cmake_minimum_required(VERSION 3.9) include_directories(../src) +set(CMAKE_CXX_FLAGS "-O3") + add_application(Emulator ../src/bootstrap.c ../src/cpu.c diff --git a/system6/emulator.c b/system6/emulator.c index 63c6268..fc724ea 100644 --- a/system6/emulator.c +++ b/system6/emulator.c @@ -17,14 +17,24 @@ #include "emulator.h" +#include "dmg.h" +#include "cpu.h" +#include "rom.h" +#include "lcd.h" + WindowPtr g_wp; +DialogPtr stateDialog; unsigned char g_running; +unsigned char emulationOn; static Point windowPt = { WINDOW_Y, WINDOW_X }; static Rect windowBounds = { WINDOW_Y, WINDOW_X, WINDOW_Y + WINDOW_HEIGHT, WINDOW_X + WINDOW_WIDTH }; -emu_state theState; +struct cpu cpu; +struct rom rom; +struct lcd lcd; +struct dmg dmg; void InitEverything(void) { @@ -45,10 +55,35 @@ void InitEverything(void) g_running = 1; } +char offscreen[32 * 256]; +Rect offscreenRect = { 0, 0, 256, 256 }; + +BitMap offscreenBmp; + +int lastTicks; + void Render(void) { - MoveTo(10, 10); - DrawString("\pTest 123"); + long k = 0, dst; + for (dst = 0; dst < 32 * 256; dst++) { + offscreen[dst] = lcd.buf[k++] << 7 + | lcd.buf[k++] << 6 + | lcd.buf[k++] << 5 + | lcd.buf[k++] << 4 + | lcd.buf[k++] << 3 + | lcd.buf[k++] << 2 + | lcd.buf[k++] << 1 + | lcd.buf[k++]; + } + SetPort(g_wp); + CopyBits(&offscreenBmp, &g_wp->portBits, &offscreenRect, &g_wp->portRect, srcCopy, NULL); + + //EraseRect(&g_wp->portRect); + MoveTo(10, 160); + char debug[128]; + sprintf(debug, "PC: %04x", cpu.pc); + C2PStr(debug); + DrawString(debug); } void StartEmulation(void) @@ -57,7 +92,10 @@ void StartEmulation(void) noGrowDocProc, (WindowPtr) -1, true, 0); SetPort(g_wp); - + offscreenBmp.baseAddr = offscreen; + offscreenBmp.bounds = offscreenRect; + offscreenBmp.rowBytes = 32; + emulationOn = 1; } bool LoadRom(StrFileName fileName, short vRefNum) @@ -66,12 +104,11 @@ bool LoadRom(StrFileName fileName, short vRefNum) short fileNo; long amtRead; - if(theState.rom != NULL) { + if(rom.data != NULL) { // unload existing ROM - free((char *) theState.rom); - theState.romLength = 0; + free((char *) rom.data); + rom.length = 0; } - err = FSOpen(fileName, vRefNum, &fileNo); @@ -79,16 +116,16 @@ bool LoadRom(StrFileName fileName, short vRefNum) return false; } - GetEOF(fileNo, (long *) &theState.romLength); - theState.rom = (unsigned char *) malloc(theState.romLength); - if(theState.rom == NULL) { + GetEOF(fileNo, (long *) &rom.length); + rom.data = (unsigned char *) malloc(rom.length); + if(rom.data == NULL) { Alert(ALRT_NOT_ENOUGH_RAM, NULL); return false; } - amtRead = theState.romLength; + amtRead = rom.length; - FSRead(fileNo, &amtRead, theState.rom); + FSRead(fileNo, &amtRead, rom.data); return true; } @@ -112,7 +149,6 @@ bool ShowOpenBox(void) return false; } -DialogPtr stateDialog; void ShowStateDialog(void) { DialogPtr dp; @@ -207,15 +243,34 @@ void OnMouseDown(EventRecord *pEvt) } // -- ENTRY POINT -- - int main(int argc, char *argv[]) { EventRecord evt; + + int executed; + int paused = 0; + int pause_next = 0; InitEverything(); + + lcd_new(&lcd); + dmg_new(&dmg, &cpu, &rom, &lcd); + cpu_bind_mem_model(&cpu, &dmg, dmg_read, dmg_write); + + cpu.pc = 0x100; + int start = TickCount(); while(g_running) { - if(WaitNextEvent(everyEvent, &evt, 10, 0) != nullEvent) { + if (emulationOn) { + dmg_step(&dmg); + int now = TickCount(); + if (now > lastTicks + 100) { + lastTicks = now; + Render(); + } + } + + if(WaitNextEvent(everyEvent, &evt, 0, 0) != nullEvent) { if (IsDialogEvent(&evt)) { DialogRef hitBox; DialogItemIndex hitItem; diff --git a/system6/emulator.h b/system6/emulator.h index 38a7b33..effbe82 100644 --- a/system6/emulator.h +++ b/system6/emulator.h @@ -44,12 +44,4 @@ typedef unsigned char bool; #define true 1 #define false 0 -typedef struct _emu_state { - struct dmg *cpu; - u8 *rom; - unsigned long int romLength; -} emu_state; - -extern emu_state theState; - #endif \ No newline at end of file diff --git a/system6/lcd_mac.c b/system6/lcd_mac.c index cc15a41..388aea5 100644 --- a/system6/lcd_mac.c +++ b/system6/lcd_mac.c @@ -4,4 +4,3 @@ void lcd_draw(struct lcd *lcd) { } -