Initial code to support SGB, command “parsing”, replacement SGB boot ROM
This commit is contained in:
parent
a47e3cc62c
commit
44891d5c4a
209
BootROMs/sgb_boot.asm
Normal file
209
BootROMs/sgb_boot.asm
Normal file
@ -0,0 +1,209 @@
|
|||||||
|
; Sameboy CGB bootstrap ROM
|
||||||
|
; Todo: use friendly names for HW registers instead of magic numbers
|
||||||
|
SECTION "BootCode", ROM0[$0]
|
||||||
|
Start:
|
||||||
|
; Init stack pointer
|
||||||
|
ld sp, $fffe
|
||||||
|
|
||||||
|
; Clear memory VRAM
|
||||||
|
ld hl, $8000
|
||||||
|
|
||||||
|
.clearVRAMLoop
|
||||||
|
ldi [hl], a
|
||||||
|
bit 5, h
|
||||||
|
jr z, .clearVRAMLoop
|
||||||
|
|
||||||
|
; Init Audio
|
||||||
|
ld a, $80
|
||||||
|
ldh [$26], a
|
||||||
|
ldh [$11], a
|
||||||
|
ld a, $f3
|
||||||
|
ldh [$12], a
|
||||||
|
ldh [$25], a
|
||||||
|
ld a, $77
|
||||||
|
ldh [$24], a
|
||||||
|
|
||||||
|
; Init BG palette to white
|
||||||
|
ld a, $0
|
||||||
|
ldh [$47], a
|
||||||
|
|
||||||
|
; Load logo from ROM.
|
||||||
|
; A nibble represents a 4-pixels line, 2 bytes represent a 4x4 tile, scaled to 8x8.
|
||||||
|
; Tiles are ordered left to right, top to bottom.
|
||||||
|
ld de, $104 ; Logo start
|
||||||
|
ld hl, $8010 ; This is where we load the tiles in VRAM
|
||||||
|
|
||||||
|
.loadLogoLoop
|
||||||
|
ld a, [de] ; Read 2 rows
|
||||||
|
ld b, a
|
||||||
|
call DoubleBitsAndWriteRow
|
||||||
|
call DoubleBitsAndWriteRow
|
||||||
|
inc de
|
||||||
|
ld a, e
|
||||||
|
xor $34 ; End of logo
|
||||||
|
jr nz, .loadLogoLoop
|
||||||
|
|
||||||
|
; Load trademark symbol
|
||||||
|
ld de, TrademarkSymbol
|
||||||
|
ld c,$08
|
||||||
|
.loadTrademarkSymbolLoop:
|
||||||
|
ld a,[de]
|
||||||
|
inc de
|
||||||
|
ldi [hl],a
|
||||||
|
inc hl
|
||||||
|
dec c
|
||||||
|
jr nz, .loadTrademarkSymbolLoop
|
||||||
|
|
||||||
|
; Set up tilemap
|
||||||
|
ld a,$19 ; Trademark symbol
|
||||||
|
ld [$9910], a ; ... put in the superscript position
|
||||||
|
ld hl,$992f ; Bottom right corner of the logo
|
||||||
|
ld c,$c ; Tiles in a logo row
|
||||||
|
.tilemapLoop
|
||||||
|
dec a
|
||||||
|
jr z, .tilemapDone
|
||||||
|
ldd [hl], a
|
||||||
|
dec c
|
||||||
|
jr nz, .tilemapLoop
|
||||||
|
ld l,$0f ; Jump to top row
|
||||||
|
jr .tilemapLoop
|
||||||
|
.tilemapDone
|
||||||
|
|
||||||
|
; Turn on LCD
|
||||||
|
ld a, $91
|
||||||
|
ldh [$40], a
|
||||||
|
|
||||||
|
ld a, $f1 ; Packet magic, increases by 2 for every packet
|
||||||
|
ldh [$80], a
|
||||||
|
ld hl, $104 ; Header start
|
||||||
|
|
||||||
|
xor a
|
||||||
|
ld c, a ; JOYP
|
||||||
|
|
||||||
|
.sendCommand
|
||||||
|
xor a
|
||||||
|
ldh [c], a
|
||||||
|
ld a, $30
|
||||||
|
ldh [c], a
|
||||||
|
|
||||||
|
ldh a, [$80]
|
||||||
|
call SendByte
|
||||||
|
push hl
|
||||||
|
ld b, $e
|
||||||
|
ld d, 0
|
||||||
|
|
||||||
|
.checksumLoop
|
||||||
|
call ReadHeaderByte
|
||||||
|
add d
|
||||||
|
ld d, a
|
||||||
|
dec b
|
||||||
|
jr nz, .checksumLoop
|
||||||
|
|
||||||
|
; Send checksum
|
||||||
|
call SendByte
|
||||||
|
pop hl
|
||||||
|
|
||||||
|
ld b, $e
|
||||||
|
.sendLoop
|
||||||
|
call ReadHeaderByte
|
||||||
|
call SendByte
|
||||||
|
dec b
|
||||||
|
jr nz, .sendLoop
|
||||||
|
|
||||||
|
; Done bit
|
||||||
|
ld a, $20
|
||||||
|
ldh [c], a
|
||||||
|
ld a, $30
|
||||||
|
ldh [c], a
|
||||||
|
|
||||||
|
; Update command
|
||||||
|
ldh a, [$80]
|
||||||
|
add 2
|
||||||
|
ldh [$80], a
|
||||||
|
|
||||||
|
ld a, $58
|
||||||
|
cp l
|
||||||
|
jr nz, .sendCommand
|
||||||
|
|
||||||
|
; Write to sound registers for DMG compatibility
|
||||||
|
ld c, $13
|
||||||
|
ld a, $c1
|
||||||
|
ldh [c], a
|
||||||
|
inc c
|
||||||
|
ld a, 7
|
||||||
|
ldh [c], a
|
||||||
|
|
||||||
|
; Init BG palette
|
||||||
|
ld a, $fc
|
||||||
|
ldh [$47], a
|
||||||
|
|
||||||
|
; Set registers to match the original SGB boot
|
||||||
|
ld a, 1
|
||||||
|
ld hl, $c060
|
||||||
|
|
||||||
|
; Boot the game
|
||||||
|
jp BootGame
|
||||||
|
|
||||||
|
ReadHeaderByte:
|
||||||
|
ld a, $4F
|
||||||
|
cp l
|
||||||
|
jr c, .zero
|
||||||
|
ld a, [hli]
|
||||||
|
ret
|
||||||
|
.zero:
|
||||||
|
inc hl
|
||||||
|
xor a
|
||||||
|
ret
|
||||||
|
|
||||||
|
SendByte:
|
||||||
|
ld e, a
|
||||||
|
ld d, 8
|
||||||
|
.loop
|
||||||
|
ld a, $10
|
||||||
|
rr e
|
||||||
|
jr c, .zeroBit
|
||||||
|
add a ; 10 -> 20
|
||||||
|
.zeroBit
|
||||||
|
ldh [c], a
|
||||||
|
ld a, $30
|
||||||
|
ldh [c], a
|
||||||
|
dec d
|
||||||
|
ret z
|
||||||
|
jr .loop
|
||||||
|
|
||||||
|
DoubleBitsAndWriteRow:
|
||||||
|
; Double the most significant 4 bits, b is shifted by 4
|
||||||
|
ld a, 4
|
||||||
|
ld c, 0
|
||||||
|
.doubleCurrentBit
|
||||||
|
sla b
|
||||||
|
push af
|
||||||
|
rl c
|
||||||
|
pop af
|
||||||
|
rl c
|
||||||
|
dec a
|
||||||
|
jr nz, .doubleCurrentBit
|
||||||
|
ld a, c
|
||||||
|
; Write as two rows
|
||||||
|
ldi [hl], a
|
||||||
|
inc hl
|
||||||
|
ldi [hl], a
|
||||||
|
inc hl
|
||||||
|
ret
|
||||||
|
|
||||||
|
WaitFrame:
|
||||||
|
push hl
|
||||||
|
ld hl, $FF0F
|
||||||
|
res 0, [hl]
|
||||||
|
.wait
|
||||||
|
bit 0, [hl]
|
||||||
|
jr z, .wait
|
||||||
|
pop hl
|
||||||
|
ret
|
||||||
|
|
||||||
|
TrademarkSymbol:
|
||||||
|
db $3c,$42,$b9,$a5,$b9,$a5,$42,$3c
|
||||||
|
|
||||||
|
SECTION "BootGame", ROM0[$fe]
|
||||||
|
BootGame:
|
||||||
|
ldh [$50], a
|
@ -16,13 +16,15 @@ enum model {
|
|||||||
MODEL_DMG,
|
MODEL_DMG,
|
||||||
MODEL_CGB,
|
MODEL_CGB,
|
||||||
MODEL_AGB,
|
MODEL_AGB,
|
||||||
|
MODEL_SGB,
|
||||||
};
|
};
|
||||||
|
|
||||||
static const GB_model_t cocoa_to_internal_model[] =
|
static const GB_model_t cocoa_to_internal_model[] =
|
||||||
{
|
{
|
||||||
[MODEL_DMG] = GB_MODEL_DMG_B,
|
[MODEL_DMG] = GB_MODEL_DMG_B,
|
||||||
[MODEL_CGB] = GB_MODEL_CGB_E,
|
[MODEL_CGB] = GB_MODEL_CGB_E,
|
||||||
[MODEL_AGB] = GB_MODEL_AGB
|
[MODEL_AGB] = GB_MODEL_AGB,
|
||||||
|
[MODEL_SGB] = GB_MODEL_SGB,
|
||||||
};
|
};
|
||||||
|
|
||||||
@interface Document ()
|
@interface Document ()
|
||||||
@ -157,7 +159,7 @@ static void printImage(GB_gameboy_t *gb, uint32_t *image, uint8_t height,
|
|||||||
return [[NSBundle mainBundle] pathForResource:name ofType:@"bin"];
|
return [[NSBundle mainBundle] pathForResource:name ofType:@"bin"];
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Todo: Unify the 3 init functions */
|
/* Todo: Unify the 4 init functions */
|
||||||
- (void) initDMG
|
- (void) initDMG
|
||||||
{
|
{
|
||||||
current_model = MODEL_DMG;
|
current_model = MODEL_DMG;
|
||||||
@ -166,6 +168,14 @@ static void printImage(GB_gameboy_t *gb, uint32_t *image, uint8_t height,
|
|||||||
[self initCommon];
|
[self initCommon];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (void) initSGB
|
||||||
|
{
|
||||||
|
current_model = MODEL_SGB;
|
||||||
|
GB_init(&gb, cocoa_to_internal_model[current_model]);
|
||||||
|
GB_load_boot_rom(&gb, [[self bootROMPathForName:@"sgb_boot"] UTF8String]);
|
||||||
|
[self initCommon];
|
||||||
|
}
|
||||||
|
|
||||||
- (void) initCGB
|
- (void) initCGB
|
||||||
{
|
{
|
||||||
if ([[NSUserDefaults standardUserDefaults] boolForKey:@"EmulateAGB"]) {
|
if ([[NSUserDefaults standardUserDefaults] boolForKey:@"EmulateAGB"]) {
|
||||||
@ -274,7 +284,7 @@ static void printImage(GB_gameboy_t *gb, uint32_t *image, uint8_t height,
|
|||||||
current_model = (enum model)[sender tag];
|
current_model = (enum model)[sender tag];
|
||||||
}
|
}
|
||||||
|
|
||||||
static NSString * const boot_names[] = {@"dmg_boot", @"cgb_boot", @"agb_boot"};
|
static NSString * const boot_names[] = {@"dmg_boot", @"cgb_boot", @"agb_boot", @"sgb_boot"};
|
||||||
GB_load_boot_rom(&gb, [[self bootROMPathForName:boot_names[current_model - 1]] UTF8String]);
|
GB_load_boot_rom(&gb, [[self bootROMPathForName:boot_names[current_model - 1]] UTF8String]);
|
||||||
|
|
||||||
if ([sender tag] == MODEL_NONE) {
|
if ([sender tag] == MODEL_NONE) {
|
||||||
@ -287,7 +297,8 @@ static void printImage(GB_gameboy_t *gb, uint32_t *image, uint8_t height,
|
|||||||
if ([sender tag] != 0) {
|
if ([sender tag] != 0) {
|
||||||
/* User explictly selected a model, save the preference */
|
/* User explictly selected a model, save the preference */
|
||||||
[[NSUserDefaults standardUserDefaults] setBool:current_model == MODEL_DMG forKey:@"EmulateDMG"];
|
[[NSUserDefaults standardUserDefaults] setBool:current_model == MODEL_DMG forKey:@"EmulateDMG"];
|
||||||
[[NSUserDefaults standardUserDefaults] setBool:current_model== MODEL_AGB forKey:@"EmulateAGB"];
|
[[NSUserDefaults standardUserDefaults] setBool:current_model == MODEL_SGB forKey:@"EmulateSGB"];
|
||||||
|
[[NSUserDefaults standardUserDefaults] setBool:current_model == MODEL_AGB forKey:@"EmulateAGB"];
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Reload the ROM, SAV and SYM files */
|
/* Reload the ROM, SAV and SYM files */
|
||||||
@ -382,6 +393,9 @@ static void printImage(GB_gameboy_t *gb, uint32_t *image, uint8_t height,
|
|||||||
if ([[NSUserDefaults standardUserDefaults] boolForKey:@"EmulateDMG"]) {
|
if ([[NSUserDefaults standardUserDefaults] boolForKey:@"EmulateDMG"]) {
|
||||||
[self initDMG];
|
[self initDMG];
|
||||||
}
|
}
|
||||||
|
else if ([[NSUserDefaults standardUserDefaults] boolForKey:@"EmulateSGB"]) {
|
||||||
|
[self initSGB];
|
||||||
|
}
|
||||||
else {
|
else {
|
||||||
[self initCGB];
|
[self initCGB];
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,8 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="9531" systemVersion="14F1713" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" customObjectInstantitationMethod="direct">
|
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="13771" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" customObjectInstantitationMethod="direct">
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="9531"/>
|
<deployment identifier="macosx"/>
|
||||||
|
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="13771"/>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
<objects>
|
<objects>
|
||||||
<customObject id="-2" userLabel="File's Owner" customClass="NSApplication">
|
<customObject id="-2" userLabel="File's Owner" customClass="NSApplication">
|
||||||
@ -311,7 +312,13 @@
|
|||||||
</menu>
|
</menu>
|
||||||
</menuItem>
|
</menuItem>
|
||||||
<menuItem isSeparatorItem="YES" id="5GS-tt-E0a"/>
|
<menuItem isSeparatorItem="YES" id="5GS-tt-E0a"/>
|
||||||
<menuItem title="Game Boy" tag="1" id="vc7-yy-ARW">
|
<menuItem title="Game Boy" tag="1" id="g7C-LA-VAr">
|
||||||
|
<modifierMask key="keyEquivalentModifierMask"/>
|
||||||
|
<connections>
|
||||||
|
<action selector="reset:" target="-1" id="rxG-cz-s1S"/>
|
||||||
|
</connections>
|
||||||
|
</menuItem>
|
||||||
|
<menuItem title="Super Game Boy" tag="4" id="vc7-yy-ARW">
|
||||||
<modifierMask key="keyEquivalentModifierMask"/>
|
<modifierMask key="keyEquivalentModifierMask"/>
|
||||||
<connections>
|
<connections>
|
||||||
<action selector="reset:" target="-1" id="E4M-QG-ua9"/>
|
<action selector="reset:" target="-1" id="E4M-QG-ua9"/>
|
||||||
|
19
Core/gb.c
19
Core/gb.c
@ -506,7 +506,12 @@ bool GB_is_inited(GB_gameboy_t *gb)
|
|||||||
|
|
||||||
bool GB_is_cgb(GB_gameboy_t *gb)
|
bool GB_is_cgb(GB_gameboy_t *gb)
|
||||||
{
|
{
|
||||||
return ((gb->model) & GB_MODEL_FAMILY_MASK) == GB_MODEL_CGB_FAMILY;
|
return (gb->model & GB_MODEL_FAMILY_MASK) == GB_MODEL_CGB_FAMILY;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool GB_is_sgb(GB_gameboy_t *gb)
|
||||||
|
{
|
||||||
|
return (gb->model & ~GB_MODEL_PAL_BIT) == GB_MODEL_SGB || gb->model == GB_MODEL_SGB2;
|
||||||
}
|
}
|
||||||
|
|
||||||
void GB_set_turbo_mode(GB_gameboy_t *gb, bool on, bool no_frame_skip)
|
void GB_set_turbo_mode(GB_gameboy_t *gb, bool on, bool no_frame_skip)
|
||||||
@ -541,6 +546,8 @@ static void reset_ram(GB_gameboy_t *gb)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case GB_MODEL_DMG_B:
|
case GB_MODEL_DMG_B:
|
||||||
|
case GB_MODEL_SGB_NTSC: /* Unverified*/
|
||||||
|
case GB_MODEL_SGB_PAL: /* Unverified */
|
||||||
for (unsigned i = 0; i < gb->ram_size; i++) {
|
for (unsigned i = 0; i < gb->ram_size; i++) {
|
||||||
gb->ram[i] = (random() & 0xFF);
|
gb->ram[i] = (random() & 0xFF);
|
||||||
if (i & 0x100) {
|
if (i & 0x100) {
|
||||||
@ -551,15 +558,13 @@ static void reset_ram(GB_gameboy_t *gb)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
#if 0
|
|
||||||
/* Not emulated yet, for documentation only */
|
|
||||||
case GB_MODEL_SGB2:
|
case GB_MODEL_SGB2:
|
||||||
for (unsigned i = 0; i < gb->ram_size; i++) {
|
for (unsigned i = 0; i < gb->ram_size; i++) {
|
||||||
gb->ram[i] = 0x55;
|
gb->ram[i] = 0x55;
|
||||||
gb->ram[i] ^= random() & random() & random();
|
gb->ram[i] ^= random() & random() & random();
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
#endif
|
|
||||||
|
|
||||||
case GB_MODEL_CGB_C:
|
case GB_MODEL_CGB_C:
|
||||||
for (unsigned i = 0; i < gb->ram_size; i++) {
|
for (unsigned i = 0; i < gb->ram_size; i++) {
|
||||||
@ -729,5 +734,11 @@ void GB_set_clock_multiplier(GB_gameboy_t *gb, double multiplier)
|
|||||||
|
|
||||||
uint32_t GB_get_clock_rate(GB_gameboy_t *gb)
|
uint32_t GB_get_clock_rate(GB_gameboy_t *gb)
|
||||||
{
|
{
|
||||||
|
if (gb->model == GB_MODEL_SGB_NTSC) {
|
||||||
|
return SGB_NTSC_FREQUENCY * gb->clock_multiplier;
|
||||||
|
}
|
||||||
|
if (gb->model == GB_MODEL_SGB_PAL) {
|
||||||
|
return SGB_PAL_FREQUENCY * gb->clock_multiplier;
|
||||||
|
}
|
||||||
return CPU_FREQUENCY * gb->clock_multiplier;
|
return CPU_FREQUENCY * gb->clock_multiplier;
|
||||||
}
|
}
|
||||||
|
20
Core/gb.h
20
Core/gb.h
@ -19,6 +19,7 @@
|
|||||||
#include "rewind.h"
|
#include "rewind.h"
|
||||||
#include "z80_cpu.h"
|
#include "z80_cpu.h"
|
||||||
#include "symbol_hash.h"
|
#include "symbol_hash.h"
|
||||||
|
#include "sgb.h"
|
||||||
|
|
||||||
#define GB_STRUCT_VERSION 13
|
#define GB_STRUCT_VERSION 13
|
||||||
|
|
||||||
@ -27,6 +28,7 @@
|
|||||||
#define GB_MODEL_DMG_FAMILY 0x000
|
#define GB_MODEL_DMG_FAMILY 0x000
|
||||||
#define GB_MODEL_MGB_FAMILY 0x100
|
#define GB_MODEL_MGB_FAMILY 0x100
|
||||||
#define GB_MODEL_CGB_FAMILY 0x200
|
#define GB_MODEL_CGB_FAMILY 0x200
|
||||||
|
#define GB_MODEL_PAL_BIT 0x1000
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
|
#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
|
||||||
@ -48,15 +50,18 @@ typedef union {
|
|||||||
uint8_t data[5];
|
uint8_t data[5];
|
||||||
} GB_rtc_time_t;
|
} GB_rtc_time_t;
|
||||||
|
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
|
|
||||||
// GB_MODEL_DMG_0 = 0x000,
|
// GB_MODEL_DMG_0 = 0x000,
|
||||||
// GB_MODEL_DMG_A = 0x001,
|
// GB_MODEL_DMG_A = 0x001,
|
||||||
GB_MODEL_DMG_B = 0x002,
|
GB_MODEL_DMG_B = 0x002,
|
||||||
// GB_MODEL_DMG_C = 0x003,
|
// GB_MODEL_DMG_C = 0x003,
|
||||||
// GB_MODEL_SGB = 0x004,
|
GB_MODEL_SGB = 0x004,
|
||||||
|
GB_MODEL_SGB_NTSC = GB_MODEL_SGB,
|
||||||
|
GB_MODEL_SGB_PAL = 0x1004,
|
||||||
// GB_MODEL_MGB = 0x100,
|
// GB_MODEL_MGB = 0x100,
|
||||||
// GB_MODEL_SGB2 = 0x101,
|
GB_MODEL_SGB2 = 0x101,
|
||||||
// GB_MODEL_CGB_0 = 0x200,
|
// GB_MODEL_CGB_0 = 0x200,
|
||||||
// GB_MODEL_CGB_A = 0x201,
|
// GB_MODEL_CGB_A = 0x201,
|
||||||
// GB_MODEL_CGB_B = 0x202,
|
// GB_MODEL_CGB_B = 0x202,
|
||||||
@ -203,6 +208,8 @@ typedef enum {
|
|||||||
#ifdef GB_INTERNAL
|
#ifdef GB_INTERNAL
|
||||||
#define LCDC_PERIOD 70224
|
#define LCDC_PERIOD 70224
|
||||||
#define CPU_FREQUENCY 0x400000
|
#define CPU_FREQUENCY 0x400000
|
||||||
|
#define SGB_NTSC_FREQUENCY (21477272 / 5)
|
||||||
|
#define SGB_PAL_FREQUENCY (21281370 / 5)
|
||||||
#define DIV_CYCLES (0x100)
|
#define DIV_CYCLES (0x100)
|
||||||
#define INTERNAL_DIV_CYCLES (0x40000)
|
#define INTERNAL_DIV_CYCLES (0x40000)
|
||||||
|
|
||||||
@ -460,6 +467,14 @@ struct GB_gameboy_internal_s {
|
|||||||
bool lyc_interrupt_line;
|
bool lyc_interrupt_line;
|
||||||
);
|
);
|
||||||
|
|
||||||
|
/* Super Game Boy state, only dumped/loaded for relevant models */
|
||||||
|
GB_SECTION(sgb,
|
||||||
|
uint8_t sgb_command[16];
|
||||||
|
uint8_t sgb_command_write_index;
|
||||||
|
bool sgb_ready_for_pulse;
|
||||||
|
bool sgb_ready_for_write;
|
||||||
|
);
|
||||||
|
|
||||||
/* Unsaved data. This includes all pointers, as well as everything that shouldn't be on a save state */
|
/* Unsaved data. This includes all pointers, as well as everything that shouldn't be on a save state */
|
||||||
/* This data is reserved on reset and must come last in the struct */
|
/* This data is reserved on reset and must come last in the struct */
|
||||||
GB_SECTION(unsaved,
|
GB_SECTION(unsaved,
|
||||||
@ -584,6 +599,7 @@ __attribute__((__format__ (__printf__, fmtarg, firstvararg)))
|
|||||||
void GB_init(GB_gameboy_t *gb, GB_model_t model);
|
void GB_init(GB_gameboy_t *gb, GB_model_t model);
|
||||||
bool GB_is_inited(GB_gameboy_t *gb);
|
bool GB_is_inited(GB_gameboy_t *gb);
|
||||||
bool GB_is_cgb(GB_gameboy_t *gb);
|
bool GB_is_cgb(GB_gameboy_t *gb);
|
||||||
|
bool GB_is_sgb(GB_gameboy_t *gb);
|
||||||
GB_model_t GB_get_model(GB_gameboy_t *gb);
|
GB_model_t GB_get_model(GB_gameboy_t *gb);
|
||||||
void GB_free(GB_gameboy_t *gb);
|
void GB_free(GB_gameboy_t *gb);
|
||||||
void GB_reset(GB_gameboy_t *gb);
|
void GB_reset(GB_gameboy_t *gb);
|
||||||
|
@ -47,12 +47,14 @@ void GB_update_joyp(GB_gameboy_t *gb)
|
|||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (previous_state != (gb->io_registers[GB_IO_JOYP] & 0xF)) {
|
if (previous_state != (gb->io_registers[GB_IO_JOYP] & 0xF)) {
|
||||||
/* The joypad interrupt DOES occur on CGB (Tested on CGB-CPU-06), unlike what some documents say. */
|
/* The joypad interrupt DOES occur on CGB (Tested on CGB-CPU-06), unlike what some documents say. */
|
||||||
gb->io_registers[GB_IO_IF] |= 0x10;
|
gb->io_registers[GB_IO_IF] |= 0x10;
|
||||||
gb->stopped = false;
|
gb->stopped = false;
|
||||||
}
|
}
|
||||||
gb->io_registers[GB_IO_JOYP] |= 0xC0; // No SGB support
|
|
||||||
|
gb->io_registers[GB_IO_JOYP] |= 0xC0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void GB_set_key_state(GB_gameboy_t *gb, GB_key_t index, bool pressed)
|
void GB_set_key_state(GB_gameboy_t *gb, GB_key_t index, bool pressed)
|
||||||
|
@ -271,6 +271,9 @@ static uint8_t read_high_memory(GB_gameboy_t *gb, uint16_t addr)
|
|||||||
return gb->extra_oam[addr - 0xfea0];
|
return gb->extra_oam[addr - 0xfea0];
|
||||||
|
|
||||||
case GB_MODEL_DMG_B:
|
case GB_MODEL_DMG_B:
|
||||||
|
case GB_MODEL_SGB_NTSC:
|
||||||
|
case GB_MODEL_SGB_PAL:
|
||||||
|
case GB_MODEL_SGB2:
|
||||||
;
|
;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -575,6 +578,9 @@ static void write_high_memory(GB_gameboy_t *gb, uint16_t addr, uint8_t value)
|
|||||||
gb->extra_oam[addr - 0xfea0] = value;
|
gb->extra_oam[addr - 0xfea0] = value;
|
||||||
break;
|
break;
|
||||||
case GB_MODEL_DMG_B:
|
case GB_MODEL_DMG_B:
|
||||||
|
case GB_MODEL_SGB_NTSC:
|
||||||
|
case GB_MODEL_SGB_PAL:
|
||||||
|
case GB_MODEL_SGB2:
|
||||||
case GB_MODEL_CGB_E:
|
case GB_MODEL_CGB_E:
|
||||||
case GB_MODEL_AGB:
|
case GB_MODEL_AGB:
|
||||||
break;
|
break;
|
||||||
@ -727,6 +733,7 @@ static void write_high_memory(GB_gameboy_t *gb, uint16_t addr, uint8_t value)
|
|||||||
gb->io_registers[GB_IO_JOYP] &= 0x0F;
|
gb->io_registers[GB_IO_JOYP] &= 0x0F;
|
||||||
gb->io_registers[GB_IO_JOYP] |= value & 0xF0;
|
gb->io_registers[GB_IO_JOYP] |= value & 0xF0;
|
||||||
GB_update_joyp(gb);
|
GB_update_joyp(gb);
|
||||||
|
GB_sgb_write(gb, value);
|
||||||
return;
|
return;
|
||||||
|
|
||||||
case GB_IO_BIOS:
|
case GB_IO_BIOS:
|
||||||
|
51
Core/sgb.c
Normal file
51
Core/sgb.c
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
#include "sgb.h"
|
||||||
|
|
||||||
|
void GB_sgb_write(GB_gameboy_t *gb, uint8_t value)
|
||||||
|
{
|
||||||
|
if (!GB_is_sgb(gb)) return;
|
||||||
|
switch ((value >> 4) & 3 ) {
|
||||||
|
case 3:
|
||||||
|
gb->sgb_ready_for_pulse = true;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 2: // Zero
|
||||||
|
if (!gb->sgb_ready_for_pulse || !gb->sgb_ready_for_write) return;
|
||||||
|
if (gb->sgb_command_write_index >= sizeof(gb->sgb_command) * 8) {
|
||||||
|
GB_log(gb, "Got SGB command: ");
|
||||||
|
for (unsigned i = 0; i < 16; i++) {
|
||||||
|
GB_log(gb, "%02x ", gb->sgb_command[i]);
|
||||||
|
}
|
||||||
|
GB_log(gb, "\n");
|
||||||
|
gb->sgb_ready_for_pulse = false;
|
||||||
|
gb->sgb_ready_for_write = false;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
gb->sgb_command_write_index++;
|
||||||
|
gb->sgb_ready_for_pulse = false;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 1: // One
|
||||||
|
if (!gb->sgb_ready_for_pulse || !gb->sgb_ready_for_write) return;
|
||||||
|
if (gb->sgb_command_write_index >= sizeof(gb->sgb_command) * 8) {
|
||||||
|
GB_log(gb, "Corrupt SGB command.\n");
|
||||||
|
gb->sgb_ready_for_pulse = false;
|
||||||
|
gb->sgb_ready_for_write = false;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
gb->sgb_command[gb->sgb_command_write_index / 8] |= 1 << (gb->sgb_command_write_index & 7);
|
||||||
|
gb->sgb_command_write_index++;
|
||||||
|
gb->sgb_ready_for_pulse = false;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0:
|
||||||
|
gb->sgb_ready_for_pulse = false;
|
||||||
|
gb->sgb_ready_for_write = true;
|
||||||
|
gb->sgb_command_write_index = 0;
|
||||||
|
memset(gb->sgb_command, 0, sizeof(gb->sgb_command));
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
9
Core/sgb.h
Normal file
9
Core/sgb.h
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
#ifndef sgb_h
|
||||||
|
#define sgb_h
|
||||||
|
#include "gb.h"
|
||||||
|
|
||||||
|
#ifdef GB_INTERNAL
|
||||||
|
void GB_sgb_write(GB_gameboy_t *gb, uint8_t value);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
9
Makefile
9
Makefile
@ -106,9 +106,9 @@ endif
|
|||||||
|
|
||||||
cocoa: $(BIN)/SameBoy.app
|
cocoa: $(BIN)/SameBoy.app
|
||||||
quicklook: $(BIN)/SameBoy.qlgenerator
|
quicklook: $(BIN)/SameBoy.qlgenerator
|
||||||
sdl: $(SDL_TARGET) $(BIN)/SDL/dmg_boot.bin $(BIN)/SDL/cgb_boot.bin $(BIN)/SDL/agb_boot.bin $(BIN)/SDL/LICENSE $(BIN)/SDL/registers.sym $(BIN)/SDL/background.bmp $(BIN)/SDL/Shaders
|
sdl: $(SDL_TARGET) $(BIN)/SDL/dmg_boot.bin $(BIN)/SDL/cgb_boot.bin $(BIN)/SDL/agb_boot.bin $(BIN)/SDL/sgb_boot.bin $(BIN)/SDL/LICENSE $(BIN)/SDL/registers.sym $(BIN)/SDL/background.bmp $(BIN)/SDL/Shaders
|
||||||
bootroms: $(BIN)/BootROMs/agb_boot.bin $(BIN)/BootROMs/cgb_boot.bin $(BIN)/BootROMs/dmg_boot.bin
|
bootroms: $(BIN)/BootROMs/agb_boot.bin $(BIN)/BootROMs/cgb_boot.bin $(BIN)/BootROMs/dmg_boot.bin $(BIN)/BootROMs/sgb_boot.bin
|
||||||
tester: $(TESTER_TARGET) $(BIN)/tester/dmg_boot.bin $(BIN)/tester/cgb_boot.bin $(BIN)/tester/agb_boot.bin
|
tester: $(TESTER_TARGET) $(BIN)/tester/dmg_boot.bin $(BIN)/tester/cgb_boot.bin $(BIN)/tester/agb_boot.bin $(BIN)/tester/sgb_boot.bin
|
||||||
all: cocoa sdl tester libretro
|
all: cocoa sdl tester libretro
|
||||||
|
|
||||||
# Get a list of our source files and their respective object file targets
|
# Get a list of our source files and their respective object file targets
|
||||||
@ -180,6 +180,7 @@ $(BIN)/SameBoy.app: $(BIN)/SameBoy.app/Contents/MacOS/SameBoy \
|
|||||||
$(BIN)/SameBoy.app/Contents/Resources/dmg_boot.bin \
|
$(BIN)/SameBoy.app/Contents/Resources/dmg_boot.bin \
|
||||||
$(BIN)/SameBoy.app/Contents/Resources/cgb_boot.bin \
|
$(BIN)/SameBoy.app/Contents/Resources/cgb_boot.bin \
|
||||||
$(BIN)/SameBoy.app/Contents/Resources/agb_boot.bin \
|
$(BIN)/SameBoy.app/Contents/Resources/agb_boot.bin \
|
||||||
|
$(BIN)/SameBoy.app/Contents/Resources/sgb_boot.bin \
|
||||||
$(patsubst %.xib,%.nib,$(addprefix $(BIN)/SameBoy.app/Contents/Resources/Base.lproj/,$(shell cd Cocoa;ls *.xib))) \
|
$(patsubst %.xib,%.nib,$(addprefix $(BIN)/SameBoy.app/Contents/Resources/Base.lproj/,$(shell cd Cocoa;ls *.xib))) \
|
||||||
$(BIN)/SameBoy.qlgenerator \
|
$(BIN)/SameBoy.qlgenerator \
|
||||||
Shaders
|
Shaders
|
||||||
@ -307,7 +308,7 @@ $(BIN)/BootROMs/%.bin: BootROMs/%.asm
|
|||||||
-@$(MKDIR) -p $(dir $@)
|
-@$(MKDIR) -p $(dir $@)
|
||||||
cd BootROMs && rgbasm -o ../$@.tmp ../$<
|
cd BootROMs && rgbasm -o ../$@.tmp ../$<
|
||||||
rgblink -o $@.tmp2 $@.tmp
|
rgblink -o $@.tmp2 $@.tmp
|
||||||
head -c $(if $(findstring dmg,$@), 256, 2304) $@.tmp2 > $@
|
head -c $(if $(findstring dmg,$@)$(findstring sgb,$@), 256, 2304) $@.tmp2 > $@
|
||||||
@rm $@.tmp $@.tmp2
|
@rm $@.tmp $@.tmp2
|
||||||
|
|
||||||
# Libretro Core (uses its own build system)
|
# Libretro Core (uses its own build system)
|
||||||
|
Loading…
Reference in New Issue
Block a user