using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Reflection;
namespace Sloth
{
public class RuntimeException : Exception
{
public RuntimeException(String message) : base(message) { }
}
[Flags()]
public enum StatusFlags
{
Positive = 1,
Negative = 2,
Zero = 4,
Overflow = 8,
Carry = 16
}
public class VirtualMemory : IDisposable
{
private BinaryReader memoryReader;
private BinaryWriter memoryWriter;
private MemoryStream memoryStream;
public Boolean IsDisposed { get; set; }
public Int64 Capacity
{
get { return memoryStream.Length; }
}
public Int64 Position
{
get { return memoryStream.Position; }
}
public VirtualMemory(Int32 size)
{
this.
memoryStream = new MemoryStream
(new Byte[size
]);
this.
memoryReader = new BinaryReader
(memoryStream
);
this.
memoryWriter = new BinaryWriter
(memoryStream
);
this.memoryStream.Position = 0;
}
public Int32 ReadValue(Int32 address, Byte size)
{
this.memoryStream.Position = address;
if (size == 32)
return memoryReader.ReadInt32();
if (size == 16)
return memoryReader.ReadInt16();
return memoryReader.ReadByte();
}
public void WriteValue(Int32 address, Int32 value, Byte size)
{
this.memoryStream.Position = address;
if (size == 32)
memoryWriter.Write(value);
else if (size == 16)
memoryWriter.Write((Int16)(value & 0xFFFF));
else
memoryWriter.Write((Byte)(value & 0xFF));
}
public void WriteStream(Int32 address, Stream source)
{
memoryStream.Position = address;
source.Position = 0;
source.CopyTo(memoryStream);
}
public void Malloc(Int32 sizeInBytes)
{
this.memoryStream.Position += sizeInBytes;
}
public void Clear()
{
this.memoryStream.Position = 0;
for (Int32 i = 0; i < memoryStream.Length; i++)
memoryStream.WriteByte(0);
this.memoryStream.Position = 0;
}
public Byte[] ToByteArray()
{
Byte[] buffer
= new Byte[memoryStream.
Capacity];
Int64 position = memoryStream.Position;
memoryStream.Position = 0;
memoryStream.Read(buffer, 0, buffer.Length);
memoryStream.Position = position;
return buffer;
}
public void Dispose()
{
if (!this.IsDisposed)
{
memoryStream.Close();
memoryStream = null;
memoryWriter = null;
memoryReader = null;
this.IsDisposed = true;
}
}
}
public class InstructionImplementationAttribute : Attribute
{
public List<String> Synonims { get; private set; }
public InstructionImplementationAttribute()
{
this.
Synonims = new List
<String>();
}
public InstructionImplementationAttribute(params String[] synonims) : this()
{
this.Synonims.AddRange(synonims);
}
}
public class ExecutionEventArgs : EventArgs
{
public Boolean Suspend { get; set; }
}
public class StringOutputEventArgs : EventArgs
{
public String Message { get; private set; }
public StringOutputEventArgs(String message)
{
this.Message = message;
}
}
public class NumberInputEventArgs : EventArgs
{
public Int32 Value { get; set; }
}
public class StringInputEventArgs : EventArgs
{
public String Value { get; set; }
}
public class Emulator
{
private delegate void ExecuteInstruction();
private Boolean executionSuspended = false;
public event EventHandler<ExecutionEventArgs> Step;
public event EventHandler ExecutionFinished;
public event EventHandler<StringOutputEventArgs> Output;
public event EventHandler<StringInputEventArgs> StringNeeded;
public event EventHandler<NumberInputEventArgs> NumberNeeded;
private AssemblyProgram program;
private CompiledInstruction currentInstruction;
private Dictionary<Int16, ExecuteInstruction> implementedFunctions;
public Dictionary<String, Int32> Registers { get; private set; }
public Boolean IsRunning { get; private set; }
public VirtualMemory Memory { get; set; }
public Boolean RaiseStepEvent { get; set; }
public CompiledInstruction CurrentInstruction
{
get { return currentInstruction; }
}
public AssemblyProgram CurrentProgram
{
get { return program; }
}
public StatusFlags StatusRegister
{
get { return (StatusFlags)this.Registers["SR"]; }
set { this.Registers["SR"] = (Int32)value; }
}
public Int32 StackPointer
{
get { return this.Registers["A7"]; }
set { this.Registers["A7"] = value; }
}
public Int32 ProgramCounter
{
get { return this.Registers["PC"]; }
set { this.Registers["PC"] = value; }
}
public Int32 FramePointer
{
get { return this.Registers["A6"]; }
set { this.Registers["A6"] = value; }
}
public Emulator(Int32 memorySize)
{
this.
Registers = new Dictionary
<String, Int32
>();
this.
Memory = new VirtualMemory
(memorySize
);
for (Int32 i = 0; i < 8; i++)
{
this.Registers.Add("A" + i.ToString(), 0);
this.Registers.Add("D" + i.ToString(), 0);
}
this.Registers.Add("SR", 0);
this.Registers.Add("PC", 0);
implementedFunctions
= new Dictionary
<Int16, ExecuteInstruction
>();
foreach (var binding in
from method
in typeof(Emulator
).
GetMethods(BindingFlags.
NonPublic | BindingFlags.
Instance)
let attributes
= method.
GetCustomAttributes(typeof(InstructionImplementationAttribute
),
false)
where attributes.Count() > 0
let attribute = (InstructionImplementationAttribute)attributes.First()
let implementation
= new ExecuteInstruction
(delegate() { method.
Invoke(this,
null); })
select
new { MethodNames
= attribute.
Synonims.
Count > 0
? attribute.
Synonims : (new List
<String>() { method.
Name }), Implementation
= implementation
})
{
foreach (String name in binding.MethodNames)
implementedFunctions.Add(name.GetHashCode16(), binding.Implementation);
}
}
public void Load(AssemblyProgram program)
{
this.program = program;
this.Memory.WriteStream(0, program.Binary);
}
public void Run()
{
if (program == null)
throw new RuntimeException
("Nessun programma caricato in memoria.");
this.Reset();
this.Resume();
}
public void Reset()
{
foreach (String key in this.Registers.Keys.ToList())
this.Registers[key] = 0;
this.StackPointer = (Int32)this.Memory.Capacity;
if (program != null)
if (program.Instructions.Count > 0)
this.ProgramCounter = program.Instructions.Keys.Min();
else
this.ProgramCounter = 0;
}
public void Resume()
{
this.IsRunning = true;
executionSuspended = false;
while (!executionSuspended && this.Fetch())
this.DecodeAndExecute();
this.IsRunning = false;
}
public void Stop()
{
executionSuspended = true;
}
private Boolean Fetch()
{
try
{
currentInstruction = program.Instructions[this.ProgramCounter];
this.ProgramCounter += currentInstruction.BinarySize; ;
return true;
}
catch
{
this.OnExecutionFinished();
return false;
}
}
private void DecodeAndExecute()
{
try
{
var implementation = implementedFunctions.Single(pair => pair.Key == currentInstruction.OpCode).Value;
implementation.Invoke();
this.OnStep();
}
catch
{
throw new RuntimeException
(String.
Format("Non è presente alcuna implementazione per l'istruzione 0x{0:X4} (offset 0x{1:X8}).", currentInstruction.
OpCode,
this.
ProgramCounter - currentInstruction.
BinarySize));
}
}
protected void OnStep()
{
if ((Step != null) && this.RaiseStepEvent)
{
ExecutionEventArgs e
= new ExecutionEventArgs
();
e.Suspend = false;
Step(this, e);
if (e.Suspend)
executionSuspended = true;
}
}
protected void OnExecutionFinished()
{
this.ProgramCounter = program.Instructions.Keys.Min();
if (ExecutionFinished != null)
ExecutionFinished(this, EventArgs.Empty);
}
protected void OnOutput(String message)
{
if (Output != null)
Output
(this,
new StringOutputEventArgs
(message
));
}
protected void OnNumberNeeded()
{
if (NumberNeeded != null)
{
NumberInputEventArgs e
= new NumberInputEventArgs
();
NumberNeeded(this, e);
this.Memory.WriteValue(this.Registers["A0"], e.Value, currentInstruction.Size);
}
}
protected void OnStringNeeded()
{
if (StringNeeded != null)
{
StringInputEventArgs e
= new StringInputEventArgs
();
StringNeeded(this, e);
for (Int32 i = 0; i < e.Value.Length; i++)
this.Memory.WriteValue(this.Registers["A0"] + i, (Byte)e.Value[i], 8);
this.Memory.WriteValue(this.Registers["A0"] + e.Value.Length, 0, 8);
}
}
private Int32 GetOperandValue(CompiledOperand operand, Byte size)
{
if (operand.Mode.HasFlag(AddressingModes.Immediate) || operand.Mode.HasFlag(AddressingModes.ImmediateLabel))
return operand.Value;
if (operand.Mode.HasFlag(AddressingModes.DirectRegister))
return this.Registers[operand.GetRegister()];
if (operand.Mode.HasFlag(AddressingModes.Absolute) || operand.Mode.HasFlag(AddressingModes.AbsoluteLabel))
return this.Memory.ReadValue(operand.Value, size);
// > IndirectRegister
Int32 offset = 0, value;
if (operand.Mode.HasFlag(AddressingModes.Offset))
offset += operand.GetOffset();
if (operand.Mode.HasFlag(AddressingModes.Base))
offset += this.Registers[operand.GetBaseRegister()];
String regName = operand.GetRegister();
if (operand.Mode.HasFlag(AddressingModes.PreDecrement))
this.Registers[regName]--;
else if (operand.Mode.HasFlag(AddressingModes.PreIncrement))
this.Registers[regName]++;
value = this.Memory.ReadValue(this.Registers[regName] + offset, size);
if (operand.Mode.HasFlag(AddressingModes.PostDecrement))
this.Registers[regName]--;
else if (operand.Mode.HasFlag(AddressingModes.PostIncrement))
this.Registers[regName]++;
return value;
}
private void SetOperandValue(CompiledOperand operand, Int32 value, Byte size)
{
if (operand.Mode.HasFlag(AddressingModes.DirectRegister))
{
this.Registers[operand.GetRegister()] = value & (Int32)(((Int64)1 << size) - 1);
return;
}
if (operand.Mode.HasFlag(AddressingModes.Absolute) || operand.Mode.HasFlag(AddressingModes.AbsoluteLabel))
{
this.Memory.WriteValue(operand.Value, value, size);
return;
}
Int32 offset = 0;
if (operand.Mode.HasFlag(AddressingModes.Offset))
offset += operand.GetOffset();
if (operand.Mode.HasFlag(AddressingModes.Base))
offset += this.Registers[operand.GetBaseRegister()];
String regName = operand.GetRegister();
if (operand.Mode.HasFlag(AddressingModes.PreDecrement))
this.Registers[regName]--;
else if (operand.Mode.HasFlag(AddressingModes.PreIncrement))
this.Registers[regName]++;
this.Memory.WriteValue(this.Registers[regName] + offset, value, size);
if (operand.Mode.HasFlag(AddressingModes.PostDecrement))
this.Registers[regName]--;
else if (operand.Mode.HasFlag(AddressingModes.PostIncrement))
this.Registers[regName]++;
}
private Int32 GetCurrentOperandValue(Byte operandIndex)
{
return GetOperandValue(currentInstruction.Operands[operandIndex], currentInstruction.Size);
}
private void SetCurrentOperandValue(Byte operandIndex, Int32 value)
{
SetOperandValue(currentInstruction.Operands[operandIndex], value, currentInstruction.Size);
}
[InstructionImplementation("MOVE", "MOVEQ", "MOVEA")]
private void Move()
{
SetCurrentOperandValue(1, GetCurrentOperandValue(0));
}
private void InvokeAluOperation(Func<Int32, Int32, Int32> function, Boolean comparation = false)
{
try
{
Int32 result = function(GetCurrentOperandValue(0), GetCurrentOperandValue(1));
if (!comparation)
SetCurrentOperandValue(1, result);
if (result > 0)
this.StatusRegister = StatusFlags.Positive;
else if (result == 0)
this.StatusRegister = StatusFlags.Zero;
else
this.StatusRegister = StatusFlags.Negative;
if (result > (1 << (currentInstruction.Size - 1)) ||
result < -(1 << (currentInstruction.Size - 1)))
this.StatusRegister |= StatusFlags.Carry;
}
catch (OverflowException)
{
this.StatusRegister = StatusFlags.Overflow;
}
}
[InstructionImplementation("ADD", "ADDI", "ADDA")]
private void Add()
{
this.InvokeAluOperation((x, y) => x + y);
}
[InstructionImplementation("SUB", "SUBI", "SUBA")]
private void Sub()
{
this.InvokeAluOperation((x, y) => y - x);
}
[InstructionImplementation]
private void Muls()
{
this.InvokeAluOperation((x, y) => x * y);
}
[InstructionImplementation]
private void Divs()
{
this.InvokeAluOperation((x, y) => y / x);
}
[InstructionImplementation]
private void Mulu()
{
this.InvokeAluOperation((x, y) => (Int32)((UInt32)x * (UInt32)y));
}
[InstructionImplementation]
private void Divu()
{
this.InvokeAluOperation((x, y) => (Int32)((UInt32)y / (UInt32)x));
}
[InstructionImplementation("AND", "ANDI")]
private void And()
{
this.InvokeAluOperation((x, y) => x & y);
}
[InstructionImplementation("OR", "ORI")]
private void Or()
{
this.InvokeAluOperation((x, y) => x | y);
}
[InstructionImplementation("EOR", "EORI")]
private void Eor()
{
this.InvokeAluOperation((x, y) => x ^ y);
}
[InstructionImplementation("CMP", "CMPI", "CMPA")]
private void Cmp()
{
this.InvokeAluOperation((x, y) => y - x, true);
}
[InstructionImplementation]
private void Neg()
{
Int32 result = -GetCurrentOperandValue(0);
SetCurrentOperandValue(0, result);
if (result > 0)
this.StatusRegister = StatusFlags.Positive;
else if (result == 0)
this.StatusRegister = StatusFlags.Zero;
else
this.StatusRegister = StatusFlags.Negative;
}
[InstructionImplementation]
private void Not()
{
Int32 result = (Int32)(0xFFFFFFFF ^ (UInt32)GetCurrentOperandValue(0));
SetCurrentOperandValue(0, result);
if (result > 0)
this.StatusRegister = StatusFlags.Positive;
else if (result == 0)
this.StatusRegister = StatusFlags.Zero;
else
this.StatusRegister = StatusFlags.Negative;
}
private void Branch()
{
this.ProgramCounter = currentInstruction.Operands[0].Value;
}
[InstructionImplementation("BRA", "JMP")]
private void Bra()
{
this.Branch();
}
[InstructionImplementation]
private void Bcc()
{
if (!this.StatusRegister.HasFlag(StatusFlags.Carry))
this.Branch();
}
[InstructionImplementation]
private void Bcs()
{
if (this.StatusRegister.HasFlag(StatusFlags.Carry))
this.Branch();
}
[InstructionImplementation]
private void Beq()
{
if (this.StatusRegister.HasFlag(StatusFlags.Zero))
this.Branch();
}
[InstructionImplementation]
private void Bge()
{
if (this.StatusRegister.HasFlag(StatusFlags.Zero) ||
this.StatusRegister.HasFlag(StatusFlags.Positive))
this.Branch();
}
[InstructionImplementation]
private void Ble()
{
if (this.StatusRegister.HasFlag(StatusFlags.Zero) ||
this.StatusRegister.HasFlag(StatusFlags.Negative))
this.Branch();
}
[InstructionImplementation]
private void Bgt()
{
if (this.StatusRegister.HasFlag(StatusFlags.Positive))
this.Branch();
}
[InstructionImplementation]
private void Blt()
{
if (this.StatusRegister.HasFlag(StatusFlags.Negative))
this.Branch();
}
[InstructionImplementation]
private void Bne()
{
if (!this.StatusRegister.HasFlag(StatusFlags.Zero))
this.Branch();
}
[InstructionImplementation]
private void Bvc()
{
if (!this.StatusRegister.HasFlag(StatusFlags.Overflow))
this.Branch();
}
[InstructionImplementation]
private void Bvs()
{
if (this.StatusRegister.HasFlag(StatusFlags.Overflow))
this.Branch();
}
[InstructionImplementation]
private void Bsr()
{
this.StackPointer -= 4;
this.Memory.WriteValue(this.StackPointer, this.ProgramCounter, 32);
this.Branch();
}
[InstructionImplementation]
private void Rts()
{
Int32 pc = this.Memory.ReadValue(this.StackPointer, 32);
this.StackPointer += 4;
this.ProgramCounter = pc;
}
[InstructionImplementation]
private void Clr()
{
SetCurrentOperandValue(0, 0);
}
[InstructionImplementation]
private void Link()
{
this.StackPointer -= 4;
this.Memory.WriteValue(this.StackPointer, this.GetCurrentOperandValue(0), 32);
this.SetCurrentOperandValue(0, this.StackPointer);
this.StackPointer += this.GetCurrentOperandValue(1);
}
[InstructionImplementation]
private void Ulnk()
{
this.StackPointer = this.GetCurrentOperandValue(0);
this.SetCurrentOperandValue(0, this.Memory.ReadValue(this.StackPointer, 32));
this.StackPointer += 4;
}
[InstructionImplementation]
private void Nop() { }
[InstructionImplementation]
private void End()
{
this.ProgramCounter = program.Instructions.Keys.Max() + 1;
}
[InstructionImplementation]
private void Trap()
{
Int32 vectorNumber = GetCurrentOperandValue(0);
switch (vectorNumber)
{
case 0:
Int32 intValue = this.Memory.ReadValue(this.Registers["A0"], currentInstruction.Size);
this.OnOutput(intValue.ToString());
break;
case 1:
StringBuilder builder
= new StringBuilder
();
Byte val;
for (Int32 i = this.Registers["A0"]; (val = (Byte)this.Memory.ReadValue(i, 8)) > 0; i++)
builder.Append((Char)val);
this.OnOutput(builder.ToString());
break;
case 2:
this.OnNumberNeeded();
break;
case 3:
this.OnStringNeeded();
break;
}
}
}
}