ChannelF: Extreme WIP! I promise nothing...

This commit is contained in:
Asnivor 2019-04-16 16:10:56 +01:00
parent 6ea20e9e9b
commit f0384b7e83
29 changed files with 1996 additions and 7 deletions

View File

@ -27,6 +27,7 @@
#include gamedb_zxspectrum.txt
#include gamedb_amstradcpc.txt
#include gamedb_ngp.txt
#include gamedb_channelf.txt
; ************ TI-83 ************

View File

@ -0,0 +1,58 @@
;;;;;;;;;;--------------------------------------------------;;;;;;;;;;
;;; Type: NO-INTRO
;;; Source: Fairchild - Channel F - 20120223-000000
;;; FileGen: 2019-04-16 13:59:49 (UTC)
;;;;;;;;;;--------------------------------------------------;;;;;;;;;;
;;;;;;;;;;--------------------------------------------------;;;;;;;;;;
;;; Bad Dumps
;;;;;;;;;;--------------------------------------------------;;;;;;;;;;
;
;;;;;;;;;;--------------------------------------------------;;;;;;;;;;
;;; Hacks
;;;;;;;;;;--------------------------------------------------;;;;;;;;;;
;
;;;;;;;;;;--------------------------------------------------;;;;;;;;;;
;;; Over Dumps
;;;;;;;;;;--------------------------------------------------;;;;;;;;;;
;
;;;;;;;;;;--------------------------------------------------;;;;;;;;;;
;;; Translated
;;;;;;;;;;--------------------------------------------------;;;;;;;;;;
;
;;;;;;;;;;--------------------------------------------------;;;;;;;;;;
;;; Believed Good
;;;;;;;;;;--------------------------------------------------;;;;;;;;;;
F7BF7D55A7660FFA80D08AD1BA903FF7 Alien Invasion (USA) ChannelF USA
D89B48AE8C906488CAAC2B2AE1D63D88 Backgammon, Acey-Deucey (USA) ChannelF USA
4FA83F734C139963AA02BDBB7A52E500 Baseball (USA) ChannelF USA
25E231E7A464A32B4715BFB47AF89240 Bowling (USA) ChannelF USA
BB7F7BBBE21F142591CDCAFA98D7F6E4 Casino Poker (USA) ChannelF USA
35D61D40EF7EC337CBA092AABAC74DBD Checkers (USA) ChannelF USA
54CF17C48707467295749490D458EAFB Demonstration Cartridge (USA) ChannelF USA
F6916B665893AA8138CDE57C37E50ADA Demonstration Cartridge 2 (USA) ChannelF USA
4F11F13CBCA685CB20E888F87B3B1586 Desert Fox, Shooting Gallery (USA) ChannelF USA
6FFEDAED3C5CD8BA74D98901849CC451 Dodge It (USA) ChannelF USA
F80AF74B09D058B90E719BB7DFBDD50E Drag Race (USA) ChannelF USA
9E0711B140E22729687DB1E1354980AB Galactic Space Wars, Lunar Lander (USA) ChannelF USA
0124CD0B61DF5502AABD59029CCB6D5A Hangman (USA) ChannelF USA
4C10FA5C7316C59EFA241043FC67DFA8 Magic Numbers - Mind Reader + Nim (USA) ChannelF USA
A8E6103FCAE4D0F9E14D9EDCFC3FC493 Math Quiz I - Addition + Subtraction (USA) ChannelF USA
86B77EAFDF7B806E19E01724987E384F Math Quiz II - Multiplication + Division (USA) ChannelF USA
6565DF74539476D66FD78DE1BAC0259C Maze, Jailbreak, Blind-man's-bluff, Trailblazer (USA) ChannelF USA
53E4CC2DA0F2C167E0692B794CB7692C Maze, Jailbreak, Blind-man's-bluff, Trailblazer (USA) (Alt 1) ChannelF USA
2B3CA549E27579E4519A765FD8F52D0F Memory Match 1 & 2 (USA) ChannelF USA
1FBD86DCCA0E4619963B902C48AE77F2 Muehle, Tontauben-Schiessen, Kreatives Malspiel, Videoscope (Germany) ChannelF Germany
C2A44D22D3865B036479E9311C74D3AD Ordtaevling (Sweden) ChannelF Sweden
E90339B7068C6227D54F3C0CA637E017 Pinball Challenge (USA) ChannelF USA
5CBCDA1C44F0DAD02B0DFE209B6325D5 Pinball Challenge (USA) (Alt 1) ChannelF USA
9A894D745356A050F95410983C3BC54A Pro Football (USA) ChannelF USA
913ECBAA30816C6D78DE8651251761FC Rat' Mal (Germany) ChannelF Germany
3783B6AC359E21B99CFA17773AA811C6 Robot War, Torpedo Alley (USA) ChannelF USA
5568205F926333914DEDC8EF8BF16AF2 Schach (Germany) ChannelF Germany
DFB66EE145FAB65062FDEADAFC8DC34C Slot Machine (USA) ChannelF USA
4CB12EDAE37DF23851884B82CA410754 Sonar Search (USA) ChannelF USA
32CCA8FF09041A39251D7AADE21EE22F Space War (USA) ChannelF USA
1B409FE1154584F4D1AB76B344A73D99 Spitfire (USA) ChannelF USA
7E5C26A6D1F9A90C68669A9800BA522D Tic-Tac-Toe, Shooting Gallery, Doodle, Quadra-Doodle (USA) ChannelF USA
B074C867F235FB69CED96C6916673B45 Video Blackjack (USA) ChannelF USA
90A9B3952568F91502A7088BFB0AE07E Video Whizball (USA) ChannelF USA

View File

@ -108,6 +108,9 @@ namespace BizHawk.Client.ApiHawk
case "GGL":
return CoreSystem.GGL;
case "ChannelF":
return CoreSystem.ChannelF;
case "VB":
case "NGP":
case "DNGP":

View File

@ -33,6 +33,7 @@
NeoGeoPocket,
ZXSpectrum,
AmstradCPC,
GGL
GGL,
ChannelF
}
}

View File

@ -154,6 +154,8 @@ namespace BizHawk.Client.Common
return SystemInfo.ZXSpectrum;
case "AmstradCPC":
return SystemInfo.AmstradCPC;
case "ChannelF":
return SystemInfo.ChannelF;
}
}
}

View File

@ -29,6 +29,7 @@ using BizHawk.Emulation.Cores.Consoles.Sega.Saturn;
using BizHawk.Emulation.Cores.Consoles.NEC.PCFX;
using BizHawk.Emulation.Cores.Computers.AmstradCPC;
using BizHawk.Emulation.Cores.Consoles.Vectrex;
using BizHawk.Emulation.Cores.Consoles.ChannelF;
namespace BizHawk.Client.Common
{
@ -1079,6 +1080,9 @@ namespace BizHawk.Client.Common
Deterministic);
nextEmulator = zx;
break;
case "ChannelF":
nextEmulator = new ChannelF(nextComm, game, rom.FileData, GetCoreSettings<ChannelF>(), GetCoreSyncSettings<ChannelF>());
break;
case "AmstradCPC":
var cpc = new AmstradCPC(nextComm, Enumerable.Repeat(rom.RomData, 1), Enumerable.Repeat(rom.GameInfo, 1).ToList(), GetCoreSettings<AmstradCPC>(), GetCoreSyncSettings<AmstradCPC>());
nextEmulator = cpc;

View File

@ -204,10 +204,15 @@ namespace BizHawk.Client.Common
public static SystemInfo AmstradCPC { get; } = new SystemInfo("Amstrad CPC", CoreSystem.AmstradCPC, 2);
/// <summary>
/// Gets the <see cref="SystemInfo"/> instance for AmstradCPC
/// Gets the <see cref="SystemInfo"/> instance for GGL
/// </summary>
public static SystemInfo GGL { get; } = new SystemInfo("Game Gear Linked", CoreSystem.GGL, 2);
/// <summary>
/// Gets the <see cref="SystemInfo"/> instance for ChannelF
/// </summary>
public static SystemInfo ChannelF { get; } = new SystemInfo("Channel F", CoreSystem.ChannelF, 2);
#endregion Get SystemInfo
/// <summary>

View File

@ -382,6 +382,12 @@ namespace BizHawk.Client.Common
new PathEntry { System = "PCFX", SystemDisplayName = "PCFX", Type = "Save RAM", Path = Path.Combine(".", "SaveRAM"), Ordinal = 3 },
new PathEntry { System = "PCFX", SystemDisplayName = "PCFX", Type = "Screenshots", Path = Path.Combine(".", "Screenshots"), Ordinal = 4 },
new PathEntry { System = "PCFX", SystemDisplayName = "PCFX", Type = "Cheats", Path = Path.Combine(".", "Cheats"), Ordinal = 5 },
new PathEntry { System = "ChannelF", SystemDisplayName = "Fairchild Channel F", Type = "Base", Path = Path.Combine(".", "ZXSpectrum"), Ordinal = 0 },
new PathEntry { System = "ChannelF", SystemDisplayName = "Fairchild Channel F", Type = "ROM", Path = ".", Ordinal = 1 },
new PathEntry { System = "ChannelF", SystemDisplayName = "Fairchild Channel F", Type = "Savestates", Path = Path.Combine(".", "State"), Ordinal = 2 },
new PathEntry { System = "ChannelF", SystemDisplayName = "Fairchild Channel F", Type = "Screenshots", Path = Path.Combine(".", "Screenshots"), Ordinal = 4 },
new PathEntry { System = "ChannelF", SystemDisplayName = "Fairchild Channel F", Type = "Cheats", Path = Path.Combine(".", "Cheats"), Ordinal = 5 },
};
}
}

View File

@ -218,6 +218,7 @@ namespace BizHawk.Client.DBMan
Lynx,
VB,
UZE,
NGP
NGP,
ChannelF
}
}

View File

@ -176,7 +176,7 @@ namespace BizHawk.Client.EmuHawk
tt.TabPages[pageidx].Controls.Add(createpanel(settings, cat.Value, tt.Size));
// zxhawk hack - it uses multiple categoryLabels
if (Global.Emulator.SystemId == "ZXSpectrum" || Global.Emulator.SystemId == "AmstradCPC")
if (Global.Emulator.SystemId == "ZXSpectrum" || Global.Emulator.SystemId == "AmstradCPC" || Global.Emulator.SystemId == "ChannelF")
pageidx++;
}
@ -184,7 +184,7 @@ namespace BizHawk.Client.EmuHawk
if (buckets[0].Count > 0)
{
// ZXHawk needs to skip this bit
if (Global.Emulator.SystemId == "ZXSpectrum" || Global.Emulator.SystemId == "AmstradCPC")
if (Global.Emulator.SystemId == "ZXSpectrum" || Global.Emulator.SystemId == "AmstradCPC" || Global.Emulator.SystemId == "ChannelF")
return;
string tabname = (Global.Emulator.SystemId == "C64") ? "Keyboard" : "Console"; // hack
@ -275,6 +275,11 @@ namespace BizHawk.Client.EmuHawk
tableLayoutPanel1.ColumnStyles[1].Width = Properties.Resources.ZXSpectrumKeyboards.Width;
}
if (controlName == "ChannelF Controller")
{
}
if (controlName == "AmstradCPC Controller")
{
/*

View File

@ -53,7 +53,8 @@ namespace BizHawk.Client.EmuHawk
{ "PCFX", "PC-FX" },
{ "32X", "32X" },
{ "ZXSpectrum", "ZX Spectrum" },
{ "AmstradCPC", "Amstrad CPC" }
{ "AmstradCPC", "Amstrad CPC" },
{ "ChannelF", "Channel F" }
};
public string TargetSystem = null;

View File

@ -61,6 +61,10 @@ namespace BizHawk.Emulation.Common
FirmwareAndOption("A584272F21DC82C14B7D4F1ED440E23A976E71F0", 32768, "ZXSpectrum", "PentagonROM", "pentagon.rom", "Russian Pentagon Clone ROM");
FirmwareAndOption("282EB7BC819AAD2A12FD954E76F7838A4E1A7929", 16384, "ZXSpectrum", "TRDOSROM", "trdos.rom", "TRDOS ROM");
// Channel F
FirmwareAndOption("81193965A374D77B99B4743D317824B53C3E3C78", 1024, "ChannelF", "ChannelF_sl131253", "ChannelF-SL31253.rom", "Channel F Rom0");
FirmwareAndOption("8F70D1B74483BA3A37E86CF16C849D601A8C3D2C", 1024, "ChannelF", "ChannelF_sl131254", "ChannelF-SL31254.rom", "Channel F Rom1");
// for saturn, we think any bios region can pretty much run any iso
// so, we're going to lay this out carefully so that we choose things in a sensible order, but prefer the correct region
var ss_100_j = File("2B8CB4F87580683EB4D760E4ED210813D667F0A2", 524288, "saturn-1.00-(J).bin", "Bios v1.00 (J)");

View File

@ -34,7 +34,8 @@ namespace BizHawk.Emulation.Common
new SystemInfo { SystemId = "AppleII", FullName = "Apple II" },
new SystemInfo { SystemId = "INTV", FullName = "Intellivision" },
new SystemInfo { SystemId = "ZXSpectrum", FullName = "Sinclair ZX Spectrum" },
new SystemInfo { SystemId = "AmstradCPC", FullName = "Amstrad CPC" }
new SystemInfo { SystemId = "AmstradCPC", FullName = "Amstrad CPC" },
new SystemInfo { SystemId = "ChannelF", FullName = "Fairchild Channel F"},
};
public SystemInfo this[string systemId]

View File

@ -595,6 +595,21 @@
</Compile>
<Compile Include="Consoles\Belogic\LibUzem.cs" />
<Compile Include="Consoles\Belogic\Uzem.cs" />
<Compile Include="Consoles\Fairchild\ChannelF\ChannelF.IO.cs" />
<Compile Include="Consoles\Fairchild\ChannelF\ChannelF.MemoryDomains.cs" />
<Compile Include="Consoles\Fairchild\ChannelF\ChannelF.IStatable.cs" />
<Compile Include="Consoles\Fairchild\ChannelF\ChannelF.ISettable.cs" />
<Compile Include="Consoles\Fairchild\ChannelF\ChannelF.InputPollable.cs" />
<Compile Include="Consoles\Fairchild\ChannelF\ChannelF.Controllers.cs" />
<Compile Include="Consoles\Fairchild\ChannelF\ChannelF.IEmulator.cs" />
<Compile Include="Consoles\Fairchild\ChannelF\ChannelF.IVideoProvider.cs" />
<Compile Include="Consoles\Fairchild\ChannelF\ChannelF.cs" />
<Compile Include="Consoles\Fairchild\ChannelF\F8\F3850.Disassembler.cs" />
<Compile Include="Consoles\Fairchild\ChannelF\F8\F3850.Tables.cs" />
<Compile Include="Consoles\Fairchild\ChannelF\F8\F3850.Registers.cs" />
<Compile Include="Consoles\Fairchild\ChannelF\F8\F3850.Operations.cs" />
<Compile Include="Consoles\Fairchild\ChannelF\F8\F3850.Execute.cs" />
<Compile Include="Consoles\Fairchild\ChannelF\F8\F3850.cs" />
<Compile Include="Consoles\GCE\Vectrex\Audio.cs" />
<Compile Include="Consoles\GCE\Vectrex\VectrexHawk.cs" />
<Compile Include="Consoles\GCE\Vectrex\VectrexHawk.ICodeDataLog.cs" />

View File

@ -0,0 +1,58 @@
using System;
using System.Collections.Generic;
using BizHawk.Common.BufferExtensions;
using BizHawk.Emulation.Common;
namespace BizHawk.Emulation.Cores.Consoles.ChannelF
{
public partial class ChannelF
{
public ControllerDefinition ChannelFControllerDefinition
{
get
{
ControllerDefinition definition = new ControllerDefinition();
definition.Name = "ChannelF Controller";
// sticks
List<string> stickL = new List<string>
{
// P1 (left) stick
"P1 Up", "P1 Down", "P1 Left", "P1 Right", "P1 Button Up", "P1 Button Down", "P1 Rotate Left", "P1 Rotate Right"
};
foreach (var s in stickL)
{
definition.BoolButtons.Add(s);
definition.CategoryLabels[s] = "Left Controller";
}
List<string> stickR = new List<string>
{
// P1 (left) stick
"P2 Up", "P2 Down", "P2 Left", "P2 Right", "P2 Button Up", "P2 Button Down", "P2 Rotate Left", "P2 Rotate Right"
};
foreach (var s in stickR)
{
definition.BoolButtons.Add(s);
definition.CategoryLabels[s] = "Right Controller";
}
// console
List<string> consoleButtons = new List<string>
{
"RESET", "START", "HOLD", "MODE", "TIME"
};
foreach (var s in consoleButtons)
{
definition.BoolButtons.Add(s);
definition.CategoryLabels[s] = "Console";
}
return definition;
}
}
}
}

View File

@ -0,0 +1,61 @@
using System;
using BizHawk.Common.BufferExtensions;
using BizHawk.Emulation.Common;
namespace BizHawk.Emulation.Cores.Consoles.ChannelF
{
public partial class ChannelF : IEmulator
{
public IEmulatorServiceProvider ServiceProvider { get; }
public ControllerDefinition ControllerDefinition { get; set; }
public string SystemId => "ChannelF";
public bool DeterministicEmulation { get; set; }
private static double cpuFreq = 1.7897725;
private static double refreshRate = 60;
public int ClockPerFrame;
public int FrameClock = 0;
private void CalcClock()
{
var c = (cpuFreq * 1000000) / refreshRate;
ClockPerFrame = (int) c;
}
public bool FrameAdvance(IController controller, bool render, bool renderSound)
{
while (FrameClock++ < ClockPerFrame)
{
CPU.ExecuteOne();
}
FrameClock = 0;
_frame++;
return true;
}
private int _frame;
private int _lagcount;
private bool _islag;
public void ResetCounters()
{
_frame = 0;
_lagcount = 0;
_islag = false;
}
public int Frame => _frame;
public CoreComm CoreComm { get; }
public void Dispose()
{
}
}
}

View File

@ -0,0 +1,80 @@
using System;
using BizHawk.Common.BufferExtensions;
using BizHawk.Emulation.Common;
namespace BizHawk.Emulation.Cores.Consoles.ChannelF
{
public partial class ChannelF
{
public byte[] BIOS01 = new byte[1024];
public byte[] BIOS02 = new byte[1024];
public byte[] FrameBuffer = new byte[2048];
public byte[] Cartridge = new byte[0x2000 - 0x800];
public byte ReadBus(ushort addr)
{
if (addr < 0x400)
{
// Rom0
return BIOS01[addr];
}
else if (addr < 0x800)
{
// Rom1
return BIOS02[addr - 0x400];
}
else if (addr < 0x2000)
{
// Cart
return Cartridge[addr - 0x800];
}
else if (addr < 0x2000 + 2048)
{
// Framebuffer
return FrameBuffer[addr - 0x2000];
}
else
{
return 0xFF;
}
}
public void WriteBus(ushort addr, byte value)
{
if (addr < 0x400)
{
// Rom0
}
else if (addr < 0x800)
{
// Rom1
}
else if (addr < 0x2000)
{
// Cart
}
else if (addr < 0x2000 + 2048)
{
// Framebuffer
FrameBuffer[addr - 0x2000] = value;
}
else
{
}
}
public byte ReadPort(ushort addr)
{
return 0xff;
}
public void WritePort(ushort addr, byte value)
{
}
}
}

View File

@ -0,0 +1,79 @@
using System;
using System.ComponentModel;
using BizHawk.Common;
using BizHawk.Common.BufferExtensions;
using BizHawk.Emulation.Common;
using BizHawk.Emulation.Cores.Nintendo.NES;
namespace BizHawk.Emulation.Cores.Consoles.ChannelF
{
public partial class ChannelF : ISettable<ChannelF.ChannelFSettings, ChannelF.ChannelFSyncSettings>
{
internal ChannelFSettings Settings = new ChannelFSettings();
internal ChannelFSyncSettings SyncSettings = new ChannelFSyncSettings();
public ChannelFSettings GetSettings()
{
return Settings.Clone();
}
public ChannelFSyncSettings GetSyncSettings()
{
return SyncSettings.Clone();
}
public bool PutSettings(ChannelFSettings o)
{
Settings = o;
return false;
}
public bool PutSyncSettings(ChannelFSyncSettings o)
{
bool ret = ChannelFSyncSettings.NeedsReboot(SyncSettings, o);
SyncSettings = o;
return ret;
}
public class ChannelFSettings
{
[DisplayName("Default Background Color")]
[Description("The default BG color")]
[DefaultValue(0)]
public int BackgroundColor { get; set; }
public ChannelFSettings Clone()
{
return (ChannelFSettings)MemberwiseClone();
}
public ChannelFSettings()
{
SettingsUtil.SetDefaultValues(this);
}
}
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; }
public ChannelFSyncSettings Clone()
{
return (ChannelFSyncSettings) MemberwiseClone();
}
public ChannelFSyncSettings()
{
SettingsUtil.SetDefaultValues(this);
}
public static bool NeedsReboot(ChannelFSyncSettings x, ChannelFSyncSettings y)
{
return !DeepEquality.DeepEquals(x, y);
}
}
}
}

View File

@ -0,0 +1,99 @@
using System;
using System.IO;
using BizHawk.Common;
using BizHawk.Common.BufferExtensions;
using BizHawk.Emulation.Common;
namespace BizHawk.Emulation.Cores.Consoles.ChannelF
{
public partial class ChannelF : IStatable
{
public bool BinarySaveStatesPreferred => true;
public void SaveStateText(TextWriter writer)
{
SyncState(new Serializer(writer));
}
public void LoadStateText(TextReader reader)
{
SyncState(new Serializer(reader));
}
public void SaveStateBinary(BinaryWriter bw)
{
SyncState(new Serializer(bw));
}
public void LoadStateBinary(BinaryReader br)
{
SyncState(new Serializer(br));
}
public byte[] SaveStateBinary()
{
MemoryStream ms = new MemoryStream();
BinaryWriter bw = new BinaryWriter(ms);
SaveStateBinary(bw);
bw.Flush();
return ms.ToArray();
}
private void SyncState(Serializer ser)
{
/*
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(ZXSpectrum));
_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(ZXSpectrum));
_machine.SyncState(ser);
ser.Sync("Frame", ref _machine.FrameCount);
ser.Sync("LagCount", ref _lagCount);
ser.Sync("IsLag", ref _isLag);
ser.EndSection();
SyncAllByteArrayDomains();
}
}
*/
}
}
}

View File

@ -0,0 +1,26 @@
using System;
using BizHawk.Common.BufferExtensions;
using BizHawk.Emulation.Common;
namespace BizHawk.Emulation.Cores.Consoles.ChannelF
{
public partial class ChannelF : IVideoProvider
{
public int _frameHz = 60;
public int[] _vidbuffer = new int[102 * 58];
public int[] GetVideoBuffer()
{
return _vidbuffer;
}
public int VirtualWidth => 102 * 2;
public int VirtualHeight => 58 * 2;
public int BufferWidth => 102;
public int BufferHeight => 58;
public int BackgroundColor => unchecked((int)0xFF000000);
public int VsyncNumerator => _frameHz;
public int VsyncDenominator => 1;
}
}

View File

@ -0,0 +1,26 @@
using System;
using BizHawk.Common.BufferExtensions;
using BizHawk.Emulation.Common;
namespace BizHawk.Emulation.Cores.Consoles.ChannelF
{
public partial class ChannelF : IInputPollable
{
public int LagCount
{
get { return _lagCount; }
set { _lagCount = value; }
}
public bool IsLagFrame
{
get { return _isLag; }
set { _isLag = value; }
}
public IInputCallbackSystem InputCallbacks { get; }
private int _lagCount = 0;
private bool _isLag = false;
}
}

View File

@ -0,0 +1,38 @@
using System;
using System.Collections.Generic;
using BizHawk.Common.BufferExtensions;
using BizHawk.Emulation.Common;
namespace BizHawk.Emulation.Cores.Consoles.ChannelF
{
public partial class ChannelF
{
internal IMemoryDomains memoryDomains;
private readonly Dictionary<string, MemoryDomainByteArray> _byteArrayDomains = new Dictionary<string, MemoryDomainByteArray>();
private bool _memoryDomainsInit = false;
private void SetupMemoryDomains()
{
}
private void SyncAllByteArrayDomains()
{
}
private void SyncByteArrayDomain(string name, byte[] data)
{
if (_memoryDomainsInit || _byteArrayDomains.ContainsKey(name))
{
var m = _byteArrayDomains[name];
m.Data = data;
}
else
{
var m = new MemoryDomainByteArray(name, MemoryDomain.Endian.Little, data, true, 1);
_byteArrayDomains.Add(name, m);
}
}
}
}

View File

@ -0,0 +1,48 @@
using System;
using BizHawk.Common.BufferExtensions;
using BizHawk.Emulation.Common;
namespace BizHawk.Emulation.Cores.Consoles.ChannelF
{
[Core(
"ChannelFHawk",
"Asnivor",
isPorted: false,
isReleased: false)]
[ServiceNotApplicable(typeof(IDriveLight))]
public partial class ChannelF
{
public ChannelF(CoreComm comm, GameInfo game, byte[] rom, object settings, object syncSettings)
{
var ser = new BasicServiceProvider(this);
ServiceProvider = ser;
CoreComm = comm;
InputCallbacks = new InputCallbackSystem();
ControllerDefinition = ChannelFControllerDefinition;
CPU = new F3850
{
ReadMemory = ReadBus,
WriteMemory = WriteBus,
ReadHardware = ReadPort,
WriteHardware = WritePort,
DummyReadMemory = ReadBus
};
byte[] bios01 = comm.CoreFileProvider.GetFirmware("ChannelF", "ChannelF_sl131253", true);
byte[] bios02 = comm.CoreFileProvider.GetFirmware("ChannelF", "ChannelF_sl131254", true);
BIOS01 = bios01;
BIOS02 = bios02;
Array.Copy(rom, 0, Cartridge, 0, rom.Length);
CalcClock();
ser.Register<IVideoProvider>(this);
}
public F3850 CPU;
}
}

View File

@ -0,0 +1,45 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using BizHawk.Common;
using BizHawk.Emulation.Common;
namespace BizHawk.Emulation.Cores.Consoles.ChannelF
{
/// <summary>
/// Disassembler
/// </summary>
public sealed partial class F3850 : IDisassemblable
{
#region IDisassemblable
public string Cpu
{
get { return "F3850"; }
set { }
}
public string PCRegisterName
{
get { return "PC"; }
}
public IEnumerable<string> AvailableCpus
{
get { yield return "F3850"; }
}
public string Disassemble(MemoryDomain m, uint addr, out int length)
{
length = 0;
string ret = "";// Disassemble((ushort)addr, a => m.PeekByte(a), out length);
return ret;
}
#endregion
}
}

View File

@ -0,0 +1,67 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using BizHawk.Common;
using BizHawk.Emulation.Common;
namespace BizHawk.Emulation.Cores.Consoles.ChannelF
{
public sealed partial class F3850
{
public const int MaxInstructionLength = 40;
public long TotalExecutedCycles;
public int instr_pntr = 0;
public ushort[] cur_instr = new ushort[MaxInstructionLength]; // fixed size - do not change at runtime
public ushort[] cur_romc = new ushort[MaxInstructionLength]; // fixed size - do not change at runtime
public byte opcode;
public byte databus;
public ushort iobus;
public void FetchInstruction()
{
switch (opcode)
{
case 0x00: LR_A_KU(); break; // LR A, (KU)
case 0x01: LR_A_KL(); break; // LR A, (KL)
case 0x02: LR_A_QU(); break; // LR A, (QU)
case 0x03: LR_A_QL(); break; // LR A, (QL)
case 0x04: LR_KU_A(); break; // LR KU, (A)
case 0x05: LR_KL_A(); break; // LR KL, (A)
case 0x06: LR_QU_A(); break; // LR QU, (A)
case 0x07: LR_QL_A(); break; // LR QL, (A)
case 0x08: LR_K_P(); break; // LR K, (P)
case 0x09: LR_P_K(); break; // LR P, (K)
case 0x0A: LR_A_IS(); break; // LR A, (ISAR)
case 0x0B: LR_IS_A(); break; // LR ISAR, (A)
case 0x0C: LR_PK(); break; // LR PC1, (PC0); LR PC0l <- (r13); LR PC0h, (r12)
case 0x0D: LR_P0_Q(); break; // LR PC0l, (r15); LR PC0h <- (r14)
case 0x0E: LR_Q_DC(); break; // LR r14, (DC0h); r15 <- (DC0l)
case 0x0F: LR_DC_Q(); break; // LR DC0h, (r14); DC0l <- (r15)
case 0x10: LR_DC_Q(); break; // LR DC0h, (r10); DC0l <- (r11)
case 0x11: LR_H_DC(); break; // LR r10, (DC0h); r11 <- (DC0l)
case 0x12: SHIFT_R(1); break; // Shift (A) right one bit position (zero fill)
case 0x13: SHIFT_L(1); break; // Shift (A) left one bit position (zero fill)
case 0x14: SHIFT_R(4); break; // Shift (A) right four bit positions (zero fill)
case 0x15: SHIFT_L(4); break; // Shift (A) left four bit positions (zero fill)
case 0x16: LM(); break; // A <- ((DC0))
case 0x17: ST(); break; // (DC) <- (A)
case 0x18: COM(); break; // A <- A ^ 255
case 0x1A: DI(); break; // Clear ICB
case 0x1B: EI(); break; // Set ICB
case 0x1C: POP(); break; // PC0 <- PC1
case 0x1D: LR_W_J(); break; // W <- (r9)
case 0x1E: LR_J_W(); break; // r9 <- (W)
case 0x1F: INC(); break; // A <- (A) + 1
default: ILLEGAL(); break; // Illegal Opcode
}
}
}
}

View File

@ -0,0 +1,124 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using BizHawk.Common;
using BizHawk.Common.NumberExtensions;
using BizHawk.Emulation.Common;
namespace BizHawk.Emulation.Cores.Consoles.ChannelF
{
public sealed partial class F3850
{
private void IncrementBySignedByte(ushort dest, byte src)
{
if (src >= 0x80)
{
dest -= (ushort)(src & 0x80);
}
else
{
dest += (ushort)(src & 0x80);
}
}
private void IncrementBySignedByte(byte dest, byte src)
{
if (src >= 0x80)
{
dest -= (byte)(src & 0x80);
}
else
{
dest += (byte)(src & 0x80);
}
}
public void LoadReg_Func(ushort dest, ushort src)
{
if (dest == DB)
{
// byte storage
Regs[dest] = (ushort)(Regs[src] & 0xFF);
}
else if (dest == W)
{
// mask for status register
Regs[dest] = (ushort)(Regs[src] & 0x1F);
}
else
{
Regs[dest] = Regs[src];
}
}
public void ShiftRight_Func(ushort src, ushort index)
{
int shft = (Regs[src] >> index) & 0xFF;
FlagO = false;
FlagC = false;
FlagZ = shft == 0;
FlagS = (~shft & 0x80) != 0;
Regs[src] = (ushort)shft;
}
public void ShiftLeft_Func(ushort src, ushort index)
{
int shft = (Regs[src] << index) & 0xFF;
FlagO = false;
FlagC = false;
FlagZ = shft == 0;
FlagS = (~shft & 0x80) != 0;
Regs[src] = (ushort)shft;
}
public void COM_Func(ushort src)
{
byte b = (byte)Regs[src];
var r = (byte)~b;
FlagO = false;
FlagC = false;
FlagZ = r == 0;
FlagS = (~r & 0x80) != 0;
Regs[src] = (ushort)r;
}
public void ADD8_Func(ushort dest, ushort src)
{
int Reg16_d = Regs[dest];
Reg16_d += Regs[src];
FlagC = Reg16_d.Bit(8);
FlagZ = (Reg16_d & 0xFF) == 0;
ushort ans = (ushort)(Reg16_d & 0xFF);
FlagO = (Regs[dest].Bit(7) == Regs[src].Bit(7)) && (Regs[dest].Bit(7) != ans.Bit(7));
FlagS = ans > 127;
Regs[dest] = ans;
}
public void INC8_Func(ushort src)
{
int Reg16_d = Regs[src];
Reg16_d += 1;
FlagC = Reg16_d.Bit(8);
FlagZ = (Reg16_d & 0xFF) == 0;
ushort ans = (ushort)(Reg16_d & 0xFF);
Regs[src] = ans;
FlagS = Regs[src].Bit(7);
FlagO = Regs[src] == 0x80;
}
public void Read_Func(ushort dest, ushort src)
{
Regs[dest] = Regs[src];
}
}
}

View File

@ -0,0 +1,231 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms.VisualStyles;
using BizHawk.Common;
using BizHawk.Emulation.Common;
namespace BizHawk.Emulation.Cores.Consoles.ChannelF
{
/// <summary>
/// Internal Registers
/// </summary>
public sealed partial class F3850
{
/// <summary>
/// Accumulator
/// </summary>
public ushort A = 0;
/// <summary>
/// Status Register
/// </summary>
public ushort W = 1;
/// <summary>
/// Indirect Scratchpad Address Register
/// (6bit)
/// </summary>
public ushort ISAR = 2;
/// <summary>
/// Primary Program Counter (low byte)
/// </summary>
public ushort PC0l = 3;
/// <summary>
/// Primary Program Counter (high byte)
/// </summary>
public ushort PC0h = 4;
/// <summary>
/// Backup Program Counter (low byte)
/// </summary>
public ushort PC1l = 5;
/// <summary>
/// Backup Program Counter (high byte)
/// </summary>
public ushort PC1h = 6;
/// <summary>
/// Data Counter (low byte)
/// </summary>
public ushort DC0l = 7;
/// <summary>
/// Data counter (high byte)
/// </summary>
public ushort DC0h = 8;
/// <summary>
/// Temporary Arithmetic Storage
/// </summary>
public ushort ALU = 9;
/// <summary>
/// Data Bus
/// </summary>
public ushort DB = 10;
/// <summary>
/// IO Bus
/// </summary>
public ushort IO = 11;
/// <summary>
/// Registers (counters and scratchpad)
/// </summary>
public ushort[] Regs = new ushort[100];
// scratchpad registers
public ushort SR0 = 20;
public ushort SR1 = 21;
public ushort SR2 = 22;
public ushort SR3 = 23;
public ushort SR4 = 24;
public ushort SR5 = 25;
public ushort SR6 = 26;
public ushort SR7 = 27;
public ushort SR8 = 28;
public ushort SR9 = 29;
public ushort SR10 = 30;
public ushort SR11 = 31;
public ushort SR12 = 32;
public ushort SR13 = 33;
public ushort SR14 = 34;
public ushort SR15 = 35;
public ushort SR16 = 36;
public ushort SR17 = 37;
public ushort SR18 = 38;
public ushort SR19 = 39;
public ushort SR20 = 40;
public ushort SR21 = 41;
public ushort SR22 = 42;
public ushort SR23 = 43;
public ushort SR24 = 44;
public ushort SR25 = 45;
public ushort SR26 = 46;
public ushort SR27 = 47;
public ushort SR28 = 48;
public ushort SR29 = 49;
public ushort SR30 = 50;
public ushort SR31 = 51;
public ushort SR32 = 52;
public ushort SR33 = 53;
public ushort SR34 = 54;
public ushort SR35 = 55;
public ushort SR36 = 56;
public ushort SR37 = 57;
public ushort SR38 = 58;
public ushort SR39 = 59;
public ushort SR40 = 60;
public ushort SR41 = 61;
public ushort SR42 = 62;
public ushort SR43 = 63;
public ushort SR44 = 64;
public ushort SR45 = 65;
public ushort SR46 = 66;
public ushort SR47 = 67;
public ushort SR48 = 68;
public ushort SR49 = 69;
public ushort SR50 = 70;
public ushort SR51 = 71;
public ushort SR52 = 72;
public ushort SR53 = 73;
public ushort SR54 = 74;
public ushort SR55 = 75;
public ushort SR56 = 76;
public ushort SR57 = 77;
public ushort SR58 = 78;
public ushort SR59 = 79;
public ushort SR60 = 80;
public ushort SR61 = 81;
public ushort SR62 = 82;
public ushort SR63 = 83;
public ushort SR64 = 84;
/// <summary>
/// Status Register - Sign Flag
/// </summary>
public bool FlagS
{
get { return (Regs[W] & 0x01) != 0; }
set { Regs[W] = (ushort)((Regs[W] & ~0x01) | (value ? 0x01 : 0x00)); }
}
/// <summary>
/// Status Register - Carry Flag
/// </summary>
public bool FlagC
{
get { return (Regs[W] & 0x02) != 0; }
set { Regs[W] = (ushort)((Regs[W] & ~0x02) | (value ? 0x02 : 0x00)); }
}
/// <summary>
/// Status Register - Zero Flag
/// </summary>
public bool FlagZ
{
get { return (Regs[W] & 0x04) != 0; }
set { Regs[W] = (ushort)((Regs[W] & ~0x04) | (value ? 0x04 : 0x00)); }
}
/// <summary>
/// Status Register - Overflow Flag
/// </summary>
public bool FlagO
{
get { return (Regs[W] & 0x08) != 0; }
set { Regs[W] = (ushort)((Regs[W] & ~0x08) | (value ? 0x08 : 0x00)); }
}
/// <summary>
/// Status Register - Interrupt Master Enable Flag
/// </summary>
public bool FlagICB
{
get { return (Regs[W] & 0x10) != 0; }
set { Regs[W] = (ushort)((Regs[W] & ~0x10) | (value ? 0x10 : 0x00)); }
}
/// <summary>
/// Access to the full 16-bit Primary Program Counter
/// </summary>
public ushort RegPC0
{
get { return (ushort)(Regs[PC0l] | (Regs[PC0h] << 8)); }
set
{
Regs[PC0l] = (ushort)(value & 0xFF);
Regs[PC0h] = (ushort)((value >> 8) & 0xFF);
}
}
/// <summary>
/// Access to the full 16-bit Backup Program Counter
/// </summary>
public ushort RegPC1
{
get { return (ushort)(Regs[PC1l] | (Regs[PC1h] << 8)); }
set
{
Regs[PC1l] = (ushort)(value & 0xFF);
Regs[PC1h] = (ushort)((value >> 8) & 0xFF);
}
}
/// <summary>
/// Access to the full 16-bit Data Counter
/// </summary>
public ushort RegDC0
{
get { return (ushort)(Regs[DC0l] | (Regs[DC0h] << 8)); }
set
{
Regs[DC0l] = (ushort)(value & 0xFF);
Regs[DC0h] = (ushort)((value >> 8) & 0xFF);
}
}
private void ResetRegisters()
{
for (var i = 0; i < Regs.Length; i++)
{
Regs[i] = 0;
}
}
}
}

View File

@ -0,0 +1,420 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using BizHawk.Common;
using BizHawk.Emulation.Common;
namespace BizHawk.Emulation.Cores.Consoles.ChannelF
{
/// <summary>
/// Vectors of Instruction Operations
/// </summary>
public sealed partial class F3850
{
private void LR_A_KU()
{
PopulateCURINSTR(
OP_LR_8, A, SR12, // S
ROMC_00_S,
IDLE,
END);
}
private void LR_A_KL()
{
PopulateCURINSTR(
OP_LR_8, A, SR13, // S
ROMC_00_S,
IDLE,
END);
}
private void LR_A_QU()
{
PopulateCURINSTR(
OP_LR_8, A, SR14, // S
ROMC_00_S,
IDLE,
END);
}
private void LR_A_QL()
{
PopulateCURINSTR(
OP_LR_8, A, SR15, // S
ROMC_00_S,
IDLE,
END);
}
private void LR_KU_A()
{
PopulateCURINSTR(
OP_LR_8, SR12, A, // S
ROMC_00_S,
IDLE,
END);
}
private void LR_KL_A()
{
PopulateCURINSTR(
OP_LR_8, SR13, A, // S
ROMC_00_S,
IDLE,
END);
}
private void LR_QU_A()
{
PopulateCURINSTR(
OP_LR_8, SR14, A, // S
ROMC_00_S,
IDLE,
END);
}
private void LR_QL_A()
{
PopulateCURINSTR(
OP_LR_8, SR15, A, // S
ROMC_00_S,
IDLE,
END);
}
private void LR_K_P()
{
PopulateCURINSTR(
ROMC_07, // L
IDLE,
IDLE,
OP_LR_8, SR12, DB,
IDLE,
IDLE,
ROMC_0B, // L
IDLE,
IDLE,
OP_LR_8, SR13, DB,
IDLE,
IDLE,
ROMC_00_S, // S
IDLE,
IDLE,
END);
}
private void LR_P_K()
{
PopulateCURINSTR(
OP_LR_8, DB, SR12, // L
IDLE,
IDLE,
ROMC_15,
IDLE,
IDLE,
OP_LR_8, DB, SR13, // L
IDLE,
IDLE,
ROMC_18,
IDLE,
IDLE,
ROMC_00_S, // S
IDLE,
IDLE,
END);
}
private void LR_A_IS()
{
PopulateCURINSTR(
OP_LR_8, A, ISAR, // S
ROMC_00_S,
IDLE,
END);
}
private void LR_IS_A()
{
PopulateCURINSTR(
OP_LR_8, ISAR, A, // S
ROMC_00_S,
IDLE,
END);
}
private void LR_PK()
{
PopulateCURINSTR(
OP_LR_8, DB, SR13, // L
IDLE,
IDLE,
ROMC_12,
IDLE,
IDLE,
OP_LR_8, DB, SR12, // L
IDLE,
IDLE,
ROMC_14,
IDLE,
IDLE,
ROMC_00_S, // S
IDLE,
IDLE,
END);
}
private void LR_P0_Q()
{
PopulateCURINSTR(
OP_LR_8, DB, SR15, // L
IDLE,
IDLE,
ROMC_17,
IDLE,
IDLE,
OP_LR_8, DB, SR14, // L
IDLE,
IDLE,
ROMC_14,
IDLE,
IDLE,
ROMC_00_S, // S
IDLE,
IDLE,
END);
}
private void LR_Q_DC()
{
PopulateCURINSTR(
ROMC_06, // L
IDLE,
IDLE,
OP_LR_8, SR14, DB,
IDLE,
IDLE,
ROMC_09, // L
IDLE,
IDLE,
OP_LR_8, SR15, DB,
IDLE,
IDLE,
ROMC_00_S, // S
IDLE,
IDLE,
END);
}
private void LR_DC_Q()
{
PopulateCURINSTR(
OP_LR_8, DB, SR14, // L
IDLE,
IDLE,
ROMC_16,
IDLE,
IDLE,
OP_LR_8, DB, SR15, // L
IDLE,
IDLE,
ROMC_19,
IDLE,
IDLE,
ROMC_00_S, // S
IDLE,
IDLE,
END);
}
private void LR_DC_H()
{
PopulateCURINSTR(
OP_LR_8, DB, SR10, // L
IDLE,
IDLE,
ROMC_16,
IDLE,
IDLE,
OP_LR_8, DB, SR11, // L
IDLE,
IDLE,
ROMC_19,
IDLE,
IDLE,
ROMC_00_S, // S
IDLE,
IDLE,
END);
}
private void LR_H_DC()
{
PopulateCURINSTR(
ROMC_06, // L
IDLE,
IDLE,
OP_LR_8, SR10, DB,
IDLE,
IDLE,
ROMC_09, // L
IDLE,
IDLE,
OP_LR_8, SR11, DB,
IDLE,
IDLE,
ROMC_00_S, // S
IDLE,
IDLE,
END);
}
private void SHIFT_R(ushort index)
{
PopulateCURINSTR(
OP_SHFT_R, A, index, // S
ROMC_00_S,
IDLE,
END);
}
private void SHIFT_L(ushort index)
{
PopulateCURINSTR(
OP_SHFT_L, A, index, // S
ROMC_00_S,
IDLE,
END);
}
private void LM()
{
PopulateCURINSTR(
ROMC_02, // L
IDLE,
IDLE,
OP_LR_8, DB, A,
IDLE,
IDLE,
ROMC_00_S, // S
IDLE,
IDLE,
END);
}
private void ST()
{
PopulateCURINSTR(
OP_LR_8, DB, A, // L
IDLE,
IDLE,
ROMC_05,
IDLE,
IDLE,
ROMC_00_S, // S
IDLE,
IDLE,
END);
}
private void COM()
{
PopulateCURINSTR(
OP_COM, // S
ROMC_00_S,
IDLE,
END);
}
private void LNK()
{
PopulateCURINSTR(
OP_LNK, // S
ROMC_00_S,
IDLE,
END);
}
private void DI()
{
PopulateCURINSTR(
ROMC_1C_S, // S
OP_DI,
IDLE,
IDLE,
ROMC_00_S, // S
IDLE,
IDLE,
END);
}
private void EI()
{
PopulateCURINSTR(
ROMC_1C_S, // S
OP_EI,
IDLE,
IDLE,
ROMC_00_S, // S
IDLE,
IDLE,
END);
}
private void POP()
{
PopulateCURINSTR(
ROMC_04, // S
IDLE,
IDLE,
IDLE,
ROMC_00_S, // S
IDLE,
IDLE,
END);
}
private void LR_W_J()
{
PopulateCURINSTR(
ROMC_1C_S, // S
IDLE,
OP_LR_8, W, SR9,
IDLE,
ROMC_00_S, // S
IDLE,
IDLE,
END);
}
private void LR_J_W()
{
PopulateCURINSTR(
OP_LR_8, SR9, W, // S
ROMC_00_S,
IDLE,
END);
}
private void INC()
{
PopulateCURINSTR(
OP_INC8, A, // S
ROMC_00_S,
IDLE,
END);
}
private void ILLEGAL()
{
PopulateCURINSTR(
ROMC_00_S, // S
IDLE,
IDLE,
END);
}
}
}

View File

@ -0,0 +1,480 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using BizHawk.Common;
using BizHawk.Emulation.Common;
namespace BizHawk.Emulation.Cores.Consoles.ChannelF
{
/// <summary>
/// Fairchild F3850 (F8) CPU (Channel F-specific implementation)
///
/// The F8 microprocessor is made up of separate interchangeable devices
/// The Channel F has:
/// * x1 F3850 CPU (central processing unit)
/// * x2 F3851 PSU (program storage unit)
/// The CPU does not have its own data counters or program counters, rather each F8 component connected to the CPU
/// holds their own PCs and SPs and are all connected to the ROMC (ROM control) pins that are serviced by the CPU.
/// Every device must respond to changes in the CPU ROMC pins output and they each update their PCs and DCs in the same way.
/// e.g. SPs and PCs should always be identical
/// Each device has a factory ROM mask applied and with every ROMC change observed is able to know whether it should respond (via the shared data bus)
/// or not based on the value within its counters.
///
/// For this reason we will hold the PCs and SPs within the F3850 implementation.
///
/// We are currently also *not* using a separate F3851 implementation. In reality the F3851 chip has/does:
/// * 1024 byte masked ROM
/// * x2 16-bit program counters
/// * x1 16-bit data counter
/// * Programmable timer
/// * Interrupt logic
///
/// However, the Channel F does not use the timer or interrupt logic at all (as far as I can see) so we can hopefully just
/// maintain the PC and DC here in the CPU and move the ROMs into the core.
/// </summary>
public sealed partial class F3850
{
// operations that can take place in an instruction
//public const ushort OP = 1;
//public const ushort LR_8 = 2;
//public const ushort LR_16 = 3;
public const ushort ROMC_00_S = 40;
public const ushort ROMC_00_L = 41;
public const ushort ROMC_01 = 1;
public const ushort ROMC_02 = 2;
public const ushort ROMC_03_S = 3;
public const ushort ROMC_03_L = 33;
public const ushort ROMC_04 = 4;
public const ushort ROMC_05 = 5;
public const ushort ROMC_06 = 6;
public const ushort ROMC_07 = 7;
public const ushort ROMC_08 = 8;
public const ushort ROMC_09 = 9;
public const ushort ROMC_0A = 10;
public const ushort ROMC_0B = 11;
public const ushort ROMC_0C = 12;
public const ushort ROMC_0D = 13;
public const ushort ROMC_0E = 14;
public const ushort ROMC_0F = 15;
public const ushort ROMC_10 = 16;
public const ushort ROMC_11 = 17;
public const ushort ROMC_12 = 18;
public const ushort ROMC_13 = 19;
public const ushort ROMC_14 = 20;
public const ushort ROMC_15 = 21;
public const ushort ROMC_16 = 22;
public const ushort ROMC_17 = 23;
public const ushort ROMC_18 = 24;
public const ushort ROMC_19 = 25;
public const ushort ROMC_1A = 26;
public const ushort ROMC_1B = 27;
public const ushort ROMC_1C_S = 28;
public const ushort ROMC_1C_L = 34;
public const ushort ROMC_1D = 29;
public const ushort ROMC_1E = 30;
public const ushort ROMC_1F = 31;
public const ushort IDLE = 0;
public const ushort END = 51;
public const ushort OP_LR_8 = 100;
public const ushort OP_SHFT_R = 101;
public const ushort OP_SHFT_L = 102;
public const ushort OP_COM = 103;
public const ushort OP_LNK = 104;
public const ushort OP_DI = 105;
public const ushort OP_EI = 106;
public const ushort OP_INC8 = 107;
public F3850()
{
Reset();
}
public void Reset()
{
ResetRegisters();
TotalExecutedCycles = 0;
instr_pntr = 0;
PopulateCURINSTR(
ROMC_08, // S
IDLE,
IDLE,
IDLE,
IDLE,
IDLE,
ROMC_00_S,
IDLE,
IDLE,
IDLE,
END);
FlagICB = false;
}
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>
public void ExecuteOne()
{
switch (cur_instr[instr_pntr++])
{
// always the last tick within an opcode instruction cycle
case END:
opcode = databus;
instr_pntr = 0;
FetchInstruction();
break;
// used as timing 'padding'
case IDLE:
break;
// load one register into another (or databus)
case OP_LR_8:
LoadReg_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++]);
break;
// Shift register n bit positions to the right (zero fill)
case OP_SHFT_R:
ShiftRight_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++]);
break;
// Shift register n bit positions to the left (zero fill)
case OP_SHFT_L:
ShiftLeft_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++]);
break;
// A <- A ^ 255
case OP_COM:
COM_Func(A);
break;
// A <- (A) + (C)
case OP_LNK:
ADD8_Func(Regs[A], (ushort)(FlagC ? 1 : 0));
break;
case OP_DI:
FlagICB = false;
break;
case OP_EI:
FlagICB = true;
break;
case OP_INC8:
INC8_Func(cur_instr[instr_pntr++]);
break;
// instruction fetch
// The device whose address space includes the contents of the PC0 register must place on the data bus the op code addressed by PC0;
// then all devices increments the content of PC0.
// CYCLE LENGTH: S
case ROMC_00_S:
databus = ReadMemory(RegPC0++);
break;
// instruction fetch
// The device whose address space includes the contents of the PC0 register must place on the data bus the op code addressed by PC0;
// then all devices increments the content of PC0.
// CYCLE LENGTH: L
case ROMC_00_L:
databus = ReadMemory(RegPC0++);
break;
// The device whose address space includes the contents of the PC0 register must place on the data bus the contents of the memory location
// addressed by by PC0; then all devices add the 8-bit value on the data bus, as a signed binary number, to PC0
// CYCLE LENGTH: L
case ROMC_01:
databus = ReadMemory(RegPC0);
IncrementBySignedByte(RegPC0, databus);
break;
// The device whose DC0 address addresses a memory word within the address space of that device must place on the data bus the contents
// of the memory location addressed by DC0; then all devices increment DC0
// CYCLE LENGTH: L
case ROMC_02:
databus = ReadMemory(RegDC0++);
break;
// Similar to 0x00, except that it is used for Immediate Operand fetches (using PC0) instead of instruction fetches
// CYCLE LENGTH: S
case ROMC_03_S:
databus = ReadMemory(RegPC0++);
iobus = databus;
break;
// Similar to 0x00, except that it is used for Immediate Operand fetches (using PC0) instead of instruction fetches
// CYCLE LENGTH: L
case ROMC_03_L:
databus = ReadMemory(RegPC0++);
iobus = databus;
break;
// Copy the contents of PC1 into PC0
// CYCLE LENGTH: S
case ROMC_04:
RegPC0 = RegPC1;
break;
// Store the data bus contents into the memory location pointed to by DC0; increment DC0
// CYCLE LENGTH: L
case ROMC_05:
WriteMemory(RegDC0++, databus);
break;
// Place the high order byte of DC0 on the data bus
// CYCLE LENGTH: L
case ROMC_06:
databus = (byte)Regs[DC0h];
break;
// Place the high order byte of PC1 on the data bus
// CYCLE LENGTH: L
case ROMC_07:
databus = (byte)Regs[PC1h];
break;
// All devices copy the contents of PC0 into PC1. The CPU outputs zero on the data bus in this ROMC state.
// Load the data bus into both halves of PC0, this clearing the register.
// CYCLE LENGTH: L
case ROMC_08:
RegPC1 = RegPC0;
databus = 0;
Regs[PC0h] = 0;
Regs[PC0l] = 0;
break;
// The device whose address space includes the contents of the DC0 register must place the low order byte of DC0 onto the data bus
// CYCLE LENGTH: L
case ROMC_09:
databus = (byte)Regs[DC0l];
break;
// All devices add the 8-bit value on the data bus, treated as a signed binary number, to the data counter
// CYCLE LENGTH: L
case ROMC_0A:
IncrementBySignedByte(RegDC0, databus);
break;
// The device whose address space includes the value in PC1 must place the low order byte of PC1 on the data bus
// CYCLE LENGTH: L
case ROMC_0B:
databus = (byte)Regs[PC1l];
break;
// The device whose address space includes the contents of the PC0 register must place the contents of the memory word addressed by PC0
// onto the data bus; then all devices move the value that has just been placed on the data bus into the low order byte of PC0
// CYCLE LENGTH: L
case ROMC_0C:
databus = ReadMemory(RegPC0);
Regs[PC0l] = databus;
break;
// All devices store in PC1 the current contents of PC0, incremented by 1; PC1 is unaltered
// CYCLE LENGTH: S
case ROMC_0D:
RegPC1 = (ushort)(RegPC0 + 1);
break;
// The device whose address space includes the contents of PC0 must place the contents of the word addressed by PC0 onto the data bus.
// The value on the data bus is then moved to the low order byte of DC0 by all devices
// CYCLE LENGTH: L
case ROMC_0E:
databus = ReadMemory(RegPC0);
Regs[DC0l] = databus;
break;
// The interrupting device with the highest priority must place the low order byte of the interrupt vector on the data bus.
// All devices must copy the contents of PC0 into PC1. All devices must move the contents of the data bus into the low order byte of PC0
// CYCLE LENGTH: L
case ROMC_0F:
throw new NotImplementedException("ROMC 0x0F not implemented");
break;
// Inhibit any modification to the interrupt priority logic
// CYCLE LENGTH: L
case ROMC_10:
throw new NotImplementedException("ROMC 0x10 not implemented");
break;
// The device whose memory space includes the contents of PC0 must place the contents of the addressed memory word on the data bus.
// All devices must then move the contents of the data bus to the upper byte of DC0
// CYCLE LENGTH: L
case ROMC_11:
databus = ReadMemory(RegPC0);
Regs[DC0h] = databus;
break;
// All devices copy the contents of PC0 into PC1. All devices then move the contents of the data bus into the low order byte of PC0
// CYCLE LENGTH: L
case ROMC_12:
RegPC1 = RegPC0;
Regs[PC0l] = databus;
break;
// The interrupting device with the highest priority must move the high order half of the interrupt vector onto the data bus.
// All devices must move the conetnts of the data bus into the high order byte of of PC0. The interrupting device resets its
// interrupt circuitry (so that it is no longer requesting CPU servicing and can respond to another interrupt)
// CYCLE LENGTH: L
case ROMC_13:
throw new NotImplementedException("ROMC 0x13 not implemented");
break;
// All devices move the contents of the data bus into the high order byte of PC0
// CYCLE LENGTH: L
case ROMC_14:
Regs[PC0h] = databus;
break;
// All devices move the contents of the data bus into the high order byte of PC1
// CYCLE LENGTH: L
case ROMC_15:
Regs[PC1h] = databus;
break;
// All devices move the contents of the data bus into the high order byte of DC0
// CYCLE LENGTH: L
case ROMC_16:
Regs[DC0h] = databus;
break;
// All devices move the contents of the data bus into the low order byte of PC0
// CYCLE LENGTH: L
case ROMC_17:
Regs[PC0l] = databus;
break;
// All devices move the contents of the data bus into the low order byte of PC1
// CYCLE LENGTH: L
case ROMC_18:
Regs[PC1l] = databus;
break;
// All devices move the contents of the data bus into the low order byte of DC0
// CYCLE LENGTH: L
case ROMC_19:
Regs[DC0l] = databus;
break;
// During the prior cycle, an I/O port timer or interrupt control register was addressed; the device containing the addressed
// port must move the current contents of the data bus into the addressed port
// CYCLE LENGTH: L
case ROMC_1A:
WriteHardware(iobus, databus);
break;
// During the prior cycle, the data bus specified the address of an I/O port. The device containing the addressed I/O port
// must place the contents of the I/O port on the data bus. (Note that the contents of the timer and interrupt control
// registers cannot be read back onto the data bus)
// CYCLE LENGTH: L
case ROMC_1B:
databus = ReadHardware(iobus);
break;
// None
// CYCLE LENGTH: S
case ROMC_1C_S:
break;
// None
// CYCLE LENGTH: L
case ROMC_1C_L:
break;
// Devices with DC0 and DC1 registers must switch registers. Devices without a DC1 register perform no operation
// CYCLE LENGTH: S
case ROMC_1D:
// we have no DC1 in this implementation
break;
// The device whose address space includes the contents of PC0 must place the low order byte of PC0 onto the data bus
// CYCLE LENGTH: L
case ROMC_1E:
databus = (byte)Regs[PC0l];
break;
// The device whose address space includes the contents of PC0 must place the high order byte of PC0 onto the data bus
// CYCLE LENGTH: L
case ROMC_1F:
databus = (byte)Regs[PC0h];
break;
}
TotalExecutedCycles++;
}
/// <summary>
/// Optimization method to set cur_instr
/// </summary>
private void PopulateCURINSTR(ushort d0 = 0, ushort d1 = 0, ushort d2 = 0, ushort d3 = 0, ushort d4 = 0, ushort d5 = 0, ushort d6 = 0, ushort d7 = 0, ushort d8 = 0,
ushort d9 = 0, ushort d10 = 0, ushort d11 = 0, ushort d12 = 0, ushort d13 = 0, ushort d14 = 0, ushort d15 = 0, ushort d16 = 0, ushort d17 = 0, ushort d18 = 0,
ushort d19 = 0, ushort d20 = 0, ushort d21 = 0, ushort d22 = 0, ushort d23 = 0, ushort d24 = 0, ushort d25 = 0, ushort d26 = 0, ushort d27 = 0, ushort d28 = 0,
ushort d29 = 0, ushort d30 = 0, ushort d31 = 0, ushort d32 = 0, ushort d33 = 0, ushort d34 = 0, ushort d35 = 0, ushort d36 = 0, ushort d37 = 0)
{
cur_instr[0] = d0; cur_instr[1] = d1; cur_instr[2] = d2;
cur_instr[3] = d3; cur_instr[4] = d4; cur_instr[5] = d5;
cur_instr[6] = d6; cur_instr[7] = d7; cur_instr[8] = d8;
cur_instr[9] = d9; cur_instr[10] = d10; cur_instr[11] = d11;
cur_instr[12] = d12; cur_instr[13] = d13; cur_instr[14] = d14;
cur_instr[15] = d15; cur_instr[16] = d16; cur_instr[17] = d17;
cur_instr[18] = d18; cur_instr[19] = d19; cur_instr[20] = d20;
cur_instr[21] = d21; cur_instr[22] = d22; cur_instr[23] = d23;
cur_instr[24] = d24; cur_instr[25] = d25; cur_instr[26] = d26;
cur_instr[27] = d27; cur_instr[28] = d28; cur_instr[29] = d29;
cur_instr[30] = d30; cur_instr[31] = d31; cur_instr[32] = d32;
cur_instr[33] = d33; cur_instr[34] = d34; cur_instr[35] = d35;
cur_instr[36] = d36; cur_instr[37] = d37;
}
public void SyncState(Serializer ser)
{
ser.BeginSection(nameof(F3850));
ser.EndSection();
}
}
}