using System; using System.Collections.Generic; using System.Linq; using System.Windows.Forms; using static processor.Extensions; namespace processor { public partial class MainForm : Form { public MainForm() => InitializeComponent(); private void MainForm_Load(object sender, EventArgs e) { InitializeRamList(); InitializeCpu(); } private void InitializeRamList() { ramList.Items.Clear(); if (radHex.Checked is true) for (int i = 0; i < 256; i++) ramList.Items.Add($"{Convert.ToString(i, 16).PadLeft(2, '0').ToUpper()}: 00"); else for (int i = 0; i < 256; i++) ramList.Items.Add($"{Convert.ToString(i, 2).PadLeft(8, '0')}: 00000000"); } private void InitializeCpu() { if (radHex.Checked is true) { txtrInstReg.Text = @"0000"; txtProgCounter.Text = @"00"; for (int i = 0; i < 16; i++) Controls.Find($"txtr{i:x}", true)[0].Text = @"00"; } else { txtrInstReg.Text = @"00000000"; txtProgCounter.Text = @"00000000"; for (int i = 0; i < 16; i++) Controls.Find($"txtr{i:x}", true)[0].Text = @"00000000"; } } #region RAM /// /// Returns data as integers hold in addressed memory cell /// /// /// private int ReadRam(int address) => CnvRespectfully(ramList.Items[address].ToString().Split(':', StringSplitOptions.TrimEntries)[1]); /// /// Reads the amount of memory cells supplied in "count", starts reading from "address". 0 for count only reads addressed memory, 1 reads addressed and next cell /// /// /// /// private int ReadRam(int address, int count = 0) { string append = string.Empty; for (int i = 0; i <= count; i++) append += ramList.Items[address + i].ToString().Split(':', StringSplitOptions.TrimEntries)[1]; return CnvRespectfully(append); } /// /// Used by loader for writing hexadecimal/binary instructions /// /// /// private void LoadProgram(int address, string value) => ramList.Items[address] = $"{CnvRespectfully(address, 2, 8)}: {value}"; /// /// Write data to addressed memory cell /// /// /// private void WriteRam(int address, int value) => ramList.Items[address] = $"{CnvRespectfully(address, 2, 8)}: {CnvRespectfully(value, 2, 8)}"; #endregion #region Registers private int ReadRegister(int address) => CnvRespectfully(Controls.Find($"txtr{address:x}".ToLower(), true)[0].Text); private void WriteRegister(int address, int value) => Controls.Find($"txtr{address:x}".ToLower(), true)[0].Text = CnvRespectfully(value); private int ReadCounter() => CnvRespectfully(txtProgCounter.Text); private void SetCounter(int value) { txtProgCounter.Text = CnvRespectfully(value); SetInstRegister(ReadRam(ReadCounter(), 1)); } private int[] ReadInstRegister() { int[] r = { 0, 0, 0, 0 }; string[] a = radHex.Checked ? txtrInstReg.Text.Split1() : txtrInstReg.Text.Split4().ToArray(); for (int i = 0; i < 4; i++) r[i] = CnvRespectfully(a[i]); return r; } private void SetInstRegister(int value) => txtrInstReg.Text = CnvRespectfully(value, 4, 16); #endregion /// /// Converts integer to hexadecimal or binary representation in text according to selected view mode /// /// Integer value in decimal /// Left "0" padding to be applied for hexadecimal representation /// Left "0" padding to be applied for binary representation /// private string CnvRespectfully(int value, int hexPad = 2, int binPad = 8) => radHex.Checked ? Convert.ToString(value, 16).PadLeft(hexPad, '0').ToUpper() : Convert.ToString(value, 2).PadLeft(binPad, '0'); /// /// Converts hexadecimal or binary representation to integer according to selected view mode /// /// Hexadecimal or binary representation string /// private int CnvRespectfully(string value) => radHex.Checked ? Convert.ToInt32(value, 16) : Convert.ToInt32(value, 2); private string AppendOperand(int x, int y) => radHex.Checked ? CnvRespectfully((x * 16) + y, 2, 8) : CnvRespectfully(5, 2, 4) + CnvRespectfully(3, 2, 4); /// /// Parses and loads instructions to ramList /// private void btnLoad_Click(object sender, EventArgs e) { if (string.IsNullOrWhiteSpace(txtCode.Text)) return; // Next line reads content from txtCode, splits it into lines using '\n' as delimiter and casts the IEnumerable to List List inputLines = txtCode.Text.Split((char)10, StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries).ToList(); // Removes comments from lines, drops empty lines and sets instructionList to this new collection List instructionList = (from x in inputLines where !string.IsNullOrEmpty(RemoveComment(x)) select RemoveComment(x)).ToList(); List funcCode, ramCode; funcCode = (from x in instructionList where x.StartsWith("0x") select x).ToList(); ramCode = (from x in instructionList where x.StartsWith("1x") select x).ToList(); if (radHex.Checked is true) { LoadHexCode(funcCode); LoadHexCode(ramCode); } else { } } private void LoadHexCode(List codes) { codes = (from x in codes select RemoveLeading(x)).ToList(); int j = 0; for (int i = 0; i < codes.Count; i++) { string[] enm = codes[i].Split2().ToArray(); LoadProgram(j, enm[0]); LoadProgram(j+1, enm[1]); j += 2; } } private void btnClear_Click(object sender, EventArgs e) => InitializeRamList(); private void btnStart_Click(object sender, EventArgs e) { btnStep.Enabled = false; btnClear.Enabled = false; btnStart.Enabled = false; do { Execute(); } while (_status is not CpuStatus.Stopped); } private CpuStatus _status = CpuStatus.Stopped; private void btnStep_Click(object sender, EventArgs e) => Execute(); private void Execute() { if (ReadInstRegister()[0] is 12) // Do not run method if instruction is 0xC - halt opcode { MessageBox.Show($"Reached end of execution: \ninstruction 0x{txtrInstReg.Text} at 0x{CnvRespectfully(ReadCounter())} prevents execution!", "Vole Runtime"); SetStatus(CpuStatus.Stopped); return; } int counter = ReadCounter(); if (_status is CpuStatus.Running) // This check is useful to determine if the execution has just started or was already running SetCounter(counter + 2); else SetCounter(counter); SetStatus(CpuStatus.Running); int[] fields = ReadInstRegister(); ResolveOpcode(fields[0], fields[1], fields[2], fields[3]); } private void SetStatus(CpuStatus status) { _status = status; lblStatus.Text = $"Status: {status}"; if (status is CpuStatus.Stopped) // Retrieve disabled controls { btnClear.Enabled = true; btnStart.Enabled = true; btnStep.Enabled = true; } } } }