Coleco: Initial commits for Super Game Module
This commit is contained in:
parent
47cfe9ceb6
commit
f4aa1269ab
|
@ -334,7 +334,8 @@
|
|||
this.ColecoSubMenu = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.ColecoControllerSettingsMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.ColecoSkipBiosMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.N64SubMenu = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.ColecoUseSGMMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.N64SubMenu = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.N64PluginSettingsMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.N64ControllerSettingsMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.toolStripSeparator23 = new System.Windows.Forms.ToolStripSeparator();
|
||||
|
@ -3034,7 +3035,8 @@
|
|||
this.ColecoSubMenu.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
|
||||
this.ColecoControllerSettingsMenuItem,
|
||||
this.toolStripSeparator35,
|
||||
this.ColecoSkipBiosMenuItem});
|
||||
this.ColecoSkipBiosMenuItem,
|
||||
this.ColecoUseSGMMenuItem});
|
||||
this.ColecoSubMenu.Name = "ColecoSubMenu";
|
||||
this.ColecoSubMenu.Size = new System.Drawing.Size(56, 19);
|
||||
this.ColecoSubMenu.Text = "&Coleco";
|
||||
|
@ -3059,10 +3061,17 @@
|
|||
this.ColecoSkipBiosMenuItem.Size = new System.Drawing.Size(253, 22);
|
||||
this.ColecoSkipBiosMenuItem.Text = "&Skip BIOS intro (When Applicable)";
|
||||
this.ColecoSkipBiosMenuItem.Click += new System.EventHandler(this.ColecoSkipBiosMenuItem_Click);
|
||||
//
|
||||
// N64SubMenu
|
||||
//
|
||||
this.N64SubMenu.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
|
||||
//
|
||||
// ColecoUseSGMMenuItem
|
||||
//
|
||||
this.ColecoUseSGMMenuItem.Name = "ColecoUseSGMMenuItem";
|
||||
this.ColecoUseSGMMenuItem.Size = new System.Drawing.Size(253, 22);
|
||||
this.ColecoUseSGMMenuItem.Text = "&Use the Super Game Module";
|
||||
this.ColecoUseSGMMenuItem.Click += new System.EventHandler(this.ColecoUseSGMMenuItem_Click);
|
||||
//
|
||||
// N64SubMenu
|
||||
//
|
||||
this.N64SubMenu.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
|
||||
this.N64PluginSettingsMenuItem,
|
||||
this.N64ControllerSettingsMenuItem,
|
||||
this.toolStripSeparator23,
|
||||
|
@ -4257,6 +4266,7 @@
|
|||
private System.Windows.Forms.ToolStripSeparator toolStripSeparator28;
|
||||
private System.Windows.Forms.ToolStripMenuItem ColecoSubMenu;
|
||||
private System.Windows.Forms.ToolStripMenuItem ColecoSkipBiosMenuItem;
|
||||
private System.Windows.Forms.ToolStripMenuItem ColecoUseSGMMenuItem;
|
||||
private System.Windows.Forms.ToolStripMenuItem ColecoControllerSettingsMenuItem;
|
||||
private System.Windows.Forms.ToolStripStatusLabel LedLightStatusLabel;
|
||||
private System.Windows.Forms.ToolStripMenuItem GBASubMenu;
|
||||
|
|
|
@ -2206,6 +2206,7 @@ namespace BizHawk.Client.EmuHawk
|
|||
{
|
||||
var ss = ((ColecoVision)Emulator).GetSyncSettings();
|
||||
ColecoSkipBiosMenuItem.Checked = ss.SkipBiosIntro;
|
||||
ColecoUseSGMMenuItem.Checked = ss.UseSGM;
|
||||
ColecoControllerSettingsMenuItem.Enabled = !Global.MovieSession.Movie.IsActive;
|
||||
}
|
||||
|
||||
|
@ -2216,6 +2217,13 @@ namespace BizHawk.Client.EmuHawk
|
|||
PutCoreSyncSettings(ss);
|
||||
}
|
||||
|
||||
private void ColecoUseSGMMenuItem_Click(object sender, EventArgs e)
|
||||
{
|
||||
var ss = ((ColecoVision)Emulator).GetSyncSettings();
|
||||
ss.UseSGM ^= true;
|
||||
PutCoreSyncSettings(ss);
|
||||
}
|
||||
|
||||
private void ColecoControllerSettingsMenuItem_Click(object sender, EventArgs e)
|
||||
{
|
||||
new ColecoControllerSettings().ShowDialog();
|
||||
|
|
|
@ -415,6 +415,7 @@
|
|||
<Compile Include="Consoles\Coleco\ColecoVision.ISoundProvider.cs">
|
||||
<DependentUpon>ColecoVision.cs</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Consoles\Coleco\AY_3_8910.cs" />
|
||||
<Compile Include="Consoles\Coleco\TMS9918A.cs" />
|
||||
<Compile Include="Consoles\Coleco\ColecoControllerDeck.cs" />
|
||||
<Compile Include="Consoles\Coleco\ColecoControllers.cs" />
|
||||
|
@ -1361,4 +1362,4 @@
|
|||
<Target Name="AfterBuild">
|
||||
</Target>
|
||||
-->
|
||||
</Project>
|
||||
</Project>
|
|
@ -0,0 +1,400 @@
|
|||
using System;
|
||||
|
||||
using BizHawk.Common;
|
||||
using BizHawk.Common.NumberExtensions;
|
||||
using BizHawk.Emulation.Common;
|
||||
|
||||
namespace BizHawk.Emulation.Cores.ColecoVision
|
||||
{
|
||||
public sealed class AY_3_8910 : ISoundProvider
|
||||
{
|
||||
private readonly BlipBuffer _blip = new BlipBuffer(4096);
|
||||
private short[] _sampleBuffer = new short[0];
|
||||
|
||||
|
||||
public AY_3_8910()
|
||||
{
|
||||
_blip.SetRates(894866 / 4.0, 44100);
|
||||
Reset();
|
||||
}
|
||||
|
||||
public byte[] Register = new byte[16];
|
||||
|
||||
public byte port_sel;
|
||||
|
||||
public int total_clock; // TODO: what is this used for?
|
||||
|
||||
public void Reset()
|
||||
{
|
||||
clock_A = clock_B = clock_C = 0x1000;
|
||||
noise_clock = 0x20;
|
||||
port_sel = 0;
|
||||
|
||||
for (int i = 0; i < 16; i++)
|
||||
{
|
||||
Register[i] = 0x0000;
|
||||
}
|
||||
sync_psg_state();
|
||||
DiscardSamples();
|
||||
}
|
||||
|
||||
public void DiscardSamples()
|
||||
{
|
||||
_blip.Clear();
|
||||
_sampleClock = 0;
|
||||
}
|
||||
|
||||
public void GetSamplesAsync(short[] samples)
|
||||
{
|
||||
throw new NotSupportedException("Async is not available");
|
||||
}
|
||||
|
||||
public bool CanProvideAsync => false;
|
||||
|
||||
public SyncSoundMode SyncMode => SyncSoundMode.Sync;
|
||||
|
||||
public void SetSyncMode(SyncSoundMode mode)
|
||||
{
|
||||
if (mode != SyncSoundMode.Sync)
|
||||
{
|
||||
throw new InvalidOperationException("Only Sync mode is supported.");
|
||||
}
|
||||
}
|
||||
|
||||
public void GetSamplesSync(out short[] samples, out int nsamp)
|
||||
{
|
||||
_blip.EndFrame((uint)_sampleClock);
|
||||
_sampleClock = 0;
|
||||
|
||||
nsamp = _blip.SamplesAvailable();
|
||||
int targetLength = nsamp * 2;
|
||||
if (_sampleBuffer.Length != targetLength)
|
||||
{
|
||||
_sampleBuffer = new short[targetLength];
|
||||
}
|
||||
|
||||
_blip.ReadSamplesLeft(_sampleBuffer, nsamp);
|
||||
for (int i = 0; i < _sampleBuffer.Length; i += 2)
|
||||
{
|
||||
_sampleBuffer[i + 1] = _sampleBuffer[i];
|
||||
}
|
||||
|
||||
samples = _sampleBuffer;
|
||||
}
|
||||
|
||||
public void GetSamples(short[] samples)
|
||||
{
|
||||
throw new Exception();
|
||||
}
|
||||
|
||||
private static readonly int[] VolumeTable =
|
||||
{
|
||||
0x0000, 0x0055, 0x0079, 0x00AB, 0x00F1, 0x0155, 0x01E3, 0x02AA,
|
||||
0x03C5, 0x0555, 0x078B, 0x0AAB, 0x0F16, 0x1555, 0x1E2B, 0x2AAA
|
||||
};
|
||||
|
||||
private int _sampleClock;
|
||||
private int _latchedSample;
|
||||
|
||||
private int TotalExecutedCycles;
|
||||
private int PendingCycles;
|
||||
private int psg_clock;
|
||||
private int sq_per_A, sq_per_B, sq_per_C;
|
||||
private int clock_A, clock_B, clock_C;
|
||||
private int vol_A, vol_B, vol_C;
|
||||
private bool A_on, B_on, C_on;
|
||||
private bool A_up, B_up, C_up;
|
||||
private bool A_noise, B_noise, C_noise;
|
||||
|
||||
private int env_per;
|
||||
private int env_clock;
|
||||
private int env_shape;
|
||||
private int env_E;
|
||||
private int E_up_down;
|
||||
private int env_vol_A, env_vol_B, env_vol_C;
|
||||
|
||||
private int noise_clock;
|
||||
private int noise_per;
|
||||
private int noise = 0x1;
|
||||
|
||||
public Func<byte, bool, byte> ReadMemory;
|
||||
public Func<byte, byte, bool, bool> WriteMemory;
|
||||
|
||||
public void SyncState(Serializer ser)
|
||||
{
|
||||
ser.BeginSection("PSG");
|
||||
|
||||
ser.Sync("Register", ref Register, false);
|
||||
ser.Sync("Toal_executed_cycles", ref TotalExecutedCycles);
|
||||
ser.Sync("Pending_Cycles", ref PendingCycles);
|
||||
|
||||
ser.Sync("psg_clock", ref psg_clock);
|
||||
ser.Sync("clock_A", ref clock_A);
|
||||
ser.Sync("clock_B", ref clock_B);
|
||||
ser.Sync("clock_C", ref clock_C);
|
||||
ser.Sync("noise_clock", ref noise_clock);
|
||||
ser.Sync("env_clock", ref env_clock);
|
||||
ser.Sync("A_up", ref A_up);
|
||||
ser.Sync("B_up", ref B_up);
|
||||
ser.Sync("C_up", ref C_up);
|
||||
ser.Sync("noise", ref noise);
|
||||
ser.Sync("env_E", ref env_E);
|
||||
ser.Sync("E_up_down", ref E_up_down);
|
||||
ser.Sync("port_sel", ref port_sel);
|
||||
|
||||
sync_psg_state();
|
||||
|
||||
ser.EndSection();
|
||||
}
|
||||
|
||||
public byte ReadPSG()
|
||||
{
|
||||
return Register[port_sel];
|
||||
}
|
||||
|
||||
private void sync_psg_state()
|
||||
{
|
||||
sq_per_A = (Register[0] & 0xFF) | (((Register[4] & 0xF) << 8));
|
||||
if (sq_per_A == 0)
|
||||
{
|
||||
sq_per_A = 0x1000;
|
||||
}
|
||||
|
||||
sq_per_B = (Register[1] & 0xFF) | (((Register[5] & 0xF) << 8));
|
||||
if (sq_per_B == 0)
|
||||
{
|
||||
sq_per_B = 0x1000;
|
||||
}
|
||||
|
||||
sq_per_C = (Register[2] & 0xFF) | (((Register[6] & 0xF) << 8));
|
||||
if (sq_per_C == 0)
|
||||
{
|
||||
sq_per_C = 0x1000;
|
||||
}
|
||||
|
||||
env_per = (Register[3] & 0xFF) | (((Register[7] & 0xFF) << 8));
|
||||
if (env_per == 0)
|
||||
{
|
||||
env_per = 0x10000;
|
||||
}
|
||||
|
||||
env_per *= 2;
|
||||
|
||||
A_on = Register[8].Bit(0);
|
||||
B_on = Register[8].Bit(1);
|
||||
C_on = Register[8].Bit(2);
|
||||
A_noise = Register[8].Bit(3);
|
||||
B_noise = Register[8].Bit(4);
|
||||
C_noise = Register[8].Bit(5);
|
||||
|
||||
noise_per = Register[9] & 0x1F;
|
||||
if (noise_per == 0)
|
||||
{
|
||||
noise_per = 0x20;
|
||||
}
|
||||
|
||||
var shape_select = Register[10] & 0xF;
|
||||
|
||||
if (shape_select < 4)
|
||||
env_shape = 0;
|
||||
else if (shape_select < 8)
|
||||
env_shape = 1;
|
||||
else
|
||||
env_shape = 2 + (shape_select - 8);
|
||||
|
||||
vol_A = Register[11] & 0xF;
|
||||
env_vol_A = (Register[11] >> 4) & 0x3;
|
||||
|
||||
vol_B = Register[12] & 0xF;
|
||||
env_vol_B = (Register[12] >> 4) & 0x3;
|
||||
|
||||
vol_C = Register[13] & 0xF;
|
||||
env_vol_C = (Register[13] >> 4) & 0x3;
|
||||
}
|
||||
|
||||
public bool WritePSG(byte value)
|
||||
{
|
||||
value &= 0xFF;
|
||||
|
||||
if (port_sel == 4 || port_sel == 5 || port_sel == 6 || port_sel == 10)
|
||||
value &= 0xF;
|
||||
|
||||
if (port_sel == 9)
|
||||
value &= 0x1F;
|
||||
|
||||
if (port_sel == 11 || port_sel == 12 || port_sel == 13)
|
||||
value &= 0x3F;
|
||||
|
||||
Register[port_sel] = value;
|
||||
|
||||
sync_psg_state();
|
||||
|
||||
if (port_sel == 10)
|
||||
{
|
||||
env_clock = env_per;
|
||||
|
||||
if (env_shape == 0 || env_shape == 2 || env_shape == 3 || env_shape == 4 || env_shape == 5)
|
||||
{
|
||||
env_E = 15;
|
||||
E_up_down = -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
env_E = 0;
|
||||
E_up_down = 1;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public void generate_sound(int cycles_to_do)
|
||||
{
|
||||
// there are 4 cpu cycles for every psg cycle
|
||||
bool sound_out_A;
|
||||
bool sound_out_B;
|
||||
bool sound_out_C;
|
||||
|
||||
for (int i = 0; i < cycles_to_do; i++)
|
||||
{
|
||||
psg_clock++;
|
||||
|
||||
if (psg_clock == 4)
|
||||
{
|
||||
psg_clock = 0;
|
||||
|
||||
total_clock++;
|
||||
|
||||
clock_A--;
|
||||
clock_B--;
|
||||
clock_C--;
|
||||
|
||||
noise_clock--;
|
||||
env_clock--;
|
||||
|
||||
// clock noise
|
||||
if (noise_clock == 0)
|
||||
{
|
||||
noise = (noise >> 1) ^ (noise.Bit(0) ? 0x10004 : 0);
|
||||
noise_clock = noise_per;
|
||||
}
|
||||
|
||||
if (env_clock == 0)
|
||||
{
|
||||
env_clock = env_per;
|
||||
|
||||
env_E += E_up_down;
|
||||
|
||||
if (env_E == 16 || env_E == -1)
|
||||
{
|
||||
|
||||
// we just completed a period of the envelope, determine what to do now based on the envelope shape
|
||||
if (env_shape == 0 || env_shape == 1 || env_shape == 3 || env_shape == 9)
|
||||
{
|
||||
E_up_down = 0;
|
||||
env_E = 0;
|
||||
}
|
||||
else if (env_shape == 5 || env_shape == 7)
|
||||
{
|
||||
E_up_down = 0;
|
||||
env_E = 15;
|
||||
}
|
||||
else if (env_shape == 4 || env_shape == 8)
|
||||
{
|
||||
if (env_E == 16)
|
||||
{
|
||||
env_E = 15;
|
||||
E_up_down = -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
env_E = 0;
|
||||
E_up_down = 1;
|
||||
}
|
||||
}
|
||||
else if (env_shape == 2)
|
||||
{
|
||||
env_E = 15;
|
||||
}
|
||||
else
|
||||
{
|
||||
env_E = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (clock_A == 0)
|
||||
{
|
||||
A_up = !A_up;
|
||||
clock_A = sq_per_A;
|
||||
}
|
||||
|
||||
if (clock_B == 0)
|
||||
{
|
||||
B_up = !B_up;
|
||||
clock_B = sq_per_B;
|
||||
}
|
||||
|
||||
if (clock_C == 0)
|
||||
{
|
||||
C_up = !C_up;
|
||||
clock_C = sq_per_C;
|
||||
}
|
||||
|
||||
|
||||
sound_out_A = (noise.Bit(0) | A_noise) & (A_on | A_up);
|
||||
sound_out_B = (noise.Bit(0) | B_noise) & (B_on | B_up);
|
||||
sound_out_C = (noise.Bit(0) | C_noise) & (C_on | C_up);
|
||||
|
||||
// now calculate the volume of each channel and add them together
|
||||
int v;
|
||||
|
||||
if (env_vol_A == 0)
|
||||
{
|
||||
v = (short)(sound_out_A ? VolumeTable[vol_A] : 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
int shift_A = 3 - env_vol_A;
|
||||
if (shift_A < 0)
|
||||
shift_A = 0;
|
||||
v = (short)(sound_out_A ? (VolumeTable[env_E] >> shift_A) : 0);
|
||||
}
|
||||
|
||||
if (env_vol_B == 0)
|
||||
{
|
||||
v += (short)(sound_out_B ? VolumeTable[vol_B] : 0);
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
int shift_B = 3 - env_vol_B;
|
||||
if (shift_B < 0)
|
||||
shift_B = 0;
|
||||
v += (short)(sound_out_B ? (VolumeTable[env_E] >> shift_B) : 0);
|
||||
}
|
||||
|
||||
if (env_vol_C == 0)
|
||||
{
|
||||
v += (short)(sound_out_C ? VolumeTable[vol_C] : 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
int shift_C = 3 - env_vol_C;
|
||||
if (shift_C < 0)
|
||||
shift_C = 0;
|
||||
v += (short)(sound_out_C ? (VolumeTable[env_E] >> shift_C) : 0);
|
||||
}
|
||||
|
||||
if (v != _latchedSample)
|
||||
{
|
||||
_blip.AddDelta((uint)_sampleClock, v - _latchedSample);
|
||||
_latchedSample = v;
|
||||
}
|
||||
|
||||
_sampleClock++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -51,6 +51,14 @@ namespace BizHawk.Emulation.Cores.ColecoVision
|
|||
}
|
||||
}
|
||||
|
||||
public bool use_SGM = false;
|
||||
public bool is_MC = false;
|
||||
public int MC_bank = 0;
|
||||
public bool enable_SGM_high = false;
|
||||
public bool enable_SGM_low = false;
|
||||
public byte port_0x53, port_0x7F;
|
||||
|
||||
|
||||
public int Frame => _frame;
|
||||
|
||||
public string SystemId => "Coleco";
|
||||
|
|
|
@ -46,6 +46,7 @@ namespace BizHawk.Emulation.Cores.ColecoVision
|
|||
public class ColecoSyncSettings
|
||||
{
|
||||
public bool SkipBiosIntro { get; set; }
|
||||
public bool UseSGM { get; set; }
|
||||
|
||||
private string _port1 = ColecoVisionControllerDeck.DefaultControllerName;
|
||||
private string _port2 = ColecoVisionControllerDeck.DefaultControllerName;
|
||||
|
|
|
@ -5,6 +5,7 @@ namespace BizHawk.Emulation.Cores.ColecoVision
|
|||
public partial class ColecoVision
|
||||
{
|
||||
private SN76489 PSG;
|
||||
private AY_3_8910 SGM_sound;
|
||||
private readonly FakeSyncSound _fakeSyncSound;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -55,7 +55,16 @@ namespace BizHawk.Emulation.Cores.ColecoVision
|
|||
ser.BeginSection("Coleco");
|
||||
_vdp.SyncState(ser);
|
||||
PSG.SyncState(ser);
|
||||
SGM_sound.SyncState(ser);
|
||||
ser.Sync("UseSGM", ref use_SGM);
|
||||
ser.Sync("is_MC", ref is_MC);
|
||||
ser.Sync("EnableSGMhigh", ref enable_SGM_high);
|
||||
ser.Sync("EnableSGMlow", ref enable_SGM_low);
|
||||
ser.Sync("Port_0x53", ref port_0x53);
|
||||
ser.Sync("Port_0x7F", ref port_0x7F);
|
||||
ser.Sync("RAM", ref _ram, false);
|
||||
ser.Sync("SGM_high_RAM", ref SGM_high_RAM, false);
|
||||
ser.Sync("SGM_low_RAM", ref SGM_low_RAM, false);
|
||||
ser.Sync("Frame", ref _frame);
|
||||
ser.Sync("LagCount", ref _lagCount);
|
||||
ser.Sync("IsLag", ref _isLag);
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
using BizHawk.Emulation.Common;
|
||||
using BizHawk.Emulation.Cores.Components;
|
||||
using BizHawk.Emulation.Cores.Components.Z80A;
|
||||
using System;
|
||||
|
||||
namespace BizHawk.Emulation.Cores.ColecoVision
|
||||
{
|
||||
|
@ -36,6 +37,8 @@ namespace BizHawk.Emulation.Cores.ColecoVision
|
|||
_fakeSyncSound = new FakeSyncSound(PSG, 735);
|
||||
ser.Register<ISoundProvider>(_fakeSyncSound);
|
||||
|
||||
SGM_sound = new AY_3_8910();
|
||||
|
||||
ControllerDeck = new ColecoVisionControllerDeck(_syncSettings.Port1, _syncSettings.Port2);
|
||||
|
||||
_vdp = new TMS9918A(_cpu);
|
||||
|
@ -56,6 +59,9 @@ namespace BizHawk.Emulation.Cores.ColecoVision
|
|||
_tracer.Header = _cpu.TraceHeader;
|
||||
ser.Register<IDisassemblable>(_cpu);
|
||||
ser.Register<ITraceable>(_tracer);
|
||||
|
||||
use_SGM = _syncSettings.UseSGM;
|
||||
Console.WriteLine(use_SGM);
|
||||
}
|
||||
|
||||
private readonly Z80A _cpu;
|
||||
|
@ -65,6 +71,9 @@ namespace BizHawk.Emulation.Cores.ColecoVision
|
|||
|
||||
private byte[] _romData;
|
||||
private byte[] _ram = new byte[1024];
|
||||
public byte[] SGM_high_RAM = new byte[0x6000];
|
||||
public byte[] SGM_low_RAM = new byte[0x2000];
|
||||
|
||||
private int _frame;
|
||||
private IController _controller;
|
||||
|
||||
|
@ -79,10 +88,22 @@ namespace BizHawk.Emulation.Cores.ColecoVision
|
|||
|
||||
private void LoadRom(byte[] rom, bool skipbios)
|
||||
{
|
||||
_romData = new byte[0x8000];
|
||||
for (int i = 0; i < 0x8000; i++)
|
||||
if (rom.Length <= 32768)
|
||||
{
|
||||
_romData[i] = rom[i % rom.Length];
|
||||
_romData = new byte[0x8000];
|
||||
for (int i = 0; i < 0x8000; i++)
|
||||
{
|
||||
_romData[i] = rom[i % rom.Length];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// all original ColecoVision games had 32k or less of ROM
|
||||
// so, if we have more then that, we must be using a MegaCart mapper
|
||||
is_MC = true;
|
||||
|
||||
_romData = rom;
|
||||
|
||||
}
|
||||
|
||||
// hack to skip colecovision title screen
|
||||
|
@ -117,6 +138,29 @@ namespace BizHawk.Emulation.Cores.ColecoVision
|
|||
return ReadController2();
|
||||
}
|
||||
|
||||
if (use_SGM)
|
||||
{
|
||||
if (port == 0x50)
|
||||
{
|
||||
return SGM_sound.port_sel;
|
||||
}
|
||||
|
||||
if (port == 0x52)
|
||||
{
|
||||
return SGM_sound.Register[SGM_sound.port_sel];
|
||||
}
|
||||
|
||||
if (port == 0x53)
|
||||
{
|
||||
return port_0x53;
|
||||
}
|
||||
|
||||
if (port == 0x7F)
|
||||
{
|
||||
return port_0x7F;
|
||||
}
|
||||
}
|
||||
|
||||
return 0xFF;
|
||||
}
|
||||
|
||||
|
@ -154,6 +198,48 @@ namespace BizHawk.Emulation.Cores.ColecoVision
|
|||
{
|
||||
PSG.WritePsgData(value, _cpu.TotalExecutedCycles);
|
||||
}
|
||||
|
||||
if (use_SGM)
|
||||
{
|
||||
if (port == 0x50)
|
||||
{
|
||||
SGM_sound.port_sel = (byte)(value & 0xF);
|
||||
}
|
||||
|
||||
if (port == 0x51)
|
||||
{
|
||||
SGM_sound.Register[SGM_sound.port_sel] = value;
|
||||
}
|
||||
|
||||
if (port == 0x53)
|
||||
{
|
||||
if ((value & 1) > 0)
|
||||
{
|
||||
enable_SGM_high = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
// NOTE: the documentation states that you shouldn't turn RAM back off once enabling it
|
||||
// so we won't do anything here
|
||||
}
|
||||
|
||||
port_0x53 = value;
|
||||
}
|
||||
|
||||
if (port == 0x7F)
|
||||
{
|
||||
if (value == 0xF)
|
||||
{
|
||||
enable_SGM_low = false;
|
||||
}
|
||||
else if (value == 0xD)
|
||||
{
|
||||
enable_SGM_low = true;
|
||||
}
|
||||
|
||||
port_0x7F = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private byte ReadController1()
|
||||
|
@ -198,17 +284,57 @@ namespace BizHawk.Emulation.Cores.ColecoVision
|
|||
{
|
||||
if (addr >= 0x8000)
|
||||
{
|
||||
return _romData[addr & 0x7FFF];
|
||||
if (!is_MC)
|
||||
{
|
||||
return _romData[addr & 0x7FFF];
|
||||
}
|
||||
else
|
||||
{
|
||||
// reading from 0xFFC0 to 0xFFFF triggers bank switching
|
||||
// I don't know if it happens before or after the read though
|
||||
|
||||
if (addr >= 0xFFC0)
|
||||
{
|
||||
MC_bank = (addr - 0xFFC0) & (_romData.Length / 0x4000 - 1);
|
||||
}
|
||||
|
||||
// the first 16K of the map is always the last 16k of the ROM
|
||||
if (addr < 0xC000)
|
||||
{
|
||||
return _romData[_romData.Length - 0x4000 + (addr - 0x8000)];
|
||||
}
|
||||
else
|
||||
{
|
||||
return _romData[MC_bank * 0x4000 + (addr - 0xC000)];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (addr >= 0x6000)
|
||||
if (!enable_SGM_high)
|
||||
{
|
||||
return _ram[addr & 1023];
|
||||
if (addr >= 0x6000)
|
||||
{
|
||||
return _ram[addr & 1023];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (addr >= 0x2000)
|
||||
{
|
||||
return SGM_high_RAM[addr - 0x2000];
|
||||
}
|
||||
}
|
||||
|
||||
if (addr < 0x2000)
|
||||
{
|
||||
return _biosRom[addr];
|
||||
if (!enable_SGM_low)
|
||||
{
|
||||
return _biosRom[addr];
|
||||
}
|
||||
else
|
||||
{
|
||||
return SGM_low_RAM[addr];
|
||||
}
|
||||
}
|
||||
|
||||
////Console.WriteLine("Unhandled read at {0:X4}", addr);
|
||||
|
@ -217,11 +343,28 @@ namespace BizHawk.Emulation.Cores.ColecoVision
|
|||
|
||||
private void WriteMemory(ushort addr, byte value)
|
||||
{
|
||||
if (addr >= 0x6000 && addr < 0x8000)
|
||||
if (!enable_SGM_high)
|
||||
{
|
||||
_ram[addr & 1023] = value;
|
||||
if (addr >= 0x6000 && addr < 0x8000)
|
||||
{
|
||||
_ram[addr & 1023] = value;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (addr >= 0x2000 && addr < 0x8000)
|
||||
{
|
||||
SGM_high_RAM[addr - 0x2000] = value;
|
||||
}
|
||||
}
|
||||
|
||||
if (addr < 0x2000)
|
||||
{
|
||||
if (enable_SGM_low)
|
||||
{
|
||||
SGM_low_RAM[addr] = value;
|
||||
}
|
||||
}
|
||||
////Console.WriteLine("Unhandled write at {0:X4}:{1:X2}", addr, value);
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue