diff --git a/6502EmulatorFrontend/6502EmulatorFrontend.psess b/6502EmulatorFrontend/6502EmulatorFrontend.psess new file mode 100644 index 0000000..b1b1a3c --- /dev/null +++ b/6502EmulatorFrontend/6502EmulatorFrontend.psess @@ -0,0 +1,80 @@ + + + + 6502EmulatorFrontend.sln + Sampling + None + true + true + Timestamp + Cycles + 10000000 + 10 + 10 + + false + + + + false + 500 + + \Memory\Pages/sec + \PhysicalDisk(_Total)\Avg. Disk Queue Length + \Processor(_Total)\% Processor Time + + + + true + false + false + + false + + + false + + + + 6502EmulatorFrontend\obj\Release\6502EmulatorFrontend.exe + 01/01/0001 00:00:00 + true + true + false + false + false + false + false + true + false + Executable + 6502EmulatorFrontend\bin\Release\6502EmulatorFrontend.exe + 6502EmulatorFrontend\bin\Release\ + + + IIS + InternetExplorer + true + false + + false + + + false + + {C198497A-3D3E-4F01-A72B-642DAB6B11D6}|6502EmulatorFrontend\6502EmulatorFrontend.csproj + 6502EmulatorFrontend\6502EmulatorFrontend.csproj + 6502EmulatorFrontend + + + + + 6502EmulatorFrontend151126.vsp + + + + + :PB:{C198497A-3D3E-4F01-A72B-642DAB6B11D6}|6502EmulatorFrontend\6502EmulatorFrontend.csproj + + + \ No newline at end of file diff --git a/6502EmulatorFrontend/6502EmulatorFrontend.sln b/6502EmulatorFrontend/6502EmulatorFrontend.sln new file mode 100644 index 0000000..1e8e8fb --- /dev/null +++ b/6502EmulatorFrontend/6502EmulatorFrontend.sln @@ -0,0 +1,36 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 14 +VisualStudioVersion = 14.0.24627.0 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "6502EmulatorFrontend", "6502EmulatorFrontend\6502EmulatorFrontend.csproj", "{C198497A-3D3E-4F01-A72B-642DAB6B11D6}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{6804C707-42F4-43D0-9C94-526B5A7DB885}" +EndProject +Global + GlobalSection(Performance) = preSolution + HasPerformanceSessions = true + EndGlobalSection + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {C198497A-3D3E-4F01-A72B-642DAB6B11D6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {C198497A-3D3E-4F01-A72B-642DAB6B11D6}.Debug|Any CPU.Build.0 = Debug|Any CPU + {C198497A-3D3E-4F01-A72B-642DAB6B11D6}.Release|Any CPU.ActiveCfg = Release|Any CPU + {C198497A-3D3E-4F01-A72B-642DAB6B11D6}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(TeamFoundationVersionControl) = preSolution + SccNumberOfProjects = 2 + SccEnterpriseProvider = {4CA58AB2-18FA-4F8D-95D4-32DDF27D184C} + SccTeamFoundationServer = https://luigithirty.visualstudio.com/defaultcollection + SccLocalPath0 = . + SccProjectUniqueName1 = 6502EmulatorFrontend\\6502EmulatorFrontend.csproj + SccProjectName1 = 6502EmulatorFrontend + SccLocalPath1 = 6502EmulatorFrontend + EndGlobalSection +EndGlobal diff --git a/6502EmulatorFrontend/6502EmulatorFrontend.vssscc b/6502EmulatorFrontend/6502EmulatorFrontend.vssscc new file mode 100644 index 0000000..6cb031b --- /dev/null +++ b/6502EmulatorFrontend/6502EmulatorFrontend.vssscc @@ -0,0 +1,10 @@ +"" +{ +"FILE_VERSION" = "9237" +"ENLISTMENT_CHOICE" = "NEVER" +"PROJECT_FILE_RELATIVE_PATH" = "" +"NUMBER_OF_EXCLUDED_FILES" = "0" +"ORIGINAL_PROJECT_FILE_PATH" = "" +"NUMBER_OF_NESTED_PROJECTS" = "0" +"SOURCE_CONTROL_SETTINGS_PROVIDER" = "PROJECT" +} diff --git a/6502EmulatorFrontend/6502EmulatorFrontend/6502EmulatorFrontend.csproj b/6502EmulatorFrontend/6502EmulatorFrontend/6502EmulatorFrontend.csproj new file mode 100644 index 0000000..8f2563e --- /dev/null +++ b/6502EmulatorFrontend/6502EmulatorFrontend/6502EmulatorFrontend.csproj @@ -0,0 +1,126 @@ + + + + + Debug + AnyCPU + {C198497A-3D3E-4F01-A72B-642DAB6B11D6} + WinExe + Properties + _6502EmulatorFrontend + 6502EmulatorFrontend + v4.6 + 512 + {60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + 4 + true + SAK + SAK + SAK + SAK + + + AnyCPU + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + AnyCPU + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + + + + + + + + + 4.0 + + + + + + E:\WriteableBitmapEx\WPF\WriteableBitmapEx.Wpf.dll + + + + + MSBuild:Compile + Designer + + + + + + + + + MSBuild:Compile + Designer + + + App.xaml + Code + + + + + + + MainWindow.xaml + Code + + + + + Code + + + True + True + Resources.resx + + + True + Settings.settings + True + + + ResXFileCodeGenerator + Resources.Designer.cs + + + SettingsSingleFileGenerator + Settings.Designer.cs + + + + + + + + + + + + \ No newline at end of file diff --git a/6502EmulatorFrontend/6502EmulatorFrontend/App.config b/6502EmulatorFrontend/6502EmulatorFrontend/App.config new file mode 100644 index 0000000..8324aa6 --- /dev/null +++ b/6502EmulatorFrontend/6502EmulatorFrontend/App.config @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/6502EmulatorFrontend/6502EmulatorFrontend/App.xaml b/6502EmulatorFrontend/6502EmulatorFrontend/App.xaml new file mode 100644 index 0000000..259fa8c --- /dev/null +++ b/6502EmulatorFrontend/6502EmulatorFrontend/App.xaml @@ -0,0 +1,9 @@ + + + + + diff --git a/6502EmulatorFrontend/6502EmulatorFrontend/App.xaml.cs b/6502EmulatorFrontend/6502EmulatorFrontend/App.xaml.cs new file mode 100644 index 0000000..7e29857 --- /dev/null +++ b/6502EmulatorFrontend/6502EmulatorFrontend/App.xaml.cs @@ -0,0 +1,17 @@ +using System; +using System.Collections.Generic; +using System.Configuration; +using System.Data; +using System.Linq; +using System.Threading.Tasks; +using System.Windows; + +namespace _6502EmulatorFrontend +{ + /// + /// Interaction logic for App.xaml + /// + public partial class App : Application + { + } +} diff --git a/6502EmulatorFrontend/6502EmulatorFrontend/Apple2Display.cs b/6502EmulatorFrontend/6502EmulatorFrontend/Apple2Display.cs new file mode 100644 index 0000000..08738fd --- /dev/null +++ b/6502EmulatorFrontend/6502EmulatorFrontend/Apple2Display.cs @@ -0,0 +1,30 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Media.Imaging; + +namespace _6502EmulatorFrontend +{ + class Apple2Display : IDisplay + { + public WriteableBitmap DisplayCanvas + { + get + { + throw new NotImplementedException(); + } + + set + { + throw new NotImplementedException(); + } + } + + public void onUpdateDisplay(object sender, EventArgs e) + { + throw new NotImplementedException(); + } + } +} diff --git a/6502EmulatorFrontend/6502EmulatorFrontend/AppleDisplay.cs b/6502EmulatorFrontend/6502EmulatorFrontend/AppleDisplay.cs new file mode 100644 index 0000000..21a483e --- /dev/null +++ b/6502EmulatorFrontend/6502EmulatorFrontend/AppleDisplay.cs @@ -0,0 +1,201 @@ +using _6502EmulatorFrontend.video; +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Linq; +using System.Text; +using System.Threading; +using System.Threading.Tasks; +using System.Windows; +using System.Windows.Media; +using System.Windows.Media.Imaging; + +namespace _6502EmulatorFrontend +{ + public class AppleDisplay : INotifyPropertyChanged, IDisplay + { + private CharacterSet _characters; + private readonly SynchronizationContext _syncContext; + + public List DisplayRows; + public WriteableBitmap _displayCanvas; + public WriteableBitmap DisplayCanvas { + get { return _displayCanvas; } + set + { + if (value != _displayCanvas) + { + _displayCanvas = value; + OnPropertyChanged("DisplayCanvas"); + } + } + } + int cursorPositionX; + int cursorPositionY; + bool cursorEnabled; + + public AppleDisplay() + { + Characters = new CharacterSet(); + DisplayCanvas = new WriteableBitmap(320, 192, 96, 96, PixelFormats.Bgr32, null); + DisplayRows = new List(); + _syncContext = SynchronizationContext.Current; + cursorPositionX = 0; + cursorPositionY = 0; + cursorEnabled = false; + for(int i = 0; i < 24; i++) + { + DisplayRows.Insert(i, new DisplayRow()); + } + } + + public void PutCharacter(CharacterBitmap character) + { + SetTile(cursorPositionY, cursorPositionX, character); //(row,column) + if(cursorPositionX == 39) + { + CarriageReturn(); + } else + { + cursorPositionX++; + } + } + + public void CarriageReturn() + { + _syncContext.Post(o => SetTile(cursorPositionY, cursorPositionX, Characters.CharacterList[0x20]), null); + + if (cursorEnabled) + { + + cursorPositionX = 0; + cursorPositionY++; + if (cursorPositionY == 24) + { + cursorPositionY = 23; + DisplayRows.RemoveAt(0); + DisplayRows.Insert(23, new DisplayRow()); + } + } + else + { + cursorPositionX = 0; + cursorPositionY++; + if (cursorPositionY == 24) + { + cursorPositionY = 23; + DisplayRows.RemoveAt(0); + DisplayRows.Insert(23, new DisplayRow()); + } + } + } + + public void onToggleCursor(M6502 sender, EventArgs e) + { + if (!cursorEnabled) + { + _syncContext.Post(o => SetTile(cursorPositionY, cursorPositionX, Characters.CharacterList[0x00]), null); + cursorEnabled = true; + } + else + { + _syncContext.Post(o => SetTile(cursorPositionY, cursorPositionX, Characters.CharacterList[0x20]), null); + cursorEnabled = false; + } + + } + + public void SetTile(int row, int column, CharacterBitmap character) + { + DisplayRows[row].Characters[column] = character; + DrawScreen(); + } + + private void DrawScreen() + { + for(int row = 0; row < 24; row++) + { + for(int column = 0; column < 40; column++) + { + var tile = DisplayRows[row].Characters[column].CharacterImage; + + int offsetX = (column * 8); + int offsetY = (row * 8); + int stride = tile.PixelWidth * (tile.Format.BitsPerPixel / 8); + byte[] data = new byte[stride * tile.PixelHeight]; + tile.CopyPixels(data, stride, 0); + + DisplayCanvas.WritePixels(new Int32Rect(0, 0, 8, 8), data, stride, offsetX, offsetY); + } + } + + } + + public void onCharacterInDisplayBuffer(AppleDisplay sender, CharacterInDisplayBufferEventArgs e) + { + byte key = (byte)e.Character; + + if (e.Character == 0x0d) + { + _syncContext.Post(o => CarriageReturn(), null); + return; + } + + if ((key & 0x60) == 0x60) + { + key = (byte)(key & ~0x60); + } + if((key & 0x40) == 0x40) + { + key = (byte)(key & ~0x40); + } + + _syncContext.Post(o => PutCharacter(Characters.CharacterList[key]), null); + } + + public void onUpdateDisplay(object sender, EventArgs e) + { + byte outputBuffer = Interop.getOutputBuffer(); + if (outputBuffer != 0x00) + { + onCharacterInDisplayBuffer(this, new CharacterInDisplayBufferEventArgs(outputBuffer)); + } + } + + public event PropertyChangedEventHandler PropertyChanged; + protected virtual void OnPropertyChanged(string name) + { + var handler = System.Threading.Interlocked.CompareExchange(ref PropertyChanged, null, null); + if (handler != null) + { + handler(this, new PropertyChangedEventArgs(name)); + } + } + + public CharacterSet Characters + { + get { return _characters; } + set + { + if (value != _characters) + { + _characters = value; + OnPropertyChanged("Characters"); + } + } + } + } + + public class DisplayRow + { + public List Characters = new List(); + + public DisplayRow() + { + for (int j = 0; j < 40; j++) + { + Characters.Insert(j, CharacterBitmap.BlankBitmap); + } + } + } +} diff --git a/6502EmulatorFrontend/6502EmulatorFrontend/IDisplay.cs b/6502EmulatorFrontend/6502EmulatorFrontend/IDisplay.cs new file mode 100644 index 0000000..0d94c8e --- /dev/null +++ b/6502EmulatorFrontend/6502EmulatorFrontend/IDisplay.cs @@ -0,0 +1,15 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Media.Imaging; + +namespace _6502EmulatorFrontend +{ + interface IDisplay + { + void onUpdateDisplay(object sender, EventArgs e); + WriteableBitmap DisplayCanvas { get; set; } + } +} diff --git a/6502EmulatorFrontend/6502EmulatorFrontend/Interop.cs b/6502EmulatorFrontend/6502EmulatorFrontend/Interop.cs new file mode 100644 index 0000000..2b211e5 --- /dev/null +++ b/6502EmulatorFrontend/6502EmulatorFrontend/Interop.cs @@ -0,0 +1,76 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.InteropServices; +using System.Text; +using System.Threading.Tasks; + +namespace _6502EmulatorFrontend +{ + public class Interop + { + [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)] + public struct InteropProcessorStatus + { + public ushort cycles; //cycles + public byte FLAG_SIGN; //N + public byte FLAG_OVERFLOW; //V + //- + public byte FLAG_BREAKPOINT; //B + public byte FLAG_DECIMAL; //D + public byte FLAG_INTERRUPT; //I + public byte FLAG_ZERO; //Z + public byte FLAG_CARRY; //C + + public byte accumulator; //A + public byte index_x; //X + public byte index_y; //Y + public byte stack_pointer; //SP + public ushort program_counter; //PC + public ushort old_program_counter; //before this opcode ran + + IntPtr last_opcode; + public string lastOpcodeAsString { get { return Marshal.PtrToStringAnsi(last_opcode); } } + }; + + [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)] + public struct MC6821Status + { + public byte KBD; + public byte KBDCR; + public byte DSP; + public byte DSPCR; + }; + + [DllImport("C:/Users/Luigi/Documents/Visual Studio 2015/Projects/M6502EmulatorDll/Debug/M6502EmulatorDll.dll", CallingConvention = CallingConvention.Cdecl)] + public static extern bool loadBinary([MarshalAs(UnmanagedType.LPStr)] string path, ushort address); + + [DllImport("C:/Users/Luigi/Documents/Visual Studio 2015/Projects/M6502EmulatorDll/Debug/M6502EmulatorDll.dll", CallingConvention = CallingConvention.Cdecl)] + public static extern ushort getProgramCounter(); + + [DllImport("C:/Users/Luigi/Documents/Visual Studio 2015/Projects/M6502EmulatorDll/Debug/M6502EmulatorDll.dll", CallingConvention = CallingConvention.Cdecl)] + public static extern InteropProcessorStatus getProcessorStatus(); + + [DllImport("C:/Users/Luigi/Documents/Visual Studio 2015/Projects/M6502EmulatorDll/Debug/M6502EmulatorDll.dll", CallingConvention = CallingConvention.Cdecl)] + public static extern void resetProcessor(); + + //Execution + [DllImport("C:/Users/Luigi/Documents/Visual Studio 2015/Projects/M6502EmulatorDll/Debug/M6502EmulatorDll.dll", CallingConvention = CallingConvention.Cdecl)] + public static extern void doSingleStep(); + + [DllImport("C:/Users/Luigi/Documents/Visual Studio 2015/Projects/M6502EmulatorDll/Debug/M6502EmulatorDll.dll", CallingConvention = CallingConvention.Cdecl)] + public static extern MC6821Status getMC6821Status(); + + [DllImport("C:/Users/Luigi/Documents/Visual Studio 2015/Projects/M6502EmulatorDll/Debug/M6502EmulatorDll.dll", CallingConvention = CallingConvention.Cdecl)] + public static extern byte getOutputBuffer(); + + [DllImport("C:/Users/Luigi/Documents/Visual Studio 2015/Projects/M6502EmulatorDll/Debug/M6502EmulatorDll.dll", CallingConvention = CallingConvention.Cdecl)] + public static extern IntPtr getMemoryRange(ushort baseAddr, ushort length); + + [DllImport("C:/Users/Luigi/Documents/Visual Studio 2015/Projects/M6502EmulatorDll/Debug/M6502EmulatorDll.dll", CallingConvention = CallingConvention.Cdecl)] + public static extern void resetCycleCounter(); + + [DllImport("C:/Users/Luigi/Documents/Visual Studio 2015/Projects/M6502EmulatorDll/Debug/M6502EmulatorDll.dll", CallingConvention = CallingConvention.Cdecl)] + public static extern void putKeyInBuffer(byte key); + } +} diff --git a/6502EmulatorFrontend/6502EmulatorFrontend/MainWindow.xaml b/6502EmulatorFrontend/6502EmulatorFrontend/MainWindow.xaml new file mode 100644 index 0000000..902af10 --- /dev/null +++ b/6502EmulatorFrontend/6502EmulatorFrontend/MainWindow.xaml @@ -0,0 +1,59 @@ + + +