2012-11-01 16:48:32 +00:00
using System ;
using System.Collections.Generic ;
using System.IO ;
2016-02-22 23:50:11 +00:00
using System.Linq ;
2013-11-04 01:06:36 +00:00
using BizHawk.Emulation.Common ;
2014-10-03 21:04:37 +00:00
using BizHawk.Emulation.Cores.Computers.Commodore64.MOS ;
2015-09-27 23:30:58 +00:00
using System.Windows.Forms ;
2016-02-22 23:50:11 +00:00
using BizHawk.Emulation.Cores.Computers.Commodore64.Cartridge ;
using BizHawk.Emulation.Cores.Computers.Commodore64.Cassette ;
using BizHawk.Emulation.Cores.Computers.Commodore64.Media ;
using BizHawk.Emulation.Cores.Computers.Commodore64.Serial ;
2012-11-01 16:48:32 +00:00
2013-11-12 19:22:09 +00:00
namespace BizHawk.Emulation.Cores.Computers.Commodore64
2012-11-01 16:48:32 +00:00
{
2014-04-25 01:19:57 +00:00
[ CoreAttributes (
"C64Hawk" ,
2016-02-22 23:50:11 +00:00
"SaxxonPike" ,
2014-04-25 01:19:57 +00:00
isPorted : false ,
isReleased : false
) ]
2015-09-28 18:53:19 +00:00
[ServiceNotApplicable(typeof(ISettable<,>))]
2016-02-22 23:50:11 +00:00
public sealed partial class C64 : IEmulator , IRegionable
2015-09-28 18:53:19 +00:00
{
2014-12-18 18:39:55 +00:00
// framework
2016-03-05 21:23:22 +00:00
public C64 ( CoreComm comm , GameInfo game , byte [ ] rom , object settings , object syncSettings )
2014-12-18 18:39:55 +00:00
{
2016-02-22 23:50:11 +00:00
PutSyncSettings ( ( C64SyncSettings ) syncSettings ? ? new C64SyncSettings ( ) ) ;
PutSettings ( ( C64Settings ) settings ? ? new C64Settings ( ) ) ;
2015-09-28 21:52:23 +00:00
2014-12-18 18:39:55 +00:00
ServiceProvider = new BasicServiceProvider ( this ) ;
InputCallbacks = new InputCallbackSystem ( ) ;
2016-02-22 23:50:11 +00:00
CoreComm = comm ;
2016-03-05 21:23:22 +00:00
Roms = new List < byte [ ] > { rom } ;
2016-03-04 03:14:19 +00:00
Init ( SyncSettings . VicType , Settings . BorderType , SyncSettings . SidType , SyncSettings . TapeDriveType , SyncSettings . DiskDriveType ) ;
2016-02-22 23:50:11 +00:00
_cyclesPerFrame = _board . Vic . CyclesPerFrame ;
SetupMemoryDomains ( _board . DiskDrive ! = null ) ;
_memoryCallbacks = new MemoryCallbackSystem ( ) ;
2015-09-28 18:53:19 +00:00
HardReset ( ) ;
2015-01-14 22:37:37 +00:00
2016-02-22 23:50:11 +00:00
switch ( SyncSettings . VicType )
{
case VicType . Ntsc :
case VicType . Drean :
case VicType . NtscOld :
Region = DisplayType . NTSC ;
break ;
case VicType . Pal :
Region = DisplayType . PAL ;
break ;
}
( ( BasicServiceProvider ) ServiceProvider ) . Register < IVideoProvider > ( _board . Vic ) ;
( ( BasicServiceProvider ) ServiceProvider ) . Register < IDriveLight > ( _board . Serial ) ;
}
2014-12-18 18:39:55 +00:00
2012-11-17 03:58:06 +00:00
// internal variables
2016-02-22 23:50:11 +00:00
private int _frame ;
[SaveState.DoNotSave] private readonly int _cyclesPerFrame ;
private bool _driveLed ;
2012-11-17 03:58:06 +00:00
2016-02-22 23:50:11 +00:00
// bizhawk I/O
[SaveState.DoNotSave] public CoreComm CoreComm { get ; private set ; }
2013-11-06 02:15:29 +00:00
2016-02-22 23:50:11 +00:00
// game/rom specific
[SaveState.DoNotSave] public GameInfo Game ;
[SaveState.DoNotSave] public string SystemId { get { return "C64" ; } }
2012-11-17 03:58:06 +00:00
2016-02-22 23:50:11 +00:00
[SaveState.DoNotSave] public string BoardName { get { return null ; } }
2013-08-24 16:54:22 +00:00
2012-11-17 03:58:06 +00:00
// running state
public bool DeterministicEmulation { get { return true ; } set { ; } }
2016-02-22 23:50:11 +00:00
[SaveState.DoNotSave] public int Frame { get { return _frame ; } set { _frame = value ; } }
2013-11-03 16:29:51 +00:00
public void ResetCounters ( )
2012-11-01 16:48:32 +00:00
{
_frame = 0 ;
2016-02-22 23:50:11 +00:00
LagCount = 0 ;
IsLagFrame = false ;
_frameCycles = 0 ;
2015-09-28 18:53:19 +00:00
}
2012-11-01 16:48:32 +00:00
2012-11-17 03:58:06 +00:00
// audio/video
2012-11-01 16:48:32 +00:00
public void EndAsyncSound ( ) { } //TODO
2016-02-22 23:50:11 +00:00
[SaveState.DoNotSave] public ISoundProvider SoundProvider { get { return null ; } }
2012-12-08 16:05:00 +00:00
public bool StartAsyncSound ( ) { return false ; } //TODO
2016-02-22 23:50:11 +00:00
[SaveState.DoNotSave] public ISyncSoundProvider SyncSoundProvider { get { return DCFilter . AsISyncSoundProvider ( _board . Sid , 512 ) ; } }
2012-11-17 03:58:06 +00:00
// controller
2016-02-22 23:50:11 +00:00
[SaveState.DoNotSave] public ControllerDefinition ControllerDefinition { get { return C64ControllerDefinition ; } }
[SaveState.DoNotSave] public IController Controller { get { return _board . Controller ; } set { _board . Controller = value ; } }
2016-03-05 21:23:22 +00:00
[SaveState.DoNotSave] public IEnumerable < byte [ ] > Roms { get ; private set ; }
2016-02-22 23:50:11 +00:00
[SaveState.DoNotSave]
private static readonly ControllerDefinition C64ControllerDefinition = new ControllerDefinition
2012-11-01 16:48:32 +00:00
{
2013-08-19 03:42:40 +00:00
Name = "Commodore 64 Controller" ,
2012-11-01 16:48:32 +00:00
BoolButtons =
{
2012-11-03 06:03:58 +00:00
"P1 Up" , "P1 Down" , "P1 Left" , "P1 Right" , "P1 Button" ,
2012-12-06 00:41:31 +00:00
"P2 Up" , "P2 Down" , "P2 Left" , "P2 Right" , "P2 Button" ,
2014-06-29 16:53:33 +00:00
"Key Left Arrow" , "Key 1" , "Key 2" , "Key 3" , "Key 4" , "Key 5" , "Key 6" , "Key 7" , "Key 8" , "Key 9" , "Key 0" , "Key Plus" , "Key Minus" , "Key Pound" , "Key Clear/Home" , "Key Insert/Delete" ,
"Key Control" , "Key Q" , "Key W" , "Key E" , "Key R" , "Key T" , "Key Y" , "Key U" , "Key I" , "Key O" , "Key P" , "Key At" , "Key Asterisk" , "Key Up Arrow" , "Key Restore" ,
"Key Run/Stop" , "Key Lck" , "Key A" , "Key S" , "Key D" , "Key F" , "Key G" , "Key H" , "Key J" , "Key K" , "Key L" , "Key Colon" , "Key Semicolon" , "Key Equal" , "Key Return" ,
"Key Commodore" , "Key Left Shift" , "Key Z" , "Key X" , "Key C" , "Key V" , "Key B" , "Key N" , "Key M" , "Key Comma" , "Key Period" , "Key Slash" , "Key Right Shift" , "Key Cursor Up/Down" , "Key Cursor Left/Right" ,
"Key Space" ,
"Key F1" , "Key F3" , "Key F5" , "Key F7"
2012-11-01 16:48:32 +00:00
}
} ;
2016-02-22 23:50:11 +00:00
[SaveState.DoNotSave] public IEmulatorServiceProvider ServiceProvider { get ; private set ; }
2014-12-04 03:38:30 +00:00
2015-09-28 18:53:19 +00:00
public DisplayType Region
{
get ;
private set ;
}
2013-11-06 02:15:29 +00:00
public void Dispose ( )
2012-12-08 16:07:06 +00:00
{
2016-03-04 22:06:25 +00:00
if ( _board ! = null )
{
if ( _board . TapeDrive ! = null )
{
_board . TapeDrive . RemoveMedia ( ) ;
}
if ( _board . DiskDrive ! = null )
{
_board . DiskDrive . RemoveMedia ( ) ;
}
_board = null ;
}
}
2012-11-17 03:58:06 +00:00
2016-02-22 23:50:11 +00:00
private int _frameCycles ;
2015-09-28 18:53:19 +00:00
// process frame
public void FrameAdvance ( bool render , bool rendersound )
{
do
{
DoCycle ( ) ;
}
2016-02-22 23:50:11 +00:00
while ( _frameCycles ! = 0 ) ;
2015-09-28 18:53:19 +00:00
}
private void DoCycle ( )
2012-11-01 16:48:32 +00:00
{
2016-02-22 23:50:11 +00:00
if ( _frameCycles = = 0 ) {
_board . InputRead = false ;
_board . PollInput ( ) ;
_board . Cpu . LagCycles = 0 ;
2015-09-28 18:53:19 +00:00
}
2016-02-22 23:50:11 +00:00
_driveLed = _board . Serial . ReadDeviceLight ( ) ;
_board . Execute ( ) ;
_frameCycles + + ;
2015-09-28 18:53:19 +00:00
// load PRG file if needed
2016-02-22 23:50:11 +00:00
if ( _loadPrg )
2015-09-28 18:53:19 +00:00
{
// check to see if cpu PC is at the BASIC warm start vector
2016-02-22 23:50:11 +00:00
if ( _board . Cpu . Pc ! = 0 & & _board . Cpu . Pc = = ( ( _board . Ram . Peek ( 0x0303 ) < < 8 ) | _board . Ram . Peek ( 0x0302 ) ) )
2015-09-28 18:53:19 +00:00
{
2016-03-04 03:14:19 +00:00
Prg . Load ( _board . Pla , _prgFile ) ;
2016-02-22 23:50:11 +00:00
_loadPrg = false ;
2015-09-28 18:53:19 +00:00
}
}
2016-02-22 23:50:11 +00:00
if ( _frameCycles ! = _cyclesPerFrame )
{
return ;
}
2015-09-28 18:53:19 +00:00
2016-02-22 23:50:11 +00:00
_board . Flush ( ) ;
IsLagFrame = ! _board . InputRead ;
2015-09-28 18:53:19 +00:00
2016-02-22 23:50:11 +00:00
if ( IsLagFrame )
LagCount + + ;
_frameCycles - = _cyclesPerFrame ;
_frame + + ;
2015-09-28 18:53:19 +00:00
}
private void HandleFirmwareError ( string file )
2012-11-27 05:11:40 +00:00
{
2016-02-22 23:50:11 +00:00
MessageBox . Show ( "the C64 core is referencing a firmware file which could not be found. Please make sure it's in your configured C64 firmwares folder. The referenced filename is: " + file ) ;
2012-11-27 05:11:40 +00:00
throw new FileNotFoundException ( ) ;
}
2016-02-22 23:50:11 +00:00
private Motherboard _board ;
private bool _loadPrg ;
2016-03-04 03:14:19 +00:00
[SaveState.DoNotSave] private byte [ ] _prgFile ;
2014-12-18 18:39:55 +00:00
2016-02-22 23:50:11 +00:00
private byte [ ] GetFirmware ( int length , params string [ ] names )
2014-12-18 18:39:55 +00:00
{
2016-02-22 23:50:11 +00:00
var result = names . Select ( n = > CoreComm . CoreFileProvider . GetFirmware ( "C64" , n , false ) ) . FirstOrDefault ( b = > b ! = null & & b . Length = = length ) ;
if ( result = = null )
throw new MissingFirmwareException ( string . Format ( "At least one of these firmwares is required: {0}" , string . Join ( ", " , names ) ) ) ;
2014-12-18 18:39:55 +00:00
return result ;
}
2016-02-22 23:50:11 +00:00
private void Init ( VicType initRegion , BorderType borderType , SidType sidType , TapeDriveType tapeDriveType , DiskDriveType diskDriveType )
2014-12-18 18:39:55 +00:00
{
2016-02-22 23:50:11 +00:00
// Force certain drive types to be available depending on ROM type
2016-03-04 03:14:19 +00:00
foreach ( var rom in Roms )
2016-02-22 23:50:11 +00:00
{
2016-03-05 21:23:22 +00:00
switch ( C64FormatFinder . GetFormat ( rom ) )
2016-03-04 03:14:19 +00:00
{
2016-03-05 21:23:22 +00:00
case C64Format . D64 :
case C64Format . G64 :
case C64Format . X64 :
2016-03-04 03:14:19 +00:00
if ( diskDriveType = = DiskDriveType . None )
diskDriveType = DiskDriveType . Commodore1541 ;
break ;
2016-03-05 21:23:22 +00:00
case C64Format . D71 :
if ( diskDriveType = = DiskDriveType . None )
diskDriveType = DiskDriveType . Commodore1571 ;
break ;
case C64Format . T64 :
case C64Format . TAP :
2016-03-04 03:14:19 +00:00
if ( tapeDriveType = = TapeDriveType . None )
{
tapeDriveType = TapeDriveType . Commodore1530 ;
}
break ;
}
}
2016-02-22 23:50:11 +00:00
_board = new Motherboard ( this , initRegion , borderType , sidType , tapeDriveType , diskDriveType ) ;
InitRoms ( diskDriveType ) ;
_board . Init ( ) ;
// configure video
CoreComm . VsyncDen = _board . Vic . CyclesPerFrame ;
CoreComm . VsyncNum = _board . Vic . CyclesPerSecond ;
}
2014-12-18 18:39:55 +00:00
private void InitMedia ( )
2012-11-17 03:58:06 +00:00
{
2016-03-04 03:14:19 +00:00
foreach ( var rom in Roms )
{
2016-03-05 21:23:22 +00:00
switch ( C64FormatFinder . GetFormat ( rom ) )
2016-03-04 03:14:19 +00:00
{
2016-03-05 21:23:22 +00:00
case C64Format . D64 :
var d64 = D64 . Read ( rom ) ;
2016-03-04 03:14:19 +00:00
if ( d64 ! = null )
{
_board . DiskDrive . InsertMedia ( d64 ) ;
}
break ;
2016-03-05 21:23:22 +00:00
case C64Format . G64 :
var g64 = G64 . Read ( rom ) ;
2016-03-04 03:14:19 +00:00
if ( g64 ! = null )
{
_board . DiskDrive . InsertMedia ( g64 ) ;
}
break ;
2016-03-05 21:23:22 +00:00
case C64Format . CRT :
var cart = CartridgeDevice . Load ( rom ) ;
2016-03-04 03:14:19 +00:00
if ( cart ! = null )
{
_board . CartPort . Connect ( cart ) ;
}
break ;
2016-03-05 21:23:22 +00:00
case C64Format . TAP :
var tape = Tape . Load ( rom ) ;
2016-03-04 03:14:19 +00:00
if ( tape ! = null )
{
_board . TapeDrive . Insert ( tape ) ;
}
break ;
2016-03-05 21:23:22 +00:00
default :
if ( rom . Length > 2 )
2016-03-04 03:14:19 +00:00
{
_loadPrg = true ;
2016-03-05 21:23:22 +00:00
_prgFile = rom ;
2016-03-04 03:14:19 +00:00
}
break ;
}
}
}
2012-11-17 03:58:06 +00:00
2016-02-22 23:50:11 +00:00
private void InitRoms ( DiskDriveType diskDriveType )
2014-12-18 18:39:55 +00:00
{
2016-03-04 22:06:25 +00:00
_board . BasicRom . Flash ( GetFirmware ( 0x2000 , "Basic" ) ) ;
2016-03-04 23:29:47 +00:00
_board . KernalRom . Flash ( GetFirmware ( 0x2000 , "Kernal" ) ) ;
_board . CharRom . Flash ( GetFirmware ( 0x1000 , "Chargen" ) ) ;
2016-02-22 23:50:11 +00:00
2016-03-04 22:06:25 +00:00
switch ( diskDriveType )
2016-02-22 23:50:11 +00:00
{
2016-03-04 22:06:25 +00:00
case DiskDriveType . Commodore1541 :
_board . DiskDrive . DriveRom . Flash ( GetFirmware ( 0x4000 , "Drive1541" ) ) ;
break ;
case DiskDriveType . Commodore1541II :
_board . DiskDrive . DriveRom . Flash ( GetFirmware ( 0x4000 , "Drive1541II" ) ) ;
break ;
2016-03-05 21:23:22 +00:00
case DiskDriveType . Commodore1571 :
_board . DiskDrive . DriveRom . Flash ( GetFirmware ( 0x8000 , "Drive1571" ) ) ;
break ;
2016-03-04 22:06:25 +00:00
}
2016-03-05 21:23:22 +00:00
}
2013-05-06 20:51:28 +00:00
2014-12-18 18:39:55 +00:00
// ------------------------------------
2014-12-04 00:43:12 +00:00
2014-12-18 18:39:55 +00:00
public void HardReset ( )
2012-11-01 16:48:32 +00:00
{
2016-03-04 03:14:19 +00:00
InitMedia ( ) ;
_board . HardReset ( ) ;
2012-11-01 16:48:32 +00:00
}
2015-09-28 18:53:19 +00:00
}
2012-11-01 16:48:32 +00:00
}