public static void Assemble(string[] lines, IOutput output) { Beboputer.Bebop.Reset(); bool errors = false; for (int i = 0; i < lines.Length; ++i) { //FOO: .EQU $FF # this is a comment //FOO: .BYTE $FF,$FF,$FF # this is a comment //FOO: LDA $FF # this is a comment //{LABEL} {DIR|INS} {UINT|OPERAND} {COMMENT} try { string[] parts = lines[i].Split((char[])null, StringSplitOptions.RemoveEmptyEntries); int p = 0; string label = null; string comment = null; Line line = null; if (parts.Length > 0 && parts[0].Length > 0) { //label if (char.IsLetter(parts[p][0]) || parts[p][0] == '_') { if (parts[p][parts[p].Length - 1] == ':') { label = parts[p].Substring(0, parts[p].Length - 1); ++p; } } if (parts[p][0] == '.') //directive { if (parts[p].Length == 1) { throw new InvalidOperationException("can't parse line " + i + " {" + lines[i] + "}"); } string dir = parts[p].Substring(1, parts[p].Length - 1); if (Beboputer.Directives.ContainsKey(dir)) { ++p; string parm = null; if (p < parts.Length) { if (parts[p][0] != '#') { parm = parts[p]; ++p; } } Directive directive = (Directive)Activator.CreateInstance(Beboputer.Directives[dir]); if (parm != null) { directive.Value = UInt.Parse(parm); } line = directive; } else { throw new InvalidOperationException("unknown directive line " + i + " {" + lines[i] + "}"); } } else if (Beboputer.Instructions.ContainsKey(parts[p])) //instruction { string ins = parts[p]; ++p; string parm = null; if (p < parts.Length) { if (parts[p][0] != '#') { parm = parts[p]; ++p; } } Instruction instruction = (Instruction)Activator.CreateInstance(Beboputer.Instructions[ins]); if (parm != null) { instruction.Operand = Operand.Parse(parm); } line = instruction; } else if (parts[p][0] == '#') //comment only line { //this is okay } else { throw new InvalidOperationException("unknown instruction line " + i + " {" + lines[i] + "}"); } if (p < parts.Length) { if (parts[p][0] == '#') { parts[p] = parts[p].Substring(1, parts[p].Length - 1); comment = ""; for (int j = p; j < (parts.Length); ++j) { if (comment != "") { comment += " "; } comment += parts[j]; } } else { throw new InvalidOperationException("unknown syntax line " + i + " {" + lines[i] + "}"); } } } if (line == null) { if (comment != null) { line = new Comment(); } else { if (lines[i].Trim().Length != 0) { throw new InvalidOperationException("can't parse line " + i + " {" + lines[i] + "}"); } line = new Line(); } } line.Text = lines[i]; if (line is Statement) { ((Statement)line).Label = label; ((Statement)line).Comment = comment; if (label != null) { if (Beboputer.Bebop.Labels.ContainsKey(label)) { throw new InvalidOperationException("label {" + label + "} already exists line " + i + " {" + lines[i] + "}"); } Beboputer.Bebop.Labels.Add(label, (Statement)line); } } else { if (label != null) { throw new InvalidOperationException("label invalid for line " + i + " {" + lines[i] + "}"); } } Beboputer.Bebop.Lines.Add(line); output.Out(i + ":\t" + line.ToString()); } catch (Exception ex) { errors = true; output.Out("ERROR: " + i + ":\t" + ex.Message); } } //load ushort address = 0; foreach (Line line in Beboputer.Bebop.Lines) { if (line is ORG) { address = ((U16)((ORG)line).Value).Read(); } else if (line is Instruction) { Instruction ins = (Instruction)line; byte opcode; if (Beboputer.Opcodes.ContainsKey(Instruction.GetOpcodeKey(ins.Mnemonic, ins.AddressingMode))) { opcode = Beboputer.Opcodes[Instruction.GetOpcodeKey(ins.Mnemonic, ins.AddressingMode)]; } else { throw new InvalidOperationException("no opcode for {" + ins.ToString() + "}"); } Beboputer.Bebop.RAM.Write(address, opcode); ++address; if (ins.Operand != null) { if (ins.Operand.Value is Literal) { Literal l = (Literal)ins.Operand.Value; if (l.Value is U8) { Beboputer.Bebop.RAM.Write(address, ((U8)l.Value).Read()); ++address; } else if (l.Value is U16) { ushort v = ((U16)l.Value).Read(); Beboputer.Bebop.RAM.Write(address, (byte)((v & 0xFF00) >> 8)); ++address; Beboputer.Bebop.RAM.Write(address, (byte)(v & 0xFF)); ++address; } } else { throw new NotImplementedException("not yet"); } } } } //refresh windows Beboputer.Bebop.Load(); }
public static Operand Parse(string text) { //v=LABEL | ($ff | 255 | %10101010) | ($ffff | 64000 | %1010101010101010 //v //[v] //[[v]] //[v,X] //[[v,X]] //[[v],X] AddressingModes addressingMode = AddressingModes.Implied; string parsed = text; if (parsed != null) { bool isAddress = false; bool isIndirect = false; bool isIndexed = false; bool isPreIndexed = false; bool isPostIndexed = false; if (parsed[0] == '[') { if (parsed[parsed.Length - 1] != ']') throw new InvalidOperationException("can't parse {" + text + "}"); isAddress = true; parsed = parsed.Substring(1, parsed.Length - 2); if (parsed[0] == '[') { isIndirect = true; if (parsed.Substring(parsed.Length - 3, 3) == ",X]") { isPreIndexed = true; parsed = parsed.Substring(1, parsed.Length - 4); } else if (parsed.Substring(parsed.Length - 3, 3) == "],X") { isPostIndexed = true; parsed = parsed.Substring(1, parsed.Length - 4); } else if (parsed[parsed.Length - 1] == ']') { parsed = parsed.Substring(1, parsed.Length - 2); } else { throw new InvalidOperationException("can't parse {" + text + "}"); } } if (parsed.Substring(parsed.Length - 2, 2) == ",X") { isIndexed = true; parsed = parsed.Substring(0, parsed.Length - 2); } } if (parsed.Length == 0) throw new InvalidOperationException("can't parse {" + text + "}"); //parse label or literal UInt ui = null; string name = null; if (char.IsLetter(parsed[0])||parsed[0]=='_') { if (!parsed.All(c => char.IsLetterOrDigit(c) || c=='_')) throw new InvalidOperationException("can't parse {" + text + "}"); name = parsed; } else { ui = UInt.Parse(parsed); if (isAddress && ui is U8) { ui = new U16(((U8)ui).Read()); } } if (isAddress) { //address literal or pointer (label) if (isIndirect) { if (isPreIndexed) addressingMode = AddressingModes.IndirectPreIndexed; else if (isPostIndexed) addressingMode = AddressingModes.IndirectPostIndexed; else addressingMode = AddressingModes.Indirect; } else { if (isIndexed) { addressingMode = AddressingModes.Indexed; } else { addressingMode = AddressingModes.Absolute; } } Value value = null; if (ui!=null) { value = new Literal(ui); } else { value=new Pointer(name); } return new Operand(value, addressingMode); } else { //immediate literal or constant (label) if (ui!=null) { if (ui is U8) { addressingMode = AddressingModes.Immediate; } else if (ui is U16) { addressingMode = AddressingModes.BigImmediate; } else { throw new NotSupportedException("only U8 and U16 supported"); } return new Operand(new Literal(ui), addressingMode); } else { //how to tell if a constant label is 8 or 16? //TODO: look up .EQU in symbol table return new Operand(new Constant(name,null), addressingMode); } } } else { //implied return new Operand(); } }