diff --git a/BizHawk.Emulation.Cores/BizHawk.Emulation.Cores.csproj b/BizHawk.Emulation.Cores/BizHawk.Emulation.Cores.csproj
index b12cbd8090..164627f03a 100644
--- a/BizHawk.Emulation.Cores/BizHawk.Emulation.Cores.csproj
+++ b/BizHawk.Emulation.Cores/BizHawk.Emulation.Cores.csproj
@@ -709,7 +709,6 @@
-
diff --git a/BizHawk.Emulation.Cores/CPUs/Intel8048/Execute.cs b/BizHawk.Emulation.Cores/CPUs/Intel8048/Execute.cs
index 340c3c5a71..512addb1e1 100644
--- a/BizHawk.Emulation.Cores/CPUs/Intel8048/Execute.cs
+++ b/BizHawk.Emulation.Cores/CPUs/Intel8048/Execute.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
diff --git a/BizHawk.Emulation.Cores/CPUs/Intel8048/I8048.cs b/BizHawk.Emulation.Cores/CPUs/Intel8048/I8048.cs
index 61691764bb..6af3e975f3 100644
--- a/BizHawk.Emulation.Cores/CPUs/Intel8048/I8048.cs
+++ b/BizHawk.Emulation.Cores/CPUs/Intel8048/I8048.cs
@@ -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",
diff --git a/BizHawk.Emulation.Cores/CPUs/Intel8048/Interrupts.cs b/BizHawk.Emulation.Cores/CPUs/Intel8048/Interrupts.cs
index f346b0ccad..fe10cf9cea 100644
--- a/BizHawk.Emulation.Cores/CPUs/Intel8048/Interrupts.cs
+++ b/BizHawk.Emulation.Cores/CPUs/Intel8048/Interrupts.cs
@@ -26,7 +26,8 @@ namespace BizHawk.Emulation.Common.Components.I8048
private void ResetInterrupts()
{
- IntEn = true;
+ IntEn = false;
+ TimIntEn = false;
}
}
}
\ No newline at end of file
diff --git a/BizHawk.Emulation.Cores/CPUs/Intel8048/OP_Tables.cs b/BizHawk.Emulation.Cores/CPUs/Intel8048/OP_Tables.cs
index ce84b8efe8..d5fd15ed0f 100644
--- a/BizHawk.Emulation.Cores/CPUs/Intel8048/OP_Tables.cs
+++ b/BizHawk.Emulation.Cores/CPUs/Intel8048/OP_Tables.cs
@@ -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;
}
diff --git a/BizHawk.Emulation.Cores/CPUs/Intel8048/Registers.cs b/BizHawk.Emulation.Cores/CPUs/Intel8048/Registers.cs
index fea2ad0fb9..a2038ba039 100644
--- a/BizHawk.Emulation.Cores/CPUs/Intel8048/Registers.cs
+++ b/BizHawk.Emulation.Cores/CPUs/Intel8048/Registers.cs
@@ -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;
diff --git a/BizHawk.Emulation.Cores/Consoles/Magnavox/Odyssey2/Audio.cs b/BizHawk.Emulation.Cores/Consoles/Magnavox/Odyssey2/Audio.cs
deleted file mode 100644
index b2edc7104c..0000000000
--- a/BizHawk.Emulation.Cores/Consoles/Magnavox/Odyssey2/Audio.cs
+++ /dev/null
@@ -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
- }
-}
\ No newline at end of file
diff --git a/BizHawk.Emulation.Cores/Consoles/Magnavox/Odyssey2/MemoryMap.cs b/BizHawk.Emulation.Cores/Consoles/Magnavox/Odyssey2/MemoryMap.cs
index 6921955868..161f17cf7b 100644
--- a/BizHawk.Emulation.Cores/Consoles/Magnavox/Odyssey2/MemoryMap.cs
+++ b/BizHawk.Emulation.Cores/Consoles/Magnavox/Odyssey2/MemoryMap.cs
@@ -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
{
diff --git a/BizHawk.Emulation.Cores/Consoles/Magnavox/Odyssey2/O2Hawk.IEmulator.cs b/BizHawk.Emulation.Cores/Consoles/Magnavox/Odyssey2/O2Hawk.IEmulator.cs
index 9dc8cb7f31..ebea0ab315 100644
--- a/BizHawk.Emulation.Cores/Consoles/Magnavox/Odyssey2/O2Hawk.IEmulator.cs
+++ b/BizHawk.Emulation.Cores/Consoles/Magnavox/Odyssey2/O2Hawk.IEmulator.cs
@@ -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
diff --git a/BizHawk.Emulation.Cores/Consoles/Magnavox/Odyssey2/O2Hawk.IStatable.cs b/BizHawk.Emulation.Cores/Consoles/Magnavox/Odyssey2/O2Hawk.IStatable.cs
index 3030adff46..ff886bc27e 100644
--- a/BizHawk.Emulation.Cores/Consoles/Magnavox/Odyssey2/O2Hawk.IStatable.cs
+++ b/BizHawk.Emulation.Cores/Consoles/Magnavox/Odyssey2/O2Hawk.IStatable.cs
@@ -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);
diff --git a/BizHawk.Emulation.Cores/Consoles/Magnavox/Odyssey2/O2Hawk.cs b/BizHawk.Emulation.Cores/Consoles/Magnavox/Odyssey2/O2Hawk.cs
index 3db97d260d..f76f4872f2 100644
--- a/BizHawk.Emulation.Cores/Consoles/Magnavox/Odyssey2/O2Hawk.cs
+++ b/BizHawk.Emulation.Cores/Consoles/Magnavox/Odyssey2/O2Hawk.cs
@@ -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(this);
- ser.Register(audio);
+ ser.Register(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);
diff --git a/BizHawk.Emulation.Cores/Consoles/Magnavox/Odyssey2/PPU.cs b/BizHawk.Emulation.Cores/Consoles/Magnavox/Odyssey2/PPU.cs
index 8589d23246..7471900a39 100644
--- a/BizHawk.Emulation.Cores/Consoles/Magnavox/Odyssey2/PPU.cs
+++ b/BizHawk.Emulation.Cores/Consoles/Magnavox/Odyssey2/PPU.cs
@@ -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
}
}