protected void Write16(ushort address, ushort value) { //convert native ushort to big endian format in ram var bytes = EndianUtils.FromNative(value); _cpu.Ram[address] = bytes[0]; //msb _cpu.Ram[(ushort)(address + 1)] = bytes[1]; //lsb; }
public static ROF Assemble(FileAstNode file) { /* * Rules: * * .ORG and .END required * file must start with EQUs or ORG * EQUs must be before ORG * EQUs must have labels * file must end with END * reserve statements must come between ORG and END (ORG doesn't mean the start of code, only the image) * * address labels are ushort * constant labels (EQU) may be bytes or ushorts * * */ //cache instructions Dictionary <string, Instruction> instructions = new Dictionary <string, Instruction>(); foreach (var instruction in Instruction.GetInstructions()) { instructions.Add(instruction.Encode(), instruction); } byte[] image = new byte[0xFFFF + 1]; Dictionary <string, Label> labels = new Dictionary <string, Label>(); ushort?start = null; ushort?code = null; ushort?end = null; ushort here = 0; foreach (var statement in file.ChildNodes) { if (end != null) { throw new AssembleException("END must be last statement in file", statement.SourceSpan); } LabelAstNode label = statement[typeof(LabelAstNode)] as LabelAstNode; if (statement is DirectiveAstNode) { IDirective directive = statement[typeof(IDirective)] as IDirective; if (directive is DeclarationAstNode) { if (start != null) { throw new AssembleException("EQU must be before ORG", statement.SourceSpan); } if (label == null) { throw new AssembleException("EQU must have a label", statement.SourceSpan); } IntegerAstNode integer = directive[typeof(IntegerAstNode)] as IntegerAstNode; labels.Add(label.Value, new Label(LabelType.Constant, integer.Value)); } else { if (directive is OriginAstNode) { start = GetIntegerRef16(statement, (OriginAstNode)directive, labels); } else { if (start == null) { throw new AssembleException("ORG must be defined first", statement.SourceSpan); } if (directive is ReservationAstNodeBase) { if (label != null) { labels.Add(label.Value, new Label(LabelType.Address, here + start.Value)); } int byteSize = ((ReservationAstNodeBase)directive).Value; if (directive is ReservationInitAstNode) { var integers = ((AstNodeBase)directive).Find(typeof(IntegerAstNode)); if (integers.Length == 0) { here += (ushort)byteSize; } else { foreach (var integer in integers) { var i = (IntegerAstNode)integer; if (byteSize == 1) { if (i.Value is ushort) { throw new AssembleException("can't use 16 bit constants in .byte reservation", statement.SourceSpan); } image[here] = (byte)i.Value; } else if (byteSize == 2) { if (i.Value is uint) { throw new AssembleException("can't use 32 bit constants in .2byte reservation", statement.SourceSpan); } var bytes = EndianUtils.FromNative(Convert.ToUInt16(i.Value)); image[here] = bytes[0]; //msb; image[here + 1] = bytes[1]; //lsb; } else if (byteSize == 4) { var bytes = EndianUtils.FromNative(Convert.ToUInt32(i.Value)); image[here] = bytes[0]; //msb; image[here + 1] = bytes[1]; image[here + 2] = bytes[2]; image[here + 3] = bytes[3]; //lsb; } else { throw new NotImplementedException("bad byte size"); } here += (ushort)byteSize; } } } else if (directive is ReservationStarAstNode) { uint bytes = GetIntegerRef32(statement, (AstNode)directive, labels); //TODO what if this overflows? here += (ushort)(bytes * byteSize); } else { throw new InvalidOperationException("bad reservation directive"); } } else if (directive is EndAstNode) { end = (ushort?)(start + here - 1); } } } } else if (statement is InstructionAstNode) { if (label != null) { labels.Add(label.Value, new Label(LabelType.Address, here + start)); } if (code == null) { code = (ushort)(here + start); } MnemonicAstNode mnemonic = statement[typeof(MnemonicAstNode)] as MnemonicAstNode; IOperand operand = statement[typeof(IOperand)] as IOperand; string encodedInstruction = EncodeInstruction(mnemonic.Value, operand); Instruction instruction = instructions[encodedInstruction]; image[here] = instruction.OpCode; if (instruction.Width == 2) { image[here + 1] = GetIntegerRef8(statement, (AstNodeBase)operand, labels); } else if (instruction.Width == 3) { ushort value = GetIntegerRef16(statement, (AstNodeBase)operand, labels); var bytes = EndianUtils.FromNative(value); image[here + 1] = bytes[0]; //msb; image[here + 2] = bytes[1]; //lsb; } here += instruction.Width; } else { throw new AssembleException("Line must be a statement.", statement.SourceSpan); } } if (end == null) { throw new InvalidOperationException("file must have END"); } return(new ROF { Start = start.Value, Code = code, End = end.Value, Image = image.ToArray() }); }