I’m making an attempt to recreate the DCPU-16 for Unity that has a console and might render the output to a TMPro textual content on a canvas. What the code ought to do is show A B C onto the TMPro textual content, however nothing seems. I’m fairly new to this and don’t fully perceive what I’m doing. For those who may also help me repair my code or give me some suggestions for studying extra about this, I might significantly respect it. If something is unclear, depart a remark and I’ll attempt to assist.
I made most of this code about 2 years in the past, so it is likely to be a little bit messy.
Right here is the DCPU-16:
utilizing System;
utilizing System.Collections.Generic;
utilizing UnityEngine;
public class DCPU16
{
// 8 Basic-Function Registers
public ushort[] Registers = new ushort[8]; // Renamed from 'registers' to 'Registers'
// 64K Phrases of Reminiscence
non-public ushort[] reminiscence = new ushort[0x10000]; // 64K = 2^16
// Particular Registers
non-public ushort pc = 0x0000; // Program Counter
non-public ushort sp = 0xFFFF; // Stack Pointer (begins at prime of reminiscence)
non-public ushort ex = 0x0000; // Further Register (overflow/underflow)
non-public ushort ia = 0x0000; // Interrupt Deal with (for interrupt dealing with)
// Interrupt Queue
non-public Queue interruptQueue = new Queue();
non-public bool interruptsEnabled = true;
// Strategies go right here...
public ushort ReadMemory(ushort tackle)
{
return reminiscence[address];
}
non-public void WriteMemory(ushort tackle, ushort worth)
{
reminiscence[address] = worth;
Debug.Log($"Reminiscence Write - Deal with: 0x{tackle:X4}, Worth: {(char)worth} (0x{worth:X4})");
}
public void LoadProgram(ushort[] program)
{
if (program.Size > reminiscence.Size)
{
throw new ArgumentException("Program exceeds out there reminiscence");
}
Array.Copy(program, reminiscence, program.Size);
pc = 0x0000; // Reset program counter to start out of program
}
non-public void ExecuteInstruction()
{
// Fetch instruction
ushort instruction = ReadMemory(pc++);
// Decode opcode and operands
ushort opcode = (ushort)(instruction & 0x1F); // Lowest 5 bits
ushort b = (ushort)((instruction >> 5) & 0x1F); // Center 5 bits
ushort a = (ushort)((instruction >> 10) & 0x3F); // Prime 6 bits
// Checks if the DCPU-16 is operating.
// Debug.Log($"PC: {pc}, Instruction: 0x{ReadMemory(pc):X4}");
// Execute primarily based on opcode
if (opcode == 0) // Particular opcodes
{
ExecuteSpecialInstruction(a, b);
}
else
{
ExecuteBasicInstruction(opcode, a, b);
}
if (instruction == 0x7F81) // Hypothetical HLT
{
Debug.Log("Program halted.");
return; // Exit execution loop
}
}
non-public void ExecuteBasicInstruction(ushort opcode, ushort a, ushort b)
{
ushort valueA = GetOperandValue(a);
ushort valueB = GetOperandValue(b); // Utilized in some directions
change (opcode)
{
case 0x01: // SET: b = a
Debug.Log($"SET: b = a. Setting Register[{b}] = {valueA}");
SetOperandValue(b, valueA);
break;
case 0x02: // ADD: b += a
ushort end result = (ushort)(valueB + valueA);
ex = (ushort)((valueB + valueA) > 0xFFFF ? 1 : 0); // Set EX for overflow
SetOperandValue(b, end result);
break;
case 0x03: // SUB: b -= a
end result = (ushort)(valueB - valueA);
ex = (ushort)((valueB > 16); // Retailer excessive bits in EX
SetOperandValue(b, end result);
break;
// Add different opcodes (DIV, MOD, SHL, SHR, AND, OR, XOR, and so on.)
default:
throw new InvalidOperationException($"Unknown opcode: {opcode}");
}
}
non-public void ExecuteSpecialInstruction(ushort a, ushort b)
{
change (a)
{
case 0x01: // JSR: Name subroutine
Push(pc); // Save present PC
pc = GetOperandValue(b); // Leap to handle
break;
// Add different particular opcodes
}
}
non-public void SetOperandValue(ushort code, ushort worth)
{
if (code -1 to 30)
}
non-public void QueueInterrupt(ushort message)
{
if (interruptsEnabled)
interruptQueue.Enqueue(message);
}
public interface IPeripheral
{
void HandleInterrupt(ushort message);
void Tick(); // Known as each CPU cycle (e.g., for clocks or timers)
}
public void Tick()
{
if (ia != 0) HandleInterrupts(); // Test for interrupts
ExecuteInstruction(); // Course of the subsequent instruction
}
non-public void HandleInterrupts()
{
if (interruptsEnabled && interruptQueue.Depend > 0)
{
ushort message = interruptQueue.Dequeue();
interruptsEnabled = false; // Disable nested interrupts
// Push present state onto the stack
Push(pc);
Push(Registers[0]); // Save register A (widespread conference)
// Leap to the interrupt tackle
pc = ia;
// Retailer the message in register A
Registers[0] = message;
}
}
non-public Record peripherals = new Record();
public void AddPeripheral(IPeripheral peripheral)
{
peripherals.Add(peripheral);
}
}
The DCPU-16 Supervisor:
utilizing TMPro; // Add this for TextMeshPro parts
utilizing UnityEngine;
public class DCPU16Manager : MonoBehaviour
{
non-public DCPU16 cpu;
non-public Console console;
public TextMeshProUGUI consoleText;
void Begin()
{
// Initialize the DCPU-16
cpu = new DCPU16();
// Initialize the Console peripheral
ushort consoleBaseAddress = 0x8000; // Instance tackle for console reminiscence
console = new Console(cpu, consoleBaseAddress, 32, 16); // 32x16 console
cpu.AddPeripheral(console);
// Connect console renderer
ConsoleRenderer renderer = gameObject.AddComponent();
renderer.console = console;
renderer.consoleText = consoleText;
// Load a demo program
// ushort[] program = {
// 0x7C01, 0x0041, // SET A, 'A' (ASCII for 'A')
// 0x7DE1, 0x8000, // SET [0x8000], A (Write 'A' to console reminiscence at 0x8000)
// 0x7C01, 0x0042, // SET A, 'B' (ASCII for 'B')
// 0x7DE1, 0x8001, // SET [0x8001], A (Write 'B' to console reminiscence at 0x8001)
// 0x7C01, 0x0043, // SET A, 'C' (ASCII for 'C')
// 0x7DE1, 0x8002, // SET [0x8002], A (Write 'C' to console reminiscence at 0x8002)
// 0x7F81, 0x0000 // HLT (hypothetical: halt CPU for simplicity)
// };
ushort[] program = {
0x7C01, 0x0041, // SET A, 'A' (ASCII for 'A')
0x7DE1, 0x8000, // SET [0x8000], A (Write 'A' to console reminiscence at 0x8000)
0x7F81, 0x0000 // HLT (halt)
};
cpu.LoadProgram(program);
}
void Replace()
{
// Run the DCPU-16 for just a few cycles per body
for (int i = 0; i
The console:
utilizing System.Collections.Generic; // Add this for Queue
utilizing UnityEngine;
public class Console : DCPU16.IPeripheral
{
non-public DCPU16 cpu;
non-public ushort baseAddress; // Beginning reminiscence tackle of the console
non-public int width;
non-public int top;
// Show Buffer (for Unity rendering)
non-public char[,] screenBuffer;
// Enter Queue (to ship characters to the DCPU-16)
non-public Queue inputQueue = new Queue();
public Console(DCPU16 cpu, ushort baseAddress, int width, int top)
{
this.cpu = cpu;
this.baseAddress = baseAddress;
this.width = width;
this.top = top;
this.screenBuffer = new char[height, width];
}
public void HandleInterrupt(ushort message)
{
if (message == 0x01) // Instance: Get a personality from the enter queue
{
if (inputQueue.Depend > 0)
{
ushort enter = inputQueue.Dequeue(); // Get the subsequent character
cpu.Registers[0] = enter; // Place the character in register A
}
else
{
cpu.Registers[0] = 0; // No enter out there
}
}
}
public void Tick()
{
Debug.Log("Console.Tick referred to as");
for (int y = 0; y '{(char)charCode}'");
}
}
}
public void AddInput(char c)
{
inputQueue.Enqueue((ushort)c);
}
public char[,] GetScreenBuffer()
{
return screenBuffer;
}
}
The Console Renderer
utilizing UnityEngine;
utilizing TMPro;
public class ConsoleRenderer : MonoBehaviour
{
public Console console; // Connect the Console peripheral
public TextMeshProUGUI consoleText; // TextMeshPro object for show
void Replace()
{
// Replace the console show
RenderConsole();
}
void RenderConsole()
{
Debug.Log("Rendering Console...");
if (console == null || consoleText == null) return;
char[,] buffer = console.GetScreenBuffer();
int width = buffer.GetLength(1);
int top = buffer.GetLength(0);
string consoleContent = "";
for (int y = 0; y
And keyboard enter.
utilizing UnityEngine;
public class KeyboardInput : MonoBehaviour
{
public Console console; // Connect the Console peripheral
void Replace()
{
foreach (char c in Enter.inputString)
{
console.AddInput(c); // Add typed character to the enter queue
}
}
}
I’ve carried out some debug strains, and most of them work as anticipated (i feel) The principle one which doesn’t work as anticipated is that this:
Debug.Log($"Console Content material:n{consoleContent}");
within the console renderer script. It ought to return ABC, however I’m undecided why it dosen’t.
I do imagine every little thing within the scene is ready up appropriately. It’s a largely empty scene with solely the beginning scene objects, a canvas containing the console textual content, and an empty GameObject with the DCPU16 Supervisor and Keyboard enter.
I couldn’t work out what else to take action I got here right here. If I ought to look someplace else, please inform me.