started adding settings window for ROM paths
cycle counts accurate when crossing page boundaries lots of other improvements
This commit is contained in:
parent
792386aceb
commit
7235d3a3bb
|
@ -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
|
||||||
|
|
|
@ -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.
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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>
|
|
||||||
<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"/>
|
|
||||||
|
|
||||||
</Grid>
|
</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>
|
||||||
|
</DockPanel>
|
||||||
</Window>
|
</Window>
|
||||||
|
|
|
@ -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();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -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"; }));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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>
|
|
@ -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)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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
|
||||||
|
}
|
||||||
|
}
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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();
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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.
|
||||||
|
|
||||||
void CPU::op_adc(WideAddress address) {
|
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, 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;
|
||||||
|
|
Loading…
Reference in New Issue