// Copyright (c) 2008, Michał Cichoń
// All rights reserved.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.IO;
using System.Windows.Forms;
using System.Threading;
using Tiny8051.Mcu8051;
using Tiny8051.Controls;
using Crownwood.Magic.Common;
using Crownwood.Magic.Docking;
namespace Tiny8051
{
public partial class Main : Form
{
//--------------------------------------------------------------------------
// Dokowanie
private DockingManager m_docking_manager;
//--------------------------------------------------------------------------
// Procesor
private Mcu8051.Mcu8051 m_processor;
// Debuger
private Debugger m_debugger;
// Deasembler
private Controls.Disassembler m_disassembler;
//--------------------------------------------------------------------------
// Procesor
public Mcu8051.Mcu8051 Processor
{
get { return m_processor; }
}
// Debuger
public Debugger Debugger
{
get { return m_debugger; }
}
//--------------------------------------------------------------------------
// Panel rejestrów
private SFRRegisters m_sfr_registers_panel;
// Panel rejestrów bankowych
private BankRegisters m_bank_registers_panel;
// Panel styków
private ExternalPinsControl m_pins_control_panel;
// Panel pamięci wewnętrznej
private Memory m_memory_1_panel;
// Panel pamięci wewnętrznej
private Memory m_memory_2_panel;
// Panel pamięci wewnętrznej
private Memory m_memory_3_panel;
// Panel pamięci wewnętrznej
private Memory m_memory_4_panel;
//--------------------------------------------------------------------------
//
private string[] m_arguments;
//--------------------------------------------------------------------------
public Main(string[] args):
this()
{
if (args.Length == 1)
LoadFile(args[0]);
if (args.Length > 1)
MessageBox.Show("Too many arguments!", this.Text, MessageBoxButtons.OK, MessageBoxIcon.Error);
}
public Main()
{
InitializeComponent();
// Tworzymy procesor
m_processor = new Tiny8051.Mcu8051.Mcu8051();
// Tworzymy debuger
m_debugger = new Debugger();
m_debugger.Processor = m_processor;
// Zdarzenie debugera
m_debugger.OnTick += OnTick;
// Dokowanie
m_docking_manager = new DockingManager(this, VisualStyle.IDE);
m_docking_manager.InnerControl = ToolBarContainer;
m_docking_manager.OuterControl = StatusBar;
m_docking_manager.ContentShown += new DockingManager.ContentHandler(OnContentShown);
m_docking_manager.ContentHidden += new DockingManager.ContentHandler(OnContentHidden);
// Panel rejestrów ogólnych
m_sfr_registers_panel = new SFRRegisters("SFR Registers", m_processor, new Content(m_docking_manager));
m_docking_manager.Contents.Add(m_sfr_registers_panel.Content);
m_sfr_registers_panel.Content.DisplaySize = new Size(222, 142);
m_sfr_registers_panel.Content.FloatingSize = new Size(232, 142);
m_docking_manager.AddContentWithState(m_sfr_registers_panel.Content, State.DockLeft);
m_docking_manager.ShowContent(m_sfr_registers_panel.Content);
// Panel wewnetrznej pamięci
m_memory_1_panel = new Memory("Memory 1", m_processor, new Content(m_docking_manager));
m_docking_manager.Contents.Add(m_memory_1_panel.Content);
WindowContent wnd_content = m_docking_manager.AddContentWithState(m_memory_1_panel.Content, State.DockBottom);
m_docking_manager.ShowContent(m_memory_1_panel.Content);
m_memory_1_panel.Content.FloatingSize = new Size(328, 470);
m_memory_2_panel = new Memory("Memory 2", m_processor, new Content(m_docking_manager));
m_docking_manager.Contents.Add(m_memory_2_panel.Content);
m_docking_manager.AddContentToZone(m_memory_2_panel.Content, wnd_content.ParentZone, 1);
m_docking_manager.ShowContent(m_memory_2_panel.Content);
m_memory_2_panel.Content.FloatingSize = new Size(328, 470);
m_memory_3_panel = new Memory("Memory 3", m_processor, new Content(m_docking_manager));
m_docking_manager.Contents.Add(m_memory_3_panel.Content);
//m_docking_manager.HideContent(m_memory_3_panel.Content);
m_memory_3_panel.Content.FloatingSize = new Size(328, 470);
//m_docking_manager.AddContentWithState(m_memory_3_panel.Content, State.Floating);
//m_docking_manager.ShowContent(m_memory_3_panel.Content);
m_memory_4_panel = new Memory("Memory 4", m_processor, new Content(m_docking_manager));
m_docking_manager.Contents.Add(m_memory_4_panel.Content);
//m_docking_manager.HideContent(m_memory_4_panel.Content);
m_memory_4_panel.Content.FloatingSize = new Size(328, 470);
//m_docking_manager.AddContentWithState(m_memory_4_panel.Content, State.Floating);
//m_docking_manager.AddContentToWindowContent(m_memory_4_panel.Content, wnd_content);
//m_docking_manager.ShowContent(m_memory_4_panel.Content);
// Panel rejestrów bankowych
m_bank_registers_panel = new BankRegisters("Bank Registers", m_processor, new Content(m_docking_manager));
m_docking_manager.Contents.Add(m_bank_registers_panel.Content);
m_bank_registers_panel.Content.DisplaySize = new Size(222, 142);
m_bank_registers_panel.Content.FloatingSize = new Size(232, 142);
m_docking_manager.AddContentWithState(m_bank_registers_panel.Content, State.DockRight);
m_docking_manager.ShowContent(m_bank_registers_panel.Content);
// Panel styków
m_pins_control_panel = new ExternalPinsControl("External Pins", m_processor, new Content(m_docking_manager));
m_docking_manager.Contents.Add(m_pins_control_panel.Content);
m_docking_manager.AddContentToZone(m_pins_control_panel.Content, m_bank_registers_panel.Content.ParentWindowContent.ParentZone, 1);
m_docking_manager.ShowContent(m_pins_control_panel.Content);
// Inicjalizujemy kontrolkę deasemblera
this.ToolBarContainer.ContentPanel.SuspendLayout();
m_disassembler = new Tiny8051.Controls.Disassembler(this);
m_disassembler.Dock = DockStyle.Fill;
this.ToolBarContainer.ContentPanel.Controls.Add(m_disassembler);
this.ToolBarContainer.ContentPanel.ResumeLayout(false);
// Inicjalizacja ui
Mnu_HighPrecision.Checked = m_debugger.HighPrecision;
//
UpdateUI();
}
private void OnToggleSFRRegistersPanel(object sender, EventArgs e)
{
if (Mnu_SFRRegisters.Checked)
m_docking_manager.ShowContent(m_sfr_registers_panel.Content);
else
m_docking_manager.HideContent(m_sfr_registers_panel.Content);
}
private void OnToggleBankRegistersPanel(object sender, EventArgs e)
{
if (Mnu_BankRegisters.Checked)
m_docking_manager.ShowContent(m_bank_registers_panel.Content);
else
m_docking_manager.HideContent(m_bank_registers_panel.Content);
}
private void OnToggleExternalPinsPanel(object sender, EventArgs e)
{
if (Mnu_ExternalPins.Checked)
m_docking_manager.ShowContent(m_pins_control_panel.Content);
else
m_docking_manager.HideContent(m_pins_control_panel.Content);
}
private void OnToggleMemory1Panel(object sender, EventArgs e)
{
if (Mnu_Memory1.Checked)
m_docking_manager.ShowContent(m_memory_1_panel.Content);
else
m_docking_manager.HideContent(m_memory_1_panel.Content);
}
private void OnToggleMemory2Panel(object sender, EventArgs e)
{
if (Mnu_Memory2.Checked)
m_docking_manager.ShowContent(m_memory_2_panel.Content);
else
m_docking_manager.HideContent(m_memory_2_panel.Content);
}
private void OnToggleMemory3Panel(object sender, EventArgs e)
{
if (Mnu_Memory3.Checked)
m_docking_manager.ShowContent(m_memory_3_panel.Content);
else
m_docking_manager.HideContent(m_memory_3_panel.Content);
}
private void OnToggleMemory4Panel(object sender, EventArgs e)
{
if (Mnu_Memory4.Checked)
m_docking_manager.ShowContent(m_memory_4_panel.Content);
else
m_docking_manager.HideContent(m_memory_4_panel.Content);
}
private void OnContentHidden(Content c, EventArgs cea)
{
OnContentShownOrHidden(c, false);
}
private void OnContentShown(Content c, EventArgs cea)
{
OnContentShownOrHidden(c, true);
}
private void OnContentShownOrHidden(Content c, bool shown)
{
if ((m_sfr_registers_panel != null) && (c == m_sfr_registers_panel.Content))
Mnu_SFRRegisters.Checked = shown;
if ((m_bank_registers_panel != null) && (c == m_bank_registers_panel.Content))
Mnu_BankRegisters.Checked = shown;
if ((m_pins_control_panel != null) && (c == m_pins_control_panel.Content))
Mnu_ExternalPins.Checked = shown;
if ((m_memory_1_panel != null) && (c == m_memory_1_panel.Content))
Mnu_Memory1.Checked = shown;
if ((m_memory_2_panel != null) && (c == m_memory_2_panel.Content))
Mnu_Memory2.Checked = shown;
if ((m_memory_3_panel != null) && (c == m_memory_3_panel.Content))
Mnu_Memory3.Checked = shown;
if ((m_memory_4_panel != null) && (c == m_memory_4_panel.Content))
Mnu_Memory4.Checked = shown;
}
private void UpdateStatus()
{
StatusBar.SuspendLayout();
switch (m_debugger.State)
{
default:
case Debugger.DebugerState.Stop:
Stat_Status.Text = "Stopped";
break;
case Debugger.DebugerState.RunWithBreakpoints:
Stat_Status.Text = "Running";
break;
case Debugger.DebugerState.RunWithoutBreakpoints:
Stat_Status.Text = "Running without debug";
break;
}
Stat_PC.Text = "PC: " + m_processor.PC.ToString("X4");
Stat_Cycles.Text = "Cycles: " + m_processor.Cycles;
Stat_Time.Text = "Time: ";/// + MakeUnit(m_processor.Cycles / m_debugger.Frequency, "0.####", "s");
double time = (double)(m_processor.Cycles / (m_debugger.Frequency / 12m));
if (time < 100e-6)
Stat_Time.Text += (time / 1e-6).ToString("0.##") + " us";
else if (time < 100e-3)
Stat_Time.Text += (time / 1e-3).ToString("0.##") + " ms";
else
Stat_Time.Text += (time / 1e-0).ToString("0.##") + " s";
Stat_Frequency.Text = "Frequency: ";
decimal frequency = m_debugger.Frequency / 12.0m;
if (frequency > 100e6m)
Stat_Frequency.Text += (frequency / 1e9m).ToString("0.##") + " GHz";
else if (frequency > 100e3m)
Stat_Frequency.Text += (frequency / 1e6m).ToString("0.##") + " MHz";
else if (frequency > 100e0m)
Stat_Frequency.Text += (frequency / 1e3m).ToString("0.##") + " kHz";
else if (frequency > 100e-3m)
Stat_Frequency.Text += (frequency / 1e0m).ToString("0.##") + " Hz";
else if (frequency > 100e-6m)
Stat_Frequency.Text += (frequency / 1e-3m).ToString("0.##") + " mHz";
else
Stat_Frequency.Text += (frequency / 1e-6m).ToString("0.##") + " uHz";
Stat_Precision.Text = (m_debugger.HighPrecision ? "High " : "Low ") + "precision";
StatusBar.ResumeLayout(true);
}
public void OnShowNextStatement(object sender, EventArgs e)
{
m_disassembler.ShowNextStatement();
UpdateStatus();
}
private void OnShowAddress(object sender, EventArgs e)
{
// Tworzymy i pokazujemy dialog
Dialogs.ShowAddressDialog dialog = new Tiny8051.Dialogs.ShowAddressDialog();
if (m_disassembler.SelectedAddress >= 0)
dialog.Address = (ushort)m_disassembler.SelectedAddress;
else
dialog.Address = 0;
DialogResult result = dialog.ShowDialog(this);
if (result == DialogResult.OK)
{
m_disassembler.ShowAddress(dialog.Address);
}
dialog.Dispose();
UpdateStatus();
}
private void OnExit(object sender, EventArgs e)
{
Close();
}
private void OnLoad(object sender, EventArgs e)
{
DialogResult result = Dlg_OpenFile.ShowDialog(this);
if (result != DialogResult.OK)
return;
LoadFile(Dlg_OpenFile.FileName);
}
private void LoadFile(string filename)
{
// Sprawdzamy istnienie pliku
if (!File.Exists(filename))
throw new Exception("File not exists!");
// Sprawdzamy typ pliku
string extension = System.IO.Path.GetExtension(filename);
switch (extension.ToUpper())
{
case ".HEX":
LoadHexFile(filename);
break;
default:
case ".BIN":
LoadBinFile(filename);
break;
}
//m_disassembler.UpdateView();
UpdateUI();
}
private void OnToggleHighPrecision(object sender, EventArgs e)
{
m_debugger.HighPrecision = Mnu_HighPrecision.Checked;
UpdateStatus();
}
private void OnFrequencyChange(object sender, EventArgs e)
{
// Tworzymy i pokazujemy dialog
Dialogs.FrequencyDialog dialog = new Tiny8051.Dialogs.FrequencyDialog();
dialog.Frequency = m_debugger.Frequency;
DialogResult result = dialog.ShowDialog(this);
if (result == DialogResult.OK)
{
m_debugger.Frequency = dialog.Frequency;
}
dialog.Dispose();
UpdateStatus();
}
private void OnPaint(object sender, PaintEventArgs e)
{
UpdateStatus();
}
private void OnStepInto(object sender, EventArgs e)
{
m_debugger.StepInto();
//m_disassembler.ShowAddress(m_processor.PC);
//UpdateStatus();
}
private void OnStepOver(object sender, EventArgs e)
{
m_debugger.StepOver();
//m_disassembler.ShowAddress(m_processor.PC);
//UpdateStatus();
}
private void OnStepOut(object sender, EventArgs e)
{
m_debugger.StepOut();
}
private void OnRestart(object sender, EventArgs e)
{
m_debugger.Restart();
m_disassembler.ShowAddress(m_processor.PC);
UpdateStatus();
}
private void OnClosed(object sender, FormClosedEventArgs e)
{
m_debugger.Close();
}
private void OnStartWithDebugging(object sender, EventArgs e)
{
m_debugger.RunWithDebugging();
}
private void OnStartWithoutDebugging(object sender, EventArgs e)
{
m_debugger.RunWithoutDebugging();
}
private void OnStop(object sender, EventArgs e)
{
m_debugger.Stop();
m_disassembler.ShowAddress(m_processor.PC);
UpdateStatus();
}
public void OnToggleBreakpoint(object sender, EventArgs e)
{
if (m_disassembler.IsAddressSelected)
m_debugger.ToggleBreakpoint((ushort)m_disassembler.SelectedAddress);
m_disassembler.UpdateView();
UpdateStatus();
}
public void OnDeleteAllBreakpoints(object sender, EventArgs e)
{
m_debugger.DeleteAllBreakpoints();
m_disassembler.UpdateView();
UpdateStatus();
}
public void OnRunToCursor(object sender, EventArgs e)
{
if (m_disassembler.IsAddressSelected)
m_debugger.RunToAddress((ushort)m_disassembler.SelectedAddress);
}
private void OnEnter(object sender, EventArgs e)
{
m_debugger.Suspend = true;
}
private void OnLeave(object sender, EventArgs e)
{
m_debugger.Suspend = false;
}
private delegate void ShowAddress(ushort address);
private delegate void UpdateStatusBar();
public void OnTick(object sender, Debugger.DebugerState state)
{
this.Invoke(new MethodInvoker(UpdateUI));
}
// Uaktualniam interfejs
public void UpdateUI()
{
if ((m_debugger.State != Debugger.DebugerState.RunWithBreakpoints
&& m_debugger.State != Debugger.DebugerState.RunWithoutBreakpoints) || Mnu_TrackDebugger.Checked)
m_disassembler.ShowAddress(m_processor.PC);
Application.DoEvents();
m_disassembler.UpdateView();
//m_sfr_registers_panel.Refresh();
//m_bank_registers_panel.Refresh();
//m_memory_1_panel.UpdateView();
//m_memory_2_panel.UpdateView();
//m_memory_3_panel.UpdateView();
//m_memory_4_panel.UpdateView();
UpdateStatus();
Refresh();
}
// Wczytuje wybrany plik do pamięci procesora
private void LoadHexFile(
string filename)
{
try
{
// Sprawdzamy istnienie pliku
if (!File.Exists(filename))
throw new Exception("File not exists!");
// Otwieramy plik do odczytu
StreamReader file = new StreamReader(filename);
// Bufor na informacje
int checksum = 0;
byte record_length;
ushort record_address;
byte record_type;
byte[] record_data = new byte[256];
// Odczytujemy kod
while (!file.EndOfStream)
{
// Wczytujemy linię
string line = file.ReadLine();
// Sprawdzamy poprawność
if (line.Length == 0 || line[0] != ':')
throw new Exception("Invalid file format!");
// Sprawdzamy wystąpienie końca pliku
if (line.CompareTo(":00000001FF") == 0)
break;
// Usuwamy pierwszy znak
line = line.Remove(0, 1);
// Zerujemy sumę kontrolną
checksum = 0;
// Długość rekordu
record_length = System.Convert.ToByte(line.Substring(0, 2), 16);
line = line.Remove(0, 2);
checksum += record_length;
// Adres
record_address = System.Convert.ToUInt16(line.Substring(0, 4), 16);
line = line.Remove(0, 4);
checksum += (record_address >> 8) & 0xFF;
checksum += record_address & 0xFF;
// Typ rekordu
record_type = System.Convert.ToByte(line.Substring(0, 2), 16);
line = line.Remove(0, 2);
checksum += record_type;
// Sprawdzamy rodzaj rekordu
if (record_type != 0)
throw new Exception("Unhandled record type!\nOnly data record is suppored.");
// Odczytujemy dane
for (int i = 0; i < record_length; i++)
{
record_data[i] = System.Convert.ToByte(line.Substring(0, 2), 16);
line = line.Remove(0, 2);
checksum += record_data[i];
}
// Obliczamy sumę kontrolną
checksum = (256 - (checksum % 256)) & 0xFF;
// Porównujemy sumę kontrolną
if (checksum != System.Convert.ToByte(line.Substring(0, 2), 16))
throw new Exception("Invalid checksum!");
// Wpisujemy kod do procesora
for (int i = 0; i < record_length; i++)
m_processor.Code[(ushort)(record_address + i)] = record_data[i];
}
// Zamykamy plik
file.Close();
}
catch (Exception e)
{
MessageBox.Show(e.Message);
}
}
// Wczytuje wybrany plik do pamięci procesora
private void LoadBinFile(
string filename)
{
try
{
// Sprawdzamy istnienie pliku
if (!File.Exists(filename))
throw new Exception("File not exists!");
FileStream file = File.Open(filename, FileMode.Open);
BinaryReader bin = new BinaryReader(file);
Dialogs.LoadBinaryDialog dialog = new Tiny8051.Dialogs.LoadBinaryDialog();
dialog.FileSize = (int)file.Length;
dialog.Processor = m_processor;
DialogResult result = dialog.ShowDialog(this);
if (result != DialogResult.OK)
return;
uint end_address = (uint)(dialog.DestAddress + file.Length);
if (end_address > dialog.DestMemory.Size)
end_address = (uint)dialog.DestMemory.Size;
for (uint i = dialog.DestAddress; i < end_address; i++)
dialog.DestMemory[(int)i] = bin.ReadByte();
bin.Close();
}
catch (Exception e)
{
MessageBox.Show(e.Message);
}
}
private void OnResetProcessor(object sender, EventArgs e)
{
if (MessageBox.Show("Are you sure?", "Reset Operation", MessageBoxButtons.YesNo) != DialogResult.Yes)
return;
for (int i = 0; i < m_processor.Code.Size; i++)
m_processor.Code[i] = 0;
for (int i = 0; i < m_processor.IData.Size; i++)
m_processor.IData[i] = 0;
for (int i = 0; i < m_processor.XData.Size; i++)
m_processor.XData[i] = 0;
OnRestart(sender, e);
}
private void OnFillMemory(object sender, EventArgs e)
{
// Tworzymy i pokazujemy dialog
Dialogs.FillMemoryDialog dialog = new Tiny8051.Dialogs.FillMemoryDialog();
DialogResult result = dialog.ShowDialog(this);
if (result == DialogResult.OK)
{
Tiny8051.Mcu8051.Mcu8051.MemoryAccessor memory;
switch (dialog.MemoryType)
{
case MemoryType.Code:
memory = m_processor.Code;
break;
case MemoryType.IData:
memory = m_processor.IData;
break;
case MemoryType.XData:
memory = m_processor.XData;
break;
default:
throw new Exception("Invalid memory type!");
}
for (int i = dialog.Start; i < dialog.FillSize; i++)
memory[i] = (byte)dialog.Filler;
}
dialog.Dispose();
UpdateUI();
}
private void OnMoveMemory(object sender, EventArgs e)
{
// Tworzymy i pokazujemy dialog
Dialogs.MoveMemoryDialog dialog = new Tiny8051.Dialogs.MoveMemoryDialog(m_processor);
dialog.ShowDialog(this);
dialog.Dispose();
UpdateUI();
}
private void OnAboutDialog(object sender, EventArgs e)
{
Dialogs.AboutDialog dialog = new Tiny8051.Dialogs.AboutDialog();
dialog.ShowDialog(this);
dialog.Dispose();
Refresh();
}
}
}