diff --git a/inc/peanut_gb.h b/inc/peanut_gb.h index 5421d1e..ecd117b 100644 --- a/inc/peanut_gb.h +++ b/inc/peanut_gb.h @@ -21,7 +21,7 @@ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS * IN THE SOFTWARE. * - * Please note that at least three parts of source code within this project was + * Please note that at least two parts of source code within this project was * taken from the SameBoy project at https://github.com/LIJI32/SameBoy/ which at * the time of this writing is released under the MIT License. Occurrences of * this code is marked as being taken from SameBoy with a comment. @@ -42,6 +42,7 @@ #endif #include /* Required for qsort and abort */ +#include /* Required for bool types */ #include /* Required for int types */ #include /* Required for memset */ #include /* Required for tm struct */ @@ -88,6 +89,12 @@ # define ENABLE_LCD 1 #endif +/* Enable 16 bit colour palette. If disabled, only four colour shades are set in + * pixel data. */ +#ifndef PEANUT_GB_12_COLOUR +# define PEANUT_GB_12_COLOUR 1 +#endif + /* Adds more code to improve LCD rendering accuracy. */ #ifndef PEANUT_GB_HIGH_LCD_ACCURACY # define PEANUT_GB_HIGH_LCD_ACCURACY 1 @@ -150,6 +157,9 @@ #define SCREEN_REFRESH_CYCLES 70224.0 #define VERTICAL_SYNC (DMG_CLOCK_FREQ/SCREEN_REFRESH_CYCLES) +/* Real Time Clock is locked to 1Hz. */ +#define RTC_CYCLES ((uint_fast32_t)DMG_CLOCK_FREQ) + /* SERIAL SC register masks. */ #define SERIAL_SC_TX_START 0x80 #define SERIAL_SC_CLOCK_SRC 0x01 @@ -174,18 +184,34 @@ #define LCDC_BG_ENABLE 0x01 /** LCD characteristics **/ -/* PPU cycles through modes every 456 cycles. */ -#define LCD_LINE_CYCLES 456 -/* Mode 0 starts on cycle 372. */ -#define LCD_MODE_0_CYCLES 372 -/* Mode 2 starts on cycle 204. */ -#define LCD_MODE_2_CYCLES 204 -/* Mode 3 starts on cycle 284. */ -#define LCD_MODE_3_CYCLES 284 /* There are 154 scanlines. LY < 154. */ #define LCD_VERT_LINES 154 #define LCD_WIDTH 160 #define LCD_HEIGHT 144 +/* PPU cycles through modes every 456 cycles. */ +#define LCD_LINE_CYCLES 456 +#define LCD_MODE0_HBLANK_MAX_DRUATION 204 +#define LCD_MODE0_HBLANK_MIN_DRUATION 87 +#define LCD_MODE2_OAM_SCAN_DURATION 80 +#define LCD_MODE3_LCD_DRAW_MIN_DURATION 172 +#define LCD_MODE3_LCD_DRAW_MAX_DURATION 289 +#define LCD_MODE1_VBLANK_DURATION (LCD_LINE_CYCLES * (LCD_VERT_LINES - LCD_HEIGHT)) +/* The following assumes that Hblank starts on cycle 0. */ +/* Mode 2 (OAM Scan) starts on cycle 204 (although this is dependent on the + * duration of Mode 3 (LCD Draw). */ +#define LCD_MODE_2_CYCLES LCD_MODE0_HBLANK_MAX_DRUATION +/* Mode 3 starts on cycle 284. */ +#define LCD_MODE_3_CYCLES (LCD_MODE_2_CYCLES + LCD_MODE2_OAM_SCAN_DURATION) +/* Mode 0 starts on cycle 376. */ +#define LCD_MODE_0_CYCLES (LCD_MODE_3_CYCLES + LCD_MODE3_LCD_DRAW_MIN_DURATION) + +#define LCD_MODE2_OAM_SCAN_START 0 +#define LCD_MODE2_OAM_SCAN_END (LCD_MODE2_OAM_SCAN_DURATION) +#define LCD_MODE3_LCD_DRAW_END (LCD_MODE2_OAM_SCAN_END + LCD_MODE3_LCD_DRAW_MIN_DURATION) +#define LCD_MODE0_HBLANK_END (LCD_MODE3_LCD_DRAW_END + LCD_MODE0_HBLANK_MAX_DRUATION) +#if LCD_MODE0_HBLANK_END != LCD_LINE_CYCLES +#error "LCD length not equal" +#endif /* VRAM Locations */ #define VRAM_TILES_1 (0x8000 - VRAM_ADDR) @@ -210,6 +236,16 @@ #define OBJ_FLIP_X 0x20 #define OBJ_PALETTE 0x10 +/* Joypad buttons */ +#define JOYPAD_A 0x01 +#define JOYPAD_B 0x02 +#define JOYPAD_SELECT 0x04 +#define JOYPAD_START 0x08 +#define JOYPAD_RIGHT 0x10 +#define JOYPAD_LEFT 0x20 +#define JOYPAD_UP 0x40 +#define JOYPAD_DOWN 0x80 + #define ROM_HEADER_CHECKSUM_LOC 0x014D /* Local macros. */ @@ -219,6 +255,13 @@ #define PEANUT_GB_ARRAYSIZE(array) (sizeof(array)/sizeof(array[0])) +/** Allow setting deprecated functions and variables. */ +#if (defined(__GNUC__) && __GNUC__ >= 6) || (defined(__clang__) && __clang_major__ >= 4) +# define PGB_DEPRECATED(msg) __attribute__((deprecated(msg))) +#else +# define PGB_DEPRECATED(msg) +#endif + #if !defined(__has_builtin) /* Stub __has_builtin if it isn't available. */ # define __has_builtin(x) 0 @@ -229,13 +272,29 @@ #if !defined(PGB_UNREACHABLE) # if __has_builtin(__builtin_unreachable) # define PGB_UNREACHABLE() __builtin_unreachable() -# elif defined(_MSC_VER) +# elif defined(_MSC_VER) && _MSC_VER >= 1200 +# /* __assume is not available before VC6. */ # define PGB_UNREACHABLE() __assume(0) # else # define PGB_UNREACHABLE() abort() # endif #endif /* !defined(PGB_UNREACHABLE) */ +#if !defined(PGB_UNLIKELY) +# if __has_builtin(__builtin_expect) +# define PGB_UNLIKELY(expr) __builtin_expect(!!(expr), 0) +# else +# define PGB_UNLIKELY(expr) (expr) +# endif +#endif /* !defined(PGB_UNLIKELY) */ +#if !defined(PGB_LIKELY) +# if __has_builtin(__builtin_expect) +# define PGB_LIKELY(expr) __builtin_expect(!!(expr), 1) +# else +# define PGB_LIKELY(expr) (expr) +# endif +#endif /* !defined(PGB_LIKELY) */ + #if PEANUT_GB_USE_INTRINSICS /* If using MSVC, only enable intrinsics for x86 platforms*/ # if defined(_MSC_VER) && __has_include("intrin.h") && \ @@ -257,39 +316,39 @@ # define PGB_INSTR_SBC_R8(r,cin) \ { \ uint8_t temp; \ - gb->cpu_reg.f_bits.c = PGB_INTRIN_SBC(gb->cpu_reg.a,r,cin,temp);\ - gb->cpu_reg.f_bits.h = ((gb->cpu_reg.a ^ r ^ temp) & 0x10) > 0; \ - gb->cpu_reg.f_bits.n = 1; \ - gb->cpu_reg.f_bits.z = (temp == 0x00); \ + gb->cpu_reg.f.f_bits.c = PGB_INTRIN_SBC(gb->cpu_reg.a,r,cin,temp);\ + gb->cpu_reg.f.f_bits.h = ((gb->cpu_reg.a ^ r ^ temp) & 0x10) > 0;\ + gb->cpu_reg.f.f_bits.n = 1; \ + gb->cpu_reg.f.f_bits.z = (temp == 0x00); \ gb->cpu_reg.a = temp; \ } # define PGB_INSTR_CP_R8(r) \ { \ uint8_t temp; \ - gb->cpu_reg.f_bits.c = PGB_INTRIN_SBC(gb->cpu_reg.a,r,0,temp); \ - gb->cpu_reg.f_bits.h = ((gb->cpu_reg.a ^ r ^ temp) & 0x10) > 0; \ - gb->cpu_reg.f_bits.n = 1; \ - gb->cpu_reg.f_bits.z = (temp == 0x00); \ + gb->cpu_reg.f.f_bits.c = PGB_INTRIN_SBC(gb->cpu_reg.a,r,0,temp);\ + gb->cpu_reg.f.f_bits.h = ((gb->cpu_reg.a ^ r ^ temp) & 0x10) > 0;\ + gb->cpu_reg.f.f_bits.n = 1; \ + gb->cpu_reg.f.f_bits.z = (temp == 0x00); \ } #else # define PGB_INSTR_SBC_R8(r,cin) \ { \ uint16_t temp = gb->cpu_reg.a - (r + cin); \ - gb->cpu_reg.f_bits.c = (temp & 0xFF00) ? 1 : 0; \ - gb->cpu_reg.f_bits.h = ((gb->cpu_reg.a ^ r ^ temp) & 0x10) > 0; \ - gb->cpu_reg.f_bits.n = 1; \ - gb->cpu_reg.f_bits.z = ((temp & 0xFF) == 0x00); \ + gb->cpu_reg.f.f_bits.c = (temp & 0xFF00) ? 1 : 0; \ + gb->cpu_reg.f.f_bits.h = ((gb->cpu_reg.a ^ r ^ temp) & 0x10) > 0; \ + gb->cpu_reg.f.f_bits.n = 1; \ + gb->cpu_reg.f.f_bits.z = ((temp & 0xFF) == 0x00); \ gb->cpu_reg.a = (temp & 0xFF); \ } # define PGB_INSTR_CP_R8(r) \ { \ uint16_t temp = gb->cpu_reg.a - r; \ - gb->cpu_reg.f_bits.c = (temp & 0xFF00) ? 1 : 0; \ - gb->cpu_reg.f_bits.h = ((gb->cpu_reg.a ^ r ^ temp) & 0x10) > 0; \ - gb->cpu_reg.f_bits.n = 1; \ - gb->cpu_reg.f_bits.z = ((temp & 0xFF) == 0x00); \ + gb->cpu_reg.f.f_bits.c = (temp & 0xFF00) ? 1 : 0; \ + gb->cpu_reg.f.f_bits.h = ((gb->cpu_reg.a ^ r ^ temp) & 0x10) > 0; \ + gb->cpu_reg.f.f_bits.n = 1; \ + gb->cpu_reg.f.f_bits.z = ((temp & 0xFF) == 0x00); \ } #endif /* PGB_INTRIN_SBC */ @@ -297,50 +356,51 @@ # define PGB_INSTR_ADC_R8(r,cin) \ { \ uint8_t temp; \ - gb->cpu_reg.f_bits.c = PGB_INTRIN_ADC(gb->cpu_reg.a,r,cin,temp);\ - gb->cpu_reg.f_bits.h = ((gb->cpu_reg.a ^ r ^ temp) & 0x10) > 0; \ - gb->cpu_reg.f_bits.n = 0; \ - gb->cpu_reg.f_bits.z = (temp == 0x00); \ + gb->cpu_reg.f.f_bits.c = PGB_INTRIN_ADC(gb->cpu_reg.a,r,cin,temp);\ + gb->cpu_reg.f.f_bits.h = ((gb->cpu_reg.a ^ r ^ temp) & 0x10) > 0; \ + gb->cpu_reg.f.f_bits.n = 0; \ + gb->cpu_reg.f.f_bits.z = (temp == 0x00); \ gb->cpu_reg.a = temp; \ } #else # define PGB_INSTR_ADC_R8(r,cin) \ { \ uint16_t temp = gb->cpu_reg.a + r + cin; \ - gb->cpu_reg.f_bits.c = (temp & 0xFF00) ? 1 : 0; \ - gb->cpu_reg.f_bits.h = ((gb->cpu_reg.a ^ r ^ temp) & 0x10) > 0; \ - gb->cpu_reg.f_bits.n = 0; \ - gb->cpu_reg.f_bits.z = ((temp & 0xFF) == 0x00); \ + gb->cpu_reg.f.f_bits.c = (temp & 0xFF00) ? 1 : 0; \ + gb->cpu_reg.f.f_bits.h = ((gb->cpu_reg.a ^ r ^ temp) & 0x10) > 0; \ + gb->cpu_reg.f.f_bits.n = 0; \ + gb->cpu_reg.f.f_bits.z = ((temp & 0xFF) == 0x00); \ gb->cpu_reg.a = (temp & 0xFF); \ } #endif /* PGB_INTRIN_ADC */ +#define PGB_INSTR_INC_R8(r) \ + r++; \ + gb->cpu_reg.f.f_bits.h = ((r & 0x0F) == 0x00); \ + gb->cpu_reg.f.f_bits.n = 0; \ + gb->cpu_reg.f.f_bits.z = (r == 0x00) + #define PGB_INSTR_DEC_R8(r) \ r--; \ - gb->cpu_reg.f_bits.h = ((r & 0x0F) == 0x0F); \ - gb->cpu_reg.f_bits.n = 1; \ - gb->cpu_reg.f_bits.z = (r == 0x00); + gb->cpu_reg.f.f_bits.h = ((r & 0x0F) == 0x0F); \ + gb->cpu_reg.f.f_bits.n = 1; \ + gb->cpu_reg.f.f_bits.z = (r == 0x00) #define PGB_INSTR_XOR_R8(r) \ gb->cpu_reg.a ^= r; \ - gb->cpu_reg.f_bits.z = (gb->cpu_reg.a == 0x00); \ - gb->cpu_reg.f_bits.n = 0; \ - gb->cpu_reg.f_bits.h = 0; \ - gb->cpu_reg.f_bits.c = 0; + gb->cpu_reg.f.reg = 0; \ + gb->cpu_reg.f.f_bits.z = (gb->cpu_reg.a == 0x00) #define PGB_INSTR_OR_R8(r) \ gb->cpu_reg.a |= r; \ - gb->cpu_reg.f_bits.z = (gb->cpu_reg.a == 0x00); \ - gb->cpu_reg.f_bits.n = 0; \ - gb->cpu_reg.f_bits.h = 0; \ - gb->cpu_reg.f_bits.c = 0; + gb->cpu_reg.f.reg = 0; \ + gb->cpu_reg.f.f_bits.z = (gb->cpu_reg.a == 0x00) #define PGB_INSTR_AND_R8(r) \ gb->cpu_reg.a &= r; \ - gb->cpu_reg.f_bits.z = (gb->cpu_reg.a == 0x00); \ - gb->cpu_reg.f_bits.n = 0; \ - gb->cpu_reg.f_bits.h = 1; \ - gb->cpu_reg.f_bits.c = 0; + gb->cpu_reg.f.reg = 0; \ + gb->cpu_reg.f.f_bits.z = (gb->cpu_reg.a == 0x00); \ + gb->cpu_reg.f.f_bits.h = 1 #if PEANUT_GB_IS_LITTLE_ENDIAN # define PEANUT_GB_GET_LSB16(x) (x & 0xFF) @@ -364,13 +424,16 @@ struct cpu_registers_s # define PEANUT_GB_LE_REG(x,y) y,x #endif /* Define specific bits of Flag register. */ - struct - { - uint8_t c : 1; /* Carry flag. */ - uint8_t h : 1; /* Half carry flag. */ - uint8_t n : 1; /* Add/sub flag. */ - uint8_t z : 1; /* Zero flag. */ - } f_bits; + union { + struct { + uint8_t : 4; /* Unused. */ + uint8_t c: 1; /* Carry flag. */ + uint8_t h: 1; /* Half carry flag. */ + uint8_t n: 1; /* Add/sub flag. */ + uint8_t z: 1; /* Zero flag. */ + } f_bits; + uint8_t reg; + } f; uint8_t a; union @@ -428,11 +491,14 @@ struct count_s uint_fast16_t div_count; /* Divider Register Counter */ uint_fast16_t tima_count; /* Timer Counter */ uint_fast16_t serial_count; /* Serial Counter */ + uint_fast32_t rtc_count; /* RTC Counter */ }; #if ENABLE_LCD /* Bit mask for the shade of pixel to display */ #define LCD_COLOUR 0x03 + +# if PEANUT_GB_12_COLOUR /** * Bit mask for whether a pixel is OBJ0, OBJ1, or BG. Each may have a different * palette when playing a DMG game on CGB. @@ -447,6 +513,7 @@ struct count_s * LCD_PALETTE_ALL == 0b11 --> NOT POSSIBLE */ #define LCD_PALETTE_ALL 0x30 +# endif #endif /** @@ -455,12 +522,15 @@ struct count_s enum gb_error_e { GB_UNKNOWN_ERROR = 0, - GB_INVALID_OPCODE, - GB_INVALID_READ, - GB_INVALID_WRITE, - GB_HALT_FOREVER, + GB_INVALID_OPCODE = 1, + GB_INVALID_READ = 2, + GB_INVALID_WRITE = 3, - GB_INVALID_MAX + /* GB_HALT_FOREVER is deprecated and will no longer be issued as an + * error by Peanut-GB. */ + GB_HALT_FOREVER PGB_DEPRECATED("Error no longer issued by Peanut-GB") = 4, + + GB_INVALID_MAX = 5 }; /** @@ -470,7 +540,9 @@ enum gb_init_error_e { GB_INIT_NO_ERROR = 0, GB_INIT_CARTRIDGE_UNSUPPORTED, - GB_INIT_INVALID_CHECKSUM + GB_INIT_INVALID_CHECKSUM, + + GB_INIT_INVALID_MAX }; /** @@ -482,6 +554,19 @@ enum gb_serial_rx_ret_e GB_SERIAL_RX_NO_CONNECTION = 1 }; +union cart_rtc +{ + struct + { + uint8_t sec; + uint8_t min; + uint8_t hour; + uint8_t yday; + uint8_t high; + } reg; + uint8_t bytes[5]; +}; + /** * Emulator context. * @@ -521,9 +606,9 @@ struct gb_s /** * Notify front-end of error. * - * \param gb_s emulator context + * \param gb_s emulator context * \param gb_error_e error code - * \param addr address of where error occurred + * \param addr address of where error occurred */ void (*gb_error)(struct gb_s*, const enum gb_error_e, const uint16_t addr); @@ -536,10 +621,10 @@ struct gb_s struct { - unsigned gb_halt : 1; - unsigned gb_ime : 1; - unsigned gb_frame : 1; /* New frame drawn. */ - unsigned lcd_blank : 1; + bool gb_halt : 1; + bool gb_ime : 1; + bool gb_frame : 1; /* New frame drawn. */ + bool lcd_blank : 1; }; /* Cartridge information: @@ -558,18 +643,8 @@ struct gb_s uint8_t enable_cart_ram; /* Cartridge ROM/RAM mode select. */ uint8_t cart_mode_select; - union - { - struct - { - uint8_t sec; - uint8_t min; - uint8_t hour; - uint8_t yday; - uint8_t high; - } rtc_bits; - uint8_t cart_rtc[5]; - }; + + union cart_rtc rtc_latched, rtc_real; struct cpu_registers_s cpu_reg; //struct gb_registers_s gb_reg; @@ -614,8 +689,8 @@ struct gb_s uint8_t WY; /* Only support 30fps frame skip. */ - unsigned frame_skip_count : 1; - unsigned interlace_count : 1; + bool frame_skip_count : 1; + bool interlace_count : 1; } display; /** @@ -630,21 +705,25 @@ struct gb_s /* Set to enable interlacing. Interlacing will start immediately * (at the next line drawing). */ - unsigned interlace : 1; - unsigned frame_skip : 1; + bool interlace : 1; + bool frame_skip : 1; union { struct { - unsigned a : 1; - unsigned b : 1; - unsigned select : 1; - unsigned start : 1; - unsigned right : 1; - unsigned left : 1; - unsigned up : 1; - unsigned down : 1; + /* Using this bitfield is deprecated due to + * portability concerns. It is recommended to + * use the JOYPAD_* defines instead. + */ + bool a : 1; + bool b : 1; + bool select : 1; + bool start : 1; + bool right : 1; + bool left : 1; + bool up : 1; + bool down : 1; } joypad_bits; uint8_t joypad; }; @@ -664,7 +743,6 @@ struct gb_s #define IO_TMA 0x06 #define IO_TAC 0x07 #define IO_IF 0x0F -#define IO_BOOT 0x50 #define IO_LCDC 0x40 #define IO_STAT 0x41 #define IO_SCY 0x42 @@ -677,7 +755,7 @@ struct gb_s #define IO_OBP1 0x49 #define IO_WY 0x4A #define IO_WX 0x4B -#define IO_BANK 0x50 +#define IO_BOOT 0x50 #define IO_IE 0xFF #define IO_TAC_RATE_MASK 0x3 @@ -686,8 +764,8 @@ struct gb_s /* LCD Mode defines. */ #define IO_STAT_MODE_HBLANK 0 #define IO_STAT_MODE_VBLANK 1 -#define IO_STAT_MODE_SEARCH_OAM 2 -#define IO_STAT_MODE_SEARCH_TRANSFER 3 +#define IO_STAT_MODE_OAM_SCAN 2 +#define IO_STAT_MODE_LCD_DRAW 3 #define IO_STAT_MODE_VBLANK_OR_TRANSFER_MASK 0x1 /** @@ -699,9 +777,9 @@ uint8_t __gb_read(struct gb_s *gb, uint16_t addr) switch(PEANUT_GB_GET_MSN16(addr)) { case 0x0: - /* IO_BANK is only set to 1 if gb->gb_bootrom_read was not NULL + /* IO_BOOT is only set to 1 if gb->gb_bootrom_read was not NULL * on reset. */ - if(gb->hram_io[IO_BANK] == 0 && addr < 0x0100) + if(gb->hram_io[IO_BOOT] == 0 && addr < 0x0100) { return gb->gb_bootrom_read(gb, addr); } @@ -728,11 +806,13 @@ uint8_t __gb_read(struct gb_s *gb, uint16_t addr) case 0xA: case 0xB: - if(gb->cart_ram && gb->enable_cart_ram) + if(gb->mbc == 3 && gb->cart_ram_bank >= 0x08) { - if(gb->mbc == 3 && gb->cart_ram_bank >= 0x08) - return gb->cart_rtc[gb->cart_ram_bank - 0x08]; - else if(gb->mbc == 2) + return gb->rtc_latched.bytes[gb->cart_ram_bank - 0x08]; + } + else if(gb->cart_ram && gb->enable_cart_ram) + { + if(gb->mbc == 2) { /* Only 9 bits are available in address. */ addr &= 0x1FF; @@ -882,7 +962,12 @@ void __gb_write(struct gb_s *gb, uint_fast16_t addr, uint8_t val) case 0x6: case 0x7: - gb->cart_mode_select = (val & 1); + val &= 1; + if(gb->mbc == 3 && val && gb->cart_mode_select == 0) + memcpy(&gb->rtc_latched.bytes, &gb->rtc_real.bytes, sizeof(gb->rtc_latched.bytes)); + + /* Set banking mode select. */ + gb->cart_mode_select = val; return; case 0x8: @@ -892,24 +977,37 @@ void __gb_write(struct gb_s *gb, uint_fast16_t addr, uint8_t val) case 0xA: case 0xB: - /* Do not write to RAM if unavailable or disabled. */ - if(gb->cart_ram && gb->enable_cart_ram) + if(gb->mbc == 3 && gb->cart_ram_bank >= 0x08) { - if(gb->mbc == 3 && gb->cart_ram_bank >= 0x08) - gb->cart_rtc[gb->cart_ram_bank - 0x08] = val; - else if(gb->mbc == 2) + const uint8_t rtc_reg_mask[5] = { + 0x3F, 0x3F, 0x1F, 0xFF, 0xC1 + }; + uint8_t reg = gb->cart_ram_bank - 0x08; + //if(reg == 0) gb->counter.rtc_count = 0; + + gb->rtc_real.bytes[reg] = val & rtc_reg_mask[reg]; + } + /* Do not write to RAM if unavailable or disabled. */ + else if(gb->cart_ram && gb->enable_cart_ram) + { + if(gb->mbc == 2) { /* Only 9 bits are available in address. */ addr &= 0x1FF; /* Data is only 4 bits wide in MBC2 RAM. */ val &= 0x0F; + /* Upper nibble is set to high. */ + val |= 0xF0; gb->gb_cart_ram_write(gb, addr, val); } - else if(gb->cart_mode_select && + /* If cart has RAM, use this. If MBC1, only the first + * RAM bank can be written to if the advanced banking + * mode is selected. */ + else if(((gb->mbc == 1 && gb->cart_mode_select) || gb->mbc != 1) && gb->cart_ram_bank < gb->num_ram_banks) { gb->gb_cart_ram_write(gb, - addr - CART_RAM_ADDR + (gb->cart_ram_bank * CRAM_BANK_SIZE), val); + addr - CART_RAM_ADDR + (gb->cart_ram_bank * CRAM_BANK_SIZE), val); } else if(gb->num_ram_banks) gb->gb_cart_ram_write(gb, addr - CART_RAM_ADDR, val); @@ -973,7 +1071,7 @@ void __gb_write(struct gb_s *gb, uint_fast16_t addr, uint8_t val) gb->hram_io[IO_JOYP] = val; /* Direction keys selected */ - if((gb->hram_io[IO_JOYP] & 0b010000) == 0) + if((gb->hram_io[IO_JOYP] & 0x10) == 0) gb->hram_io[IO_JOYP] |= (gb->direct.joypad >> 4); /* Button keys selected */ else @@ -1009,7 +1107,7 @@ void __gb_write(struct gb_s *gb, uint_fast16_t addr, uint8_t val) /* Interrupt Flag Register */ case 0x0F: - gb->hram_io[IO_IF] = (val | 0b11100000); + gb->hram_io[IO_IF] = (val | 0xE0); return; /* LCD Registers */ @@ -1025,7 +1123,7 @@ void __gb_write(struct gb_s *gb, uint_fast16_t addr, uint8_t val) /* Check if LCD is going to be switched on. */ if (!lcd_enabled && (val & LCDC_ENABLE)) { - gb->lcd_blank = 1; + gb->lcd_blank = true; } /* Check if LCD is being switched off. */ else if (lcd_enabled && !(val & LCDC_ENABLE)) @@ -1047,7 +1145,7 @@ void __gb_write(struct gb_s *gb, uint_fast16_t addr, uint8_t val) } case 0x41: - gb->hram_io[IO_STAT] = (val & STAT_USER_BITS) | (gb->hram_io[IO_STAT] & STAT_MODE); + gb->hram_io[IO_STAT] = (val & STAT_USER_BITS) | (gb->hram_io[IO_STAT] & STAT_MODE) | 0x80; return; case 0x42: @@ -1066,10 +1164,13 @@ void __gb_write(struct gb_s *gb, uint_fast16_t addr, uint8_t val) /* DMA Register */ case 0x46: { - uint16_t dma_addr = (uint_fast16_t)val << 8; + uint16_t dma_addr; + uint16_t i; + + dma_addr = (uint_fast16_t)val << 8; gb->hram_io[IO_DMA] = val; - for(uint16_t i = 0; i < OAM_SIZE; i++) + for(i = 0; i < OAM_SIZE; i++) { gb->oam[i] = __gb_read(gb, dma_addr + i); } @@ -1113,7 +1214,7 @@ void __gb_write(struct gb_s *gb, uint_fast16_t addr, uint8_t val) /* Turn off boot ROM */ case 0x50: - gb->hram_io[IO_BANK] = val; + gb->hram_io[IO_BOOT] = 0x01; return; /* Interrupt Enable Register */ @@ -1188,7 +1289,6 @@ uint8_t __gb_execute_cb(struct gb_s *gb) break; } - /* TODO: Find out WTF this is doing. */ switch(cbop >> 6) { case 0x0: @@ -1202,21 +1302,19 @@ uint8_t __gb_execute_cb(struct gb_s *gb) { uint8_t temp = val; val = (val >> 1); - val |= cbop ? (gb->cpu_reg.f_bits.c << 7) : (temp << 7); - gb->cpu_reg.f_bits.z = (val == 0x00); - gb->cpu_reg.f_bits.n = 0; - gb->cpu_reg.f_bits.h = 0; - gb->cpu_reg.f_bits.c = (temp & 0x01); + val |= cbop ? (gb->cpu_reg.f.f_bits.c << 7) : (temp << 7); + gb->cpu_reg.f.reg = 0; + gb->cpu_reg.f.f_bits.z = (val == 0x00); + gb->cpu_reg.f.f_bits.c = (temp & 0x01); } else /* RLC R / RL R */ { uint8_t temp = val; val = (val << 1); - val |= cbop ? gb->cpu_reg.f_bits.c : (temp >> 7); - gb->cpu_reg.f_bits.z = (val == 0x00); - gb->cpu_reg.f_bits.n = 0; - gb->cpu_reg.f_bits.h = 0; - gb->cpu_reg.f_bits.c = (temp >> 7); + val |= cbop ? gb->cpu_reg.f.f_bits.c : (temp >> 7); + gb->cpu_reg.f.reg = 0; + gb->cpu_reg.f.f_bits.z = (val == 0x00); + gb->cpu_reg.f.f_bits.c = (temp >> 7); } break; @@ -1224,19 +1322,17 @@ uint8_t __gb_execute_cb(struct gb_s *gb) case 0x2: if(d) /* SRA R */ { - gb->cpu_reg.f_bits.c = val & 0x01; + gb->cpu_reg.f.reg = 0; + gb->cpu_reg.f.f_bits.c = val & 0x01; val = (val >> 1) | (val & 0x80); - gb->cpu_reg.f_bits.z = (val == 0x00); - gb->cpu_reg.f_bits.n = 0; - gb->cpu_reg.f_bits.h = 0; + gb->cpu_reg.f.f_bits.z = (val == 0x00); } else /* SLA R */ { - gb->cpu_reg.f_bits.c = (val >> 7); + gb->cpu_reg.f.reg = 0; + gb->cpu_reg.f.f_bits.c = (val >> 7); val = val << 1; - gb->cpu_reg.f_bits.z = (val == 0x00); - gb->cpu_reg.f_bits.n = 0; - gb->cpu_reg.f_bits.h = 0; + gb->cpu_reg.f.f_bits.z = (val == 0x00); } break; @@ -1244,21 +1340,18 @@ uint8_t __gb_execute_cb(struct gb_s *gb) case 0x3: if(d) /* SRL R */ { - gb->cpu_reg.f_bits.c = val & 0x01; + gb->cpu_reg.f.reg = 0; + gb->cpu_reg.f.f_bits.c = val & 0x01; val = val >> 1; - gb->cpu_reg.f_bits.z = (val == 0x00); - gb->cpu_reg.f_bits.n = 0; - gb->cpu_reg.f_bits.h = 0; + gb->cpu_reg.f.f_bits.z = (val == 0x00); } else /* SWAP R */ { uint8_t temp = (val >> 4) & 0x0F; temp |= (val << 4) & 0xF0; val = temp; - gb->cpu_reg.f_bits.z = (val == 0x00); - gb->cpu_reg.f_bits.n = 0; - gb->cpu_reg.f_bits.h = 0; - gb->cpu_reg.f_bits.c = 0; + gb->cpu_reg.f.reg = 0; + gb->cpu_reg.f.f_bits.z = (val == 0x00); } break; @@ -1267,9 +1360,9 @@ uint8_t __gb_execute_cb(struct gb_s *gb) break; case 0x1: /* BIT B, R */ - gb->cpu_reg.f_bits.z = !((val >> b) & 0x1); - gb->cpu_reg.f_bits.n = 0; - gb->cpu_reg.f_bits.h = 1; + gb->cpu_reg.f.f_bits.z = !((val >> b) & 0x1); + gb->cpu_reg.f.f_bits.n = 0; + gb->cpu_reg.f.f_bits.h = 1; writeback = 0; break; @@ -1332,10 +1425,11 @@ struct sprite_data { static int compare_sprites(const void *in1, const void *in2) { const struct sprite_data *sd1, *sd2; + int x_res; sd1 = (struct sprite_data *)in1; sd2 = (struct sprite_data *)in2; - int x_res = (int)sd1->x - (int)sd2->x; + x_res = (int)sd1->x - (int)sd2->x; if(x_res != 0) return x_res; @@ -1358,9 +1452,9 @@ void __gb_draw_line(struct gb_s *gb) * line. */ if(gb->direct.interlace) { - if((gb->display.interlace_count == 0 + if((!gb->display.interlace_count && (gb->hram_io[IO_LY] & 1) == 0) - || (gb->display.interlace_count == 1 + || (gb->display.interlace_count && (gb->hram_io[IO_LY] & 1) == 1)) { /* Compensate for missing window draw if required. */ @@ -1376,35 +1470,36 @@ void __gb_draw_line(struct gb_s *gb) /* If background is enabled, draw it. */ if(gb->hram_io[IO_LCDC] & LCDC_BG_ENABLE) { + uint8_t bg_y, disp_x, bg_x, idx, py, px, t1, t2; + uint16_t bg_map, tile; + /* Calculate current background line to draw. Constant because * this function draws only this one line each time it is * called. */ - const uint8_t bg_y = gb->hram_io[IO_LY] + gb->hram_io[IO_SCY]; + bg_y = gb->hram_io[IO_LY] + gb->hram_io[IO_SCY]; /* Get selected background map address for first tile * corresponding to current line. * 0x20 (32) is the width of a background tile, and the bit * shift is to calculate the address. */ - const uint16_t bg_map = + bg_map = ((gb->hram_io[IO_LCDC] & LCDC_BG_MAP) ? VRAM_BMAP_2 : VRAM_BMAP_1) + (bg_y >> 3) * 0x20; /* The displays (what the player sees) X coordinate, drawn right * to left. */ - uint8_t disp_x = LCD_WIDTH - 1; + disp_x = LCD_WIDTH - 1; /* The X coordinate to begin drawing the background at. */ - uint8_t bg_x = disp_x + gb->hram_io[IO_SCX]; + bg_x = disp_x + gb->hram_io[IO_SCX]; /* Get tile index for current background tile. */ - uint8_t idx = gb->vram[bg_map + (bg_x >> 3)]; + idx = gb->vram[bg_map + (bg_x >> 3)]; /* Y coordinate of tile pixel to draw. */ - const uint8_t py = (bg_y & 0x07); + py = (bg_y & 0x07); /* X coordinate of tile pixel to draw. */ - uint8_t px = 7 - (bg_x & 0x07); - - uint16_t tile; + px = 7 - (bg_x & 0x07); /* Select addressing mode. */ if(gb->hram_io[IO_LCDC] & LCDC_TILE_SELECT) @@ -1415,11 +1510,13 @@ void __gb_draw_line(struct gb_s *gb) tile += 2 * py; /* fetch first tile */ - uint8_t t1 = gb->vram[tile] >> px; - uint8_t t2 = gb->vram[tile + 1] >> px; + t1 = gb->vram[tile] >> px; + t2 = gb->vram[tile + 1] >> px; for(; disp_x != 0xFF; disp_x--) { + uint8_t c; + if(px == 8) { /* fetch next tile */ @@ -1438,9 +1535,11 @@ void __gb_draw_line(struct gb_s *gb) } /* copy background */ - uint8_t c = (t1 & 0x1) | ((t2 & 0x1) << 1); + c = (t1 & 0x1) | ((t2 & 0x1) << 1); pixels[disp_x] = gb->display.bg_palette[c]; +#if PEANUT_GB_12_COLOUR pixels[disp_x] |= LCD_PALETTE_BG; +#endif t1 = t1 >> 1; t2 = t2 >> 1; px++; @@ -1452,20 +1551,21 @@ void __gb_draw_line(struct gb_s *gb) && gb->hram_io[IO_LY] >= gb->display.WY && gb->hram_io[IO_WX] <= 166) { + uint16_t win_line, tile; + uint8_t disp_x, win_x, py, px, idx, t1, t2, end; + /* Calculate Window Map Address. */ - uint16_t win_line = (gb->hram_io[IO_LCDC] & LCDC_WINDOW_MAP) ? + win_line = (gb->hram_io[IO_LCDC] & LCDC_WINDOW_MAP) ? VRAM_BMAP_2 : VRAM_BMAP_1; win_line += (gb->display.window_clear >> 3) * 0x20; - uint8_t disp_x = LCD_WIDTH - 1; - uint8_t win_x = disp_x - gb->hram_io[IO_WX] + 7; + disp_x = LCD_WIDTH - 1; + win_x = disp_x - gb->hram_io[IO_WX] + 7; // look up tile - uint8_t py = gb->display.window_clear & 0x07; - uint8_t px = 7 - (win_x & 0x07); - uint8_t idx = gb->vram[win_line + (win_x >> 3)]; - - uint16_t tile; + py = gb->display.window_clear & 0x07; + px = 7 - (win_x & 0x07); + idx = gb->vram[win_line + (win_x >> 3)]; if(gb->hram_io[IO_LCDC] & LCDC_TILE_SELECT) tile = VRAM_TILES_1 + idx * 0x10; @@ -1475,14 +1575,16 @@ void __gb_draw_line(struct gb_s *gb) tile += 2 * py; // fetch first tile - uint8_t t1 = gb->vram[tile] >> px; - uint8_t t2 = gb->vram[tile + 1] >> px; + t1 = gb->vram[tile] >> px; + t2 = gb->vram[tile + 1] >> px; // loop & copy window - uint8_t end = (gb->hram_io[IO_WX] < 7 ? 0 : gb->hram_io[IO_WX] - 7) - 1; + end = (gb->hram_io[IO_WX] < 7 ? 0 : gb->hram_io[IO_WX] - 7) - 1; for(; disp_x != end; disp_x--) { + uint8_t c; + if(px == 8) { // fetch next tile @@ -1501,9 +1603,11 @@ void __gb_draw_line(struct gb_s *gb) } // copy window - uint8_t c = (t1 & 0x1) | ((t2 & 0x1) << 1); + c = (t1 & 0x1) | ((t2 & 0x1) << 1); pixels[disp_x] = gb->display.bg_palette[c]; +#if PEANUT_GB_12_COLOUR pixels[disp_x] |= LCD_PALETTE_BG; +#endif t1 = t1 >> 1; t2 = t2 >> 1; px++; @@ -1515,14 +1619,16 @@ void __gb_draw_line(struct gb_s *gb) // draw sprites if(gb->hram_io[IO_LCDC] & LCDC_OBJ_ENABLE) { + uint8_t sprite_number; #if PEANUT_GB_HIGH_LCD_ACCURACY uint8_t number_of_sprites = 0; + struct sprite_data sprites_to_render[NUM_SPRITES]; /* Record number of sprites on the line being rendered, limited * to the maximum number sprites that the Game Boy is able to * render on each line (10 sprites). */ - for(uint8_t sprite_number = 0; + for(sprite_number = 0; sprite_number < PEANUT_GB_ARRAYSIZE(sprites_to_render); sprite_number++) { @@ -1554,18 +1660,19 @@ void __gb_draw_line(struct gb_s *gb) /* Render each sprite, from low priority to high priority. */ #if PEANUT_GB_HIGH_LCD_ACCURACY /* Render the top ten prioritised sprites on this scanline. */ - for(uint8_t sprite_number = number_of_sprites - 1; + for(sprite_number = number_of_sprites - 1; sprite_number != 0xFF; sprite_number--) { uint8_t s = sprites_to_render[sprite_number].sprite_number; #else - for (uint8_t sprite_number = NUM_SPRITES - 1; + for (sprite_number = NUM_SPRITES - 1; sprite_number != 0xFF; sprite_number--) { uint8_t s = sprite_number; #endif + uint8_t py, t1, t2, dir, start, end, shift, disp_x; /* Sprite Y position. */ uint8_t OY = gb->oam[4 * s + 0]; /* Sprite X position. */ @@ -1589,18 +1696,16 @@ void __gb_draw_line(struct gb_s *gb) continue; // y flip - uint8_t py = gb->hram_io[IO_LY] - OY + 16; + py = gb->hram_io[IO_LY] - OY + 16; if(OF & OBJ_FLIP_Y) py = (gb->hram_io[IO_LCDC] & LCDC_OBJ_SIZE ? 15 : 7) - py; // fetch the tile - uint8_t t1 = gb->vram[VRAM_TILES_1 + OT * 0x10 + 2 * py]; - uint8_t t2 = gb->vram[VRAM_TILES_1 + OT * 0x10 + 2 * py + 1]; + t1 = gb->vram[VRAM_TILES_1 + OT * 0x10 + 2 * py]; + t2 = gb->vram[VRAM_TILES_1 + OT * 0x10 + 2 * py + 1]; // handle x flip - uint8_t dir, start, end, shift; - if(OF & OBJ_FLIP_X) { dir = 1; @@ -1610,7 +1715,7 @@ void __gb_draw_line(struct gb_s *gb) } else { - dir = -1; + dir = (uint8_t)-1; start = MIN(OX, LCD_WIDTH) - 1; end = (OX < 8 ? 0 : OX - 8) - 1; shift = OX - (start + 1); @@ -1623,7 +1728,7 @@ void __gb_draw_line(struct gb_s *gb) /* TODO: Put for loop within the to if statements * because the BG priority bit will be the same for * all the pixels in the tile. */ - for(uint8_t disp_x = start; disp_x != end; disp_x += dir) + for(disp_x = start; disp_x != end; disp_x += dir) { uint8_t c = (t1 & 0x1) | ((t2 & 0x1) << 1); // check transparency / sprite overlap / background overlap @@ -1634,8 +1739,10 @@ void __gb_draw_line(struct gb_s *gb) pixels[disp_x] = (OF & OBJ_PALETTE) ? gb->display.sp_palette[c + 4] : gb->display.sp_palette[c]; +#if PEANUT_GB_12_COLOUR /* Set pixel palette (OBJ0 or OBJ1). */ pixels[disp_x] |= (OF & OBJ_PALETTE); +#endif } t1 = t1 >> 1; @@ -1680,19 +1787,19 @@ void __gb_step_cpu(struct gb_s *gb) static const uint_fast16_t TAC_CYCLES[4] = {1024, 16, 64, 256}; /* Handle interrupts */ - /* If gb_halt is positive, then an interrupt must have occured by the - * time we reach here, becuase on HALT, we jump to the next interrupt + /* If gb_halt is positive, then an interrupt must have occurred by the + * time we reach here, because on HALT, we jump to the next interrupt * immediately. */ while(gb->gb_halt || (gb->gb_ime && gb->hram_io[IO_IF] & gb->hram_io[IO_IE] & ANY_INTR)) { - gb->gb_halt = 0; + gb->gb_halt = false; if(!gb->gb_ime) break; /* Disable interrupts */ - gb->gb_ime = 0; + gb->gb_ime = false; /* Push Program Counter */ __gb_write(gb, --gb->cpu_reg.sp.reg, gb->cpu_reg.pc.bytes.p); @@ -1752,10 +1859,7 @@ void __gb_step_cpu(struct gb_s *gb) break; case 0x04: /* INC B */ - gb->cpu_reg.bc.bytes.b++; - gb->cpu_reg.f_bits.z = (gb->cpu_reg.bc.bytes.b == 0x00); - gb->cpu_reg.f_bits.n = 0; - gb->cpu_reg.f_bits.h = ((gb->cpu_reg.bc.bytes.b & 0x0F) == 0x00); + PGB_INSTR_INC_R8(gb->cpu_reg.bc.bytes.b); break; case 0x05: /* DEC B */ @@ -1768,10 +1872,8 @@ void __gb_step_cpu(struct gb_s *gb) case 0x07: /* RLCA */ gb->cpu_reg.a = (gb->cpu_reg.a << 1) | (gb->cpu_reg.a >> 7); - gb->cpu_reg.f_bits.z = 0; - gb->cpu_reg.f_bits.n = 0; - gb->cpu_reg.f_bits.h = 0; - gb->cpu_reg.f_bits.c = (gb->cpu_reg.a & 0x01); + gb->cpu_reg.f.reg = 0; + gb->cpu_reg.f.f_bits.c = (gb->cpu_reg.a & 0x01); break; case 0x08: /* LD (imm), SP */ @@ -1789,10 +1891,10 @@ void __gb_step_cpu(struct gb_s *gb) case 0x09: /* ADD HL, BC */ { uint_fast32_t temp = gb->cpu_reg.hl.reg + gb->cpu_reg.bc.reg; - gb->cpu_reg.f_bits.n = 0; - gb->cpu_reg.f_bits.h = + gb->cpu_reg.f.f_bits.n = 0; + gb->cpu_reg.f.f_bits.h = (temp ^ gb->cpu_reg.hl.reg ^ gb->cpu_reg.bc.reg) & 0x1000 ? 1 : 0; - gb->cpu_reg.f_bits.c = (temp & 0xFFFF0000) ? 1 : 0; + gb->cpu_reg.f.f_bits.c = (temp & 0xFFFF0000) ? 1 : 0; gb->cpu_reg.hl.reg = (temp & 0x0000FFFF); break; } @@ -1806,10 +1908,7 @@ void __gb_step_cpu(struct gb_s *gb) break; case 0x0C: /* INC C */ - gb->cpu_reg.bc.bytes.c++; - gb->cpu_reg.f_bits.z = (gb->cpu_reg.bc.bytes.c == 0x00); - gb->cpu_reg.f_bits.n = 0; - gb->cpu_reg.f_bits.h = ((gb->cpu_reg.bc.bytes.c & 0x0F) == 0x00); + PGB_INSTR_INC_R8(gb->cpu_reg.bc.bytes.c); break; case 0x0D: /* DEC C */ @@ -1821,15 +1920,13 @@ void __gb_step_cpu(struct gb_s *gb) break; case 0x0F: /* RRCA */ - gb->cpu_reg.f_bits.c = gb->cpu_reg.a & 0x01; + gb->cpu_reg.f.reg = 0; + gb->cpu_reg.f.f_bits.c = gb->cpu_reg.a & 0x01; gb->cpu_reg.a = (gb->cpu_reg.a >> 1) | (gb->cpu_reg.a << 7); - gb->cpu_reg.f_bits.z = 0; - gb->cpu_reg.f_bits.n = 0; - gb->cpu_reg.f_bits.h = 0; break; case 0x10: /* STOP */ - //gb->gb_halt = 1; + //gb->gb_halt = true; break; case 0x11: /* LD DE, imm */ @@ -1846,10 +1943,7 @@ void __gb_step_cpu(struct gb_s *gb) break; case 0x14: /* INC D */ - gb->cpu_reg.de.bytes.d++; - gb->cpu_reg.f_bits.z = (gb->cpu_reg.de.bytes.d == 0x00); - gb->cpu_reg.f_bits.n = 0; - gb->cpu_reg.f_bits.h = ((gb->cpu_reg.de.bytes.d & 0x0F) == 0x00); + PGB_INSTR_INC_R8(gb->cpu_reg.de.bytes.d); break; case 0x15: /* DEC D */ @@ -1863,11 +1957,9 @@ void __gb_step_cpu(struct gb_s *gb) case 0x17: /* RLA */ { uint8_t temp = gb->cpu_reg.a; - gb->cpu_reg.a = (gb->cpu_reg.a << 1) | gb->cpu_reg.f_bits.c; - gb->cpu_reg.f_bits.z = 0; - gb->cpu_reg.f_bits.n = 0; - gb->cpu_reg.f_bits.h = 0; - gb->cpu_reg.f_bits.c = (temp >> 7) & 0x01; + gb->cpu_reg.a = (gb->cpu_reg.a << 1) | gb->cpu_reg.f.f_bits.c; + gb->cpu_reg.f.reg = 0; + gb->cpu_reg.f.f_bits.c = (temp >> 7) & 0x01; break; } @@ -1881,10 +1973,10 @@ void __gb_step_cpu(struct gb_s *gb) case 0x19: /* ADD HL, DE */ { uint_fast32_t temp = gb->cpu_reg.hl.reg + gb->cpu_reg.de.reg; - gb->cpu_reg.f_bits.n = 0; - gb->cpu_reg.f_bits.h = + gb->cpu_reg.f.f_bits.n = 0; + gb->cpu_reg.f.f_bits.h = (temp ^ gb->cpu_reg.hl.reg ^ gb->cpu_reg.de.reg) & 0x1000 ? 1 : 0; - gb->cpu_reg.f_bits.c = (temp & 0xFFFF0000) ? 1 : 0; + gb->cpu_reg.f.f_bits.c = (temp & 0xFFFF0000) ? 1 : 0; gb->cpu_reg.hl.reg = (temp & 0x0000FFFF); break; } @@ -1898,10 +1990,7 @@ void __gb_step_cpu(struct gb_s *gb) break; case 0x1C: /* INC E */ - gb->cpu_reg.de.bytes.e++; - gb->cpu_reg.f_bits.z = (gb->cpu_reg.de.bytes.e == 0x00); - gb->cpu_reg.f_bits.n = 0; - gb->cpu_reg.f_bits.h = ((gb->cpu_reg.de.bytes.e & 0x0F) == 0x00); + PGB_INSTR_INC_R8(gb->cpu_reg.de.bytes.e); break; case 0x1D: /* DEC E */ @@ -1915,16 +2004,14 @@ void __gb_step_cpu(struct gb_s *gb) case 0x1F: /* RRA */ { uint8_t temp = gb->cpu_reg.a; - gb->cpu_reg.a = gb->cpu_reg.a >> 1 | (gb->cpu_reg.f_bits.c << 7); - gb->cpu_reg.f_bits.z = 0; - gb->cpu_reg.f_bits.n = 0; - gb->cpu_reg.f_bits.h = 0; - gb->cpu_reg.f_bits.c = temp & 0x1; + gb->cpu_reg.a = gb->cpu_reg.a >> 1 | (gb->cpu_reg.f.f_bits.c << 7); + gb->cpu_reg.f.reg = 0; + gb->cpu_reg.f.f_bits.c = temp & 0x1; break; } case 0x20: /* JR NZ, imm */ - if(!gb->cpu_reg.f_bits.z) + if(!gb->cpu_reg.f.f_bits.z) { int8_t temp = (int8_t) __gb_read(gb, gb->cpu_reg.pc.reg++); gb->cpu_reg.pc.reg += temp; @@ -1950,10 +2037,7 @@ void __gb_step_cpu(struct gb_s *gb) break; case 0x24: /* INC H */ - gb->cpu_reg.hl.bytes.h++; - gb->cpu_reg.f_bits.z = (gb->cpu_reg.hl.bytes.h == 0x00); - gb->cpu_reg.f_bits.n = 0; - gb->cpu_reg.f_bits.h = ((gb->cpu_reg.hl.bytes.h & 0x0F) == 0x00); + PGB_INSTR_INC_R8(gb->cpu_reg.hl.bytes.h); break; case 0x25: /* DEC H */ @@ -1969,35 +2053,35 @@ void __gb_step_cpu(struct gb_s *gb) /* The following is from SameBoy. MIT License. */ int16_t a = gb->cpu_reg.a; - if(gb->cpu_reg.f_bits.n) + if(gb->cpu_reg.f.f_bits.n) { - if(gb->cpu_reg.f_bits.h) + if(gb->cpu_reg.f.f_bits.h) a = (a - 0x06) & 0xFF; - if(gb->cpu_reg.f_bits.c) + if(gb->cpu_reg.f.f_bits.c) a -= 0x60; } else { - if(gb->cpu_reg.f_bits.h || (a & 0x0F) > 9) + if(gb->cpu_reg.f.f_bits.h || (a & 0x0F) > 9) a += 0x06; - if(gb->cpu_reg.f_bits.c || a > 0x9F) + if(gb->cpu_reg.f.f_bits.c || a > 0x9F) a += 0x60; } if((a & 0x100) == 0x100) - gb->cpu_reg.f_bits.c = 1; + gb->cpu_reg.f.f_bits.c = 1; gb->cpu_reg.a = a; - gb->cpu_reg.f_bits.z = (gb->cpu_reg.a == 0); - gb->cpu_reg.f_bits.h = 0; + gb->cpu_reg.f.f_bits.z = (gb->cpu_reg.a == 0); + gb->cpu_reg.f.f_bits.h = 0; break; } - case 0x28: /* JP Z, imm */ - if(gb->cpu_reg.f_bits.z) + case 0x28: /* JR Z, imm */ + if(gb->cpu_reg.f.f_bits.z) { int8_t temp = (int8_t) __gb_read(gb, gb->cpu_reg.pc.reg++); gb->cpu_reg.pc.reg += temp; @@ -2010,10 +2094,10 @@ void __gb_step_cpu(struct gb_s *gb) case 0x29: /* ADD HL, HL */ { - gb->cpu_reg.f_bits.c = (gb->cpu_reg.hl.reg & 0x8000) > 0; + gb->cpu_reg.f.f_bits.c = (gb->cpu_reg.hl.reg & 0x8000) > 0; gb->cpu_reg.hl.reg <<= 1; - gb->cpu_reg.f_bits.n = 0; - gb->cpu_reg.f_bits.h = (gb->cpu_reg.hl.reg & 0x1000) > 0; + gb->cpu_reg.f.f_bits.n = 0; + gb->cpu_reg.f.f_bits.h = (gb->cpu_reg.hl.reg & 0x1000) > 0; break; } @@ -2026,10 +2110,7 @@ void __gb_step_cpu(struct gb_s *gb) break; case 0x2C: /* INC L */ - gb->cpu_reg.hl.bytes.l++; - gb->cpu_reg.f_bits.z = (gb->cpu_reg.hl.bytes.l == 0x00); - gb->cpu_reg.f_bits.n = 0; - gb->cpu_reg.f_bits.h = ((gb->cpu_reg.hl.bytes.l & 0x0F) == 0x00); + PGB_INSTR_INC_R8(gb->cpu_reg.hl.bytes.l); break; case 0x2D: /* DEC L */ @@ -2042,12 +2123,12 @@ void __gb_step_cpu(struct gb_s *gb) case 0x2F: /* CPL */ gb->cpu_reg.a = ~gb->cpu_reg.a; - gb->cpu_reg.f_bits.n = 1; - gb->cpu_reg.f_bits.h = 1; + gb->cpu_reg.f.f_bits.n = 1; + gb->cpu_reg.f.f_bits.h = 1; break; - case 0x30: /* JP NC, imm */ - if(!gb->cpu_reg.f_bits.c) + case 0x30: /* JR NC, imm */ + if(!gb->cpu_reg.f.f_bits.c) { int8_t temp = (int8_t) __gb_read(gb, gb->cpu_reg.pc.reg++); gb->cpu_reg.pc.reg += temp; @@ -2074,20 +2155,16 @@ void __gb_step_cpu(struct gb_s *gb) case 0x34: /* INC (HL) */ { - uint8_t temp = __gb_read(gb, gb->cpu_reg.hl.reg) + 1; - gb->cpu_reg.f_bits.z = (temp == 0x00); - gb->cpu_reg.f_bits.n = 0; - gb->cpu_reg.f_bits.h = ((temp & 0x0F) == 0x00); + uint8_t temp = __gb_read(gb, gb->cpu_reg.hl.reg); + PGB_INSTR_INC_R8(temp); __gb_write(gb, gb->cpu_reg.hl.reg, temp); break; } case 0x35: /* DEC (HL) */ { - uint8_t temp = __gb_read(gb, gb->cpu_reg.hl.reg) - 1; - gb->cpu_reg.f_bits.z = (temp == 0x00); - gb->cpu_reg.f_bits.n = 1; - gb->cpu_reg.f_bits.h = ((temp & 0x0F) == 0x0F); + uint8_t temp = __gb_read(gb, gb->cpu_reg.hl.reg); + PGB_INSTR_DEC_R8(temp); __gb_write(gb, gb->cpu_reg.hl.reg, temp); break; } @@ -2097,13 +2174,13 @@ void __gb_step_cpu(struct gb_s *gb) break; case 0x37: /* SCF */ - gb->cpu_reg.f_bits.n = 0; - gb->cpu_reg.f_bits.h = 0; - gb->cpu_reg.f_bits.c = 1; + gb->cpu_reg.f.f_bits.n = 0; + gb->cpu_reg.f.f_bits.h = 0; + gb->cpu_reg.f.f_bits.c = 1; break; - case 0x38: /* JP C, imm */ - if(gb->cpu_reg.f_bits.c) + case 0x38: /* JR C, imm */ + if(gb->cpu_reg.f.f_bits.c) { int8_t temp = (int8_t) __gb_read(gb, gb->cpu_reg.pc.reg++); gb->cpu_reg.pc.reg += temp; @@ -2117,10 +2194,10 @@ void __gb_step_cpu(struct gb_s *gb) case 0x39: /* ADD HL, SP */ { uint_fast32_t temp = gb->cpu_reg.hl.reg + gb->cpu_reg.sp.reg; - gb->cpu_reg.f_bits.n = 0; - gb->cpu_reg.f_bits.h = + gb->cpu_reg.f.f_bits.n = 0; + gb->cpu_reg.f.f_bits.h = ((gb->cpu_reg.hl.reg & 0xFFF) + (gb->cpu_reg.sp.reg & 0xFFF)) & 0x1000 ? 1 : 0; - gb->cpu_reg.f_bits.c = temp & 0x10000 ? 1 : 0; + gb->cpu_reg.f.f_bits.c = temp & 0x10000 ? 1 : 0; gb->cpu_reg.hl.reg = (uint16_t)temp; break; } @@ -2134,17 +2211,11 @@ void __gb_step_cpu(struct gb_s *gb) break; case 0x3C: /* INC A */ - gb->cpu_reg.a++; - gb->cpu_reg.f_bits.z = (gb->cpu_reg.a == 0x00); - gb->cpu_reg.f_bits.n = 0; - gb->cpu_reg.f_bits.h = ((gb->cpu_reg.a & 0x0F) == 0x00); + PGB_INSTR_INC_R8(gb->cpu_reg.a); break; case 0x3D: /* DEC A */ - gb->cpu_reg.a--; - gb->cpu_reg.f_bits.z = (gb->cpu_reg.a == 0x00); - gb->cpu_reg.f_bits.n = 1; - gb->cpu_reg.f_bits.h = ((gb->cpu_reg.a & 0x0F) == 0x0F); + PGB_INSTR_DEC_R8(gb->cpu_reg.a); break; case 0x3E: /* LD A, imm */ @@ -2152,9 +2223,9 @@ void __gb_step_cpu(struct gb_s *gb) break; case 0x3F: /* CCF */ - gb->cpu_reg.f_bits.n = 0; - gb->cpu_reg.f_bits.h = 0; - gb->cpu_reg.f_bits.c = ~gb->cpu_reg.f_bits.c; + gb->cpu_reg.f.f_bits.n = 0; + gb->cpu_reg.f.f_bits.h = 0; + gb->cpu_reg.f.f_bits.c = ~gb->cpu_reg.f.f_bits.c; break; case 0x40: /* LD B, B */ @@ -2372,16 +2443,7 @@ void __gb_step_cpu(struct gb_s *gb) int_fast16_t halt_cycles = INT_FAST16_MAX; /* TODO: Emulate HALT bug? */ - gb->gb_halt = 1; - - if (gb->hram_io[IO_IE] == 0) - { - /* Return program counter where this halt forever state started. */ - /* This may be intentional, but this is required to stop an infinite - * loop. */ - (gb->gb_error)(gb, GB_HALT_FOREVER, gb->cpu_reg.pc.reg - 1); - PGB_UNREACHABLE(); - } + gb->gb_halt = true; if(gb->hram_io[IO_SC] & SERIAL_SC_TX_START) { @@ -2410,24 +2472,20 @@ void __gb_step_cpu(struct gb_s *gb) * mode 1. */ if((gb->hram_io[IO_STAT] & STAT_MODE) == IO_STAT_MODE_HBLANK) { - lcd_cycles = LCD_MODE_2_CYCLES - - gb->counter.lcd_count; + lcd_cycles = LCD_MODE0_HBLANK_MAX_DRUATION - gb->counter.lcd_count; } - else if((gb->hram_io[IO_STAT] & STAT_MODE) == IO_STAT_MODE_SEARCH_OAM) + else if((gb->hram_io[IO_STAT] & STAT_MODE) == IO_STAT_MODE_OAM_SCAN) { - lcd_cycles = LCD_MODE_3_CYCLES - - gb->counter.lcd_count; + lcd_cycles = LCD_MODE3_LCD_DRAW_MIN_DURATION - gb->counter.lcd_count; } - else if((gb->hram_io[IO_STAT] & STAT_MODE) == IO_STAT_MODE_SEARCH_TRANSFER) + else if((gb->hram_io[IO_STAT] & STAT_MODE) == IO_STAT_MODE_LCD_DRAW) { - lcd_cycles = LCD_MODE_0_CYCLES - - gb->counter.lcd_count; + lcd_cycles = LCD_MODE0_HBLANK_MAX_DRUATION - gb->counter.lcd_count; } else { /* VBlank */ - lcd_cycles = - LCD_LINE_CYCLES - gb->counter.lcd_count; + lcd_cycles = LCD_LINE_CYCLES - gb->counter.lcd_count; } if(lcd_cycles < halt_cycles) @@ -2511,35 +2569,35 @@ void __gb_step_cpu(struct gb_s *gb) break; case 0x88: /* ADC A, B */ - PGB_INSTR_ADC_R8(gb->cpu_reg.bc.bytes.b, gb->cpu_reg.f_bits.c); + PGB_INSTR_ADC_R8(gb->cpu_reg.bc.bytes.b, gb->cpu_reg.f.f_bits.c); break; case 0x89: /* ADC A, C */ - PGB_INSTR_ADC_R8(gb->cpu_reg.bc.bytes.c, gb->cpu_reg.f_bits.c); + PGB_INSTR_ADC_R8(gb->cpu_reg.bc.bytes.c, gb->cpu_reg.f.f_bits.c); break; case 0x8A: /* ADC A, D */ - PGB_INSTR_ADC_R8(gb->cpu_reg.de.bytes.d, gb->cpu_reg.f_bits.c); + PGB_INSTR_ADC_R8(gb->cpu_reg.de.bytes.d, gb->cpu_reg.f.f_bits.c); break; case 0x8B: /* ADC A, E */ - PGB_INSTR_ADC_R8(gb->cpu_reg.de.bytes.e, gb->cpu_reg.f_bits.c); + PGB_INSTR_ADC_R8(gb->cpu_reg.de.bytes.e, gb->cpu_reg.f.f_bits.c); break; case 0x8C: /* ADC A, H */ - PGB_INSTR_ADC_R8(gb->cpu_reg.hl.bytes.h, gb->cpu_reg.f_bits.c); + PGB_INSTR_ADC_R8(gb->cpu_reg.hl.bytes.h, gb->cpu_reg.f.f_bits.c); break; case 0x8D: /* ADC A, L */ - PGB_INSTR_ADC_R8(gb->cpu_reg.hl.bytes.l, gb->cpu_reg.f_bits.c); + PGB_INSTR_ADC_R8(gb->cpu_reg.hl.bytes.l, gb->cpu_reg.f.f_bits.c); break; case 0x8E: /* ADC A, (HL) */ - PGB_INSTR_ADC_R8(__gb_read(gb, gb->cpu_reg.hl.reg), gb->cpu_reg.f_bits.c); + PGB_INSTR_ADC_R8(__gb_read(gb, gb->cpu_reg.hl.reg), gb->cpu_reg.f.f_bits.c); break; case 0x8F: /* ADC A, A */ - PGB_INSTR_ADC_R8(gb->cpu_reg.a, gb->cpu_reg.f_bits.c); + PGB_INSTR_ADC_R8(gb->cpu_reg.a, gb->cpu_reg.f.f_bits.c); break; case 0x90: /* SUB B */ @@ -2572,45 +2630,44 @@ void __gb_step_cpu(struct gb_s *gb) case 0x97: /* SUB A */ gb->cpu_reg.a = 0; - gb->cpu_reg.f_bits.z = 1; - gb->cpu_reg.f_bits.n = 1; - gb->cpu_reg.f_bits.h = 0; - gb->cpu_reg.f_bits.c = 0; + gb->cpu_reg.f.reg = 0; + gb->cpu_reg.f.f_bits.z = 1; + gb->cpu_reg.f.f_bits.n = 1; break; case 0x98: /* SBC A, B */ - PGB_INSTR_SBC_R8(gb->cpu_reg.bc.bytes.b, gb->cpu_reg.f_bits.c); + PGB_INSTR_SBC_R8(gb->cpu_reg.bc.bytes.b, gb->cpu_reg.f.f_bits.c); break; case 0x99: /* SBC A, C */ - PGB_INSTR_SBC_R8(gb->cpu_reg.bc.bytes.c, gb->cpu_reg.f_bits.c); + PGB_INSTR_SBC_R8(gb->cpu_reg.bc.bytes.c, gb->cpu_reg.f.f_bits.c); break; case 0x9A: /* SBC A, D */ - PGB_INSTR_SBC_R8(gb->cpu_reg.de.bytes.d, gb->cpu_reg.f_bits.c); + PGB_INSTR_SBC_R8(gb->cpu_reg.de.bytes.d, gb->cpu_reg.f.f_bits.c); break; case 0x9B: /* SBC A, E */ - PGB_INSTR_SBC_R8(gb->cpu_reg.de.bytes.e, gb->cpu_reg.f_bits.c); + PGB_INSTR_SBC_R8(gb->cpu_reg.de.bytes.e, gb->cpu_reg.f.f_bits.c); break; case 0x9C: /* SBC A, H */ - PGB_INSTR_SBC_R8(gb->cpu_reg.hl.bytes.h, gb->cpu_reg.f_bits.c); + PGB_INSTR_SBC_R8(gb->cpu_reg.hl.bytes.h, gb->cpu_reg.f.f_bits.c); break; case 0x9D: /* SBC A, L */ - PGB_INSTR_SBC_R8(gb->cpu_reg.hl.bytes.l, gb->cpu_reg.f_bits.c); + PGB_INSTR_SBC_R8(gb->cpu_reg.hl.bytes.l, gb->cpu_reg.f.f_bits.c); break; case 0x9E: /* SBC A, (HL) */ - PGB_INSTR_SBC_R8(__gb_read(gb, gb->cpu_reg.hl.reg), gb->cpu_reg.f_bits.c); + PGB_INSTR_SBC_R8(__gb_read(gb, gb->cpu_reg.hl.reg), gb->cpu_reg.f.f_bits.c); break; case 0x9F: /* SBC A, A */ - gb->cpu_reg.a = gb->cpu_reg.f_bits.c ? 0xFF : 0x00; - gb->cpu_reg.f_bits.z = !gb->cpu_reg.f_bits.c; - gb->cpu_reg.f_bits.n = 1; - gb->cpu_reg.f_bits.h = gb->cpu_reg.f_bits.c; + gb->cpu_reg.a = gb->cpu_reg.f.f_bits.c ? 0xFF : 0x00; + gb->cpu_reg.f.f_bits.z = !gb->cpu_reg.f.f_bits.c; + gb->cpu_reg.f.f_bits.n = 1; + gb->cpu_reg.f.f_bits.h = gb->cpu_reg.f.f_bits.c; break; case 0xA0: /* AND B */ @@ -2738,14 +2795,13 @@ void __gb_step_cpu(struct gb_s *gb) break; case 0xBF: /* CP A */ - gb->cpu_reg.f_bits.z = 1; - gb->cpu_reg.f_bits.n = 1; - gb->cpu_reg.f_bits.h = 0; - gb->cpu_reg.f_bits.c = 0; + gb->cpu_reg.f.reg = 0; + gb->cpu_reg.f.f_bits.z = 1; + gb->cpu_reg.f.f_bits.n = 1; break; case 0xC0: /* RET NZ */ - if(!gb->cpu_reg.f_bits.z) + if(!gb->cpu_reg.f.f_bits.z) { gb->cpu_reg.pc.bytes.c = __gb_read(gb, gb->cpu_reg.sp.reg++); gb->cpu_reg.pc.bytes.p = __gb_read(gb, gb->cpu_reg.sp.reg++); @@ -2760,7 +2816,7 @@ void __gb_step_cpu(struct gb_s *gb) break; case 0xC2: /* JP NZ, imm */ - if(!gb->cpu_reg.f_bits.z) + if(!gb->cpu_reg.f.f_bits.z) { uint8_t p, c; c = __gb_read(gb, gb->cpu_reg.pc.reg++); @@ -2785,7 +2841,7 @@ void __gb_step_cpu(struct gb_s *gb) } case 0xC4: /* CALL NZ imm */ - if(!gb->cpu_reg.f_bits.z) + if(!gb->cpu_reg.f.f_bits.z) { uint8_t p, c; c = __gb_read(gb, gb->cpu_reg.pc.reg++); @@ -2820,7 +2876,7 @@ void __gb_step_cpu(struct gb_s *gb) break; case 0xC8: /* RET Z */ - if(gb->cpu_reg.f_bits.z) + if(gb->cpu_reg.f.f_bits.z) { gb->cpu_reg.pc.bytes.c = __gb_read(gb, gb->cpu_reg.sp.reg++); gb->cpu_reg.pc.bytes.p = __gb_read(gb, gb->cpu_reg.sp.reg++); @@ -2836,7 +2892,7 @@ void __gb_step_cpu(struct gb_s *gb) } case 0xCA: /* JP Z, imm */ - if(gb->cpu_reg.f_bits.z) + if(gb->cpu_reg.f.f_bits.z) { uint8_t p, c; c = __gb_read(gb, gb->cpu_reg.pc.reg++); @@ -2855,7 +2911,7 @@ void __gb_step_cpu(struct gb_s *gb) break; case 0xCC: /* CALL Z, imm */ - if(gb->cpu_reg.f_bits.z) + if(gb->cpu_reg.f.f_bits.z) { uint8_t p, c; c = __gb_read(gb, gb->cpu_reg.pc.reg++); @@ -2886,7 +2942,7 @@ void __gb_step_cpu(struct gb_s *gb) case 0xCE: /* ADC A, imm */ { uint8_t val = __gb_read(gb, gb->cpu_reg.pc.reg++); - PGB_INSTR_ADC_R8(val, gb->cpu_reg.f_bits.c); + PGB_INSTR_ADC_R8(val, gb->cpu_reg.f.f_bits.c); break; } @@ -2897,7 +2953,7 @@ void __gb_step_cpu(struct gb_s *gb) break; case 0xD0: /* RET NC */ - if(!gb->cpu_reg.f_bits.c) + if(!gb->cpu_reg.f.f_bits.c) { gb->cpu_reg.pc.bytes.c = __gb_read(gb, gb->cpu_reg.sp.reg++); gb->cpu_reg.pc.bytes.p = __gb_read(gb, gb->cpu_reg.sp.reg++); @@ -2912,7 +2968,7 @@ void __gb_step_cpu(struct gb_s *gb) break; case 0xD2: /* JP NC, imm */ - if(!gb->cpu_reg.f_bits.c) + if(!gb->cpu_reg.f.f_bits.c) { uint8_t p, c; c = __gb_read(gb, gb->cpu_reg.pc.reg++); @@ -2927,7 +2983,7 @@ void __gb_step_cpu(struct gb_s *gb) break; case 0xD4: /* CALL NC, imm */ - if(!gb->cpu_reg.f_bits.c) + if(!gb->cpu_reg.f.f_bits.c) { uint8_t p, c; c = __gb_read(gb, gb->cpu_reg.pc.reg++); @@ -2952,11 +3008,11 @@ void __gb_step_cpu(struct gb_s *gb) { uint8_t val = __gb_read(gb, gb->cpu_reg.pc.reg++); uint16_t temp = gb->cpu_reg.a - val; - gb->cpu_reg.f_bits.z = ((temp & 0xFF) == 0x00); - gb->cpu_reg.f_bits.n = 1; - gb->cpu_reg.f_bits.h = + gb->cpu_reg.f.f_bits.z = ((temp & 0xFF) == 0x00); + gb->cpu_reg.f.f_bits.n = 1; + gb->cpu_reg.f.f_bits.h = (gb->cpu_reg.a ^ val ^ temp) & 0x10 ? 1 : 0; - gb->cpu_reg.f_bits.c = (temp & 0xFF00) ? 1 : 0; + gb->cpu_reg.f.f_bits.c = (temp & 0xFF00) ? 1 : 0; gb->cpu_reg.a = (temp & 0xFF); break; } @@ -2968,7 +3024,7 @@ void __gb_step_cpu(struct gb_s *gb) break; case 0xD8: /* RET C */ - if(gb->cpu_reg.f_bits.c) + if(gb->cpu_reg.f.f_bits.c) { gb->cpu_reg.pc.bytes.c = __gb_read(gb, gb->cpu_reg.sp.reg++); gb->cpu_reg.pc.bytes.p = __gb_read(gb, gb->cpu_reg.sp.reg++); @@ -2981,12 +3037,12 @@ void __gb_step_cpu(struct gb_s *gb) { gb->cpu_reg.pc.bytes.c = __gb_read(gb, gb->cpu_reg.sp.reg++); gb->cpu_reg.pc.bytes.p = __gb_read(gb, gb->cpu_reg.sp.reg++); - gb->gb_ime = 1; + gb->gb_ime = true; } break; case 0xDA: /* JP C, imm */ - if(gb->cpu_reg.f_bits.c) + if(gb->cpu_reg.f.f_bits.c) { uint8_t p, c; c = __gb_read(gb, gb->cpu_reg.pc.reg++); @@ -3001,7 +3057,7 @@ void __gb_step_cpu(struct gb_s *gb) break; case 0xDC: /* CALL C, imm */ - if(gb->cpu_reg.f_bits.c) + if(gb->cpu_reg.f.f_bits.c) { uint8_t p, c; c = __gb_read(gb, gb->cpu_reg.pc.reg++); @@ -3020,7 +3076,7 @@ void __gb_step_cpu(struct gb_s *gb) case 0xDE: /* SBC A, imm */ { uint8_t val = __gb_read(gb, gb->cpu_reg.pc.reg++); - PGB_INSTR_SBC_R8(val, gb->cpu_reg.f_bits.c); + PGB_INSTR_SBC_R8(val, gb->cpu_reg.f.f_bits.c); break; } @@ -3050,13 +3106,11 @@ void __gb_step_cpu(struct gb_s *gb) break; case 0xE6: /* AND imm */ - /* TODO: Optimisation? */ - gb->cpu_reg.a = gb->cpu_reg.a & __gb_read(gb, gb->cpu_reg.pc.reg++); - gb->cpu_reg.f_bits.z = (gb->cpu_reg.a == 0x00); - gb->cpu_reg.f_bits.n = 0; - gb->cpu_reg.f_bits.h = 1; - gb->cpu_reg.f_bits.c = 0; + { + uint8_t temp = __gb_read(gb, gb->cpu_reg.pc.reg++); + PGB_INSTR_AND_R8(temp); break; + } case 0xE7: /* RST 0x0020 */ __gb_write(gb, --gb->cpu_reg.sp.reg, gb->cpu_reg.pc.bytes.p); @@ -3067,10 +3121,9 @@ void __gb_step_cpu(struct gb_s *gb) case 0xE8: /* ADD SP, imm */ { int8_t offset = (int8_t) __gb_read(gb, gb->cpu_reg.pc.reg++); - gb->cpu_reg.f_bits.z = 0; - gb->cpu_reg.f_bits.n = 0; - gb->cpu_reg.f_bits.h = ((gb->cpu_reg.sp.reg & 0xF) + (offset & 0xF) > 0xF) ? 1 : 0; - gb->cpu_reg.f_bits.c = ((gb->cpu_reg.sp.reg & 0xFF) + (offset & 0xFF) > 0xFF); + gb->cpu_reg.f.reg = 0; + gb->cpu_reg.f.f_bits.h = ((gb->cpu_reg.sp.reg & 0xF) + (offset & 0xF) > 0xF) ? 1 : 0; + gb->cpu_reg.f.f_bits.c = ((gb->cpu_reg.sp.reg & 0xFF) + (offset & 0xFF) > 0xFF); gb->cpu_reg.sp.reg += offset; break; } @@ -3108,10 +3161,10 @@ void __gb_step_cpu(struct gb_s *gb) case 0xF1: /* POP AF */ { uint8_t temp_8 = __gb_read(gb, gb->cpu_reg.sp.reg++); - gb->cpu_reg.f_bits.z = (temp_8 >> 7) & 1; - gb->cpu_reg.f_bits.n = (temp_8 >> 6) & 1; - gb->cpu_reg.f_bits.h = (temp_8 >> 5) & 1; - gb->cpu_reg.f_bits.c = (temp_8 >> 4) & 1; + gb->cpu_reg.f.f_bits.z = (temp_8 >> 7) & 1; + gb->cpu_reg.f.f_bits.n = (temp_8 >> 6) & 1; + gb->cpu_reg.f.f_bits.h = (temp_8 >> 5) & 1; + gb->cpu_reg.f.f_bits.c = (temp_8 >> 4) & 1; gb->cpu_reg.a = __gb_read(gb, gb->cpu_reg.sp.reg++); break; } @@ -3121,14 +3174,14 @@ void __gb_step_cpu(struct gb_s *gb) break; case 0xF3: /* DI */ - gb->gb_ime = 0; + gb->gb_ime = false; break; case 0xF5: /* PUSH AF */ __gb_write(gb, --gb->cpu_reg.sp.reg, gb->cpu_reg.a); __gb_write(gb, --gb->cpu_reg.sp.reg, - gb->cpu_reg.f_bits.z << 7 | gb->cpu_reg.f_bits.n << 6 | - gb->cpu_reg.f_bits.h << 5 | gb->cpu_reg.f_bits.c << 4); + gb->cpu_reg.f.f_bits.z << 7 | gb->cpu_reg.f.f_bits.n << 6 | + gb->cpu_reg.f.f_bits.h << 5 | gb->cpu_reg.f.f_bits.c << 4); break; case 0xF6: /* OR imm */ @@ -3146,11 +3199,9 @@ void __gb_step_cpu(struct gb_s *gb) /* Taken from SameBoy, which is released under MIT Licence. */ int8_t offset = (int8_t) __gb_read(gb, gb->cpu_reg.pc.reg++); gb->cpu_reg.hl.reg = gb->cpu_reg.sp.reg + offset; - gb->cpu_reg.f_bits.z = 0; - gb->cpu_reg.f_bits.n = 0; - gb->cpu_reg.f_bits.h = ((gb->cpu_reg.sp.reg & 0xF) + (offset & 0xF) > 0xF) ? 1 : 0; - gb->cpu_reg.f_bits.c = ((gb->cpu_reg.sp.reg & 0xFF) + (offset & 0xFF) > 0xFF) ? 1 : - 0; + gb->cpu_reg.f.reg = 0; + gb->cpu_reg.f.f_bits.h = ((gb->cpu_reg.sp.reg & 0xF) + (offset & 0xF) > 0xF) ? 1 : 0; + gb->cpu_reg.f.f_bits.c = ((gb->cpu_reg.sp.reg & 0xFF) + (offset & 0xFF) > 0xFF) ? 1 : 0; break; } @@ -3170,7 +3221,7 @@ void __gb_step_cpu(struct gb_s *gb) } case 0xFB: /* EI */ - gb->gb_ime = 1; + gb->gb_ime = true; break; case 0xFE: /* CP imm */ @@ -3187,7 +3238,7 @@ void __gb_step_cpu(struct gb_s *gb) break; default: - /* Return address where invlid opcode that was read. */ + /* Return address where invalid opcode that was read. */ (gb->gb_error)(gb, GB_INVALID_OPCODE, gb->cpu_reg.pc.reg - 1); PGB_UNREACHABLE(); } @@ -3202,6 +3253,53 @@ void __gb_step_cpu(struct gb_s *gb) gb->counter.div_count -= DIV_CYCLES; } + /* Check for RTC tick. */ + if(gb->mbc == 3 && (gb->rtc_real.reg.high & 0x40) == 0) + { + gb->counter.rtc_count += inst_cycles; + while(PGB_UNLIKELY(gb->counter.rtc_count >= RTC_CYCLES)) + { + gb->counter.rtc_count -= RTC_CYCLES; + + /* Detect invalid rollover. */ + if(PGB_UNLIKELY(gb->rtc_real.reg.sec == 63)) + { + gb->rtc_real.reg.sec = 0; + continue; + } + + if(++gb->rtc_real.reg.sec != 60) + continue; + + gb->rtc_real.reg.sec = 0; + if(gb->rtc_real.reg.min == 63) + { + gb->rtc_real.reg.min = 0; + continue; + } + if(++gb->rtc_real.reg.min != 60) + continue; + + gb->rtc_real.reg.min = 0; + if(gb->rtc_real.reg.hour == 31) + { + gb->rtc_real.reg.hour = 0; + continue; + } + if(++gb->rtc_real.reg.hour != 24) + continue; + + gb->rtc_real.reg.hour = 0; + if(++gb->rtc_real.reg.yday != 0) + continue; + + if(gb->rtc_real.reg.high & 1) /* Bit 8 of days*/ + gb->rtc_real.reg.high |= 0x80; /* Overflow bit */ + + gb->rtc_real.reg.high ^= 1; + } + } + /* Check serial transmission. */ if(gb->hram_io[IO_SC] & SERIAL_SC_TX_START) { @@ -3281,7 +3379,7 @@ void __gb_step_cpu(struct gb_s *gb) /* LCD Timing */ gb->counter.lcd_count += inst_cycles; - /* New Scanline */ + /* New Scanline. HBlank -> VBlank or OAM Scan */ if(gb->counter.lcd_count >= LCD_LINE_CYCLES) { gb->counter.lcd_count -= LCD_LINE_CYCLES; @@ -3300,14 +3398,14 @@ void __gb_step_cpu(struct gb_s *gb) else gb->hram_io[IO_STAT] &= 0xFB; - /* VBLANK Start */ + /* Check if LCD should be in Mode 1 (VBLANK) state */ if(gb->hram_io[IO_LY] == LCD_HEIGHT) { gb->hram_io[IO_STAT] = (gb->hram_io[IO_STAT] & ~STAT_MODE) | IO_STAT_MODE_VBLANK; - gb->gb_frame = 1; + gb->gb_frame = true; gb->hram_io[IO_IF] |= VBLANK_INTR; - gb->lcd_blank = 0; + gb->lcd_blank = false; if(gb->hram_io[IO_STAT] & STAT_MODE_1_INTR) gb->hram_io[IO_IF] |= LCDC_INTR; @@ -3332,8 +3430,11 @@ void __gb_step_cpu(struct gb_s *gb) !gb->display.interlace_count; } #endif + /* If halted forever, then return on VBLANK. */ + if(gb->gb_halt && !gb->hram_io[IO_IE]) + break; } - /* Normal Line */ + /* Start of normal Line (not in VBLANK) */ else if(gb->hram_io[IO_LY] < LCD_HEIGHT) { if(gb->hram_io[IO_LY] == 0) @@ -3343,44 +3444,45 @@ void __gb_step_cpu(struct gb_s *gb) gb->display.window_clear = 0; } - gb->hram_io[IO_STAT] = - (gb->hram_io[IO_STAT] & ~STAT_MODE) | IO_STAT_MODE_HBLANK; + /* OAM Search occurs at the start of the line. */ + gb->hram_io[IO_STAT] = (gb->hram_io[IO_STAT] & ~STAT_MODE) | IO_STAT_MODE_OAM_SCAN; + gb->counter.lcd_count = 0; - if(gb->hram_io[IO_STAT] & STAT_MODE_0_INTR) + if(gb->hram_io[IO_STAT] & STAT_MODE_2_INTR) gb->hram_io[IO_IF] |= LCDC_INTR; - /* If halted immediately jump to next LCD mode. */ - if(gb->counter.lcd_count < LCD_MODE_2_CYCLES) - inst_cycles = LCD_MODE_2_CYCLES - gb->counter.lcd_count; + /* If halted immediately jump to next LCD mode. + * From OAM Search to LCD Draw. */ + //if(gb->counter.lcd_count < LCD_MODE2_OAM_SCAN_END) + // inst_cycles = LCD_MODE2_OAM_SCAN_END - gb->counter.lcd_count; + inst_cycles = LCD_MODE2_OAM_SCAN_DURATION; } } - /* OAM access */ - else if((gb->hram_io[IO_STAT] & STAT_MODE) == IO_STAT_MODE_HBLANK && - gb->counter.lcd_count >= LCD_MODE_2_CYCLES) + /* Go from Mode 3 (LCD Draw) to Mode 0 (HBLANK). */ + else if((gb->hram_io[IO_STAT] & STAT_MODE) == IO_STAT_MODE_LCD_DRAW && + gb->counter.lcd_count >= LCD_MODE3_LCD_DRAW_END) { - gb->hram_io[IO_STAT] = - (gb->hram_io[IO_STAT] & ~STAT_MODE) | IO_STAT_MODE_SEARCH_OAM; + gb->hram_io[IO_STAT] = (gb->hram_io[IO_STAT] & ~STAT_MODE) | IO_STAT_MODE_HBLANK; - if(gb->hram_io[IO_STAT] & STAT_MODE_2_INTR) + if(gb->hram_io[IO_STAT] & STAT_MODE_0_INTR) gb->hram_io[IO_IF] |= LCDC_INTR; - /* If halted immediately jump to next LCD mode. */ - if (gb->counter.lcd_count < LCD_MODE_3_CYCLES) - inst_cycles = LCD_MODE_3_CYCLES - gb->counter.lcd_count; + /* If halted immediately, jump from OAM Scan to LCD Draw. */ + if (gb->counter.lcd_count < LCD_MODE0_HBLANK_MAX_DRUATION) + inst_cycles = LCD_MODE0_HBLANK_MAX_DRUATION - gb->counter.lcd_count; } - /* Update LCD */ - else if((gb->hram_io[IO_STAT] & STAT_MODE) == IO_STAT_MODE_SEARCH_OAM && - gb->counter.lcd_count >= LCD_MODE_3_CYCLES) + /* Go from Mode 2 (OAM Scan) to Mode 3 (LCD Draw). */ + else if((gb->hram_io[IO_STAT] & STAT_MODE) == IO_STAT_MODE_OAM_SCAN && + gb->counter.lcd_count >= LCD_MODE2_OAM_SCAN_END) { - gb->hram_io[IO_STAT] = - (gb->hram_io[IO_STAT] & ~STAT_MODE) | IO_STAT_MODE_SEARCH_TRANSFER; + gb->hram_io[IO_STAT] = (gb->hram_io[IO_STAT] & ~STAT_MODE) | IO_STAT_MODE_LCD_DRAW; #if ENABLE_LCD if(!gb->lcd_blank) __gb_draw_line(gb); #endif /* If halted immediately jump to next LCD mode. */ - if (gb->counter.lcd_count < LCD_MODE_0_CYCLES) - inst_cycles = LCD_MODE_0_CYCLES - gb->counter.lcd_count; + if (gb->counter.lcd_count < LCD_MODE3_LCD_DRAW_MIN_DURATION) + inst_cycles = LCD_MODE3_LCD_DRAW_MIN_DURATION - gb->counter.lcd_count; } } while(gb->gb_halt && (gb->hram_io[IO_IF] & gb->hram_io[IO_IE]) == 0); /* If halted, loop until an interrupt occurs. */ @@ -3388,7 +3490,7 @@ void __gb_step_cpu(struct gb_s *gb) void gb_run_frame(struct gb_s *gb) { - gb->gb_frame = 0; + gb->gb_frame = false; while(!gb->gb_frame) __gb_step_cpu(gb); @@ -3428,8 +3530,9 @@ uint8_t gb_colour_hash(struct gb_s *gb) #define ROM_TITLE_END_ADDR 0x0143 uint8_t x = 0; + uint16_t i; - for(uint16_t i = ROM_TITLE_START_ADDR; i <= ROM_TITLE_END_ADDR; i++) + for(i = ROM_TITLE_START_ADDR; i <= ROM_TITLE_END_ADDR; i++) x += gb->gb_rom_read(gb, i); return x; @@ -3440,8 +3543,8 @@ uint8_t gb_colour_hash(struct gb_s *gb) */ void gb_reset(struct gb_s *gb) { - gb->gb_halt = 0; - gb->gb_ime = 1; + gb->gb_halt = false; + gb->gb_ime = true; /* Initialise MBC values. */ gb->selected_rom_bank = 1; @@ -3456,10 +3559,10 @@ void gb_reset(struct gb_s *gb) hdr_chk = gb->gb_rom_read(gb, ROM_HEADER_CHECKSUM_LOC) != 0; gb->cpu_reg.a = 0x01; - gb->cpu_reg.f_bits.z = 1; - gb->cpu_reg.f_bits.n = 0; - gb->cpu_reg.f_bits.h = hdr_chk; - gb->cpu_reg.f_bits.c = hdr_chk; + gb->cpu_reg.f.f_bits.z = 1; + gb->cpu_reg.f.f_bits.n = 0; + gb->cpu_reg.f.f_bits.h = hdr_chk; + gb->cpu_reg.f.f_bits.c = hdr_chk; gb->cpu_reg.bc.reg = 0x0013; gb->cpu_reg.de.reg = 0x00D8; gb->cpu_reg.hl.reg = 0x014D; @@ -3469,7 +3572,9 @@ void gb_reset(struct gb_s *gb) gb->hram_io[IO_DIV ] = 0xAB; gb->hram_io[IO_LCDC] = 0x91; gb->hram_io[IO_STAT] = 0x85; - gb->hram_io[IO_BANK] = 0x01; + gb->hram_io[IO_BOOT] = 0x01; + + __gb_write(gb, 0xFF26, 0xF1); memset(gb->vram, 0x00, VRAM_SIZE); } @@ -3481,13 +3586,14 @@ void gb_reset(struct gb_s *gb) gb->hram_io[IO_DIV ] = 0x00; gb->hram_io[IO_LCDC] = 0x00; gb->hram_io[IO_STAT] = 0x84; - gb->hram_io[IO_BANK] = 0x00; + gb->hram_io[IO_BOOT] = 0x00; } gb->counter.lcd_count = 0; gb->counter.div_count = 0; gb->counter.tima_count = 0; gb->counter.serial_count = 0; + gb->counter.rtc_count = 0; gb->direct.joypad = 0xFF; gb->hram_io[IO_JOYP] = 0xCF; @@ -3539,15 +3645,19 @@ enum gb_init_error_e gb_init(struct gb_s *gb, 0, 1, 1, 1, -1, 2, 2, -1, 0, 0, -1, 0, 0, 0, -1, 3, 3, 3, 3, 3, -1, -1, -1, -1, -1, 5, 5, 5, 5, 5, 5, -1 }; + /* Whether cart has RAM. */ const uint8_t cart_ram[] = { 0, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0 }; + /* How large the ROM is in banks of 16 KiB. */ const uint16_t num_rom_banks_mask[] = { 2, 4, 8, 16, 32, 64, 128, 256, 512 }; + /* How large the cart RAM is in banks of 8 KiB. Code $01 is unused, but + * some early homebrew ROMs supposedly may use this value. */ const uint8_t num_ram_banks[] = { 0, 1, 1, 4, 16, 8 }; gb->gb_rom_read = gb_rom_read; @@ -3567,8 +3677,9 @@ enum gb_init_error_e gb_init(struct gb_s *gb, /* Check valid ROM using checksum value. */ { uint8_t x = 0; + uint16_t i; - for(uint16_t i = 0x0134; i <= 0x014C; i++) + for(i = 0x0134; i <= 0x014C; i++) x = x - gb->gb_rom_read(gb, i) - 1; if(x != gb->gb_rom_read(gb, ROM_HEADER_CHECKSUM_LOC)) @@ -3592,7 +3703,7 @@ enum gb_init_error_e gb_init(struct gb_s *gb, * always has 512 half-bytes of RAM. Hence, gb->num_ram_banks must be * ignored for MBC2. */ - gb->lcd_blank = 0; + gb->lcd_blank = false; gb->display.lcd_draw_line = NULL; gb_reset(gb); @@ -3632,10 +3743,10 @@ void gb_init_lcd(struct gb_s *gb, { gb->display.lcd_draw_line = lcd_draw_line; - gb->direct.interlace = 0; - gb->display.interlace_count = 0; - gb->direct.frame_skip = 0; - gb->display.frame_skip_count = 0; + gb->direct.interlace = false; + gb->display.interlace_count = false; + gb->direct.frame_skip = false; + gb->display.frame_skip_count = false; gb->display.window_clear = 0; gb->display.WY = 0; @@ -3651,47 +3762,22 @@ void gb_set_bootrom(struct gb_s *gb, } /** - * This was taken from SameBoy, which is released under MIT Licence. + * Deprecated. Will be removed in the next major version. */ +PGB_DEPRECATED("RTC is now ticked internally; this function has no effect") void gb_tick_rtc(struct gb_s *gb) { - /* is timer running? */ - if((gb->cart_rtc[4] & 0x40) == 0) - { - if(++gb->rtc_bits.sec == 60) - { - gb->rtc_bits.sec = 0; - - if(++gb->rtc_bits.min == 60) - { - gb->rtc_bits.min = 0; - - if(++gb->rtc_bits.hour == 24) - { - gb->rtc_bits.hour = 0; - - if(++gb->rtc_bits.yday == 0) - { - if(gb->rtc_bits.high & 1) /* Bit 8 of days*/ - { - gb->rtc_bits.high |= 0x80; /* Overflow bit */ - } - - gb->rtc_bits.high ^= 1; - } - } - } - } - } + (void) gb; + return; } void gb_set_rtc(struct gb_s *gb, const struct tm * const time) { - gb->cart_rtc[0] = time->tm_sec; - gb->cart_rtc[1] = time->tm_min; - gb->cart_rtc[2] = time->tm_hour; - gb->cart_rtc[3] = time->tm_yday & 0xFF; /* Low 8 bits of day counter. */ - gb->cart_rtc[4] = time->tm_yday >> 8; /* High 1 bit of day counter. */ + gb->rtc_real.bytes[0] = time->tm_sec; + gb->rtc_real.bytes[1] = time->tm_min; + gb->rtc_real.bytes[2] = time->tm_hour; + gb->rtc_real.bytes[3] = time->tm_yday & 0xFF; /* Low 8 bits of day counter. */ + gb->rtc_real.bytes[4] = time->tm_yday >> 8; /* High 1 bit of day counter. */ } #endif // PEANUT_GB_HEADER_ONLY @@ -3814,10 +3900,8 @@ uint8_t gb_colour_hash(struct gb_s *gb); const char* gb_get_rom_name(struct gb_s* gb, char *title_str); /** - * Tick the internal RTC by one second. This does not affect games with no RTC - * support. - * - * \param gb An initialised emulator context. Must not be NULL. + * Deprecated. Will be removed in the next major version. + * RTC is ticked internally and this function has no effect. */ void gb_tick_rtc(struct gb_s *gb);