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
# Visual Studio 14
VisualStudioVersion = 14.0.24627.0
VisualStudioVersion = 14.0.24720.0
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "6502EmulatorFrontend", "6502EmulatorFrontend\6502EmulatorFrontend.csproj", "{C198497A-3D3E-4F01-A72B-642DAB6B11D6}"
EndProject
@ -24,13 +24,4 @@ Global
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

View File

@ -18,6 +18,21 @@
<SccLocalPath>SAK</SccLocalPath>
<SccAuxPath>SAK</SccAuxPath>
<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 Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
@ -65,7 +80,12 @@
<Compile Include="Apple2Display.cs" />
<Compile Include="cpu\Disassembly.cs" />
<Compile Include="IDisplay.cs" />
<Compile Include="MainWindowEvents.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\CharacterSet.cs" />
<Page Include="MainWindow.xaml">
@ -84,6 +104,10 @@
<DependentUpon>MainWindow.xaml</DependentUpon>
<SubType>Code</SubType>
</Compile>
<Page Include="SettingsWindow.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
</ItemGroup>
<ItemGroup>
<Compile Include="Properties\AssemblyInfo.cs">
@ -115,6 +139,18 @@
<ItemGroup>
<Folder Include="memory\" />
</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" />
<!-- 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.

View File

@ -42,35 +42,35 @@ namespace _6502EmulatorFrontend
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);
[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();
[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();
[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();
//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();
[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();
[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();
[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);
[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();
[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);
}
}

View File

@ -5,55 +5,64 @@
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:_6502EmulatorFrontend"
mc:Ignorable="d"
Title="Fruit Machine 0.0000001a" Height="600" Width="954">
<Grid>
<Button x:Name="btnLoadBinary" Content="Load Binary" HorizontalAlignment="Left" Margin="10,10,0,0" VerticalAlignment="Top" Width="75" Click="btnLoadBinary_Click"/>
<Label x:Name="binaryLoadedStatus" Content="Label" HorizontalAlignment="Left" Margin="90,8,0,0" VerticalAlignment="Top" Width="417"/>
<Grid HorizontalAlignment="Left" Height="185" Margin="10,39,0,0" VerticalAlignment="Top" Width="200" Background="#FFACACAC">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="3*"/>
<ColumnDefinition Width="5*"/>
</Grid.ColumnDefinitions>
<StackPanel Orientation="Vertical" Grid.ColumnSpan="1">
<Separator Style="{StaticResource {x:Static ToolBar.SeparatorStyleKey}}" />
<Label Content="PC" Height="25"></Label>
<Separator Style="{StaticResource {x:Static ToolBar.SeparatorStyleKey}}" />
<Label Content="A" Height="25"></Label>
<Separator Style="{StaticResource {x:Static ToolBar.SeparatorStyleKey}}" />
<Label Content="X" Height="25"></Label>
<Separator Style="{StaticResource {x:Static ToolBar.SeparatorStyleKey}}" />
<Label Content="Y" Height="25"></Label>
<Separator Style="{StaticResource {x:Static ToolBar.SeparatorStyleKey}}" />
<Label Content="SP" Height="25"></Label>
<Separator Style="{StaticResource {x:Static ToolBar.SeparatorStyleKey}}" />
<Label Content="Flags" Height="25"></Label>
</StackPanel>
<StackPanel Orientation="Vertical" Grid.ColumnSpan="1" Grid.Column="1">
<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>
<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>
<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>
<Separator Style="{StaticResource {x:Static ToolBar.SeparatorStyleKey}}" />
<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>
<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>
<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>
</StackPanel>
</Grid>
<Button x:Name="btnSingleStep" Content="Single Step" HorizontalAlignment="Left" Margin="10,229,0,0" VerticalAlignment="Top" Width="75" Click="btnSingleStep_Click" IsEnabled="False"/>
<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"/>
<Button x:Name="btnRun" Content="Run" HorizontalAlignment="Left" Margin="135,229,0,0" VerticalAlignment="Top" Width="75" Click="btnRun_Click" IsEnabled="False"/>
<ListBox x:Name="lbDisassembly" ItemsSource="{Binding DisassembledOpcodes}" HorizontalAlignment="Left" Height="277" Margin="10,283,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="104" Margin="215,428,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="721"/>
<Button x:Name="btnBreak" Content="Break" HorizontalAlignment="Left" Margin="135,256,0,0" VerticalAlignment="Top" Width="75" Click="btnBreak_Click"/>
<TextBox x:Name="tbDebugEntry" HorizontalAlignment="Left" Height="23" Margin="215,537,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="721" KeyDown="tbDebugEntry_KeyDown"/>
Title="Fruit Machine 0.0000001a" Height="700" Width="954">
<DockPanel>
<Menu DockPanel.Dock="Top">
<MenuItem Header="_File"/>
<MenuItem Header="_Settings">
<MenuItem Header="_ROM Paths" Click="MenuItem_Click"/>
</MenuItem>
</Menu>
<Grid>
<Button x:Name="btnLoadBinary" Content="Load Binary" HorizontalAlignment="Left" Margin="10,0,0,0" VerticalAlignment="Top" Width="75" Click="btnLoadBinary_Click"/>
<Label x:Name="binaryLoadedStatus" Content="Label" HorizontalAlignment="Left" Margin="90,108,0,0" VerticalAlignment="Top" Width="417"/>
<Grid HorizontalAlignment="Left" Height="185" Margin="10,27,0,0" VerticalAlignment="Top" Width="200" Background="#FFACACAC">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="3*"/>
<ColumnDefinition Width="5*"/>
</Grid.ColumnDefinitions>
<StackPanel Orientation="Vertical" Grid.ColumnSpan="1">
<Separator Style="{StaticResource {x:Static ToolBar.SeparatorStyleKey}}" />
<Label Content="PC" Height="25"></Label>
<Separator Style="{StaticResource {x:Static ToolBar.SeparatorStyleKey}}" />
<Label Content="A" Height="25"></Label>
<Separator Style="{StaticResource {x:Static ToolBar.SeparatorStyleKey}}" />
<Label Content="X" Height="25"></Label>
<Separator Style="{StaticResource {x:Static ToolBar.SeparatorStyleKey}}" />
<Label Content="Y" Height="25"></Label>
<Separator Style="{StaticResource {x:Static ToolBar.SeparatorStyleKey}}" />
<Label Content="SP" Height="25"></Label>
<Separator Style="{StaticResource {x:Static ToolBar.SeparatorStyleKey}}" />
<Label Content="Flags" Height="25"></Label>
</StackPanel>
<StackPanel Orientation="Vertical" Grid.ColumnSpan="1" Grid.Column="1">
<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>
<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>
<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>
<Separator Style="{StaticResource {x:Static ToolBar.SeparatorStyleKey}}" />
<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>
<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>
<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>
</StackPanel>
</Grid>
<Button x:Name="btnSingleStep" Content="Single Step" HorizontalAlignment="Left" Margin="10,217,0,0" VerticalAlignment="Top" Width="75" Click="btnSingleStep_Click" IsEnabled="False"/>
<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"/>
<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>

View File

@ -29,6 +29,9 @@ namespace _6502EmulatorFrontend
Thread M6502WorkerThread;
MainWindowViewModel vm = new MainWindowViewModel();
byte[] videoRom = File.ReadAllBytes("C:/apple/apple1.vid");
string monitorRomPath;
string basicRomPath;
SettingsWindow settingsWindow;
public MainWindow()
{
@ -55,21 +58,24 @@ namespace _6502EmulatorFrontend
vm.Processor.ExecutionStopped += new M6502.ExecutionStoppedEventHandler(onExecutionStopped);
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
InitializeComponent();
binaryLoadedStatus.SetBinding(ContentProperty, new Binding("LoadSuccess"));
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)
{
Interop.loadBinary("C:/apple/apple1.rom", 0xFF00);
Interop.loadBinary("C:/apple/apple1basic.bin", 0xE000);
Interop.loadBinary(monitorRomPath, 0xFF00);
Interop.loadBinary(basicRomPath, 0xE000);
decodeGraphics();
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()
{
for(int i=0; i < (videoRom.Length / 8); i++)
@ -134,35 +130,7 @@ namespace _6502EmulatorFrontend
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)
{
@ -224,5 +192,10 @@ namespace _6502EmulatorFrontend
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.
bool CPU::lastInstructionCrossedPageBoundary = false;
void CPU::process_instruction() {
last_executed_opcode = "";
last_operand = 0x00;
@ -198,7 +200,7 @@ void CPU::execute_opcode(uint8_t opcode)
{
cycles += 5;
last_executed_opcode = "ORA (M),Y $";
op_ora(fetch_operand_address(ADDRESSING_INDIRECT_Y));
op_ora(fetch_operand_address(ADDRESSING_INDIRECT_Y), true);
break;
}
@ -230,7 +232,7 @@ void CPU::execute_opcode(uint8_t opcode)
{
cycles += 4;
last_executed_opcode = "ORA M,Y $";
op_ora(fetch_operand_address(ADDRESSING_ABSOLUTE_Y));
op_ora(fetch_operand_address(ADDRESSING_ABSOLUTE_Y), true);
break;
}
@ -238,7 +240,7 @@ void CPU::execute_opcode(uint8_t opcode)
{
cycles += 4;
last_executed_opcode = "ORA M,X $";
op_ora(fetch_operand_address(ADDRESSING_ABSOLUTE_X));
op_ora(fetch_operand_address(ADDRESSING_ABSOLUTE_X), true);
break;
}
@ -350,7 +352,7 @@ void CPU::execute_opcode(uint8_t opcode)
{
cycles += 5;
last_executed_opcode = "AND (M),Y $";
op_and(fetch_operand_address(ADDRESSING_INDIRECT_Y));
op_and(fetch_operand_address(ADDRESSING_INDIRECT_Y), true);
break;
}
@ -382,7 +384,7 @@ void CPU::execute_opcode(uint8_t opcode)
{
cycles += 4;
last_executed_opcode = "AND M,Y $";
op_and(fetch_operand_address(ADDRESSING_ABSOLUTE_Y));
op_and(fetch_operand_address(ADDRESSING_ABSOLUTE_Y), true);
break;
}
@ -390,7 +392,7 @@ void CPU::execute_opcode(uint8_t opcode)
{
cycles += 4;
last_executed_opcode = "AND M,X $";
op_and(fetch_operand_address(ADDRESSING_ABSOLUTE_X));
op_and(fetch_operand_address(ADDRESSING_ABSOLUTE_X), true);
break;
}
@ -494,7 +496,7 @@ void CPU::execute_opcode(uint8_t opcode)
{
cycles += 5;
last_executed_opcode = "EOR (ZP),Y $";
op_eor(fetch_operand_address(ADDRESSING_INDIRECT_Y));
op_eor(fetch_operand_address(ADDRESSING_INDIRECT_Y), true);
break;
}
@ -526,7 +528,7 @@ void CPU::execute_opcode(uint8_t opcode)
{
cycles += 4;
last_executed_opcode = "EOR M,Y $";
op_eor(fetch_operand_address(ADDRESSING_ABSOLUTE_Y));
op_eor(fetch_operand_address(ADDRESSING_ABSOLUTE_Y), true);
break;
}
@ -534,7 +536,7 @@ void CPU::execute_opcode(uint8_t opcode)
{
cycles += 4;
last_executed_opcode = "EOR M,X $";
op_eor(fetch_operand_address(ADDRESSING_ABSOLUTE_X));
op_eor(fetch_operand_address(ADDRESSING_ABSOLUTE_X), true);
break;
}
@ -640,7 +642,7 @@ void CPU::execute_opcode(uint8_t opcode)
{
cycles += 5;
last_executed_opcode = "ADC (ZP),Y $";
op_adc(fetch_operand_address(ADDRESSING_INDIRECT_Y));
op_adc(fetch_operand_address(ADDRESSING_INDIRECT_Y), true);
break;
}
@ -680,7 +682,7 @@ void CPU::execute_opcode(uint8_t opcode)
{
cycles += 4;
last_executed_opcode = "ADC M,Y $";
op_adc(fetch_operand_address(ADDRESSING_ABSOLUTE_Y));
op_adc(fetch_operand_address(ADDRESSING_ABSOLUTE_Y), true);
break;
}
@ -688,7 +690,7 @@ void CPU::execute_opcode(uint8_t opcode)
{
cycles += 4;
last_executed_opcode = "ADC M,X $";
op_adc(fetch_operand_address(ADDRESSING_ABSOLUTE_X));
op_adc(fetch_operand_address(ADDRESSING_ABSOLUTE_X), true);
break;
}
@ -944,7 +946,7 @@ void CPU::execute_opcode(uint8_t opcode)
{
cycles += 5;
last_executed_opcode = "LDA (ZP),Y $";
op_lda(fetch_operand_address(ADDRESSING_INDIRECT_Y));
op_lda(fetch_operand_address(ADDRESSING_INDIRECT_Y), true);
break;
}
@ -984,7 +986,7 @@ void CPU::execute_opcode(uint8_t opcode)
{
cycles += 4;
last_executed_opcode = "LDA M,Y $";
op_lda(fetch_operand_address(ADDRESSING_ABSOLUTE_Y));
op_lda(fetch_operand_address(ADDRESSING_ABSOLUTE_Y), true);
break;
}
@ -1000,7 +1002,7 @@ void CPU::execute_opcode(uint8_t opcode)
{
cycles += 4;
last_executed_opcode = "LDY M,X $";
op_ldy(fetch_operand_address(ADDRESSING_ABSOLUTE_X));
op_ldy(fetch_operand_address(ADDRESSING_ABSOLUTE_X), true);
break;
}
@ -1008,7 +1010,7 @@ void CPU::execute_opcode(uint8_t opcode)
{
cycles += 4;
last_executed_opcode = "LDA M,X $";
op_lda(fetch_operand_address(ADDRESSING_ABSOLUTE_X));
op_lda(fetch_operand_address(ADDRESSING_ABSOLUTE_X), true);
break;
}
@ -1016,7 +1018,7 @@ void CPU::execute_opcode(uint8_t opcode)
{
cycles += 4;
last_executed_opcode = "LDX M,Y $";
op_ldx(fetch_operand_address(ADDRESSING_ABSOLUTE_Y));
op_ldx(fetch_operand_address(ADDRESSING_ABSOLUTE_Y), true);
break;
}
@ -1120,7 +1122,7 @@ void CPU::execute_opcode(uint8_t opcode)
{
cycles += 5;
last_executed_opcode = "CMP (ZP),Y";
op_cmp(fetch_operand_address(ADDRESSING_INDIRECT_Y));
op_cmp(fetch_operand_address(ADDRESSING_INDIRECT_Y), true);
break;
}
@ -1152,7 +1154,7 @@ void CPU::execute_opcode(uint8_t opcode)
{
cycles += 4;
last_executed_opcode = "CMP M,Y $";
op_cmp(fetch_operand_address(ADDRESSING_ABSOLUTE_Y));
op_cmp(fetch_operand_address(ADDRESSING_ABSOLUTE_Y), true);
break;
}
@ -1160,7 +1162,7 @@ void CPU::execute_opcode(uint8_t opcode)
{
cycles += 4;
last_executed_opcode = "CMP M,X $";
op_cmp(fetch_operand_address(ADDRESSING_ABSOLUTE_X));
op_cmp(fetch_operand_address(ADDRESSING_ABSOLUTE_X), true);
break;
}
@ -1271,7 +1273,7 @@ void CPU::execute_opcode(uint8_t opcode)
{
cycles += 5;
last_executed_opcode = "SBC (ZP),Y $";
op_sbc(fetch_operand_address(ADDRESSING_INDIRECT_Y));
op_sbc(fetch_operand_address(ADDRESSING_INDIRECT_Y), true);
break;
}
@ -1303,7 +1305,7 @@ void CPU::execute_opcode(uint8_t opcode)
{
cycles += 4;
last_executed_opcode = "SBC M,Y $";
op_sbc(fetch_operand_address(ADDRESSING_ABSOLUTE_Y));
op_sbc(fetch_operand_address(ADDRESSING_ABSOLUTE_Y), true);
break;
}
@ -1311,7 +1313,7 @@ void CPU::execute_opcode(uint8_t opcode)
{
cycles += 4;
last_executed_opcode = "SBC M,X $";
op_sbc(fetch_operand_address(ADDRESSING_ABSOLUTE_X));
op_sbc(fetch_operand_address(ADDRESSING_ABSOLUTE_X), true);
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 INDEX_MODE { INDEX_NONE = 0x01, INDEX_X = 0x02, INDEX_Y = 0x03 };
static bool lastInstructionCrossedPageBoundary;
bool frameInstructionsComplete();
void resetCycleCounter();
void reset_processor() {
lastInstructionCrossedPageBoundary = false;
FLAG_SIGN = false;
FLAG_OVERFLOW = false;
FLAG_BREAKPOINT = false;
@ -117,13 +120,13 @@ public:
void print_status(uint8_t opcode);
/* 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);
@ -157,9 +160,9 @@ public:
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);
@ -175,9 +178,9 @@ public:
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);
@ -189,17 +192,17 @@ public:
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();
@ -207,9 +210,9 @@ public:
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();
@ -231,9 +234,9 @@ public:
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();

View File

@ -4,6 +4,7 @@
#include <iostream>
uint8_t CPU::fetch_operand(ADDRESSING_MODE mode) {
lastInstructionCrossedPageBoundary = false;
switch (mode) {
case ADDRESSING_IMMEDIATE:
@ -24,6 +25,7 @@ uint8_t CPU::fetch_operand(ADDRESSING_MODE mode) {
case ADDRESSING_ZEROPAGE_X:
{
uint8_t address = fetch_operand(ADDRESSING_IMMEDIATE);
lastInstructionCrossedPageBoundary = (address + index_x < address);
uint8_t operand = fetch_zero_page_byte(address + index_x);
last_operand = address;
return operand;
@ -32,6 +34,7 @@ uint8_t CPU::fetch_operand(ADDRESSING_MODE mode) {
case ADDRESSING_ZEROPAGE_Y:
{
uint8_t address = fetch_operand(ADDRESSING_IMMEDIATE);
lastInstructionCrossedPageBoundary = (address + index_y < address);
uint8_t operand = fetch_zero_page_byte(address + index_y);
last_operand = address;
return operand;
@ -52,6 +55,7 @@ uint8_t CPU::fetch_operand(ADDRESSING_MODE mode) {
uint8_t addrLow = fetch_memory_byte(program_counter);
uint8_t addrHigh = fetch_memory_byte(program_counter);
WideAddress address = { addrHigh, addrLow };
lastInstructionCrossedPageBoundary = (addrLow + index_x < addrLow);
uint8_t operand = fetch_memory_byte(address.add(index_x, false), false);
last_operand = address;
return operand;
@ -62,6 +66,7 @@ uint8_t CPU::fetch_operand(ADDRESSING_MODE mode) {
uint8_t addrLow = fetch_memory_byte(program_counter);
uint8_t addrHigh = fetch_memory_byte(program_counter);
WideAddress address = { addrHigh, addrLow };
lastInstructionCrossedPageBoundary = (addrLow + index_y < addrLow);
uint8_t operand = fetch_memory_byte(address.add(index_y, false), false);
last_operand = address;
return operand;
@ -79,6 +84,7 @@ uint8_t CPU::fetch_operand(ADDRESSING_MODE mode) {
case ADDRESSING_INDIRECT_Y:
{
WideAddress destination = fetch_dereferenced_zero_page_pointer(INDEX_NONE);
lastInstructionCrossedPageBoundary = ((destination & 0xFF00) + index_y) > (destination & 0xFF00);
destination = destination.add(index_y, false);
uint8_t operand = fetch_memory_byte(destination);
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.
Assume that PC value is correct coming in.
The exception is 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
goes to a different page. */
When branching because we don't know if we were successful until now
so we need to add +1 to cycles on a successful branch and another +1 if the branch
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:
t = A + M + P.C
@ -44,6 +49,10 @@ void CPU::op_adc(WideAddress address) {
A = t & 0xFF
*/
if (crossedPageBoundary && lastInstructionCrossedPageBoundary) {
cycles++;
}
if (accumulator == 0x7f) {
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:
t = A + M + P.C
@ -79,6 +88,10 @@ void CPU::op_adc(uint8_t immediate) {
A = t & 0xFF
*/
if (crossedPageBoundary && lastInstructionCrossedPageBoundary) {
cycles++;
}
if (accumulator == 0x7f) {
int x = 0;
}
@ -108,23 +121,33 @@ void CPU::op_adc(uint8_t immediate) {
accumulator = (t & 0xFF);
};
void CPU::op_and(WideAddress address) {
void CPU::op_and(WideAddress address, bool crossedPageBoundary) {
/*
Logic:
A = A & M
P.N = A.7
P.Z = (A==0) ? 1:0 */
if (crossedPageBoundary && lastInstructionCrossedPageBoundary) {
cycles++;
}
accumulator = (accumulator & fetch_memory_byte(address, false));
FLAG_SIGN = (accumulator & 0x80) == 0x80;
FLAG_ZERO = (accumulator == 0);
}
void CPU::op_and(uint8_t immediate) {
void CPU::op_and(uint8_t immediate, bool crossedPageBoundary) {
/*
Logic:
A = A & M
P.N = A.7
P.Z = (A==0) ? 1:0 */
if (crossedPageBoundary && lastInstructionCrossedPageBoundary) {
cycles++;
}
accumulator = (accumulator & immediate);
FLAG_SIGN = (accumulator & 0x80) == 0x80;
FLAG_ZERO = (accumulator == 0);
@ -162,9 +185,9 @@ void CPU::op_bcc(int8_t relative) {
if (!FLAG_CARRY) {
//+1 cycle for branching, +2 if branching to a different page
if ((program_counter & 0x00FF) + relative > 0x100) {
EmulatorState::Instance()->processor.cycles++;
cycles++;
}
EmulatorState::Instance()->processor.cycles++;
cycles++;
program_counter += relative;
}
}
@ -173,9 +196,9 @@ void CPU::op_bcs(int8_t relative) {
if (FLAG_CARRY) {
//+1 cycle for branching, +2 if branching to a different page
if ((program_counter & 0x00FF) + relative > 0x100) {
EmulatorState::Instance()->processor.cycles++;
cycles++;
}
EmulatorState::Instance()->processor.cycles++;
cycles++;
program_counter += relative;
}
}
@ -184,9 +207,9 @@ void CPU::op_beq(int8_t relative) {
if (FLAG_ZERO) {
//+1 cycle for branching, +2 if branching to a different page
if ((program_counter & 0x00FF) + relative > 0x100) {
EmulatorState::Instance()->processor.cycles++;
cycles++;
}
EmulatorState::Instance()->processor.cycles++;
cycles++;
program_counter += relative;
}
}
@ -210,16 +233,16 @@ void CPU::op_bmi(int8_t relative) {
if (PN) {
//+1 cycle for branching, +2 if branching to a different page
if ((program_counter & 0x00FF) + relative > 0x100) {
EmulatorState::Instance()->processor.cycles++;
cycles++;
}
EmulatorState::Instance()->processor.cycles++;
cycles++;
program_counter += relative;
}
}
void CPU::op_bne(int8_t relative) {
if (!PZ) {
EmulatorState::Instance()->processor.cycles++;
cycles++;
program_counter += relative;
if (relative == (int8_t)0xFE) {
std::exit(4);
@ -231,9 +254,9 @@ void CPU::op_bpl(int8_t relative) {
if (!PN) {
//+1 cycle for branching, +2 if branching to a different page
if ((program_counter & 0x00FF) + relative > 0x100) {
EmulatorState::Instance()->processor.cycles++;
cycles++;
}
EmulatorState::Instance()->processor.cycles++;
cycles++;
program_counter += relative;
}
}
@ -253,9 +276,9 @@ void CPU::op_bvc(int8_t relative) {
if (!PV) {
//+1 cycle for branching, +2 if branching to a different page
if ((program_counter & 0x00FF) + relative > 0x100) {
EmulatorState::Instance()->processor.cycles++;
cycles++;
}
EmulatorState::Instance()->processor.cycles++;
cycles++;
program_counter += relative;
}
}
@ -264,9 +287,9 @@ void CPU::op_bvs(int8_t relative) {
if (PV) {
//+1 cycle for branching, +2 if branching to a different page
if ((program_counter & 0x00FF) + relative > 0x100) {
EmulatorState::Instance()->processor.cycles++;
cycles++;
}
EmulatorState::Instance()->processor.cycles++;
cycles++;
program_counter += relative;
}
}
@ -287,7 +310,7 @@ void CPU::op_clv() {
PV = false;
}
void CPU::op_cmp(uint8_t immediate) { //immediate
void CPU::op_cmp(uint8_t immediate, bool crossedPageBoundary) { //immediate
/*
Logic:
t = A - M
@ -296,6 +319,10 @@ void CPU::op_cmp(uint8_t immediate) { //immediate
P.Z = (t==0) ? 1:0
*/
if (crossedPageBoundary && lastInstructionCrossedPageBoundary) {
cycles++;
}
uint8_t t = accumulator - immediate;
PN = (t & 0x80) == 0x80;
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:
t = A - M
@ -312,6 +339,10 @@ void CPU::op_cmp(WideAddress address) {
P.Z = (t==0) ? 1:0
*/
if (crossedPageBoundary && lastInstructionCrossedPageBoundary) {
cycles++;
}
uint8_t t = accumulator - fetch_memory_byte(address, false);
PN = (t & 0x80) == 0x80;
PC = (accumulator >= fetch_memory_byte(address, false));
@ -372,13 +403,23 @@ void CPU::op_dey() {
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;
PN = (accumulator & 0x80) == 0x80;
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);
PN = (accumulator & 0x80) == 0x80;
PZ = (accumulator == 0);
@ -430,37 +471,67 @@ void CPU::op_jsr(WideAddress 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;
PN = (accumulator & 0x80) == 0x80;
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);
PN = (accumulator & 0x80) == 0x80;
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;
PN = (index_x & 0x80) == 0x80;
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);
PN = (index_x & 0x80) == 0x80;
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;
PN = (index_y & 0x80) == 0x80;
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);
PN = (index_y & 0x80) == 0x80;
PZ = (index_y == 0);
@ -498,13 +569,23 @@ void CPU::op_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;
PN = (accumulator & 0x80) == 0x80;
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);
PN = (accumulator & 0x80) == 0x80;
PZ = (accumulator == 0);
@ -613,7 +694,7 @@ void CPU::op_rts() {
program_counter = addr.add(1, false);
}
void CPU::op_sbc(uint8_t immediate) {
void CPU::op_sbc(uint8_t immediate, bool crossedPageBoundary) {
/*
Logic:
IF (P.D)
@ -629,7 +710,7 @@ void CPU::op_sbc(uint8_t immediate) {
*/
//TODO: decimal
op_adc(~immediate);
op_adc(~immediate, crossedPageBoundary);
/*
int8_t t;
@ -649,8 +730,8 @@ void CPU::op_sbc(uint8_t immediate) {
*/
}
void CPU::op_sbc(WideAddress address) {
op_adc(~fetch_memory_byte(address, false));
void CPU::op_sbc(WideAddress address, bool crossedPageBoundary) {
op_adc(~fetch_memory_byte(address, false), crossedPageBoundary);
/*
int8_t t;