Tuesday, January 7, 2025
spot_img

c# – How can I repair this show error with my customized DCPU-16 for Unity?


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.

Related Articles

LEAVE A REPLY

Please enter your comment!
Please enter your name here

- Advertisement -spot_img

Latest Articles