Hallo,
habe gerade wieder dieses "Projekt" in meinem Projektordner gefunden. Es ist schon über ein Jahr alt, und da dachte ich mir das es hier vieleicht jemanden interessieren könnte.
Damals habe ich mir Gedanken darüber gemacht, wie ich eine CPU-Simulator implementieren würde.
Erwartet nichts grosses, die CPU die im Moment simuliert wird hat einen Speicher von 255 Byte welcher intern als byte[] dargestellt wird. Es sind zwei 8-Bit Register (a und b) verfügbar. Ansonsten kann man nur Werte aus dem Speicher in die Register laden, einen Sprung ausführen (0x01), sowie die CPU stoppen (0xFF).
Desweiteren ist die Simulation der dauer von Maschienenzyklen vorgesehen (Cycling(int))
aber noch nicht implementiert.
Dieser Quelltext ist wirklich nur ein Dump aus meinem Gehirn d.h ich habe nicht besonders auf gutes Design geachtet.
Das Programm das ausgeführt werden soll ist in der Methode ProgramInit() in Form einer Array-Zuweisung "hart kodiert."
Benutzen könnt ihr die Klasse wie folgt:
Console.WriteLine("PC\tOPCODE\t \tDESC");
Console.WriteLine("**\t******\t*\t****");
cpu Test = new cpu();
Test.ProgInit(); //Programm in Speicher laden
Test.Run(); //CPU starten
Hier der eigentliche Simulator:
/* Proof of Concept: Very Basic CPU simulation in C#
*/
using System;
namespace TestEmu
{
/* Machine Data:
*
*
* Memory: 255 Bytes flat adressed
* Registers: 2 8-Bit registers
*
* Implemented Opcodes:
*
* 0x01 Unconditional jump (Size 2 Bytes (OpCode,Target Adress)
* 0x02 Move value to register a (Size 2 Bytes Byte1=OpCode, Byte2=Value)
* 0x03 Move value to register b (Size 2 Bytes Byte1=OpCode, Byte2=Value)
* 0xFF Shutdown CPU
*
*/
class cpu
{
//Basics (Emulation)
byte[] Memory = new byte[255]; //Memory
byte PC = 0x0; //Program Counter
byte OpCode = 0x0; //Current Opcode
//Controles
bool CPURun = true; //Cpu runs while this is true
#region Testprogram
/// <summary>
/// Program for the simulator is hardcoded here.
/// Call this to load the program in to the memory-array
/// </summary>
public void ProgInit()
{
//Copy 24 to register A, jump to Adress 0x45
//Copy 58 to register B then halt CPU
Memory[0x00] = 0x00;
Memory[0x01] = 0x02; //Copy to A
Memory[0x02] = 0x18; //DEZ:24
Memory[0x03] = 0x01; //Jump command
Memory[0x04] = 0x45; //Jump adress
//****
Memory[0x45] = 0x00;
Memory[0x46] = 0x03; //Copy to b
Memory[0x47] = 0x3A; //DATA (Value);
Memory[0x48] = 0xFF; //HALT
}
#endregion
#region Registers
byte a = 0; //Register A
byte b = 0; //Register B
byte aku = 0; //Akkumulator
#endregion
public void Run()
{
while (CPURun)
{
Fetch(); //Fetch Next Instruction
Execute(); //Execute it
PC++; //Inkrement Programcounter to next Memory Adress
}
}
/// <summary>
/// Execute Cycle
/// </summary>
/// <param name="cycles">Number of Cycles</param>
void Cycling(int cycles)
{
//Implements one machine cycle here ;)
//Do Cyclic Tasks here, (Interrupt Handling, Screenrefresh...)
}
/// <summary>
/// Execute OpCode
/// </summary>
void Execute()
{
switch (OpCode)
{
case 0x0:
{
//Do Nothing (NOP)
DebugWrite(0x0,"NOP");
Cycling(1); //Cycling Action (Screen Refresh, Int Handling etc.)
break;
}
case 0x1:
{
//Jump to
PC = Memory[PC+1]; //Get Adress from Second Byte
DebugWrite(0x1,"JMP");
Cycling(1); //Cycling Action (Screen Refresh, Int Handling etc.)
break;
}
case 0x2:
{
//Move Value to A
PC++;
a = Memory[PC];
Cycling(1); //Cycling Action (Screen Refresh, Int Handling etc.)
DebugWrite(0x2, "Move "+PC+1+" to Register A");
break;
}
case 0x3:
{
//Move Value to B
PC++;
b = Memory[PC];
Cycling(1); //Cycling Action (Screen Refresh, Int Handling etc.)
DebugWrite(0x2, "Move " + PC + 1 + " to Register B");
break;
}
case 0xFF:
{
//Shutdown Processor
CPURun = false;
Cycling(1); //Cycling Action (Screen Refresh, Int Handling etc.)
DebugWrite(0xFF, "HALT");
break;
}
}
}
/// <summary>
/// Fetch next OpCode
/// </summary>
void Fetch()
{
OpCode = Memory[PC]; //Get OpCode from PC Adress
}
/// <summary>
/// Write Debug Message to Console
/// </summary>
/// <param name="Adress">Adress</param>
/// <param name="Message">Message</param>
void DebugWrite(byte Adress,string Message)
{
const string DEBUG_OUT = "0x{0:X2}\t:\t{1}";
Console.WriteLine("@"+PC+"\t"+DEBUG_OUT,Adress,Message);
}
}
}
Viel Spass 😉