2015-02-17 22:58:25 +00:00
using System ;
2015-05-18 00:14:00 +00:00
using System.Collections.Generic ;
2015-02-17 22:58:25 +00:00
using System.Collections.ObjectModel ;
using System.Diagnostics.CodeAnalysis ;
using System.IO ;
using System.Linq ;
using System.Threading ;
using Jellyfish.Virtu.Services ;
2015-05-18 00:14:00 +00:00
using Newtonsoft.Json ;
using Newtonsoft.Json.Linq ;
using Newtonsoft.Json.Serialization ;
2015-02-17 22:58:25 +00:00
namespace Jellyfish.Virtu
{
2015-05-18 00:14:00 +00:00
public sealed class Machine : IDisposable
{
2015-05-20 00:12:19 +00:00
/// <summary>
/// for deserialization only!!
/// </summary>
public Machine ( ) { }
2015-05-18 00:14:00 +00:00
public Machine ( byte [ ] appleIIe , byte [ ] diskIIRom )
{
2015-04-10 00:13:26 +00:00
Events = new MachineEvents ( ) ;
2015-02-18 00:06:49 +00:00
2015-05-18 00:14:00 +00:00
Cpu = new Cpu ( this ) ;
Memory = new Memory ( this , appleIIe ) ;
Keyboard = new Keyboard ( this ) ;
GamePort = new GamePort ( this ) ;
Cassette = new Cassette ( this ) ;
Speaker = new Speaker ( this ) ;
Video = new Video ( this ) ;
NoSlotClock = new NoSlotClock ( this ) ;
var emptySlot = new PeripheralCard ( this ) ;
Slot1 = emptySlot ;
Slot2 = emptySlot ;
Slot3 = emptySlot ;
Slot4 = emptySlot ;
Slot5 = emptySlot ;
Slot6 = new DiskIIController ( this , diskIIRom ) ;
Slot7 = emptySlot ;
Slots = new List < PeripheralCard > { null , Slot1 , Slot2 , Slot3 , Slot4 , Slot5 , Slot6 , Slot7 } ;
Components = new List < MachineComponent > { Cpu , Memory , Keyboard , GamePort , Cassette , Speaker , Video , NoSlotClock , Slot1 , Slot2 , Slot3 , Slot4 , Slot5 , Slot6 , Slot7 } ;
BootDiskII = Slots . OfType < DiskIIController > ( ) . Last ( ) ;
}
2015-02-17 22:58:25 +00:00
2015-05-18 00:14:00 +00:00
public void Dispose ( )
{
}
2015-02-17 22:58:25 +00:00
2015-05-18 00:14:00 +00:00
public void Reset ( )
2015-03-08 03:10:20 +00:00
{
foreach ( var component in Components )
{
2015-05-18 00:14:00 +00:00
DebugService . WriteMessage ( "Resetting machine '{0}'" , component . GetType ( ) . Name ) ;
component . Reset ( ) ;
//DebugService.WriteMessage("Reset machine '{0}'", component.GetType().Name);
2015-03-08 03:10:20 +00:00
}
}
2015-02-17 22:58:25 +00:00
2015-05-18 00:14:00 +00:00
private void Initialize ( )
2015-03-08 03:10:20 +00:00
{
foreach ( var component in Components )
{
2015-05-18 00:14:00 +00:00
DebugService . WriteMessage ( "Initializing machine '{0}'" , component . GetType ( ) . Name ) ;
component . Initialize ( ) ;
//DebugService.WriteMessage("Initialized machine '{0}'", component.GetType().Name);
2015-03-08 03:10:20 +00:00
}
}
2015-05-18 00:14:00 +00:00
private void Uninitialize ( )
{
foreach ( var component in Components )
{
DebugService . WriteMessage ( "Uninitializing machine '{0}'" , component . GetType ( ) . Name ) ;
component . Uninitialize ( ) ;
//DebugService.WriteMessage("Uninitialized machine '{0}'", component.GetType().Name);
}
}
2015-02-18 00:06:49 +00:00
2015-05-18 00:14:00 +00:00
public void BizInitialize ( )
{
Initialize ( ) ;
Reset ( ) ;
}
2015-02-18 00:06:49 +00:00
2015-05-18 00:14:00 +00:00
public void BizFrameAdvance ( IEnumerable < string > buttons )
{
Lagged = true ;
2015-05-19 23:33:50 +00:00
DriveLight = false ;
2015-04-12 23:38:19 +00:00
2015-05-18 00:14:00 +00:00
Keyboard . SetKeys ( buttons ) ;
2015-02-18 00:06:49 +00:00
2015-05-18 00:14:00 +00:00
//frame begins at vsync.. beginning of vblank
while ( Video . IsVBlank )
{
/ *
var sb = new System . Text . StringBuilder ( ) ;
sb . AppendFormat ( "{0} " , Cpu ) ;
for ( int i = 0 ; i < 256 ; i + + )
sb . AppendFormat ( "{0:x2} " , Memory . Read ( i ) ) ;
tw . WriteLine ( sb . ToString ( ) ) ; * /
Events . HandleEvents ( Cpu . Execute ( ) ) ;
}
//now, while not vblank, we're in a frame
while ( ! Video . IsVBlank )
{
/ *
var sb = new System . Text . StringBuilder ( ) ;
sb . AppendFormat ( "{0} " , Cpu ) ;
for ( int i = 0 ; i < 256 ; i + + )
sb . AppendFormat ( "{0:x2} " , Memory . Read ( i ) ) ;
tw . WriteLine ( sb . ToString ( ) ) ; * /
Events . HandleEvents ( Cpu . Execute ( ) ) ;
}
}
2015-02-17 22:58:25 +00:00
2015-05-18 00:14:00 +00:00
public void BizShutdown ( )
{
Uninitialize ( ) ;
}
2015-02-17 22:58:25 +00:00
2015-05-18 00:14:00 +00:00
private static JsonSerializer CreateSerializer ( )
{
2015-05-19 23:27:28 +00:00
// TODO: converters could be cached for speedup
2015-05-18 00:14:00 +00:00
var ser = new JsonSerializer
{
TypeNameHandling = TypeNameHandling . Auto ,
PreserveReferencesHandling = PreserveReferencesHandling . All , // leaving out Array is a very important problem, and means that we can't rely on a directly shared array to work.
ReferenceLoopHandling = ReferenceLoopHandling . Serialize ,
} ;
2015-05-19 23:27:28 +00:00
ser . Converters . Add ( new TypeTypeConverter ( new [ ]
{
// all expected Types to convert are either in this assembly or mscorlib
typeof ( Machine ) . Assembly ,
typeof ( object ) . Assembly
} ) ) ;
2015-05-18 00:14:00 +00:00
ser . Converters . Add ( new DelegateConverter ( ) ) ;
ser . Converters . Add ( new ArrayConverter ( ) ) ;
2015-05-19 23:27:28 +00:00
2015-05-18 00:14:00 +00:00
var cr = new DefaultContractResolver ( ) ;
cr . DefaultMembersSearchFlags | = System . Reflection . BindingFlags . NonPublic ;
ser . ContractResolver = cr ;
return ser ;
}
2015-02-17 22:58:25 +00:00
2015-05-18 00:14:00 +00:00
public void Serialize ( JsonWriter w )
{
CreateSerializer ( ) . Serialize ( w , this ) ;
}
2015-02-17 22:58:25 +00:00
2015-05-18 00:14:00 +00:00
public static Machine Deserialize ( JsonReader r )
{
2015-05-20 00:12:19 +00:00
return CreateSerializer ( ) . Deserialize < Machine > ( r ) ;
2015-05-18 00:14:00 +00:00
}
2015-02-17 22:58:25 +00:00
2015-05-18 00:14:00 +00:00
public const string Version = "0.9.4.0" ;
2015-02-17 22:58:25 +00:00
2015-05-18 00:14:00 +00:00
public MachineEvents Events { get ; private set ; }
2015-02-17 22:58:25 +00:00
2015-05-18 00:14:00 +00:00
public Cpu Cpu { get ; private set ; }
public Memory Memory { get ; private set ; }
public Keyboard Keyboard { get ; private set ; }
public GamePort GamePort { get ; private set ; }
public Cassette Cassette { get ; private set ; }
public Speaker Speaker { get ; private set ; }
public Video Video { get ; private set ; }
public NoSlotClock NoSlotClock { get ; private set ; }
2015-03-08 01:34:18 +00:00
2015-05-18 00:14:00 +00:00
public PeripheralCard Slot1 { get ; private set ; }
public PeripheralCard Slot2 { get ; private set ; }
public PeripheralCard Slot3 { get ; private set ; }
public PeripheralCard Slot4 { get ; private set ; }
public PeripheralCard Slot5 { get ; private set ; }
public PeripheralCard Slot6 { get ; private set ; }
public PeripheralCard Slot7 { get ; private set ; }
2015-02-17 22:58:25 +00:00
2015-05-18 00:14:00 +00:00
public IList < PeripheralCard > Slots { get ; private set ; }
public IList < MachineComponent > Components { get ; private set ; }
2015-02-17 22:58:25 +00:00
2015-05-18 00:14:00 +00:00
public DiskIIController BootDiskII { get ; private set ; }
2015-04-26 12:40:21 +00:00
public bool Lagged { get ; set ; }
2015-05-19 23:33:50 +00:00
public bool DriveLight { get ; set ; }
2015-06-12 23:51:03 +00:00
public IDictionary < string , int > GetCpuFlagsAndRegisters ( )
{
return new Dictionary < string , int >
{
{ "A" , Cpu . RA } ,
{ "X" , Cpu . RX } ,
{ "Y" , Cpu . RY } ,
{ "S" , Cpu . RS } ,
{ "PC" , Cpu . RPC } ,
{ "Flag C" , Cpu . FlagC ? 1 : 0 } ,
{ "Flag Z" , Cpu . FlagZ ? 1 : 0 } ,
{ "Flag I" , Cpu . FlagI ? 1 : 0 } ,
{ "Flag D" , Cpu . FlagD ? 1 : 0 } ,
{ "Flag B" , Cpu . FlagB ? 1 : 0 } ,
{ "Flag V" , Cpu . FlagV ? 1 : 0 } ,
{ "Flag N" , Cpu . FlagN ? 1 : 0 } ,
{ "Flag T" , Cpu . FlagT ? 1 : 0 }
} ;
}
2015-05-18 00:14:00 +00:00
}
2015-02-17 22:58:25 +00:00
}