private List <ushort> AssembleNOP(List <string> param, OpcodeFlag opcodeFlag, ParserState state) { Guard.RequireParamCountExact(param, 0); return(new List <ushort> { 0x2080 }); // LOD R0, R0 }
private List <ushort> AssembleLOD(List <string> param, OpcodeFlag opcodeFlag, ParserState state) { Guard.RequireParamCountExact(param, 2); Guard.RequireOpcodeFlag(opcodeFlag, new[] { OpcodeFlag.BitWidth8, OpcodeFlag.BitWidth16 }); return(state.Parser.AssembleALU(0x0080, param[0], param[1], opcodeFlag, state)); }
public static void RequireOpcodeFlag(OpcodeFlag flag, OpcodeFlag[] acceptable) { for (int i = 0; i < acceptable.Length; i++) if (flag.HasFlag(acceptable[i])) return; throw new Exception($"Opcode flag of '{flag}' is unsupported for this opcode"); }
private List <ushort> AssembleSLP(List <string> param, OpcodeFlag opcodeFlag, ParserState state) { Guard.RequireParamCountExact(param, 0); Guard.RequireOpcodeFlag(opcodeFlag, new[] { OpcodeFlag.BitWidth16 }); return(new List <ushort> { 0x04B4 }); }
private List <ushort> AssembleJSR(List <string> param, OpcodeFlag opcodeFlag, ParserState state) { if (opcodeFlag.HasFlag(OpcodeFlag.FarJump)) { Guard.RequireParamCountMinMax(param, 1, 2); // allow two params for immediate far jump. return(state.Parser.AssembleJMI(0x01B9, param[0], param.Count == 2 ? param[1] : null, state)); } Guard.RequireParamCountExact(param, 1); return(state.Parser.AssembleJMI(0x00B9, param[0], null, state)); }
private List <ushort> AssembleJMP(List <string> param, OpcodeFlag opcodeFlag, ParserState state) { Guard.RequireOpcodeFlag(opcodeFlag, new[] { OpcodeFlag.BitWidth16 }); if (opcodeFlag.HasFlag(OpcodeFlag.FarJump)) { Guard.RequireParamCountMinMax(param, 1, 2); return(state.Parser.AssembleJMI(0x01B8, param[0], param.Count == 2 ? param[1] : null, state)); } Guard.RequireParamCountExact(param, 1); return(state.Parser.AssembleJMI(0x00B8, param[0], null, state)); }
public static void RequireOpcodeFlag(OpcodeFlag flag, OpcodeFlag[] acceptable) { for (int i = 0; i < acceptable.Length; i++) { if (flag.HasFlag(acceptable[i])) { return; } } throw new Exception($"Opcode flag of '{flag}' is unsupported for this opcode"); }
private List <ushort> AssembleRTS(List <string> param, OpcodeFlag opcodeFlag, ParserState state) { if (opcodeFlag.HasFlag(OpcodeFlag.FarJump)) { return(new List <ushort> { 0x01B4 }); // RTS.F } return(new List <ushort> { 0x00B4 }); // RTS }
private List <ushort> AssembleSTO(List <string> param, OpcodeFlag opcodeFlag, ParserState state) { Guard.RequireParamCountExact(param, 2); Guard.RequireOpcodeFlag(opcodeFlag, new[] { OpcodeFlag.BitWidth8, OpcodeFlag.BitWidth16 }); List <ushort> code = state.Parser.AssembleALU(0x0088, param[0], param[1], opcodeFlag, state); if ((code[0] & 0xF000) == 0x1000) // no sto register - should lod r0, r1, not sto r0, r1 { throw new Exception("Store register instructions not supported"); } if ((code[0] & 0xFE00) == 0x0000) // no sto immediate. { throw new Exception("Store immediate instructions not supported"); } return(code); }
private bool ParseOpcodeFlag(string value, ref OpcodeFlag opcodeFlag) { switch (value) { case "8": opcodeFlag &= ~OpcodeFlag.BitWidthsAll; opcodeFlag |= OpcodeFlag.BitWidth8; return(true); case "16": opcodeFlag &= ~OpcodeFlag.BitWidthsAll; opcodeFlag |= OpcodeFlag.BitWidth16; return(true); case "f": opcodeFlag |= OpcodeFlag.FarJump; return(true); default: return(false); } }
private List <ushort> AssembleSTX(List <string> param, OpcodeFlag opcodeFlag, ParserState state) { Guard.RequireParamCountExact(param, 1); Param p1 = ParseParam(param[0]); if (p1.AddressingMode != AddressingMode.Immediate) { throw new Exception("stx instructions expect a single immediate parameter"); } int p1i = (short)p1.ImmediateWordShort; if (p1i < sbyte.MinValue || p1i > sbyte.MaxValue) { throw new Exception("stx instructions accept a single immediate parameter with values between -128 and +127"); } return(new List <ushort> { (ushort)(0x00BB | (((sbyte)p1i) << 8)) }); }
private List<ushort> AssembleRTS(List<string> param, OpcodeFlag opcodeFlag, ParserState state) { if (opcodeFlag.HasFlag(OpcodeFlag.FarJump)) { return new List<ushort> { 0x01B4 }; // RTS.F } return new List<ushort> { 0x00B4 }; // RTS }
private List<ushort> AssemblePSH(List<string> param, OpcodeFlag opcodeFlag, ParserState state) { Guard.RequireParamCountMinMax(param, 1, 13); Guard.RequireOpcodeFlag(opcodeFlag, new[] { OpcodeFlag.BitWidth16 }); return state.Parser.AssembleSTK(0x00B0, param, false); }
private List <ushort> AssembleSET(List <string> param, OpcodeFlag opcodeFlag, ParserState state) { Guard.RequireParamCountExact(param, 2); return(state.Parser.AssembleSEI(0x00AC, param[0], param[1])); }
private void AssembleLine(int lineIndex, string line, ParserState state) { line = line.Trim(); if (LineSearch.MatchLabel(line)) { if (!state.Scopes.IsScopeOpen) // global scope { while ((state.Code.Count % m_Alignment) != 0) { state.Code.Add(0x00); } } // parse label and determine if there is anything else to parse on this line. int remaiderLineContentIndex = ParseLabel(line, state); if (remaiderLineContentIndex <= 0) { return; } // if there is something left to parse, trim it and then interpret it as its own line. line = line.Remove(0, remaiderLineContentIndex).Trim(); if (line.Length == 0) { return; } } List <string> tokens = Tokenize(line); string opcode = tokens[0]; opcode = opcode.Trim(); if (ParsePragma(lineIndex, line, opcode, tokens, state)) { // Successfully parsed a pragma, no need to continue with this line. return; } OpcodeFlag opcodeFlag = OpcodeFlag.BitWidth16; // default to operating on 16 bits // Look for flags on operands (xxx.yyy, where y is the flag). if (opcode.IndexOf('.') != -1 && (opcode.IndexOf('.') > 1) && (opcode.Length - opcode.IndexOf('.') - 1 > 0)) { // opcode has a flag string flag = opcode.Substring(opcode.IndexOf('.') + 1); if (!ParseOpcodeFlag(flag, ref opcodeFlag)) { throw new Exception($"Unknown bit width flag '{flag}' for instruction '{line}'"); } opcode = opcode.Substring(0, opcode.IndexOf('.')); } // get the assembler for this opcode. If no assembler exists, throw error. Func <List <string>, OpcodeFlag, ParserState, List <ushort> > assembler; if (m_Opcodes.ContainsKey(opcode.ToLowerInvariant())) { assembler = m_Opcodes[opcode.ToLowerInvariant()]; } else { throw new Exception($"Undefined instruction in line \"{line}\""); } // get the parameters List <string> param = new List <string>(); for (int i = 1; i < tokens.Count; i++) { param.Add(tokens[i].Trim()); } // pass the params to the opcode's assembler. If no output, throw error. List <ushort> code = assembler(param, opcodeFlag, state); if (code == null) { throw new Exception($"Error assembling line {line}"); } // add the output of the assembler to the machine code output. for (int i = 0; i < code.Count; i++) { ushort this_opcode = code[i]; state.Code.Add((byte)(this_opcode & 0x00ff)); state.Code.Add((byte)((this_opcode & 0xff00) >> 8)); } }
private List<ushort> AssembleSUB(List<string> param, OpcodeFlag opcodeFlag, ParserState state) { Guard.RequireParamCountExact(param, 2); Guard.RequireOpcodeFlag(opcodeFlag, state.Parser.flag8or16); return state.Parser.AssembleALU(0x0018, param[0], param[1], opcodeFlag, state); }
private List<ushort> AssembleSTO(List<string> param, OpcodeFlag opcodeFlag, ParserState state) { Guard.RequireParamCountExact(param, 2); Guard.RequireOpcodeFlag(opcodeFlag, new[] { OpcodeFlag.BitWidth8, OpcodeFlag.BitWidth16 }); List<ushort> code = state.Parser.AssembleALU(0x0088, param[0], param[1], opcodeFlag, state); if ((code[0] & 0xF000) == 0x1000) // no sto register - should lod r0, r1, not sto r0, r1 throw new Exception("Store register instructions not supported"); if ((code[0] & 0xFE00) == 0x0000) // no sto immediate. throw new Exception("Store immediate instructions not supported"); return code; }
private List<ushort> AssembleSET(List<string> param, OpcodeFlag opcodeFlag, ParserState state) { Guard.RequireParamCountExact(param, 2); return state.Parser.AssembleSEI(0x00AC, param[0], param[1]); }
private bool ParseOpcodeFlag(string value, ref OpcodeFlag opcodeFlag) { switch (value) { case "8": opcodeFlag &= ~OpcodeFlag.BitWidthsAll; opcodeFlag |= OpcodeFlag.BitWidth8; return true; case "16": opcodeFlag &= ~OpcodeFlag.BitWidthsAll; opcodeFlag |= OpcodeFlag.BitWidth16; return true; case "f": opcodeFlag |= OpcodeFlag.FarJump; return true; default: return false; } }
private List <ushort> AssembleMDI(List <string> param, OpcodeFlag opcodeFlag, ParserState state) { Guard.RequireParamCountExact(param, 2); Guard.RequireOpcodeFlag(opcodeFlag, state.Parser.flag8or16); return(state.Parser.AssembleALU(0x0058, param[0], param[1], opcodeFlag, state)); }
private List <ushort> AssembleALU(ushort opcode, string param1, string param2, OpcodeFlag opcodeFlag, ParserState state) { Param p1 = ParseParam(param1); Param p2 = ParseParam(param2); if (p1.AddressingMode != AddressingMode.Register) { throw new Exception("ALU instruction first operand must be a general purpose register"); } ushort addressingmode = 0x0000; switch (p2.AddressingMode) { case AddressingMode.None: return(null); case AddressingMode.Immediate: // .000 000e Immediate LOD R0, $1234 +1m // special case: alu.8 immediate with value greater than $FF should raise a warning... if (opcodeFlag == OpcodeFlag.BitWidth8 && p2.ImmediateWordShort >= 256) { throw new Exception("8-bit load operation with an immediate value of greater than 8 bits"); } addressingmode = 0x0000; if (p2.UsesExtraDataSegment) { throw new Exception("Immediate addressing mode cannot use extra data segment"); } break; case AddressingMode.Absolute: // s000 001e Absolute LOD R0, [$1234] +2m addressingmode = 0x0200; if (p2.UsesExtraDataSegment) { addressingmode |= 0x8000; } break; case AddressingMode.ControlRegister: // .000 1ppp Control register LOD R0, PS // can't use eightbit mode with proc regs... if (opcodeFlag.HasFlag(OpcodeFlag.BitWidth8)) { throw new Exception("ALU instructions with status register operands do not support 8-bit mode"); } if (p2.UsesExtraDataSegment) { throw new Exception("Control register addressing mode cannot use extra data segment"); } addressingmode = (ushort)(0x0800 | ((p2.RegisterIndex & 0x0007) << 8)); p2.RegisterIndex = 0; // must wipe out control register index, as it is used later in this subroutine. break; case AddressingMode.Register: // .001 rrre Register LOD R0, r1 addressingmode = 0x1000; if (p2.UsesExtraDataSegment) { throw new Exception("Register addressing mode cannot use extra data segment"); } break; case AddressingMode.Indirect: // s010 rrre Indirect LOD R0, [r1] +1m addressingmode = 0x2000; if (p2.UsesExtraDataSegment) { addressingmode |= 0x8000; } break; case AddressingMode.IndirectOffset: // s011 rrre Indirect Offset LOD R0, [r1,$1234] +2m addressingmode = 0x3000; if (p2.UsesExtraDataSegment) { addressingmode |= 0x8000; } break; case AddressingMode.IndirectIndexed: // s1ii rrre Indirect Indexed LOD R0, [r1,i2] +1m int index_register = (p2.RegisterIndex & 0x0300) << 4; addressingmode = (ushort)(0x4000 | index_register); if (p2.UsesExtraDataSegment) { addressingmode |= 0x8000; } break; default: throw new Exception("Unknown addressing mode"); } ushort bitwidth = 0x0000; if (opcodeFlag == OpcodeFlag.BitWidth8) { bitwidth = 0x0100; } // FEDC BA98 7654 3210 // AAAA rrrE OOOO ORRR m_Code.Clear(); m_Code.Add((ushort)(opcode | addressingmode | bitwidth | (p1.RegisterIndex & 0x0007) | ((p2.RegisterIndex & 0x0007) << 9))); if (p2.HasLabel) { state.Labels.Add((ushort)(state.Code.Count + m_Code.Count * c_InstructionSize), p2.Label); m_Code.Add(0xDEAD); } else if (p2.HasImmediateWord) { m_Code.Add(p2.ImmediateWordShort); } return(m_Code); }
private List <ushort> AssembleCLF(List <string> param, OpcodeFlag opcodeFlag, ParserState state) { Guard.RequireParamCountMinMax(param, 1, 4); Guard.RequireOpcodeFlag(opcodeFlag, new[] { OpcodeFlag.BitWidth16 }); return(state.Parser.AssembleFLG(0x00AF, param)); }
private List <ushort> AssemblePOP(List <string> param, OpcodeFlag opcodeFlag, ParserState state) { Guard.RequireParamCountMinMax(param, 1, 13); Guard.RequireOpcodeFlag(opcodeFlag, new[] { OpcodeFlag.BitWidth16 }); return(state.Parser.AssembleSTK(0x00B2, param, true)); }
private List <ushort> AssembleSSG(List <string> param, OpcodeFlag opcodeFlag, ParserState state) { Guard.RequireParamCountExact(param, 1); return(state.Parser.AssembleMMU(0x01B5, param[0], state)); }
private List<ushort> AssembleSBI(List<string> param, OpcodeFlag opcodeFlag, ParserState state) { Guard.RequireParamCountExact(param, 2); Guard.RequireOpcodeFlag(opcodeFlag, new[] { OpcodeFlag.BitWidth16 }); return state.Parser.AssembleIMM(0x00B7, param[0], param[1]); }
private List<ushort> AssembleALU(ushort opcode, string param1, string param2, OpcodeFlag opcodeFlag, ParserState state) { Param p1 = ParseParam(param1); Param p2 = ParseParam(param2); if (p1.AddressingMode != AddressingMode.Register) { throw new Exception("ALU instruction first operand must be a general purpose register"); } ushort addressingmode = 0x0000; switch (p2.AddressingMode) { case AddressingMode.None: return null; case AddressingMode.Immediate: // .000 000e Immediate LOD R0, $1234 +1m // special case: alu.8 immediate with value greater than $FF should raise a warning... if (opcodeFlag == OpcodeFlag.BitWidth8 && p2.ImmediateWordShort >= 256) { throw new Exception("8-bit load operation with an immediate value of greater than 8 bits"); } addressingmode = 0x0000; if (p2.UsesExtraDataSegment) throw new Exception("Immediate addressing mode cannot use extra data segment"); break; case AddressingMode.Absolute: // s000 001e Absolute LOD R0, [$1234] +2m addressingmode = 0x0200; if (p2.UsesExtraDataSegment) addressingmode |= 0x8000; break; case AddressingMode.ControlRegister: // .000 1ppp Control register LOD R0, PS // can't use eightbit mode with proc regs... if (opcodeFlag.HasFlag(OpcodeFlag.BitWidth8)) throw new Exception("ALU instructions with status register operands do not support 8-bit mode"); if (p2.UsesExtraDataSegment) throw new Exception("Control register addressing mode cannot use extra data segment"); addressingmode = (ushort)(0x0800 | ((p2.RegisterIndex & 0x0007) << 8)); p2.RegisterIndex = 0; // must wipe out control register index, as it is used later in this subroutine. break; case AddressingMode.Register: // .001 rrre Register LOD R0, r1 addressingmode = 0x1000; if (p2.UsesExtraDataSegment) throw new Exception("Register addressing mode cannot use extra data segment"); break; case AddressingMode.Indirect: // s010 rrre Indirect LOD R0, [r1] +1m addressingmode = 0x2000; if (p2.UsesExtraDataSegment) addressingmode |= 0x8000; break; case AddressingMode.IndirectOffset: // s011 rrre Indirect Offset LOD R0, [r1,$1234] +2m addressingmode = 0x3000; if (p2.UsesExtraDataSegment) addressingmode |= 0x8000; break; case AddressingMode.IndirectIndexed: // s1ii rrre Indirect Indexed LOD R0, [r1,i2] +1m int index_register = (p2.RegisterIndex & 0x0300) << 4; addressingmode = (ushort)(0x4000 | index_register); if (p2.UsesExtraDataSegment) addressingmode |= 0x8000; break; default: throw new Exception("Unknown addressing mode"); } ushort bitwidth = 0x0000; if (opcodeFlag == OpcodeFlag.BitWidth8) bitwidth = 0x0100; // FEDC BA98 7654 3210 // AAAA rrrE OOOO ORRR m_Code.Clear(); m_Code.Add((ushort)(opcode | addressingmode | bitwidth | (p1.RegisterIndex & 0x0007) | ((p2.RegisterIndex & 0x0007) << 9))); if (p2.HasLabel) { state.Labels.Add((ushort)(state.Code.Count + m_Code.Count * c_InstructionSize), p2.Label); m_Code.Add(0xDEAD); } else if (p2.HasImmediateWord) { m_Code.Add(p2.ImmediateWordShort); } return m_Code; }
private List<ushort> AssembleSEF(List<string> param, OpcodeFlag opcodeFlag, ParserState state) { Guard.RequireParamCountMinMax(param, 1, 4); Guard.RequireOpcodeFlag(opcodeFlag, new[] { OpcodeFlag.BitWidth16 }); return state.Parser.AssembleFLG(0x00AE, param); }
private List<ushort> AssembleJMP(List<string> param, OpcodeFlag opcodeFlag, ParserState state) { Guard.RequireOpcodeFlag(opcodeFlag, new[] { OpcodeFlag.BitWidth16 }); if (opcodeFlag.HasFlag(OpcodeFlag.FarJump)) { Guard.RequireParamCountMinMax(param, 1, 2); return state.Parser.AssembleJMI(0x01B8, param[0], param.Count == 2 ? param[1] : null, state); } Guard.RequireParamCountExact(param, 1); return state.Parser.AssembleJMI(0x00B8, param[0], null, state); }
private List<ushort> AssembleSSG(List<string> param, OpcodeFlag opcodeFlag, ParserState state) { Guard.RequireParamCountExact(param, 1); return state.Parser.AssembleMMU(0x01B5, param[0], state); }
private List<ushort> AssembleJSR(List<string> param, OpcodeFlag opcodeFlag, ParserState state) { if (opcodeFlag.HasFlag(OpcodeFlag.FarJump)) { Guard.RequireParamCountMinMax(param, 1, 2); // allow two params for immediate far jump. return state.Parser.AssembleJMI(0x01B9, param[0], param.Count == 2 ? param[1] : null, state); } Guard.RequireParamCountExact(param, 1); return state.Parser.AssembleJMI(0x00B9, param[0], null, state); }
private List<ushort> AssembleSTX(List<string> param, OpcodeFlag opcodeFlag, ParserState state) { Guard.RequireParamCountExact(param, 1); Param p1 = ParseParam(param[0]); if (p1.AddressingMode != AddressingMode.Immediate) throw new Exception("stx instructions expect a single immediate parameter"); int p1i = (short)p1.ImmediateWordShort; if (p1i < sbyte.MinValue || p1i > sbyte.MaxValue) throw new Exception("stx instructions accept a single immediate parameter with values between -128 and +127"); return new List<ushort> { (ushort)(0x00BB | (((sbyte)p1i) << 8)) }; }
private List<ushort> AssembleLOD(List<string> param, OpcodeFlag opcodeFlag, ParserState state) { Guard.RequireParamCountExact(param, 2); Guard.RequireOpcodeFlag(opcodeFlag, new[] { OpcodeFlag.BitWidth8, OpcodeFlag.BitWidth16 }); return state.Parser.AssembleALU(0x0080, param[0], param[1], opcodeFlag, state); }
private List<ushort> AssembleSWI(List<string> param, OpcodeFlag opcodeFlag, ParserState state) { Guard.RequireParamCountExact(param, 0); Guard.RequireOpcodeFlag(opcodeFlag, new[] { OpcodeFlag.BitWidth16 }); return new List<ushort> { 0x03B4 }; }
private List<ushort> AssembleNOP(List<string> param, OpcodeFlag opcodeFlag, ParserState state) { Guard.RequireParamCountExact(param, 0); return new List<ushort> { 0x2080 }; // LOD R0, R0 }
private List<ushort> AssembleBVS(List<string> param, OpcodeFlag opcodeFlag, ParserState state) { Guard.RequireParamCountExact(param, 1); Guard.RequireOpcodeFlag(opcodeFlag, new[] { OpcodeFlag.BitWidth16 }); return state.Parser.AssembleBRA(0x0097, param[0], state); }
private List <ushort> AssembleHWQ(List <string> param, OpcodeFlag opcodeFlag, ParserState state) { Guard.RequireParamCountExact(param, 1); Guard.RequireOpcodeFlag(opcodeFlag, new[] { OpcodeFlag.BitWidth16 }); return(state.Parser.AssembleHWI(0x00BA, param[0])); }