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 - Assembler.cs

Assembler.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.  
  7. namespace Sloth
  8. {
  9.     public class AssemblerException : InterpreterException
  10.     {
  11.         public AssemblerException(String message, Int32 lineNumber) : base(message, lineNumber) { }
  12.     }
  13.  
  14.     public struct CompiledOperand
  15.     {
  16.         public AddressingModes Mode { get; set; }
  17.         public Int32 Value { get; set; }
  18.  
  19.         public void SetRegister(String registerName)
  20.         {
  21.             this.Value |= GetRegisterIndex(registerName);
  22.         }
  23.  
  24.         public void SetBaseRegister(String registerName)
  25.         {
  26.             this.Value |= GetRegisterIndex(registerName) << 8;
  27.         }
  28.  
  29.         public void SetOffset(Int16 offset)
  30.         {
  31.             this.Value |= offset << 16;
  32.         }
  33.  
  34.         public String GetRegister()
  35.         {
  36.             return GetRegisterName((Byte)(this.Value & 0xFF));
  37.         }
  38.  
  39.         public String GetBaseRegister()
  40.         {
  41.             return GetRegisterName((Byte)((this.Value & 0xFF00) >> 8));
  42.         }
  43.  
  44.         public Int16 GetOffset()
  45.         {
  46.             return (Int16)((this.Value & 0xFFFF0000) >> 16);
  47.         }
  48.  
  49.         private static Byte GetRegisterIndex(String registerName)
  50.         {
  51.             return (Byte)((registerName[0] == 'A' ? 8 : 0) + Byte.Parse(registerName[1].ToString()));
  52.         }
  53.  
  54.         private static String GetRegisterName(Byte index)
  55.         {
  56.             if (index >= 8)
  57.                 return 'A' + (index - 8).ToString();
  58.             return 'D' + index.ToString();
  59.         }
  60.     }
  61.  
  62.     public struct CompiledInstruction
  63.     {
  64.         private static readonly Int16[] branchOpCodes = (new String[] { "BRA", "BLE", "BGE", "BLT", "BGT", "BVS", "BVC", "BCS", "BCC", "BEQ", "BNE", "BSR" }).Select(name => name.GetHashCode16()).ToArray();
  65.  
  66.         private Byte binarySize;
  67.  
  68.         public Int16 OpCode { get; set; }
  69.         public List<CompiledOperand> Operands { get; set; }
  70.         public Byte Size { get; set; }
  71.  
  72.         public Byte BinarySize
  73.         {
  74.             get
  75.             {
  76.                 if (binarySize == 0)
  77.                     binarySize = this.GetBinarySize();
  78.                 return binarySize;
  79.             }
  80.         }
  81.  
  82.         public void WriteBinary(BinaryWriter writer)
  83.         {
  84.             writer.Write(this.OpCode);
  85.  
  86.             if (branchOpCodes.Contains(this.OpCode))
  87.                 return;
  88.  
  89.             foreach (var operand in this.Operands)
  90.                 if (operand.Mode.HasAnyFlags(AddressingModes.Immediate, AddressingModes.Absolute, AddressingModes.ImmediateLabel, AddressingModes.AbsoluteLabel))
  91.                     if (!operand.Value.IsInt16())
  92.                         writer.Write(operand.Value);
  93.                     else
  94.                         writer.Write((Int16)operand.Value);
  95.                 else if (operand.Mode.HasFlag(AddressingModes.Offset))
  96.                     writer.Write((Int16)operand.Value);
  97.         }
  98.  
  99.         private Byte GetBinarySize()
  100.         {
  101.             if (branchOpCodes.Contains(this.OpCode))
  102.                 return 2;
  103.  
  104.             Byte size = 2;
  105.             foreach(var operand in this.Operands)
  106.                 if (operand.Mode.HasAnyFlags(AddressingModes.Immediate, AddressingModes.Absolute, AddressingModes.ImmediateLabel, AddressingModes.AbsoluteLabel))
  107.                     if (!operand.Value.IsInt16())
  108.                         size += 4;
  109.                     else
  110.                         size += 2;
  111.                 else if (operand.Mode.HasFlag(AddressingModes.Offset))
  112.                     size += 2;
  113.  
  114.             return size;
  115.         }
  116.     }
  117.  
  118.     public class AssemblyProgram
  119.     {
  120.         public MemoryStream Binary { get; private set; }
  121.         public Dictionary<Int32, CompiledInstruction> Instructions { get; private set; }
  122.  
  123.         public AssemblyProgram()
  124.         {
  125.             this.Binary = new MemoryStream();
  126.             this.Instructions = new Dictionary<Int32, CompiledInstruction>();
  127.         }
  128.     }
  129.  
  130.     public class Assembler
  131.     {
  132.         private Dictionary<String, Int32> labels;
  133.  
  134.         public AssemblyProgram Output { get; private set; }
  135.  
  136.         public Assembler()
  137.         {
  138.             labels = new Dictionary<string, int>();
  139.         }
  140.  
  141.         public void Assemble(InstructionList instructions)
  142.         {
  143.             this.Output = new AssemblyProgram();
  144.             labels.Clear();
  145.  
  146.             BinaryWriter writer = new BinaryWriter(this.Output.Binary);
  147.             Int32 position = 0;
  148.  
  149.             foreach (Instruction instruction in instructions)
  150.                 if (instruction.IsLabel)
  151.                     labels.Add(instruction.Name.TrimEnd(':'), position);
  152.                 else
  153.                     position += instruction.GetBinarySize();
  154.  
  155.             foreach (Instruction instruction in instructions)
  156.             {
  157.                 if (instruction.IsLabel)
  158.                     continue;
  159.  
  160.                 switch (instruction.Name)
  161.                 {
  162.                     case "DC":
  163.                         for (Int32 i = 0; i < instruction.Operands.Count; i++)
  164.                         {
  165.                             if (instruction.Size == 32)
  166.                                 writer.Write(instruction.Operands[i].LiteralValue);
  167.                             else if (instruction.Size == 16)
  168.                                 writer.Write((Int16)instruction.Operands[i].LiteralValue);
  169.                             else
  170.                                 writer.Write((Byte)instruction.Operands[i].LiteralValue);
  171.                         }
  172.                         break;
  173.  
  174.                     case "DS":
  175.                         for (Int32 i = 0; i < instruction.Size / 8 * instruction.Operands[0].LiteralValue; i++)
  176.                             writer.Write((Byte)0);
  177.                         break;
  178.  
  179.                     default:
  180.                         CompiledInstruction compiled = this.CompileInstruction(instruction);
  181.                         this.Output.Instructions.Add((Int32)this.Output.Binary.Position, compiled);
  182.                         compiled.WriteBinary(writer);
  183.                         break;
  184.                 }
  185.             }
  186.             labels.Clear();
  187.         }
  188.  
  189.         private CompiledInstruction CompileInstruction(Instruction instruction)
  190.         {
  191.             CompiledInstruction result = new CompiledInstruction();
  192.             result.OpCode = instruction.Name.GetHashCode16();
  193.             result.Size = instruction.Size;
  194.             try
  195.             {
  196.                 result.Operands = instruction.Operands.Select(op => this.CompileOperand(op)).ToList();
  197.             }
  198.             catch
  199.             {
  200.                 throw new AssemblerException("L'etichetta specificata non è valida.", instruction.LineNumber);
  201.             }
  202.             return result;
  203.         }
  204.  
  205.         private CompiledOperand CompileOperand(Operand operand)
  206.         {
  207.             CompiledOperand result = new CompiledOperand();
  208.             result.Mode = operand.Mode;
  209.  
  210.             if (operand.Mode.HasAnyFlags(AddressingModes.Absolute, AddressingModes.Immediate))
  211.                 result.Value = operand.LiteralValue;
  212.             else if (operand.Mode.HasAnyFlags(AddressingModes.AbsoluteLabel, AddressingModes.ImmediateLabel))
  213.                     result.Value = labels[operand.MemoryLocation];
  214.             else if (operand.Mode.HasAnyFlags(AddressingModes.DirectRegister, AddressingModes.IndirectRegister))
  215.                 result.SetRegister(operand.MemoryLocation);
  216.  
  217.             if (operand.Mode.HasFlag(AddressingModes.Base))
  218.                 result.SetBaseRegister(operand.BaseRegister);
  219.  
  220.             if (operand.Mode.HasFlag(AddressingModes.Offset))
  221.                 result.SetOffset((Int16)operand.LiteralValue);
  222.  
  223.             return result;
  224.         }
  225.     }
  226. }