summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIan C <ianc@noddybox.co.uk>2012-04-09 23:02:00 +0000
committerIan C <ianc@noddybox.co.uk>2012-04-09 23:02:00 +0000
commit903bc80a68613e55c57ca53b589e13674d2d42ec (patch)
treea7873f368361d56ba292a01165ee4e4554284c97
parentcc22d168dfa8a28fffd1d79d9541bfde2f20bdb6 (diff)
Updated display and emulation to use the new clock.
Added Disassembler page.
-rw-r--r--wpspec/wpspec/AboutPage.xaml11
-rw-r--r--wpspec/wpspec/Converters/ConvertFlagsToString.cs59
-rw-r--r--wpspec/wpspec/Converters/ConvertIntToHex2.cs42
-rw-r--r--wpspec/wpspec/Converters/ConvertIntToHex4.cs42
-rw-r--r--wpspec/wpspec/DisassemblerPage.xaml274
-rw-r--r--wpspec/wpspec/DisassemblerPage.xaml.cs51
-rw-r--r--wpspec/wpspec/GamePage.xaml.cs15
-rw-r--r--wpspec/wpspec/MainPage.xaml40
-rw-r--r--wpspec/wpspec/MainPage.xaml.cs5
-rw-r--r--wpspec/wpspec/Resources/Strings.Designer.cs46
-rw-r--r--wpspec/wpspec/Resources/Strings.resx22
-rw-r--r--wpspec/wpspec/Shared.cs25
-rw-r--r--wpspec/wpspec/Spectrum/Emulation.cs212
-rw-r--r--wpspec/wpspec/ViewModels/BaseViewModel.cs67
-rw-r--r--wpspec/wpspec/ViewModels/DisassemblerLine.cs34
-rw-r--r--wpspec/wpspec/ViewModels/DisassemblerViewModel.cs249
-rw-r--r--wpspec/wpspec/wpspec.csproj17
17 files changed, 1091 insertions, 120 deletions
diff --git a/wpspec/wpspec/AboutPage.xaml b/wpspec/wpspec/AboutPage.xaml
index 07a07fa..5fc5ae1 100644
--- a/wpspec/wpspec/AboutPage.xaml
+++ b/wpspec/wpspec/AboutPage.xaml
@@ -32,9 +32,10 @@
<RowDefinition Height="auto" />
<RowDefinition Height="auto" />
<RowDefinition Height="auto" />
+ <RowDefinition Height="auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
- <Rectangle Grid.RowSpan="5" Opacity="0.3">
+ <Rectangle Grid.RowSpan="6" Opacity="0.3">
<Rectangle.Fill>
<LinearGradientBrush StartPoint="0.5,0"
EndPoint="0.5,1.0">
@@ -56,11 +57,15 @@
TargetName="_blank" Grid.Row="2"
NavigateUri="{Binding SourceHyperlinkUri, Source={StaticResource Strings}}" />
<TextBlock TextWrapping="Wrap" TextAlignment="Left" Grid.Row="3"
- FontSize="24" Foreground="Red" Margin="2,2,2,2"
+ FontSize="24" Foreground="Red" Margin="2,20,2,2"
Text="{Binding ROMCopyrightText, Source={StaticResource Strings}}" />
+ <HyperlinkButton Content="Amstrad PLC"
+ TargetName="_blank" Grid.Row="4"
+ Margin="2,5,2,2"
+ NavigateUri="http://www.amstrad.com/" />
<TextBlock FontSize="10" VerticalAlignment="Bottom"
HorizontalAlignment="Center"
- Grid.Row="4"
+ Grid.Row="5"
Text="Your user can't help you now my little program..." />
</Grid>
</Grid>
diff --git a/wpspec/wpspec/Converters/ConvertFlagsToString.cs b/wpspec/wpspec/Converters/ConvertFlagsToString.cs
new file mode 100644
index 0000000..5946cc7
--- /dev/null
+++ b/wpspec/wpspec/Converters/ConvertFlagsToString.cs
@@ -0,0 +1,59 @@
+using System;
+using System.Net;
+using System.Windows;
+using System.Windows.Controls;
+using System.Windows.Documents;
+using System.Windows.Ink;
+using System.Windows.Input;
+using System.Windows.Media;
+using System.Windows.Media.Animation;
+using System.Windows.Shapes;
+using System.Windows.Data;
+using Noddybox.Emulation.EightBit.Z80;
+
+namespace wpspec.Converters
+{
+ /// <summary>
+ ///
+ /// </summary>
+ public class ConvertFlagsToString : IValueConverter
+ {
+ #region IValueConverter Members
+
+ public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
+ {
+ object ret = null;
+
+ if (value is Z80Flags)
+ {
+ int flag = (int)value;
+ char[] names = new char[8] {'C', 'N', 'P', '3', 'H', '5', 'Z', 'S'};
+ char[] flags = new char[8];
+ int f;
+
+ for(f = 0; f < 8; f++)
+ {
+ if ((flag & (1 << f)) == (1 << f))
+ {
+ flags[7-f] = names[7-f];
+ }
+ else
+ {
+ flags[7-f] = '-';
+ }
+ }
+
+ ret = new string(flags);
+ }
+
+ return ret;
+ }
+
+ public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
+ {
+ throw new NotImplementedException();
+ }
+
+ #endregion
+ }
+}
diff --git a/wpspec/wpspec/Converters/ConvertIntToHex2.cs b/wpspec/wpspec/Converters/ConvertIntToHex2.cs
new file mode 100644
index 0000000..e640a00
--- /dev/null
+++ b/wpspec/wpspec/Converters/ConvertIntToHex2.cs
@@ -0,0 +1,42 @@
+using System;
+using System.Net;
+using System.Windows;
+using System.Windows.Controls;
+using System.Windows.Documents;
+using System.Windows.Ink;
+using System.Windows.Input;
+using System.Windows.Media;
+using System.Windows.Media.Animation;
+using System.Windows.Shapes;
+using System.Windows.Data;
+
+namespace wpspec.Converters
+{
+ /// <summary>
+ /// Convert an integer to a 2-digit hex string.
+ /// </summary>
+ public class ConvertIntToHex2 : IValueConverter
+ {
+ #region IValueConverter Members
+
+ public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
+ {
+ object ret = null;
+
+ if (value is int)
+ {
+ int i = (int)value;
+ ret = i.ToString("X2");
+ }
+
+ return ret;
+ }
+
+ public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
+ {
+ throw new NotImplementedException();
+ }
+
+ #endregion
+ }
+}
diff --git a/wpspec/wpspec/Converters/ConvertIntToHex4.cs b/wpspec/wpspec/Converters/ConvertIntToHex4.cs
new file mode 100644
index 0000000..ab2fb86
--- /dev/null
+++ b/wpspec/wpspec/Converters/ConvertIntToHex4.cs
@@ -0,0 +1,42 @@
+using System;
+using System.Net;
+using System.Windows;
+using System.Windows.Controls;
+using System.Windows.Documents;
+using System.Windows.Ink;
+using System.Windows.Input;
+using System.Windows.Media;
+using System.Windows.Media.Animation;
+using System.Windows.Shapes;
+using System.Windows.Data;
+
+namespace wpspec.Converters
+{
+ /// <summary>
+ /// Convert an integer to a 4-digit hex string.
+ /// </summary>
+ public class ConvertIntToHex4 : IValueConverter
+ {
+ #region IValueConverter Members
+
+ public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
+ {
+ object ret = null;
+
+ if (value is int)
+ {
+ int i = (int)value;
+ ret = i.ToString("X4");
+ }
+
+ return ret;
+ }
+
+ public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
+ {
+ throw new NotImplementedException();
+ }
+
+ #endregion
+ }
+}
diff --git a/wpspec/wpspec/DisassemblerPage.xaml b/wpspec/wpspec/DisassemblerPage.xaml
new file mode 100644
index 0000000..95b149c
--- /dev/null
+++ b/wpspec/wpspec/DisassemblerPage.xaml
@@ -0,0 +1,274 @@
+<phone:PhoneApplicationPage
+ x:Class="wpspec.DisassemblerPage"
+ xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
+ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+ xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone"
+ xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone"
+ xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
+ xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
+ xmlns:res="clr-namespace:wpspec.Resources"
+ xmlns:conv="clr-namespace:wpspec.Converters"
+ FontFamily="{StaticResource PhoneFontFamilyNormal}"
+ FontSize="{StaticResource PhoneFontSizeNormal}"
+ Foreground="{StaticResource PhoneForegroundBrush}"
+ SupportedOrientations="Portrait" Orientation="Portrait"
+ mc:Ignorable="d" d:DesignHeight="800" d:DesignWidth="480"
+ shell:SystemTray.IsVisible="False">
+
+ <phone:PhoneApplicationPage.Resources>
+ <res:Strings x:Key="Strings" />
+ <conv:ConvertFlagsToString x:Key="ConvertFlagsToString" />
+ <conv:ConvertIntToHex2 x:Key="ConvertIntToHex2" />
+ <conv:ConvertIntToHex4 x:Key="ConvertIntToHex4" />
+
+ <Style x:Name="StateInfo" TargetType="TextBlock">
+ <Setter Property="FontSize" Value="18" />
+ <Setter Property="FontWeight" Value="Bold" />
+ <Setter Property="Foreground" Value="White" />
+ <Setter Property="HorizontalAlignment" Value="Center" />
+ </Style>
+ <Style x:Name="StateData" TargetType="TextBlock">
+ <Setter Property="FontFamily" Value="Courier New" />
+ <Setter Property="FontSize" Value="18" />
+ <Setter Property="FontWeight" Value="Normal" />
+ <Setter Property="Foreground" Value="LightGray" />
+ <Setter Property="HorizontalAlignment" Value="Center" />
+ </Style>
+ <Style x:Name="DisassemMemory" TargetType="TextBlock">
+ <Setter Property="FontFamily" Value="Courier New" />
+ <Setter Property="FontWeight" Value="Normal" />
+ <Setter Property="Foreground" Value="Yellow" />
+ <Setter Property="FontSize" Value="18" />
+ <Setter Property="HorizontalAlignment" Value="Left" />
+ </Style>
+ <Style x:Name="DisassemOpcode" TargetType="TextBlock">
+ <Setter Property="FontWeight" Value="Normal" />
+ <Setter Property="Foreground" Value="White" />
+ <Setter Property="FontFamily" Value="Courier New" />
+ <Setter Property="FontSize" Value="18" />
+ <Setter Property="HorizontalAlignment" Value="Left" />
+ </Style>
+ <Style x:Name="DisassemHexdump" TargetType="TextBlock">
+ <Setter Property="FontWeight" Value="Normal" />
+ <Setter Property="Foreground" Value="Red" />
+ <Setter Property="FontFamily" Value="Courier New" />
+ <Setter Property="FontSize" Value="18" />
+ <Setter Property="HorizontalAlignment" Value="Left" />
+ </Style>
+ <Style x:Name="ButtonText" TargetType="TextBlock">
+ <Setter Property="FontWeight" Value="Normal" />
+ <Setter Property="FontSize" Value="18" />
+ <Setter Property="HorizontalAlignment" Value="Center" />
+ <Setter Property="TextWrapping" Value="Wrap" />
+ </Style>
+ </phone:PhoneApplicationPage.Resources>
+
+ <!--LayoutRoot is the root grid where all page content is placed-->
+ <Grid x:Name="LayoutRoot" Background="Transparent">
+ <Grid.RowDefinitions>
+ <RowDefinition Height="Auto"/>
+ <RowDefinition Height="*"/>
+ </Grid.RowDefinitions>
+
+ <!--TitlePanel contains the name of the application and page title-->
+ <StackPanel x:Name="TitlePanel" Grid.Row="0" Margin="12,17,0,28">
+ <TextBlock x:Name="ApplicationTitle"
+ Text="{Binding AppTitle, Source={StaticResource Strings}}"
+ Style="{StaticResource PhoneTextNormalStyle}"/>
+ <TextBlock x:Name="PageTitle"
+ Text="{Binding DisassemblerPageTitleText, Source={StaticResource Strings}}"
+ Margin="9,-7,0,0" Style="{StaticResource PhoneTextTitle1Style}"/>
+ </StackPanel>
+
+ <!--ContentPanel - place additional content here-->
+ <Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
+ <Grid.RowDefinitions>
+ <RowDefinition Height="Auto"/>
+ <RowDefinition Height="*"/>
+ <RowDefinition Height="Auto"/>
+ <RowDefinition Height="Auto"/>
+ </Grid.RowDefinitions>
+
+ <!-- Z80 State -->
+ <Grid Grid.Row="0">
+ <Grid.RowDefinitions>
+ <RowDefinition Height="Auto"/>
+ <RowDefinition Height="Auto"/>
+ <RowDefinition Height="Auto"/>
+ <RowDefinition Height="Auto"/>
+ <RowDefinition Height="Auto"/>
+ <RowDefinition Height="Auto"/>
+ </Grid.RowDefinitions>
+ <Grid.ColumnDefinitions>
+ <ColumnDefinition Width="1*" />
+ <ColumnDefinition Width="1*" />
+ <ColumnDefinition Width="1*" />
+ <ColumnDefinition Width="1*" />
+ <ColumnDefinition Width="1*" />
+ <ColumnDefinition Width="1*" />
+ <ColumnDefinition Width="1*" />
+ </Grid.ColumnDefinitions>
+
+ <TextBlock Style="{StaticResource StateInfo}" Text="A"
+ Grid.Row="0" Grid.Column="0" />
+ <TextBlock Style="{StaticResource StateInfo}" Text="Flags"
+ Grid.Row="0" Grid.Column="1" Grid.ColumnSpan="2" />
+ <TextBlock Style="{StaticResource StateInfo}" Text="BC"
+ Grid.Row="0" Grid.Column="3" />
+ <TextBlock Style="{StaticResource StateInfo}" Text="DE"
+ Grid.Row="0" Grid.Column="4" />
+ <TextBlock Style="{StaticResource StateInfo}" Text="HL"
+ Grid.Row="0" Grid.Column="5" />
+ <TextBlock Style="{StaticResource StateInfo}" Text="PC"
+ Grid.Row="0" Grid.Column="6" />
+
+ <TextBlock Style="{StaticResource StateData}"
+ Text="{Binding A, Mode=OneWay, Converter={StaticResource ConvertIntToHex2}}"
+ Grid.Row="1" Grid.Column="0"/>
+ <TextBlock Style="{StaticResource StateData}"
+ Text="{Binding Flags, Mode=OneWay, Converter={StaticResource ConvertFlagsToString}}"
+ Grid.Row="1" Grid.Column="1" Grid.ColumnSpan="2"/>
+ <TextBlock Style="{StaticResource StateData}"
+ Text="{Binding BC, Mode=OneWay, Converter={StaticResource ConvertIntToHex4}}"
+ Grid.Row="1" Grid.Column="3"/>
+ <TextBlock Style="{StaticResource StateData}"
+ Text="{Binding DE, Mode=OneWay, Converter={StaticResource ConvertIntToHex4}}"
+ Grid.Row="1" Grid.Column="4"/>
+ <TextBlock Style="{StaticResource StateData}"
+ Text="{Binding HL, Mode=OneWay, Converter={StaticResource ConvertIntToHex4}}"
+ Grid.Row="1" Grid.Column="5"/>
+ <TextBlock Style="{StaticResource StateData}"
+ Text="{Binding PC, Mode=OneWay, Converter={StaticResource ConvertIntToHex4}}"
+ Grid.Row="1" Grid.Column="6"/>
+
+ <TextBlock Style="{StaticResource StateInfo}" Text="IX"
+ Grid.Row="2" Grid.Column="0" />
+ <TextBlock Style="{StaticResource StateInfo}" Text="IY"
+ Grid.Row="2" Grid.Column="1" />
+ <TextBlock Style="{StaticResource StateInfo}" Text="SP"
+ Grid.Row="2" Grid.Column="2" />
+ <TextBlock Style="{StaticResource StateInfo}" Text="AF'"
+ Grid.Row="2" Grid.Column="3" />
+ <TextBlock Style="{StaticResource StateInfo}" Text="BC'"
+ Grid.Row="2" Grid.Column="4" />
+ <TextBlock Style="{StaticResource StateInfo}" Text="DE'"
+ Grid.Row="2" Grid.Column="5" />
+ <TextBlock Style="{StaticResource StateInfo}" Text="HL'"
+ Grid.Row="2" Grid.Column="6" />
+
+ <TextBlock Style="{StaticResource StateData}"
+ Text="{Binding IY, Mode=OneWay, Converter={StaticResource ConvertIntToHex4}}"
+ Grid.Row="3" Grid.Column="0"/>
+ <TextBlock Style="{StaticResource StateData}"
+ Text="{Binding IY, Mode=OneWay, Converter={StaticResource ConvertIntToHex4}}"
+ Grid.Row="3" Grid.Column="1"/>
+ <TextBlock Style="{StaticResource StateData}"
+ Text="{Binding SP, Mode=OneWay, Converter={StaticResource ConvertIntToHex4}}"
+ Grid.Row="3" Grid.Column="2"/>
+ <TextBlock Style="{StaticResource StateData}"
+ Text="{Binding AF_, Mode=OneWay, Converter={StaticResource ConvertIntToHex4}}"
+ Grid.Row="3" Grid.Column="3"/>
+ <TextBlock Style="{StaticResource StateData}"
+ Text="{Binding BC_, Mode=OneWay, Converter={StaticResource ConvertIntToHex4}}"
+ Grid.Row="3" Grid.Column="4"/>
+ <TextBlock Style="{StaticResource StateData}"
+ Text="{Binding DE_, Mode=OneWay, Converter={StaticResource ConvertIntToHex4}}"
+ Grid.Row="3" Grid.Column="5"/>
+ <TextBlock Style="{StaticResource StateData}"
+ Text="{Binding HL_, Mode=OneWay, Converter={StaticResource ConvertIntToHex4}}"
+ Grid.Row="3" Grid.Column="6"/>
+
+ <TextBlock Style="{StaticResource StateInfo}" Text="IM"
+ Grid.Row="4" Grid.Column="0" />
+ <TextBlock Style="{StaticResource StateInfo}" Text="I"
+ Grid.Row="4" Grid.Column="1" />
+ <TextBlock Style="{StaticResource StateInfo}" Text="R"
+ Grid.Row="4" Grid.Column="2" />
+ <TextBlock Style="{StaticResource StateInfo}" Text="IFF1"
+ Grid.Row="4" Grid.Column="3" />
+ <TextBlock Style="{StaticResource StateInfo}" Text="IFF2"
+ Grid.Row="4" Grid.Column="4" />
+ <TextBlock Style="{StaticResource StateInfo}" Text="Opcodes"
+ Grid.Row="4" Grid.Column="5" Grid.ColumnSpan="2"/>
+
+ <TextBlock Style="{StaticResource StateData}"
+ Text="{Binding IM, Mode=OneWay, Converter={StaticResource ConvertIntToHex2}}"
+ Grid.Row="5" Grid.Column="0"/>
+ <TextBlock Style="{StaticResource StateData}"
+ Text="{Binding I, Mode=OneWay, Converter={StaticResource ConvertIntToHex2}}"
+ Grid.Row="5" Grid.Column="1"/>
+ <TextBlock Style="{StaticResource StateData}"
+ Text="{Binding R, Mode=OneWay, Converter={StaticResource ConvertIntToHex2}}"
+ Grid.Row="5" Grid.Column="2"/>
+ <TextBlock Style="{StaticResource StateData}"
+ Text="{Binding IFF1, Mode=OneWay}"
+ Grid.Row="5" Grid.Column="3"/>
+ <TextBlock Style="{StaticResource StateData}"
+ Text="{Binding IFF2, Mode=OneWay}"
+ Grid.Row="5" Grid.Column="4"/>
+ <TextBlock Style="{StaticResource StateData}"
+ Text="{Binding ExecutedInstructions, Mode=OneWay}"
+ Grid.Row="5" Grid.Column="5" Grid.ColumnSpan="2"/>
+
+ </Grid>
+
+ <!-- Disassembly -->
+ <ListBox Grid.Row="1"
+ ItemsSource="{Binding Disassembly, Mode=OneWay}"
+ VerticalAlignment="Top" BorderThickness="2"
+ BorderBrush="DarkBlue" >
+ <ListBox.ItemTemplate>
+ <DataTemplate>
+ <Grid>
+ <Grid.ColumnDefinitions>
+ <ColumnDefinition Width="100" />
+ <ColumnDefinition Width="200" />
+ <ColumnDefinition Width="*" />
+ </Grid.ColumnDefinitions>
+ <TextBlock Text="{Binding Path=Address}"
+ Grid.Column="0"
+ Style="{StaticResource DisassemMemory}" />
+ <TextBlock Text="{Binding Path=Opcode}"
+ Grid.Column="1"
+ Style="{StaticResource DisassemOpcode}" />
+ <TextBlock Text="{Binding Path=Hexdump}"
+ Grid.Column="2"
+ Style="{StaticResource DisassemHexdump}" />
+ </Grid>
+ </DataTemplate>
+ </ListBox.ItemTemplate>
+ </ListBox>
+
+ <Grid Grid.Row="2">
+ <Grid.ColumnDefinitions>
+ <ColumnDefinition Width="1*" />
+ <ColumnDefinition Width="1*" />
+ <ColumnDefinition Width="1*" />
+ </Grid.ColumnDefinitions>
+ <Grid.RowDefinitions>
+ <RowDefinition Height="3*" />
+ <RowDefinition Height="1*" />
+ </Grid.RowDefinitions>
+ <!-- Step -->
+ <Button Grid.Column="0" Grid.RowSpan="2" Click="StepClick">
+ <TextBlock Text="{Binding DisassemblerStepButtonText, Source={StaticResource Strings}}"
+ Style="{StaticResource ButtonText}" />
+ </Button>
+
+ <Slider Minimum="1" Maximum="1000" Grid.Column="1" Grid.Row="0"
+ Value="{Binding Steps, Mode=TwoWay}"/>
+
+ <TextBlock Grid.Column="1" Grid.Row="1"
+ Text="{Binding Steps, Mode=OneWay}"
+ HorizontalAlignment="Center"/>
+
+ <!-- Run Frame -->
+ <Button Grid.Column="3" Grid.RowSpan="2" Click="RunClick">
+ <TextBlock Text="{Binding DisassemblerRunFrameButtonText, Source={StaticResource Strings}}"
+ Style="{StaticResource ButtonText}" />
+ </Button>
+ </Grid>
+ </Grid>
+ </Grid>
+
+</phone:PhoneApplicationPage>
diff --git a/wpspec/wpspec/DisassemblerPage.xaml.cs b/wpspec/wpspec/DisassemblerPage.xaml.cs
new file mode 100644
index 0000000..a09bfbd
--- /dev/null
+++ b/wpspec/wpspec/DisassemblerPage.xaml.cs
@@ -0,0 +1,51 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Net;
+using System.Windows;
+using System.Windows.Controls;
+using System.Windows.Documents;
+using System.Windows.Input;
+using System.Windows.Media;
+using System.Windows.Media.Animation;
+using System.Windows.Shapes;
+using Microsoft.Phone.Controls;
+using System.ComponentModel;
+using wpspec.ViewModels;
+
+namespace wpspec
+{
+ /// <summary>
+ /// Displays the disassembler page.
+ /// </summary>
+ public partial class DisassemblerPage : PhoneApplicationPage, INotifyPropertyChanged
+ {
+ private DisassemblerViewModel model;
+
+ public DisassemblerPage()
+ {
+ model = new DisassemblerViewModel();
+ DataContext = model;
+ InitializeComponent();
+ }
+
+ private void StepClick(object sender, RoutedEventArgs e)
+ {
+ model.Step();
+ }
+
+ private void RunClick(object sender, RoutedEventArgs e)
+ {
+ model.Run();
+ }
+
+ #region INotifyPropertyChanged Members
+
+ /// <summary>
+ /// Event for property changes.
+ /// </summary>
+ public event PropertyChangedEventHandler PropertyChanged;
+
+ #endregion
+ }
+} \ No newline at end of file
diff --git a/wpspec/wpspec/GamePage.xaml.cs b/wpspec/wpspec/GamePage.xaml.cs
index 7645921..079b19f 100644
--- a/wpspec/wpspec/GamePage.xaml.cs
+++ b/wpspec/wpspec/GamePage.xaml.cs
@@ -25,6 +25,7 @@ namespace wpspec
private GameTimer timer;
private SpriteBatch spriteBatch;
private Texture2D screen;
+ private Vector2 location;
#endregion
@@ -44,7 +45,7 @@ namespace wpspec
// Create a timer for this page.
//
timer = new GameTimer();
- timer.UpdateInterval = TimeSpan.FromMilliseconds(20 * Shared.FrameSkip);
+ timer.UpdateInterval = TimeSpan.FromMilliseconds(20);
timer.Update += OnUpdate;
timer.Draw += OnDraw;
}
@@ -75,6 +76,9 @@ namespace wpspec
//
timer.Start();
+ location = new Vector2(SharedGraphicsDeviceManager.Current.GraphicsDevice.DisplayMode.Width / 2 - Shared.Spectrum.Width / 2,
+ 10);
+
base.OnNavigatedTo(e);
}
@@ -104,7 +108,6 @@ namespace wpspec
private void OnUpdate(object sender, GameTimerEventArgs e)
{
// TODO: Softkeyboard
-
Shared.Spectrum.Run();
}
@@ -113,20 +116,14 @@ namespace wpspec
/// </summary>
private void OnDraw(object sender, GameTimerEventArgs e)
{
- Stopwatch s = Stopwatch.StartNew();
-
SharedGraphicsDeviceManager.Current.GraphicsDevice.Clear(Color.Black);
- Shared.Spectrum.Update();
screen.SetData(Shared.Spectrum.Screen);
spriteBatch.Begin();
- spriteBatch.Draw(screen, Vector2.Zero, Color.White);
+ spriteBatch.Draw(screen, location, Color.White);
spriteBatch.End();
SharedGraphicsDeviceManager.Current.GraphicsDevice.Textures[0] = null;
-
- s.Stop();
- Debug.WriteLine("RENDER: {0} ms {1} ticks", s.ElapsedMilliseconds, s.ElapsedTicks);
}
#endregion
diff --git a/wpspec/wpspec/MainPage.xaml b/wpspec/wpspec/MainPage.xaml
index 87073a3..655a1d8 100644
--- a/wpspec/wpspec/MainPage.xaml
+++ b/wpspec/wpspec/MainPage.xaml
@@ -25,7 +25,6 @@
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
-
<!--TitlePanel contains the name of the application and page title-->
<StackPanel x:Name="TitlePanel" Grid.Row="0" Margin="12,17,0,28">
<TextBlock x:Name="ApplicationTitle"
@@ -38,19 +37,24 @@
</StackPanel>
<!--ContentPanel - place additional content here-->
- <Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0" VerticalAlignment="Center">
+ <Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0" VerticalAlignment="Top">
<Grid.RowDefinitions>
<RowDefinition Height="auto" />
<RowDefinition Height="auto" />
<RowDefinition Height="auto" />
<RowDefinition Height="auto" />
<RowDefinition Height="auto" />
- <RowDefinition Height="auto" />
</Grid.RowDefinitions>
+
+ <Grid.ColumnDefinitions>
+ <ColumnDefinition Width="*" />
+ <ColumnDefinition Width="*" />
+ </Grid.ColumnDefinitions>
+
<!-- Run the emulator -->
- <Button Height="100"
+ <Button Height="120"
Content="{Binding RunEmulationButtonText, Source={StaticResource Strings}}"
- Grid.Row="0"
+ Grid.Row="0" Grid.ColumnSpan="2"
Click="RunEmulationClick">
<Button.Background>
<LinearGradientBrush StartPoint="0.5,0"
@@ -70,33 +74,39 @@
</Button.Background>
</Button>
<!-- Open Remote Tape -->
- <Button Height="100"
+ <Button Height="120"
Content="{Binding OpenRemoteTapeButtonText, Source={StaticResource Strings}}"
- Grid.Row="1"
+ Grid.Row="1" Grid.ColumnSpan="2"
Background="Black"
Click="OpenRemoteTapeClick" />
<!-- Open Local Tape -->
- <Button Height="100"
+ <Button Height="120"
Content="{Binding OpenLocalTapeButtonText, Source={StaticResource Strings}}"
- Grid.Row="2"
+ Grid.Row="2" Grid.Column="0"
Background="Black"
Click="OpenLocalTapeClick" />
<!-- Save Local Tape -->
- <Button Height="100"
+ <Button Height="120"
Content="{Binding SaveLocalTapeButtonText, Source={StaticResource Strings}}"
- Grid.Row="3"
+ Grid.Row="2" Grid.Column="1"
Background="Black"
Click="SaveLocalTapeClick" />
<!-- Configure the emulator -->
- <Button Height="100"
+ <Button Height="120"
Content="{Binding SettingsButtonText, Source={StaticResource Strings}}"
- Grid.Row="4"
+ Grid.Row="3" Grid.Column="0"
Background="Black"
Click="SettingsClick" />
+ <!-- Run the Monitor -->
+ <Button Height="120"
+ Content="{Binding DisassemblerButtonText, Source={StaticResource Strings}}"
+ Grid.Row="3" Grid.Column="1"
+ Background="Black"
+ Click="DisassemblerClick" />
<!-- About -->
- <Button Height="100"
+ <Button Height="120"
Content="{Binding AboutButtonText, Source={StaticResource Strings}}"
- Grid.Row="5"
+ Grid.Row="5" Grid.ColumnSpan="2"
Background="Black"
Click="AboutClick" />
diff --git a/wpspec/wpspec/MainPage.xaml.cs b/wpspec/wpspec/MainPage.xaml.cs
index 02b279d..3ebb4be 100644
--- a/wpspec/wpspec/MainPage.xaml.cs
+++ b/wpspec/wpspec/MainPage.xaml.cs
@@ -50,5 +50,10 @@ namespace wpspec
{
NavigationService.Navigate(new Uri("/SaveLocalTapePage.xaml", UriKind.Relative));
}
+
+ private void DisassemblerClick(object sender, RoutedEventArgs e)
+ {
+ NavigationService.Navigate(new Uri("/DisassemblerPage.xaml", UriKind.Relative));
+ }
}
} \ No newline at end of file
diff --git a/wpspec/wpspec/Resources/Strings.Designer.cs b/wpspec/wpspec/Resources/Strings.Designer.cs
index e5cf7d5..dcee2cd 100644
--- a/wpspec/wpspec/Resources/Strings.Designer.cs
+++ b/wpspec/wpspec/Resources/Strings.Designer.cs
@@ -110,6 +110,42 @@ namespace wpspec.Resources {
}
/// <summary>
+ /// Looks up a localized string similar to Disassembler.
+ /// </summary>
+ public static string DisassemblerButtonText {
+ get {
+ return ResourceManager.GetString("DisassemblerButtonText", resourceCulture);
+ }
+ }
+
+ /// <summary>
+ /// Looks up a localized string similar to Disassembler.
+ /// </summary>
+ public static string DisassemblerPageTitleText {
+ get {
+ return ResourceManager.GetString("DisassemblerPageTitleText", resourceCulture);
+ }
+ }
+
+ /// <summary>
+ /// Looks up a localized string similar to Run Frame.
+ /// </summary>
+ public static string DisassemblerRunFrameButtonText {
+ get {
+ return ResourceManager.GetString("DisassemblerRunFrameButtonText", resourceCulture);
+ }
+ }
+
+ /// <summary>
+ /// Looks up a localized string similar to Step.
+ /// </summary>
+ public static string DisassemblerStepButtonText {
+ get {
+ return ResourceManager.GetString("DisassemblerStepButtonText", resourceCulture);
+ }
+ }
+
+ /// <summary>
/// Looks up a localized string similar to See the GNU General Public License Online.
/// </summary>
public static string LicenseHyperlinkText {
@@ -146,7 +182,7 @@ namespace wpspec.Resources {
}
/// <summary>
- /// Looks up a localized string similar to Open Game State.
+ /// Looks up a localized string similar to Open State.
/// </summary>
public static string OpenLocalTapeButtonText {
get {
@@ -155,7 +191,7 @@ namespace wpspec.Resources {
}
/// <summary>
- /// Looks up a localized string similar to Open Game.
+ /// Looks up a localized string similar to Open Spectrum State.
/// </summary>
public static string OpenLocalTapePageTitle {
get {
@@ -173,7 +209,7 @@ namespace wpspec.Resources {
}
/// <summary>
- /// Looks up a localized string similar to Open Remote.
+ /// Looks up a localized string similar to Open Remote Tape File.
/// </summary>
public static string OpenRemoteTapePageTitle {
get {
@@ -200,7 +236,7 @@ namespace wpspec.Resources {
}
/// <summary>
- /// Looks up a localized string similar to Save Game State.
+ /// Looks up a localized string similar to Save State.
/// </summary>
public static string SaveLocalTapeButtonText {
get {
@@ -209,7 +245,7 @@ namespace wpspec.Resources {
}
/// <summary>
- /// Looks up a localized string similar to Save Game.
+ /// Looks up a localized string similar to Save Spectrum State.
/// </summary>
public static string SaveLocalTapePageTitle {
get {
diff --git a/wpspec/wpspec/Resources/Strings.resx b/wpspec/wpspec/Resources/Strings.resx
index 2b22545..2a0b059 100644
--- a/wpspec/wpspec/Resources/Strings.resx
+++ b/wpspec/wpspec/Resources/Strings.resx
@@ -136,6 +136,18 @@ This program is free software: you can redistribute it and/or modify it under th
This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.</value>
</data>
+ <data name="DisassemblerButtonText" xml:space="preserve">
+ <value>Disassembler</value>
+ </data>
+ <data name="DisassemblerPageTitleText" xml:space="preserve">
+ <value>Disassembler</value>
+ </data>
+ <data name="DisassemblerRunFrameButtonText" xml:space="preserve">
+ <value>Run Frame</value>
+ </data>
+ <data name="DisassemblerStepButtonText" xml:space="preserve">
+ <value>Step</value>
+ </data>
<data name="LicenseHyperlinkText" xml:space="preserve">
<value>See the GNU General Public License Online</value>
</data>
@@ -149,16 +161,16 @@ This program is distributed in the hope that it will be useful, but WITHOUT ANY
<value>OK</value>
</data>
<data name="OpenLocalTapeButtonText" xml:space="preserve">
- <value>Open Game State</value>
+ <value>Open State</value>
</data>
<data name="OpenLocalTapePageTitle" xml:space="preserve">
- <value>Open Game</value>
+ <value>Open Spectrum State</value>
</data>
<data name="OpenRemoteTapeButtonText" xml:space="preserve">
<value>Open Remote Tape</value>
</data>
<data name="OpenRemoteTapePageTitle" xml:space="preserve">
- <value>Open Remote</value>
+ <value>Open Remote Tape File</value>
</data>
<data name="ROMCopyrightText" xml:space="preserve">
<value>Copyright of the included Spectrum 48K ROM is held by Amstrad PLC, and the ROM image is included with their kind permission.</value>
@@ -167,10 +179,10 @@ This program is distributed in the hope that it will be useful, but WITHOUT ANY
<value>Run Spectrum 48K</value>
</data>
<data name="SaveLocalTapeButtonText" xml:space="preserve">
- <value>Save Game State</value>
+ <value>Save State</value>
</data>
<data name="SaveLocalTapePageTitle" xml:space="preserve">
- <value>Save Game</value>
+ <value>Save Spectrum State</value>
</data>
<data name="SelectLocalTapeText" xml:space="preserve">
<value>Select Game to open</value>
diff --git a/wpspec/wpspec/Shared.cs b/wpspec/wpspec/Shared.cs
new file mode 100644
index 0000000..28b8e9e
--- /dev/null
+++ b/wpspec/wpspec/Shared.cs
@@ -0,0 +1,25 @@
+using System;
+using System.Net;
+using System.Windows;
+using System.Windows.Controls;
+using System.Windows.Documents;
+using System.Windows.Ink;
+using System.Windows.Input;
+using System.Windows.Media;
+using System.Windows.Media.Animation;
+using System.Windows.Shapes;
+using wpspec.Spectrum;
+
+namespace wpspec
+{
+ /// <summary>
+ /// Contains shared objects between the Silverlight and XNA domains
+ /// </summary>
+ public static class Shared
+ {
+ /// <summary>
+ /// The emulation driving the Spectrum.
+ /// </summary>
+ public static Emulation Spectrum {get; set;}
+ }
+}
diff --git a/wpspec/wpspec/Spectrum/Emulation.cs b/wpspec/wpspec/Spectrum/Emulation.cs
index feeb04d..1b86a93 100644
--- a/wpspec/wpspec/Spectrum/Emulation.cs
+++ b/wpspec/wpspec/Spectrum/Emulation.cs
@@ -9,6 +9,7 @@ using System.IO;
using Microsoft.Xna.Framework;
using System.Diagnostics;
using Microsoft.Xna.Framework.Graphics;
+using Noddybox.Emulation.EightBit.Z80.Disassembler;
namespace wpspec.Spectrum
{
@@ -17,17 +18,16 @@ namespace wpspec.Spectrum
/// </summary>
public class Emulation: IMemory, IDevice
{
- #region Private
+ #region Private Data
private readonly byte[] mem = new byte[0x10000];
- private readonly Clock clock = new Clock(69888 * Shared.FrameSkip, 50 / Shared.FrameSkip);
- private readonly Z80Cpu z80 = new Z80Cpu();
+ private readonly Clock clock = new Clock(0, 224, 312, 0);
private byte[] tape;
private readonly byte[] matrix = new byte[9];
- private readonly int[] screen = new int[192];
+ private readonly int[] screenAccel = new int[192];
//private readonly uint[] colours = new uint[16]
//{
@@ -82,6 +82,93 @@ namespace wpspec.Spectrum
private int flashCounter;
+ private int border;
+
+ #endregion
+
+ #region Private Members
+
+ private void LineHandler(object sender, ClockEventArgs e)
+ {
+ ushort[] scr = Screen;
+ int addr;
+ int attr;
+ int ink;
+ int paper;
+ int t;
+ int p = clock.RasterLine * Width;
+ byte b;
+
+ // Just draw border for these lines
+ //
+ if (clock.RasterLine < 64 || clock.RasterLine > 255)
+ {
+ for(int x = 0; x < Width; x++)
+ {
+ scr[p++] = colours[border];
+ }
+ }
+ else
+ {
+ addr = screenAccel[clock.RasterLine - 64];
+
+ for(int x = 0; x < 32; x++)
+ {
+ scr[p++] = colours[border];
+ }
+
+ for(int x = 0; x < 32; x++)
+ {
+ attr = mem[0x5800 + x + clock.RasterLine / 8 * 32];
+ ink = attr & 0x07;
+ paper = (attr & 0x38) >> 3;
+
+ if ((attr & 0x40) == 0x40)
+ {
+ ink += 8;
+ paper += 8;
+ }
+
+ if ((attr & 0x80) == 0x80 && flash)
+ {
+ t = ink;
+ ink = paper;
+ paper = t;
+ }
+
+ b = mem[addr + x];
+
+ for(int r = 128; r > 0; r /= 2)
+ {
+ if ((b & r) == r)
+ {
+ scr[p++] = colours[ink];
+ }
+ else
+ {
+ scr[p++] = colours[paper];
+ }
+ }
+ }
+
+ for(int x = 0; x < 32; x++)
+ {
+ scr[p++] = colours[border];
+ }
+ }
+ }
+
+ private void VBLHandler(object sender, ClockEventArgs e)
+ {
+ if (++flashCounter == 16)
+ {
+ flashCounter = 0;
+ flash = !flash;
+ }
+
+ Z80.MaskableInterrupt(0xff);
+ }
+
#endregion
#region IMemory Members
@@ -170,7 +257,12 @@ namespace wpspec.Spectrum
/// <param name="value">The byte to send to the device.</param>
void IDevice.Write(ushort device, byte value)
{
- // Do nothing
+ Register16 addr = new Register16(device);
+
+ if (addr.low == 0xfe)
+ {
+ border = value & 0x7;
+ }
}
#endregion
@@ -180,12 +272,12 @@ namespace wpspec.Spectrum
/// <summary>
/// Get the width of the emulated screen in pixels.
/// </summary>
- public int Width {get {return 256;}}
+ public int Width {get {return 320;}}
/// <summary>
/// Get the height of the emulated screen in pixels.
/// </summary>
- public int Height {get {return 192;}}
+ public int Height {get {return 312;}}
/// <summary>
/// Gets the format of data returned by
@@ -209,6 +301,16 @@ namespace wpspec.Spectrum
}
/// <summary>
+ /// The Z80 CPU being used.
+ /// </summary>
+ public Z80Cpu Z80 {private set; get;}
+
+ /// <summary>
+ /// A disassembler for this machine.
+ /// </summary>
+ public Z80Disassembler Disassembler {private set; get;}
+
+ /// <summary>
/// Reset the spectrum
/// </summary>
public void Reset()
@@ -224,7 +326,7 @@ namespace wpspec.Spectrum
// Initialise the Z80
//
- z80.Reset();
+ Z80.Reset();
}
/// <summary>
@@ -232,86 +334,19 @@ namespace wpspec.Spectrum
/// </summary>
public void Run()
{
- Stopwatch s = Stopwatch.StartNew();
-
- z80.ExecutedInstructions = 0;
-
- clock.StartFrame();
- z80.Run();
- z80.MaskableInterrupt(0);
-
- s.Stop();
- Debug.WriteLine("EXEC: {0} ms {1} ticks (PC = {2:4X}, instructions = {3}", s.ElapsedMilliseconds, s.ElapsedTicks, z80.ProgramCounter, z80.ExecutedInstructions);
+ Z80.Run();
}
/// <summary>
- /// Update the emulation display.
+ /// Run the emulation for a number of steps.
/// </summary>
- public void Update()
+ /// <param name="steps">The steps to run.</param>
+ public void Step(int steps)
{
- Stopwatch s = Stopwatch.StartNew();
-
- ushort[] scr = Screen;
- int addr;
- int attr;
- int ink;
- int paper;
- int t;
- int p = 0;
- byte b;
-
- for(int y = 0; y < 192; y++)
+ while(steps-- > 0)
{
- addr = screen[y];
-
- for(int x = 0; x < 32; x++)
- {
- attr = mem[0x5800 + x + y / 8 * 32];
- ink = attr & 0x07;
- paper = (attr & 0x38) >> 3;
-
- if ((attr & 0x40) == 0x40)
- {
- ink += 8;
- paper += 8;
- }
-
- if ((attr & 0x80) == 0x80 && flash)
- {
- t = ink;
- ink = paper;
- paper = t;
- }
-
- b = mem[addr + x];
-
- for(int r = 128; r > 0; r /= 2)
- {
- if ((b & r) == r)
- {
- scr[p++] = colours[ink];
- }
- else
- {
- scr[p++] = colours[paper];
- }
- }
- }
+ Z80.Step();
}
-
- for(int f = 0; f < 192; f++)
- {
- scr[f] = colours[(flashCounter + f) % 16];
- }
-
- if (++flashCounter == 16)
- {
- flashCounter = 0;
- flash = !flash;
- }
-
- s.Stop();
- Debug.WriteLine("UPDATE: {0} ms {1} ticks", s.ElapsedMilliseconds, s.ElapsedTicks);
}
#endregion
@@ -323,6 +358,9 @@ namespace wpspec.Spectrum
/// </summary>
public Emulation()
{
+ Z80 = new Z80Cpu();
+ Disassembler = new Z80Disassembler();
+
// Load the spectrum ROM
//
Uri uri = new Uri("Resources/48.rom", UriKind.Relative);
@@ -341,7 +379,7 @@ namespace wpspec.Spectrum
for(int f = 0; f < 192; f++)
{
- screen[f] = 0x4000 + (c * 8 * 32) + (r * 32);
+ screenAccel[f] = 0x4000 + (c * 8 * 32) + (r * 32);
c++;
@@ -358,9 +396,17 @@ namespace wpspec.Spectrum
}
}
+ // Initialise the clock events
+ //
+ clock.EndOfLine += LineHandler;
+ clock.EndOfVBL += VBLHandler;
+
// Initialise the CPU
//
- z80.Initialise(this, this, clock);
+ Z80.Initialise(this, this, clock);
+ Disassembler.Initialise(this);
+
+ Debug.WriteLine("Clock total = {0}", clock.TotalCyclesPerFrame);
Reset();
}
diff --git a/wpspec/wpspec/ViewModels/BaseViewModel.cs b/wpspec/wpspec/ViewModels/BaseViewModel.cs
new file mode 100644
index 0000000..90cb300
--- /dev/null
+++ b/wpspec/wpspec/ViewModels/BaseViewModel.cs
@@ -0,0 +1,67 @@
+using System;
+using System.Net;
+using System.Windows;
+using System.Windows.Controls;
+using System.Windows.Documents;
+using System.Windows.Ink;
+using System.Windows.Input;
+using System.Windows.Media;
+using System.Windows.Media.Animation;
+using System.Windows.Shapes;
+using System.ComponentModel;
+
+namespace wpspec.ViewModels
+{
+ /// <summary>
+ /// Provides a base for view models.
+ /// </summary>
+ public class BaseViewModel : INotifyPropertyChanged
+ {
+
+ #region SetValue
+
+ /// <summary>
+ /// Sets a value in the model.
+ /// </summary>
+ /// <typeparam name="T">The type of the value.</typeparam>
+ /// <param name="member">A reference to the member variable.</param>
+ /// <param name="value">The new value.</param>
+ /// <param name="names">The propertys to change if the value has changed.</param>
+ protected void SetValue<T>(ref T member, T value, params string[] names)
+ {
+ if (!value.Equals(member))
+ {
+ member = value;
+
+ foreach (string name in names)
+ {
+ NotifyPropertyChanged(name);
+ }
+ }
+ }
+
+ #endregion
+
+ #region Notify
+
+ /// <summary>
+ /// Notifies handlers of a property change.
+ /// </summary>
+ /// <param name="propertyName">The property's name.</param>
+ protected void NotifyPropertyChanged(string propertyName)
+ {
+ if (PropertyChanged != null)
+ {
+ PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
+ }
+ }
+
+ #endregion
+
+ #region INotifyPropertyChanged Members
+
+ public event PropertyChangedEventHandler PropertyChanged;
+
+ #endregion
+ }
+}
diff --git a/wpspec/wpspec/ViewModels/DisassemblerLine.cs b/wpspec/wpspec/ViewModels/DisassemblerLine.cs
new file mode 100644
index 0000000..5504ed8
--- /dev/null
+++ b/wpspec/wpspec/ViewModels/DisassemblerLine.cs
@@ -0,0 +1,34 @@
+using System;
+using System.Net;
+using System.Windows;
+using System.Windows.Controls;
+using System.Windows.Documents;
+using System.Windows.Ink;
+using System.Windows.Input;
+using System.Windows.Media;
+using System.Windows.Media.Animation;
+using System.Windows.Shapes;
+
+namespace wpspec.ViewModels
+{
+ /// <summary>
+ /// Represents a line of disassembly.
+ /// </summary>
+ public class DisassemblerLine
+ {
+ /// <summary>
+ /// The address part.
+ /// </summary>
+ public string Address {get; set;}
+
+ /// <summary>
+ /// The assembly opcode part.
+ /// </summary>
+ public string Opcode {get; set;}
+
+ /// <summary>
+ /// The hexdump part.
+ /// </summary>
+ public string Hexdump {get; set;}
+ }
+}
diff --git a/wpspec/wpspec/ViewModels/DisassemblerViewModel.cs b/wpspec/wpspec/ViewModels/DisassemblerViewModel.cs
new file mode 100644
index 0000000..2b10f98
--- /dev/null
+++ b/wpspec/wpspec/ViewModels/DisassemblerViewModel.cs
@@ -0,0 +1,249 @@
+using System;
+using System.Net;
+using System.Windows;
+using System.Windows.Controls;
+using System.Windows.Documents;
+using System.Windows.Ink;
+using System.Windows.Input;
+using System.Windows.Media;
+using System.Windows.Media.Animation;
+using System.Windows.Shapes;
+using System.Collections.Generic;
+using Noddybox.Emulation.EightBit.Z80;
+
+namespace wpspec.ViewModels
+{
+ /// <summary>
+ /// Implements a view model for the diassembler page.
+ /// </summary>
+ public class DisassemblerViewModel : BaseViewModel
+ {
+ #region Private data
+
+ private Z80Cpu z80;
+ private int a;
+ private Z80Flags flags;
+ private int bc;
+ private int de;
+ private int hl;
+ private int af_;
+ private int bc_;
+ private int de_;
+ private int hl_;
+ private int ix;
+ private int iy;
+ private int sp;
+ private int pc;
+ private int i;
+ private int r;
+ private int im;
+ private string iff1;
+ private string iff2;
+ private uint executedInstructions;
+ private int steps;
+
+ #endregion
+
+ #region Private methods
+
+ private void Update()
+ {
+ Z80Cpu z80 = Shared.Spectrum.Z80;
+
+ A = z80.Acummulator;
+ Flags = z80.StatusFlags;
+ BC = z80.BC_Register.reg;
+ DE = z80.DE_Register.reg;
+ HL = z80.HL_Register.reg;
+ IX = z80.IX_Register.reg;
+ IY = z80.IY_Register.reg;
+ AF_ = z80.AF_Alternate.reg;
+ BC_ = z80.BC_Alternate.reg;
+ DE_ = z80.DE_Alternate.reg;
+ HL_ = z80.HL_Alternate.reg;
+ PC = z80.ProgramCounter;
+ SP = z80.StackPointer;
+ ExecutedInstructions = z80.ExecutedInstructions;
+ I = z80.InterruptVector;
+ R = z80.Refresh;
+ IFF1 = z80.IFF1_Register ? "On":"Off";
+ IFF2 = z80.IFF2_Register ? "On":"Off";
+ }
+
+ #endregion
+
+ #region Properties
+
+ public int A
+ {
+ get {return a;}
+ set {SetValue(ref a, value, "A");}
+ }
+
+ public Z80Flags Flags
+ {
+ get {return flags;}
+ set {SetValue(ref flags, value, "Flags");}
+ }
+
+ public int BC
+ {
+ get {return bc;}
+ set {SetValue(ref bc, value, "BC");}
+ }
+
+ public int DE
+ {
+ get {return de;}
+ set {SetValue(ref de, value, "DE");}
+ }
+
+ public int HL
+ {
+ get {return hl;}
+ set {SetValue(ref hl, value, "HL");}
+ }
+
+ public int AF_
+ {
+ get {return af_;}
+ set {SetValue(ref af_, value, "AF_");}
+ }
+
+ public int BC_
+ {
+ get {return bc_;}
+ set {SetValue(ref bc_, value, "BC_");}
+ }
+
+ public int DE_
+ {
+ get {return de_;}
+ set {SetValue(ref de_, value, "DE_");}
+ }
+
+ public int HL_
+ {
+ get {return hl_;}
+ set {SetValue(ref hl_, value, "HL_");}
+ }
+
+ public int IX
+ {
+ get {return ix;}
+ set {SetValue(ref ix, value, "IX");}
+ }
+
+ public int IY
+ {
+ get {return iy;}
+ set {SetValue(ref iy, value, "IY");}
+ }
+
+ public int SP
+ {
+ get {return sp;}
+ set {SetValue(ref sp, value, "SP");}
+ }
+
+ public int PC
+ {
+ get {return pc;}
+ set {SetValue(ref pc, value, "PC", "Disassembly");}
+ }
+
+ public uint ExecutedInstructions
+ {
+ get {return executedInstructions;}
+ set {SetValue(ref executedInstructions, value, "ExecutedInstructions");}
+ }
+
+ public int I
+ {
+ get {return i;}
+ set {SetValue(ref i, value, "I");}
+ }
+
+ public int R
+ {
+ get {return r;}
+ set {SetValue(ref r, value, "R");}
+ }
+ public int IM
+ {
+ get {return im;}
+ set {SetValue(ref im, value, "IM");}
+ }
+ public string IFF1
+ {
+ get {return iff1;}
+ set {SetValue(ref iff1, value, "ExecutedInstructions");}
+ }
+ public string IFF2
+ {
+ get {return iff2;}
+ set {SetValue(ref iff2, value, "ExecutedInstructions");}
+ }
+
+ public IEnumerable<DisassemblerLine> Disassembly
+ {
+ get
+ {
+ List<DisassemblerLine> list = new List<DisassemblerLine>();
+
+ ushort pc = Shared.Spectrum.Z80.ProgramCounter;
+ string address;
+ string opcode;
+ string hexdump;
+
+ for(int f = 0 ; f < 15; f++)
+ {
+ pc = Shared.Spectrum.Disassembler.Disassemble(pc, out address, out opcode, out hexdump);
+ list.Add(new DisassemblerLine() {Address = address, Opcode = opcode, Hexdump = hexdump});
+ }
+
+ return list;
+ }
+ }
+
+ public int Steps
+ {
+ get {return steps;}
+ set {SetValue(ref steps, value, "Steps");}
+ }
+
+ #endregion
+
+ #region Public methods
+
+ /// <summary>
+ /// Run the ZX81 for a step.
+ /// </summary>
+ public void Step()
+ {
+ Shared.Spectrum.Step(steps);
+ Update();
+ }
+
+ /// <summary>
+ /// Run the ZX81 for a frame.
+ /// </summary>
+ public void Run()
+ {
+ Shared.Spectrum.Run();
+ Update();
+ }
+
+ #endregion
+
+ #region Constructors
+
+ public DisassemblerViewModel()
+ {
+ Steps = 1;
+ Update();
+ }
+
+ #endregion
+ }
+}
diff --git a/wpspec/wpspec/wpspec.csproj b/wpspec/wpspec/wpspec.csproj
index 633c10c..eb2cf9c 100644
--- a/wpspec/wpspec/wpspec.csproj
+++ b/wpspec/wpspec/wpspec.csproj
@@ -72,6 +72,12 @@
<Compile Include="AppServiceProvider.cs">
<DependentUpon>GamePage.xaml</DependentUpon>
</Compile>
+ <Compile Include="Converters\ConvertFlagsToString.cs" />
+ <Compile Include="Converters\ConvertIntToHex2.cs" />
+ <Compile Include="Converters\ConvertIntToHex4.cs" />
+ <Compile Include="DisassemblerPage.xaml.cs">
+ <DependentUpon>DisassemblerPage.xaml</DependentUpon>
+ </Compile>
<Compile Include="MainPage.xaml.cs">
<DependentUpon>MainPage.xaml</DependentUpon>
</Compile>
@@ -99,6 +105,9 @@
</Compile>
<Compile Include="Shared.cs" />
<Compile Include="Spectrum\Emulation.cs" />
+ <Compile Include="ViewModels\BaseViewModel.cs" />
+ <Compile Include="ViewModels\DisassemblerLine.cs" />
+ <Compile Include="ViewModels\DisassemblerViewModel.cs" />
</ItemGroup>
<ItemGroup>
<ApplicationDefinition Include="App.xaml">
@@ -109,6 +118,10 @@
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
+ <Page Include="DisassemblerPage.xaml">
+ <SubType>Designer</SubType>
+ <Generator>MSBuild:Compile</Generator>
+ </Page>
<Page Include="MainPage.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
@@ -151,6 +164,10 @@
<Content Include="SplashScreenImage.jpg" />
</ItemGroup>
<ItemGroup>
+ <ProjectReference Include="..\..\..\Noddybox.Emulation\WindowsPhone\Noddybox.Emulation.EightBit.Z80.Disassembler\Noddybox.Emulation.EightBit.Z80.Disassembler.csproj">
+ <Project>{08D7120E-3D84-49D2-B73D-255E5DB9655C}</Project>
+ <Name>Noddybox.Emulation.EightBit.Z80.Disassembler</Name>
+ </ProjectReference>
<ProjectReference Include="..\..\..\Noddybox.Emulation\WindowsPhone\Noddybox.Emulation.EightBit.Z80\Noddybox.Emulation.EightBit.Z80.csproj">
<Project>{7F257886-40D3-4E2A-BA9C-C5FEE93C08E9}</Project>
<Name>Noddybox.Emulation.EightBit.Z80</Name>