mirror of
https://github.com/livingcomputermuseum/ContrAlto.git
synced 2026-02-23 07:32:39 +00:00
Built basic debugger UI and execution framework; a few bugfixes. CPU now executes uCode up until the first STARTF (unimplemented).
This commit is contained in:
347
Contralto/Debugger.cs
Normal file
347
Contralto/Debugger.cs
Normal file
@@ -0,0 +1,347 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Data;
|
||||
using System.Drawing;
|
||||
using System.Linq;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using System.Windows.Forms;
|
||||
|
||||
using Contralto.CPU;
|
||||
|
||||
namespace Contralto
|
||||
{
|
||||
public partial class Debugger : Form
|
||||
{
|
||||
public Debugger(AltoSystem system)
|
||||
{
|
||||
_system = system;
|
||||
|
||||
InitializeComponent();
|
||||
InitControls();
|
||||
RefreshUI();
|
||||
}
|
||||
|
||||
public void LoadSourceCode(string path)
|
||||
{
|
||||
if (path == null)
|
||||
{
|
||||
throw new ArgumentNullException(path, "Microcode path must be specified.");
|
||||
}
|
||||
|
||||
StreamReader sr = new StreamReader(path);
|
||||
|
||||
while(!sr.EndOfStream)
|
||||
{
|
||||
string line = sr.ReadLine();
|
||||
|
||||
SourceLine src = new SourceLine(line);
|
||||
|
||||
int i = _sourceViewer.Rows.Add(
|
||||
GetTextForTask(src.Task),
|
||||
src.Address,
|
||||
src.Text);
|
||||
|
||||
// Give the row a color based on the task
|
||||
_sourceViewer.Rows[i].DefaultCellStyle.BackColor = GetColorForTask(src.Task);
|
||||
|
||||
// Tag the row based on the PROM address (if any) to make it easy to find.
|
||||
if (!String.IsNullOrEmpty(src.Address))
|
||||
{
|
||||
_sourceViewer.Rows[i].Tag = Convert.ToUInt16(src.Address, 8);
|
||||
}
|
||||
}
|
||||
|
||||
// Ensure the UI view gets refreshed to display the current MPC source
|
||||
Refresh();
|
||||
}
|
||||
|
||||
public override void Refresh()
|
||||
{
|
||||
base.Refresh();
|
||||
|
||||
RefreshUI();
|
||||
}
|
||||
|
||||
private void RefreshUI()
|
||||
{
|
||||
// Registers
|
||||
for(int i=0;i<32;i++)
|
||||
{
|
||||
_registerData.Rows[i].Cells[0].Value = OctalHelpers.ToOctal(i,2);
|
||||
_registerData.Rows[i].Cells[1].Value = OctalHelpers.ToOctal(_system.CPU.R[i], 6);
|
||||
_registerData.Rows[i].Cells[2].Value = OctalHelpers.ToOctal(_system.CPU.S[0][i], 6);
|
||||
}
|
||||
|
||||
// Tasks
|
||||
for (int i=0;i<16;i++)
|
||||
{
|
||||
_taskData.Rows[i].Cells[0].Value = GetTextForTask((TaskType)i);
|
||||
_taskData.Rows[i].Cells[1].Value = GetTextForTaskState(_system.CPU.Tasks[i]);
|
||||
_taskData.Rows[i].Cells[2].Value =
|
||||
_system.CPU.Tasks[i] != null ? OctalHelpers.ToOctal(_system.CPU.Tasks[i].MPC, 4) : String.Empty;
|
||||
}
|
||||
|
||||
// Other registers
|
||||
_otherRegs.Rows[0].Cells[1].Value = OctalHelpers.ToOctal(_system.CPU.L, 6);
|
||||
_otherRegs.Rows[1].Cells[1].Value = OctalHelpers.ToOctal(_system.CPU.T, 6);
|
||||
_otherRegs.Rows[2].Cells[1].Value = OctalHelpers.ToOctal(_system.CPU.M, 6);
|
||||
_otherRegs.Rows[3].Cells[1].Value = OctalHelpers.ToOctal(_system.CPU.IR, 6);
|
||||
_otherRegs.Rows[4].Cells[1].Value = OctalHelpers.ToOctal(_system.CPU.ALUC0, 1);
|
||||
_otherRegs.Rows[5].Cells[1].Value = OctalHelpers.ToOctal(_system.MemoryBus.MAR, 6);
|
||||
_otherRegs.Rows[6].Cells[1].Value = OctalHelpers.ToOctal(_system.MemoryBus.MD, 6);
|
||||
_otherRegs.Rows[7].Cells[1].Value = OctalHelpers.ToOctal(_system.MemoryBus.Cycle, 2);
|
||||
|
||||
// Find the right source line
|
||||
foreach(DataGridViewRow row in _sourceViewer.Rows)
|
||||
{
|
||||
if (row.Tag != null &&
|
||||
(ushort)(row.Tag) == _system.CPU.CurrentTask.MPC)
|
||||
{
|
||||
_sourceViewer.ClearSelection();
|
||||
row.Selected = true;
|
||||
_sourceViewer.CurrentCell = row.Cells[0];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void InitControls()
|
||||
{
|
||||
for (int i = 0; i < 32; i++)
|
||||
{
|
||||
_registerData.Rows.Add(-1, -1 ,-1);
|
||||
}
|
||||
|
||||
for (int i = 0; i < 16; i++)
|
||||
{
|
||||
_taskData.Rows.Add("0", "0", "0");
|
||||
}
|
||||
|
||||
/*
|
||||
for (int i=0;i<65536;i++)
|
||||
{
|
||||
_memoryData.Rows.Add();
|
||||
} */
|
||||
|
||||
_otherRegs.Rows.Add("L", "0");
|
||||
_otherRegs.Rows.Add("T", "0");
|
||||
_otherRegs.Rows.Add("M", "0");
|
||||
_otherRegs.Rows.Add("IR", "0");
|
||||
_otherRegs.Rows.Add("ALUC0", "0");
|
||||
_otherRegs.Rows.Add("MAR", "0");
|
||||
_otherRegs.Rows.Add("MD", "0");
|
||||
_otherRegs.Rows.Add("MCycle", "0");
|
||||
}
|
||||
|
||||
private void dataGridView1_CellContentClick(object sender, DataGridViewCellEventArgs e)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
private string GetTextForTaskState(AltoCPU.Task task)
|
||||
{
|
||||
if (task == null)
|
||||
{
|
||||
return String.Empty;
|
||||
}
|
||||
else
|
||||
{
|
||||
// TODO: block status
|
||||
return task.Wakeup ? "W" : String.Empty;
|
||||
}
|
||||
}
|
||||
|
||||
private string GetTextForTask(TaskType task)
|
||||
{
|
||||
string[] taskText =
|
||||
{
|
||||
"EM", // 0 - emulator
|
||||
String.Empty,
|
||||
String.Empty,
|
||||
String.Empty,
|
||||
"KS", // 4 - disk sector
|
||||
String.Empty,
|
||||
String.Empty,
|
||||
"EN", // 7 - ethernet
|
||||
"MR", // 8 - memory refresh
|
||||
"DW", // 9 - display word
|
||||
"CU", // 10 - cursor
|
||||
"DH", // 11 - display horizontal
|
||||
"DV", // 12 - display vertical
|
||||
"PA", // 13 - parity
|
||||
"KW", // 14 - disk word
|
||||
String.Empty,
|
||||
};
|
||||
|
||||
if (task == TaskType.Invalid)
|
||||
{
|
||||
return String.Empty;
|
||||
}
|
||||
else
|
||||
{
|
||||
return taskText[(int)task];
|
||||
}
|
||||
}
|
||||
|
||||
private Color GetColorForTask(TaskType task)
|
||||
{
|
||||
Color[] taskColors =
|
||||
{
|
||||
Color.LightBlue, // 0 - emulator
|
||||
Color.LightGray, // 1 - unused
|
||||
Color.LightGray, // 2 - unused
|
||||
Color.LightGray, // 3 - unused
|
||||
Color.LightGreen, // 4 - disk sector
|
||||
Color.LightGray, // 5 - unused
|
||||
Color.LightGray, // 6 - unused
|
||||
Color.LightSalmon, // 7 - ethernet
|
||||
Color.LightSeaGreen,// 8 - memory refresh
|
||||
Color.LightYellow, // 9 - display word
|
||||
Color.LightPink, // 10 - cursor
|
||||
Color.LightGoldenrodYellow, // 11 - display horizontal
|
||||
Color.LightCoral, // 12 - display vertical
|
||||
Color.LightSteelBlue, // 13 - parity
|
||||
Color.Gray, // 14 - disk word
|
||||
Color.LightGray, // 15 - unused
|
||||
};
|
||||
|
||||
if (task == TaskType.Invalid)
|
||||
{
|
||||
return Color.White;
|
||||
}
|
||||
else
|
||||
{
|
||||
return taskColors[(int)task];
|
||||
}
|
||||
}
|
||||
|
||||
private struct SourceLine
|
||||
{
|
||||
public SourceLine(string sourceText)
|
||||
{
|
||||
//
|
||||
// Mangle "<-" found in the source into the unicode arrow character, just to be neat.
|
||||
//
|
||||
sourceText = sourceText.Replace("<-", _arrowChar.ToString());
|
||||
|
||||
// See if line begins with something of the form "TNxxxxx>".
|
||||
// If it does then we have extra metadata to parse out.
|
||||
string[] tokens = sourceText.Split(new char[] { ' ', '\t' }, StringSplitOptions.RemoveEmptyEntries);
|
||||
|
||||
bool annotated = false;
|
||||
|
||||
// Make the compiler happy
|
||||
Text = sourceText;
|
||||
Address = String.Empty;
|
||||
Task = TaskType.Invalid;
|
||||
|
||||
if (tokens.Length > 0 &&
|
||||
tokens[0].Length == 8 &&
|
||||
tokens[0].EndsWith(">"))
|
||||
{
|
||||
// Close enough. Look for the task tag and parse out the (octal) address
|
||||
switch(tokens[0].Substring(0,2))
|
||||
{
|
||||
case "EM":
|
||||
Task = TaskType.Emulator;
|
||||
break;
|
||||
|
||||
case "SE":
|
||||
Task = TaskType.DiskSector;
|
||||
break;
|
||||
|
||||
case "EN":
|
||||
Task = TaskType.Emulator;
|
||||
break;
|
||||
|
||||
case "MR":
|
||||
Task = TaskType.MemoryRefresh;
|
||||
break;
|
||||
|
||||
case "DW":
|
||||
Task = TaskType.DisplayWord;
|
||||
break;
|
||||
|
||||
case "CU":
|
||||
Task = TaskType.Cursor;
|
||||
break;
|
||||
|
||||
case "DH":
|
||||
Task = TaskType.DisplayHorizontal;
|
||||
break;
|
||||
|
||||
case "DV":
|
||||
Task = TaskType.DisplayVertical;
|
||||
break;
|
||||
|
||||
case "PA":
|
||||
Task = TaskType.Parity;
|
||||
break;
|
||||
|
||||
case "KW":
|
||||
Task = TaskType.DiskWord;
|
||||
break;
|
||||
|
||||
default:
|
||||
Task = TaskType.Invalid;
|
||||
break;
|
||||
}
|
||||
|
||||
if (Task != TaskType.Invalid)
|
||||
{
|
||||
try
|
||||
{
|
||||
// Belongs to a task, so we can grab the address out as well
|
||||
Address = sourceText.Substring(2, 5);
|
||||
}
|
||||
catch
|
||||
{
|
||||
// That didn't work for whatever reason, just treat this as a normal source line.
|
||||
annotated = false;
|
||||
}
|
||||
|
||||
Text = sourceText.Substring(tokens[0].Length + 1, sourceText.Length - tokens[0].Length -1);
|
||||
annotated = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
// We will just display this as a non-source line
|
||||
annotated = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (!annotated)
|
||||
{
|
||||
Text = sourceText;
|
||||
Address = String.Empty;
|
||||
Task = TaskType.Invalid;
|
||||
}
|
||||
}
|
||||
|
||||
public string Text;
|
||||
public string Address;
|
||||
public TaskType Task;
|
||||
|
||||
}
|
||||
|
||||
private void Debugger_Load(object sender, EventArgs e)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
private void OnStepButtonClicked(object sender, EventArgs e)
|
||||
{
|
||||
_system.SingleStep();
|
||||
Refresh();
|
||||
}
|
||||
|
||||
private AltoSystem _system;
|
||||
|
||||
// Unicode character for the Arrow used by Alto microcode
|
||||
private const char _arrowChar = (char)0x2190;
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user