O2Hawk: begin ppu work
This commit is contained in:
parent
8ce403dab2
commit
ecc9899f92
|
@ -709,7 +709,6 @@
|
|||
</Compile>
|
||||
<Compile Include="Consoles\Intellivision\PSG.cs" />
|
||||
<Compile Include="Consoles\Intellivision\STIC.cs" />
|
||||
<Compile Include="Consoles\Magnavox\Odyssey2\Audio.cs" />
|
||||
<Compile Include="Consoles\Magnavox\Odyssey2\O2Hawk.cs" />
|
||||
<Compile Include="Consoles\Magnavox\Odyssey2\O2Hawk.ICodeDataLog.cs" />
|
||||
<Compile Include="Consoles\Magnavox\Odyssey2\O2Hawk.IDebuggable.cs">
|
||||
|
|
|
@ -159,9 +159,9 @@ namespace BizHawk.Emulation.Common.Components.I8048
|
|||
case 0x85: OP_IMP(CL0); break; // CLR F0
|
||||
case 0x86: JP_COND(!IRQPending, IDLE); break; // JP !IRQ
|
||||
case 0x87: ILLEGAL(); break; // ILLEGAL
|
||||
case 0x88: OP_PB_DIR(OR8, BUS); break; // OR BUS,#
|
||||
case 0x89: OP_PB_DIR(OR8, P1); break; // OR P1,#
|
||||
case 0x8A: OP_PB_DIR(OR8, P2); break; // OR P2,#
|
||||
case 0x88: OP_PB_DIR(OR8, 0); break; // OR BUS,#
|
||||
case 0x89: OP_PB_DIR(OR8, 1); break; // OR P1,#
|
||||
case 0x8A: OP_PB_DIR(OR8, 2); break; // OR P2,#
|
||||
case 0x8B: ILLEGAL(); break; // ILLEGAL
|
||||
case 0x8C: OP_EXP_A(OR8, P4); break; // OR P4,A
|
||||
case 0x8D: OP_EXP_A(OR8, P5); break; // OR P5,A
|
||||
|
@ -175,9 +175,9 @@ namespace BizHawk.Emulation.Common.Components.I8048
|
|||
case 0x95: OP_IMP(CM0); break; // COM F0
|
||||
case 0x96: JP_COND(Regs[A] != 0, IDLE); break; // JP (A != 0)
|
||||
case 0x97: OP_IMP(CLC); break; // CLR C
|
||||
case 0x98: OP_PB_DIR(AND8, BUS); break; // AND BUS,#
|
||||
case 0x99: OP_PB_DIR(AND8, P1); break; // AND P1,#
|
||||
case 0x9A: OP_PB_DIR(AND8, P2); break; // AND P2,#
|
||||
case 0x98: OP_PB_DIR(AND8, 0); break; // AND BUS,#
|
||||
case 0x99: OP_PB_DIR(AND8, 1); break; // AND P1,#
|
||||
case 0x9A: OP_PB_DIR(AND8, 2); break; // AND P2,#
|
||||
case 0x9B: ILLEGAL(); break; // ILLEGAL
|
||||
case 0x9C: OP_EXP_A(AND8, P4); break; // AND P4,A
|
||||
case 0x9D: OP_EXP_A(AND8, P5); break; // AND P5,A
|
||||
|
|
|
@ -418,10 +418,18 @@ namespace BizHawk.Emulation.Common.Components.I8048
|
|||
EA = false;
|
||||
break;
|
||||
case RD_P:
|
||||
EA = false;
|
||||
reg_d_ad = cur_instr[instr_pntr++];
|
||||
reg_l_ad = cur_instr[instr_pntr++];
|
||||
|
||||
Regs[reg_d_ad] = ReadPort(reg_l_ad);
|
||||
Regs[PX + reg_l_ad] = Regs[reg_d_ad];
|
||||
break;
|
||||
case WR_P:
|
||||
WritePort(cur_instr[instr_pntr++], (byte)Regs[cur_instr[instr_pntr++]]);
|
||||
reg_d_ad = cur_instr[instr_pntr++];
|
||||
reg_l_ad = cur_instr[instr_pntr++];
|
||||
|
||||
WritePort(reg_d_ad, (byte)Regs[reg_l_ad]);
|
||||
Regs[PX + reg_d_ad] = Regs[reg_l_ad];
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -492,7 +500,7 @@ namespace BizHawk.Emulation.Common.Components.I8048
|
|||
|
||||
public string TraceHeader
|
||||
{
|
||||
get { return "MC6809: PC, machine code, mnemonic, operands, registers (A, B, X, Y, US, SP, DP, CC), Cy, flags (EFHINZVC)"; }
|
||||
get { return "MC6809: PC, machine code, mnemonic, operands, registers (A, B, X, Y, US, SP, DP, CC), Cy, flags (CAFBIFTTR)"; }
|
||||
}
|
||||
|
||||
public TraceInfo State(bool disassemble = true)
|
||||
|
@ -503,7 +511,7 @@ namespace BizHawk.Emulation.Common.Components.I8048
|
|||
{
|
||||
Disassembly = $"{(disassemble ? Disassemble(Regs[PC], ReadMemory, out notused) : "---")} ".PadRight(50),
|
||||
RegisterInfo = string.Format(
|
||||
"A:{0:X2} R0:{1:X2} R1:{2:X2} R2:{3:X2} R3:{4:X2} R4:{5:X2} R5:{6:X2} R6:{7:X2} R7:{8:X2} PSW:{9:X4} Cy:{10} {11}{12}{13}{14} {15}{16}{17}{18}{19}",
|
||||
"A:{0:X2} R0:{1:X2} R1:{2:X2} R2:{3:X2} R3:{4:X2} R4:{5:X2} R5:{6:X2} R6:{7:X2} R7:{8:X2} PSW:{9:X4} Cy:{10} {11}{12}{13}{14}{15}{16}{17}{18}{19}{20}",
|
||||
Regs[A],
|
||||
Regs[(ushort)(R0 + RB)],
|
||||
Regs[(ushort)(R1 + RB)],
|
||||
|
@ -520,6 +528,7 @@ namespace BizHawk.Emulation.Common.Components.I8048
|
|||
FlagF0 ? "F" : "f",
|
||||
FlagBS ? "B" : "b",
|
||||
IntEn ? "I" : "i",
|
||||
TimIntEn ? "N" : "n",
|
||||
F1 ? "F" : "f",
|
||||
T0 ? "T" : "t",
|
||||
T1 ? "T" : "t",
|
||||
|
|
|
@ -26,7 +26,8 @@ namespace BizHawk.Emulation.Common.Components.I8048
|
|||
|
||||
private void ResetInterrupts()
|
||||
{
|
||||
IntEn = true;
|
||||
IntEn = false;
|
||||
TimIntEn = false;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -212,13 +212,13 @@ namespace BizHawk.Emulation.Common.Components.I8048
|
|||
{
|
||||
PopulateCURINSTR(IDLE,
|
||||
IDLE,
|
||||
EEA,
|
||||
WR_P, 0, (ushort)(reg + RB),
|
||||
DEA,
|
||||
IDLE,
|
||||
IDLE,
|
||||
IDLE,
|
||||
IDLE,
|
||||
IDLE,
|
||||
IDLE,
|
||||
IDLE);
|
||||
RD_P, A, 0);
|
||||
|
||||
IRQS = 9;
|
||||
}
|
||||
|
@ -268,18 +268,35 @@ namespace BizHawk.Emulation.Common.Components.I8048
|
|||
IRQS = 9;
|
||||
}
|
||||
|
||||
// TODO: This should only write back to the port destination if directly wired, otherwise we should wait for a write pulse
|
||||
// TODO: for O2, P1 is tied direct to CTRL outputs so this is ok, BUS and P2 should do something else though
|
||||
public void OP_PB_DIR(ushort oper, ushort reg)
|
||||
{
|
||||
PopulateCURINSTR(IDLE,
|
||||
IDLE,
|
||||
IDLE,
|
||||
RD, ALU, PC,
|
||||
INC11, PC,
|
||||
IDLE,
|
||||
IDLE,
|
||||
IDLE,
|
||||
oper, reg, ALU);
|
||||
|
||||
if (reg == 1)
|
||||
{
|
||||
PopulateCURINSTR(IDLE,
|
||||
IDLE,
|
||||
IDLE,
|
||||
RD, ALU, PC,
|
||||
INC11, PC,
|
||||
oper, (ushort)(reg + PX), ALU,
|
||||
IDLE,
|
||||
IDLE,
|
||||
WR_P, reg, (ushort)(reg + PX));
|
||||
}
|
||||
else
|
||||
{
|
||||
PopulateCURINSTR(IDLE,
|
||||
IDLE,
|
||||
IDLE,
|
||||
RD, ALU, PC,
|
||||
INC11, PC,
|
||||
oper, (ushort)(reg + PX), ALU,
|
||||
IDLE,
|
||||
IDLE,
|
||||
IDLE);
|
||||
}
|
||||
|
||||
IRQS = 9;
|
||||
}
|
||||
|
||||
|
|
|
@ -33,6 +33,9 @@ namespace BizHawk.Emulation.Common.Components.I8048
|
|||
public const ushort R6 = 6;
|
||||
public const ushort R7 = 7;
|
||||
|
||||
// offset for port regs
|
||||
public const ushort PX = 70;
|
||||
|
||||
// the location pointed to by the registers is controlled by the RAM bank
|
||||
public ushort RB = 0;
|
||||
public ushort RAM_ptr = 0;
|
||||
|
@ -44,11 +47,11 @@ namespace BizHawk.Emulation.Common.Components.I8048
|
|||
//RAM occupies registers 0-63
|
||||
public const ushort PC = 64;
|
||||
public const ushort PSW = 65;
|
||||
public const ushort BUS = 66;
|
||||
public const ushort A = 67;
|
||||
public const ushort ADDR = 68; // internal
|
||||
public const ushort ALU = 69; // internal
|
||||
public const ushort ALU2 = 70; // internal
|
||||
public const ushort A = 66;
|
||||
public const ushort ADDR = 67; // internal
|
||||
public const ushort ALU = 68; // internal
|
||||
public const ushort ALU2 = 69; // internal
|
||||
public const ushort BUS = 70;
|
||||
public const ushort P1 = 71;
|
||||
public const ushort P2 = 72;
|
||||
public const ushort P4 = 73;
|
||||
|
|
|
@ -1,180 +0,0 @@
|
|||
using System;
|
||||
|
||||
using BizHawk.Common;
|
||||
using BizHawk.Common.BufferExtensions;
|
||||
using BizHawk.Emulation.Common;
|
||||
using BizHawk.Common.NumberExtensions;
|
||||
|
||||
namespace BizHawk.Emulation.Cores.Consoles.O2Hawk
|
||||
{
|
||||
// Audio Emulation (a 24 bit shift register plus a control register)
|
||||
public class Audio : ISoundProvider
|
||||
{
|
||||
public O2Hawk Core { get; set; }
|
||||
|
||||
private BlipBuffer _blip_C = new BlipBuffer(15000);
|
||||
|
||||
public byte sample;
|
||||
|
||||
public byte shift_0, shift_1, shift_2, aud_ctrl;
|
||||
|
||||
public uint master_audio_clock;
|
||||
|
||||
public int tick_cnt, output_bit;
|
||||
|
||||
public int latched_sample_C;
|
||||
|
||||
public byte ReadReg(int addr)
|
||||
{
|
||||
byte ret = 0;
|
||||
|
||||
switch (addr)
|
||||
{
|
||||
case 0xA7: ret = shift_0; break;
|
||||
case 0xA8: ret = shift_1; break;
|
||||
case 0xA9: ret = shift_2; break;
|
||||
case 0xAA: ret = aud_ctrl; break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
public void WriteReg(int addr, byte value)
|
||||
{
|
||||
switch (addr)
|
||||
{
|
||||
case 0xA7: shift_0 = value; break;
|
||||
case 0xA8: shift_1 = value; break;
|
||||
case 0xA9: shift_2 = value; break;
|
||||
case 0xAA: aud_ctrl = value; break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void tick()
|
||||
{
|
||||
int C_final = 0;
|
||||
|
||||
if (aud_ctrl.Bit(7))
|
||||
{
|
||||
tick_cnt++;
|
||||
if (tick_cnt > (aud_ctrl.Bit(5) ? 455 : 1820))
|
||||
{
|
||||
tick_cnt = 0;
|
||||
|
||||
output_bit = (shift_0 >> 1) & 1;
|
||||
|
||||
shift_0 = (byte)((shift_0 >> 1) | ((shift_1 & 1) << 3));
|
||||
shift_1 = (byte)((shift_1 >> 1) | ((shift_2 & 1) << 3));
|
||||
|
||||
if (aud_ctrl.Bit(6))
|
||||
{
|
||||
shift_2 = (byte)((shift_2 >> 1) | ((output_bit) << 3));
|
||||
}
|
||||
else
|
||||
{
|
||||
shift_0 = (byte)(shift_2 >> 1);
|
||||
}
|
||||
}
|
||||
|
||||
C_final = output_bit;
|
||||
C_final *= ((aud_ctrl & 0xF) + 1) * 40;
|
||||
}
|
||||
|
||||
if (C_final != latched_sample_C)
|
||||
{
|
||||
_blip_C.AddDelta(master_audio_clock, C_final - latched_sample_C);
|
||||
latched_sample_C = C_final;
|
||||
}
|
||||
|
||||
master_audio_clock++;
|
||||
}
|
||||
|
||||
public void power_off()
|
||||
{
|
||||
for (int i = 0; i < 0x16; i++)
|
||||
{
|
||||
WriteReg(0xFF10 + i, 0);
|
||||
}
|
||||
}
|
||||
|
||||
public void Reset()
|
||||
{
|
||||
master_audio_clock = 0;
|
||||
|
||||
sample = 0;
|
||||
|
||||
_blip_C.SetRates(4194304, 44100);
|
||||
}
|
||||
|
||||
public void SyncState(Serializer ser)
|
||||
{
|
||||
ser.Sync(nameof(master_audio_clock), ref master_audio_clock);
|
||||
|
||||
ser.Sync(nameof(sample), ref sample);
|
||||
ser.Sync(nameof(latched_sample_C), ref latched_sample_C);
|
||||
|
||||
ser.Sync(nameof(aud_ctrl), ref aud_ctrl);
|
||||
ser.Sync(nameof(shift_0), ref shift_0);
|
||||
ser.Sync(nameof(shift_1), ref shift_1);
|
||||
ser.Sync(nameof(shift_2), ref shift_2);
|
||||
ser.Sync(nameof(tick_cnt), ref tick_cnt);
|
||||
ser.Sync(nameof(output_bit), ref output_bit);
|
||||
}
|
||||
|
||||
#region audio
|
||||
|
||||
public bool CanProvideAsync => false;
|
||||
|
||||
public void SetSyncMode(SyncSoundMode mode)
|
||||
{
|
||||
if (mode != SyncSoundMode.Sync)
|
||||
{
|
||||
throw new InvalidOperationException("Only Sync mode is supported_");
|
||||
}
|
||||
}
|
||||
|
||||
public SyncSoundMode SyncMode => SyncSoundMode.Sync;
|
||||
|
||||
public void GetSamplesSync(out short[] samples, out int nsamp)
|
||||
{
|
||||
_blip_C.EndFrame(master_audio_clock);
|
||||
|
||||
nsamp = _blip_C.SamplesAvailable();
|
||||
|
||||
samples = new short[nsamp * 2];
|
||||
|
||||
if (nsamp != 0)
|
||||
{
|
||||
_blip_C.ReadSamples(samples, nsamp, false);
|
||||
}
|
||||
|
||||
master_audio_clock = 0;
|
||||
}
|
||||
|
||||
public void GetSamplesAsync(short[] samples)
|
||||
{
|
||||
throw new NotSupportedException("Async is not available");
|
||||
}
|
||||
|
||||
public void DiscardSamples()
|
||||
{
|
||||
_blip_C.Clear();
|
||||
master_audio_clock = 0;
|
||||
}
|
||||
|
||||
private void GetSamples(short[] samples)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public void DisposeSound()
|
||||
{
|
||||
_blip_C.Clear();
|
||||
_blip_C.Dispose();
|
||||
_blip_C = null;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
|
@ -80,10 +80,6 @@ namespace BizHawk.Emulation.Cores.Consoles.O2Hawk
|
|||
}
|
||||
if (ppu_en && !copy_en)
|
||||
{
|
||||
if ((addr_latch >= 0xA7) || (addr_latch <= 0xAA))
|
||||
{
|
||||
return audio.ReadReg(addr_latch);
|
||||
}
|
||||
return ppu.ReadReg(addr_latch);
|
||||
}
|
||||
|
||||
|
@ -134,14 +130,8 @@ namespace BizHawk.Emulation.Cores.Consoles.O2Hawk
|
|||
}
|
||||
if (ppu_en)
|
||||
{
|
||||
if ((addr_latch >= 0xA7) || (addr_latch <= 0xAA))
|
||||
{
|
||||
audio.WriteReg(addr_latch, value);
|
||||
}
|
||||
else
|
||||
{
|
||||
ppu.WriteReg(addr_latch, value);
|
||||
}
|
||||
ppu.WriteReg(addr_latch, value);
|
||||
//Console.WriteLine((addr_latch) + " " + value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -155,6 +145,8 @@ namespace BizHawk.Emulation.Cores.Consoles.O2Hawk
|
|||
kybrd_en = !value.Bit(2);
|
||||
cart_b1 = value.Bit(1);
|
||||
cart_b0 = value.Bit(0);
|
||||
|
||||
//Console.WriteLine("main ctrl: " + value + " " + ppu_en + " " + RAM_en);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
@ -52,10 +52,11 @@ namespace BizHawk.Emulation.Cores.Consoles.O2Hawk
|
|||
{
|
||||
for (int i = 0; i < 10000; i++)
|
||||
{
|
||||
audio.tick();
|
||||
ppu.tick();
|
||||
ppu.tick();
|
||||
ppu.DMA_tick();
|
||||
serialport.serial_transfer_tick();
|
||||
ppu.Audio_tick();
|
||||
cpu.ExecuteOne();
|
||||
|
||||
if (in_vblank && !in_vblank_old)
|
||||
|
@ -82,10 +83,11 @@ namespace BizHawk.Emulation.Cores.Consoles.O2Hawk
|
|||
|
||||
public void do_single_step()
|
||||
{
|
||||
audio.tick();
|
||||
ppu.tick();
|
||||
ppu.tick();
|
||||
ppu.DMA_tick();
|
||||
serialport.serial_transfer_tick();
|
||||
ppu.Audio_tick();
|
||||
cpu.ExecuteOne();
|
||||
}
|
||||
|
||||
|
@ -138,7 +140,7 @@ namespace BizHawk.Emulation.Cores.Consoles.O2Hawk
|
|||
|
||||
public void Dispose()
|
||||
{
|
||||
audio.DisposeSound();
|
||||
ppu.DisposeSound();
|
||||
}
|
||||
|
||||
#region Video provider
|
||||
|
|
|
@ -51,7 +51,6 @@ namespace BizHawk.Emulation.Cores.Consoles.O2Hawk
|
|||
mapper.SyncState(ser);
|
||||
ppu.SyncState(ser);
|
||||
serialport.SyncState(ser);
|
||||
audio.SyncState(ser);
|
||||
|
||||
ser.BeginSection("Odyssey2");
|
||||
ser.Sync(nameof(core), ref core, false);
|
||||
|
|
|
@ -35,7 +35,7 @@ namespace BizHawk.Emulation.Cores.Consoles.O2Hawk
|
|||
public byte[] cart_RAM;
|
||||
public bool has_bat;
|
||||
|
||||
private int _frame = 0;
|
||||
public int _frame = 0;
|
||||
|
||||
public MapperBase mapper;
|
||||
|
||||
|
@ -43,7 +43,6 @@ namespace BizHawk.Emulation.Cores.Consoles.O2Hawk
|
|||
|
||||
public I8048 cpu;
|
||||
public PPU ppu;
|
||||
public Audio audio;
|
||||
public SerialPort serialport;
|
||||
|
||||
[CoreConstructor("O2")]
|
||||
|
@ -62,7 +61,6 @@ namespace BizHawk.Emulation.Cores.Consoles.O2Hawk
|
|||
OnExecFetch = ExecFetch,
|
||||
};
|
||||
|
||||
audio = new Audio();
|
||||
serialport = new SerialPort();
|
||||
|
||||
CoreComm = comm;
|
||||
|
@ -92,12 +90,11 @@ namespace BizHawk.Emulation.Cores.Consoles.O2Hawk
|
|||
|
||||
_frameHz = 60;
|
||||
|
||||
audio.Core = this;
|
||||
ppu.Core = this;
|
||||
serialport.Core = this;
|
||||
|
||||
ser.Register<IVideoProvider>(this);
|
||||
ser.Register<ISoundProvider>(audio);
|
||||
ser.Register<ISoundProvider>(ppu);
|
||||
ServiceProvider = ser;
|
||||
|
||||
_settings = (O2Settings)settings ?? new O2Settings();
|
||||
|
@ -118,6 +115,11 @@ namespace BizHawk.Emulation.Cores.Consoles.O2Hawk
|
|||
{
|
||||
RAM[j] = (byte)j;
|
||||
}
|
||||
|
||||
for (int k = 0; k < 0x100; k++)
|
||||
{
|
||||
ppu.WriteReg(k, (byte)k);
|
||||
}
|
||||
}
|
||||
|
||||
public DisplayType Region => DisplayType.NTSC;
|
||||
|
@ -132,7 +134,6 @@ namespace BizHawk.Emulation.Cores.Consoles.O2Hawk
|
|||
RAM_Bank = 1; // RAM bank always starts as 1 (even writing zero still sets 1)
|
||||
|
||||
ppu.Reset();
|
||||
audio.Reset();
|
||||
serialport.Reset();
|
||||
|
||||
cpu.SetCallbacks(ReadMemory, PeekMemory, PeekMemory, WriteMemory);
|
||||
|
|
|
@ -1,9 +1,13 @@
|
|||
using System;
|
||||
using BizHawk.Common;
|
||||
using BizHawk.Common.NumberExtensions;
|
||||
using BizHawk.Common.BufferExtensions;
|
||||
using BizHawk.Emulation.Common;
|
||||
|
||||
|
||||
namespace BizHawk.Emulation.Cores.Consoles.O2Hawk
|
||||
{
|
||||
public class PPU
|
||||
public class PPU : ISoundProvider
|
||||
{
|
||||
public O2Hawk Core { get; set; }
|
||||
|
||||
|
@ -25,7 +29,7 @@ namespace BizHawk.Emulation.Cores.Consoles.O2Hawk
|
|||
public byte STAT;
|
||||
public byte scroll_y;
|
||||
public byte scroll_x;
|
||||
public byte LY;
|
||||
public int LY;
|
||||
public byte LY_actual;
|
||||
public byte LY_inc;
|
||||
public byte LYC;
|
||||
|
@ -39,6 +43,9 @@ namespace BizHawk.Emulation.Cores.Consoles.O2Hawk
|
|||
public int DMA_clock;
|
||||
public int DMA_inc;
|
||||
public byte DMA_byte;
|
||||
public int cycle;
|
||||
public bool VBL;
|
||||
public bool HBL;
|
||||
|
||||
public byte ReadReg(int addr)
|
||||
{
|
||||
|
@ -76,6 +83,10 @@ namespace BizHawk.Emulation.Cores.Consoles.O2Hawk
|
|||
{
|
||||
ret = VDC_color;
|
||||
}
|
||||
else if (addr <= 0xA7)
|
||||
{
|
||||
ret = AudioReadReg(addr);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@ -114,11 +125,47 @@ namespace BizHawk.Emulation.Cores.Consoles.O2Hawk
|
|||
{
|
||||
VDC_color = value;
|
||||
}
|
||||
else if (addr <= 0xA7)
|
||||
{
|
||||
AudioWriteReg(addr, value);
|
||||
}
|
||||
}
|
||||
|
||||
public void tick()
|
||||
{
|
||||
cycle++;
|
||||
|
||||
// drawing cycles
|
||||
if ((cycle >= 43) && !VBL)
|
||||
{
|
||||
if (cycle == 43)
|
||||
{
|
||||
HBL = false;
|
||||
// trigger timer tick if enabled
|
||||
if (Core.cpu.counter_en) { Core.cpu.T1 = false; }
|
||||
}
|
||||
}
|
||||
|
||||
// end of scanline
|
||||
if (cycle == 228)
|
||||
{
|
||||
cycle = 0;
|
||||
HBL = true;
|
||||
if (VDC_ctrl.Bit(0)) { Core.cpu.IRQPending = true;}
|
||||
|
||||
// trigger timer tick if enabled
|
||||
if (Core.cpu.counter_en) { Core.cpu.T1 = true; }
|
||||
|
||||
LY++;
|
||||
if (LY == 262)
|
||||
{
|
||||
LY = 0;
|
||||
HBL = false;
|
||||
VBL = true;
|
||||
}
|
||||
|
||||
if (LY == 22) { VBL = false; }
|
||||
}
|
||||
}
|
||||
|
||||
// might be needed, not sure yet
|
||||
|
@ -151,7 +198,7 @@ namespace BizHawk.Emulation.Cores.Consoles.O2Hawk
|
|||
|
||||
public void Reset()
|
||||
{
|
||||
|
||||
AudioReset();
|
||||
}
|
||||
|
||||
public static readonly byte[] Internal_Graphics = { 0x3C, 0x66, 0x66, 0x66, 0x66, 0x66, 0x3C, // 0 0x00
|
||||
|
@ -220,6 +267,7 @@ namespace BizHawk.Emulation.Cores.Consoles.O2Hawk
|
|||
0x00, 0x00, 0x00, 0x54, 0x54, 0xFF, 0x7E, // (boat 3 unk) 0x3F
|
||||
};
|
||||
|
||||
|
||||
public void SyncState(Serializer ser)
|
||||
{
|
||||
ser.Sync(nameof(Sprites), ref Sprites, false);
|
||||
|
@ -255,6 +303,168 @@ namespace BizHawk.Emulation.Cores.Consoles.O2Hawk
|
|||
ser.Sync(nameof(DMA_clock), ref DMA_clock);
|
||||
ser.Sync(nameof(DMA_inc), ref DMA_inc);
|
||||
ser.Sync(nameof(DMA_byte), ref DMA_byte);
|
||||
ser.Sync(nameof(cycle), ref cycle);
|
||||
ser.Sync(nameof(VBL), ref VBL);
|
||||
ser.Sync(nameof(HBL), ref HBL);
|
||||
|
||||
AudioSyncState(ser);
|
||||
}
|
||||
|
||||
private BlipBuffer _blip_C = new BlipBuffer(15000);
|
||||
|
||||
public byte sample;
|
||||
|
||||
public byte shift_0, shift_1, shift_2, aud_ctrl;
|
||||
|
||||
public uint master_audio_clock;
|
||||
|
||||
public int tick_cnt, output_bit;
|
||||
|
||||
public int latched_sample_C;
|
||||
|
||||
public byte AudioReadReg(int addr)
|
||||
{
|
||||
byte ret = 0;
|
||||
|
||||
switch (addr)
|
||||
{
|
||||
case 0xA7: ret = shift_0; break;
|
||||
case 0xA8: ret = shift_1; break;
|
||||
case 0xA9: ret = shift_2; break;
|
||||
case 0xAA: ret = aud_ctrl; break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
public void AudioWriteReg(int addr, byte value)
|
||||
{
|
||||
switch (addr)
|
||||
{
|
||||
case 0xA7: shift_0 = value; break;
|
||||
case 0xA8: shift_1 = value; break;
|
||||
case 0xA9: shift_2 = value; break;
|
||||
case 0xAA: aud_ctrl = value; break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void Audio_tick()
|
||||
{
|
||||
int C_final = 0;
|
||||
|
||||
if (aud_ctrl.Bit(7))
|
||||
{
|
||||
tick_cnt++;
|
||||
if (tick_cnt > (aud_ctrl.Bit(5) ? 455 : 1820))
|
||||
{
|
||||
tick_cnt = 0;
|
||||
|
||||
output_bit = (shift_0 >> 1) & 1;
|
||||
|
||||
shift_0 = (byte)((shift_0 >> 1) | ((shift_1 & 1) << 3));
|
||||
shift_1 = (byte)((shift_1 >> 1) | ((shift_2 & 1) << 3));
|
||||
|
||||
if (aud_ctrl.Bit(6))
|
||||
{
|
||||
shift_2 = (byte)((shift_2 >> 1) | ((output_bit) << 3));
|
||||
}
|
||||
else
|
||||
{
|
||||
shift_0 = (byte)(shift_2 >> 1);
|
||||
}
|
||||
}
|
||||
|
||||
C_final = output_bit;
|
||||
C_final *= ((aud_ctrl & 0xF) + 1) * 40;
|
||||
}
|
||||
|
||||
if (C_final != latched_sample_C)
|
||||
{
|
||||
_blip_C.AddDelta(master_audio_clock, C_final - latched_sample_C);
|
||||
latched_sample_C = C_final;
|
||||
}
|
||||
|
||||
master_audio_clock++;
|
||||
}
|
||||
|
||||
public void AudioReset()
|
||||
{
|
||||
master_audio_clock = 0;
|
||||
|
||||
sample = 0;
|
||||
|
||||
_blip_C.SetRates(4194304, 44100);
|
||||
}
|
||||
|
||||
public void AudioSyncState(Serializer ser)
|
||||
{
|
||||
ser.Sync(nameof(master_audio_clock), ref master_audio_clock);
|
||||
|
||||
ser.Sync(nameof(sample), ref sample);
|
||||
ser.Sync(nameof(latched_sample_C), ref latched_sample_C);
|
||||
|
||||
ser.Sync(nameof(aud_ctrl), ref aud_ctrl);
|
||||
ser.Sync(nameof(shift_0), ref shift_0);
|
||||
ser.Sync(nameof(shift_1), ref shift_1);
|
||||
ser.Sync(nameof(shift_2), ref shift_2);
|
||||
ser.Sync(nameof(tick_cnt), ref tick_cnt);
|
||||
ser.Sync(nameof(output_bit), ref output_bit);
|
||||
}
|
||||
|
||||
#region audio
|
||||
|
||||
public bool CanProvideAsync => false;
|
||||
|
||||
public void SetSyncMode(SyncSoundMode mode)
|
||||
{
|
||||
if (mode != SyncSoundMode.Sync)
|
||||
{
|
||||
throw new InvalidOperationException("Only Sync mode is supported_");
|
||||
}
|
||||
}
|
||||
|
||||
public SyncSoundMode SyncMode => SyncSoundMode.Sync;
|
||||
|
||||
public void GetSamplesSync(out short[] samples, out int nsamp)
|
||||
{
|
||||
_blip_C.EndFrame(master_audio_clock);
|
||||
|
||||
nsamp = _blip_C.SamplesAvailable();
|
||||
|
||||
samples = new short[nsamp * 2];
|
||||
|
||||
if (nsamp != 0)
|
||||
{
|
||||
_blip_C.ReadSamples(samples, nsamp, false);
|
||||
}
|
||||
|
||||
master_audio_clock = 0;
|
||||
}
|
||||
|
||||
public void GetSamplesAsync(short[] samples)
|
||||
{
|
||||
throw new NotSupportedException("Async is not available");
|
||||
}
|
||||
|
||||
public void DiscardSamples()
|
||||
{
|
||||
_blip_C.Clear();
|
||||
master_audio_clock = 0;
|
||||
}
|
||||
|
||||
private void GetSamples(short[] samples)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public void DisposeSound()
|
||||
{
|
||||
_blip_C.Clear();
|
||||
_blip_C.Dispose();
|
||||
_blip_C = null;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue