diff --git a/apu.cpp b/apu.cpp index c0f75b5..3c53b8b 100644 --- a/apu.cpp +++ b/apu.cpp @@ -20,7 +20,7 @@ typedef struct unsigned outfreq,ratelo,ratehi,z0; sndchan ch[4]; uint8_t wave[16]; -} so; +} apu; const static uint8_t dmgwave[16] = { @@ -50,7 +50,7 @@ const static int divtab[8] = 14 }; -so snd; +apu snd; static uint8_t noise7[16]; static uint8_t noise15[4096]; @@ -91,7 +91,7 @@ void apu_shutdown() // ********************************************************************** /* -Questionable aspects of SO terminal emulation: +Questionable aspects of APU emulation: NR51 contains updated "sound enable" flags Frequency registers can update if sweep is operating @@ -333,103 +333,102 @@ void apu_write(uint8_t r, uint8_t b) apu_mix(); switch (r) { - case RI_NR10: - R_NR10 = b; - S1.swfreq = 2047&*(unsigned short*)&R_NR13; - S1.swcnt = 0; // TODO? Is it true? - break; - case RI_NR11: - R_NR11 = b; - S1.cnt = 64-(b&63); - break; - case RI_NR12: - R_NR12 = b; - S1.envol = R_NR12 >> 4; - if((b&0xF8) == 0) apu_1off(); // Forced OFF mode(as stated in patent docs) if 0 and down - //S1.endir = (R_NR12>>3) & 1; - //S1.endir |= S1.endir - 1; - break; - case RI_NR13: - R_NR13 = b; - s1_freq(); - break; - case RI_NR14: - R_NR14 = b; - s1_freq(); - if (b & 128) s1_init(); - break; - case RI_NR21: - R_NR21 = b; - S2.cnt = 64-(b&63); - break; - case RI_NR22: - R_NR22 = b; - if((b&0xF8) == 0) apu_2off(); // Forced OFF mode(as stated in patent docs) if 0 and down - S2.envol = R_NR22 >> 4; - //S2.endir = (R_NR22>>3) & 1; - //S2.endir |= S2.endir - 1; - break; - case RI_NR23: - R_NR23 = b; - s2_freq(); - break; - case RI_NR24: - R_NR24 = b; - s2_freq(); - if (b & 128) s2_init(); - break; - case RI_NR30: - R_NR30 = b; - if (!(b & 128)) apu_3off(); - break; - case RI_NR31: - R_NR31 = b; - S3.cnt = 256-b; - break; - case RI_NR32: - R_NR32 = b; - - break; - case RI_NR33: - R_NR33 = b; - s3_freq(); - break; - case RI_NR34: - R_NR34 = b; - s3_freq(); - if (b & 128) s3_init(); - break; - case RI_NR41: - R_NR41 = b; - S4.cnt = 64-(b&63); - break; - case RI_NR42: - R_NR42 = b; - S4.envol = R_NR42 >> 4; - if((b&0xF8) == 0) apu_4off(); // Forced OFF mode(as stated in patent docs) if 0 and down - break; - case RI_NR43: - R_NR43 = b; - s4_freq(); - break; - case RI_NR44: - R_NR44 = b; - s4_freq(); - if (b & 128) s4_init(); - break; - case RI_NR50: - R_NR50 = b; - break; - case RI_NR51: - R_NR51 = b; - break; - case RI_NR52: - R_NR52 = b; - if (!(R_NR52 & 128)) - apu_off(); - break; - default: - return; + case RI_NR10: + R_NR10 = b; + S1.swfreq = 2047&*(unsigned short*)&R_NR13; + S1.swcnt = 0; // TODO? Is it true? + break; + case RI_NR11: + R_NR11 = b; + S1.cnt = 64-(b&63); + break; + case RI_NR12: + R_NR12 = b; + S1.envol = R_NR12 >> 4; + if((b&0xF8) == 0) apu_1off(); // Forced OFF mode(as stated in patent docs) if 0 and down + //S1.endir = (R_NR12>>3) & 1; + //S1.endir |= S1.endir - 1; + break; + case RI_NR13: + R_NR13 = b; + s1_freq(); + break; + case RI_NR14: + R_NR14 = b; + s1_freq(); + if (b & 128) s1_init(); + break; + case RI_NR21: + R_NR21 = b; + S2.cnt = 64-(b&63); + break; + case RI_NR22: + R_NR22 = b; + if((b&0xF8) == 0) apu_2off(); // Forced OFF mode(as stated in patent docs) if 0 and down + S2.envol = R_NR22 >> 4; + //S2.endir = (R_NR22>>3) & 1; + //S2.endir |= S2.endir - 1; + break; + case RI_NR23: + R_NR23 = b; + s2_freq(); + break; + case RI_NR24: + R_NR24 = b; + s2_freq(); + if (b & 128) s2_init(); + break; + case RI_NR30: + R_NR30 = b; + if (!(b & 128)) apu_3off(); + break; + case RI_NR31: + R_NR31 = b; + S3.cnt = 256-b; + break; + case RI_NR32: + R_NR32 = b; + break; + case RI_NR33: + R_NR33 = b; + s3_freq(); + break; + case RI_NR34: + R_NR34 = b; + s3_freq(); + if (b & 128) s3_init(); + break; + case RI_NR41: + R_NR41 = b; + S4.cnt = 64-(b&63); + break; + case RI_NR42: + R_NR42 = b; + S4.envol = R_NR42 >> 4; + if((b&0xF8) == 0) apu_4off(); // Forced OFF mode(as stated in patent docs) if 0 and down + break; + case RI_NR43: + R_NR43 = b; + s4_freq(); + break; + case RI_NR44: + R_NR44 = b; + s4_freq(); + if (b & 128) s4_init(); + break; + case RI_NR50: + R_NR50 = b; + break; + case RI_NR51: + R_NR51 = b; + break; + case RI_NR52: + R_NR52 = b; + if (!(R_NR52 & 128)) + apu_off(); + break; + default: + return; } } diff --git a/gb.cpp b/gb.cpp index f2bae74..811f4d0 100644 --- a/gb.cpp +++ b/gb.cpp @@ -6,7 +6,7 @@ void gb_init() { // log_init("gbemu.log"); mem_init(); - gbz80_init(); + sm83_init(); pad_init(); ppu_init(); apu_init(44100); @@ -38,7 +38,7 @@ void check4LCDint(unsigned mode) { // Also called from mem.c!! //unsigned lcd_int_on_new=; // LYC is not processed here if(R_STAT&stat2LCDflg[mode]/* !lcd_int_on && */) {// check if interrupt is requested already R_IF|=INT_LCDSTAT; - check4int(); // do int if possible + sm83_check4int(); // do int if possible } //lcd_int_on = lcd_int_on_new; } @@ -49,7 +49,7 @@ void check4LYC(void) { // Also called from mem.c!! if(R_STAT < stnew) if(stnew&0x40) {// check if interrupt allowed R_IF|=INT_LCDSTAT; - check4int(); // do int if possible + sm83_check4int(); // do int if possible } } R_STAT=stnew; @@ -74,12 +74,12 @@ void gb_reload_tima(unsigned data) { // will only contain byte value static void execute(unsigned long n) { gb_eventclk+=n; // timerclk = MAXULONG means that timer interrupt is off /*while(gb_eventclk>gb_timerclk) { - gbz80_execute_until(gb_timerclk); + sm83_execute_until(gb_timerclk); gb_reload_tima(R_TMA); R_IF|=INT_TIMER; // request timer interrupt - check4int(); + sm83_check4int(); }*/ - gbz80_execute_until(gb_eventclk); + sm83_execute_until(gb_eventclk); } // ********************************************************************** @@ -105,7 +105,7 @@ void start() /* LCD during H-Blank */ //STAT_MODE(0); //gb_eventclk+=204; - //gbz80_execute_until(gb_eventclk); + //sm83_execute_until(gb_eventclk); STAT_MODE(2); ppu_enumsprites(); @@ -125,7 +125,7 @@ void start() /* LCD during V-Blank (10 "empty" lines) */ //if(R_STAT & 0x10) // questionable R_IF|=INT_VBLANK; // Queue V-blank int - check4int(); + sm83_check4int(); STAT_MODE(1); ppu_vsync(); for(i=10;i!=0;i--) { diff --git a/gb.h b/gb.h index b717cf2..ba43adf 100644 --- a/gb.h +++ b/gb.h @@ -1,5 +1,15 @@ #pragma once +/* Interrupt flags*/ +#define INT_NONE 0 +#define INT_VBLANK 1 +#define INT_LCDSTAT 2 +#define INT_TIMER 4 +#define INT_SERIAL 8 +#define INT_PAD 0x10 +#define INT_ALL 0x1F + + void gb_init(void); void gb_shutdown(void); void start(void); diff --git a/lcd.cpp b/lcd.cpp index 415fc2d..0f507cb 100644 --- a/lcd.cpp +++ b/lcd.cpp @@ -36,9 +36,7 @@ unsigned benchmark_sound, benchmark_gfx; static HDC main_hdc, hdcc; static HBITMAP DIB_section; static HGDIOBJ old_obj; -//static RGBQUAD *pbuf; - -RGBQUAD* pbuf; +static RGBQUAD *pbuf; /* milk to cofee */ RGBQUAD dib_pal[] = { @@ -90,8 +88,8 @@ void win32_win_init(int width, int height) { HINSTANCE hInstance = GetModuleHandle(NULL); char title[128]; - WNDCLASS wc; - RECT rect; + WNDCLASS wc{}; + RECT rect{}; int w, h; sprintf(title, "GameBoy - %s", romhdr->title); @@ -127,8 +125,10 @@ void win32_win_init(int width, int height) NULL, NULL, hInstance, NULL); - if (!main_hwnd) + if (!main_hwnd) { sys_error("couldn't create main window."); + return; + } ShowWindow(main_hwnd, SW_NORMAL); UpdateWindow(main_hwnd); @@ -185,32 +185,37 @@ void WIN_Center(HWND hwnd) void win32_dib_init(int width, int height) { HDC hdc; - BITMAPINFO* bmi; + BITMAPINFO bmi{}; void* DIB_base; - bmi = (BITMAPINFO*)calloc(sizeof(BITMAPINFO) + 16 * 4, 1); main_hdc = hdc = GetDC(main_hwnd); - //memset(&(bmi->bmiHeader), 0, sizeof(BITMAPINFOHEADER)); - - bmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER); - dib_width = bmi->bmiHeader.biWidth = width; - dib_height = bmi->bmiHeader.biHeight = -height; - bmi->bmiHeader.biPlanes = 1; - bmi->bmiHeader.biBitCount = 32; - bmi->bmiHeader.biCompression = BI_RGB; - //bmi->bmiHeader. - - DIB_section = CreateDIBSection(hdc, bmi, DIB_RGB_COLORS, &DIB_base, NULL, 0); + bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); + dib_width = bmi.bmiHeader.biWidth = width; + dib_height = bmi.bmiHeader.biHeight = -height; + bmi.bmiHeader.biPlanes = 1; + bmi.bmiHeader.biBitCount = 32; + bmi.bmiHeader.biCompression = BI_RGB; + + DIB_section = CreateDIBSection(hdc, &bmi, DIB_RGB_COLORS, &DIB_base, NULL, 0); + if (!DIB_section) { + sys_error("CreateDIBSection() failed!"); + return; + } pbuf = (RGBQUAD*)DIB_base; hdcc = CreateCompatibleDC(hdc); - if (!hdcc) + if (!hdcc) { + DeleteObject(DIB_section); sys_error("CreateCompatibleDC() failed!"); + return; + } - if (!(old_obj = SelectObject(hdcc, DIB_section))) + if (!(old_obj = SelectObject(hdcc, DIB_section))) { + DeleteDC(hdcc); + DeleteObject(DIB_section); sys_error("SelectObject() failed!"); - free(bmi); + } } void win32_dib_shutdown() diff --git a/mem.cpp b/mem.cpp index 1df42a3..ef53ec3 100644 --- a/mem.cpp +++ b/mem.cpp @@ -382,11 +382,11 @@ void mem_w8_IO(unsigned addr, uint8_t data) { return; case 0x0F : // R_IF (interrupt request) R_IF = data; - check4int(); + sm83_check4int(); return; case 0xFF : // R_IE (interrupt mask) R_IE = data; - check4int(); + sm83_check4int(); return; /*case 0x10: case 0x11: case 0x12: case 0x13: case 0x14: case 0x15: case 0x16: case 0x17: diff --git a/mem.h b/mem.h index ac7648e..5e571c8 100644 --- a/mem.h +++ b/mem.h @@ -99,7 +99,7 @@ extern struct Cartridge { unsigned ram_nbanks; // Size of RAM in banks (mapper dependent) unsigned rom_nmask; // Mask for ROM bank selection unsigned ram_nmask; // Mask for RAM bank selection - unsigned ram_end; // End address for usable RAM area in Z80 address space + unsigned ram_end; // End address for usable RAM area in CPU address space unsigned ram_amask; // Mask for allowed RAM bank space struct MemBank rom[4]; // selected ROM bank(s) diff --git a/misc.cpp b/misc.cpp index b94f3ec..025a7f5 100644 --- a/misc.cpp +++ b/misc.cpp @@ -29,7 +29,10 @@ void load_game(char *name) long size; f = fopen(name, "rb"); - if(!f) sys_error("couldn't load game \'%s\'", name); + if (!f) { + sys_error("couldn't load game \'%s\'", name); + return; + } fseek(f, 0, SEEK_END); size = ftell(f); @@ -37,7 +40,10 @@ void load_game(char *name) memset(&cart,0,sizeof(cart)); cart.data = (uint8_t *)malloc(size); - if(!cart.data) sys_error("not enough memory for game!"); + if (!cart.data) { + fclose(f); + sys_error("not enough memory for game!"); + } fread(cart.data, 1, size, f); fclose(f); @@ -78,7 +84,7 @@ void show_regs() p += sprintf(&buf[p], "SCX=%.2X\t\tWX=%.2X\t\tOBP1=%.2X\n", HRAM(0xff43), HRAM(0xff4b), HRAM(0xff49)); p += sprintf(&buf[p], "SCY=%.2X\t\tWY=%.2X\n", HRAM(0xff42), HRAM(0xff4a)); - MessageBox(NULL, buf, "GB Z80 and hardware register map", MB_OK | MB_TOPMOST | MB_ICONINFORMATION); + MessageBox(NULL, buf, "GB SM83 and hardware register map", MB_OK | MB_TOPMOST | MB_ICONINFORMATION); } /* load battery-backed/onboard RAM */ diff --git a/pch.h b/pch.h index 2aa84ff..b2cb792 100644 --- a/pch.h +++ b/pch.h @@ -11,16 +11,6 @@ #define MAXULONG (unsigned long)(-1) -/* Interrupt flags*/ -#define INT_NONE 0 -#define INT_VBLANK 1 -#define INT_LCDSTAT 2 -#define INT_TIMER 4 -#define INT_SERIAL 8 -#define INT_PAD 0x10 -#define INT_ALL 0x1F - - /* project includes */ #include "misc.h" #include "mem.h" diff --git a/ppu.cpp b/ppu.cpp index 17beb34..2d8f2ed 100644 --- a/ppu.cpp +++ b/ppu.cpp @@ -1,15 +1,8 @@ -/* GameBoy LCD emulation (win32) */ +// GameBoy PPU emulation #include "pch.h" unsigned lcd_WYline; - -/* -************************************************************************* - LCD interface -************************************************************************* -*/ - void tilecache_init(void); void ppu_init() diff --git a/sm83.cpp b/sm83.cpp index 5e1b2e7..0a6847a 100644 --- a/sm83.cpp +++ b/sm83.cpp @@ -1,4 +1,5 @@ -// SM83 interpreter +// SM83 interpreter. +// The DMG SoC uses a custom SHARP SM83 core, which mostly uses the Z80 instruction set, but a completely proprietary implementation + additional opcodes and HLT/STOP modes. #include "pch.h" #define USEBFLAGS @@ -33,7 +34,7 @@ static void Undefined(void) { R_PC--; show_regs (); - sys_error("Undefined GB Z80 opcode %02X at PC = %.4X",(unsigned)RD(R_PC), (unsigned)(R_PC)); + sys_error("Undefined SM83 opcode %02X at PC = %.4X",(unsigned)RD(R_PC), (unsigned)(R_PC)); } static uint8_t z_b_t[256]; @@ -281,7 +282,7 @@ static int cb_clk_t[256] = { ************************************************************************* */ -void check4int(void) { // Check for posibility of interrupt, do it if possible +void sm83_check4int(void) { // Check for posibility of interrupt, do it if possible unsigned imask,iflags,intaddr; if(iflags=(IME & R_IE & R_IF)) // if interrupts enabled and there are some active interrupts in queue { @@ -340,7 +341,7 @@ borderline typically represent CPU-independent events, such as: 1: LCD mode changes(both LCD interrupts included) 2: timer based interrupts */ -void gbz80_execute_until(unsigned long clk_nextevent) +void sm83_execute_until(unsigned long clk_nextevent) { /* temporaries for calculations */ uint8_t tmp8; @@ -847,7 +848,7 @@ OP(D6) { tmp8 = FETCH(); SUB(tmp8); } // SUB A,n OP(D7) { RST(0x10); } // RST 10h OP(D8) { if(R_F & CF) goto opC9; else z80_clk -= 3; } // RETC OP(D9) { POP(r_pc); IME = INT_ALL; -check4int(); +sm83_check4int(); } // [GB] IRET OP(DA) { if(R_F & CF) R_PC = FETCH16(); else {R_PC += 2; z80_clk--;} } // JPC nn OP(DB) {Undefined();} // [GB] not implemented @@ -885,7 +886,7 @@ OP(F9) { R_SP = R_HL; } // LD SP,HL OP(FA) { tmp32 = FETCH16();R_A = RD(tmp32); }// [GB] LD A,(nn) OP(FB) { IME = INT_ALL; -check4int(); +sm83_check4int(); } // EI (=STI) OP(FC) {Undefined();} // [GB] NOT implemented OP(FD) {Undefined();} // [GB] NOT implemented @@ -916,7 +917,7 @@ static void filltables(void) { dec_t[i] = (i&0xF)==0xF? (p|HF) : p; } } -void gbz80_init() +void sm83_init() { filltables(); // This makes code more readable, editable & compressable :) R_PC = 0; diff --git a/sm83.h b/sm83.h index 6a58ece..4d6cfa0 100644 --- a/sm83.h +++ b/sm83.h @@ -65,14 +65,13 @@ extern unsigned HALT, IME; #define BFLAGS (uint8_t)0xAC #define BFLAGSh (uint16_t)0xAC00 -// eto maska dlya "skvoznyh" flagov) mozhet i ne nado ee uzat', tem ne menee +// this is a mask for "pass-through" flags, maybe you don't need to use it, nevertheless //#define FETCH() RD(R_PC++) disabled because of incompatibility /* CPU interface */ -void gbz80_init(); -//int gbz80_execute(); -void gbz80_execute_until(unsigned long clk_nextevent); // Exact timing is not guarantied -void check4int(void); // Call interrupt if IE,request flags are set and not masked. +void sm83_init(); +void sm83_execute_until(unsigned long clk_nextevent); // Exact timing is not guarantied +void sm83_check4int(void); // Call interrupt if IE,request flags are set and not masked. extern unsigned debug_canwrite,debug_written[2];