[ChannelF] Cleanup + optimize some code
This commit is contained in:
parent
314f32b95f
commit
84f4d6ae28
|
@ -8,7 +8,7 @@ namespace BizHawk.Emulation.Cores.Components.FairchildF8
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Disassembler
|
/// Disassembler
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public sealed partial class F3850 : IDisassemblable
|
public sealed partial class F3850<TLink> : IDisassemblable
|
||||||
{
|
{
|
||||||
private static string Result(string format, Func<ushort, byte> read, ref ushort addr)
|
private static string Result(string format, Func<ushort, byte> read, ref ushort addr)
|
||||||
{
|
{
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
namespace BizHawk.Emulation.Cores.Components.FairchildF8
|
namespace BizHawk.Emulation.Cores.Components.FairchildF8
|
||||||
{
|
{
|
||||||
public sealed partial class F3850
|
public sealed partial class F3850<TLink>
|
||||||
{
|
{
|
||||||
public const int MaxInstructionLength = 48;
|
public const int MaxInstructionLength = 48;
|
||||||
|
|
||||||
|
|
|
@ -5,21 +5,21 @@ namespace BizHawk.Emulation.Cores.Components.FairchildF8
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// ALU Operations
|
/// ALU Operations
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public sealed partial class F3850
|
public sealed partial class F3850<TLink>
|
||||||
{
|
{
|
||||||
public void Read_Func(byte dest, byte src_l, byte src_h)
|
public void Read_Func(byte dest, byte src_l, byte src_h)
|
||||||
{
|
{
|
||||||
Regs[dest] = ReadMemory((ushort)(Regs[src_l] | (Regs[src_h]) << 8));
|
Regs[dest] = _link.ReadMemory((ushort)(Regs[src_l] | (Regs[src_h]) << 8));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Write_Func(byte dest_l, byte dest_h, byte src)
|
public void Write_Func(byte dest_l, byte dest_h, byte src)
|
||||||
{
|
{
|
||||||
WriteMemory((ushort)(Regs[dest_l] | (Regs[dest_h] << 8)), Regs[src]);
|
_link.WriteMemory((ushort)(Regs[dest_l] | (Regs[dest_h] << 8)), Regs[src]);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void IN_Func(byte dest, byte src)
|
public void IN_Func(byte dest, byte src)
|
||||||
{
|
{
|
||||||
Regs[dest] = ReadHardware(Regs[src]);
|
Regs[dest] = _link.ReadHardware(Regs[src]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -48,7 +48,7 @@ namespace BizHawk.Emulation.Cores.Components.FairchildF8
|
||||||
{
|
{
|
||||||
// data is complemented between accumulator and I/O pins (because PINs are active-low)
|
// data is complemented between accumulator and I/O pins (because PINs are active-low)
|
||||||
// however for ease here we will make them active-high
|
// however for ease here we will make them active-high
|
||||||
WriteHardware(Regs[dest], Regs[src]);
|
_link.WriteHardware(Regs[dest], Regs[src]);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void ClearFlags_Func()
|
public void ClearFlags_Func()
|
||||||
|
|
|
@ -7,7 +7,7 @@ namespace BizHawk.Emulation.Cores.Components.FairchildF8
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Internal Registers
|
/// Internal Registers
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public sealed partial class F3850
|
public sealed partial class F3850<TLink>
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Registers (counters and scratchpad)
|
/// Registers (counters and scratchpad)
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Vectors of Instruction Operations
|
/// Vectors of Instruction Operations
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public sealed partial class F3850
|
public sealed partial class F3850<TLink>
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// LR - LOAD REGISTER
|
/// LR - LOAD REGISTER
|
||||||
|
|
|
@ -29,7 +29,7 @@ namespace BizHawk.Emulation.Cores.Components.FairchildF8
|
||||||
///
|
///
|
||||||
/// Note: Programmable timer and interrupt logic from the F3851 is not currently emulated
|
/// Note: Programmable timer and interrupt logic from the F3851 is not currently emulated
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public sealed partial class F3850
|
public sealed partial class F3850<TLink> where TLink : IF3850Link
|
||||||
{
|
{
|
||||||
// operations that can take place in an instruction
|
// operations that can take place in an instruction
|
||||||
public const byte ROMC_01 = 1;
|
public const byte ROMC_01 = 1;
|
||||||
|
@ -100,8 +100,11 @@ namespace BizHawk.Emulation.Cores.Components.FairchildF8
|
||||||
public const byte OP_DS = 157;
|
public const byte OP_DS = 157;
|
||||||
public const byte OP_LIS = 158;
|
public const byte OP_LIS = 158;
|
||||||
|
|
||||||
public F3850()
|
private readonly TLink _link;
|
||||||
|
|
||||||
|
public F3850(TLink link)
|
||||||
{
|
{
|
||||||
|
_link = link;
|
||||||
Reset();
|
Reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -133,36 +136,6 @@ namespace BizHawk.Emulation.Cores.Components.FairchildF8
|
||||||
|
|
||||||
public IMemoryCallbackSystem MemoryCallbacks { get; set; }
|
public IMemoryCallbackSystem MemoryCallbacks { get; set; }
|
||||||
|
|
||||||
// Memory Access
|
|
||||||
public Func<ushort, byte> ReadMemory;
|
|
||||||
public Action<ushort, byte> WriteMemory;
|
|
||||||
public Func<ushort, byte> PeekMemory;
|
|
||||||
public Func<ushort, byte> DummyReadMemory;
|
|
||||||
|
|
||||||
// Hardware I/O Port Access
|
|
||||||
public Func<ushort, byte> ReadHardware;
|
|
||||||
public Action<ushort, byte> WriteHardware;
|
|
||||||
|
|
||||||
public Action<ushort> OnExecFetch;
|
|
||||||
|
|
||||||
public void SetCallbacks
|
|
||||||
(
|
|
||||||
Func<ushort, byte> ReadMemory,
|
|
||||||
Func<ushort, byte> DummyReadMemory,
|
|
||||||
Func<ushort, byte> PeekMemory,
|
|
||||||
Action<ushort, byte> WriteMemory,
|
|
||||||
Func<ushort, byte> ReadHardware,
|
|
||||||
Action<ushort, byte> WriteHardware
|
|
||||||
)
|
|
||||||
{
|
|
||||||
this.ReadMemory = ReadMemory;
|
|
||||||
this.DummyReadMemory = DummyReadMemory;
|
|
||||||
this.PeekMemory = PeekMemory;
|
|
||||||
this.WriteMemory = WriteMemory;
|
|
||||||
this.ReadHardware = ReadHardware;
|
|
||||||
this.WriteHardware = WriteHardware;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Runs a single CPU clock cycle
|
/// Runs a single CPU clock cycle
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -180,7 +153,7 @@ namespace BizHawk.Emulation.Cores.Components.FairchildF8
|
||||||
{
|
{
|
||||||
// always the last tick within an opcode instruction cycle
|
// always the last tick within an opcode instruction cycle
|
||||||
case END:
|
case END:
|
||||||
OnExecFetch?.Invoke(RegPC0);
|
_link.OnExecFetch(RegPC0);
|
||||||
TraceCallback?.Invoke(State());
|
TraceCallback?.Invoke(State());
|
||||||
opcode = Regs[DB];
|
opcode = Regs[DB];
|
||||||
instr_pntr = 0;
|
instr_pntr = 0;
|
||||||
|
@ -785,12 +758,12 @@ namespace BizHawk.Emulation.Cores.Components.FairchildF8
|
||||||
{
|
{
|
||||||
int bytes_read = 0;
|
int bytes_read = 0;
|
||||||
ushort pc = (ushort)(RegPC0 - 1);
|
ushort pc = (ushort)(RegPC0 - 1);
|
||||||
string disasm = disassemble ? Disassemble(pc, ReadMemory, out bytes_read) : "---";
|
string disasm = disassemble ? Disassemble(pc, _link.ReadMemory, out bytes_read) : "---";
|
||||||
string byte_code = null;
|
string byte_code = null;
|
||||||
|
|
||||||
for (ushort i = 0; i < bytes_read; i++)
|
for (ushort i = 0; i < bytes_read; i++)
|
||||||
{
|
{
|
||||||
byte_code += ReadMemory((ushort)(pc + i)).ToString("X2");
|
byte_code += _link.ReadMemory((ushort)(pc + i)).ToString("X2");
|
||||||
if (i < (bytes_read - 1))
|
if (i < (bytes_read - 1))
|
||||||
{
|
{
|
||||||
byte_code += " ";
|
byte_code += " ";
|
||||||
|
@ -868,7 +841,7 @@ namespace BizHawk.Emulation.Cores.Components.FairchildF8
|
||||||
|
|
||||||
public void SyncState(Serializer ser)
|
public void SyncState(Serializer ser)
|
||||||
{
|
{
|
||||||
ser.BeginSection(nameof(F3850));
|
ser.BeginSection("F3850");
|
||||||
ser.Sync(nameof(Regs), ref Regs, false);
|
ser.Sync(nameof(Regs), ref Regs, false);
|
||||||
ser.Sync(nameof(cur_instr), ref cur_instr, false);
|
ser.Sync(nameof(cur_instr), ref cur_instr, false);
|
||||||
ser.Sync(nameof(instr_pntr), ref instr_pntr);
|
ser.Sync(nameof(instr_pntr), ref instr_pntr);
|
||||||
|
|
|
@ -0,0 +1,19 @@
|
||||||
|
namespace BizHawk.Emulation.Cores.Components.FairchildF8
|
||||||
|
{
|
||||||
|
// Interface that has all the methods required by the F3850 to talk to
|
||||||
|
// the emulator core.
|
||||||
|
// Should only be used as a generic type argument for the F3850, and
|
||||||
|
// implementations should be structs where possible. This combination allows
|
||||||
|
// the JITer to generate much faster code than calling a Func<> or Action<>.
|
||||||
|
public interface IF3850Link
|
||||||
|
{
|
||||||
|
byte ReadMemory(ushort address);
|
||||||
|
void WriteMemory(ushort address, byte value);
|
||||||
|
|
||||||
|
byte ReadHardware(ushort address);
|
||||||
|
void WriteHardware(ushort address, byte value);
|
||||||
|
|
||||||
|
// This only calls when the first byte of an instruction is fetched.
|
||||||
|
void OnExecFetch(ushort address);
|
||||||
|
}
|
||||||
|
}
|
|
@ -2,36 +2,29 @@
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Hangman ChannelF Cartridge
|
/// Hangman ChannelF Cartridge
|
||||||
/// 2KB ROM / NO RAM
|
/// Utilises 2102 SRAM over IO
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class mapper_HANG : VesCartBase
|
public class MapperHANG : VesCartBase
|
||||||
{
|
{
|
||||||
public override string BoardType => "HANG";
|
public override string BoardType => "HANG";
|
||||||
|
|
||||||
public mapper_HANG(byte[] rom)
|
public MapperHANG(byte[] rom)
|
||||||
{
|
{
|
||||||
ROM = new byte[0x10000 - 0x800];
|
_rom = new byte[0x10000 - 0x800];
|
||||||
for (int i = 0; i < rom.Length; i++)
|
Array.Copy(rom, _rom, rom.Length);
|
||||||
{
|
_rom.AsSpan(rom.Length).Fill(0xFF);
|
||||||
ROM[i] = rom[i];
|
_ram = new byte[0x400];
|
||||||
if (i > 3000)
|
|
||||||
{
|
|
||||||
var test = rom[i];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
RAM = new byte[0x400];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public override byte ReadBus(ushort addr)
|
public override byte ReadBus(ushort addr)
|
||||||
{
|
{
|
||||||
var off = addr - 0x800;
|
var off = addr - 0x800;
|
||||||
return ROM[off];
|
return _rom[off];
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void WriteBus(ushort addr, byte value)
|
public override void WriteBus(ushort addr, byte value)
|
||||||
{
|
{
|
||||||
// no writeable memory
|
// no directly writeable memory
|
||||||
}
|
}
|
||||||
|
|
||||||
public override byte ReadPort(ushort addr)
|
public override byte ReadPort(ushort addr)
|
||||||
|
@ -45,6 +38,5 @@
|
||||||
var index = addr - 0x20;
|
var index = addr - 0x20;
|
||||||
SRAM2102_Write(index, data);
|
SRAM2102_Write(index, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,27 +1,25 @@
|
||||||
namespace BizHawk.Emulation.Cores.Consoles.ChannelF
|
namespace BizHawk.Emulation.Cores.Consoles.ChannelF
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// ChannelF Cartridge that utilises 2102 SRAM over IO
|
/// Maze ChannelF Cartridge
|
||||||
|
/// Utilises 2102 SRAM over IO
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class mapper_MAZE : VesCartBase
|
public class MapperMAZE : VesCartBase
|
||||||
{
|
{
|
||||||
public override string BoardType => "MAZE";
|
public override string BoardType => "MAZE";
|
||||||
|
|
||||||
public mapper_MAZE(byte[] rom)
|
public MapperMAZE(byte[] rom)
|
||||||
{
|
{
|
||||||
ROM = new byte[0x10000 - 0x800];
|
_rom = new byte[0x10000 - 0x800];
|
||||||
for (int i = 0; i < rom.Length; i++)
|
Array.Copy(rom, _rom, rom.Length);
|
||||||
{
|
_rom.AsSpan(rom.Length).Fill(0xFF);
|
||||||
ROM[i] = rom[i];
|
_ram = new byte[0x400];
|
||||||
}
|
|
||||||
|
|
||||||
RAM = new byte[0x400];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public override byte ReadBus(ushort addr)
|
public override byte ReadBus(ushort addr)
|
||||||
{
|
{
|
||||||
var off = addr - 0x800;
|
var off = addr - 0x800;
|
||||||
return ROM[off];
|
return _rom[off];
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void WriteBus(ushort addr, byte value)
|
public override void WriteBus(ushort addr, byte value)
|
|
@ -3,19 +3,15 @@
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Sean Riddle's modified SCHACH cart mapper (multi-cart) (WIP)
|
/// Sean Riddle's modified SCHACH cart mapper (multi-cart) (WIP)
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class mapper_RIDDLE : VesCartBase
|
public class MapperRIDDLE : VesCartBase
|
||||||
{
|
{
|
||||||
public override string BoardType => "RIDDLE";
|
public override string BoardType => "RIDDLE";
|
||||||
|
|
||||||
public mapper_RIDDLE(byte[] rom)
|
public MapperRIDDLE(byte[] rom)
|
||||||
{
|
{
|
||||||
ROM = new byte[rom.Length];
|
_rom = new byte[rom.Length];
|
||||||
for (int i = 0; i < rom.Length; i++)
|
Array.Copy(rom, _rom, rom.Length);
|
||||||
{
|
_ram = new byte[0x800];
|
||||||
ROM[i] = rom[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
RAM = new byte[0x800];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public override byte ReadBus(ushort addr)
|
public override byte ReadBus(ushort addr)
|
||||||
|
@ -23,15 +19,15 @@
|
||||||
var result = 0xFF;
|
var result = 0xFF;
|
||||||
var off = addr - 0x800;
|
var off = addr - 0x800;
|
||||||
|
|
||||||
if (addr >= 0x2800 && addr < 0x3000)
|
if (addr is >= 0x2800 and < 0x3000)
|
||||||
{
|
{
|
||||||
// 2KB RAM
|
// 2KB RAM
|
||||||
result = RAM[addr - 0x2800];
|
result = _ram[addr - 0x2800];
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (off < ROM.Length)
|
if (off < _rom.Length)
|
||||||
result = ROM[off + (MultiBank * 0x2000) + (MultiHalfBank * 0x1000)];
|
result = _rom[off + (MultiBank * 0x2000) + (MultiHalfBank * 0x1000)];
|
||||||
}
|
}
|
||||||
|
|
||||||
return (byte)result;
|
return (byte)result;
|
||||||
|
@ -40,9 +36,9 @@
|
||||||
public override void WriteBus(ushort addr, byte value)
|
public override void WriteBus(ushort addr, byte value)
|
||||||
{
|
{
|
||||||
// 2KB writeable memory at 0x2800;
|
// 2KB writeable memory at 0x2800;
|
||||||
if (addr >= 0x2800 && addr < 0x3000)
|
if (addr is >= 0x2800 and < 0x3000)
|
||||||
{
|
{
|
||||||
RAM[addr - 0x2800] = value;
|
_ram[addr - 0x2800] = value;
|
||||||
}
|
}
|
||||||
else if (addr == 0x3000)
|
else if (addr == 0x3000)
|
||||||
{
|
{
|
||||||
|
@ -50,16 +46,10 @@
|
||||||
MultiBank = value & 0x1F;
|
MultiBank = value & 0x1F;
|
||||||
MultiHalfBank = (value & 0x20) >> 5;
|
MultiHalfBank = (value & 0x20) >> 5;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public override byte ReadPort(ushort addr)
|
public override byte ReadPort(ushort addr)
|
||||||
{
|
=> 0xFF;
|
||||||
return 0xFF;
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void WritePort(ushort addr, byte data)
|
public override void WritePort(ushort addr, byte data)
|
||||||
{
|
{
|
|
@ -5,48 +5,42 @@
|
||||||
/// Any size ROM / 2KB RAM mapped at 0x2800 - 0x2FFF
|
/// Any size ROM / 2KB RAM mapped at 0x2800 - 0x2FFF
|
||||||
/// Info here: http://www.seanriddle.com/chanfmulti.html
|
/// Info here: http://www.seanriddle.com/chanfmulti.html
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class mapper_SCHACH : VesCartBase
|
public class MapperSCHACH : VesCartBase
|
||||||
{
|
{
|
||||||
public override string BoardType => "SCHACH";
|
public override string BoardType => "SCHACH";
|
||||||
public override bool HasActivityLED => true;
|
public override bool HasActivityLED => true;
|
||||||
public override string ActivityLEDDescription => "Chess Brain Thinking Activity";
|
public override string ActivityLEDDescription => "Chess Brain Thinking Activity";
|
||||||
|
|
||||||
public mapper_SCHACH(byte[] rom)
|
public MapperSCHACH(byte[] rom)
|
||||||
{
|
{
|
||||||
ROM = new byte[0x10000 - 0x800];
|
_rom = new byte[0x10000 - 0x800];
|
||||||
for (int i = 0; i < rom.Length; i++)
|
Array.Copy(rom, _rom, rom.Length);
|
||||||
{
|
_rom.AsSpan(rom.Length).Fill(0xFF);
|
||||||
ROM[i] = rom[i];
|
_ram = new byte[0x800];
|
||||||
}
|
|
||||||
|
|
||||||
RAM = new byte[0x800];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public override byte ReadBus(ushort addr)
|
public override byte ReadBus(ushort addr)
|
||||||
{
|
{
|
||||||
var result = 0xFF;
|
byte result;
|
||||||
var off = addr - 0x800;
|
if (addr is >= 0x2800 and < 0x3000)
|
||||||
|
|
||||||
if (addr >= 0x2800 && addr < 0x3000)
|
|
||||||
{
|
{
|
||||||
// 2KB RAM
|
// 2KB RAM
|
||||||
result = RAM[addr - 0x2800];
|
result = _ram[addr - 0x2800];
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (off < ROM.Length)
|
result = _rom[addr - 0x800];
|
||||||
result = ROM[off];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return (byte)result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void WriteBus(ushort addr, byte value)
|
public override void WriteBus(ushort addr, byte value)
|
||||||
{
|
{
|
||||||
// 2KB writeable memory at 0x2800;
|
// 2KB writeable memory at 0x2800;
|
||||||
if (addr >= 0x2800 && addr < 0x3000)
|
if (addr is >= 0x2800 and < 0x3000)
|
||||||
{
|
{
|
||||||
RAM[addr - 0x2800] = value;
|
_ram[addr - 0x2800] = value;
|
||||||
}
|
}
|
||||||
else if (addr == 0x3800)
|
else if (addr == 0x3800)
|
||||||
{
|
{
|
||||||
|
@ -59,9 +53,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
public override byte ReadPort(ushort addr)
|
public override byte ReadPort(ushort addr)
|
||||||
{
|
=> 0xFF;
|
||||||
return 0xFF;
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void WritePort(ushort addr, byte data)
|
public override void WritePort(ushort addr, byte data)
|
||||||
{
|
{
|
|
@ -4,28 +4,22 @@
|
||||||
/// Standard ChannelF Cartridge
|
/// Standard ChannelF Cartridge
|
||||||
/// 2KB ROM / NO RAM
|
/// 2KB ROM / NO RAM
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class mapper_STD : VesCartBase
|
public class MapperSTD : VesCartBase
|
||||||
{
|
{
|
||||||
public override string BoardType => "STD";
|
public override string BoardType => "STD";
|
||||||
|
|
||||||
public mapper_STD(byte[] rom)
|
public MapperSTD(byte[] rom)
|
||||||
{
|
{
|
||||||
ROM = new byte[0x10000 - 0x800];
|
_rom = new byte[0x10000 - 0x800];
|
||||||
for (int i = 0; i < rom.Length; i++)
|
Array.Copy(rom, _rom, rom.Length);
|
||||||
{
|
_rom.AsSpan(rom.Length).Fill(0xFF);
|
||||||
ROM[i] = rom[i];
|
_ram = [ ];
|
||||||
}
|
|
||||||
|
|
||||||
RAM = new byte[0];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public override byte ReadBus(ushort addr)
|
public override byte ReadBus(ushort addr)
|
||||||
{
|
{
|
||||||
var off = addr - 0x800;
|
var off = addr - 0x800;
|
||||||
if (off < ROM.Length)
|
return _rom[off];
|
||||||
return ROM[off];
|
|
||||||
else
|
|
||||||
return 0xFF;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void WriteBus(ushort addr, byte value)
|
public override void WriteBus(ushort addr, byte value)
|
||||||
|
@ -34,9 +28,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
public override byte ReadPort(ushort addr)
|
public override byte ReadPort(ushort addr)
|
||||||
{
|
=> 0xFF;
|
||||||
return 0xFF;
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void WritePort(ushort addr, byte data)
|
public override void WritePort(ushort addr, byte data)
|
||||||
{
|
{
|
|
@ -19,24 +19,12 @@ namespace BizHawk.Emulation.Cores.Consoles.ChannelF
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public virtual byte[] ROM
|
|
||||||
{
|
|
||||||
get { return _rom; }
|
|
||||||
protected set { _rom = value; }
|
|
||||||
}
|
|
||||||
protected byte[] _rom;
|
protected byte[] _rom;
|
||||||
|
|
||||||
public virtual byte[] RAM
|
|
||||||
{
|
|
||||||
get { return _ram; }
|
|
||||||
protected set { _ram = value; }
|
|
||||||
}
|
|
||||||
protected byte[] _ram;
|
protected byte[] _ram;
|
||||||
|
|
||||||
public virtual bool HasActivityLED { get; set; }
|
public virtual bool HasActivityLED { get; set; }
|
||||||
public virtual string ActivityLEDDescription { get; set; }
|
public virtual string ActivityLEDDescription { get; set; }
|
||||||
|
|
||||||
|
|
||||||
public bool ActivityLED;
|
public bool ActivityLED;
|
||||||
public int MultiBank;
|
public int MultiBank;
|
||||||
public int MultiHalfBank;
|
public int MultiHalfBank;
|
||||||
|
@ -58,38 +46,36 @@ namespace BizHawk.Emulation.Cores.Consoles.ChannelF
|
||||||
public static VesCartBase Configure(GameInfo gi, byte[] rom)
|
public static VesCartBase Configure(GameInfo gi, byte[] rom)
|
||||||
{
|
{
|
||||||
// get board type
|
// get board type
|
||||||
string boardStr = gi.OptionPresent("board") ? gi.GetStringValue("board") : "STD";
|
var boardStr = gi.OptionPresent("board") ? gi.GetStringValue("board") : "STD";
|
||||||
|
|
||||||
switch (boardStr)
|
switch (boardStr)
|
||||||
{
|
{
|
||||||
// The supplied ROM is actually a BIOS
|
// The supplied ROM is actually a BIOS
|
||||||
case "BIOS":
|
case "BIOS":
|
||||||
// we can just pass the rom into channel f and because it does not detect a 0x55 at rom[0] it will just jump straight to onboard games
|
// we can just pass the rom into channel f and because it does not detect a 0x55 at rom[0] it will just jump straight to onboard games
|
||||||
// (hockey and tennis)
|
// (hockey and tennis)
|
||||||
return new mapper_STD(rom);
|
return new MapperSTD(rom);
|
||||||
|
|
||||||
// standard cart layout
|
// standard cart layout
|
||||||
case "STD":
|
case "STD":
|
||||||
// any number of F3851 Program Storage Units (1KB ROM each) or F3856 Program Storage Unit (2KB ROM)
|
// any number of F3851 Program Storage Units (1KB ROM each) or F3856 Program Storage Unit (2KB ROM)
|
||||||
// no on-pcb RAM and no extra IO
|
// no on-pcb RAM and no extra IO
|
||||||
return new mapper_STD(rom);
|
return new MapperSTD(rom);
|
||||||
|
|
||||||
case "MAZE":
|
case "MAZE":
|
||||||
return new mapper_MAZE(rom);
|
return new MapperMAZE(rom);
|
||||||
|
|
||||||
case "RIDDLE":
|
case "RIDDLE":
|
||||||
// Sean Riddle's modified SCHACH multi-cart
|
// Sean Riddle's modified SCHACH multi-cart
|
||||||
return new mapper_RIDDLE(rom);
|
return new MapperRIDDLE(rom);
|
||||||
|
|
||||||
case "SCHACH":
|
case "SCHACH":
|
||||||
default:
|
default:
|
||||||
// F3853 Memory Interface Chip, 6KB of ROM and 2KB of RAM
|
// F3853 Memory Interface Chip, 6KB of ROM and 2KB of RAM
|
||||||
// - default to this
|
// - default to this
|
||||||
return new mapper_SCHACH(rom);
|
return new MapperSCHACH(rom);
|
||||||
|
|
||||||
case "HANG":
|
case "HANG":
|
||||||
|
return new MapperHANG(rom);
|
||||||
return new mapper_HANG(rom);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -106,7 +92,7 @@ namespace BizHawk.Emulation.Cores.Consoles.ChannelF
|
||||||
if (m_read_write == 0)
|
if (m_read_write == 0)
|
||||||
{
|
{
|
||||||
m_addr = m_addr_latch;
|
m_addr = m_addr_latch;
|
||||||
m_data0 = RAM[m_addr] & 1;
|
m_data0 = _ram[m_addr] & 1;
|
||||||
return (byte)((m_latch[0] & 0x7f) | (m_data0 << 7));
|
return (byte)((m_latch[0] & 0x7f) | (m_data0 << 7));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -141,7 +127,7 @@ namespace BizHawk.Emulation.Cores.Consoles.ChannelF
|
||||||
|
|
||||||
if (m_read_write == 1)
|
if (m_read_write == 1)
|
||||||
{
|
{
|
||||||
RAM[m_addr] = (byte)m_data0;
|
_ram[m_addr] = (byte)m_data0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -187,7 +173,7 @@ namespace BizHawk.Emulation.Cores.Consoles.ChannelF
|
||||||
public virtual void SyncState(Serializer ser)
|
public virtual void SyncState(Serializer ser)
|
||||||
{
|
{
|
||||||
ser.BeginSection("Cart");
|
ser.BeginSection("Cart");
|
||||||
ser.Sync(nameof(RAM), ref _ram, false);
|
ser.Sync(nameof(_ram), ref _ram, false);
|
||||||
ser.Sync(nameof(m_latch), ref m_latch, false);
|
ser.Sync(nameof(m_latch), ref m_latch, false);
|
||||||
ser.Sync(nameof(m_addr_latch), ref m_addr_latch);
|
ser.Sync(nameof(m_addr_latch), ref m_addr_latch);
|
||||||
ser.Sync(nameof(m_addr), ref m_addr);
|
ser.Sync(nameof(m_addr), ref m_addr);
|
||||||
|
|
|
@ -1,25 +1,21 @@
|
||||||
using System.Collections.Generic;
|
using BizHawk.Emulation.Common;
|
||||||
|
|
||||||
using BizHawk.Emulation.Common;
|
|
||||||
|
|
||||||
namespace BizHawk.Emulation.Cores.Consoles.ChannelF
|
namespace BizHawk.Emulation.Cores.Consoles.ChannelF
|
||||||
{
|
{
|
||||||
public partial class ChannelF
|
public partial class ChannelF
|
||||||
{
|
{
|
||||||
public ControllerDefinition ChannelFControllerDefinition
|
private static readonly Lazy<ControllerDefinition> _channelFControllerDefinition = new(() =>
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
{
|
||||||
ControllerDefinition definition = new("ChannelF Controller");
|
ControllerDefinition definition = new("ChannelF Controller");
|
||||||
|
|
||||||
string pre = "P1 ";
|
|
||||||
|
|
||||||
// sticks
|
// sticks
|
||||||
var stickR = new List<string>
|
|
||||||
{
|
const string P1_PREFIX = "P1 ";
|
||||||
|
string[] stickR =
|
||||||
|
[
|
||||||
// P1 (right) stick
|
// P1 (right) stick
|
||||||
pre + "Forward", pre + "Back", pre + "Left", pre + "Right", pre + "CCW", pre + "CW", pre + "Pull", pre + "Push"
|
P1_PREFIX + "Forward", P1_PREFIX + "Back", P1_PREFIX + "Left", P1_PREFIX + "Right", P1_PREFIX + "CCW", P1_PREFIX + "CW", P1_PREFIX + "Pull", P1_PREFIX + "Push"
|
||||||
};
|
];
|
||||||
|
|
||||||
foreach (var s in stickR)
|
foreach (var s in stickR)
|
||||||
{
|
{
|
||||||
|
@ -27,13 +23,12 @@ namespace BizHawk.Emulation.Cores.Consoles.ChannelF
|
||||||
definition.CategoryLabels[s] = "Right Controller";
|
definition.CategoryLabels[s] = "Right Controller";
|
||||||
}
|
}
|
||||||
|
|
||||||
pre = "P2 ";
|
const string P2_PREFIX = "P2 ";
|
||||||
|
string[] stickL =
|
||||||
var stickL = new List<string>
|
[
|
||||||
{
|
|
||||||
// P2 (left) stick
|
// P2 (left) stick
|
||||||
pre + "Forward", pre + "Back", pre + "Left", pre + "Right", pre + "CCW", pre + "CW", pre + "Pull", pre + "Push"
|
P2_PREFIX + "Forward", P2_PREFIX + "Back", P2_PREFIX + "Left", P2_PREFIX + "Right", P2_PREFIX + "CCW", P2_PREFIX + "CW", P2_PREFIX + "Pull", P2_PREFIX + "Push"
|
||||||
};
|
];
|
||||||
|
|
||||||
foreach (var s in stickL)
|
foreach (var s in stickL)
|
||||||
{
|
{
|
||||||
|
@ -42,10 +37,10 @@ namespace BizHawk.Emulation.Cores.Consoles.ChannelF
|
||||||
}
|
}
|
||||||
|
|
||||||
// console
|
// console
|
||||||
var consoleButtons = new List<string>
|
string[] consoleButtons =
|
||||||
{
|
[
|
||||||
"TIME", "MODE", "HOLD", "START", "RESET"
|
"TIME", "MODE", "HOLD", "START", "RESET"
|
||||||
};
|
];
|
||||||
|
|
||||||
foreach (var s in consoleButtons)
|
foreach (var s in consoleButtons)
|
||||||
{
|
{
|
||||||
|
@ -54,64 +49,68 @@ namespace BizHawk.Emulation.Cores.Consoles.ChannelF
|
||||||
}
|
}
|
||||||
|
|
||||||
return definition.MakeImmutable();
|
return definition.MakeImmutable();
|
||||||
}
|
});
|
||||||
}
|
|
||||||
|
|
||||||
public bool[] StateConsole = new bool[5];
|
private readonly string[] _buttonsConsole =
|
||||||
public string[] ButtonsConsole =
|
[
|
||||||
{
|
|
||||||
"TIME", "MODE", "HOLD", "START", "RESET"
|
"TIME", "MODE", "HOLD", "START", "RESET"
|
||||||
};
|
];
|
||||||
|
|
||||||
public byte DataConsole
|
private bool[] _stateConsole = new bool[5];
|
||||||
|
|
||||||
|
private byte DataConsole
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
int w = 0;
|
var w = 0;
|
||||||
for (int i = 0; i < 5; i++)
|
for (var i = 0; i < 5; i++)
|
||||||
{
|
{
|
||||||
byte mask = (byte) (1 << i);
|
var mask = (byte)(1 << i);
|
||||||
w = StateConsole[i] ? w | mask : w & ~mask;
|
w = _stateConsole[i] ? w | mask : w & ~mask;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (byte)(w & 0xFF);
|
return (byte)(w & 0xFF);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool[] StateRight = new bool[8];
|
private bool[] _stateRight = new bool[8];
|
||||||
public string[] ButtonsRight =
|
|
||||||
{
|
private readonly string[] _buttonsRight =
|
||||||
"Right", "Left", "Back", "Forward", "CCW", "CW", "Pull", "Push"
|
[
|
||||||
};
|
"P1 Right", "P1 Left", "P1 Back", "P1 Forward", "P1 CCW", "P1 CW", "P1 Pull", "P1 Push"
|
||||||
public byte DataRight
|
];
|
||||||
|
|
||||||
|
private byte DataRight
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
int w = 0;
|
var w = 0;
|
||||||
for (int i = 0; i < 8; i++)
|
for (var i = 0; i < 8; i++)
|
||||||
{
|
{
|
||||||
byte mask = (byte)(1 << i);
|
var mask = (byte)(1 << i);
|
||||||
w = StateRight[i] ? w | mask : w & ~mask;
|
w = _stateRight[i] ? w | mask : w & ~mask;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (byte)(w & 0xFF);
|
return (byte)(w & 0xFF);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool[] StateLeft = new bool[8];
|
private bool[] _stateLeft = new bool[8];
|
||||||
public string[] ButtonsLeft =
|
|
||||||
{
|
private readonly string[] _buttonsLeft =
|
||||||
"Right", "Left", "Back", "Forward", "CCW", "CW", "Pull", "Push"
|
[
|
||||||
};
|
"P2 Right", "P2 Left", "P2 Back", "P2 Forward", "P2 CCW", "P2 CW", "P2 Pull", "P2 Push"
|
||||||
public byte DataLeft
|
];
|
||||||
|
|
||||||
|
private byte DataLeft
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
int w = 0;
|
var w = 0;
|
||||||
for (int i = 0; i < 8; i++)
|
for (var i = 0; i < 8; i++)
|
||||||
{
|
{
|
||||||
byte mask = (byte)(1 << i);
|
var mask = (byte)(1 << i);
|
||||||
w = StateLeft[i] ? w | mask : w & ~mask;
|
w = _stateLeft[i] ? w | mask : w & ~mask;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (byte)(w & 0xFF);
|
return (byte)(w & 0xFF);
|
||||||
|
|
|
@ -0,0 +1,27 @@
|
||||||
|
using BizHawk.Emulation.Cores.Components.FairchildF8;
|
||||||
|
|
||||||
|
namespace BizHawk.Emulation.Cores.Consoles.ChannelF
|
||||||
|
{
|
||||||
|
public partial class ChannelF
|
||||||
|
{
|
||||||
|
public readonly struct CpuLink(ChannelF channelF) : IF3850Link
|
||||||
|
{
|
||||||
|
public byte ReadMemory(ushort address)
|
||||||
|
=> channelF.ReadBus(address);
|
||||||
|
|
||||||
|
public void WriteMemory(ushort address, byte value)
|
||||||
|
=> channelF.WriteBus(address, value);
|
||||||
|
|
||||||
|
public byte ReadHardware(ushort address)
|
||||||
|
=> channelF.ReadPort(address);
|
||||||
|
|
||||||
|
public void WriteHardware(ushort address, byte value)
|
||||||
|
=> channelF.WritePort(address, value);
|
||||||
|
|
||||||
|
public void OnExecFetch(ushort address)
|
||||||
|
{
|
||||||
|
// TODO: implement
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -7,10 +7,10 @@ namespace BizHawk.Emulation.Cores.Consoles.ChannelF
|
||||||
public partial class ChannelF : IDebuggable
|
public partial class ChannelF : IDebuggable
|
||||||
{
|
{
|
||||||
public IDictionary<string, RegisterValue> GetCpuFlagsAndRegisters()
|
public IDictionary<string, RegisterValue> GetCpuFlagsAndRegisters()
|
||||||
=> CPU.GetCpuFlagsAndRegisters();
|
=> _cpu.GetCpuFlagsAndRegisters();
|
||||||
|
|
||||||
public void SetCpuRegister(string register, int value)
|
public void SetCpuRegister(string register, int value)
|
||||||
=> CPU.SetCpuRegister(register, value);
|
=> _cpu.SetCpuRegister(register, value);
|
||||||
|
|
||||||
public IMemoryCallbackSystem MemoryCallbacks { get; }
|
public IMemoryCallbackSystem MemoryCallbacks { get; }
|
||||||
|
|
||||||
|
@ -19,6 +19,6 @@ namespace BizHawk.Emulation.Cores.Consoles.ChannelF
|
||||||
[FeatureNotImplemented]
|
[FeatureNotImplemented]
|
||||||
public void Step(StepType type) => throw new NotImplementedException();
|
public void Step(StepType type) => throw new NotImplementedException();
|
||||||
|
|
||||||
public long TotalExecutedCycles => CPU.TotalExecutedCycles;
|
public long TotalExecutedCycles => _cpu.TotalExecutedCycles;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,21 +6,20 @@ namespace BizHawk.Emulation.Cores.Consoles.ChannelF
|
||||||
{
|
{
|
||||||
public IEmulatorServiceProvider ServiceProvider { get; }
|
public IEmulatorServiceProvider ServiceProvider { get; }
|
||||||
|
|
||||||
public ControllerDefinition ControllerDefinition { get; set; }
|
public ControllerDefinition ControllerDefinition { get; }
|
||||||
|
|
||||||
public string SystemId => VSystemID.Raw.ChannelF;
|
public string SystemId => VSystemID.Raw.ChannelF;
|
||||||
|
|
||||||
public bool DeterministicEmulation { get; set; }
|
public bool DeterministicEmulation => true;
|
||||||
|
|
||||||
public int CpuClocksPerFrame;
|
private int _cpuClocksPerFrame;
|
||||||
public int FrameClock;
|
private int _frameClock;
|
||||||
|
|
||||||
private void CalcClock()
|
private void CalcClock()
|
||||||
{
|
{
|
||||||
// CPU speeds from https://en.wikipedia.org/wiki/Fairchild_Channel_F
|
// CPU speeds from https://en.wikipedia.org/wiki/Fairchild_Channel_F
|
||||||
// also https://github.com/mamedev/mame/blob/c8192c898ce7f68c0c0b87e44199f0d3e710439b/src/mame/drivers/channelf.cpp
|
// also https://github.com/mamedev/mame/blob/c8192c898ce7f68c0c0b87e44199f0d3e710439b/src/mame/drivers/channelf.cpp
|
||||||
double cpuFreq, pixelClock;
|
double cpuFreq, pixelClock;
|
||||||
int pixelClocksPerFrame;
|
|
||||||
if (Region == DisplayType.NTSC)
|
if (Region == DisplayType.NTSC)
|
||||||
{
|
{
|
||||||
HTotal = 256;
|
HTotal = 256;
|
||||||
|
@ -37,8 +36,7 @@ namespace BizHawk.Emulation.Cores.Consoles.ChannelF
|
||||||
cpuFreq = NTSC_COLORBURST / 2;
|
cpuFreq = NTSC_COLORBURST / 2;
|
||||||
// NTSC pixel clock is NTSC Colorburst * 8 / 7
|
// NTSC pixel clock is NTSC Colorburst * 8 / 7
|
||||||
pixelClock = NTSC_COLORBURST * 8 / 7;
|
pixelClock = NTSC_COLORBURST * 8 / 7;
|
||||||
// NTSC refresh rate is (pixelclock * 8 / 7) / (256 * 264)
|
// NTSC refresh rate is (pixelclock * 8 / 7) / (HTotal * VTotal)
|
||||||
pixelClocksPerFrame = 256 * 264;
|
|
||||||
// (aka (1023750000 * 8) / (256 * 264 * 286 * 7)
|
// (aka (1023750000 * 8) / (256 * 264 * 286 * 7)
|
||||||
// reduced to 234375 / 3872
|
// reduced to 234375 / 3872
|
||||||
VsyncNumerator = 234375;
|
VsyncNumerator = 234375;
|
||||||
|
@ -55,19 +53,18 @@ namespace BizHawk.Emulation.Cores.Consoles.ChannelF
|
||||||
ScanlineRepeats = 5;
|
ScanlineRepeats = 5;
|
||||||
PixelWidth = 2;
|
PixelWidth = 2;
|
||||||
|
|
||||||
if (version == ConsoleVersion.ChannelF)
|
if (_version == ConsoleVersion.ChannelF)
|
||||||
{
|
{
|
||||||
// PAL CPU speed is 2MHz
|
// PAL CPU speed is 2MHz
|
||||||
cpuFreq = 2000000;
|
cpuFreq = 2000000;
|
||||||
// PAL pixel clock is 4MHz
|
// PAL pixel clock is 4MHz
|
||||||
pixelClock = 4000000;
|
pixelClock = 4000000;
|
||||||
// PAL refresh rate is pixelclock / (256 * 312)
|
// PAL refresh rate is pixelclock / (HTotal * VTotal)
|
||||||
pixelClocksPerFrame = 256 * 312;
|
|
||||||
// reduced to 15625 / 312
|
// reduced to 15625 / 312
|
||||||
VsyncNumerator = 15625;
|
VsyncNumerator = 15625;
|
||||||
VsyncDenominator = 312;
|
VsyncDenominator = 312;
|
||||||
}
|
}
|
||||||
else if (version == ConsoleVersion.ChannelF_II)
|
else if (_version == ConsoleVersion.ChannelF_II)
|
||||||
{
|
{
|
||||||
// PAL CPU speed for gen 2 seems to be contested
|
// PAL CPU speed for gen 2 seems to be contested
|
||||||
// various sources seem to say 1.77MHz (i.e. PAL Colorburst * 2 / 5)
|
// various sources seem to say 1.77MHz (i.e. PAL Colorburst * 2 / 5)
|
||||||
|
@ -81,8 +78,7 @@ namespace BizHawk.Emulation.Cores.Consoles.ChannelF
|
||||||
// not entirely sure what the pixel clock for PAL is here
|
// not entirely sure what the pixel clock for PAL is here
|
||||||
// presumingly, it's just cpuFreq * 2?
|
// presumingly, it's just cpuFreq * 2?
|
||||||
pixelClock = PAL_COLORBURST * 8 / 9;
|
pixelClock = PAL_COLORBURST * 8 / 9;
|
||||||
// PAL refresh rate is pixelclock / (256 * 312)
|
// PAL refresh rate is pixelclock / (HTotal * VTotal)
|
||||||
pixelClocksPerFrame = 256 * 312;
|
|
||||||
// (aka (4433618.75 * 8) / (256 * 312 * 9)
|
// (aka (4433618.75 * 8) / (256 * 312 * 9)
|
||||||
// reduced to 17734475 / 359424
|
// reduced to 17734475 / 359424
|
||||||
VsyncNumerator = 17734475;
|
VsyncNumerator = 17734475;
|
||||||
|
@ -94,10 +90,12 @@ namespace BizHawk.Emulation.Cores.Consoles.ChannelF
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var c = cpuFreq * pixelClocksPerFrame / pixelClock;
|
|
||||||
CpuClocksPerFrame = (int) c;
|
|
||||||
PixelClocksPerCpuClock = pixelClock / cpuFreq;
|
PixelClocksPerCpuClock = pixelClock / cpuFreq;
|
||||||
PixelClocksPerFrame = pixelClocksPerFrame;
|
PixelClocksPerFrame = HTotal * VTotal;
|
||||||
|
|
||||||
|
var c = cpuFreq * PixelClocksPerFrame / pixelClock;
|
||||||
|
// note: this always results in a nice integer, no precision is lost!
|
||||||
|
_cpuClocksPerFrame = (int)c;
|
||||||
|
|
||||||
SetupAudio();
|
SetupAudio();
|
||||||
}
|
}
|
||||||
|
@ -109,22 +107,22 @@ namespace BizHawk.Emulation.Cores.Consoles.ChannelF
|
||||||
|
|
||||||
if (_tracer.IsEnabled())
|
if (_tracer.IsEnabled())
|
||||||
{
|
{
|
||||||
CPU.TraceCallback = s => _tracer.Put(s);
|
_cpu.TraceCallback = s => _tracer.Put(s);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
CPU.TraceCallback = null;
|
_cpu.TraceCallback = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
PollInput();
|
PollInput();
|
||||||
|
|
||||||
while (FrameClock++ < CpuClocksPerFrame)
|
while (_frameClock++ < _cpuClocksPerFrame)
|
||||||
{
|
{
|
||||||
CPU.ExecuteOne();
|
_cpu.ExecuteOne();
|
||||||
ClockVideo();
|
ClockVideo();
|
||||||
}
|
}
|
||||||
|
|
||||||
FrameClock = 0;
|
_frameClock = 0;
|
||||||
_frame++;
|
_frame++;
|
||||||
|
|
||||||
if (_isLag)
|
if (_isLag)
|
||||||
|
@ -134,10 +132,6 @@ namespace BizHawk.Emulation.Cores.Consoles.ChannelF
|
||||||
}
|
}
|
||||||
|
|
||||||
private int _frame;
|
private int _frame;
|
||||||
#pragma warning disable CS0414
|
|
||||||
//private int _lagcount;
|
|
||||||
//private bool _islag;
|
|
||||||
#pragma warning restore CS0414
|
|
||||||
|
|
||||||
public void ResetCounters()
|
public void ResetCounters()
|
||||||
{
|
{
|
||||||
|
@ -154,8 +148,8 @@ namespace BizHawk.Emulation.Cores.Consoles.ChannelF
|
||||||
|
|
||||||
private void ConsoleReset()
|
private void ConsoleReset()
|
||||||
{
|
{
|
||||||
CPU.Reset();
|
_cpu.Reset();
|
||||||
Cartridge.Reset();
|
_cartridge.Reset();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,38 +25,6 @@ namespace BizHawk.Emulation.Cores.Consoles.ChannelF
|
||||||
return ret ? PutSettingsDirtyBits.RebootCore : PutSettingsDirtyBits.None;
|
return ret ? PutSettingsDirtyBits.RebootCore : PutSettingsDirtyBits.None;
|
||||||
}
|
}
|
||||||
|
|
||||||
[CoreSettings]
|
|
||||||
public class ChannelFSyncSettings
|
|
||||||
{
|
|
||||||
[DisplayName("Deterministic Emulation")]
|
|
||||||
[Description("If true, the core agrees to behave in a completely deterministic manner")]
|
|
||||||
[DefaultValue(true)]
|
|
||||||
public bool DeterministicEmulation { get; set; }
|
|
||||||
[DisplayName("Region")]
|
|
||||||
[Description("NTSC or PAL - Affects the CPU clock speed and refresh rate")]
|
|
||||||
[DefaultValue(RegionType.NTSC)]
|
|
||||||
public RegionType Region { get; set; }
|
|
||||||
[DisplayName("Version")]
|
|
||||||
[Description("Channel F II has a very slightly different BIOS to Channel F and a slightly slower CPU in the PAL version compared to v1")]
|
|
||||||
[DefaultValue(ConsoleVersion.ChannelF)]
|
|
||||||
public ConsoleVersion Version { get; set; }
|
|
||||||
|
|
||||||
public ChannelFSyncSettings Clone()
|
|
||||||
{
|
|
||||||
return (ChannelFSyncSettings) MemberwiseClone();
|
|
||||||
}
|
|
||||||
|
|
||||||
public ChannelFSyncSettings()
|
|
||||||
{
|
|
||||||
SettingsUtil.SetDefaultValues(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static bool NeedsReboot(ChannelFSyncSettings x, ChannelFSyncSettings y)
|
|
||||||
{
|
|
||||||
return !DeepEquality.DeepEquals(x, y);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public enum RegionType
|
public enum RegionType
|
||||||
{
|
{
|
||||||
NTSC,
|
NTSC,
|
||||||
|
@ -68,5 +36,28 @@ namespace BizHawk.Emulation.Cores.Consoles.ChannelF
|
||||||
ChannelF,
|
ChannelF,
|
||||||
ChannelF_II
|
ChannelF_II
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[CoreSettings]
|
||||||
|
public class ChannelFSyncSettings
|
||||||
|
{
|
||||||
|
[DisplayName("Region")]
|
||||||
|
[Description("NTSC or PAL - Affects the CPU clock speed and refresh rate")]
|
||||||
|
[DefaultValue(RegionType.NTSC)]
|
||||||
|
public RegionType Region { get; set; }
|
||||||
|
|
||||||
|
[DisplayName("Version")]
|
||||||
|
[Description("Channel F II has a very slightly different BIOS to Channel F and a slightly slower CPU in the PAL version compared to v1")]
|
||||||
|
[DefaultValue(ConsoleVersion.ChannelF)]
|
||||||
|
public ConsoleVersion Version { get; set; }
|
||||||
|
|
||||||
|
public ChannelFSyncSettings Clone()
|
||||||
|
=> (ChannelFSyncSettings)MemberwiseClone();
|
||||||
|
|
||||||
|
public ChannelFSyncSettings()
|
||||||
|
=> SettingsUtil.SetDefaultValues(this);
|
||||||
|
|
||||||
|
public static bool NeedsReboot(ChannelFSyncSettings x, ChannelFSyncSettings y)
|
||||||
|
=> !DeepEquality.DeepEquals(x, y);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,7 +29,7 @@ namespace BizHawk.Emulation.Cores.Consoles.ChannelF
|
||||||
{
|
{
|
||||||
_samplesPerFrame = (int)(SAMPLE_RATE * VsyncDenominator / VsyncNumerator);
|
_samplesPerFrame = (int)(SAMPLE_RATE * VsyncDenominator / VsyncNumerator);
|
||||||
// TODO: more precise audio clocking
|
// TODO: more precise audio clocking
|
||||||
_cyclesPerSample = CpuClocksPerFrame / (double)_samplesPerFrame;
|
_cyclesPerSample = _cpuClocksPerFrame / (double)_samplesPerFrame;
|
||||||
_sampleBuffer = new short[_samplesPerFrame];
|
_sampleBuffer = new short[_samplesPerFrame];
|
||||||
_filteredSampleBuffer = new double[_samplesPerFrame];
|
_filteredSampleBuffer = new double[_samplesPerFrame];
|
||||||
_toneBuffer = new int[_samplesPerFrame];
|
_toneBuffer = new int[_samplesPerFrame];
|
||||||
|
@ -37,8 +37,7 @@ namespace BizHawk.Emulation.Cores.Consoles.ChannelF
|
||||||
|
|
||||||
private void AudioChange()
|
private void AudioChange()
|
||||||
{
|
{
|
||||||
var currSample = (int)(FrameClock / _cyclesPerSample);
|
var currSample = (int)(_frameClock / _cyclesPerSample);
|
||||||
|
|
||||||
while (currSample < _samplesPerFrame)
|
while (currSample < _samplesPerFrame)
|
||||||
{
|
{
|
||||||
_toneBuffer[currSample++] = _tone;
|
_toneBuffer[currSample++] = _tone;
|
||||||
|
@ -150,9 +149,7 @@ namespace BizHawk.Emulation.Cores.Consoles.ChannelF
|
||||||
}
|
}
|
||||||
|
|
||||||
public void GetSamplesAsync(short[] samples)
|
public void GetSamplesAsync(short[] samples)
|
||||||
{
|
=> throw new NotSupportedException("Async is not available");
|
||||||
throw new NotSupportedException("Async is not available");
|
|
||||||
}
|
|
||||||
|
|
||||||
public void DiscardSamples()
|
public void DiscardSamples()
|
||||||
{
|
{
|
||||||
|
|
|
@ -7,14 +7,14 @@ namespace BizHawk.Emulation.Cores.Consoles.ChannelF
|
||||||
private void SyncState(Serializer ser)
|
private void SyncState(Serializer ser)
|
||||||
{
|
{
|
||||||
ser.BeginSection("ChannelF");
|
ser.BeginSection("ChannelF");
|
||||||
ser.Sync(nameof(VRAM), ref VRAM, false);
|
ser.Sync(nameof(_vram), ref _vram, false);
|
||||||
ser.Sync(nameof(_latch_colour), ref _latch_colour);
|
ser.Sync(nameof(_latchColour), ref _latchColour);
|
||||||
ser.Sync(nameof(_latch_x), ref _latch_x);
|
ser.Sync(nameof(_latchX), ref _latchX);
|
||||||
ser.Sync(nameof(_latch_y), ref _latch_y);
|
ser.Sync(nameof(_latchY), ref _latchY);
|
||||||
ser.Sync(nameof(_pixelClockCounter), ref _pixelClockCounter);
|
ser.Sync(nameof(_pixelClockCounter), ref _pixelClockCounter);
|
||||||
ser.Sync(nameof(_pixelClocksRemaining), ref _pixelClocksRemaining);
|
ser.Sync(nameof(_pixelClocksRemaining), ref _pixelClocksRemaining);
|
||||||
|
|
||||||
ser.Sync(nameof(FrameClock), ref FrameClock);
|
ser.Sync(nameof(_frameClock), ref _frameClock);
|
||||||
ser.Sync(nameof(_frame), ref _frame);
|
ser.Sync(nameof(_frame), ref _frame);
|
||||||
ser.Sync(nameof(_isLag), ref _isLag);
|
ser.Sync(nameof(_isLag), ref _isLag);
|
||||||
ser.Sync(nameof(_lagCount), ref _lagCount);
|
ser.Sync(nameof(_lagCount), ref _lagCount);
|
||||||
|
@ -30,75 +30,21 @@ namespace BizHawk.Emulation.Cores.Consoles.ChannelF
|
||||||
ser.Sync(nameof(_currTone), ref _currTone);
|
ser.Sync(nameof(_currTone), ref _currTone);
|
||||||
ser.Sync(nameof(_samplePosition), ref _samplePosition);
|
ser.Sync(nameof(_samplePosition), ref _samplePosition);
|
||||||
|
|
||||||
ser.Sync(nameof(StateConsole), ref StateConsole, false);
|
ser.Sync(nameof(_stateConsole), ref _stateConsole, false);
|
||||||
ser.Sync(nameof(StateRight), ref StateRight, false);
|
ser.Sync(nameof(_stateRight), ref _stateRight, false);
|
||||||
ser.Sync(nameof(StateLeft), ref StateLeft, false);
|
ser.Sync(nameof(_stateLeft), ref _stateLeft, false);
|
||||||
|
|
||||||
ser.Sync(nameof(OutputLatch), ref OutputLatch, false);
|
ser.Sync(nameof(_outputLatch), ref _outputLatch, false);
|
||||||
ser.Sync(nameof(LS368Enable), ref LS368Enable);
|
ser.Sync(nameof(LS368Enable), ref LS368Enable);
|
||||||
|
|
||||||
//ser.Sync(nameof(ControllersEnabled), ref ControllersEnabled);
|
_cpu.SyncState(ser);
|
||||||
CPU.SyncState(ser);
|
_cartridge.SyncState(ser);
|
||||||
Cartridge.SyncState(ser);
|
|
||||||
ser.EndSection();
|
ser.EndSection();
|
||||||
|
|
||||||
if (ser.IsReader)
|
if (ser.IsReader)
|
||||||
{
|
{
|
||||||
SyncAllByteArrayDomains();
|
SyncAllByteArrayDomains();
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
|
|
||||||
byte[] core = null;
|
|
||||||
if (ser.IsWriter)
|
|
||||||
{
|
|
||||||
var ms = new MemoryStream();
|
|
||||||
ms.Close();
|
|
||||||
core = ms.ToArray();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ser.IsWriter)
|
|
||||||
{
|
|
||||||
ser.SyncEnum(nameof(_machineType), ref _machineType);
|
|
||||||
|
|
||||||
_cpu.SyncState(ser);
|
|
||||||
ser.BeginSection(nameof(ChannelF));
|
|
||||||
_machine.SyncState(ser);
|
|
||||||
ser.Sync("Frame", ref _machine.FrameCount);
|
|
||||||
ser.Sync("LagCount", ref _lagCount);
|
|
||||||
ser.Sync("IsLag", ref _isLag);
|
|
||||||
ser.EndSection();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ser.IsReader)
|
|
||||||
{
|
|
||||||
var tmpM = _machineType;
|
|
||||||
ser.SyncEnum(nameof(_machineType), ref _machineType);
|
|
||||||
if (tmpM != _machineType && _machineType.ToString() != "72")
|
|
||||||
{
|
|
||||||
string msg = "SAVESTATE FAILED TO LOAD!!\n\n";
|
|
||||||
msg += "Current Configuration: " + tmpM.ToString();
|
|
||||||
msg += "\n";
|
|
||||||
msg += "Saved Configuration: " + _machineType.ToString();
|
|
||||||
msg += "\n\n";
|
|
||||||
msg += "If you wish to load this SaveState ensure that you have the correct machine configuration selected, reboot the core, then try again.";
|
|
||||||
CoreComm.ShowMessage(msg);
|
|
||||||
_machineType = tmpM;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
_cpu.SyncState(ser);
|
|
||||||
ser.BeginSection(nameof(ChannelF));
|
|
||||||
_machine.SyncState(ser);
|
|
||||||
ser.Sync("Frame", ref _machine.FrameCount);
|
|
||||||
ser.Sync("LagCount", ref _lagCount);
|
|
||||||
ser.Sync("IsLag", ref _isLag);
|
|
||||||
ser.EndSection();
|
|
||||||
|
|
||||||
SyncAllByteArrayDomains();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,13 +8,11 @@ namespace BizHawk.Emulation.Cores.Consoles.ChannelF
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 128x64 pixels - 8192x2bits (2 KB)
|
/// 128x64 pixels - 8192x2bits (2 KB)
|
||||||
/// For the purposes of this core we will use 8192 bytes and just mask 0x03
|
/// For the purposes of this core we will use 8192 bytes and just mask 0x03
|
||||||
/// (Also adding an additional 10 rows to the RAM buffer so that it's more aligned with the actual display)
|
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public byte[] VRAM = new byte[128 * 64];
|
private byte[] _vram = new byte[128 * 64];
|
||||||
|
|
||||||
|
|
||||||
public static readonly int[] FPalette =
|
public static readonly int[] FPalette =
|
||||||
{
|
[
|
||||||
// 0x101010, 0xFDFDFD, 0x5331FF, 0x5DCC02, 0xF33F4B, 0xE0E0E0, 0xA6FF91, 0xD0CEFF
|
// 0x101010, 0xFDFDFD, 0x5331FF, 0x5DCC02, 0xF33F4B, 0xE0E0E0, 0xA6FF91, 0xD0CEFF
|
||||||
|
|
||||||
Colors.ARGB(0x10, 0x10, 0x10), // Black
|
Colors.ARGB(0x10, 0x10, 0x10), // Black
|
||||||
|
@ -25,24 +23,23 @@ namespace BizHawk.Emulation.Cores.Consoles.ChannelF
|
||||||
Colors.ARGB(0xE0, 0xE0, 0xE0), // Gray
|
Colors.ARGB(0xE0, 0xE0, 0xE0), // Gray
|
||||||
Colors.ARGB(0x91, 0xFF, 0xA6), // BGreen
|
Colors.ARGB(0x91, 0xFF, 0xA6), // BGreen
|
||||||
Colors.ARGB(0xCE, 0xD0, 0xFF), // BBlue
|
Colors.ARGB(0xCE, 0xD0, 0xFF), // BBlue
|
||||||
};
|
];
|
||||||
|
|
||||||
public static readonly int[] CMap =
|
public static readonly int[] CMap =
|
||||||
{
|
[
|
||||||
0, 1, 1, 1,
|
0, 1, 1, 1,
|
||||||
7, 4, 2, 3,
|
7, 4, 2, 3,
|
||||||
5, 4, 2, 3,
|
5, 4, 2, 3,
|
||||||
6, 4, 2, 3,
|
6, 4, 2, 3,
|
||||||
};
|
];
|
||||||
|
|
||||||
private int _latch_colour = 2;
|
private int _latchColour = 2;
|
||||||
private int _latch_x;
|
private int _latchX;
|
||||||
private int _latch_y;
|
private int _latchY;
|
||||||
private int[] videoBuffer;
|
private int[] _videoBuffer;
|
||||||
private double _pixelClockCounter;
|
private double _pixelClockCounter;
|
||||||
private double _pixelClocksRemaining;
|
private double _pixelClocksRemaining;
|
||||||
|
|
||||||
|
|
||||||
private int ScanlineRepeats;
|
private int ScanlineRepeats;
|
||||||
private int PixelWidth;
|
private int PixelWidth;
|
||||||
private int HTotal;
|
private int HTotal;
|
||||||
|
@ -54,10 +51,8 @@ namespace BizHawk.Emulation.Cores.Consoles.ChannelF
|
||||||
private double PixelClocksPerCpuClock;
|
private double PixelClocksPerCpuClock;
|
||||||
private double PixelClocksPerFrame;
|
private double PixelClocksPerFrame;
|
||||||
|
|
||||||
public void SetupVideo()
|
private void SetupVideo()
|
||||||
{
|
=> _videoBuffer = new int[HTotal * VTotal];
|
||||||
videoBuffer = new int[HTotal * VTotal];
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Called after every CPU clock
|
/// Called after every CPU clock
|
||||||
|
@ -67,7 +62,7 @@ namespace BizHawk.Emulation.Cores.Consoles.ChannelF
|
||||||
while (_pixelClocksRemaining > 1)
|
while (_pixelClocksRemaining > 1)
|
||||||
{
|
{
|
||||||
var currScanline = (int)(_pixelClockCounter / HTotal);
|
var currScanline = (int)(_pixelClockCounter / HTotal);
|
||||||
var currPixelInLine = (int)(_pixelClockCounter % HTotal);
|
var currPixelInLine = (int)(_pixelClockCounter - currScanline * HTotal);
|
||||||
var currRowInVram = currScanline / ScanlineRepeats;
|
var currRowInVram = currScanline / ScanlineRepeats;
|
||||||
var currColInVram = currPixelInLine / PixelWidth;
|
var currColInVram = currPixelInLine / PixelWidth;
|
||||||
|
|
||||||
|
@ -84,12 +79,12 @@ namespace BizHawk.Emulation.Cores.Consoles.ChannelF
|
||||||
// active display
|
// active display
|
||||||
if (currRowInVram < 64)
|
if (currRowInVram < 64)
|
||||||
{
|
{
|
||||||
var p1 = (VRAM[(currRowInVram * 0x80) + 125]) & 0x03;
|
var p1 = _vram[(currRowInVram * 0x80) + 125] & 0x03;
|
||||||
var p2 = (VRAM[(currRowInVram * 0x80) + 126]) & 0x03;
|
var p2 = _vram[(currRowInVram * 0x80) + 126] & 0x03;
|
||||||
var pOffset = ((p2 & 0x02) | (p1 >> 1)) << 2;
|
var pOffset = ((p2 & 0x02) | (p1 >> 1)) << 2;
|
||||||
|
|
||||||
var colourIndex = pOffset + (VRAM[currColInVram | (currRowInVram << 7)] & 0x03);
|
var colourIndex = pOffset + (_vram[currColInVram | (currRowInVram << 7)] & 0x03);
|
||||||
videoBuffer[(currScanline * HTotal) + currPixelInLine] = FPalette[CMap[colourIndex]];
|
_videoBuffer[(currScanline * HTotal) + currPixelInLine] = FPalette[CMap[colourIndex]];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -98,13 +93,16 @@ namespace BizHawk.Emulation.Cores.Consoles.ChannelF
|
||||||
}
|
}
|
||||||
|
|
||||||
_pixelClocksRemaining += PixelClocksPerCpuClock;
|
_pixelClocksRemaining += PixelClocksPerCpuClock;
|
||||||
_pixelClockCounter %= PixelClocksPerFrame;
|
while (_pixelClockCounter >= PixelClocksPerFrame)
|
||||||
|
{
|
||||||
|
_pixelClockCounter -= PixelClocksPerFrame;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private int HDisplayable => HBlankOn - HBlankOff;
|
private int HDisplayable => HBlankOn - HBlankOff;
|
||||||
private int VDisplayable => VBlankOn - VBlankOff;
|
private int VDisplayable => VBlankOn - VBlankOff;
|
||||||
|
|
||||||
private int[] ClampBuffer(int[] buffer, int originalWidth, int originalHeight, int trimLeft, int trimTop, int trimRight, int trimBottom)
|
private static int[] ClampBuffer(int[] buffer, int originalWidth, int originalHeight, int trimLeft, int trimTop, int trimRight, int trimBottom)
|
||||||
{
|
{
|
||||||
var newWidth = originalWidth - trimLeft - trimRight;
|
var newWidth = originalWidth - trimLeft - trimRight;
|
||||||
var newHeight = originalHeight - trimTop - trimBottom;
|
var newHeight = originalHeight - trimTop - trimBottom;
|
||||||
|
@ -112,7 +110,7 @@ namespace BizHawk.Emulation.Cores.Consoles.ChannelF
|
||||||
|
|
||||||
for (var y = 0; y < newHeight; y++)
|
for (var y = 0; y < newHeight; y++)
|
||||||
{
|
{
|
||||||
for (int x = 0; x < newWidth; x++)
|
for (var x = 0; x < newWidth; x++)
|
||||||
{
|
{
|
||||||
var originalIndex = (y + trimTop) * originalWidth + (x + trimLeft);
|
var originalIndex = (y + trimTop) * originalWidth + (x + trimLeft);
|
||||||
var newIndex = y * newWidth + x;
|
var newIndex = y * newWidth + x;
|
||||||
|
@ -139,8 +137,6 @@ namespace BizHawk.Emulation.Cores.Consoles.ChannelF
|
||||||
public int VsyncDenominator { get; private set; }
|
public int VsyncDenominator { get; private set; }
|
||||||
|
|
||||||
|
|
||||||
public int[] GetVideoBuffer()
|
|
||||||
{
|
|
||||||
// https://channelf.se/veswiki/index.php?title=VRAM
|
// https://channelf.se/veswiki/index.php?title=VRAM
|
||||||
// 'The emulator MESS uses a fixed 102x58 resolution starting at (4,4) but the safe area for a real system is about 95x58 pixels'
|
// 'The emulator MESS uses a fixed 102x58 resolution starting at (4,4) but the safe area for a real system is about 95x58 pixels'
|
||||||
// 'Note that the pixel aspect is a lot closer to widescreen (16:9) than standard definition (4:3). On a TV from the 70's or 80's pixels are rectangular, standing up. In widescreen mode they are close to perfect squares'
|
// 'Note that the pixel aspect is a lot closer to widescreen (16:9) than standard definition (4:3). On a TV from the 70's or 80's pixels are rectangular, standing up. In widescreen mode they are close to perfect squares'
|
||||||
|
@ -150,29 +146,9 @@ namespace BizHawk.Emulation.Cores.Consoles.ChannelF
|
||||||
// Right now we are just trimming based on the HBLANK and VBLANK values (we might need to go further like the other emulators)
|
// Right now we are just trimming based on the HBLANK and VBLANK values (we might need to go further like the other emulators)
|
||||||
// VirtualWidth is being used to force the aspect ratio into 4:3
|
// VirtualWidth is being used to force the aspect ratio into 4:3
|
||||||
// On real hardware it looks like this (so we are close): https://www.youtube.com/watch?v=ZvQA9tiEIuQ
|
// On real hardware it looks like this (so we are close): https://www.youtube.com/watch?v=ZvQA9tiEIuQ
|
||||||
return ClampBuffer(videoBuffer, HTotal, VTotal, HBlankOff, VBlankOff, HTotal - HBlankOn, VTotal - VBlankOn);
|
public int[] GetVideoBuffer()
|
||||||
}
|
=> ClampBuffer(_videoBuffer, HTotal, VTotal, HBlankOff, VBlankOff, HTotal - HBlankOn, VTotal - VBlankOn);
|
||||||
|
|
||||||
public DisplayType Region => region == RegionType.NTSC ? DisplayType.NTSC : DisplayType.PAL;
|
public DisplayType Region => _region == RegionType.NTSC ? DisplayType.NTSC : DisplayType.PAL;
|
||||||
|
|
||||||
/*
|
|
||||||
private void BuildFrameFromRAM()
|
|
||||||
{
|
|
||||||
for (int r = 0; r < 64; r++)
|
|
||||||
{
|
|
||||||
// lines
|
|
||||||
var p1 = (VRAM[(r * 0x80) + 125]) & 0x03;
|
|
||||||
var p2 = (VRAM[(r * 0x80) + 126]) & 0x03;
|
|
||||||
var pOffset = ((p2 & 0x02) | (p1 >> 1)) << 2;
|
|
||||||
|
|
||||||
for (int c = 0; c < 128; c++)
|
|
||||||
{
|
|
||||||
// columns
|
|
||||||
var colourIndex = pOffset + (VRAM[c | (r << 7)] & 0x03);
|
|
||||||
frameBuffer[(r << 7) + c] = CMap[colourIndex];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,63 +18,48 @@ namespace BizHawk.Emulation.Cores.Consoles.ChannelF
|
||||||
|
|
||||||
public IInputCallbackSystem InputCallbacks { get; } = new InputCallbackSystem();
|
public IInputCallbackSystem InputCallbacks { get; } = new InputCallbackSystem();
|
||||||
|
|
||||||
private int _lagCount = 0;
|
private int _lagCount;
|
||||||
private bool _isLag = false;
|
private bool _isLag;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Cycles through all the input callbacks
|
/// Cycles through all the input callbacks
|
||||||
/// This should be done once per frame
|
/// This should be done once per frame
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool PollInput()
|
private void PollInput()
|
||||||
{
|
{
|
||||||
bool noInput = true;
|
for (var i = 0; i < _buttonsConsole.Length; i++)
|
||||||
for (int i = 0; i < ButtonsConsole.Length; i++)
|
|
||||||
{
|
{
|
||||||
var key = ButtonsConsole[i];
|
var key = _buttonsConsole[i];
|
||||||
bool prevState = StateConsole[i]; // CTRLConsole.Bit(i);
|
var prevState = _stateConsole[i];
|
||||||
bool currState = _controller.IsPressed(key);
|
var currState = _controller.IsPressed(key);
|
||||||
if (currState != prevState)
|
if (currState != prevState)
|
||||||
{
|
{
|
||||||
StateConsole[i] = currState;
|
_stateConsole[i] = currState;
|
||||||
noInput = false;
|
|
||||||
|
|
||||||
if (key == "RESET" && StateConsole[i])
|
if (key == "RESET" && _stateConsole[i])
|
||||||
{
|
{
|
||||||
ConsoleReset();
|
ConsoleReset();
|
||||||
for (int l = 0; l < OutputLatch.Length; l++)
|
for (var l = 0; l < _outputLatch.Length; l++)
|
||||||
{
|
{
|
||||||
OutputLatch[l] = 0;
|
_outputLatch[l] = 0;
|
||||||
}
|
}
|
||||||
return true;
|
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = 0; i < ButtonsRight.Length; i++)
|
for (var i = 0; i < _buttonsRight.Length; i++)
|
||||||
{
|
{
|
||||||
var key = "P1 " + ButtonsRight[i];
|
var key = _buttonsRight[i];
|
||||||
bool prevState = StateRight[i];
|
_stateRight[i] = _controller.IsPressed(key);
|
||||||
bool currState = _controller.IsPressed(key);
|
|
||||||
if (currState != prevState)
|
|
||||||
{
|
|
||||||
StateRight[i] = currState;
|
|
||||||
noInput = false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = 0; i < ButtonsLeft.Length; i++)
|
for (var i = 0; i < _buttonsLeft.Length; i++)
|
||||||
{
|
{
|
||||||
var key = "P2 " + ButtonsLeft[i];
|
var key = _buttonsLeft[i];
|
||||||
bool prevState = StateLeft[i];
|
_stateLeft[i] = _controller.IsPressed(key);
|
||||||
bool currState = _controller.IsPressed(key);
|
}
|
||||||
if (currState != prevState)
|
|
||||||
{
|
|
||||||
StateLeft[i] = currState;
|
|
||||||
noInput = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return noInput;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,12 +19,12 @@ namespace BizHawk.Emulation.Cores.Consoles.ChannelF
|
||||||
addr =>
|
addr =>
|
||||||
{
|
{
|
||||||
if (addr is < 0 or > 63) throw new ArgumentOutOfRangeException(paramName: nameof(addr), addr, message: "address out of range");
|
if (addr is < 0 or > 63) throw new ArgumentOutOfRangeException(paramName: nameof(addr), addr, message: "address out of range");
|
||||||
return CPU.Regs[addr];
|
return _cpu.Regs[addr];
|
||||||
},
|
},
|
||||||
(addr, value) =>
|
(addr, value) =>
|
||||||
{
|
{
|
||||||
if (addr is < 0 or > 63) throw new ArgumentOutOfRangeException(paramName: nameof(addr), addr, message: "address out of range");
|
if (addr is < 0 or > 63) throw new ArgumentOutOfRangeException(paramName: nameof(addr), addr, message: "address out of range");
|
||||||
CPU.Regs[addr] = value;
|
_cpu.Regs[addr] = value;
|
||||||
}, 1),
|
}, 1),
|
||||||
new MemoryDomainDelegate("System Bus", 0x10000, MemoryDomain.Endian.Big,
|
new MemoryDomainDelegate("System Bus", 0x10000, MemoryDomain.Endian.Big,
|
||||||
addr =>
|
addr =>
|
||||||
|
@ -49,11 +49,10 @@ namespace BizHawk.Emulation.Cores.Consoles.ChannelF
|
||||||
|
|
||||||
private void SyncAllByteArrayDomains()
|
private void SyncAllByteArrayDomains()
|
||||||
{
|
{
|
||||||
SyncByteArrayDomain("BIOS1", BIOS01);
|
SyncByteArrayDomain("BIOS1", _bios01);
|
||||||
SyncByteArrayDomain("BIOS2", BIOS02);
|
SyncByteArrayDomain("BIOS2", _bios02);
|
||||||
Cartridge.SyncByteArrayDomain(this);
|
_cartridge.SyncByteArrayDomain(this);
|
||||||
//SyncByteArrayDomain("ROM", Rom);
|
SyncByteArrayDomain("VRAM", _vram);
|
||||||
SyncByteArrayDomain("VRAM", VRAM);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SyncByteArrayDomain(string name, byte[] data)
|
public void SyncByteArrayDomain(string name, byte[] data)
|
||||||
|
|
|
@ -1,7 +1,4 @@
|
||||||
using System.Collections.Generic;
|
using BizHawk.Emulation.Common;
|
||||||
using System.Linq;
|
|
||||||
|
|
||||||
using BizHawk.Emulation.Common;
|
|
||||||
using BizHawk.Emulation.Cores.Components.FairchildF8;
|
using BizHawk.Emulation.Cores.Components.FairchildF8;
|
||||||
|
|
||||||
namespace BizHawk.Emulation.Cores.Consoles.ChannelF
|
namespace BizHawk.Emulation.Cores.Consoles.ChannelF
|
||||||
|
@ -15,71 +12,60 @@ namespace BizHawk.Emulation.Cores.Consoles.ChannelF
|
||||||
var ser = new BasicServiceProvider(this);
|
var ser = new BasicServiceProvider(this);
|
||||||
ServiceProvider = ser;
|
ServiceProvider = ser;
|
||||||
CoreComm = lp.Comm;
|
CoreComm = lp.Comm;
|
||||||
_gameInfo = lp.Roms.Select(r => r.Game).ToList();
|
var gameInfo = lp.Roms[0].Game;
|
||||||
_files = lp.Roms.Select(r => r.RomData).ToList();
|
var rom = lp.Roms[0].RomData;
|
||||||
|
|
||||||
_syncSettings = lp.SyncSettings ?? new ChannelFSyncSettings();
|
_syncSettings = lp.SyncSettings ?? new ChannelFSyncSettings();
|
||||||
region = _syncSettings.Region;
|
_region = _syncSettings.Region;
|
||||||
version = _syncSettings.Version;
|
_version = _syncSettings.Version;
|
||||||
|
|
||||||
MemoryCallbacks = new MemoryCallbackSystem([ "System Bus" ]);
|
MemoryCallbacks = new MemoryCallbackSystem([ "System Bus" ]);
|
||||||
|
|
||||||
ControllerDefinition = ChannelFControllerDefinition;
|
ControllerDefinition = _channelFControllerDefinition.Value;
|
||||||
|
|
||||||
if (version == ConsoleVersion.ChannelF)
|
if (_version == ConsoleVersion.ChannelF)
|
||||||
{
|
{
|
||||||
BIOS01 = CoreComm.CoreFileProvider.GetFirmwareOrThrow(new("ChannelF", "ChannelF_sl131253"));
|
_bios01 = CoreComm.CoreFileProvider.GetFirmwareOrThrow(new("ChannelF", "ChannelF_sl131253"));
|
||||||
BIOS02 = CoreComm.CoreFileProvider.GetFirmwareOrThrow(new("ChannelF", "ChannelF_sl131254"));
|
_bios02 = CoreComm.CoreFileProvider.GetFirmwareOrThrow(new("ChannelF", "ChannelF_sl131254"));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
BIOS01 = CoreComm.CoreFileProvider.GetFirmwareOrThrow(new("ChannelF", "ChannelF_sl90025"));
|
_bios01 = CoreComm.CoreFileProvider.GetFirmwareOrThrow(new("ChannelF", "ChannelF_sl90025"));
|
||||||
BIOS02 = CoreComm.CoreFileProvider.GetFirmwareOrThrow(new("ChannelF", "ChannelF_sl131254"));
|
_bios02 = CoreComm.CoreFileProvider.GetFirmwareOrThrow(new("ChannelF", "ChannelF_sl131254"));
|
||||||
}
|
}
|
||||||
|
|
||||||
Cartridge = VesCartBase.Configure(_gameInfo[0], _files[0]);
|
if (_bios01.Length != 1024 || _bios02.Length != 1024)
|
||||||
|
|
||||||
CPU = new F3850
|
|
||||||
{
|
{
|
||||||
ReadMemory = ReadBus,
|
throw new InvalidOperationException("BIOS must be exactly 1024 bytes!");
|
||||||
WriteMemory = WriteBus,
|
}
|
||||||
ReadHardware = ReadPort,
|
|
||||||
WriteHardware = WritePort,
|
|
||||||
DummyReadMemory = ReadBus
|
|
||||||
};
|
|
||||||
|
|
||||||
_tracer = new TraceBuffer(CPU.TraceHeader);
|
_cartridge = VesCartBase.Configure(gameInfo, rom);
|
||||||
|
|
||||||
//var rom = _files.First();
|
_cpu = new F3850<CpuLink>(new CpuLink(this));
|
||||||
//Array.Copy(rom, 0, Rom, 0, rom.Length);
|
_tracer = new TraceBuffer(_cpu.TraceHeader);
|
||||||
|
|
||||||
CalcClock();
|
CalcClock();
|
||||||
SetupVideo();
|
SetupVideo();
|
||||||
|
|
||||||
ser.Register<IVideoProvider>(this);
|
|
||||||
ser.Register<ITraceable>(_tracer);
|
ser.Register<ITraceable>(_tracer);
|
||||||
ser.Register<IDisassemblable>(CPU);
|
ser.Register<IDisassemblable>(_cpu);
|
||||||
ser.Register<ISoundProvider>(this);
|
|
||||||
ser.Register<IStatable>(new StateSerializer(SyncState));
|
ser.Register<IStatable>(new StateSerializer(SyncState));
|
||||||
SetupMemoryDomains();
|
SetupMemoryDomains();
|
||||||
}
|
}
|
||||||
|
|
||||||
internal CoreComm CoreComm { get; }
|
private CoreComm CoreComm { get; }
|
||||||
|
|
||||||
public List<GameInfo> _gameInfo;
|
private readonly F3850<CpuLink> _cpu;
|
||||||
private readonly List<byte[]> _files;
|
|
||||||
|
|
||||||
public F3850 CPU;
|
|
||||||
private readonly TraceBuffer _tracer;
|
private readonly TraceBuffer _tracer;
|
||||||
public IController _controller;
|
private IController _controller;
|
||||||
|
|
||||||
public VesCartBase Cartridge;
|
private readonly VesCartBase _cartridge;
|
||||||
public RegionType region;
|
private readonly RegionType _region;
|
||||||
public ConsoleVersion version;
|
private readonly ConsoleVersion _version;
|
||||||
|
|
||||||
public bool DriveLightEnabled => Cartridge.HasActivityLED;
|
public bool DriveLightEnabled => _cartridge.HasActivityLED;
|
||||||
|
|
||||||
public bool DriveLightOn => Cartridge.ActivityLED;
|
public bool DriveLightOn => _cartridge.ActivityLED;
|
||||||
|
|
||||||
public string DriveLightIconDescription => "Computer thinking activity";
|
public string DriveLightIconDescription => "Computer thinking activity";
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,8 +5,8 @@
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public partial class ChannelF
|
public partial class ChannelF
|
||||||
{
|
{
|
||||||
public byte[] BIOS01 = new byte[1024];
|
private readonly byte[] _bios01;
|
||||||
public byte[] BIOS02 = new byte[1024];
|
private readonly byte[] _bios02;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Simulates reading a byte of data from the address space
|
/// Simulates reading a byte of data from the address space
|
||||||
|
@ -16,17 +16,17 @@
|
||||||
if (addr < 0x400)
|
if (addr < 0x400)
|
||||||
{
|
{
|
||||||
// BIOS ROM 1
|
// BIOS ROM 1
|
||||||
return BIOS01[addr];
|
return _bios01[addr];
|
||||||
}
|
}
|
||||||
else if (addr < 0x800)
|
else if (addr < 0x800)
|
||||||
{
|
{
|
||||||
// BIOS ROM 2
|
// BIOS ROM 2
|
||||||
return BIOS02[addr - 0x400];
|
return _bios02[addr - 0x400];
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Cartridge Memory Space
|
// Cartridge Memory Space
|
||||||
return Cartridge.ReadBus(addr);
|
return _cartridge.ReadBus(addr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -35,8 +35,6 @@
|
||||||
/// Channel F addressable through the address space)
|
/// Channel F addressable through the address space)
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public void WriteBus(ushort addr, byte value)
|
public void WriteBus(ushort addr, byte value)
|
||||||
{
|
=> _cartridge.WriteBus(addr, value);
|
||||||
Cartridge.WriteBus(addr, value);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,17 +18,16 @@ namespace BizHawk.Emulation.Cores.Consoles.ChannelF
|
||||||
/// Depending on the attached cartridge, there may be additional hardware on the IO bus
|
/// Depending on the attached cartridge, there may be additional hardware on the IO bus
|
||||||
/// All CPU and PSU I/O ports are active-low with output-latches
|
/// All CPU and PSU I/O ports are active-low with output-latches
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public byte[] OutputLatch = new byte[0xFF];
|
private byte[] _outputLatch = new byte[0xFF];
|
||||||
|
|
||||||
public bool LS368Enable;
|
private bool LS368Enable;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// CPU is attempting to read from a port
|
/// CPU is attempting to read from a port
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public byte ReadPort(ushort addr)
|
private byte ReadPort(ushort addr)
|
||||||
{
|
{
|
||||||
var result = 0xFF;
|
int result;
|
||||||
|
|
||||||
switch (addr)
|
switch (addr)
|
||||||
{
|
{
|
||||||
case 0:
|
case 0:
|
||||||
|
@ -38,7 +37,7 @@ namespace BizHawk.Emulation.Cores.Consoles.ChannelF
|
||||||
// b2: HOLD
|
// b2: HOLD
|
||||||
// b3: START
|
// b3: START
|
||||||
// RESET button is connected directly to the RST pin on the CPU (this is handled here in the PollInput() method)
|
// RESET button is connected directly to the RST pin on the CPU (this is handled here in the PollInput() method)
|
||||||
result = (~DataConsole & 0x0F) | OutputLatch[addr];
|
result = (~DataConsole & 0x0F) | _outputLatch[addr];
|
||||||
InputCallbacks.Call();
|
InputCallbacks.Call();
|
||||||
_isLag = false;
|
_isLag = false;
|
||||||
break;
|
break;
|
||||||
|
@ -53,7 +52,7 @@ namespace BizHawk.Emulation.Cores.Consoles.ChannelF
|
||||||
// b4: CCW
|
// b4: CCW
|
||||||
// b5: CW
|
// b5: CW
|
||||||
var v1 = LS368Enable ? DataRight : DataRight | 0xC0;
|
var v1 = LS368Enable ? DataRight : DataRight | 0xC0;
|
||||||
result = (~v1) | OutputLatch[addr];
|
result = ~v1 | _outputLatch[addr];
|
||||||
InputCallbacks.Call();
|
InputCallbacks.Call();
|
||||||
_isLag = false;
|
_isLag = false;
|
||||||
break;
|
break;
|
||||||
|
@ -71,21 +70,22 @@ namespace BizHawk.Emulation.Cores.Consoles.ChannelF
|
||||||
// b6: PULL
|
// b6: PULL
|
||||||
// b7: PUSH
|
// b7: PUSH
|
||||||
var v2 = LS368Enable ? DataLeft : 0xFF;
|
var v2 = LS368Enable ? DataLeft : 0xFF;
|
||||||
result = (~v2) | OutputLatch[addr];
|
result = ~v2 | _outputLatch[addr];
|
||||||
if (LS368Enable)
|
if (LS368Enable)
|
||||||
{
|
{
|
||||||
InputCallbacks.Call();
|
InputCallbacks.Call();
|
||||||
_isLag = false;
|
_isLag = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 5:
|
case 5:
|
||||||
result = OutputLatch[addr];
|
result = _outputLatch[addr];
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
// possible cartridge hardware IO space
|
// possible cartridge hardware IO space
|
||||||
result = (Cartridge.ReadPort(addr));
|
result = _cartridge.ReadPort(addr);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -95,37 +95,37 @@ namespace BizHawk.Emulation.Cores.Consoles.ChannelF
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// CPU is attempting to write to the specified IO port
|
/// CPU is attempting to write to the specified IO port
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public void WritePort(ushort addr, byte value)
|
private void WritePort(ushort addr, byte value)
|
||||||
{
|
{
|
||||||
switch (addr)
|
switch (addr)
|
||||||
{
|
{
|
||||||
case 0:
|
case 0:
|
||||||
OutputLatch[addr] = value;
|
_outputLatch[addr] = value;
|
||||||
LS368Enable = !value.Bit(6);
|
LS368Enable = !value.Bit(6);
|
||||||
if (value.Bit(5))
|
if (value.Bit(5))
|
||||||
{
|
{
|
||||||
// WRT pulse
|
// WRT pulse
|
||||||
// pulse clocks the 74195 parallel access shift register which feeds inputs of 2 NAND gates
|
// pulse clocks the 74195 parallel access shift register which feeds inputs of 2 NAND gates
|
||||||
// writing data to both sets of even and odd VRAM chips (based on the row and column addresses latched into the 7493 ICs)
|
// writing data to both sets of even and odd VRAM chips (based on the row and column addresses latched into the 7493 ICs)
|
||||||
VRAM[((_latch_y) * 0x80) + _latch_x] = (byte)_latch_colour;
|
_vram[_latchY * 0x80 + _latchX] = (byte)_latchColour;
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 1:
|
case 1:
|
||||||
OutputLatch[addr] = value;
|
_outputLatch[addr] = value;
|
||||||
_latch_colour = ((value ^ 0xFF) >> 6) & 0x03;
|
_latchColour = ((value ^ 0xFF) >> 6) & 0x03;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 4:
|
case 4:
|
||||||
OutputLatch[addr] = value;
|
_outputLatch[addr] = value;
|
||||||
_latch_x = (value | 0x80) ^ 0xFF;
|
_latchX = (value | 0x80) ^ 0xFF;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 5:
|
case 5:
|
||||||
OutputLatch[addr] = value;
|
_outputLatch[addr] = value;
|
||||||
_latch_y = (value | 0xC0) ^ 0xFF;
|
_latchY = (value | 0xC0) ^ 0xFF;
|
||||||
var audio = ((value) >> 6) & 0x03;
|
var audio = (value >> 6) & 0x03;
|
||||||
if (audio != _tone)
|
if (audio != _tone)
|
||||||
{
|
{
|
||||||
_tone = audio;
|
_tone = audio;
|
||||||
|
@ -136,7 +136,7 @@ namespace BizHawk.Emulation.Cores.Consoles.ChannelF
|
||||||
|
|
||||||
default:
|
default:
|
||||||
// possible write to cartridge hardware
|
// possible write to cartridge hardware
|
||||||
Cartridge.WritePort(addr, value);
|
_cartridge.WritePort(addr, value);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue