[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>
|
||||
/// Disassembler
|
||||
/// </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)
|
||||
{
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
namespace BizHawk.Emulation.Cores.Components.FairchildF8
|
||||
{
|
||||
public sealed partial class F3850
|
||||
public sealed partial class F3850<TLink>
|
||||
{
|
||||
public const int MaxInstructionLength = 48;
|
||||
|
||||
|
|
|
@ -5,21 +5,21 @@ namespace BizHawk.Emulation.Cores.Components.FairchildF8
|
|||
/// <summary>
|
||||
/// ALU Operations
|
||||
/// </summary>
|
||||
public sealed partial class F3850
|
||||
public sealed partial class F3850<TLink>
|
||||
{
|
||||
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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
Regs[dest] = ReadHardware(Regs[src]);
|
||||
Regs[dest] = _link.ReadHardware(Regs[src]);
|
||||
}
|
||||
|
||||
/// <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)
|
||||
// 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()
|
||||
|
|
|
@ -7,7 +7,7 @@ namespace BizHawk.Emulation.Cores.Components.FairchildF8
|
|||
/// <summary>
|
||||
/// Internal Registers
|
||||
/// </summary>
|
||||
public sealed partial class F3850
|
||||
public sealed partial class F3850<TLink>
|
||||
{
|
||||
/// <summary>
|
||||
/// Registers (counters and scratchpad)
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
/// <summary>
|
||||
/// Vectors of Instruction Operations
|
||||
/// </summary>
|
||||
public sealed partial class F3850
|
||||
public sealed partial class F3850<TLink>
|
||||
{
|
||||
/// <summary>
|
||||
/// 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
|
||||
/// </summary>
|
||||
public sealed partial class F3850
|
||||
public sealed partial class F3850<TLink> where TLink : IF3850Link
|
||||
{
|
||||
// operations that can take place in an instruction
|
||||
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_LIS = 158;
|
||||
|
||||
public F3850()
|
||||
private readonly TLink _link;
|
||||
|
||||
public F3850(TLink link)
|
||||
{
|
||||
_link = link;
|
||||
Reset();
|
||||
}
|
||||
|
||||
|
@ -133,36 +136,6 @@ namespace BizHawk.Emulation.Cores.Components.FairchildF8
|
|||
|
||||
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>
|
||||
/// Runs a single CPU clock cycle
|
||||
/// </summary>
|
||||
|
@ -180,7 +153,7 @@ namespace BizHawk.Emulation.Cores.Components.FairchildF8
|
|||
{
|
||||
// always the last tick within an opcode instruction cycle
|
||||
case END:
|
||||
OnExecFetch?.Invoke(RegPC0);
|
||||
_link.OnExecFetch(RegPC0);
|
||||
TraceCallback?.Invoke(State());
|
||||
opcode = Regs[DB];
|
||||
instr_pntr = 0;
|
||||
|
@ -785,12 +758,12 @@ namespace BizHawk.Emulation.Cores.Components.FairchildF8
|
|||
{
|
||||
int bytes_read = 0;
|
||||
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;
|
||||
|
||||
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))
|
||||
{
|
||||
byte_code += " ";
|
||||
|
@ -868,7 +841,7 @@ namespace BizHawk.Emulation.Cores.Components.FairchildF8
|
|||
|
||||
public void SyncState(Serializer ser)
|
||||
{
|
||||
ser.BeginSection(nameof(F3850));
|
||||
ser.BeginSection("F3850");
|
||||
ser.Sync(nameof(Regs), ref Regs, false);
|
||||
ser.Sync(nameof(cur_instr), ref cur_instr, false);
|
||||
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>
|
||||
/// Hangman ChannelF Cartridge
|
||||
/// 2KB ROM / NO RAM
|
||||
/// Utilises 2102 SRAM over IO
|
||||
/// </summary>
|
||||
public class mapper_HANG : VesCartBase
|
||||
public class MapperHANG : VesCartBase
|
||||
{
|
||||
public override string BoardType => "HANG";
|
||||
|
||||
public mapper_HANG(byte[] rom)
|
||||
public MapperHANG(byte[] rom)
|
||||
{
|
||||
ROM = new byte[0x10000 - 0x800];
|
||||
for (int i = 0; i < rom.Length; i++)
|
||||
{
|
||||
ROM[i] = rom[i];
|
||||
if (i > 3000)
|
||||
{
|
||||
var test = rom[i];
|
||||
}
|
||||
}
|
||||
|
||||
RAM = new byte[0x400];
|
||||
_rom = new byte[0x10000 - 0x800];
|
||||
Array.Copy(rom, _rom, rom.Length);
|
||||
_rom.AsSpan(rom.Length).Fill(0xFF);
|
||||
_ram = new byte[0x400];
|
||||
}
|
||||
|
||||
public override byte ReadBus(ushort addr)
|
||||
{
|
||||
var off = addr - 0x800;
|
||||
return ROM[off];
|
||||
return _rom[off];
|
||||
}
|
||||
|
||||
public override void WriteBus(ushort addr, byte value)
|
||||
{
|
||||
// no writeable memory
|
||||
// no directly writeable memory
|
||||
}
|
||||
|
||||
public override byte ReadPort(ushort addr)
|
||||
|
@ -45,6 +38,5 @@
|
|||
var index = addr - 0x20;
|
||||
SRAM2102_Write(index, data);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -1,27 +1,25 @@
|
|||
namespace BizHawk.Emulation.Cores.Consoles.ChannelF
|
||||
{
|
||||
/// <summary>
|
||||
/// ChannelF Cartridge that utilises 2102 SRAM over IO
|
||||
/// Maze ChannelF Cartridge
|
||||
/// Utilises 2102 SRAM over IO
|
||||
/// </summary>
|
||||
public class mapper_MAZE : VesCartBase
|
||||
public class MapperMAZE : VesCartBase
|
||||
{
|
||||
public override string BoardType => "MAZE";
|
||||
|
||||
public mapper_MAZE(byte[] rom)
|
||||
public MapperMAZE(byte[] rom)
|
||||
{
|
||||
ROM = new byte[0x10000 - 0x800];
|
||||
for (int i = 0; i < rom.Length; i++)
|
||||
{
|
||||
ROM[i] = rom[i];
|
||||
}
|
||||
|
||||
RAM = new byte[0x400];
|
||||
_rom = new byte[0x10000 - 0x800];
|
||||
Array.Copy(rom, _rom, rom.Length);
|
||||
_rom.AsSpan(rom.Length).Fill(0xFF);
|
||||
_ram = new byte[0x400];
|
||||
}
|
||||
|
||||
public override byte ReadBus(ushort addr)
|
||||
{
|
||||
var off = addr - 0x800;
|
||||
return ROM[off];
|
||||
return _rom[off];
|
||||
}
|
||||
|
||||
public override void WriteBus(ushort addr, byte value)
|
||||
|
@ -38,7 +36,7 @@
|
|||
public override void WritePort(ushort addr, byte data)
|
||||
{
|
||||
var index = addr - 0x24;
|
||||
SRAM2102_Write(index, data);
|
||||
SRAM2102_Write(index, data);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -3,19 +3,15 @@
|
|||
/// <summary>
|
||||
/// Sean Riddle's modified SCHACH cart mapper (multi-cart) (WIP)
|
||||
/// </summary>
|
||||
public class mapper_RIDDLE : VesCartBase
|
||||
public class MapperRIDDLE : VesCartBase
|
||||
{
|
||||
public override string BoardType => "RIDDLE";
|
||||
|
||||
public mapper_RIDDLE(byte[] rom)
|
||||
public MapperRIDDLE(byte[] rom)
|
||||
{
|
||||
ROM = new byte[rom.Length];
|
||||
for (int i = 0; i < rom.Length; i++)
|
||||
{
|
||||
ROM[i] = rom[i];
|
||||
}
|
||||
|
||||
RAM = new byte[0x800];
|
||||
_rom = new byte[rom.Length];
|
||||
Array.Copy(rom, _rom, rom.Length);
|
||||
_ram = new byte[0x800];
|
||||
}
|
||||
|
||||
public override byte ReadBus(ushort addr)
|
||||
|
@ -23,15 +19,15 @@
|
|||
var result = 0xFF;
|
||||
var off = addr - 0x800;
|
||||
|
||||
if (addr >= 0x2800 && addr < 0x3000)
|
||||
if (addr is >= 0x2800 and < 0x3000)
|
||||
{
|
||||
// 2KB RAM
|
||||
result = RAM[addr - 0x2800];
|
||||
result = _ram[addr - 0x2800];
|
||||
}
|
||||
else
|
||||
{
|
||||
if (off < ROM.Length)
|
||||
result = ROM[off + (MultiBank * 0x2000) + (MultiHalfBank * 0x1000)];
|
||||
if (off < _rom.Length)
|
||||
result = _rom[off + (MultiBank * 0x2000) + (MultiHalfBank * 0x1000)];
|
||||
}
|
||||
|
||||
return (byte)result;
|
||||
|
@ -40,9 +36,9 @@
|
|||
public override void WriteBus(ushort addr, byte value)
|
||||
{
|
||||
// 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)
|
||||
{
|
||||
|
@ -50,16 +46,10 @@
|
|||
MultiBank = value & 0x1F;
|
||||
MultiHalfBank = (value & 0x20) >> 5;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public override byte ReadPort(ushort addr)
|
||||
{
|
||||
return 0xFF;
|
||||
}
|
||||
=> 0xFF;
|
||||
|
||||
public override void WritePort(ushort addr, byte data)
|
||||
{
|
|
@ -5,48 +5,42 @@
|
|||
/// Any size ROM / 2KB RAM mapped at 0x2800 - 0x2FFF
|
||||
/// Info here: http://www.seanriddle.com/chanfmulti.html
|
||||
/// </summary>
|
||||
public class mapper_SCHACH : VesCartBase
|
||||
public class MapperSCHACH : VesCartBase
|
||||
{
|
||||
public override string BoardType => "SCHACH";
|
||||
public override bool HasActivityLED => true;
|
||||
public override string ActivityLEDDescription => "Chess Brain Thinking Activity";
|
||||
|
||||
public mapper_SCHACH(byte[] rom)
|
||||
public MapperSCHACH(byte[] rom)
|
||||
{
|
||||
ROM = new byte[0x10000 - 0x800];
|
||||
for (int i = 0; i < rom.Length; i++)
|
||||
{
|
||||
ROM[i] = rom[i];
|
||||
}
|
||||
|
||||
RAM = new byte[0x800];
|
||||
_rom = new byte[0x10000 - 0x800];
|
||||
Array.Copy(rom, _rom, rom.Length);
|
||||
_rom.AsSpan(rom.Length).Fill(0xFF);
|
||||
_ram = new byte[0x800];
|
||||
}
|
||||
|
||||
public override byte ReadBus(ushort addr)
|
||||
{
|
||||
var result = 0xFF;
|
||||
var off = addr - 0x800;
|
||||
|
||||
if (addr >= 0x2800 && addr < 0x3000)
|
||||
byte result;
|
||||
if (addr is >= 0x2800 and < 0x3000)
|
||||
{
|
||||
// 2KB RAM
|
||||
result = RAM[addr - 0x2800];
|
||||
result = _ram[addr - 0x2800];
|
||||
}
|
||||
else
|
||||
{
|
||||
if (off < ROM.Length)
|
||||
result = ROM[off];
|
||||
result = _rom[addr - 0x800];
|
||||
}
|
||||
|
||||
return (byte)result;
|
||||
return result;
|
||||
}
|
||||
|
||||
public override void WriteBus(ushort addr, byte value)
|
||||
{
|
||||
// 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)
|
||||
{
|
||||
|
@ -59,9 +53,7 @@
|
|||
}
|
||||
|
||||
public override byte ReadPort(ushort addr)
|
||||
{
|
||||
return 0xFF;
|
||||
}
|
||||
=> 0xFF;
|
||||
|
||||
public override void WritePort(ushort addr, byte data)
|
||||
{
|
|
@ -4,28 +4,22 @@
|
|||
/// Standard ChannelF Cartridge
|
||||
/// 2KB ROM / NO RAM
|
||||
/// </summary>
|
||||
public class mapper_STD : VesCartBase
|
||||
public class MapperSTD : VesCartBase
|
||||
{
|
||||
public override string BoardType => "STD";
|
||||
|
||||
public mapper_STD(byte[] rom)
|
||||
public MapperSTD(byte[] rom)
|
||||
{
|
||||
ROM = new byte[0x10000 - 0x800];
|
||||
for (int i = 0; i < rom.Length; i++)
|
||||
{
|
||||
ROM[i] = rom[i];
|
||||
}
|
||||
|
||||
RAM = new byte[0];
|
||||
_rom = new byte[0x10000 - 0x800];
|
||||
Array.Copy(rom, _rom, rom.Length);
|
||||
_rom.AsSpan(rom.Length).Fill(0xFF);
|
||||
_ram = [ ];
|
||||
}
|
||||
|
||||
public override byte ReadBus(ushort addr)
|
||||
{
|
||||
var off = addr - 0x800;
|
||||
if (off < ROM.Length)
|
||||
return ROM[off];
|
||||
else
|
||||
return 0xFF;
|
||||
return _rom[off];
|
||||
}
|
||||
|
||||
public override void WriteBus(ushort addr, byte value)
|
||||
|
@ -34,9 +28,7 @@
|
|||
}
|
||||
|
||||
public override byte ReadPort(ushort addr)
|
||||
{
|
||||
return 0xFF;
|
||||
}
|
||||
=> 0xFF;
|
||||
|
||||
public override void WritePort(ushort addr, byte data)
|
||||
{
|
|
@ -8,7 +8,7 @@ namespace BizHawk.Emulation.Cores.Consoles.ChannelF
|
|||
{
|
||||
public abstract class VesCartBase
|
||||
{
|
||||
public abstract string BoardType { get; }
|
||||
public abstract string BoardType { get; }
|
||||
|
||||
public virtual void SyncByteArrayDomain(ChannelF sys)
|
||||
{
|
||||
|
@ -19,23 +19,11 @@ namespace BizHawk.Emulation.Cores.Consoles.ChannelF
|
|||
}
|
||||
}
|
||||
|
||||
public virtual byte[] ROM
|
||||
{
|
||||
get { return _rom; }
|
||||
protected set { _rom = value; }
|
||||
}
|
||||
protected byte[] _rom;
|
||||
|
||||
public virtual byte[] RAM
|
||||
{
|
||||
get { return _ram; }
|
||||
protected set { _ram = value; }
|
||||
}
|
||||
protected byte[] _rom;
|
||||
protected byte[] _ram;
|
||||
|
||||
public virtual bool HasActivityLED { get; set; }
|
||||
public virtual string ActivityLEDDescription { get; set; }
|
||||
|
||||
|
||||
public bool ActivityLED;
|
||||
public int MultiBank;
|
||||
|
@ -58,38 +46,36 @@ namespace BizHawk.Emulation.Cores.Consoles.ChannelF
|
|||
public static VesCartBase Configure(GameInfo gi, byte[] rom)
|
||||
{
|
||||
// get board type
|
||||
string boardStr = gi.OptionPresent("board") ? gi.GetStringValue("board") : "STD";
|
||||
|
||||
var boardStr = gi.OptionPresent("board") ? gi.GetStringValue("board") : "STD";
|
||||
switch (boardStr)
|
||||
{
|
||||
// The supplied ROM is actually a 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
|
||||
// (hockey and tennis)
|
||||
return new mapper_STD(rom);
|
||||
return new MapperSTD(rom);
|
||||
|
||||
// standard cart layout
|
||||
case "STD":
|
||||
case "STD":
|
||||
// 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
|
||||
return new mapper_STD(rom);
|
||||
return new MapperSTD(rom);
|
||||
|
||||
case "MAZE":
|
||||
return new mapper_MAZE(rom);
|
||||
return new MapperMAZE(rom);
|
||||
|
||||
case "RIDDLE":
|
||||
// Sean Riddle's modified SCHACH multi-cart
|
||||
return new mapper_RIDDLE(rom);
|
||||
return new MapperRIDDLE(rom);
|
||||
|
||||
case "SCHACH":
|
||||
default:
|
||||
// F3853 Memory Interface Chip, 6KB of ROM and 2KB of RAM
|
||||
// - default to this
|
||||
return new mapper_SCHACH(rom);
|
||||
return new MapperSCHACH(rom);
|
||||
|
||||
case "HANG":
|
||||
|
||||
return new mapper_HANG(rom);
|
||||
return new MapperHANG(rom);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -106,7 +92,7 @@ namespace BizHawk.Emulation.Cores.Consoles.ChannelF
|
|||
if (m_read_write == 0)
|
||||
{
|
||||
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));
|
||||
}
|
||||
|
||||
|
@ -141,8 +127,8 @@ namespace BizHawk.Emulation.Cores.Consoles.ChannelF
|
|||
|
||||
if (m_read_write == 1)
|
||||
{
|
||||
RAM[m_addr] = (byte)m_data0;
|
||||
}
|
||||
_ram[m_addr] = (byte)m_data0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -171,7 +157,7 @@ namespace BizHawk.Emulation.Cores.Consoles.ChannelF
|
|||
b.CopyTo(resBytes, 0);
|
||||
m_addr_latch = (ushort)(resBytes[0] | resBytes[1] << 8);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public virtual void Reset()
|
||||
{
|
||||
|
@ -187,7 +173,7 @@ namespace BizHawk.Emulation.Cores.Consoles.ChannelF
|
|||
public virtual void SyncState(Serializer ser)
|
||||
{
|
||||
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_addr_latch), ref m_addr_latch);
|
||||
ser.Sync(nameof(m_addr), ref m_addr);
|
||||
|
|
|
@ -1,117 +1,116 @@
|
|||
using System.Collections.Generic;
|
||||
|
||||
using BizHawk.Emulation.Common;
|
||||
using BizHawk.Emulation.Common;
|
||||
|
||||
namespace BizHawk.Emulation.Cores.Consoles.ChannelF
|
||||
{
|
||||
public partial class ChannelF
|
||||
{
|
||||
public ControllerDefinition ChannelFControllerDefinition
|
||||
private static readonly Lazy<ControllerDefinition> _channelFControllerDefinition = new(() =>
|
||||
{
|
||||
get
|
||||
ControllerDefinition definition = new("ChannelF Controller");
|
||||
|
||||
// sticks
|
||||
|
||||
const string P1_PREFIX = "P1 ";
|
||||
string[] stickR =
|
||||
[
|
||||
// P1 (right) stick
|
||||
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)
|
||||
{
|
||||
ControllerDefinition definition = new("ChannelF Controller");
|
||||
|
||||
string pre = "P1 ";
|
||||
|
||||
// sticks
|
||||
var stickR = new List<string>
|
||||
{
|
||||
// P1 (right) stick
|
||||
pre + "Forward", pre + "Back", pre + "Left", pre + "Right", pre + "CCW", pre + "CW", pre + "Pull", pre + "Push"
|
||||
};
|
||||
|
||||
foreach (var s in stickR)
|
||||
{
|
||||
definition.BoolButtons.Add(s);
|
||||
definition.CategoryLabels[s] = "Right Controller";
|
||||
}
|
||||
|
||||
pre = "P2 ";
|
||||
|
||||
var stickL = new List<string>
|
||||
{
|
||||
// P2 (left) stick
|
||||
pre + "Forward", pre + "Back", pre + "Left", pre + "Right", pre + "CCW", pre + "CW", pre + "Pull", pre + "Push"
|
||||
};
|
||||
|
||||
foreach (var s in stickL)
|
||||
{
|
||||
definition.BoolButtons.Add(s);
|
||||
definition.CategoryLabels[s] = "Left Controller";
|
||||
}
|
||||
|
||||
// console
|
||||
var consoleButtons = new List<string>
|
||||
{
|
||||
"TIME", "MODE", "HOLD", "START", "RESET"
|
||||
};
|
||||
|
||||
foreach (var s in consoleButtons)
|
||||
{
|
||||
definition.BoolButtons.Add(s);
|
||||
definition.CategoryLabels[s] = "Console";
|
||||
}
|
||||
|
||||
return definition.MakeImmutable();
|
||||
definition.BoolButtons.Add(s);
|
||||
definition.CategoryLabels[s] = "Right Controller";
|
||||
}
|
||||
}
|
||||
|
||||
public bool[] StateConsole = new bool[5];
|
||||
public string[] ButtonsConsole =
|
||||
{
|
||||
const string P2_PREFIX = "P2 ";
|
||||
string[] stickL =
|
||||
[
|
||||
// P2 (left) stick
|
||||
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)
|
||||
{
|
||||
definition.BoolButtons.Add(s);
|
||||
definition.CategoryLabels[s] = "Left Controller";
|
||||
}
|
||||
|
||||
// console
|
||||
string[] consoleButtons =
|
||||
[
|
||||
"TIME", "MODE", "HOLD", "START", "RESET"
|
||||
];
|
||||
|
||||
foreach (var s in consoleButtons)
|
||||
{
|
||||
definition.BoolButtons.Add(s);
|
||||
definition.CategoryLabels[s] = "Console";
|
||||
}
|
||||
|
||||
return definition.MakeImmutable();
|
||||
});
|
||||
|
||||
private readonly string[] _buttonsConsole =
|
||||
[
|
||||
"TIME", "MODE", "HOLD", "START", "RESET"
|
||||
};
|
||||
];
|
||||
|
||||
public byte DataConsole
|
||||
private bool[] _stateConsole = new bool[5];
|
||||
|
||||
private byte DataConsole
|
||||
{
|
||||
get
|
||||
{
|
||||
int w = 0;
|
||||
for (int i = 0; i < 5; i++)
|
||||
var w = 0;
|
||||
for (var i = 0; i < 5; i++)
|
||||
{
|
||||
byte mask = (byte) (1 << i);
|
||||
w = StateConsole[i] ? w | mask : w & ~mask;
|
||||
var mask = (byte)(1 << i);
|
||||
w = _stateConsole[i] ? w | mask : w & ~mask;
|
||||
}
|
||||
|
||||
return (byte)(w & 0xFF);
|
||||
}
|
||||
}
|
||||
|
||||
public bool[] StateRight = new bool[8];
|
||||
public string[] ButtonsRight =
|
||||
{
|
||||
"Right", "Left", "Back", "Forward", "CCW", "CW", "Pull", "Push"
|
||||
};
|
||||
public byte DataRight
|
||||
private bool[] _stateRight = new bool[8];
|
||||
|
||||
private readonly string[] _buttonsRight =
|
||||
[
|
||||
"P1 Right", "P1 Left", "P1 Back", "P1 Forward", "P1 CCW", "P1 CW", "P1 Pull", "P1 Push"
|
||||
];
|
||||
|
||||
private byte DataRight
|
||||
{
|
||||
get
|
||||
{
|
||||
int w = 0;
|
||||
for (int i = 0; i < 8; i++)
|
||||
var w = 0;
|
||||
for (var i = 0; i < 8; i++)
|
||||
{
|
||||
byte mask = (byte)(1 << i);
|
||||
w = StateRight[i] ? w | mask : w & ~mask;
|
||||
var mask = (byte)(1 << i);
|
||||
w = _stateRight[i] ? w | mask : w & ~mask;
|
||||
}
|
||||
|
||||
return (byte)(w & 0xFF);
|
||||
}
|
||||
}
|
||||
|
||||
public bool[] StateLeft = new bool[8];
|
||||
public string[] ButtonsLeft =
|
||||
{
|
||||
"Right", "Left", "Back", "Forward", "CCW", "CW", "Pull", "Push"
|
||||
};
|
||||
public byte DataLeft
|
||||
private bool[] _stateLeft = new bool[8];
|
||||
|
||||
private readonly string[] _buttonsLeft =
|
||||
[
|
||||
"P2 Right", "P2 Left", "P2 Back", "P2 Forward", "P2 CCW", "P2 CW", "P2 Pull", "P2 Push"
|
||||
];
|
||||
|
||||
private byte DataLeft
|
||||
{
|
||||
get
|
||||
{
|
||||
int w = 0;
|
||||
for (int i = 0; i < 8; i++)
|
||||
var w = 0;
|
||||
for (var i = 0; i < 8; i++)
|
||||
{
|
||||
byte mask = (byte)(1 << i);
|
||||
w = StateLeft[i] ? w | mask : w & ~mask;
|
||||
var mask = (byte)(1 << i);
|
||||
w = _stateLeft[i] ? w | mask : w & ~mask;
|
||||
}
|
||||
|
||||
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 IDictionary<string, RegisterValue> GetCpuFlagsAndRegisters()
|
||||
=> CPU.GetCpuFlagsAndRegisters();
|
||||
=> _cpu.GetCpuFlagsAndRegisters();
|
||||
|
||||
public void SetCpuRegister(string register, int value)
|
||||
=> CPU.SetCpuRegister(register, value);
|
||||
=> _cpu.SetCpuRegister(register, value);
|
||||
|
||||
public IMemoryCallbackSystem MemoryCallbacks { get; }
|
||||
|
||||
|
@ -19,6 +19,6 @@ namespace BizHawk.Emulation.Cores.Consoles.ChannelF
|
|||
[FeatureNotImplemented]
|
||||
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 ControllerDefinition ControllerDefinition { get; set; }
|
||||
public ControllerDefinition ControllerDefinition { get; }
|
||||
|
||||
public string SystemId => VSystemID.Raw.ChannelF;
|
||||
|
||||
public bool DeterministicEmulation { get; set; }
|
||||
public bool DeterministicEmulation => true;
|
||||
|
||||
public int CpuClocksPerFrame;
|
||||
public int FrameClock;
|
||||
private int _cpuClocksPerFrame;
|
||||
private int _frameClock;
|
||||
|
||||
private void CalcClock()
|
||||
{
|
||||
// CPU speeds from https://en.wikipedia.org/wiki/Fairchild_Channel_F
|
||||
// also https://github.com/mamedev/mame/blob/c8192c898ce7f68c0c0b87e44199f0d3e710439b/src/mame/drivers/channelf.cpp
|
||||
double cpuFreq, pixelClock;
|
||||
int pixelClocksPerFrame;
|
||||
if (Region == DisplayType.NTSC)
|
||||
{
|
||||
HTotal = 256;
|
||||
|
@ -37,8 +36,7 @@ namespace BizHawk.Emulation.Cores.Consoles.ChannelF
|
|||
cpuFreq = NTSC_COLORBURST / 2;
|
||||
// NTSC pixel clock is NTSC Colorburst * 8 / 7
|
||||
pixelClock = NTSC_COLORBURST * 8 / 7;
|
||||
// NTSC refresh rate is (pixelclock * 8 / 7) / (256 * 264)
|
||||
pixelClocksPerFrame = 256 * 264;
|
||||
// NTSC refresh rate is (pixelclock * 8 / 7) / (HTotal * VTotal)
|
||||
// (aka (1023750000 * 8) / (256 * 264 * 286 * 7)
|
||||
// reduced to 234375 / 3872
|
||||
VsyncNumerator = 234375;
|
||||
|
@ -55,19 +53,18 @@ namespace BizHawk.Emulation.Cores.Consoles.ChannelF
|
|||
ScanlineRepeats = 5;
|
||||
PixelWidth = 2;
|
||||
|
||||
if (version == ConsoleVersion.ChannelF)
|
||||
if (_version == ConsoleVersion.ChannelF)
|
||||
{
|
||||
// PAL CPU speed is 2MHz
|
||||
cpuFreq = 2000000;
|
||||
// PAL pixel clock is 4MHz
|
||||
pixelClock = 4000000;
|
||||
// PAL refresh rate is pixelclock / (256 * 312)
|
||||
pixelClocksPerFrame = 256 * 312;
|
||||
// PAL refresh rate is pixelclock / (HTotal * VTotal)
|
||||
// reduced to 15625 / 312
|
||||
VsyncNumerator = 15625;
|
||||
VsyncDenominator = 312;
|
||||
}
|
||||
else if (version == ConsoleVersion.ChannelF_II)
|
||||
else if (_version == ConsoleVersion.ChannelF_II)
|
||||
{
|
||||
// PAL CPU speed for gen 2 seems to be contested
|
||||
// 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
|
||||
// presumingly, it's just cpuFreq * 2?
|
||||
pixelClock = PAL_COLORBURST * 8 / 9;
|
||||
// PAL refresh rate is pixelclock / (256 * 312)
|
||||
pixelClocksPerFrame = 256 * 312;
|
||||
// PAL refresh rate is pixelclock / (HTotal * VTotal)
|
||||
// (aka (4433618.75 * 8) / (256 * 312 * 9)
|
||||
// reduced to 17734475 / 359424
|
||||
VsyncNumerator = 17734475;
|
||||
|
@ -94,10 +90,12 @@ namespace BizHawk.Emulation.Cores.Consoles.ChannelF
|
|||
}
|
||||
}
|
||||
|
||||
var c = cpuFreq * pixelClocksPerFrame / pixelClock;
|
||||
CpuClocksPerFrame = (int) c;
|
||||
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();
|
||||
}
|
||||
|
@ -109,22 +107,22 @@ namespace BizHawk.Emulation.Cores.Consoles.ChannelF
|
|||
|
||||
if (_tracer.IsEnabled())
|
||||
{
|
||||
CPU.TraceCallback = s => _tracer.Put(s);
|
||||
_cpu.TraceCallback = s => _tracer.Put(s);
|
||||
}
|
||||
else
|
||||
{
|
||||
CPU.TraceCallback = null;
|
||||
_cpu.TraceCallback = null;
|
||||
}
|
||||
|
||||
PollInput();
|
||||
|
||||
while (FrameClock++ < CpuClocksPerFrame)
|
||||
while (_frameClock++ < _cpuClocksPerFrame)
|
||||
{
|
||||
CPU.ExecuteOne();
|
||||
_cpu.ExecuteOne();
|
||||
ClockVideo();
|
||||
}
|
||||
|
||||
FrameClock = 0;
|
||||
_frameClock = 0;
|
||||
_frame++;
|
||||
|
||||
if (_isLag)
|
||||
|
@ -134,10 +132,6 @@ namespace BizHawk.Emulation.Cores.Consoles.ChannelF
|
|||
}
|
||||
|
||||
private int _frame;
|
||||
#pragma warning disable CS0414
|
||||
//private int _lagcount;
|
||||
//private bool _islag;
|
||||
#pragma warning restore CS0414
|
||||
|
||||
public void ResetCounters()
|
||||
{
|
||||
|
@ -154,8 +148,8 @@ namespace BizHawk.Emulation.Cores.Consoles.ChannelF
|
|||
|
||||
private void ConsoleReset()
|
||||
{
|
||||
CPU.Reset();
|
||||
Cartridge.Reset();
|
||||
_cpu.Reset();
|
||||
_cartridge.Reset();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -25,38 +25,6 @@ namespace BizHawk.Emulation.Cores.Consoles.ChannelF
|
|||
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
|
||||
{
|
||||
NTSC,
|
||||
|
@ -68,5 +36,28 @@ namespace BizHawk.Emulation.Cores.Consoles.ChannelF
|
|||
ChannelF,
|
||||
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);
|
||||
// TODO: more precise audio clocking
|
||||
_cyclesPerSample = CpuClocksPerFrame / (double)_samplesPerFrame;
|
||||
_cyclesPerSample = _cpuClocksPerFrame / (double)_samplesPerFrame;
|
||||
_sampleBuffer = new short[_samplesPerFrame];
|
||||
_filteredSampleBuffer = new double[_samplesPerFrame];
|
||||
_toneBuffer = new int[_samplesPerFrame];
|
||||
|
@ -37,8 +37,7 @@ namespace BizHawk.Emulation.Cores.Consoles.ChannelF
|
|||
|
||||
private void AudioChange()
|
||||
{
|
||||
var currSample = (int)(FrameClock / _cyclesPerSample);
|
||||
|
||||
var currSample = (int)(_frameClock / _cyclesPerSample);
|
||||
while (currSample < _samplesPerFrame)
|
||||
{
|
||||
_toneBuffer[currSample++] = _tone;
|
||||
|
@ -130,7 +129,7 @@ namespace BizHawk.Emulation.Cores.Consoles.ChannelF
|
|||
for (var i = 2; i < samples.Length; i++)
|
||||
{
|
||||
filteredSamples[i] = (b0 / a0) * samples[i] + (b1 / a0) * samples[i - 1] + (b2 / a0) * samples[i - 2]
|
||||
- (a1 / a0) * filteredSamples[i - 1] - (a2 / a0) * filteredSamples[i - 2];
|
||||
- (a1 / a0) * filteredSamples[i - 1] - (a2 / a0) * filteredSamples[i - 2];
|
||||
}
|
||||
|
||||
for (var i = 0; i < samples.Length; i++)
|
||||
|
@ -150,9 +149,7 @@ namespace BizHawk.Emulation.Cores.Consoles.ChannelF
|
|||
}
|
||||
|
||||
public void GetSamplesAsync(short[] samples)
|
||||
{
|
||||
throw new NotSupportedException("Async is not available");
|
||||
}
|
||||
=> throw new NotSupportedException("Async is not available");
|
||||
|
||||
public void DiscardSamples()
|
||||
{
|
||||
|
@ -166,7 +163,7 @@ namespace BizHawk.Emulation.Cores.Consoles.ChannelF
|
|||
|
||||
public void GetSamplesSync(out short[] samples, out int nsamp)
|
||||
{
|
||||
// process tone buffer
|
||||
// process tone buffer
|
||||
for (var t = 0; t < _toneBuffer.Length; t++)
|
||||
{
|
||||
var tValue = _toneBuffer[t];
|
||||
|
@ -189,7 +186,7 @@ namespace BizHawk.Emulation.Cores.Consoles.ChannelF
|
|||
_currTone = tValue;
|
||||
|
||||
if (_rampCounter <= 0)
|
||||
_sampleBuffer[t] = (short)((GetWaveSample(_samplePosition++, _currTone) * _amplitude) / 30);
|
||||
_sampleBuffer[t] = (short)((GetWaveSample(_samplePosition++, _currTone) * _amplitude) / 30);
|
||||
}
|
||||
}
|
||||
else if (_currTone > 0)
|
||||
|
|
|
@ -7,14 +7,14 @@ namespace BizHawk.Emulation.Cores.Consoles.ChannelF
|
|||
private void SyncState(Serializer ser)
|
||||
{
|
||||
ser.BeginSection("ChannelF");
|
||||
ser.Sync(nameof(VRAM), ref VRAM, false);
|
||||
ser.Sync(nameof(_latch_colour), ref _latch_colour);
|
||||
ser.Sync(nameof(_latch_x), ref _latch_x);
|
||||
ser.Sync(nameof(_latch_y), ref _latch_y);
|
||||
ser.Sync(nameof(_pixelClockCounter), ref _pixelClockCounter);
|
||||
ser.Sync(nameof(_vram), ref _vram, false);
|
||||
ser.Sync(nameof(_latchColour), ref _latchColour);
|
||||
ser.Sync(nameof(_latchX), ref _latchX);
|
||||
ser.Sync(nameof(_latchY), ref _latchY);
|
||||
ser.Sync(nameof(_pixelClockCounter), ref _pixelClockCounter);
|
||||
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(_isLag), ref _isLag);
|
||||
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(_samplePosition), ref _samplePosition);
|
||||
|
||||
ser.Sync(nameof(StateConsole), ref StateConsole, false);
|
||||
ser.Sync(nameof(StateRight), ref StateRight, false);
|
||||
ser.Sync(nameof(StateLeft), ref StateLeft, false);
|
||||
ser.Sync(nameof(_stateConsole), ref _stateConsole, false);
|
||||
ser.Sync(nameof(_stateRight), ref _stateRight, 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(ControllersEnabled), ref ControllersEnabled);
|
||||
CPU.SyncState(ser);
|
||||
Cartridge.SyncState(ser);
|
||||
_cpu.SyncState(ser);
|
||||
_cartridge.SyncState(ser);
|
||||
ser.EndSection();
|
||||
|
||||
if (ser.IsReader)
|
||||
{
|
||||
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,41 +8,38 @@ namespace BizHawk.Emulation.Cores.Consoles.ChannelF
|
|||
/// <summary>
|
||||
/// 128x64 pixels - 8192x2bits (2 KB)
|
||||
/// 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>
|
||||
public byte[] VRAM = new byte[128 * 64];
|
||||
|
||||
private byte[] _vram = new byte[128 * 64];
|
||||
|
||||
public static readonly int[] FPalette =
|
||||
{
|
||||
//0x101010, 0xFDFDFD, 0x5331FF, 0x5DCC02, 0xF33F4B, 0xE0E0E0, 0xA6FF91, 0xD0CEFF
|
||||
|
||||
Colors.ARGB(0x10, 0x10, 0x10), // Black
|
||||
Colors.ARGB(0xFD, 0xFD, 0xFD), // White
|
||||
Colors.ARGB(0xFF, 0x31, 0x53), // Red
|
||||
Colors.ARGB(0x02, 0xCC, 0x5D), // Green
|
||||
Colors.ARGB(0x4B, 0x3F, 0xF3), // Blue
|
||||
Colors.ARGB(0xE0, 0xE0, 0xE0), // Gray
|
||||
Colors.ARGB(0x91, 0xFF, 0xA6), // BGreen
|
||||
Colors.ARGB(0xCE, 0xD0, 0xFF), // BBlue
|
||||
};
|
||||
[
|
||||
// 0x101010, 0xFDFDFD, 0x5331FF, 0x5DCC02, 0xF33F4B, 0xE0E0E0, 0xA6FF91, 0xD0CEFF
|
||||
|
||||
Colors.ARGB(0x10, 0x10, 0x10), // Black
|
||||
Colors.ARGB(0xFD, 0xFD, 0xFD), // White
|
||||
Colors.ARGB(0xFF, 0x31, 0x53), // Red
|
||||
Colors.ARGB(0x02, 0xCC, 0x5D), // Green
|
||||
Colors.ARGB(0x4B, 0x3F, 0xF3), // Blue
|
||||
Colors.ARGB(0xE0, 0xE0, 0xE0), // Gray
|
||||
Colors.ARGB(0x91, 0xFF, 0xA6), // BGreen
|
||||
Colors.ARGB(0xCE, 0xD0, 0xFF), // BBlue
|
||||
];
|
||||
|
||||
public static readonly int[] CMap =
|
||||
{
|
||||
[
|
||||
0, 1, 1, 1,
|
||||
7, 4, 2, 3,
|
||||
5, 4, 2, 3,
|
||||
6, 4, 2, 3,
|
||||
};
|
||||
];
|
||||
|
||||
private int _latch_colour = 2;
|
||||
private int _latch_x;
|
||||
private int _latch_y;
|
||||
private int[] videoBuffer;
|
||||
private int _latchColour = 2;
|
||||
private int _latchX;
|
||||
private int _latchY;
|
||||
private int[] _videoBuffer;
|
||||
private double _pixelClockCounter;
|
||||
private double _pixelClocksRemaining;
|
||||
|
||||
|
||||
private int ScanlineRepeats;
|
||||
private int PixelWidth;
|
||||
private int HTotal;
|
||||
|
@ -54,20 +51,18 @@ namespace BizHawk.Emulation.Cores.Consoles.ChannelF
|
|||
private double PixelClocksPerCpuClock;
|
||||
private double PixelClocksPerFrame;
|
||||
|
||||
public void SetupVideo()
|
||||
{
|
||||
videoBuffer = new int[HTotal * VTotal];
|
||||
}
|
||||
private void SetupVideo()
|
||||
=> _videoBuffer = new int[HTotal * VTotal];
|
||||
|
||||
/// <summary>
|
||||
/// Called after every CPU clock
|
||||
/// </summary>
|
||||
private void ClockVideo()
|
||||
{
|
||||
{
|
||||
while (_pixelClocksRemaining > 1)
|
||||
{
|
||||
var currScanline = (int)(_pixelClockCounter / HTotal);
|
||||
var currPixelInLine = (int)(_pixelClockCounter % HTotal);
|
||||
var currPixelInLine = (int)(_pixelClockCounter - currScanline * HTotal);
|
||||
var currRowInVram = currScanline / ScanlineRepeats;
|
||||
var currColInVram = currPixelInLine / PixelWidth;
|
||||
|
||||
|
@ -84,27 +79,30 @@ namespace BizHawk.Emulation.Cores.Consoles.ChannelF
|
|||
// active display
|
||||
if (currRowInVram < 64)
|
||||
{
|
||||
var p1 = (VRAM[(currRowInVram * 0x80) + 125]) & 0x03;
|
||||
var p2 = (VRAM[(currRowInVram * 0x80) + 126]) & 0x03;
|
||||
var p1 = _vram[(currRowInVram * 0x80) + 125] & 0x03;
|
||||
var p2 = _vram[(currRowInVram * 0x80) + 126] & 0x03;
|
||||
var pOffset = ((p2 & 0x02) | (p1 >> 1)) << 2;
|
||||
|
||||
var colourIndex = pOffset + (VRAM[currColInVram | (currRowInVram << 7)] & 0x03);
|
||||
videoBuffer[(currScanline * HTotal) + currPixelInLine] = FPalette[CMap[colourIndex]];
|
||||
var colourIndex = pOffset + (_vram[currColInVram | (currRowInVram << 7)] & 0x03);
|
||||
_videoBuffer[(currScanline * HTotal) + currPixelInLine] = FPalette[CMap[colourIndex]];
|
||||
}
|
||||
}
|
||||
|
||||
_pixelClockCounter++;
|
||||
_pixelClocksRemaining -= 1;
|
||||
_pixelClocksRemaining -= 1;
|
||||
}
|
||||
|
||||
_pixelClocksRemaining += PixelClocksPerCpuClock;
|
||||
_pixelClockCounter %= PixelClocksPerFrame;
|
||||
while (_pixelClockCounter >= PixelClocksPerFrame)
|
||||
{
|
||||
_pixelClockCounter -= PixelClocksPerFrame;
|
||||
}
|
||||
}
|
||||
|
||||
private int HDisplayable => HBlankOn - HBlankOff;
|
||||
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 newHeight = originalHeight - trimTop - trimBottom;
|
||||
|
@ -112,7 +110,7 @@ namespace BizHawk.Emulation.Cores.Consoles.ChannelF
|
|||
|
||||
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 newIndex = y * newWidth + x;
|
||||
|
@ -139,40 +137,18 @@ namespace BizHawk.Emulation.Cores.Consoles.ChannelF
|
|||
public int VsyncDenominator { get; private set; }
|
||||
|
||||
|
||||
// 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'
|
||||
// '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'
|
||||
// https://channelf.se/veswiki/index.php?title=Resolution
|
||||
// 'Even though PAL televisions system has more lines vertically, the Channel F displays about the same as on the original NTSC video system'
|
||||
//
|
||||
// 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
|
||||
// On real hardware it looks like this (so we are close): https://www.youtube.com/watch?v=ZvQA9tiEIuQ
|
||||
public int[] GetVideoBuffer()
|
||||
{
|
||||
// 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'
|
||||
// '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'
|
||||
// https://channelf.se/veswiki/index.php?title=Resolution
|
||||
// 'Even though PAL televisions system has more lines vertically, the Channel F displays about the same as on the original NTSC video system'
|
||||
//
|
||||
// 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
|
||||
// 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);
|
||||
}
|
||||
=> ClampBuffer(_videoBuffer, HTotal, VTotal, HBlankOff, VBlankOff, HTotal - HBlankOn, VTotal - VBlankOn);
|
||||
|
||||
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];
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
public DisplayType Region => _region == RegionType.NTSC ? DisplayType.NTSC : DisplayType.PAL;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,63 +18,48 @@ namespace BizHawk.Emulation.Cores.Consoles.ChannelF
|
|||
|
||||
public IInputCallbackSystem InputCallbacks { get; } = new InputCallbackSystem();
|
||||
|
||||
private int _lagCount = 0;
|
||||
private bool _isLag = false;
|
||||
private int _lagCount;
|
||||
private bool _isLag;
|
||||
|
||||
/// <summary>
|
||||
/// Cycles through all the input callbacks
|
||||
/// This should be done once per frame
|
||||
/// </summary>
|
||||
public bool PollInput()
|
||||
private void PollInput()
|
||||
{
|
||||
bool noInput = true;
|
||||
for (int i = 0; i < ButtonsConsole.Length; i++)
|
||||
for (var i = 0; i < _buttonsConsole.Length; i++)
|
||||
{
|
||||
var key = ButtonsConsole[i];
|
||||
bool prevState = StateConsole[i]; // CTRLConsole.Bit(i);
|
||||
bool currState = _controller.IsPressed(key);
|
||||
var key = _buttonsConsole[i];
|
||||
var prevState = _stateConsole[i];
|
||||
var currState = _controller.IsPressed(key);
|
||||
if (currState != prevState)
|
||||
{
|
||||
StateConsole[i] = currState;
|
||||
noInput = false;
|
||||
_stateConsole[i] = currState;
|
||||
|
||||
if (key == "RESET" && StateConsole[i])
|
||||
if (key == "RESET" && _stateConsole[i])
|
||||
{
|
||||
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];
|
||||
bool prevState = StateRight[i];
|
||||
bool currState = _controller.IsPressed(key);
|
||||
if (currState != prevState)
|
||||
{
|
||||
StateRight[i] = currState;
|
||||
noInput = false;
|
||||
}
|
||||
var key = _buttonsRight[i];
|
||||
_stateRight[i] = _controller.IsPressed(key);
|
||||
}
|
||||
|
||||
for (int i = 0; i < ButtonsLeft.Length; i++)
|
||||
for (var i = 0; i < _buttonsLeft.Length; i++)
|
||||
{
|
||||
var key = "P2 " + ButtonsLeft[i];
|
||||
bool prevState = StateLeft[i];
|
||||
bool currState = _controller.IsPressed(key);
|
||||
if (currState != prevState)
|
||||
{
|
||||
StateLeft[i] = currState;
|
||||
noInput = false;
|
||||
}
|
||||
var key = _buttonsLeft[i];
|
||||
_stateLeft[i] = _controller.IsPressed(key);
|
||||
}
|
||||
|
||||
return noInput;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,12 +19,12 @@ namespace BizHawk.Emulation.Cores.Consoles.ChannelF
|
|||
addr =>
|
||||
{
|
||||
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) =>
|
||||
{
|
||||
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),
|
||||
new MemoryDomainDelegate("System Bus", 0x10000, MemoryDomain.Endian.Big,
|
||||
addr =>
|
||||
|
@ -49,11 +49,10 @@ namespace BizHawk.Emulation.Cores.Consoles.ChannelF
|
|||
|
||||
private void SyncAllByteArrayDomains()
|
||||
{
|
||||
SyncByteArrayDomain("BIOS1", BIOS01);
|
||||
SyncByteArrayDomain("BIOS2", BIOS02);
|
||||
Cartridge.SyncByteArrayDomain(this);
|
||||
//SyncByteArrayDomain("ROM", Rom);
|
||||
SyncByteArrayDomain("VRAM", VRAM);
|
||||
SyncByteArrayDomain("BIOS1", _bios01);
|
||||
SyncByteArrayDomain("BIOS2", _bios02);
|
||||
_cartridge.SyncByteArrayDomain(this);
|
||||
SyncByteArrayDomain("VRAM", _vram);
|
||||
}
|
||||
|
||||
public void SyncByteArrayDomain(string name, byte[] data)
|
||||
|
|
|
@ -1,7 +1,4 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
using BizHawk.Emulation.Common;
|
||||
using BizHawk.Emulation.Common;
|
||||
using BizHawk.Emulation.Cores.Components.FairchildF8;
|
||||
|
||||
namespace BizHawk.Emulation.Cores.Consoles.ChannelF
|
||||
|
@ -15,71 +12,60 @@ namespace BizHawk.Emulation.Cores.Consoles.ChannelF
|
|||
var ser = new BasicServiceProvider(this);
|
||||
ServiceProvider = ser;
|
||||
CoreComm = lp.Comm;
|
||||
_gameInfo = lp.Roms.Select(r => r.Game).ToList();
|
||||
_files = lp.Roms.Select(r => r.RomData).ToList();
|
||||
var gameInfo = lp.Roms[0].Game;
|
||||
var rom = lp.Roms[0].RomData;
|
||||
|
||||
_syncSettings = lp.SyncSettings ?? new ChannelFSyncSettings();
|
||||
region = _syncSettings.Region;
|
||||
version = _syncSettings.Version;
|
||||
_region = _syncSettings.Region;
|
||||
_version = _syncSettings.Version;
|
||||
|
||||
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"));
|
||||
BIOS02 = CoreComm.CoreFileProvider.GetFirmwareOrThrow(new("ChannelF", "ChannelF_sl131254"));
|
||||
_bios01 = CoreComm.CoreFileProvider.GetFirmwareOrThrow(new("ChannelF", "ChannelF_sl131253"));
|
||||
_bios02 = CoreComm.CoreFileProvider.GetFirmwareOrThrow(new("ChannelF", "ChannelF_sl131254"));
|
||||
}
|
||||
else
|
||||
{
|
||||
BIOS01 = CoreComm.CoreFileProvider.GetFirmwareOrThrow(new("ChannelF", "ChannelF_sl90025"));
|
||||
BIOS02 = CoreComm.CoreFileProvider.GetFirmwareOrThrow(new("ChannelF", "ChannelF_sl131254"));
|
||||
_bios01 = CoreComm.CoreFileProvider.GetFirmwareOrThrow(new("ChannelF", "ChannelF_sl90025"));
|
||||
_bios02 = CoreComm.CoreFileProvider.GetFirmwareOrThrow(new("ChannelF", "ChannelF_sl131254"));
|
||||
}
|
||||
|
||||
Cartridge = VesCartBase.Configure(_gameInfo[0], _files[0]);
|
||||
|
||||
CPU = new F3850
|
||||
if (_bios01.Length != 1024 || _bios02.Length != 1024)
|
||||
{
|
||||
ReadMemory = ReadBus,
|
||||
WriteMemory = WriteBus,
|
||||
ReadHardware = ReadPort,
|
||||
WriteHardware = WritePort,
|
||||
DummyReadMemory = ReadBus
|
||||
};
|
||||
throw new InvalidOperationException("BIOS must be exactly 1024 bytes!");
|
||||
}
|
||||
|
||||
_tracer = new TraceBuffer(CPU.TraceHeader);
|
||||
_cartridge = VesCartBase.Configure(gameInfo, rom);
|
||||
|
||||
//var rom = _files.First();
|
||||
//Array.Copy(rom, 0, Rom, 0, rom.Length);
|
||||
_cpu = new F3850<CpuLink>(new CpuLink(this));
|
||||
_tracer = new TraceBuffer(_cpu.TraceHeader);
|
||||
|
||||
CalcClock();
|
||||
SetupVideo();
|
||||
|
||||
ser.Register<IVideoProvider>(this);
|
||||
ser.Register<ITraceable>(_tracer);
|
||||
ser.Register<IDisassemblable>(CPU);
|
||||
ser.Register<ISoundProvider>(this);
|
||||
ser.Register<IDisassemblable>(_cpu);
|
||||
ser.Register<IStatable>(new StateSerializer(SyncState));
|
||||
SetupMemoryDomains();
|
||||
}
|
||||
|
||||
internal CoreComm CoreComm { get; }
|
||||
private CoreComm CoreComm { get; }
|
||||
|
||||
public List<GameInfo> _gameInfo;
|
||||
private readonly List<byte[]> _files;
|
||||
|
||||
public F3850 CPU;
|
||||
private readonly F3850<CpuLink> _cpu;
|
||||
private readonly TraceBuffer _tracer;
|
||||
public IController _controller;
|
||||
private IController _controller;
|
||||
|
||||
public VesCartBase Cartridge;
|
||||
public RegionType region;
|
||||
public ConsoleVersion version;
|
||||
private readonly VesCartBase _cartridge;
|
||||
private readonly RegionType _region;
|
||||
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";
|
||||
}
|
||||
|
|
|
@ -5,8 +5,8 @@
|
|||
/// </summary>
|
||||
public partial class ChannelF
|
||||
{
|
||||
public byte[] BIOS01 = new byte[1024];
|
||||
public byte[] BIOS02 = new byte[1024];
|
||||
private readonly byte[] _bios01;
|
||||
private readonly byte[] _bios02;
|
||||
|
||||
/// <summary>
|
||||
/// Simulates reading a byte of data from the address space
|
||||
|
@ -16,17 +16,17 @@
|
|||
if (addr < 0x400)
|
||||
{
|
||||
// BIOS ROM 1
|
||||
return BIOS01[addr];
|
||||
return _bios01[addr];
|
||||
}
|
||||
else if (addr < 0x800)
|
||||
{
|
||||
// BIOS ROM 2
|
||||
return BIOS02[addr - 0x400];
|
||||
return _bios02[addr - 0x400];
|
||||
}
|
||||
else
|
||||
{
|
||||
// Cartridge Memory Space
|
||||
return Cartridge.ReadBus(addr);
|
||||
return _cartridge.ReadBus(addr);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -35,8 +35,6 @@
|
|||
/// Channel F addressable through the address space)
|
||||
/// </summary>
|
||||
public void WriteBus(ushort addr, byte value)
|
||||
{
|
||||
Cartridge.WriteBus(addr, value);
|
||||
}
|
||||
=> _cartridge.WriteBus(addr, value);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,27 +18,26 @@ namespace BizHawk.Emulation.Cores.Consoles.ChannelF
|
|||
/// 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
|
||||
/// </summary>
|
||||
public byte[] OutputLatch = new byte[0xFF];
|
||||
private byte[] _outputLatch = new byte[0xFF];
|
||||
|
||||
public bool LS368Enable;
|
||||
private bool LS368Enable;
|
||||
|
||||
/// <summary>
|
||||
/// CPU is attempting to read from a port
|
||||
/// </summary>
|
||||
public byte ReadPort(ushort addr)
|
||||
private byte ReadPort(ushort addr)
|
||||
{
|
||||
var result = 0xFF;
|
||||
|
||||
int result;
|
||||
switch (addr)
|
||||
{
|
||||
case 0:
|
||||
// Console Buttons - these are connected to pins 0-3 (bits 0-3) through a 7404 Hex Inverter
|
||||
// b0: TIME
|
||||
// b1: MODE
|
||||
// b2: HOLD
|
||||
// b3: START
|
||||
// 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];
|
||||
// Console Buttons - these are connected to pins 0-3 (bits 0-3) through a 7404 Hex Inverter
|
||||
// b0: TIME
|
||||
// b1: MODE
|
||||
// b2: HOLD
|
||||
// b3: START
|
||||
// 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];
|
||||
InputCallbacks.Call();
|
||||
_isLag = false;
|
||||
break;
|
||||
|
@ -46,14 +45,14 @@ namespace BizHawk.Emulation.Cores.Consoles.ChannelF
|
|||
case 1:
|
||||
// right controller (player 1)
|
||||
// connected through 7404 Hex Inverter
|
||||
// b0: RIGHT
|
||||
// b1: LEFT
|
||||
// b2: BACK
|
||||
// b3: FORWARD
|
||||
// b4: CCW
|
||||
// b5: CW
|
||||
// b0: RIGHT
|
||||
// b1: LEFT
|
||||
// b2: BACK
|
||||
// b3: FORWARD
|
||||
// b4: CCW
|
||||
// b5: CW
|
||||
var v1 = LS368Enable ? DataRight : DataRight | 0xC0;
|
||||
result = (~v1) | OutputLatch[addr];
|
||||
result = ~v1 | _outputLatch[addr];
|
||||
InputCallbacks.Call();
|
||||
_isLag = false;
|
||||
break;
|
||||
|
@ -62,30 +61,31 @@ namespace BizHawk.Emulation.Cores.Consoles.ChannelF
|
|||
// left controller (player 2)
|
||||
// connected through LS368 Hex Interting 3-State Buffer
|
||||
// the enable pin of this IC is driven by a CPU write to pin 6 on port 0
|
||||
// b0: RIGHT
|
||||
// b1: LEFT
|
||||
// b2: BACK
|
||||
// b3: FORWARD
|
||||
// b4: CCW
|
||||
// b5: CW
|
||||
// b6: PULL
|
||||
// b7: PUSH
|
||||
// b0: RIGHT
|
||||
// b1: LEFT
|
||||
// b2: BACK
|
||||
// b3: FORWARD
|
||||
// b4: CCW
|
||||
// b5: CW
|
||||
// b6: PULL
|
||||
// b7: PUSH
|
||||
var v2 = LS368Enable ? DataLeft : 0xFF;
|
||||
result = (~v2) | OutputLatch[addr];
|
||||
result = ~v2 | _outputLatch[addr];
|
||||
if (LS368Enable)
|
||||
{
|
||||
InputCallbacks.Call();
|
||||
_isLag = false;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case 5:
|
||||
result = OutputLatch[addr];
|
||||
result = _outputLatch[addr];
|
||||
break;
|
||||
|
||||
default:
|
||||
// possible cartridge hardware IO space
|
||||
result = (Cartridge.ReadPort(addr));
|
||||
result = _cartridge.ReadPort(addr);
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -95,37 +95,37 @@ namespace BizHawk.Emulation.Cores.Consoles.ChannelF
|
|||
/// <summary>
|
||||
/// CPU is attempting to write to the specified IO port
|
||||
/// </summary>
|
||||
public void WritePort(ushort addr, byte value)
|
||||
private void WritePort(ushort addr, byte value)
|
||||
{
|
||||
switch (addr)
|
||||
{
|
||||
case 0:
|
||||
OutputLatch[addr] = value;
|
||||
_outputLatch[addr] = value;
|
||||
LS368Enable = !value.Bit(6);
|
||||
if (value.Bit(5))
|
||||
{
|
||||
// WRT pulse
|
||||
// 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)
|
||||
VRAM[((_latch_y) * 0x80) + _latch_x] = (byte)_latch_colour;
|
||||
_vram[_latchY * 0x80 + _latchX] = (byte)_latchColour;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case 1:
|
||||
OutputLatch[addr] = value;
|
||||
_latch_colour = ((value ^ 0xFF) >> 6) & 0x03;
|
||||
_outputLatch[addr] = value;
|
||||
_latchColour = ((value ^ 0xFF) >> 6) & 0x03;
|
||||
break;
|
||||
|
||||
case 4:
|
||||
OutputLatch[addr] = value;
|
||||
_latch_x = (value | 0x80) ^ 0xFF;
|
||||
_outputLatch[addr] = value;
|
||||
_latchX = (value | 0x80) ^ 0xFF;
|
||||
break;
|
||||
|
||||
case 5:
|
||||
OutputLatch[addr] = value;
|
||||
_latch_y = (value | 0xC0) ^ 0xFF;
|
||||
var audio = ((value) >> 6) & 0x03;
|
||||
_outputLatch[addr] = value;
|
||||
_latchY = (value | 0xC0) ^ 0xFF;
|
||||
var audio = (value >> 6) & 0x03;
|
||||
if (audio != _tone)
|
||||
{
|
||||
_tone = audio;
|
||||
|
@ -136,7 +136,7 @@ namespace BizHawk.Emulation.Cores.Consoles.ChannelF
|
|||
|
||||
default:
|
||||
// possible write to cartridge hardware
|
||||
Cartridge.WritePort(addr, value);
|
||||
_cartridge.WritePort(addr, value);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue