started adding settings window for ROM paths

cycle counts accurate when crossing page boundaries
lots of other improvements
This commit is contained in:
Luigi Thirty 2015-12-04 22:10:31 -05:00
parent 792386aceb
commit 7235d3a3bb
13 changed files with 495 additions and 195 deletions

View File

@ -1,7 +1,7 @@
 
Microsoft Visual Studio Solution File, Format Version 12.00 Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 14 # Visual Studio 14
VisualStudioVersion = 14.0.24627.0 VisualStudioVersion = 14.0.24720.0
MinimumVisualStudioVersion = 10.0.40219.1 MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "6502EmulatorFrontend", "6502EmulatorFrontend\6502EmulatorFrontend.csproj", "{C198497A-3D3E-4F01-A72B-642DAB6B11D6}" Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "6502EmulatorFrontend", "6502EmulatorFrontend\6502EmulatorFrontend.csproj", "{C198497A-3D3E-4F01-A72B-642DAB6B11D6}"
EndProject EndProject
@ -24,13 +24,4 @@ Global
GlobalSection(SolutionProperties) = preSolution GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE HideSolutionNode = FALSE
EndGlobalSection 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 EndGlobal

View File

@ -18,6 +18,21 @@
<SccLocalPath>SAK</SccLocalPath> <SccLocalPath>SAK</SccLocalPath>
<SccAuxPath>SAK</SccAuxPath> <SccAuxPath>SAK</SccAuxPath>
<SccProvider>SAK</SccProvider> <SccProvider>SAK</SccProvider>
<PublishUrl>publish\</PublishUrl>
<Install>true</Install>
<InstallFrom>Disk</InstallFrom>
<UpdateEnabled>false</UpdateEnabled>
<UpdateMode>Foreground</UpdateMode>
<UpdateInterval>7</UpdateInterval>
<UpdateIntervalUnits>Days</UpdateIntervalUnits>
<UpdatePeriodically>false</UpdatePeriodically>
<UpdateRequired>false</UpdateRequired>
<MapFileExtensions>true</MapFileExtensions>
<ApplicationRevision>0</ApplicationRevision>
<ApplicationVersion>1.0.0.%2a</ApplicationVersion>
<IsWebBootstrapper>false</IsWebBootstrapper>
<UseApplicationTrust>false</UseApplicationTrust>
<BootstrapperEnabled>true</BootstrapperEnabled>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "> <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget> <PlatformTarget>AnyCPU</PlatformTarget>
@ -65,7 +80,12 @@
<Compile Include="Apple2Display.cs" /> <Compile Include="Apple2Display.cs" />
<Compile Include="cpu\Disassembly.cs" /> <Compile Include="cpu\Disassembly.cs" />
<Compile Include="IDisplay.cs" /> <Compile Include="IDisplay.cs" />
<Compile Include="MainWindowEvents.cs" />
<Compile Include="MainWindowViewModel.cs" /> <Compile Include="MainWindowViewModel.cs" />
<Compile Include="SettingsWindow.xaml.cs">
<DependentUpon>SettingsWindow.xaml</DependentUpon>
</Compile>
<Compile Include="SettingsWindowViewModel.cs" />
<Compile Include="video\CharacterBitmap.cs" /> <Compile Include="video\CharacterBitmap.cs" />
<Compile Include="video\CharacterSet.cs" /> <Compile Include="video\CharacterSet.cs" />
<Page Include="MainWindow.xaml"> <Page Include="MainWindow.xaml">
@ -84,6 +104,10 @@
<DependentUpon>MainWindow.xaml</DependentUpon> <DependentUpon>MainWindow.xaml</DependentUpon>
<SubType>Code</SubType> <SubType>Code</SubType>
</Compile> </Compile>
<Page Include="SettingsWindow.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Compile Include="Properties\AssemblyInfo.cs"> <Compile Include="Properties\AssemblyInfo.cs">
@ -115,6 +139,18 @@
<ItemGroup> <ItemGroup>
<Folder Include="memory\" /> <Folder Include="memory\" />
</ItemGroup> </ItemGroup>
<ItemGroup>
<BootstrapperPackage Include=".NETFramework,Version=v4.6">
<Visible>False</Visible>
<ProductName>Microsoft .NET Framework 4.6 %28x86 and x64%29</ProductName>
<Install>true</Install>
</BootstrapperPackage>
<BootstrapperPackage Include="Microsoft.Net.Framework.3.5.SP1">
<Visible>False</Visible>
<ProductName>.NET Framework 3.5 SP1</ProductName>
<Install>false</Install>
</BootstrapperPackage>
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it. <!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets. Other similar extension points exist, see Microsoft.Common.targets.

View File

@ -42,35 +42,35 @@ namespace _6502EmulatorFrontend
public byte DSPCR; public byte DSPCR;
}; };
[DllImport("C:/Users/Luigi/Documents/Visual Studio 2015/Projects/M6502EmulatorDll/Debug/M6502EmulatorDll.dll", CallingConvention = CallingConvention.Cdecl)] [DllImport("C:/apple/fruitmachine/M6502EmulatorDll/Debug/M6502EmulatorDll.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern bool loadBinary([MarshalAs(UnmanagedType.LPStr)] string path, ushort address); 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)] [DllImport("C:/apple/fruitmachine/M6502EmulatorDll/Debug/M6502EmulatorDll.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern ushort getProgramCounter(); public static extern ushort getProgramCounter();
[DllImport("C:/Users/Luigi/Documents/Visual Studio 2015/Projects/M6502EmulatorDll/Debug/M6502EmulatorDll.dll", CallingConvention = CallingConvention.Cdecl)] [DllImport("C:/apple/fruitmachine/M6502EmulatorDll/Debug/M6502EmulatorDll.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern InteropProcessorStatus getProcessorStatus(); public static extern InteropProcessorStatus getProcessorStatus();
[DllImport("C:/Users/Luigi/Documents/Visual Studio 2015/Projects/M6502EmulatorDll/Debug/M6502EmulatorDll.dll", CallingConvention = CallingConvention.Cdecl)] [DllImport("C:/apple/fruitmachine/M6502EmulatorDll/Debug/M6502EmulatorDll.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern void resetProcessor(); public static extern void resetProcessor();
//Execution //Execution
[DllImport("C:/Users/Luigi/Documents/Visual Studio 2015/Projects/M6502EmulatorDll/Debug/M6502EmulatorDll.dll", CallingConvention = CallingConvention.Cdecl)] [DllImport("C:/apple/fruitmachine/M6502EmulatorDll/Debug/M6502EmulatorDll.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern void doSingleStep(); public static extern void doSingleStep();
[DllImport("C:/Users/Luigi/Documents/Visual Studio 2015/Projects/M6502EmulatorDll/Debug/M6502EmulatorDll.dll", CallingConvention = CallingConvention.Cdecl)] [DllImport("C:/apple/fruitmachine/M6502EmulatorDll/Debug/M6502EmulatorDll.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern MC6821Status getMC6821Status(); public static extern MC6821Status getMC6821Status();
[DllImport("C:/Users/Luigi/Documents/Visual Studio 2015/Projects/M6502EmulatorDll/Debug/M6502EmulatorDll.dll", CallingConvention = CallingConvention.Cdecl)] [DllImport("C:/apple/fruitmachine/M6502EmulatorDll/Debug/M6502EmulatorDll.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern byte getOutputBuffer(); public static extern byte getOutputBuffer();
[DllImport("C:/Users/Luigi/Documents/Visual Studio 2015/Projects/M6502EmulatorDll/Debug/M6502EmulatorDll.dll", CallingConvention = CallingConvention.Cdecl)] [DllImport("C:/apple/fruitmachine/M6502EmulatorDll/Debug/M6502EmulatorDll.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern IntPtr getMemoryRange(ushort baseAddr, ushort length); 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)] [DllImport("C:/apple/fruitmachine/M6502EmulatorDll/Debug/M6502EmulatorDll.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern void resetCycleCounter(); public static extern void resetCycleCounter();
[DllImport("C:/Users/Luigi/Documents/Visual Studio 2015/Projects/M6502EmulatorDll/Debug/M6502EmulatorDll.dll", CallingConvention = CallingConvention.Cdecl)] [DllImport("C:/apple/fruitmachine/M6502EmulatorDll/Debug/M6502EmulatorDll.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern void putKeyInBuffer(byte key); public static extern void putKeyInBuffer(byte key);
} }
} }

View File

@ -5,55 +5,64 @@
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:_6502EmulatorFrontend" xmlns:local="clr-namespace:_6502EmulatorFrontend"
mc:Ignorable="d" mc:Ignorable="d"
Title="Fruit Machine 0.0000001a" Height="600" Width="954"> Title="Fruit Machine 0.0000001a" Height="700" Width="954">
<Grid> <DockPanel>
<Button x:Name="btnLoadBinary" Content="Load Binary" HorizontalAlignment="Left" Margin="10,10,0,0" VerticalAlignment="Top" Width="75" Click="btnLoadBinary_Click"/> <Menu DockPanel.Dock="Top">
<Label x:Name="binaryLoadedStatus" Content="Label" HorizontalAlignment="Left" Margin="90,8,0,0" VerticalAlignment="Top" Width="417"/> <MenuItem Header="_File"/>
<Grid HorizontalAlignment="Left" Height="185" Margin="10,39,0,0" VerticalAlignment="Top" Width="200" Background="#FFACACAC"> <MenuItem Header="_Settings">
<Grid.ColumnDefinitions> <MenuItem Header="_ROM Paths" Click="MenuItem_Click"/>
<ColumnDefinition Width="3*"/> </MenuItem>
<ColumnDefinition Width="5*"/>
</Grid.ColumnDefinitions> </Menu>
<StackPanel Orientation="Vertical" Grid.ColumnSpan="1"> <Grid>
<Separator Style="{StaticResource {x:Static ToolBar.SeparatorStyleKey}}" /> <Button x:Name="btnLoadBinary" Content="Load Binary" HorizontalAlignment="Left" Margin="10,0,0,0" VerticalAlignment="Top" Width="75" Click="btnLoadBinary_Click"/>
<Label Content="PC" Height="25"></Label> <Label x:Name="binaryLoadedStatus" Content="Label" HorizontalAlignment="Left" Margin="90,108,0,0" VerticalAlignment="Top" Width="417"/>
<Separator Style="{StaticResource {x:Static ToolBar.SeparatorStyleKey}}" /> <Grid HorizontalAlignment="Left" Height="185" Margin="10,27,0,0" VerticalAlignment="Top" Width="200" Background="#FFACACAC">
<Label Content="A" Height="25"></Label> <Grid.ColumnDefinitions>
<Separator Style="{StaticResource {x:Static ToolBar.SeparatorStyleKey}}" /> <ColumnDefinition Width="3*"/>
<Label Content="X" Height="25"></Label> <ColumnDefinition Width="5*"/>
<Separator Style="{StaticResource {x:Static ToolBar.SeparatorStyleKey}}" /> </Grid.ColumnDefinitions>
<Label Content="Y" Height="25"></Label> <StackPanel Orientation="Vertical" Grid.ColumnSpan="1">
<Separator Style="{StaticResource {x:Static ToolBar.SeparatorStyleKey}}" /> <Separator Style="{StaticResource {x:Static ToolBar.SeparatorStyleKey}}" />
<Label Content="SP" Height="25"></Label> <Label Content="PC" Height="25"></Label>
<Separator Style="{StaticResource {x:Static ToolBar.SeparatorStyleKey}}" /> <Separator Style="{StaticResource {x:Static ToolBar.SeparatorStyleKey}}" />
<Label Content="Flags" Height="25"></Label> <Label Content="A" Height="25"></Label>
</StackPanel> <Separator Style="{StaticResource {x:Static ToolBar.SeparatorStyleKey}}" />
<StackPanel Orientation="Vertical" Grid.ColumnSpan="1" Grid.Column="1"> <Label Content="X" Height="25"></Label>
<Separator Style="{StaticResource {x:Static ToolBar.SeparatorStyleKey}}" /> <Separator Style="{StaticResource {x:Static ToolBar.SeparatorStyleKey}}" />
<TextBox Name="txtProgramCounter" Height="25" Text="{Binding Path=Processor.ProgramCounter, StringFormat={}{0:X4}}" HorizontalAlignment="Right" Width="115" Margin="0,0,10,0" FontFamily="Courier New" FontWeight="Bold" FontSize="13.333"></TextBox> <Label Content="Y" Height="25"></Label>
<Separator Style="{StaticResource {x:Static ToolBar.SeparatorStyleKey}}" /> <Separator Style="{StaticResource {x:Static ToolBar.SeparatorStyleKey}}" />
<TextBox Name="txtAccumulator" Height="25" Text="{Binding Path=Processor.Accumulator, StringFormat={}{0:X2}}" Margin="0,0,10,0" FontFamily="Courier New" FontWeight="Bold" FontSize="13.333"></TextBox> <Label Content="SP" Height="25"></Label>
<Separator Style="{StaticResource {x:Static ToolBar.SeparatorStyleKey}}" /> <Separator Style="{StaticResource {x:Static ToolBar.SeparatorStyleKey}}" />
<TextBox Name="txtIndexX" Height="25" Text="{Binding Path=Processor.IndexX, StringFormat={}{0:X2}}" Margin="0,0,10,0" FontFamily="Courier New" FontWeight="Bold" FontSize="13.333"></TextBox> <Label Content="Flags" Height="25"></Label>
<Separator Style="{StaticResource {x:Static ToolBar.SeparatorStyleKey}}" /> </StackPanel>
<TextBox Name="txtIndexY" Height="25" Text="{Binding Path=Processor.IndexY, StringFormat={}{0:X2}}" Margin="0,0,10,0" FontFamily="Courier New" FontWeight="Bold" FontSize="13.333"></TextBox> <StackPanel Orientation="Vertical" Grid.ColumnSpan="1" Grid.Column="1">
<Separator Style="{StaticResource {x:Static ToolBar.SeparatorStyleKey}}" /> <Separator Style="{StaticResource {x:Static ToolBar.SeparatorStyleKey}}" />
<TextBox Name="txtStackPointer" Height="25" Text="{Binding Path=Processor.StackPointer, StringFormat={}{0:X2}}" Margin="0,0,10,0" FontFamily="Courier New" FontWeight="Bold" FontSize="13.333"></TextBox> <TextBox Name="txtProgramCounter" Height="25" Text="{Binding Path=Processor.ProgramCounter, StringFormat={}{0:X4}}" HorizontalAlignment="Right" Width="115" Margin="0,0,10,0" FontFamily="Courier New" FontWeight="Bold" FontSize="13.333"></TextBox>
<Separator Style="{StaticResource {x:Static ToolBar.SeparatorStyleKey}}" /> <Separator Style="{StaticResource {x:Static ToolBar.SeparatorStyleKey}}" />
<TextBox Name="txtFlags" Height="25" Text="{Binding Path=Processor.Flags}" Margin="0,0,10,0" FontFamily="Courier New" FontWeight="Bold" FontSize="13.333"></TextBox> <TextBox Name="txtAccumulator" Height="25" Text="{Binding Path=Processor.Accumulator, StringFormat={}{0:X2}}" Margin="0,0,10,0" FontFamily="Courier New" FontWeight="Bold" FontSize="13.333"></TextBox>
</StackPanel> <Separator Style="{StaticResource {x:Static ToolBar.SeparatorStyleKey}}" />
</Grid> <TextBox Name="txtIndexX" Height="25" Text="{Binding Path=Processor.IndexX, StringFormat={}{0:X2}}" Margin="0,0,10,0" FontFamily="Courier New" FontWeight="Bold" FontSize="13.333"></TextBox>
<Button x:Name="btnSingleStep" Content="Single Step" HorizontalAlignment="Left" Margin="10,229,0,0" VerticalAlignment="Top" Width="75" Click="btnSingleStep_Click" IsEnabled="False"/> <Separator Style="{StaticResource {x:Static ToolBar.SeparatorStyleKey}}" />
<Image x:Name="image" Source="{Binding Path=DisplayGrid.DisplayCanvas}" HorizontalAlignment="Left" Height="384" Margin="215,39,0,0" VerticalAlignment="Top" Width="640" RenderOptions.BitmapScalingMode="NearestNeighbor"/> <TextBox Name="txtIndexY" Height="25" Text="{Binding Path=Processor.IndexY, StringFormat={}{0:X2}}" Margin="0,0,10,0" FontFamily="Courier New" FontWeight="Bold" FontSize="13.333"></TextBox>
<Button x:Name="btnRun" Content="Run" HorizontalAlignment="Left" Margin="135,229,0,0" VerticalAlignment="Top" Width="75" Click="btnRun_Click" IsEnabled="False"/> <Separator Style="{StaticResource {x:Static ToolBar.SeparatorStyleKey}}" />
<ListBox x:Name="lbDisassembly" ItemsSource="{Binding DisassembledOpcodes}" HorizontalAlignment="Left" Height="277" Margin="10,283,0,0" VerticalAlignment="Top" Width="200" FontFamily="Courier New"> <TextBox Name="txtStackPointer" Height="25" Text="{Binding Path=Processor.StackPointer, StringFormat={}{0:X2}}" Margin="0,0,10,0" FontFamily="Courier New" FontWeight="Bold" FontSize="13.333"></TextBox>
<ListBox.Resources> <Separator Style="{StaticResource {x:Static ToolBar.SeparatorStyleKey}}" />
<SolidColorBrush x:Key="{x:Static SystemColors.InactiveSelectionHighlightBrushKey}">LightBlue</SolidColorBrush> <TextBox Name="txtFlags" Height="25" Text="{Binding Path=Processor.Flags}" Margin="0,0,10,0" FontFamily="Courier New" FontWeight="Bold" FontSize="13.333"></TextBox>
</ListBox.Resources> </StackPanel>
</ListBox> </Grid>
<TextBox ScrollViewer.VerticalScrollBarVisibility="Visible" x:Name="tbDebugConsole" HorizontalAlignment="Left" Height="104" Margin="215,428,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="721"/> <Button x:Name="btnSingleStep" Content="Single Step" HorizontalAlignment="Left" Margin="10,217,0,0" VerticalAlignment="Top" Width="75" Click="btnSingleStep_Click" IsEnabled="False"/>
<Button x:Name="btnBreak" Content="Break" HorizontalAlignment="Left" Margin="135,256,0,0" VerticalAlignment="Top" Width="75" Click="btnBreak_Click"/> <Image x:Name="image" Source="{Binding Path=DisplayGrid.DisplayCanvas}" HorizontalAlignment="Left" Height="384" Margin="215,0,0,0" VerticalAlignment="Top" Width="640" RenderOptions.BitmapScalingMode="NearestNeighbor"/>
<TextBox x:Name="tbDebugEntry" HorizontalAlignment="Left" Height="23" Margin="215,537,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="721" KeyDown="tbDebugEntry_KeyDown"/> <Button x:Name="btnRun" Content="Run" HorizontalAlignment="Left" Margin="135,217,0,0" VerticalAlignment="Top" Width="75" Click="btnRun_Click" IsEnabled="False"/>
<ListBox x:Name="lbDisassembly" ItemsSource="{Binding DisassembledOpcodes}" HorizontalAlignment="Left" Height="277" Margin="10,271,0,0" VerticalAlignment="Top" Width="200" FontFamily="Courier New">
<ListBox.Resources>
<SolidColorBrush x:Key="{x:Static SystemColors.InactiveSelectionHighlightBrushKey}">LightBlue</SolidColorBrush>
</ListBox.Resources>
</ListBox>
<TextBox ScrollViewer.VerticalScrollBarVisibility="Visible" x:Name="tbDebugConsole" HorizontalAlignment="Left" Height="159" Margin="215,389,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="721"/>
<Button x:Name="btnBreak" Content="Break" HorizontalAlignment="Left" Margin="135,244,0,0" VerticalAlignment="Top" Width="75" Click="btnBreak_Click"/>
<TextBox x:Name="tbDebugEntry" HorizontalAlignment="Left" Height="23" Margin="215,637,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="721" KeyDown="tbDebugEntry_KeyDown"/>
</Grid> </Grid>
</DockPanel>
</Window> </Window>

View File

@ -29,6 +29,9 @@ namespace _6502EmulatorFrontend
Thread M6502WorkerThread; Thread M6502WorkerThread;
MainWindowViewModel vm = new MainWindowViewModel(); MainWindowViewModel vm = new MainWindowViewModel();
byte[] videoRom = File.ReadAllBytes("C:/apple/apple1.vid"); byte[] videoRom = File.ReadAllBytes("C:/apple/apple1.vid");
string monitorRomPath;
string basicRomPath;
SettingsWindow settingsWindow;
public MainWindow() public MainWindow()
{ {
@ -55,21 +58,24 @@ namespace _6502EmulatorFrontend
vm.Processor.ExecutionStopped += new M6502.ExecutionStoppedEventHandler(onExecutionStopped); vm.Processor.ExecutionStopped += new M6502.ExecutionStoppedEventHandler(onExecutionStopped);
TextCompositionManager.AddTextInputHandler(this, new TextCompositionEventHandler(OnTextComposition)); TextCompositionManager.AddTextInputHandler(this, new TextCompositionEventHandler(OnTextComposition));
//Set up settings window
settingsWindow = new SettingsWindow();
settingsWindow.RomPathsSaved += new SettingsWindow.RomPathsSavedEventHandler(OnRomPathsSaved);
settingsWindow.swvm.BasicRomPath = @"C:\apple\apple1basic.bin";
settingsWindow.swvm.MonitorRomPath = @"C:\apple\apple1.rom";
basicRomPath = @"C:\apple\apple1basic.bin";
monitorRomPath = @"C:\apple\apple1.rom";
//Set up window //Set up window
InitializeComponent(); InitializeComponent();
binaryLoadedStatus.SetBinding(ContentProperty, new Binding("LoadSuccess")); binaryLoadedStatus.SetBinding(ContentProperty, new Binding("LoadSuccess"));
DataContext = vm; DataContext = vm;
} }
private void OnTextComposition(object sender, TextCompositionEventArgs e)
{
Interop.putKeyInBuffer((byte)e.Text.ToUpper().ToCharArray()[0]);
}
private void btnLoadBinary_Click(object sender, RoutedEventArgs e) private void btnLoadBinary_Click(object sender, RoutedEventArgs e)
{ {
Interop.loadBinary("C:/apple/apple1.rom", 0xFF00); Interop.loadBinary(monitorRomPath, 0xFF00);
Interop.loadBinary("C:/apple/apple1basic.bin", 0xE000); Interop.loadBinary(basicRomPath, 0xE000);
decodeGraphics(); decodeGraphics();
Interop.resetProcessor(); Interop.resetProcessor();
@ -94,16 +100,6 @@ namespace _6502EmulatorFrontend
} }
private void AfterProcessorStepCompleted(M6502 sender, EventArgs e)
{
UpdateDisassemblySelection(sender.ProgramCounter);
}
private void btnSingleStep_Click(object sender, RoutedEventArgs e)
{
vm.Processor.DoProcessorStep(null, null);
}
private void decodeGraphics() private void decodeGraphics()
{ {
for(int i=0; i < (videoRom.Length / 8); i++) for(int i=0; i < (videoRom.Length / 8); i++)
@ -134,35 +130,7 @@ namespace _6502EmulatorFrontend
BindingOperations.SetBinding(lbDisassembly, ListBox.ItemsSourceProperty, new Binding("DisassembledOpcodes")); BindingOperations.SetBinding(lbDisassembly, ListBox.ItemsSourceProperty, new Binding("DisassembledOpcodes"));
} }
private void onExecutionStopped(object sender, EventArgs e)
{
Dispatcher.Invoke(new Action(() => { vm.DisassembledOpcodes.Clear(); }));
ushort length = 0xFFFE;
IntPtr memoryValuesPtr = Interop.getMemoryRange(0x0000, length);
byte[] result = new byte[length + 1];
Marshal.Copy(memoryValuesPtr, result, 0, length);
Disassembly disassembly = new Disassembly(result);
disassembly.Begin((ushort)(vm.Processor.ProgramCounter - 0x100));
while (disassembly.NextInstructionAddress < (ushort)vm.Processor.ProgramCounter + 0x100)
{
Dispatcher.Invoke(new Action(() =>
{
vm.DisassembledOpcodes.Add(disassembly.ToDisassembledOpcode());
}));
disassembly.Next();
}
Dispatcher.Invoke(new Action(() =>
{
UpdateDisassemblySelection(vm.Processor.ProgramCounter);
}));
lbDisassembly.Dispatcher.Invoke(new Action(() => { enableReadoutControls(); }));
lbDisassembly.Dispatcher.Invoke(new Action(() => { tbDebugConsole.Text += "Breakpoint hit.\r\n"; }));
}
private void UpdateDisassemblySelection(ushort address) private void UpdateDisassemblySelection(ushort address)
{ {
@ -224,5 +192,10 @@ namespace _6502EmulatorFrontend
tbDebugEntry.Clear(); tbDebugEntry.Clear();
} }
} }
private void MenuItem_Click(object sender, RoutedEventArgs e)
{
settingsWindow.ShowDialog();
}
} }
} }

View File

@ -0,0 +1,79 @@
using _6502EmulatorFrontend.cpu;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Input;
namespace _6502EmulatorFrontend
{
partial class MainWindow
{
public class RomPathEventArgs : EventArgs
{
public readonly string MonitorPath;
public readonly string BasicPath;
public RomPathEventArgs(string monitorPath, string basicPath)
{
MonitorPath = monitorPath;
BasicPath = basicPath;
}
}
private void OnRomPathsSaved(object sender, RomPathEventArgs e)
{
monitorRomPath = e.MonitorPath;
basicRomPath = e.BasicPath;
}
private void OnTextComposition(object sender, TextCompositionEventArgs e)
{
Interop.putKeyInBuffer((byte)e.Text.ToUpper().ToCharArray()[0]);
}
private void AfterProcessorStepCompleted(M6502 sender, EventArgs e)
{
UpdateDisassemblySelection(sender.ProgramCounter);
}
private void btnSingleStep_Click(object sender, RoutedEventArgs e)
{
vm.Processor.DoProcessorStep(null, null);
}
//
private void onExecutionStopped(object sender, EventArgs e)
{
Dispatcher.Invoke(new Action(() => { vm.DisassembledOpcodes.Clear(); }));
ushort length = 0xFFFE;
IntPtr memoryValuesPtr = Interop.getMemoryRange(0x0000, length);
byte[] result = new byte[length + 1];
Marshal.Copy(memoryValuesPtr, result, 0, length);
Disassembly disassembly = new Disassembly(result);
disassembly.Begin((ushort)(vm.Processor.ProgramCounter - 0x100));
while (disassembly.NextInstructionAddress < (ushort)vm.Processor.ProgramCounter + 0x100)
{
Dispatcher.Invoke(new Action(() =>
{
vm.DisassembledOpcodes.Add(disassembly.ToDisassembledOpcode());
}));
disassembly.Next();
}
Dispatcher.Invoke(new Action(() =>
{
UpdateDisassemblySelection(vm.Processor.ProgramCounter);
}));
lbDisassembly.Dispatcher.Invoke(new Action(() => { enableReadoutControls(); }));
lbDisassembly.Dispatcher.Invoke(new Action(() => { tbDebugConsole.Text += "Breakpoint hit.\r\n"; }));
}
}
}

View File

@ -0,0 +1,28 @@
<Window x:Class="_6502EmulatorFrontend.SettingsWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:_6502EmulatorFrontend"
mc:Ignorable="d"
Title="SettingsWindow" Height="300" Width="525.627">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="22*"/>
<RowDefinition Height="93*"/>
<RowDefinition Height="20*"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="150"/>
<ColumnDefinition Width="65*"/>
<ColumnDefinition Width="27*"/>
</Grid.ColumnDefinitions>
<Label Grid.Column="0" x:Name="label" Content="Monitor ROM ($FF00)" HorizontalAlignment="Left" Margin="10,8,0,0" VerticalAlignment="Top" Width="130" Height="26"/>
<Label Grid.Column="0" x:Name="label1" Content="Basic ROM ($E000)" HorizontalAlignment="Left" Margin="10,10,0,0" VerticalAlignment="Top" Width="130" Grid.Row="1" Height="26"/>
<TextBox Grid.Column="1" Grid.Row="0" x:Name="tbMonitorRomPath" HorizontalAlignment="Left" Height="23" Margin="10,12,0,0" TextWrapping="Wrap" Text="{Binding Path=MonitorRomPath}" VerticalAlignment="Top" Width="240"/>
<Button x:Name="btnMonitorRom" Content="Browse" Grid.Column="2" HorizontalAlignment="Left" Margin="10,12,0,0" VerticalAlignment="Top" Width="88" Height="22"/>
<TextBox Grid.Column="1" Grid.Row="1" x:Name="tbBasicRomPath" HorizontalAlignment="Left" Height="23" Margin="10,12,0,0" TextWrapping="Wrap" Text="{Binding Path=BasicRomPath}" VerticalAlignment="Top" Width="240"/>
<Button x:Name="btnBasicRom" Content="Browse" Grid.Column="2" HorizontalAlignment="Left" Margin="10,12,0,0" VerticalAlignment="Top" Width="88" Height="22" Grid.Row="1"/>
<Button x:Name="btnSave" Content="Save" Grid.Column="2" HorizontalAlignment="Left" Margin="10,8,0,0" Grid.Row="2" VerticalAlignment="Top" Width="88" Click="btnSave_Click"/>
</Grid>
</Window>

View File

@ -0,0 +1,39 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
namespace _6502EmulatorFrontend
{
/// <summary>
/// Interaction logic for SettingsWindow.xaml
/// </summary>
public partial class SettingsWindow : Window
{
public event RomPathsSavedEventHandler RomPathsSaved;
public delegate void RomPathsSavedEventHandler(object sender, MainWindow.RomPathEventArgs e);
public SettingsWindowViewModel swvm;
public SettingsWindow()
{
swvm = new SettingsWindowViewModel();
InitializeComponent();
DataContext = swvm;
}
private void btnSave_Click(object sender, RoutedEventArgs e)
{
}
}
}

View File

@ -0,0 +1,53 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace _6502EmulatorFrontend
{
public class SettingsWindowViewModel
{
private string _monitorRomPath;
private string _basicRomPath;
public string MonitorRomPath
{
get { return _monitorRomPath; }
set
{
if (value != _monitorRomPath)
{
_monitorRomPath = value;
OnPropertyChanged("MonitorRomPath");
}
}
}
public string BasicRomPath
{
get { return _basicRomPath; }
set
{
if (value != _basicRomPath)
{
_basicRomPath = value;
OnPropertyChanged("BasicRomPath");
}
}
}
#region INotifyPropertyChanged Implementation
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));
}
}
#endregion
}
}

View File

@ -11,6 +11,8 @@
*/ */
//The master processor of instructions. //The master processor of instructions.
bool CPU::lastInstructionCrossedPageBoundary = false;
void CPU::process_instruction() { void CPU::process_instruction() {
last_executed_opcode = ""; last_executed_opcode = "";
last_operand = 0x00; last_operand = 0x00;
@ -198,7 +200,7 @@ void CPU::execute_opcode(uint8_t opcode)
{ {
cycles += 5; cycles += 5;
last_executed_opcode = "ORA (M),Y $"; last_executed_opcode = "ORA (M),Y $";
op_ora(fetch_operand_address(ADDRESSING_INDIRECT_Y)); op_ora(fetch_operand_address(ADDRESSING_INDIRECT_Y), true);
break; break;
} }
@ -230,7 +232,7 @@ void CPU::execute_opcode(uint8_t opcode)
{ {
cycles += 4; cycles += 4;
last_executed_opcode = "ORA M,Y $"; last_executed_opcode = "ORA M,Y $";
op_ora(fetch_operand_address(ADDRESSING_ABSOLUTE_Y)); op_ora(fetch_operand_address(ADDRESSING_ABSOLUTE_Y), true);
break; break;
} }
@ -238,7 +240,7 @@ void CPU::execute_opcode(uint8_t opcode)
{ {
cycles += 4; cycles += 4;
last_executed_opcode = "ORA M,X $"; last_executed_opcode = "ORA M,X $";
op_ora(fetch_operand_address(ADDRESSING_ABSOLUTE_X)); op_ora(fetch_operand_address(ADDRESSING_ABSOLUTE_X), true);
break; break;
} }
@ -350,7 +352,7 @@ void CPU::execute_opcode(uint8_t opcode)
{ {
cycles += 5; cycles += 5;
last_executed_opcode = "AND (M),Y $"; last_executed_opcode = "AND (M),Y $";
op_and(fetch_operand_address(ADDRESSING_INDIRECT_Y)); op_and(fetch_operand_address(ADDRESSING_INDIRECT_Y), true);
break; break;
} }
@ -382,7 +384,7 @@ void CPU::execute_opcode(uint8_t opcode)
{ {
cycles += 4; cycles += 4;
last_executed_opcode = "AND M,Y $"; last_executed_opcode = "AND M,Y $";
op_and(fetch_operand_address(ADDRESSING_ABSOLUTE_Y)); op_and(fetch_operand_address(ADDRESSING_ABSOLUTE_Y), true);
break; break;
} }
@ -390,7 +392,7 @@ void CPU::execute_opcode(uint8_t opcode)
{ {
cycles += 4; cycles += 4;
last_executed_opcode = "AND M,X $"; last_executed_opcode = "AND M,X $";
op_and(fetch_operand_address(ADDRESSING_ABSOLUTE_X)); op_and(fetch_operand_address(ADDRESSING_ABSOLUTE_X), true);
break; break;
} }
@ -494,7 +496,7 @@ void CPU::execute_opcode(uint8_t opcode)
{ {
cycles += 5; cycles += 5;
last_executed_opcode = "EOR (ZP),Y $"; last_executed_opcode = "EOR (ZP),Y $";
op_eor(fetch_operand_address(ADDRESSING_INDIRECT_Y)); op_eor(fetch_operand_address(ADDRESSING_INDIRECT_Y), true);
break; break;
} }
@ -526,7 +528,7 @@ void CPU::execute_opcode(uint8_t opcode)
{ {
cycles += 4; cycles += 4;
last_executed_opcode = "EOR M,Y $"; last_executed_opcode = "EOR M,Y $";
op_eor(fetch_operand_address(ADDRESSING_ABSOLUTE_Y)); op_eor(fetch_operand_address(ADDRESSING_ABSOLUTE_Y), true);
break; break;
} }
@ -534,7 +536,7 @@ void CPU::execute_opcode(uint8_t opcode)
{ {
cycles += 4; cycles += 4;
last_executed_opcode = "EOR M,X $"; last_executed_opcode = "EOR M,X $";
op_eor(fetch_operand_address(ADDRESSING_ABSOLUTE_X)); op_eor(fetch_operand_address(ADDRESSING_ABSOLUTE_X), true);
break; break;
} }
@ -640,7 +642,7 @@ void CPU::execute_opcode(uint8_t opcode)
{ {
cycles += 5; cycles += 5;
last_executed_opcode = "ADC (ZP),Y $"; last_executed_opcode = "ADC (ZP),Y $";
op_adc(fetch_operand_address(ADDRESSING_INDIRECT_Y)); op_adc(fetch_operand_address(ADDRESSING_INDIRECT_Y), true);
break; break;
} }
@ -680,7 +682,7 @@ void CPU::execute_opcode(uint8_t opcode)
{ {
cycles += 4; cycles += 4;
last_executed_opcode = "ADC M,Y $"; last_executed_opcode = "ADC M,Y $";
op_adc(fetch_operand_address(ADDRESSING_ABSOLUTE_Y)); op_adc(fetch_operand_address(ADDRESSING_ABSOLUTE_Y), true);
break; break;
} }
@ -688,7 +690,7 @@ void CPU::execute_opcode(uint8_t opcode)
{ {
cycles += 4; cycles += 4;
last_executed_opcode = "ADC M,X $"; last_executed_opcode = "ADC M,X $";
op_adc(fetch_operand_address(ADDRESSING_ABSOLUTE_X)); op_adc(fetch_operand_address(ADDRESSING_ABSOLUTE_X), true);
break; break;
} }
@ -944,7 +946,7 @@ void CPU::execute_opcode(uint8_t opcode)
{ {
cycles += 5; cycles += 5;
last_executed_opcode = "LDA (ZP),Y $"; last_executed_opcode = "LDA (ZP),Y $";
op_lda(fetch_operand_address(ADDRESSING_INDIRECT_Y)); op_lda(fetch_operand_address(ADDRESSING_INDIRECT_Y), true);
break; break;
} }
@ -984,7 +986,7 @@ void CPU::execute_opcode(uint8_t opcode)
{ {
cycles += 4; cycles += 4;
last_executed_opcode = "LDA M,Y $"; last_executed_opcode = "LDA M,Y $";
op_lda(fetch_operand_address(ADDRESSING_ABSOLUTE_Y)); op_lda(fetch_operand_address(ADDRESSING_ABSOLUTE_Y), true);
break; break;
} }
@ -1000,7 +1002,7 @@ void CPU::execute_opcode(uint8_t opcode)
{ {
cycles += 4; cycles += 4;
last_executed_opcode = "LDY M,X $"; last_executed_opcode = "LDY M,X $";
op_ldy(fetch_operand_address(ADDRESSING_ABSOLUTE_X)); op_ldy(fetch_operand_address(ADDRESSING_ABSOLUTE_X), true);
break; break;
} }
@ -1008,7 +1010,7 @@ void CPU::execute_opcode(uint8_t opcode)
{ {
cycles += 4; cycles += 4;
last_executed_opcode = "LDA M,X $"; last_executed_opcode = "LDA M,X $";
op_lda(fetch_operand_address(ADDRESSING_ABSOLUTE_X)); op_lda(fetch_operand_address(ADDRESSING_ABSOLUTE_X), true);
break; break;
} }
@ -1016,7 +1018,7 @@ void CPU::execute_opcode(uint8_t opcode)
{ {
cycles += 4; cycles += 4;
last_executed_opcode = "LDX M,Y $"; last_executed_opcode = "LDX M,Y $";
op_ldx(fetch_operand_address(ADDRESSING_ABSOLUTE_Y)); op_ldx(fetch_operand_address(ADDRESSING_ABSOLUTE_Y), true);
break; break;
} }
@ -1120,7 +1122,7 @@ void CPU::execute_opcode(uint8_t opcode)
{ {
cycles += 5; cycles += 5;
last_executed_opcode = "CMP (ZP),Y"; last_executed_opcode = "CMP (ZP),Y";
op_cmp(fetch_operand_address(ADDRESSING_INDIRECT_Y)); op_cmp(fetch_operand_address(ADDRESSING_INDIRECT_Y), true);
break; break;
} }
@ -1152,7 +1154,7 @@ void CPU::execute_opcode(uint8_t opcode)
{ {
cycles += 4; cycles += 4;
last_executed_opcode = "CMP M,Y $"; last_executed_opcode = "CMP M,Y $";
op_cmp(fetch_operand_address(ADDRESSING_ABSOLUTE_Y)); op_cmp(fetch_operand_address(ADDRESSING_ABSOLUTE_Y), true);
break; break;
} }
@ -1160,7 +1162,7 @@ void CPU::execute_opcode(uint8_t opcode)
{ {
cycles += 4; cycles += 4;
last_executed_opcode = "CMP M,X $"; last_executed_opcode = "CMP M,X $";
op_cmp(fetch_operand_address(ADDRESSING_ABSOLUTE_X)); op_cmp(fetch_operand_address(ADDRESSING_ABSOLUTE_X), true);
break; break;
} }
@ -1271,7 +1273,7 @@ void CPU::execute_opcode(uint8_t opcode)
{ {
cycles += 5; cycles += 5;
last_executed_opcode = "SBC (ZP),Y $"; last_executed_opcode = "SBC (ZP),Y $";
op_sbc(fetch_operand_address(ADDRESSING_INDIRECT_Y)); op_sbc(fetch_operand_address(ADDRESSING_INDIRECT_Y), true);
break; break;
} }
@ -1303,7 +1305,7 @@ void CPU::execute_opcode(uint8_t opcode)
{ {
cycles += 4; cycles += 4;
last_executed_opcode = "SBC M,Y $"; last_executed_opcode = "SBC M,Y $";
op_sbc(fetch_operand_address(ADDRESSING_ABSOLUTE_Y)); op_sbc(fetch_operand_address(ADDRESSING_ABSOLUTE_Y), true);
break; break;
} }
@ -1311,7 +1313,7 @@ void CPU::execute_opcode(uint8_t opcode)
{ {
cycles += 4; cycles += 4;
last_executed_opcode = "SBC M,X $"; last_executed_opcode = "SBC M,X $";
op_sbc(fetch_operand_address(ADDRESSING_ABSOLUTE_X)); op_sbc(fetch_operand_address(ADDRESSING_ABSOLUTE_X), true);
break; break;
} }

View File

@ -38,10 +38,13 @@ public:
enum ADDRESSING_MODE { ADDRESSING_IMMEDIATE, ADDRESSING_ABSOLUTE, ADDRESSING_ABSOLUTE_X, ADDRESSING_ABSOLUTE_Y, ADDRESSING_ZEROPAGE, ADDRESSING_ZEROPAGE_X, ADDRESSING_ZEROPAGE_Y, ADDRESSING_INDIRECT, ADDRESSING_INDIRECT_X, ADDRESSING_INDIRECT_Y }; enum ADDRESSING_MODE { ADDRESSING_IMMEDIATE, ADDRESSING_ABSOLUTE, ADDRESSING_ABSOLUTE_X, ADDRESSING_ABSOLUTE_Y, ADDRESSING_ZEROPAGE, ADDRESSING_ZEROPAGE_X, ADDRESSING_ZEROPAGE_Y, ADDRESSING_INDIRECT, ADDRESSING_INDIRECT_X, ADDRESSING_INDIRECT_Y };
enum INDEX_MODE { INDEX_NONE = 0x01, INDEX_X = 0x02, INDEX_Y = 0x03 }; enum INDEX_MODE { INDEX_NONE = 0x01, INDEX_X = 0x02, INDEX_Y = 0x03 };
static bool lastInstructionCrossedPageBoundary;
bool frameInstructionsComplete(); bool frameInstructionsComplete();
void resetCycleCounter(); void resetCycleCounter();
void reset_processor() { void reset_processor() {
lastInstructionCrossedPageBoundary = false;
FLAG_SIGN = false; FLAG_SIGN = false;
FLAG_OVERFLOW = false; FLAG_OVERFLOW = false;
FLAG_BREAKPOINT = false; FLAG_BREAKPOINT = false;
@ -117,13 +120,13 @@ public:
void print_status(uint8_t opcode); void print_status(uint8_t opcode);
/* Opcodes */ /* Opcodes */
void CPU::op_adc(WideAddress address); void CPU::op_adc(WideAddress address, bool crossedPageBoundary = false);
void CPU::op_adc(uint8_t immediate); void CPU::op_adc(uint8_t immediate, bool crossedPageBoundary = false);
void CPU::op_and(WideAddress address); void CPU::op_and(WideAddress address, bool crossedPageBoundary = false);
void CPU::op_and(uint8_t immediate); void CPU::op_and(uint8_t immediate, bool crossedPageBoundary = false);
void CPU::op_asl(WideAddress address); void CPU::op_asl(WideAddress address);
@ -157,9 +160,9 @@ public:
void CPU::op_clv(); void CPU::op_clv();
void CPU::op_cmp(uint8_t immediate); void CPU::op_cmp(uint8_t immediate, bool crossedPageBoundary = false);
void CPU::op_cmp(WideAddress address); void CPU::op_cmp(WideAddress address, bool crossedPageBoundary = false);
void CPU::op_cpx(uint8_t immediate); void CPU::op_cpx(uint8_t immediate);
@ -175,9 +178,9 @@ public:
void CPU::op_dey(); void CPU::op_dey();
void CPU::op_eor(uint8_t immediate); void CPU::op_eor(uint8_t immediate, bool crossedPageBoundary = false);
void CPU::op_eor(WideAddress address); void CPU::op_eor(WideAddress address, bool crossedPageBoundary = false);
void CPU::op_inc(WideAddress address); void CPU::op_inc(WideAddress address);
@ -189,17 +192,17 @@ public:
void CPU::op_jsr(WideAddress address); void CPU::op_jsr(WideAddress address);
void CPU::op_lda(uint8_t immediate); void CPU::op_lda(uint8_t immediate, bool crossedPageBoundary = false);
void CPU::op_lda(WideAddress address); void CPU::op_lda(WideAddress address, bool crossedPageBoundary = false);
void CPU::op_ldx(uint8_t immediate); void CPU::op_ldx(uint8_t immediate, bool crossedPageBoundary = false);
void CPU::op_ldx(WideAddress address); void CPU::op_ldx(WideAddress address, bool crossedPageBoundary = false);
void CPU::op_ldy(uint8_t immediate); void CPU::op_ldy(uint8_t immediate, bool crossedPageBoundary = false);
void CPU::op_ldy(WideAddress address); void CPU::op_ldy(WideAddress address, bool crossedPageBoundary = false);
void CPU::op_lsr(); void CPU::op_lsr();
@ -207,9 +210,9 @@ public:
void CPU::op_nop(); void CPU::op_nop();
void CPU::op_ora(uint8_t immediate); void CPU::op_ora(uint8_t immediate, bool crossedPageBoundary = false);
void CPU::op_ora(WideAddress address); void CPU::op_ora(WideAddress address, bool crossedPageBoundary = false);
void CPU::op_pha(); void CPU::op_pha();
@ -231,9 +234,9 @@ public:
void CPU::op_rts(); void CPU::op_rts();
void CPU::op_sbc(uint8_t immediate); void CPU::op_sbc(uint8_t immediate, bool crossedPageBoundary = false);
void CPU::op_sbc(WideAddress address); void CPU::op_sbc(WideAddress address, bool crossedPageBoundary = false);
void CPU::op_sec(); void CPU::op_sec();

View File

@ -4,6 +4,7 @@
#include <iostream> #include <iostream>
uint8_t CPU::fetch_operand(ADDRESSING_MODE mode) { uint8_t CPU::fetch_operand(ADDRESSING_MODE mode) {
lastInstructionCrossedPageBoundary = false;
switch (mode) { switch (mode) {
case ADDRESSING_IMMEDIATE: case ADDRESSING_IMMEDIATE:
@ -24,6 +25,7 @@ uint8_t CPU::fetch_operand(ADDRESSING_MODE mode) {
case ADDRESSING_ZEROPAGE_X: case ADDRESSING_ZEROPAGE_X:
{ {
uint8_t address = fetch_operand(ADDRESSING_IMMEDIATE); uint8_t address = fetch_operand(ADDRESSING_IMMEDIATE);
lastInstructionCrossedPageBoundary = (address + index_x < address);
uint8_t operand = fetch_zero_page_byte(address + index_x); uint8_t operand = fetch_zero_page_byte(address + index_x);
last_operand = address; last_operand = address;
return operand; return operand;
@ -32,6 +34,7 @@ uint8_t CPU::fetch_operand(ADDRESSING_MODE mode) {
case ADDRESSING_ZEROPAGE_Y: case ADDRESSING_ZEROPAGE_Y:
{ {
uint8_t address = fetch_operand(ADDRESSING_IMMEDIATE); uint8_t address = fetch_operand(ADDRESSING_IMMEDIATE);
lastInstructionCrossedPageBoundary = (address + index_y < address);
uint8_t operand = fetch_zero_page_byte(address + index_y); uint8_t operand = fetch_zero_page_byte(address + index_y);
last_operand = address; last_operand = address;
return operand; return operand;
@ -52,6 +55,7 @@ uint8_t CPU::fetch_operand(ADDRESSING_MODE mode) {
uint8_t addrLow = fetch_memory_byte(program_counter); uint8_t addrLow = fetch_memory_byte(program_counter);
uint8_t addrHigh = fetch_memory_byte(program_counter); uint8_t addrHigh = fetch_memory_byte(program_counter);
WideAddress address = { addrHigh, addrLow }; WideAddress address = { addrHigh, addrLow };
lastInstructionCrossedPageBoundary = (addrLow + index_x < addrLow);
uint8_t operand = fetch_memory_byte(address.add(index_x, false), false); uint8_t operand = fetch_memory_byte(address.add(index_x, false), false);
last_operand = address; last_operand = address;
return operand; return operand;
@ -62,6 +66,7 @@ uint8_t CPU::fetch_operand(ADDRESSING_MODE mode) {
uint8_t addrLow = fetch_memory_byte(program_counter); uint8_t addrLow = fetch_memory_byte(program_counter);
uint8_t addrHigh = fetch_memory_byte(program_counter); uint8_t addrHigh = fetch_memory_byte(program_counter);
WideAddress address = { addrHigh, addrLow }; WideAddress address = { addrHigh, addrLow };
lastInstructionCrossedPageBoundary = (addrLow + index_y < addrLow);
uint8_t operand = fetch_memory_byte(address.add(index_y, false), false); uint8_t operand = fetch_memory_byte(address.add(index_y, false), false);
last_operand = address; last_operand = address;
return operand; return operand;
@ -79,6 +84,7 @@ uint8_t CPU::fetch_operand(ADDRESSING_MODE mode) {
case ADDRESSING_INDIRECT_Y: case ADDRESSING_INDIRECT_Y:
{ {
WideAddress destination = fetch_dereferenced_zero_page_pointer(INDEX_NONE); WideAddress destination = fetch_dereferenced_zero_page_pointer(INDEX_NONE);
lastInstructionCrossedPageBoundary = ((destination & 0xFF00) + index_y) > (destination & 0xFF00);
destination = destination.add(index_y, false); destination = destination.add(index_y, false);
uint8_t operand = fetch_memory_byte(destination); uint8_t operand = fetch_memory_byte(destination);
last_operand = operand; last_operand = operand;

View File

@ -25,11 +25,16 @@ unsigned char hex2bcd(unsigned char x)
If there is no parameter on the function, it's either implied or accumulator. If there is no parameter on the function, it's either implied or accumulator.
Assume that PC value is correct coming in. Assume that PC value is correct coming in.
The exception is when branching because we don't know if we were successful until now When branching because we don't know if we were successful until now
so we need to add +1 to PC on a successful branch and another +1 if the branch so we need to add +1 to cycles on a successful branch and another +1 if the branch
goes to a different page. */ goes to a different page.
crossedPageBoundary tells us if we need to increase cycle count by 1 if we crossed the page boundary
CPU::lastInstructionCrossedPageBoundary keeps track of if we did or not
if both are true, increase cycle count by 1.
*/
void CPU::op_adc(WideAddress address) { void CPU::op_adc(WideAddress address, bool crossedPageBoundary) {
/* /*
Logic: Logic:
t = A + M + P.C t = A + M + P.C
@ -44,6 +49,10 @@ void CPU::op_adc(WideAddress address) {
A = t & 0xFF A = t & 0xFF
*/ */
if (crossedPageBoundary && lastInstructionCrossedPageBoundary) {
cycles++;
}
if (accumulator == 0x7f) { if (accumulator == 0x7f) {
int x = 0; int x = 0;
} }
@ -64,7 +73,7 @@ void CPU::op_adc(WideAddress address) {
}; };
void CPU::op_adc(uint8_t immediate) { void CPU::op_adc(uint8_t immediate, bool crossedPageBoundary) {
/* /*
Logic: Logic:
t = A + M + P.C t = A + M + P.C
@ -79,6 +88,10 @@ void CPU::op_adc(uint8_t immediate) {
A = t & 0xFF A = t & 0xFF
*/ */
if (crossedPageBoundary && lastInstructionCrossedPageBoundary) {
cycles++;
}
if (accumulator == 0x7f) { if (accumulator == 0x7f) {
int x = 0; int x = 0;
} }
@ -108,23 +121,33 @@ void CPU::op_adc(uint8_t immediate) {
accumulator = (t & 0xFF); accumulator = (t & 0xFF);
}; };
void CPU::op_and(WideAddress address) { void CPU::op_and(WideAddress address, bool crossedPageBoundary) {
/* /*
Logic: Logic:
A = A & M A = A & M
P.N = A.7 P.N = A.7
P.Z = (A==0) ? 1:0 */ P.Z = (A==0) ? 1:0 */
if (crossedPageBoundary && lastInstructionCrossedPageBoundary) {
cycles++;
}
accumulator = (accumulator & fetch_memory_byte(address, false)); accumulator = (accumulator & fetch_memory_byte(address, false));
FLAG_SIGN = (accumulator & 0x80) == 0x80; FLAG_SIGN = (accumulator & 0x80) == 0x80;
FLAG_ZERO = (accumulator == 0); FLAG_ZERO = (accumulator == 0);
} }
void CPU::op_and(uint8_t immediate) { void CPU::op_and(uint8_t immediate, bool crossedPageBoundary) {
/* /*
Logic: Logic:
A = A & M A = A & M
P.N = A.7 P.N = A.7
P.Z = (A==0) ? 1:0 */ P.Z = (A==0) ? 1:0 */
if (crossedPageBoundary && lastInstructionCrossedPageBoundary) {
cycles++;
}
accumulator = (accumulator & immediate); accumulator = (accumulator & immediate);
FLAG_SIGN = (accumulator & 0x80) == 0x80; FLAG_SIGN = (accumulator & 0x80) == 0x80;
FLAG_ZERO = (accumulator == 0); FLAG_ZERO = (accumulator == 0);
@ -162,9 +185,9 @@ void CPU::op_bcc(int8_t relative) {
if (!FLAG_CARRY) { if (!FLAG_CARRY) {
//+1 cycle for branching, +2 if branching to a different page //+1 cycle for branching, +2 if branching to a different page
if ((program_counter & 0x00FF) + relative > 0x100) { if ((program_counter & 0x00FF) + relative > 0x100) {
EmulatorState::Instance()->processor.cycles++; cycles++;
} }
EmulatorState::Instance()->processor.cycles++; cycles++;
program_counter += relative; program_counter += relative;
} }
} }
@ -173,9 +196,9 @@ void CPU::op_bcs(int8_t relative) {
if (FLAG_CARRY) { if (FLAG_CARRY) {
//+1 cycle for branching, +2 if branching to a different page //+1 cycle for branching, +2 if branching to a different page
if ((program_counter & 0x00FF) + relative > 0x100) { if ((program_counter & 0x00FF) + relative > 0x100) {
EmulatorState::Instance()->processor.cycles++; cycles++;
} }
EmulatorState::Instance()->processor.cycles++; cycles++;
program_counter += relative; program_counter += relative;
} }
} }
@ -184,9 +207,9 @@ void CPU::op_beq(int8_t relative) {
if (FLAG_ZERO) { if (FLAG_ZERO) {
//+1 cycle for branching, +2 if branching to a different page //+1 cycle for branching, +2 if branching to a different page
if ((program_counter & 0x00FF) + relative > 0x100) { if ((program_counter & 0x00FF) + relative > 0x100) {
EmulatorState::Instance()->processor.cycles++; cycles++;
} }
EmulatorState::Instance()->processor.cycles++; cycles++;
program_counter += relative; program_counter += relative;
} }
} }
@ -210,16 +233,16 @@ void CPU::op_bmi(int8_t relative) {
if (PN) { if (PN) {
//+1 cycle for branching, +2 if branching to a different page //+1 cycle for branching, +2 if branching to a different page
if ((program_counter & 0x00FF) + relative > 0x100) { if ((program_counter & 0x00FF) + relative > 0x100) {
EmulatorState::Instance()->processor.cycles++; cycles++;
} }
EmulatorState::Instance()->processor.cycles++; cycles++;
program_counter += relative; program_counter += relative;
} }
} }
void CPU::op_bne(int8_t relative) { void CPU::op_bne(int8_t relative) {
if (!PZ) { if (!PZ) {
EmulatorState::Instance()->processor.cycles++; cycles++;
program_counter += relative; program_counter += relative;
if (relative == (int8_t)0xFE) { if (relative == (int8_t)0xFE) {
std::exit(4); std::exit(4);
@ -231,9 +254,9 @@ void CPU::op_bpl(int8_t relative) {
if (!PN) { if (!PN) {
//+1 cycle for branching, +2 if branching to a different page //+1 cycle for branching, +2 if branching to a different page
if ((program_counter & 0x00FF) + relative > 0x100) { if ((program_counter & 0x00FF) + relative > 0x100) {
EmulatorState::Instance()->processor.cycles++; cycles++;
} }
EmulatorState::Instance()->processor.cycles++; cycles++;
program_counter += relative; program_counter += relative;
} }
} }
@ -253,9 +276,9 @@ void CPU::op_bvc(int8_t relative) {
if (!PV) { if (!PV) {
//+1 cycle for branching, +2 if branching to a different page //+1 cycle for branching, +2 if branching to a different page
if ((program_counter & 0x00FF) + relative > 0x100) { if ((program_counter & 0x00FF) + relative > 0x100) {
EmulatorState::Instance()->processor.cycles++; cycles++;
} }
EmulatorState::Instance()->processor.cycles++; cycles++;
program_counter += relative; program_counter += relative;
} }
} }
@ -264,9 +287,9 @@ void CPU::op_bvs(int8_t relative) {
if (PV) { if (PV) {
//+1 cycle for branching, +2 if branching to a different page //+1 cycle for branching, +2 if branching to a different page
if ((program_counter & 0x00FF) + relative > 0x100) { if ((program_counter & 0x00FF) + relative > 0x100) {
EmulatorState::Instance()->processor.cycles++; cycles++;
} }
EmulatorState::Instance()->processor.cycles++; cycles++;
program_counter += relative; program_counter += relative;
} }
} }
@ -287,7 +310,7 @@ void CPU::op_clv() {
PV = false; PV = false;
} }
void CPU::op_cmp(uint8_t immediate) { //immediate void CPU::op_cmp(uint8_t immediate, bool crossedPageBoundary) { //immediate
/* /*
Logic: Logic:
t = A - M t = A - M
@ -296,6 +319,10 @@ void CPU::op_cmp(uint8_t immediate) { //immediate
P.Z = (t==0) ? 1:0 P.Z = (t==0) ? 1:0
*/ */
if (crossedPageBoundary && lastInstructionCrossedPageBoundary) {
cycles++;
}
uint8_t t = accumulator - immediate; uint8_t t = accumulator - immediate;
PN = (t & 0x80) == 0x80; PN = (t & 0x80) == 0x80;
PC = (accumulator >= immediate); PC = (accumulator >= immediate);
@ -303,7 +330,7 @@ void CPU::op_cmp(uint8_t immediate) { //immediate
} }
void CPU::op_cmp(WideAddress address) { void CPU::op_cmp(WideAddress address, bool crossedPageBoundary) {
/* /*
Logic: Logic:
t = A - M t = A - M
@ -312,6 +339,10 @@ void CPU::op_cmp(WideAddress address) {
P.Z = (t==0) ? 1:0 P.Z = (t==0) ? 1:0
*/ */
if (crossedPageBoundary && lastInstructionCrossedPageBoundary) {
cycles++;
}
uint8_t t = accumulator - fetch_memory_byte(address, false); uint8_t t = accumulator - fetch_memory_byte(address, false);
PN = (t & 0x80) == 0x80; PN = (t & 0x80) == 0x80;
PC = (accumulator >= fetch_memory_byte(address, false)); PC = (accumulator >= fetch_memory_byte(address, false));
@ -372,13 +403,23 @@ void CPU::op_dey() {
PN = (index_y & 0x80) == 0x80; PN = (index_y & 0x80) == 0x80;
} }
void CPU::op_eor(uint8_t immediate) { void CPU::op_eor(uint8_t immediate, bool crossedPageBoundary) {
if (crossedPageBoundary && lastInstructionCrossedPageBoundary) {
cycles++;
}
accumulator = accumulator ^ immediate; accumulator = accumulator ^ immediate;
PN = (accumulator & 0x80) == 0x80; PN = (accumulator & 0x80) == 0x80;
PZ = (accumulator == 0); PZ = (accumulator == 0);
} }
void CPU::op_eor(WideAddress address) { void CPU::op_eor(WideAddress address, bool crossedPageBoundary) {
if (crossedPageBoundary && lastInstructionCrossedPageBoundary) {
cycles++;
}
accumulator = accumulator ^ fetch_memory_byte(address, false); accumulator = accumulator ^ fetch_memory_byte(address, false);
PN = (accumulator & 0x80) == 0x80; PN = (accumulator & 0x80) == 0x80;
PZ = (accumulator == 0); PZ = (accumulator == 0);
@ -430,37 +471,67 @@ void CPU::op_jsr(WideAddress address) {
program_counter = address; program_counter = address;
} }
void CPU::op_lda(uint8_t immediate) { void CPU::op_lda(uint8_t immediate, bool crossedPageBoundary) {
if (crossedPageBoundary && lastInstructionCrossedPageBoundary) {
cycles++;
}
accumulator = immediate; accumulator = immediate;
PN = (accumulator & 0x80) == 0x80; PN = (accumulator & 0x80) == 0x80;
PZ = (accumulator == 0); PZ = (accumulator == 0);
} }
void CPU::op_lda(WideAddress address) { void CPU::op_lda(WideAddress address, bool crossedPageBoundary) {
if (crossedPageBoundary && lastInstructionCrossedPageBoundary) {
cycles++;
}
accumulator = fetch_memory_byte(address, false); accumulator = fetch_memory_byte(address, false);
PN = (accumulator & 0x80) == 0x80; PN = (accumulator & 0x80) == 0x80;
PZ = (accumulator == 0); PZ = (accumulator == 0);
} }
void CPU::op_ldx(uint8_t immediate) { void CPU::op_ldx(uint8_t immediate, bool crossedPageBoundary) {
if (crossedPageBoundary && lastInstructionCrossedPageBoundary) {
cycles++;
}
index_x = immediate; index_x = immediate;
PN = (index_x & 0x80) == 0x80; PN = (index_x & 0x80) == 0x80;
PZ = (index_x == 0); PZ = (index_x == 0);
} }
void CPU::op_ldx(WideAddress address) { void CPU::op_ldx(WideAddress address, bool crossedPageBoundary) {
if (crossedPageBoundary && lastInstructionCrossedPageBoundary) {
cycles++;
}
index_x = fetch_memory_byte(address, false); index_x = fetch_memory_byte(address, false);
PN = (index_x & 0x80) == 0x80; PN = (index_x & 0x80) == 0x80;
PZ = (index_x == 0); PZ = (index_x == 0);
} }
void CPU::op_ldy(uint8_t immediate) { void CPU::op_ldy(uint8_t immediate, bool crossedPageBoundary) {
if (crossedPageBoundary && lastInstructionCrossedPageBoundary) {
cycles++;
}
index_y = immediate; index_y = immediate;
PN = (index_y & 0x80) == 0x80; PN = (index_y & 0x80) == 0x80;
PZ = (index_y == 0); PZ = (index_y == 0);
} }
void CPU::op_ldy(WideAddress address) { void CPU::op_ldy(WideAddress address, bool crossedPageBoundary) {
if (crossedPageBoundary && lastInstructionCrossedPageBoundary) {
cycles++;
}
index_y = fetch_memory_byte(address, false); index_y = fetch_memory_byte(address, false);
PN = (index_y & 0x80) == 0x80; PN = (index_y & 0x80) == 0x80;
PZ = (index_y == 0); PZ = (index_y == 0);
@ -498,13 +569,23 @@ void CPU::op_nop() {
//NOP //NOP
} }
void CPU::op_ora(uint8_t immediate) { void CPU::op_ora(uint8_t immediate, bool crossedPageBoundary) {
if (crossedPageBoundary && lastInstructionCrossedPageBoundary) {
cycles++;
}
accumulator = accumulator | immediate; accumulator = accumulator | immediate;
PN = (accumulator & 0x80) == 0x80; PN = (accumulator & 0x80) == 0x80;
PZ = (accumulator == 0); PZ = (accumulator == 0);
} }
void CPU::op_ora(WideAddress address) { void CPU::op_ora(WideAddress address, bool crossedPageBoundary) {
if (crossedPageBoundary && lastInstructionCrossedPageBoundary) {
cycles++;
}
accumulator = accumulator | fetch_memory_byte(address, false); accumulator = accumulator | fetch_memory_byte(address, false);
PN = (accumulator & 0x80) == 0x80; PN = (accumulator & 0x80) == 0x80;
PZ = (accumulator == 0); PZ = (accumulator == 0);
@ -613,7 +694,7 @@ void CPU::op_rts() {
program_counter = addr.add(1, false); program_counter = addr.add(1, false);
} }
void CPU::op_sbc(uint8_t immediate) { void CPU::op_sbc(uint8_t immediate, bool crossedPageBoundary) {
/* /*
Logic: Logic:
IF (P.D) IF (P.D)
@ -629,7 +710,7 @@ void CPU::op_sbc(uint8_t immediate) {
*/ */
//TODO: decimal //TODO: decimal
op_adc(~immediate); op_adc(~immediate, crossedPageBoundary);
/* /*
int8_t t; int8_t t;
@ -649,8 +730,8 @@ void CPU::op_sbc(uint8_t immediate) {
*/ */
} }
void CPU::op_sbc(WideAddress address) { void CPU::op_sbc(WideAddress address, bool crossedPageBoundary) {
op_adc(~fetch_memory_byte(address, false)); op_adc(~fetch_memory_byte(address, false), crossedPageBoundary);
/* /*
int8_t t; int8_t t;