using System;


  

public class RAM
{
    public byte[] memory = new byte[256];
}

public class CPU
{
  
  // ALU OPERATIONS
  public byte ExecuteADD(byte regA, byte regB)
  {
    byte result = (byte)(regA + regB);
    
    if (result < regA) 
    {
        flagRegister |= (byte)flags.carry;
        Console.WriteLine("Carry flag set on");
    }
    else
    {
        flagRegister &= (byte)~flags.carry;
    }
    
    return result;
  }
  
  public void ExecuteSHL(byte regA, byte regB)
  {
    register[regB] = (byte)(register[regA] << 1);
    Console.WriteLine($"SHL Result: {register[regB]}");
  }
  
  public void ExecuteSHR(byte regA, byte regB)
  {
    register[regB] = (byte)(register[regA] >> 1);
    Console.WriteLine($"SHR Result: {register[regB]}");
  }
  
  public void ExecuteNOT(byte regA, byte regB)
  {
    register[regB] = (byte)(~regA);
    Console.WriteLine($"NOT Result: {register[regB]}");
  }
  
  public void ExecuteAND(byte regA, byte regB)
  {
    register[regB] = (byte)(regA & regB);
    Console.WriteLine($"AND Result: {register[regB]}");
  }
  
  public void ExecuteOR(byte regA, byte regB)
  {
    register[regB] = (byte)(regA | regB);
    Console.WriteLine($"OR Result: {register[regB]}");
  }
  
  public void ExecuteXOR(byte regA, byte regB)
  {
    register[regB] = (byte)(regA ^ regB);
    Console.WriteLine($"XOR Result: {register[regB]}");
  }
  
  public void ExecuteCMP(byte regA, byte regB)
  {
    flagRegister = 0;
    
    if (register[regA] > register[regB])
    {
      flagRegister = (byte)(flagRegister | (byte)flags.greaterThan);
      Console.WriteLine("greaterThan flag set on");
    }
    else if (register[regA] == register[regB])
    {
      flagRegister = (byte)(flagRegister | (byte)flags.equal);
      Console.WriteLine("equal flag set on");
    }
    else if (register[regA] < register[regB])
    {
      flagRegister = (byte)(flagRegister | (byte)flags.zero);
      Console.WriteLine("zero flag set on");
    }
  }
  
  
  //OTHER INSTRUCTIONS
  public void ExecuteLD(RAM ram, byte regA, byte regB)
  {
    register[regB] = ram.memory[register[regA]];
  }
  
  public void ExecuteST(RAM ram, byte regA, byte regB)
  {
    ram.memory[register[regA]] = register[regB];
  }
  
  public void ExecuteDATA(RAM ram, byte IR)
  {
    byte regB = (byte)(IR & 0b00000011);
    
    IAR++;
    
    byte data = ram.memory[IAR];
    register[regB] = data;
    
    
    Console.WriteLine($"Loaded {data} into register {regB}.");
  }
  
  public void ExecuteJMPR(byte regB)
  {
    IAR = register[regB];
  }
  
  public void ExecuteJMP(RAM ram, byte IR)
  {
    byte regB = (byte)(IR & 0b00000011);
    
    IAR++;
  
    IAR = ram.memory[regB];
    
    Console.WriteLine($"Jumping to address: {IAR}");
  }
  
  public void ExecuteJMPIF(byte flagBits, byte targetAddress)
  {
    flagRegister = flagBits;
    bool conditionMet = false;

    if ((flagBits & 0b1000) != 0 && (flagRegister & (byte)flags.carry) != 0) conditionMet = true;
    if ((flagBits & 0b0100) != 0 && (flagRegister & (byte)flags.greaterThan) != 0) conditionMet = true;
    if ((flagBits & 0b0010) != 0 && (flagRegister & (byte)flags.equal) != 0) conditionMet = true;
    if ((flagBits & 0b0001) != 0 && (flagRegister & (byte)flags.zero) != 0) conditionMet = true;

    if (conditionMet)
    {
        IAR = (byte)(targetAddress - 1); // -1 because the main loop will increment it after
        Console.WriteLine($"Condition met. Jumping to {targetAddress}");
    }
    else
    {
        Console.WriteLine("Condition not met, no jump.");
    }
  }

  
  public void ExecuteCLF()
  {
    flagRegister = 0;
  }

  public void ExecuteHALT()
  {
    running = false;
  }
  
  
  public byte[] register = new byte[4];
  public byte IAR;
  public byte IR;
  public byte MAR;
  public byte flagRegister;
  
  public enum flags : byte
  {
    carry = 0b1000,
    greaterThan = 0b0100,
    equal = 0b0010,
    zero = 0b0001
  }  
  public enum aluOp : byte
  {
    ADD = 0b000,
    SHL = 0b001,
    SHR = 0b010,
    NOT = 0b011,
    AND = 0b100,
    OR =  0b101,
    XOR = 0b110,
    CMP = 0b111
  }
  public enum instructions : byte
  {
    LD = 0b000,
    ST = 0b001,
    DATA = 0b010,
    JMPR = 0b011,
    JMP = 0b100,
    JMPIF = 0b101,
    CLF = 0b110,
    HALT = 0b111
  }
  
  bool running = true;
  
  public void Run(RAM ram)
  {
    
    while(running)
    {
    
      IR = ram.memory[IAR];
      
      bool isALU = (IR & 0b10000000) != 0;
      

    
      if (isALU)
      {
        byte aluOperation = (byte)((IR >> 4) & 0b00000111);
        byte regA = (byte)((IR >> 2) & 0b00000011);
        byte regB = (byte)(IR & 0b00000011);

      
        switch ((aluOp)aluOperation)
        {
          case aluOp.ADD:
            register[regB] = ExecuteADD(register[regA], register[regB]);
            Console.WriteLine($"ADD Result: {register[regB]}");
            break;
          case aluOp.SHL:
            ExecuteSHL(regA, regB);
            break;
          case aluOp.SHR:
            ExecuteSHR(regA, regB);
            break;
          case aluOp.NOT:
            ExecuteNOT(regA, regB);
            break;
          case aluOp.AND:
            ExecuteAND(regA, regB);
            break;
          case aluOp.OR:
            ExecuteOR(regA, regB);
            break;      
          case aluOp.XOR:
            ExecuteXOR(regA, regB);
            break;      
          case aluOp.CMP:
            ExecuteCMP(regA, regB);
            break;            
        }
      }
      else
      {
        byte instr = (byte)((IR >> 4) & 0b00000111);
        byte regA = (byte)((IR >> 2) & 0b00000011);
        byte regB = (byte)(IR & 0b00000011);

        switch ((instructions)instr)
        {
          case instructions.LD:
            ExecuteLD(ram, regA, regB);
            Console.WriteLine($"LD Result: {register[regB]}");
            break;
          case instructions.ST:
            ExecuteST(ram, regA, regB);
            Console.WriteLine($"ST Result: {ram.memory[regA]}");
            break;
          case instructions.DATA:
            ExecuteDATA(ram, IR);
            break;
          case instructions.JMPR:
            ExecuteJMPR(regB);
            Console.WriteLine($"Jumped to adress: {regB}");
            break;
          case instructions.JMP:
            ExecuteJMP(ram, IR);
            break;
          case instructions.JMPIF:
            byte flagBits = (byte)(IR & 0b00001111);  // Extract the 4 flag bits
            byte targetAddress = ram.memory[++IAR];   // Fetch the next byte as the address
            ExecuteJMPIF(flagBits, targetAddress);
            break;
          case instructions.CLF:
            ExecuteCLF();
            Console.WriteLine("Flags cleared");
            break;
          case instructions.HALT:
            ExecuteHALT();
            Console.WriteLine("CPU Halted");
            break;
        }
      }
      
      IAR++;
    }
  }
  
}

public class SimulateComputer
{
    public static void Main(string[] args)
    {
        RAM ram = new RAM();
        CPU cpu = new CPU();
        
        ram.memory[0] = 0b00100000;
        ram.memory[1] = 35;
        
        ram.memory[2] = 0b00100001;
        ram.memory[3] = 13;
        
        ram.memory[4] = 0b10000001;
        
        ram.memory[5] = 0b01110000;

        
        cpu.Run(ram);

    }
}
 
by

C Sharp Online Compiler

Write, Run & Share C# code online using OneCompiler's C# online compiler for free. It's one of the robust, feature-rich online compilers for C# language, running on the latest version 8.0. Getting started with the OneCompiler's C# compiler is simple and pretty fast. The editor shows sample boilerplate code when you choose language as C# and start coding.

Read inputs from stdin

OneCompiler's C# online compiler supports stdin and users can give inputs to programs using the STDIN textbox under the I/O tab. Following is a sample program which takes name as input and print your name with hello.

using System;
 
namespace Sample
{
  class Test
    {
      public static void Main(string[] args)
       {
         string name;
         name = Console.ReadLine();
         Console.WriteLine("Hello {0} ", name);
	}
     }
}

About C Sharp

C# is a general purpose object-oriented programming language by Microsoft. Though initially it was developed as part of .net but later it was approved by ECMA and ISO standards.

You can use C# to create variety of applications, like web, windows, mobile, console applications and much more using Visual studio.

Syntax help

Data types

Data TypeDescriptionRangesize
intTo store integers-2,147,483,648 to 2,147,483,6474 bytes
doubleto store large floating point numbers with decimalscan store 15 decimal digits8 bytes
floatto store floating point numbers with decimalscan store upto 7 decimal digits4 bytes
charto store single characters-2 bytes
stringto stores text-2 bytes per character
boolto stores either true or false-1 bit

Variables

Syntax

datatype variable-name = value;

Loops

1. If-Else:

When ever you want to perform a set of operations based on a condition or set of few conditions IF-ELSE is used.

if(conditional-expression) {
   // code
} 
else {
   // code
}

You can also use if-else for nested Ifs and If-Else-If ladder when multiple conditions are to be performed on a single variable.

2. Switch:

Switch is an alternative to If-Else-If ladder.

switch(conditional-expression) {    
case value1:    
 // code    
 break;  // optional  
case value2:    
 // code    
 break;  // optional  
...    
    
default:     
 // code to be executed when all the above cases are not matched;    
} 

3. For:

For loop is used to iterate a set of statements based on a condition.

for(Initialization; Condition; Increment/decrement) {
  // code  
} 

4. While:

While is also used to iterate a set of statements based on a condition. Usually while is preferred when number of iterations are not known in advance.

while(condition) {
 // code 
}

5. Do-While:

Do-while is also used to iterate a set of statements based on a condition. It is mostly used when you need to execute the statements atleast once.

do {
  // code 
} while (condition);

Arrays

Array is a collection of similar data which is stored in continuous memory addresses. Array values can be fetched using index. Index starts from 0 to size-1.

Syntax

data-type[] array-name;

Methods

Method is a set of statements which gets executed only when they are called. Call the method name in the main function to execute the method.

Syntax

static void method-name() 
{
  // code to be executed
}