/// <summary> /// Adds a line to the file and also adds labels to the label table as necessary. /// </summary> /// <param name="tokens"></param> public void AddLine(Token[] tokens) { if (tokens.Length > 0) { EnumTokenTypes type; if (tokens[0].GetTokenType(out type)) { if (type == EnumTokenTypes.Label) { if (!LabelTable.ContainsKey(tokens[0].Text)) { //tokens[0].Text = tokens[0].Text.Trim(':'); LabelTable.Add(tokens[0].Text.Trim(':'), FileSize); } return; } if (type == EnumTokenTypes.Instruction) { EnumInstructions inst; Int64 InstructionLength = 0; if (tokens[0].GetInstruction(out inst)) { InstructionLength = Y86Sizes.GetInstructionSize(inst); } else { throw new AssemblerException(EnumAssemblerStages.TokenFile, "Could not get instruction length"); } TokenLine tempLine = new TokenLine(); tempLine.Tokens = tokens; tempLine.BeginAddress = FileSize; tempLine.EndAddress = tempLine.BeginAddress + InstructionLength; FileSize = tempLine.EndAddress; File.Add(tempLine); return; } } } throw new Exception("Tried to add empty line to token file"); }
/// <summary> /// Writes a given TokenFile to a binary file. /// </summary> public void WriteToFile(TokenFile tokenFile, BinaryWriter filestream) { //TODO Create Wrapper functions for movs, jmps, etc. for (int line = 0; line < tokenFile.NumberOfLines; line++) { TokenLine currentTokenLine = tokenFile.GetLine(line); Token firstToken = currentTokenLine.Tokens[0]; EnumInstructions first_instruction; if (!firstToken.GetInstruction(out first_instruction)) { return; } byte[] someBytes = new byte[0]; byte aByte; long someProperty; long otherProperty; int rA; int rB; int tmpInt; switch (first_instruction) { case EnumInstructions.halt: //0x00 filestream.Write((byte)0); break; case EnumInstructions.nop: //0x10 filestream.Write((byte)16); break; case EnumInstructions.rrmov: //0x20<rA><rB> if (currentTokenLine.Tokens.Length != 3) { throw new AssemblerException(EnumAssemblerStages.BinaryWriter, "Not enough tokens in RRMOV instruction."); } filestream.Write((byte)32); //0x20 if (!currentTokenLine.Tokens[1].GetProperty(EnumTokenProperties.RegisterNumber, out rA)) { throw new AssemblerException(EnumAssemblerStages.BinaryWriter, "Token does not contain register code."); } if (!currentTokenLine.Tokens[2].GetProperty(EnumTokenProperties.RegisterNumber, out rB) || currentTokenLine.Tokens[2].TokenType != EnumTokenTypes.Register) { throw new AssemblerException(EnumAssemblerStages.BinaryWriter, "Token does not contain register code."); } tmpInt = rA << 4; tmpInt = tmpInt | rB; filestream.Write((byte)tmpInt); //0x<rA><rB> tmpInt = 0; break; case EnumInstructions.irmov: //0x30<F><rB><V> if (currentTokenLine.Tokens.Length != 3) { throw new AssemblerException(EnumAssemblerStages.BinaryWriter, "Not enough tokens in IRMOV instruction."); } filestream.Write((byte)48); if (!currentTokenLine.Tokens[1].GetProperty(EnumTokenProperties.ImmediateValue, out someProperty) || currentTokenLine.Tokens[1].TokenType != EnumTokenTypes.Immediate) { throw new AssemblerException(EnumAssemblerStages.BinaryWriter, "Token is not expected immediate value."); } if (!currentTokenLine.Tokens[2].GetProperty(EnumTokenProperties.RegisterNumber, out rB) || currentTokenLine.Tokens[2].TokenType != EnumTokenTypes.Register) { throw new AssemblerException(EnumAssemblerStages.BinaryWriter, "Token is not expected address register."); } filestream.Write((byte)(rB + 240)); //Write byte F,rB someBytes = BitConverter.GetBytes((uint)someProperty); WriteBytes(someBytes, filestream); break; case EnumInstructions.rmmov: //0x40<rA><rB><D> Where D is offset to address in register B (rB). if (currentTokenLine.Tokens.Length != 3) { throw new AssemblerException(EnumAssemblerStages.BinaryWriter, "Not enough tokens in RMMOV instruction."); } filestream.Write((byte)64); if (!currentTokenLine.Tokens[1].GetProperty(EnumTokenProperties.RegisterNumber, out rA) || currentTokenLine.Tokens[1].TokenType != EnumTokenTypes.Register) { throw new AssemblerException(EnumAssemblerStages.BinaryWriter, "Token is not expected register value."); } if (!currentTokenLine.Tokens[2].GetProperty(EnumTokenProperties.RegisterNumber, out rB) || currentTokenLine.Tokens[2].TokenType != EnumTokenTypes.AddressRegister) { throw new AssemblerException(EnumAssemblerStages.BinaryWriter, "Token is not expected address register value."); } //someProperty represents the offset of destination memory address if (!currentTokenLine.Tokens[2].GetProperty(EnumTokenProperties.ImmediateValue, out someProperty)) { someProperty = 0; } tmpInt = rA << 4; tmpInt = tmpInt | rB; filestream.Write((byte)tmpInt); tmpInt = 0; someBytes = BitConverter.GetBytes((uint)someProperty); WriteBytes(someBytes, filestream); break; case EnumInstructions.mrmov: //0x50<rA><rB><D> Where D is offset to address in register A (rA). if (currentTokenLine.Tokens.Length != 3) { throw new AssemblerException(EnumAssemblerStages.BinaryWriter, "Not enough tokens in MRMOV instruction."); } filestream.Write((byte)80); if (!currentTokenLine.Tokens[1].GetProperty(EnumTokenProperties.RegisterNumber, out rA) || currentTokenLine.Tokens[1].TokenType != EnumTokenTypes.AddressRegister) { throw new AssemblerException(EnumAssemblerStages.BinaryWriter, "Token is not expected address register value."); } if (!currentTokenLine.Tokens[2].GetProperty(EnumTokenProperties.RegisterNumber, out rB) || currentTokenLine.Tokens[2].TokenType != EnumTokenTypes.Register) { throw new AssemblerException(EnumAssemblerStages.BinaryWriter, "Token is not expected immediate value."); } //someProperty represents the offset of destination memory address if (!currentTokenLine.Tokens[1].GetProperty(EnumTokenProperties.ImmediateValue, out someProperty)) { someProperty = 0; } tmpInt = rA << 4; tmpInt = tmpInt | rB; filestream.Write((byte)tmpInt); tmpInt = 0; someBytes = BitConverter.GetBytes((uint)someProperty); WriteBytes(someBytes, filestream); break; case EnumInstructions.add: if (currentTokenLine.Tokens.Length != 3) { throw new AssemblerException(EnumAssemblerStages.BinaryWriter, "Not enough tokens in ADD instruction."); } filestream.Write((byte)96); if (!currentTokenLine.Tokens[1].GetProperty(EnumTokenProperties.RegisterNumber, out rA) || currentTokenLine.Tokens[1].TokenType != EnumTokenTypes.Register) { throw new AssemblerException(EnumAssemblerStages.BinaryWriter, "Token is not expected register value."); } if (!currentTokenLine.Tokens[2].GetProperty(EnumTokenProperties.RegisterNumber, out rB) || currentTokenLine.Tokens[2].TokenType != EnumTokenTypes.Register) { throw new AssemblerException(EnumAssemblerStages.BinaryWriter, "Token is not expected register value."); } tmpInt = rA << 4; tmpInt = tmpInt | rB; filestream.Write((byte)tmpInt); tmpInt = 0; break; case EnumInstructions.sub: if (currentTokenLine.Tokens.Length != 3) { throw new AssemblerException(EnumAssemblerStages.BinaryWriter, "Not enough tokens in SUB instruction."); } filestream.Write((byte)(96 + 1)); if (!currentTokenLine.Tokens[1].GetProperty(EnumTokenProperties.RegisterNumber, out rA) || currentTokenLine.Tokens[1].TokenType != EnumTokenTypes.Register) { throw new AssemblerException(EnumAssemblerStages.BinaryWriter, "Token is not expected register value."); } if (!currentTokenLine.Tokens[2].GetProperty(EnumTokenProperties.RegisterNumber, out rB) || currentTokenLine.Tokens[2].TokenType != EnumTokenTypes.Register) { throw new AssemblerException(EnumAssemblerStages.BinaryWriter, "Token is not expected register value."); } tmpInt = rA << 4; tmpInt = tmpInt | rB; filestream.Write((byte)tmpInt); tmpInt = 0; break; case EnumInstructions.and: if (currentTokenLine.Tokens.Length != 3) { throw new AssemblerException(EnumAssemblerStages.BinaryWriter, "Not enough tokens in AND instruction."); } filestream.Write((byte)(96 + 2)); if (!currentTokenLine.Tokens[1].GetProperty(EnumTokenProperties.RegisterNumber, out rA) || currentTokenLine.Tokens[1].TokenType != EnumTokenTypes.Register) { throw new AssemblerException(EnumAssemblerStages.BinaryWriter, "Token is not expected register value."); } if (!currentTokenLine.Tokens[2].GetProperty(EnumTokenProperties.RegisterNumber, out rB) || currentTokenLine.Tokens[2].TokenType != EnumTokenTypes.Register) { throw new AssemblerException(EnumAssemblerStages.BinaryWriter, "Token is not expected register value."); } tmpInt = rA << 4; tmpInt = tmpInt | rB; filestream.Write((byte)tmpInt); tmpInt = 0; break; case EnumInstructions.xor: if (currentTokenLine.Tokens.Length != 3) { throw new AssemblerException(EnumAssemblerStages.BinaryWriter, "Not enough tokens in XOR instruction."); } filestream.Write((byte)(96 + 3)); if (!currentTokenLine.Tokens[1].GetProperty(EnumTokenProperties.RegisterNumber, out rA) || currentTokenLine.Tokens[1].TokenType != EnumTokenTypes.Register) { throw new AssemblerException(EnumAssemblerStages.BinaryWriter, "Token is not expected register value."); } if (!currentTokenLine.Tokens[2].GetProperty(EnumTokenProperties.RegisterNumber, out rB) || currentTokenLine.Tokens[2].TokenType != EnumTokenTypes.Register) { throw new AssemblerException(EnumAssemblerStages.BinaryWriter, "Token is not expected register value."); } tmpInt = rA << 4; tmpInt = tmpInt | rB; filestream.Write((byte)tmpInt); tmpInt = 0; break; case EnumInstructions.imul: if (currentTokenLine.Tokens.Length != 3) { throw new AssemblerException(EnumAssemblerStages.BinaryWriter, "Not enough tokens in IMUL instruction."); } filestream.Write((byte)(96 + 4)); if (!currentTokenLine.Tokens[1].GetProperty(EnumTokenProperties.RegisterNumber, out rA) || currentTokenLine.Tokens[1].TokenType != EnumTokenTypes.Register) { throw new AssemblerException(EnumAssemblerStages.BinaryWriter, "Token is not expected register value."); } if (!currentTokenLine.Tokens[2].GetProperty(EnumTokenProperties.RegisterNumber, out rB) || currentTokenLine.Tokens[2].TokenType != EnumTokenTypes.Register) { throw new AssemblerException(EnumAssemblerStages.BinaryWriter, "Token is not expected register value."); } tmpInt = rA << 4; tmpInt = tmpInt | rB; filestream.Write((byte)tmpInt); tmpInt = 0; break; case EnumInstructions.jmp: //0x7<fn><Dest> if (currentTokenLine.Tokens.Length != 2) { throw new AssemblerException(EnumAssemblerStages.BinaryWriter, "Not enough tokens in JMP instruction."); } filestream.Write((byte)112); if (!currentTokenLine.Tokens[1].GetProperty(EnumTokenProperties.ImmediateValue, out someProperty) || currentTokenLine.Tokens[1].TokenType != EnumTokenTypes.Immediate) { throw new AssemblerException(EnumAssemblerStages.BinaryWriter, "Token is not expected immediate value."); } someBytes = BitConverter.GetBytes((uint)someProperty); WriteBytes(someBytes, filestream); break; case EnumInstructions.jle: if (currentTokenLine.Tokens.Length != 2) { throw new AssemblerException(EnumAssemblerStages.BinaryWriter, "Not enough tokens in JLE instruction."); } filestream.Write((byte)(112 + 1)); if (!currentTokenLine.Tokens[1].GetProperty(EnumTokenProperties.ImmediateValue, out someProperty) || currentTokenLine.Tokens[1].TokenType != EnumTokenTypes.Immediate) { throw new AssemblerException(EnumAssemblerStages.BinaryWriter, "Token is not expected immediate value."); } someBytes = BitConverter.GetBytes((uint)someProperty); WriteBytes(someBytes, filestream); break; case EnumInstructions.jl: if (currentTokenLine.Tokens.Length != 2) { throw new AssemblerException(EnumAssemblerStages.BinaryWriter, "Not enough tokens in JL instruction."); } filestream.Write((byte)(112 + 2)); if (!currentTokenLine.Tokens[1].GetProperty(EnumTokenProperties.ImmediateValue, out someProperty) || currentTokenLine.Tokens[1].TokenType != EnumTokenTypes.Immediate) { throw new AssemblerException(EnumAssemblerStages.BinaryWriter, "Token is not expected immediate value."); } someBytes = BitConverter.GetBytes((uint)someProperty); WriteBytes(someBytes, filestream); break; case EnumInstructions.je: if (currentTokenLine.Tokens.Length != 2) { throw new AssemblerException(EnumAssemblerStages.BinaryWriter, "Not enough tokens in JE instruction."); } filestream.Write((byte)(112 + 3)); if (!currentTokenLine.Tokens[1].GetProperty(EnumTokenProperties.ImmediateValue, out someProperty) || currentTokenLine.Tokens[1].TokenType != EnumTokenTypes.Immediate) { throw new AssemblerException(EnumAssemblerStages.BinaryWriter, "Token is not expected immediate value."); } someBytes = BitConverter.GetBytes((uint)someProperty); WriteBytes(someBytes, filestream); break; case EnumInstructions.jne: if (currentTokenLine.Tokens.Length != 2) { throw new AssemblerException(EnumAssemblerStages.BinaryWriter, "Not enough tokens in JNE instruction."); } filestream.Write((byte)(112 + 4)); if (!currentTokenLine.Tokens[1].GetProperty(EnumTokenProperties.ImmediateValue, out someProperty) || currentTokenLine.Tokens[1].TokenType != EnumTokenTypes.Immediate) { throw new AssemblerException(EnumAssemblerStages.BinaryWriter, "Token is not expected immediate value."); } someBytes = BitConverter.GetBytes((uint)someProperty); WriteBytes(someBytes, filestream); break; case EnumInstructions.jge: if (currentTokenLine.Tokens.Length != 2) { throw new AssemblerException(EnumAssemblerStages.BinaryWriter, "Not enough tokens in JGE instruction."); } filestream.Write((byte)(112 + 5)); if (!currentTokenLine.Tokens[1].GetProperty(EnumTokenProperties.ImmediateValue, out someProperty) || currentTokenLine.Tokens[1].TokenType != EnumTokenTypes.Immediate) { throw new AssemblerException(EnumAssemblerStages.BinaryWriter, "Token is not expected immediate value."); } someBytes = BitConverter.GetBytes((uint)someProperty); WriteBytes(someBytes, filestream); break; case EnumInstructions.jg: if (currentTokenLine.Tokens.Length != 2) { throw new AssemblerException(EnumAssemblerStages.BinaryWriter, "Not enough tokens in JG instruction."); } filestream.Write((byte)(112 + 6)); if (!currentTokenLine.Tokens[1].GetProperty(EnumTokenProperties.ImmediateValue, out someProperty) || currentTokenLine.Tokens[1].TokenType != EnumTokenTypes.Immediate) { throw new AssemblerException(EnumAssemblerStages.BinaryWriter, "Token is not expected immediate value."); } someBytes = BitConverter.GetBytes((uint)someProperty); WriteBytes(someBytes, filestream); break; case EnumInstructions.call: //0x80<Dest> if (currentTokenLine.Tokens.Length != 2) { throw new AssemblerException(EnumAssemblerStages.BinaryWriter, "Not enough tokens in CALL instruction."); } filestream.Write((byte)128); if (!currentTokenLine.Tokens[1].GetProperty(EnumTokenProperties.ImmediateValue, out someProperty) || currentTokenLine.Tokens[1].TokenType != EnumTokenTypes.Immediate) { throw new AssemblerException(EnumAssemblerStages.BinaryWriter, "Token is not expected immediate value."); } someBytes = BitConverter.GetBytes((uint)someProperty); WriteBytes(someBytes, filestream); break; case EnumInstructions.ret: if (currentTokenLine.Tokens.Length != 1) { throw new AssemblerException(EnumAssemblerStages.BinaryWriter, "Not enough tokens in RET instruction."); } filestream.Write((byte)144); break; case EnumInstructions.interrupt: if (currentTokenLine.Tokens.Length != 2) { throw new AssemblerException(EnumAssemblerStages.BinaryWriter, "Not enough tokens in Interrupt instruction."); } filestream.Write((byte)240); if (!currentTokenLine.Tokens[1].GetProperty(EnumTokenProperties.ImmediateValue, out someProperty) || currentTokenLine.Tokens[1].TokenType != EnumTokenTypes.Immediate) { throw new AssemblerException(EnumAssemblerStages.BinaryWriter, "Token is not expected immediate value."); } someBytes = BitConverter.GetBytes((uint)someProperty); WriteBytes(someBytes, filestream); break; case EnumInstructions.push: case EnumInstructions.pop: throw new AssemblerException(EnumAssemblerStages.BinaryWriter, "Push/Pop instructions not implemented!"); default: #if DEBUG #else throw new AssemblerException(EnumAssemblerStages.BinaryWriter, "File writer does not support this instruction yet."); #endif break; } } }