Пример #1
0
        public static void Split(Assembler.AsmState state, string outputPath)
        {
            var output = state.Output;

            output.Info($"Splitting ROM into {state.RomDefinitions.Count} output files.");
            try
            {
                foreach (var romDef in state.RomDefinitions)
                {
                    var filename = Path.Combine(outputPath, romDef.Filename + OutputSuffix);
                    var rom      = new byte[romDef.Size];
                    Array.Copy(state.RomImage, romDef.Offset, rom, 0, romDef.Size);
                    File.WriteAllBytes(filename, rom);
                    output.Info($"File {filename} created");
                }
            }
            catch (Exception ex)
            {
                output.Error($"Exception: {ex}");
            }
        }
Пример #2
0
        // evaluate expression
        // return true if evaluated to a value, else false
        // if false, marks line as needing a fixup
        public static bool Evaluate(Assembler.AsmState state, Line line, string expression, out int value)
        {
            var retval = true; // assume works

            value = 0;
            try
            {
                var state2 = new State(expression);
                var t      = ParseToTree(state2);
                retval = EvaluateTree(state, t, out value);
            }
            catch (Exception)
            {
                // todo - errors handled elsewhere
                retval = false;
            }

            if (!retval)
            {
                line.NeedsFixup = true;
            }
            return(retval);
        }
Пример #3
0
        /// <summary>
        /// Handle the opcode parsing
        /// </summary>
        /// <param name="state"></param>
        /// <param name="line"></param>
        /// <param name="op"></param>
        public void ParseOpcodeAndOperand(Assembler.AsmState state, Line line, Opcode op)
        {
            /* rules:
             * 1. empty operand  => Inherent mode
             * 2. starts with #  => Immediate
             * 3. relative       => Direct (branching, etc)
             * 4. ,R or n,R      => Indexed (last Indexed Indirect, PC relative)
             * 5. expr           => Direct (if fits) or Extended (if does not)
             */

            var addrMode    = Opcodes6800.AddressingMode.Direct;
            var operand     = line.Operand;
            var operandText = operand?.Text ?? "";
            var mnemonic    = Assembler.GetMnemonic(line);

            var isBranch = Opcodes6800.IsBranch(mnemonic);
            var indexed  = operandText.Contains(",");

            if (String.IsNullOrEmpty(operand?.Text))
            {
                addrMode = Opcodes6800.AddressingMode.Inherent;  // rule 1
            }
            else if (operandText.StartsWith("#"))
            {
                addrMode = Opcodes6800.AddressingMode.Immediate; // rule 2
            }
            else if (isBranch)
            {
                addrMode = Opcodes6800.AddressingMode.Direct; // rule 3
            }
            else if (indexed)
            {
                addrMode = Opcodes6800.AddressingMode.Indexed; // rule 4
            }
            else if (operandText.StartsWith(">"))
            {
                addrMode = Opcodes6800.AddressingMode.Extended;
            }
            else // rule 5
            {
                if (!Evaluator.Evaluate(state, line, operandText, out int value1))
                {
                    if (state.Pass == 2)
                    {
                        state.Output.Error(line, line.Operand, "Cannot evaluate operand.");
                    }
                }
                if (Assembler.BitsRequired(value1) <= 8)
                {
                    addrMode = Opcodes6800.AddressingMode.Direct;
                }
                else
                {
                    addrMode = Opcodes6800.AddressingMode.Extended;
                }
            }

            // now have addrMode, isBranch, requiresRegisterList, isRegisterList, indexed to decide

            var missingKey = !op.Forms.ContainsKey((int)addrMode);

            if (addrMode == Opcodes6800.AddressingMode.Direct && missingKey && op.Forms.ContainsKey((int)Opcodes6800.AddressingMode.Extended))
            {
                addrMode   = Opcodes6800.AddressingMode.Extended;
                missingKey = false;
            }

            // encode instruction and operand bytes
            if (missingKey)
            {
                state.Output.Error(line, line.Operand, "Illegal operand mode");
                return;
            }
            var opMode = op.Forms[(int)addrMode];

            line.AddressingMode = (int)addrMode;
            line.Data.Clear(); // in case double called
            line.Data.AddRange(opMode.Bytes);
            line.Length = Math.Abs(opMode.Length);

            int value;

            switch (addrMode)
            {
            case Opcodes6800.AddressingMode.Inherent:
                // no bytes to add
                break;

            case Opcodes6800.AddressingMode.Direct:
                if (Evaluator.Evaluate(state, line, operandText, out value))
                {
                    if (isBranch)
                    {
                        if (Evaluator.Evaluate(state, line, operandText, out value))
                        {
                            var relative     = -(state.Address - value + line.Length);
                            var bitsRequired = Assembler.BitsRequired(relative);
                            if (bitsRequired <= 8)
                            {
                                line.AddValue(relative, 1);
                            }
                            else
                            {
                                // loop may not exist yet. track pass, and error on second one
                                line.NeedsFixup = true;
                                if (state.Pass == 2)
                                {
                                    state.Output.Error(line, operand,
                                                       $"Operand {relative} out of 8 bit target range");
                                }
                                return;
                            }
                        }
                    }
                    else
                    {
                        line.AddValue(value, 1);
                    }
                }
                break;

            case Opcodes6800.AddressingMode.Immediate:
                if (!operandText.StartsWith("#"))
                {
                    state.Output.Error(line, line.Operand, "Missing '#' on immediate addressing mode.");
                    return;
                }
                var len = opMode.Length - opMode.Bytes.Count;
                if (Evaluator.Evaluate(state, line, operandText.Substring(1), out value))
                {
                    line.AddValue(value, len);
                }
                break;

            case Opcodes6800.AddressingMode.Extended:
                var clearOp = operandText;
                if (operandText.StartsWith(">"))
                {
                    clearOp = clearOp.Substring(1);
                }
                if (Evaluator.Evaluate(state, line, clearOp, out value))
                {
                    line.AddValue(value, 2);
                }
                break;

            case Opcodes6800.AddressingMode.Indexed:
                var words = operandText.Split(',').Select(t => t.Trim()).ToList();
                if (words.Count != 2 || words[1].ToLower() != "x")
                {
                    state.Output.Error(line, line.Operand,
                                       "Indexed addressing mode not of form [n],x");
                    return;
                }
                if (Evaluator.Evaluate(state, line, words[0], out value))
                {
                    if (value < 0 || 255 < value)
                    {
                        state.Output.Error(line, line.Operand,
                                           "Indexed addressing mode operand not in range 0-255.");
                    }
                    line.AddValue(value, 1);
                }
                else if (state.Pass == 2)
                {
                    state.Output.Error(line, line.Operand,
                                       "Cannot evaluate operand.");
                }
                break;

            default:
                state.Output.Error(line, line.Operand, $"Unknown addressing mode {addrMode}");
                break;
            }
        }
Пример #4
0
        static bool EvaluateTree(Assembler.AsmState state, Tree tree, out int value)
        {
            value = 0;
            int left, right;

            if (tree.op != null)
            {
                switch (tree.op)
                {
                case "+":
                    if (!EvaluateTree(state, tree.left, out left))
                    {
                        return(false);
                    }
                    if (tree.right == null)
                    {
                        value = left;
                        return(true);
                    }
                    if (!EvaluateTree(state, tree.right, out right))
                    {
                        return(false);
                    }
                    value = left + right;
                    return(true);

                case "-":
                    if (!EvaluateTree(state, tree.left, out left))
                    {
                        return(false);
                    }
                    if (tree.right == null)
                    {
                        value = -left;
                        return(true);
                    }
                    if (!EvaluateTree(state, tree.right, out right))
                    {
                        return(false);
                    }
                    value = left - right;
                    return(true);

                case "*":
                    if (!EvaluateTree(state, tree.left, out left) ||
                        !EvaluateTree(state, tree.right, out right))
                    {
                        return(false);
                    }
                    value = left * right;
                    return(true);

                case "/":
                    if (!EvaluateTree(state, tree.left, out left) ||
                        !EvaluateTree(state, tree.right, out right))
                    {
                        return(false);
                    }
                    if (right == 0)
                    {
                        throw new Exception("Division by zero");
                    }
                    value = left / right;
                    return(true);

                case "%":
                    if (!EvaluateTree(state, tree.left, out left) ||
                        !EvaluateTree(state, tree.right, out right))
                    {
                        return(false);
                    }
                    if (right == 0)
                    {
                        throw new Exception("Mod division by zero");
                    }
                    value = left % right;
                    return(true);

                default:
                    throw new Exception($"unknown op {tree.op}");
                }
            }
            else
            {
                var text = tree.value;
                if (text.StartsWith("$"))
                {
                    value = Convert.ToInt32(text.Substring(1), 16);
                    return(true);
                }
                if (text.All(t => Char.IsDigit(t)))
                {
                    value = Int32.Parse(text);
                    return(true);
                }
                // must be symbol - look up value or throw
                if (state.Symbols.GetValue(text, out value, state.Address))
                {
                    return(true);
                }
                return(false); // Symbol {text} not yet evaluated
            }
        }