pizza: SGB joypad functionality working
This commit is contained in:
parent
6df2afccee
commit
95a56b15a8
|
@ -12,7 +12,7 @@ namespace BizHawk.Emulation.Cores.Consoles.Nintendo.Gameboy
|
||||||
public abstract class LibPizza : LibWaterboxCore
|
public abstract class LibPizza : LibWaterboxCore
|
||||||
{
|
{
|
||||||
[Flags]
|
[Flags]
|
||||||
public enum Buttons : int
|
public enum Buttons : uint
|
||||||
{
|
{
|
||||||
A = 0x01,
|
A = 0x01,
|
||||||
B = 0x02,
|
B = 0x02,
|
||||||
|
@ -29,7 +29,7 @@ namespace BizHawk.Emulation.Cores.Consoles.Nintendo.Gameboy
|
||||||
public Buttons Keys;
|
public Buttons Keys;
|
||||||
}
|
}
|
||||||
[BizImport(CC)]
|
[BizImport(CC)]
|
||||||
public abstract bool Init(byte[] rom, int romlen);
|
public abstract bool Init(byte[] rom, int romlen, bool sgb);
|
||||||
[BizImport(CC)]
|
[BizImport(CC)]
|
||||||
public abstract bool IsCGB();
|
public abstract bool IsCGB();
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,6 +15,7 @@ namespace BizHawk.Emulation.Cores.Consoles.Nintendo.Gameboy
|
||||||
public class Pizza : WaterboxCore, IGameboyCommon
|
public class Pizza : WaterboxCore, IGameboyCommon
|
||||||
{
|
{
|
||||||
private LibPizza _pizza;
|
private LibPizza _pizza;
|
||||||
|
private readonly bool _sgb;
|
||||||
|
|
||||||
[CoreConstructor("GB")]
|
[CoreConstructor("GB")]
|
||||||
public Pizza(byte[] rom, CoreComm comm)
|
public Pizza(byte[] rom, CoreComm comm)
|
||||||
|
@ -22,8 +23,8 @@ namespace BizHawk.Emulation.Cores.Consoles.Nintendo.Gameboy
|
||||||
{
|
{
|
||||||
DefaultWidth = 160,
|
DefaultWidth = 160,
|
||||||
DefaultHeight = 144,
|
DefaultHeight = 144,
|
||||||
MaxWidth = 160,
|
MaxWidth = 256,
|
||||||
MaxHeight = 144,
|
MaxHeight = 224,
|
||||||
MaxSamples = 1024,
|
MaxSamples = 1024,
|
||||||
SystemId = "GB",
|
SystemId = "GB",
|
||||||
DefaultFpsNumerator = TICKSPERSECOND,
|
DefaultFpsNumerator = TICKSPERSECOND,
|
||||||
|
@ -42,12 +43,16 @@ namespace BizHawk.Emulation.Cores.Consoles.Nintendo.Gameboy
|
||||||
MmapHeapSizeKB = 32 * 1024
|
MmapHeapSizeKB = 32 * 1024
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!_pizza.Init(rom, rom.Length))
|
_sgb = true;
|
||||||
|
if (!_pizza.Init(rom, rom.Length, _sgb))
|
||||||
{
|
{
|
||||||
throw new InvalidOperationException("Core rejected the rom!");
|
throw new InvalidOperationException("Core rejected the rom!");
|
||||||
}
|
}
|
||||||
|
|
||||||
PostInit();
|
PostInit();
|
||||||
|
|
||||||
|
if (_sgb)
|
||||||
|
VsyncNumerator = TICKSPERSECOND_SGB;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -65,28 +70,50 @@ namespace BizHawk.Emulation.Cores.Consoles.Nintendo.Gameboy
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private const int TICKSPERSECOND_SGB = 2147727;
|
private const int TICKSPERSECOND_SGB = 2147727;
|
||||||
|
|
||||||
|
#region Controller
|
||||||
|
|
||||||
|
private static readonly ControllerDefinition _definition;
|
||||||
|
public override ControllerDefinition ControllerDefinition => _definition;
|
||||||
|
|
||||||
|
static Pizza()
|
||||||
|
{
|
||||||
|
_definition = new ControllerDefinition { Name = "Gameboy Controller" };
|
||||||
|
for (int i = 0; i < 4; i++)
|
||||||
|
{
|
||||||
|
_definition.BoolButtons.AddRange(
|
||||||
|
new[] { "Up", "Down", "Left", "Right", "A", "B", "Select", "Start" }
|
||||||
|
.Select(s => $"P{i + 1} {s}"));
|
||||||
|
}
|
||||||
|
}
|
||||||
private static LibPizza.Buttons GetButtons(IController c)
|
private static LibPizza.Buttons GetButtons(IController c)
|
||||||
{
|
{
|
||||||
LibPizza.Buttons b = 0;
|
LibPizza.Buttons b = 0;
|
||||||
if (c.IsPressed("Up"))
|
for (int i = 4; i > 0; i--)
|
||||||
|
{
|
||||||
|
if (c.IsPressed($"P{i} Up"))
|
||||||
b |= LibPizza.Buttons.UP;
|
b |= LibPizza.Buttons.UP;
|
||||||
if (c.IsPressed("Down"))
|
if (c.IsPressed($"P{i} Down"))
|
||||||
b |= LibPizza.Buttons.DOWN;
|
b |= LibPizza.Buttons.DOWN;
|
||||||
if (c.IsPressed("Left"))
|
if (c.IsPressed($"P{i} Left"))
|
||||||
b |= LibPizza.Buttons.LEFT;
|
b |= LibPizza.Buttons.LEFT;
|
||||||
if (c.IsPressed("Right"))
|
if (c.IsPressed($"P{i} Right"))
|
||||||
b |= LibPizza.Buttons.RIGHT;
|
b |= LibPizza.Buttons.RIGHT;
|
||||||
if (c.IsPressed("A"))
|
if (c.IsPressed($"P{i} A"))
|
||||||
b |= LibPizza.Buttons.A;
|
b |= LibPizza.Buttons.A;
|
||||||
if (c.IsPressed("B"))
|
if (c.IsPressed($"P{i} B"))
|
||||||
b |= LibPizza.Buttons.B;
|
b |= LibPizza.Buttons.B;
|
||||||
if (c.IsPressed("Select"))
|
if (c.IsPressed($"P{i} Select"))
|
||||||
b |= LibPizza.Buttons.SELECT;
|
b |= LibPizza.Buttons.SELECT;
|
||||||
if (c.IsPressed("Start"))
|
if (c.IsPressed($"P{i} Start"))
|
||||||
b |= LibPizza.Buttons.START;
|
b |= LibPizza.Buttons.START;
|
||||||
|
if (i != 1)
|
||||||
|
b = (LibPizza.Buttons)((uint)b << 8);
|
||||||
|
}
|
||||||
return b;
|
return b;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
LibPizza.FrameInfo _tmp; // TODO: clean this up so it's not so hacky
|
LibPizza.FrameInfo _tmp; // TODO: clean this up so it's not so hacky
|
||||||
|
|
||||||
protected override LibWaterboxCore.FrameInfo FrameAdvancePrep(IController controller, bool render, bool rendersound)
|
protected override LibWaterboxCore.FrameInfo FrameAdvancePrep(IController controller, bool render, bool rendersound)
|
||||||
|
@ -99,11 +126,12 @@ namespace BizHawk.Emulation.Cores.Consoles.Nintendo.Gameboy
|
||||||
|
|
||||||
protected override void FrameAdvancePost()
|
protected override void FrameAdvancePost()
|
||||||
{
|
{
|
||||||
Console.WriteLine(_tmp.Cycles);
|
//Console.WriteLine(_tmp.Cycles);
|
||||||
_tmp = null;
|
_tmp = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool IsCGBMode() => _pizza.IsCGB();
|
public bool IsCGBMode() => _pizza.IsCGB();
|
||||||
|
public bool IsSGBMode() => _sgb;
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,6 +24,7 @@
|
||||||
|
|
||||||
char global_cart_name[256];
|
char global_cart_name[256];
|
||||||
char global_cgb; // if true, in CGB mode
|
char global_cgb; // if true, in CGB mode
|
||||||
|
char global_sgb; // if true, in SGB mode
|
||||||
char global_cpu_double_speed;
|
char global_cpu_double_speed;
|
||||||
char global_debug;
|
char global_debug;
|
||||||
char global_rumble;
|
char global_rumble;
|
||||||
|
@ -34,6 +35,7 @@ void global_init()
|
||||||
global_window = 1;
|
global_window = 1;
|
||||||
global_debug = 0;
|
global_debug = 0;
|
||||||
global_cgb = 0;
|
global_cgb = 0;
|
||||||
|
global_sgb = 0;
|
||||||
global_cpu_double_speed = 0;
|
global_cpu_double_speed = 0;
|
||||||
global_rumble = 0;
|
global_rumble = 0;
|
||||||
sprintf(global_cart_name, "NOCARTIRDGE");
|
sprintf(global_cart_name, "NOCARTIRDGE");
|
||||||
|
|
|
@ -23,6 +23,7 @@
|
||||||
extern char global_window;
|
extern char global_window;
|
||||||
extern char global_debug;
|
extern char global_debug;
|
||||||
extern char global_cgb;
|
extern char global_cgb;
|
||||||
|
extern char global_sgb;
|
||||||
// extern char global_started;
|
// extern char global_started;
|
||||||
extern char global_cpu_double_speed;
|
extern char global_cpu_double_speed;
|
||||||
extern char global_rumble;
|
extern char global_rumble;
|
||||||
|
|
|
@ -33,6 +33,7 @@
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <strings.h>
|
#include <strings.h>
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
|
#include "sgb.h"
|
||||||
|
|
||||||
/* GAMEBOY MEMORY AREAS
|
/* GAMEBOY MEMORY AREAS
|
||||||
|
|
||||||
|
@ -249,7 +250,7 @@ uint8_t mmu_read(uint16_t a)
|
||||||
|
|
||||||
/* joypad reading */
|
/* joypad reading */
|
||||||
case 0xFF00:
|
case 0xFF00:
|
||||||
return input_get_keys(mmu.memory[a]);
|
return global_sgb ? sgb_read_ff00(cycles.sampleclock) : input_get_keys(mmu.memory[a]);
|
||||||
|
|
||||||
/* CGB HDMA transfer */
|
/* CGB HDMA transfer */
|
||||||
case 0xFF55:
|
case 0xFF55:
|
||||||
|
@ -944,6 +945,9 @@ void mmu_write(uint16_t a, uint8_t v)
|
||||||
/* TODO - put them all */
|
/* TODO - put them all */
|
||||||
switch(a)
|
switch(a)
|
||||||
{
|
{
|
||||||
|
case 0xFF00:
|
||||||
|
sgb_write_ff00(v, cycles.sampleclock);
|
||||||
|
break;
|
||||||
case 0xFF01:
|
case 0xFF01:
|
||||||
case 0xFF02:
|
case 0xFF02:
|
||||||
serial_write_reg(a, v);
|
serial_write_reg(a, v);
|
||||||
|
|
|
@ -0,0 +1,278 @@
|
||||||
|
#include "sgb.h"
|
||||||
|
#include "utils.h"
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
// writes to FF00
|
||||||
|
uint64_t last_write_time;
|
||||||
|
uint8_t last_write_value;
|
||||||
|
|
||||||
|
// recv packets
|
||||||
|
uint8_t read_index; // 0-127, index of the next bit read. if 255, not currently reading
|
||||||
|
uint8_t packet[16]; // a packet in the process of being formed
|
||||||
|
|
||||||
|
uint8_t command[16 * 7]; // a command in the process of being formed
|
||||||
|
uint8_t expected_packets; // total number of packets expected for a command
|
||||||
|
uint8_t next_packet; // index of the next packet to be read
|
||||||
|
|
||||||
|
// joypad reading
|
||||||
|
uint8_t joypad_index; // index of currently reading joypad
|
||||||
|
uint8_t num_joypads; // number of currently selected joypads (MLT_REQ)
|
||||||
|
uint8_t joypad_data[4]; // data for each joypad
|
||||||
|
uint8_t joypad_has_been_read; // state for advancing joypad_index. extermely weird; logic lifted from VBA and probably wrong
|
||||||
|
|
||||||
|
// palettes
|
||||||
|
uint32_t palette[8][16];
|
||||||
|
} sgb_t;
|
||||||
|
|
||||||
|
static sgb_t sgb;
|
||||||
|
|
||||||
|
static uint32_t makecol(uint16_t c)
|
||||||
|
{
|
||||||
|
return c >> 7 & 0xf8 | c >> 12 & 0x07 | c << 6 & 0xf800 | c << 1 & 0x0700 | c << 19 & 0xf80000 | c << 14 & 0x070000 | 0xff000000;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void cmd_pal(int a, int b)
|
||||||
|
{
|
||||||
|
if ((sgb.command[0] & 7) == 1)
|
||||||
|
{
|
||||||
|
uint32_t c[7];
|
||||||
|
for (int i = 0; i < 7; i++)
|
||||||
|
c[i] = makecol(sgb.command[1 + i] | sgb.command[2 + i] << 8);
|
||||||
|
sgb.palette[0][0] = c[0];
|
||||||
|
sgb.palette[a][1] = c[1];
|
||||||
|
sgb.palette[a][2] = c[2];
|
||||||
|
sgb.palette[a][3] = c[3];
|
||||||
|
sgb.palette[b][1] = c[4];
|
||||||
|
sgb.palette[b][2] = c[5];
|
||||||
|
sgb.palette[b][3] = c[6];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
utils_log("SGB: cmd_pal bad length");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void cmd_mlt_req(void)
|
||||||
|
{
|
||||||
|
if ((sgb.command[0] & 7) == 1)
|
||||||
|
{
|
||||||
|
switch (sgb.command[1] & 3)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
case 2:
|
||||||
|
sgb.num_joypads = 1;
|
||||||
|
sgb.joypad_index = 0;
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
sgb.num_joypads = 2;
|
||||||
|
sgb.joypad_index = 1;
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
sgb.num_joypads = 4;
|
||||||
|
sgb.joypad_index = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
utils_log("SGB: %u joypads", sgb.num_joypads);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
utils_log("SGB: cmd_mlt_req bad length");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void do_command(void)
|
||||||
|
{
|
||||||
|
const int command = sgb.command[0] >> 3;
|
||||||
|
switch (command)
|
||||||
|
{
|
||||||
|
default:
|
||||||
|
utils_log("SGB: Unknown or unimplemented command %02xh", command);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x00: // PAL01
|
||||||
|
utils_log("SGB: PAL01");
|
||||||
|
cmd_pal(0, 1);
|
||||||
|
break;
|
||||||
|
case 0x01: // PAL23
|
||||||
|
utils_log("SGB: PAL23");
|
||||||
|
cmd_pal(2, 3);
|
||||||
|
break;
|
||||||
|
case 0x02: // PAL03
|
||||||
|
utils_log("SGB: PAL03");
|
||||||
|
cmd_pal(0, 3);
|
||||||
|
break;
|
||||||
|
case 0x03: // PAL12
|
||||||
|
utils_log("SGB: PAL12");
|
||||||
|
cmd_pal(1, 2);
|
||||||
|
break;
|
||||||
|
|
||||||
|
// unknown functions
|
||||||
|
case 0x0c: // ATRC_EN
|
||||||
|
utils_log("SGB: ATRC_EN??");
|
||||||
|
break;
|
||||||
|
case 0x0d: // TEST_EN
|
||||||
|
utils_log("SGB: TEST_EN??");
|
||||||
|
break;
|
||||||
|
case 0x0e: // ICON_EN
|
||||||
|
utils_log("SGB: ICON_EN??");
|
||||||
|
break;
|
||||||
|
case 0x18: // OBJ_TRN
|
||||||
|
// no game used this
|
||||||
|
utils_log("SGB: OBJ_TRN??");
|
||||||
|
break;
|
||||||
|
|
||||||
|
// unimplementable functions
|
||||||
|
case 0x10: // DATA_TRN
|
||||||
|
// TODO: Is it possible for this to write data to
|
||||||
|
// memory areas used for the attribute file, etc?
|
||||||
|
// If so, do games do this?
|
||||||
|
utils_log("SGB: DATA_TRN!!");
|
||||||
|
break;
|
||||||
|
case 0x12: // JUMP
|
||||||
|
utils_log("SGB: JUMP!!");
|
||||||
|
break;
|
||||||
|
|
||||||
|
// joypad
|
||||||
|
case 0x11: // MLT_REQ
|
||||||
|
utils_log("SGB: MLT_REQ");
|
||||||
|
cmd_mlt_req();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void do_packet(void)
|
||||||
|
{
|
||||||
|
memcpy(sgb.command + sgb.next_packet * 16, sgb.packet, sizeof(sgb.packet));
|
||||||
|
sgb.next_packet++;
|
||||||
|
|
||||||
|
if (sgb.expected_packets == 0) // not in the middle of a command
|
||||||
|
sgb.expected_packets = sgb.command[0] & 7;
|
||||||
|
|
||||||
|
if (sgb.expected_packets == 0) // huh?
|
||||||
|
{
|
||||||
|
utils_log("SGB: zero packet command");
|
||||||
|
sgb.expected_packets = 0;
|
||||||
|
sgb.next_packet = 0;
|
||||||
|
}
|
||||||
|
else if (sgb.next_packet == sgb.expected_packets)
|
||||||
|
{
|
||||||
|
do_command();
|
||||||
|
sgb.expected_packets = 0;
|
||||||
|
sgb.next_packet = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void sgb_init(void)
|
||||||
|
{
|
||||||
|
memset(&sgb, 0, sizeof(sgb));
|
||||||
|
sgb.read_index = 255;
|
||||||
|
sgb.num_joypads = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void sgb_write_ff00(uint8_t val, uint64_t time)
|
||||||
|
{
|
||||||
|
val &= 0x30;
|
||||||
|
|
||||||
|
utils_log("ZZ: %02x, %llu", val, time);
|
||||||
|
const int p14_fell = (val & 0x10) < (sgb.last_write_value & 0x10);
|
||||||
|
const int p15_fell = (val & 0x20) < (sgb.last_write_value & 0x20);
|
||||||
|
const int p14_rose = (val & 0x10) > (sgb.last_write_value & 0x10);
|
||||||
|
const int p15_rose = (val & 0x20) > (sgb.last_write_value & 0x20);
|
||||||
|
|
||||||
|
if (val == 0) // reset command processing
|
||||||
|
{
|
||||||
|
sgb.read_index = 0;
|
||||||
|
memset(sgb.packet, 0, sizeof(sgb.packet));
|
||||||
|
}
|
||||||
|
else if (sgb.read_index != 255) // currently reading a packet
|
||||||
|
{
|
||||||
|
if (p14_fell || p15_fell)
|
||||||
|
{
|
||||||
|
if (sgb.read_index == 128) // end of packet
|
||||||
|
{
|
||||||
|
if (p14_fell)
|
||||||
|
do_packet();
|
||||||
|
else
|
||||||
|
utils_log("SGB: Stop bit not present");
|
||||||
|
sgb.read_index = 255;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (p15_fell)
|
||||||
|
{
|
||||||
|
int byte = sgb.read_index >> 3;
|
||||||
|
int bit = sgb.read_index & 7;
|
||||||
|
sgb.packet[byte] |= 1 << bit;
|
||||||
|
}
|
||||||
|
sgb.read_index++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else // joypad processing
|
||||||
|
{
|
||||||
|
if (val == 0x10)
|
||||||
|
sgb.joypad_has_been_read |= 2; // reading P15
|
||||||
|
if (val == 0x20)
|
||||||
|
sgb.joypad_has_been_read |= 1; // reading P14
|
||||||
|
if (val == 0x30 && (p14_rose || p15_rose))
|
||||||
|
{
|
||||||
|
if (sgb.joypad_has_been_read == 7)
|
||||||
|
{
|
||||||
|
sgb.joypad_has_been_read = 0;
|
||||||
|
sgb.joypad_index++;
|
||||||
|
sgb.joypad_index &= sgb.num_joypads - 1;
|
||||||
|
utils_log("SGB: joypad index to %u", sgb.joypad_index);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
sgb.joypad_has_been_read &= 3; // the other line must be asserted and a read must happen before joypad_index inc??
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sgb.last_write_value = val;
|
||||||
|
sgb.last_write_time = time;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t sgb_read_ff00(uint64_t time)
|
||||||
|
{
|
||||||
|
uint8_t ret = sgb.last_write_value & 0xf0 | 0xc0;
|
||||||
|
const int p14 = !(ret & 0x10);
|
||||||
|
const int p15 = !(ret & 0x20);
|
||||||
|
const int ji = sgb.joypad_index;
|
||||||
|
|
||||||
|
// TODO: is this "reset" correct?
|
||||||
|
sgb.joypad_has_been_read |= 4; // read occured
|
||||||
|
sgb.read_index = 255;
|
||||||
|
sgb.next_packet = 0;
|
||||||
|
sgb.expected_packets = 0;
|
||||||
|
|
||||||
|
if (!p14 && !p15)
|
||||||
|
{
|
||||||
|
utils_log("SGB: SCAN%u", ji);
|
||||||
|
// scan id
|
||||||
|
return ret | (15 - ji);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// get data
|
||||||
|
const uint8_t j = sgb.joypad_data[ji];
|
||||||
|
if (p14)
|
||||||
|
ret |= j >> 4;
|
||||||
|
if (p15)
|
||||||
|
ret |= j & 0x0f;
|
||||||
|
utils_log("SGB: READ%u %02x", ji, ret ^ 0x0f);
|
||||||
|
return ret ^ 0x0f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// for each of 4 joypads:
|
||||||
|
// 7......0
|
||||||
|
// DULRSsBA
|
||||||
|
void sgb_set_controller_data(const uint8_t *buttons)
|
||||||
|
{
|
||||||
|
memcpy(sgb.joypad_data, buttons, sizeof(sgb.joypad_data));
|
||||||
|
}
|
|
@ -0,0 +1,10 @@
|
||||||
|
#pragma once
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
void sgb_write_ff00(uint8_t val, uint64_t time);
|
||||||
|
|
||||||
|
uint8_t sgb_read_ff00(uint64_t time);
|
||||||
|
|
||||||
|
void sgb_set_controller_data(const uint8_t* buttons);
|
||||||
|
|
||||||
|
void sgb_init(void);
|
|
@ -37,6 +37,7 @@
|
||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
#include "mmu.h"
|
#include "mmu.h"
|
||||||
#include "sound_output.h"
|
#include "sound_output.h"
|
||||||
|
#include "sgb.h"
|
||||||
|
|
||||||
/* proto */
|
/* proto */
|
||||||
void frame_cb();
|
void frame_cb();
|
||||||
|
@ -54,7 +55,7 @@ int main(void)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
EXPORT int Init(const void *rom, int romlen)
|
EXPORT int Init(const void *rom, int romlen, int sgb)
|
||||||
{
|
{
|
||||||
/* init global variables */
|
/* init global variables */
|
||||||
global_init();
|
global_init();
|
||||||
|
@ -64,6 +65,11 @@ EXPORT int Init(const void *rom, int romlen)
|
||||||
|
|
||||||
if (ret != 0)
|
if (ret != 0)
|
||||||
return 0; // failure
|
return 0; // failure
|
||||||
|
global_sgb = !!sgb;
|
||||||
|
if (global_sgb && global_cgb)
|
||||||
|
utils_log("Warn: CGB game in SGB mode");
|
||||||
|
if (sgb)
|
||||||
|
sgb_init();
|
||||||
|
|
||||||
gameboy_init();
|
gameboy_init();
|
||||||
|
|
||||||
|
@ -73,7 +79,7 @@ EXPORT int Init(const void *rom, int romlen)
|
||||||
/* set rumble cb */
|
/* set rumble cb */
|
||||||
mmu_set_rumble_cb(&rumble_cb);
|
mmu_set_rumble_cb(&rumble_cb);
|
||||||
|
|
||||||
sound_output_init(2 * 1024 * 1024, 44100);
|
sound_output_init(global_sgb ? 2147727 : 2097152, 44100);
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
@ -95,6 +101,9 @@ static uint64_t overflow;
|
||||||
|
|
||||||
EXPORT void FrameAdvance(MyFrameInfo* frame)
|
EXPORT void FrameAdvance(MyFrameInfo* frame)
|
||||||
{
|
{
|
||||||
|
if (global_sgb)
|
||||||
|
sgb_set_controller_data((uint8_t*)&frame->Keys);
|
||||||
|
else
|
||||||
input_set_keys(frame->Keys);
|
input_set_keys(frame->Keys);
|
||||||
current_vbuff = frame->VideoBuffer;
|
current_vbuff = frame->VideoBuffer;
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue