Questo sito utilizza cookies solo per scopi di autenticazione sul sito e nient'altro. Nessuna informazione personale viene tracciata. Leggi l'informativa sui cookies.
Username: Password: oppure
Sloth - Emulator.cs

Emulator.cs

Caricato da: Totem
Scarica il programma completo

  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5. using System.IO;
  6. using System.Reflection;
  7.  
  8. namespace Sloth
  9. {
  10.     public class RuntimeException : Exception
  11.     {
  12.         public RuntimeException(String message) : base(message) { }
  13.     }
  14.  
  15.     [Flags()]
  16.     public enum StatusFlags
  17.     {
  18.         Positive = 1,
  19.         Negative = 2,
  20.         Zero = 4,
  21.         Overflow = 8,
  22.         Carry = 16
  23.     }
  24.  
  25.     public class VirtualMemory : IDisposable
  26.     {
  27.         private BinaryReader memoryReader;
  28.         private BinaryWriter memoryWriter;
  29.         private MemoryStream memoryStream;
  30.  
  31.         public Boolean IsDisposed { get; set; }
  32.  
  33.         public Int64 Capacity
  34.         {
  35.             get { return memoryStream.Length; }
  36.         }
  37.  
  38.         public Int64 Position
  39.         {
  40.             get { return memoryStream.Position; }
  41.         }
  42.  
  43.         public VirtualMemory(Int32 size)
  44.         {
  45.             this.memoryStream = new MemoryStream(new Byte[size]);
  46.             this.memoryReader = new BinaryReader(memoryStream);
  47.             this.memoryWriter = new BinaryWriter(memoryStream);
  48.             this.memoryStream.Position = 0;
  49.         }
  50.  
  51.         public Int32 ReadValue(Int32 address, Byte size)
  52.         {
  53.             this.memoryStream.Position = address;
  54.             if (size == 32)
  55.                 return memoryReader.ReadInt32();
  56.             if (size == 16)
  57.                 return memoryReader.ReadInt16();
  58.             return memoryReader.ReadByte();
  59.         }
  60.  
  61.         public void WriteValue(Int32 address, Int32 value, Byte size)
  62.         {
  63.             this.memoryStream.Position = address;
  64.             if (size == 32)
  65.                 memoryWriter.Write(value);
  66.             else if (size == 16)
  67.                 memoryWriter.Write((Int16)(value & 0xFFFF));
  68.             else
  69.                 memoryWriter.Write((Byte)(value & 0xFF));
  70.         }
  71.  
  72.         public void WriteStream(Int32 address, Stream source)
  73.         {
  74.             memoryStream.Position = address;
  75.             source.Position = 0;
  76.             source.CopyTo(memoryStream);
  77.         }
  78.  
  79.         public void Malloc(Int32 sizeInBytes)
  80.         {
  81.             this.memoryStream.Position += sizeInBytes;
  82.         }
  83.  
  84.         public void Clear()
  85.         {
  86.             this.memoryStream.Position = 0;
  87.             for (Int32 i = 0; i < memoryStream.Length; i++)
  88.                 memoryStream.WriteByte(0);
  89.             this.memoryStream.Position = 0;
  90.         }
  91.  
  92.         public Byte[] ToByteArray()
  93.         {
  94.             Byte[] buffer = new Byte[memoryStream.Capacity];
  95.             Int64 position = memoryStream.Position;
  96.             memoryStream.Position = 0;
  97.             memoryStream.Read(buffer, 0, buffer.Length);
  98.             memoryStream.Position = position;
  99.             return buffer;
  100.         }
  101.  
  102.         public void Dispose()
  103.         {
  104.             if (!this.IsDisposed)
  105.             {
  106.                 memoryStream.Close();
  107.                 memoryStream = null;
  108.                 memoryWriter = null;
  109.                 memoryReader = null;
  110.                 this.IsDisposed = true;
  111.             }
  112.         }
  113.     }
  114.  
  115.     public class InstructionImplementationAttribute : Attribute
  116.     {
  117.         public List<String> Synonims { get; private set; }
  118.  
  119.         public InstructionImplementationAttribute()
  120.         {
  121.             this.Synonims = new List<String>();
  122.         }
  123.  
  124.         public InstructionImplementationAttribute(params String[] synonims) : this()
  125.         {
  126.             this.Synonims.AddRange(synonims);
  127.         }
  128.     }
  129.  
  130.     public class ExecutionEventArgs : EventArgs
  131.     {
  132.         public Boolean Suspend { get; set; }
  133.     }
  134.  
  135.     public class StringOutputEventArgs : EventArgs
  136.     {
  137.         public String Message { get; private set; }
  138.  
  139.         public StringOutputEventArgs(String message)
  140.         {
  141.             this.Message = message;
  142.         }
  143.     }
  144.  
  145.     public class NumberInputEventArgs : EventArgs
  146.     {
  147.         public Int32 Value { get; set; }
  148.     }
  149.  
  150.     public class StringInputEventArgs : EventArgs
  151.     {
  152.         public String Value { get; set; }
  153.     }
  154.  
  155.     public class Emulator
  156.     {
  157.         private delegate void ExecuteInstruction();
  158.  
  159.         private Boolean executionSuspended = false;
  160.  
  161.         public event EventHandler<ExecutionEventArgs> Step;
  162.         public event EventHandler ExecutionFinished;
  163.  
  164.         public event EventHandler<StringOutputEventArgs> Output;
  165.         public event EventHandler<StringInputEventArgs> StringNeeded;
  166.         public event EventHandler<NumberInputEventArgs> NumberNeeded;
  167.  
  168.         private AssemblyProgram program;
  169.         private CompiledInstruction currentInstruction;
  170.         private Dictionary<Int16, ExecuteInstruction> implementedFunctions;
  171.  
  172.         public Dictionary<String, Int32> Registers { get; private set; }
  173.         public Boolean IsRunning { get; private set; }
  174.         public VirtualMemory Memory { get; set; }
  175.         public Boolean RaiseStepEvent { get; set; }
  176.  
  177.         public CompiledInstruction CurrentInstruction
  178.         {
  179.             get { return currentInstruction; }
  180.         }
  181.  
  182.         public AssemblyProgram CurrentProgram
  183.         {
  184.             get { return program; }
  185.         }
  186.  
  187.         public StatusFlags StatusRegister
  188.         {
  189.             get { return (StatusFlags)this.Registers["SR"]; }
  190.             set { this.Registers["SR"] = (Int32)value; }
  191.         }
  192.  
  193.         public Int32 StackPointer
  194.         {
  195.             get { return this.Registers["A7"]; }
  196.             set { this.Registers["A7"] = value; }
  197.         }
  198.  
  199.         public Int32 ProgramCounter
  200.         {
  201.             get { return this.Registers["PC"]; }
  202.             set { this.Registers["PC"] = value; }
  203.         }
  204.  
  205.         public Int32 FramePointer
  206.         {
  207.             get { return this.Registers["A6"]; }
  208.             set { this.Registers["A6"] = value; }
  209.         }
  210.  
  211.         public Emulator(Int32 memorySize)
  212.         {
  213.             this.Registers = new Dictionary<String, Int32>();
  214.             this.Memory = new VirtualMemory(memorySize);
  215.  
  216.             for (Int32 i = 0; i < 8; i++)
  217.             {
  218.                 this.Registers.Add("A" + i.ToString(), 0);
  219.                 this.Registers.Add("D" + i.ToString(), 0);
  220.             }
  221.             this.Registers.Add("SR", 0);
  222.             this.Registers.Add("PC", 0);
  223.  
  224.             implementedFunctions = new Dictionary<Int16, ExecuteInstruction>();
  225.             foreach (var binding in
  226.                 from method in typeof(Emulator).GetMethods(BindingFlags.NonPublic | BindingFlags.Instance)
  227.                 let attributes = method.GetCustomAttributes(typeof(InstructionImplementationAttribute), false)
  228.                 where attributes.Count() > 0
  229.                 let attribute = (InstructionImplementationAttribute)attributes.First()
  230.                 let implementation = new ExecuteInstruction(delegate() { method.Invoke(this, null); })
  231.                 select new { MethodNames = attribute.Synonims.Count > 0 ? attribute.Synonims : (new List<String>() { method.Name }), Implementation = implementation })
  232.             {
  233.                 foreach (String name in binding.MethodNames)
  234.                     implementedFunctions.Add(name.GetHashCode16(), binding.Implementation);
  235.             }
  236.         }
  237.  
  238.         public void Load(AssemblyProgram program)
  239.         {
  240.             this.program = program;
  241.             this.Memory.WriteStream(0, program.Binary);
  242.         }
  243.  
  244.         public void Run()
  245.         {
  246.             if (program == null)
  247.                 throw new RuntimeException("Nessun programma caricato in memoria.");
  248.             this.Reset();
  249.             this.Resume();
  250.         }
  251.  
  252.         public void Reset()
  253.         {
  254.             foreach (String key in this.Registers.Keys.ToList())
  255.                 this.Registers[key] = 0;
  256.             this.StackPointer = (Int32)this.Memory.Capacity;
  257.             if (program != null)
  258.                 if (program.Instructions.Count > 0)
  259.                     this.ProgramCounter = program.Instructions.Keys.Min();
  260.                 else
  261.                     this.ProgramCounter = 0;
  262.         }
  263.  
  264.         public void Resume()
  265.         {
  266.             this.IsRunning = true;
  267.             executionSuspended = false;
  268.             while (!executionSuspended && this.Fetch())
  269.                 this.DecodeAndExecute();
  270.             this.IsRunning = false;
  271.         }
  272.  
  273.         public void Stop()
  274.         {
  275.             executionSuspended = true;
  276.         }
  277.  
  278.         private Boolean Fetch()
  279.         {
  280.             try
  281.             {
  282.                 currentInstruction = program.Instructions[this.ProgramCounter];
  283.                 this.ProgramCounter += currentInstruction.BinarySize; ;
  284.                 return true;
  285.             }
  286.             catch
  287.             {
  288.                 this.OnExecutionFinished();
  289.                 return false;
  290.             }
  291.         }
  292.  
  293.         private void DecodeAndExecute()
  294.         {
  295.             try
  296.             {
  297.                 var implementation = implementedFunctions.Single(pair => pair.Key == currentInstruction.OpCode).Value;
  298.                 implementation.Invoke();
  299.                 this.OnStep();
  300.             }
  301.             catch
  302.             {
  303.                 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));
  304.             }
  305.         }
  306.  
  307.  
  308.         protected void OnStep()
  309.         {
  310.             if ((Step != null) && this.RaiseStepEvent)
  311.             {
  312.                 ExecutionEventArgs e = new ExecutionEventArgs();
  313.                 e.Suspend = false;
  314.                 Step(this, e);
  315.                 if (e.Suspend)
  316.                     executionSuspended = true;
  317.             }
  318.         }
  319.  
  320.         protected void OnExecutionFinished()
  321.         {
  322.             this.ProgramCounter = program.Instructions.Keys.Min();
  323.             if (ExecutionFinished != null)
  324.                 ExecutionFinished(this, EventArgs.Empty);
  325.         }
  326.  
  327.         protected void OnOutput(String message)
  328.         {
  329.             if (Output != null)
  330.                 Output(this, new StringOutputEventArgs(message));
  331.         }
  332.  
  333.         protected void OnNumberNeeded()
  334.         {
  335.             if (NumberNeeded != null)
  336.             {
  337.                 NumberInputEventArgs e = new NumberInputEventArgs();
  338.                 NumberNeeded(this, e);
  339.                 this.Memory.WriteValue(this.Registers["A0"], e.Value, currentInstruction.Size);
  340.             }
  341.         }
  342.  
  343.         protected void OnStringNeeded()
  344.         {
  345.             if (StringNeeded != null)
  346.             {
  347.                 StringInputEventArgs e = new StringInputEventArgs();
  348.                 StringNeeded(this, e);
  349.                 for (Int32 i = 0; i < e.Value.Length; i++)
  350.                     this.Memory.WriteValue(this.Registers["A0"] + i, (Byte)e.Value[i], 8);
  351.                 this.Memory.WriteValue(this.Registers["A0"] + e.Value.Length, 0, 8);
  352.             }
  353.         }
  354.  
  355.  
  356.         private Int32 GetOperandValue(CompiledOperand operand, Byte size)
  357.         {
  358.             if (operand.Mode.HasFlag(AddressingModes.Immediate) || operand.Mode.HasFlag(AddressingModes.ImmediateLabel))
  359.                 return operand.Value;
  360.             if (operand.Mode.HasFlag(AddressingModes.DirectRegister))
  361.                 return this.Registers[operand.GetRegister()];
  362.             if (operand.Mode.HasFlag(AddressingModes.Absolute) || operand.Mode.HasFlag(AddressingModes.AbsoluteLabel))
  363.                 return this.Memory.ReadValue(operand.Value, size);
  364.  
  365.             // > IndirectRegister
  366.             Int32 offset = 0, value;
  367.             if (operand.Mode.HasFlag(AddressingModes.Offset))
  368.                 offset += operand.GetOffset();
  369.             if (operand.Mode.HasFlag(AddressingModes.Base))
  370.                 offset += this.Registers[operand.GetBaseRegister()];
  371.  
  372.             String regName = operand.GetRegister();
  373.  
  374.             if (operand.Mode.HasFlag(AddressingModes.PreDecrement))
  375.                 this.Registers[regName]--;
  376.             else if (operand.Mode.HasFlag(AddressingModes.PreIncrement))
  377.                 this.Registers[regName]++;
  378.  
  379.             value = this.Memory.ReadValue(this.Registers[regName] + offset, size);
  380.  
  381.             if (operand.Mode.HasFlag(AddressingModes.PostDecrement))
  382.                 this.Registers[regName]--;
  383.             else if (operand.Mode.HasFlag(AddressingModes.PostIncrement))
  384.                 this.Registers[regName]++;
  385.  
  386.             return value;
  387.         }
  388.  
  389.         private void SetOperandValue(CompiledOperand operand, Int32 value, Byte size)
  390.         {
  391.             if (operand.Mode.HasFlag(AddressingModes.DirectRegister))
  392.             {
  393.                 this.Registers[operand.GetRegister()] = value & (Int32)(((Int64)1 << size) - 1);
  394.                 return;
  395.             }
  396.             if (operand.Mode.HasFlag(AddressingModes.Absolute) || operand.Mode.HasFlag(AddressingModes.AbsoluteLabel))
  397.             {
  398.                 this.Memory.WriteValue(operand.Value, value, size);
  399.                 return;
  400.             }
  401.  
  402.             Int32 offset = 0;
  403.             if (operand.Mode.HasFlag(AddressingModes.Offset))
  404.                 offset += operand.GetOffset();
  405.             if (operand.Mode.HasFlag(AddressingModes.Base))
  406.                 offset += this.Registers[operand.GetBaseRegister()];
  407.  
  408.             String regName = operand.GetRegister();
  409.  
  410.             if (operand.Mode.HasFlag(AddressingModes.PreDecrement))
  411.                 this.Registers[regName]--;
  412.             else if (operand.Mode.HasFlag(AddressingModes.PreIncrement))
  413.                 this.Registers[regName]++;
  414.  
  415.             this.Memory.WriteValue(this.Registers[regName] + offset, value, size);
  416.  
  417.             if (operand.Mode.HasFlag(AddressingModes.PostDecrement))
  418.                 this.Registers[regName]--;
  419.             else if (operand.Mode.HasFlag(AddressingModes.PostIncrement))
  420.                 this.Registers[regName]++;
  421.         }
  422.  
  423.         private Int32 GetCurrentOperandValue(Byte operandIndex)
  424.         {
  425.             return GetOperandValue(currentInstruction.Operands[operandIndex], currentInstruction.Size);
  426.         }
  427.  
  428.         private void SetCurrentOperandValue(Byte operandIndex, Int32 value)
  429.         {
  430.             SetOperandValue(currentInstruction.Operands[operandIndex], value, currentInstruction.Size);
  431.         }
  432.  
  433.  
  434.         [InstructionImplementation("MOVE", "MOVEQ", "MOVEA")]
  435.         private void Move()
  436.         {
  437.             SetCurrentOperandValue(1, GetCurrentOperandValue(0));
  438.         }
  439.  
  440.         private void InvokeAluOperation(Func<Int32, Int32, Int32> function, Boolean comparation = false)
  441.         {
  442.             try
  443.             {
  444.                 Int32 result = function(GetCurrentOperandValue(0), GetCurrentOperandValue(1));
  445.                 if (!comparation)
  446.                     SetCurrentOperandValue(1, result);
  447.                 if (result > 0)
  448.                     this.StatusRegister = StatusFlags.Positive;
  449.                 else if (result == 0)
  450.                     this.StatusRegister = StatusFlags.Zero;
  451.                 else
  452.                     this.StatusRegister = StatusFlags.Negative;
  453.  
  454.                 if (result > (1 << (currentInstruction.Size - 1)) ||
  455.                     result < -(1 << (currentInstruction.Size - 1)))
  456.                     this.StatusRegister |= StatusFlags.Carry;
  457.             }
  458.             catch (OverflowException)
  459.             {
  460.                 this.StatusRegister = StatusFlags.Overflow;
  461.             }
  462.         }
  463.  
  464.         [InstructionImplementation("ADD", "ADDI", "ADDA")]
  465.         private void Add()
  466.         {
  467.             this.InvokeAluOperation((x, y) => x + y);
  468.         }
  469.  
  470.         [InstructionImplementation("SUB", "SUBI", "SUBA")]
  471.         private void Sub()
  472.         {
  473.             this.InvokeAluOperation((x, y) => y - x);
  474.         }
  475.  
  476.         [InstructionImplementation]
  477.         private void Muls()
  478.         {
  479.             this.InvokeAluOperation((x, y) => x * y);
  480.         }
  481.  
  482.         [InstructionImplementation]
  483.         private void Divs()
  484.         {
  485.             this.InvokeAluOperation((x, y) => y / x);
  486.         }
  487.  
  488.         [InstructionImplementation]
  489.         private void Mulu()
  490.         {
  491.             this.InvokeAluOperation((x, y) => (Int32)((UInt32)x * (UInt32)y));
  492.         }
  493.  
  494.         [InstructionImplementation]
  495.         private void Divu()
  496.         {
  497.             this.InvokeAluOperation((x, y) => (Int32)((UInt32)y / (UInt32)x));
  498.         }
  499.  
  500.         [InstructionImplementation("AND", "ANDI")]
  501.         private void And()
  502.         {
  503.             this.InvokeAluOperation((x, y) => x & y);
  504.         }
  505.  
  506.         [InstructionImplementation("OR", "ORI")]
  507.         private void Or()
  508.         {
  509.             this.InvokeAluOperation((x, y) => x | y);
  510.         }
  511.  
  512.         [InstructionImplementation("EOR", "EORI")]
  513.         private void Eor()
  514.         {
  515.             this.InvokeAluOperation((x, y) => x ^ y);
  516.         }
  517.  
  518.         [InstructionImplementation("CMP", "CMPI", "CMPA")]
  519.         private void Cmp()
  520.         {
  521.             this.InvokeAluOperation((x, y) => y - x, true);
  522.         }
  523.  
  524.         [InstructionImplementation]
  525.         private void Neg()
  526.         {
  527.             Int32 result = -GetCurrentOperandValue(0);
  528.             SetCurrentOperandValue(0, result);
  529.  
  530.             if (result > 0)
  531.                 this.StatusRegister = StatusFlags.Positive;
  532.             else if (result == 0)
  533.                 this.StatusRegister = StatusFlags.Zero;
  534.             else
  535.                 this.StatusRegister = StatusFlags.Negative;
  536.         }
  537.  
  538.         [InstructionImplementation]
  539.         private void Not()
  540.         {
  541.             Int32 result = (Int32)(0xFFFFFFFF ^ (UInt32)GetCurrentOperandValue(0));
  542.             SetCurrentOperandValue(0, result);
  543.  
  544.             if (result > 0)
  545.                 this.StatusRegister = StatusFlags.Positive;
  546.             else if (result == 0)
  547.                 this.StatusRegister = StatusFlags.Zero;
  548.             else
  549.                 this.StatusRegister = StatusFlags.Negative;
  550.         }
  551.  
  552.         private void Branch()
  553.         {
  554.             this.ProgramCounter = currentInstruction.Operands[0].Value;
  555.         }
  556.  
  557.         [InstructionImplementation("BRA", "JMP")]
  558.         private void Bra()
  559.         {
  560.             this.Branch();
  561.         }
  562.  
  563.         [InstructionImplementation]
  564.         private void Bcc()
  565.         {
  566.             if (!this.StatusRegister.HasFlag(StatusFlags.Carry))
  567.                 this.Branch();
  568.         }
  569.  
  570.         [InstructionImplementation]
  571.         private void Bcs()
  572.         {
  573.             if (this.StatusRegister.HasFlag(StatusFlags.Carry))
  574.                 this.Branch();
  575.         }
  576.  
  577.         [InstructionImplementation]
  578.         private void Beq()
  579.         {
  580.             if (this.StatusRegister.HasFlag(StatusFlags.Zero))
  581.                 this.Branch();
  582.         }
  583.  
  584.         [InstructionImplementation]
  585.         private void Bge()
  586.         {
  587.             if (this.StatusRegister.HasFlag(StatusFlags.Zero) ||
  588.                 this.StatusRegister.HasFlag(StatusFlags.Positive))
  589.                 this.Branch();
  590.         }
  591.  
  592.         [InstructionImplementation]
  593.         private void Ble()
  594.         {
  595.             if (this.StatusRegister.HasFlag(StatusFlags.Zero) ||
  596.                 this.StatusRegister.HasFlag(StatusFlags.Negative))
  597.                 this.Branch();
  598.         }
  599.  
  600.         [InstructionImplementation]
  601.         private void Bgt()
  602.         {
  603.             if (this.StatusRegister.HasFlag(StatusFlags.Positive))
  604.                 this.Branch();
  605.         }
  606.  
  607.         [InstructionImplementation]
  608.         private void Blt()
  609.         {
  610.             if (this.StatusRegister.HasFlag(StatusFlags.Negative))
  611.                 this.Branch();
  612.         }
  613.  
  614.         [InstructionImplementation]
  615.         private void Bne()
  616.         {
  617.             if (!this.StatusRegister.HasFlag(StatusFlags.Zero))
  618.                 this.Branch();
  619.         }
  620.  
  621.         [InstructionImplementation]
  622.         private void Bvc()
  623.         {
  624.             if (!this.StatusRegister.HasFlag(StatusFlags.Overflow))
  625.                 this.Branch();
  626.         }
  627.  
  628.         [InstructionImplementation]
  629.         private void Bvs()
  630.         {
  631.             if (this.StatusRegister.HasFlag(StatusFlags.Overflow))
  632.                 this.Branch();
  633.         }
  634.  
  635.         [InstructionImplementation]
  636.         private void Bsr()
  637.         {
  638.             this.StackPointer -= 4;
  639.             this.Memory.WriteValue(this.StackPointer, this.ProgramCounter, 32);
  640.             this.Branch();
  641.         }
  642.  
  643.         [InstructionImplementation]
  644.         private void Rts()
  645.         {
  646.             Int32 pc = this.Memory.ReadValue(this.StackPointer, 32);
  647.             this.StackPointer += 4;
  648.             this.ProgramCounter = pc;
  649.         }
  650.  
  651.         [InstructionImplementation]
  652.         private void Clr()
  653.         {
  654.             SetCurrentOperandValue(0, 0);
  655.         }
  656.  
  657.         [InstructionImplementation]
  658.         private void Link()
  659.         {
  660.             this.StackPointer -= 4;
  661.             this.Memory.WriteValue(this.StackPointer, this.GetCurrentOperandValue(0), 32);
  662.             this.SetCurrentOperandValue(0, this.StackPointer);
  663.             this.StackPointer += this.GetCurrentOperandValue(1);
  664.         }
  665.  
  666.         [InstructionImplementation]
  667.         private void Ulnk()
  668.         {
  669.             this.StackPointer = this.GetCurrentOperandValue(0);
  670.             this.SetCurrentOperandValue(0, this.Memory.ReadValue(this.StackPointer, 32));
  671.             this.StackPointer += 4;
  672.         }
  673.  
  674.         [InstructionImplementation]
  675.         private void Nop() { }
  676.  
  677.         [InstructionImplementation]
  678.         private void End()
  679.         {
  680.             this.ProgramCounter = program.Instructions.Keys.Max() + 1;
  681.         }
  682.  
  683.         [InstructionImplementation]
  684.         private void Trap()
  685.         {
  686.             Int32 vectorNumber = GetCurrentOperandValue(0);
  687.  
  688.             switch (vectorNumber)
  689.             {
  690.                 case 0:
  691.                     Int32 intValue = this.Memory.ReadValue(this.Registers["A0"], currentInstruction.Size);
  692.                     this.OnOutput(intValue.ToString());
  693.                     break;
  694.  
  695.                 case 1:
  696.                     StringBuilder builder = new StringBuilder();
  697.                     Byte val;
  698.                     for (Int32 i = this.Registers["A0"]; (val = (Byte)this.Memory.ReadValue(i, 8)) > 0; i++)
  699.                         builder.Append((Char)val);
  700.                     this.OnOutput(builder.ToString());
  701.                     break;
  702.  
  703.                 case 2:
  704.                     this.OnNumberNeeded();
  705.                     break;
  706.  
  707.                 case 3:
  708.                     this.OnStringNeeded();
  709.                     break;
  710.             }
  711.         }
  712.     }
  713. }