Ejemplo n.º 1
0
        private static void ExpandComplex(Statement s, List<Statement> next_pass)
        {
            if(s is Instruction)
            {
                Instruction src = s as Instruction;

                string op_lower = src.op.ToLower();

                // is it complex?
                if (op_lower == "jl")
                {
                    /* Jump with link
                        add PC, 4->LR
                        j x
                    */
                    Instruction new_1 = new Instruction();
                    new_1.cond = src.cond;
                    new_1.op = "add";
                    new_1.srca = new RegisterOperand { val = "PC" };
                    new_1.srcb = new IntegerOperand { val = 4 };
                    new_1.dest = new RegisterOperand { val = "LR" };
                    next_pass.Add(new_1);

                    Instruction new_2 = new Instruction();
                    new_2.cond = src.cond;
                    new_2.op = "j";
                    new_2.srca = src.srca;
                    next_pass.Add(new_2);
                }
                else if (op_lower == "jrel")
                {
                    /* Relative jump
                        only valid if srca is a label/integer
                        -> mov x -> pc (which is interpreted as an add to pc)
                    */
                    Expression new_srca = null;
                    if (src.srca is IntegerOperand)
                        new_srca = src.srca;
                    else if (src.srca is LabelExpression)
                    {
                        new_srca = src.srca;
                        ((LabelExpression)new_srca).addend = -4;
                        ((LabelExpression)new_srca).is_pcrel = true;
                    }
                    else if (src.srca is RegisterOperand)
                    {
                        var r_srca = src.srca as RegisterOperand;
                        if (regs.ContainsKey(r_srca.val.ToUpper()))
                        {
                            throw new Exception("jrel must have an integer or label operand");
                        }
                        new_srca = src.srca;
                        ((LabelExpression)new_srca).addend = -4;
                        ((LabelExpression)new_srca).is_pcrel = true;
                    }

                    Instruction new_1 = new Instruction();
                    new_1.cond = src.cond;
                    new_1.op = "mov";
                    new_1.srca = new_srca;
                    new_1.dest = new RegisterOperand { val = "PC" };
                    next_pass.Add(new_1);
                }
                else if (op_lower == "jlrel")
                {
                    /* Relative jump with link
                        only valid if srca is a label/integer
                        ->  add pc, 4 -> lr
                            mov x -> pc (which is interpreted as an add to pc)
                    */
                    Expression new_srca = null;
                    if (src.srca is IntegerOperand)
                        new_srca = src.srca;
                    else if (src.srca is LabelExpression)
                    {
                        new_srca = src.srca;
                        ((LabelExpression)new_srca).addend = -4;
                        ((LabelExpression)new_srca).is_pcrel = true;
                    }
                    else if (src.srca is RegisterOperand)
                    {
                        var r_srca = src.srca as RegisterOperand;
                        if (regs.ContainsKey(r_srca.val.ToUpper()))
                        {
                            throw new Exception("jrel must have an integer or label operand");
                        }
                        new_srca = src.srca;
                        ((LabelExpression)new_srca).addend = -4;
                        ((LabelExpression)new_srca).is_pcrel = true;
                    }

                    Instruction new_1 = new Instruction();
                    new_1.cond = src.cond;
                    new_1.op = "add";
                    new_1.srca = new RegisterOperand { val = "PC" };
                    new_1.srcb = new IntegerOperand { val = 4 };
                    new_1.dest = new RegisterOperand { val = "LR" };
                    next_pass.Add(new_1);

                    Instruction new_2 = new Instruction();
                    new_2.cond = src.cond;
                    new_2.op = "mov";
                    new_2.srca = new_srca;
                    new_2.dest = new RegisterOperand { val = "PC" };
                    next_pass.Add(new_2);
                }
                else if (op_lower == "ret")
                {
                    /* Return
                        j LR
                    */
                    Instruction new_1 = new Instruction();
                    new_1.cond = src.cond;
                    new_1.op = "j";
                    new_1.srca = new RegisterOperand { val = "LR" };
                    next_pass.Add(new_1);
                }
                else if (op_lower == "push")
                {
                    /* Push x
                        sub SP, 4 -> SP
                        store x, 4 -> SP
                    */
                    Instruction new_1 = new Instruction();
                    new_1.cond = src.cond;
                    new_1.op = "sub";
                    new_1.srca = new RegisterOperand { val = "SP" };
                    new_1.srcb = new IntegerOperand { val = 4 };
                    new_1.dest = new RegisterOperand { val = "SP" };
                    next_pass.Add(new_1);

                    Instruction new_2 = new Instruction();
                    new_2.cond = src.cond;
                    new_2.op = "store";
                    new_2.srca = src.srca;
                    new_2.srcb = new IntegerOperand { val = 4 };
                    new_2.dest = new RegisterOperand { val = "SP" };
                    next_pass.Add(new_2);
                }
                else if (op_lower == "pop")
                {
                    /* Pop x
                        load SP, 4 -> x
                        add SP, 4 -> SP
                    */
                    Instruction new_1 = new Instruction();
                    new_1.cond = src.cond;
                    new_1.op = "load";
                    new_1.srca = new RegisterOperand { val = "SP" };
                    new_1.srcb = new IntegerOperand { val = 4 };
                    new_1.dest = src.srca;
                    next_pass.Add(new_1);

                    Instruction new_2 = new Instruction();
                    new_2.cond = src.cond;
                    new_2.op = "add";
                    new_2.srca = new RegisterOperand { val = "SP" };
                    new_2.srcb = new IntegerOperand { val = 4 };
                    new_2.dest = new RegisterOperand { val = "SP" };
                    next_pass.Add(new_2);
                }
                else
                {
                    Instruction dest = new Instruction();
                    dest.op = op_lower;
                    dest.srca = src.srca;
                    dest.srcb = src.srcb;
                    dest.dest = src.dest;
                    dest.cond = src.cond;
                    next_pass.Add(dest);
                }
            }
            else
                next_pass.Add(s);
        }
Ejemplo n.º 2
0
        private static Statement ExpandComplex(Statement s)
        {
            if(s is Instruction)
            {
                Instruction src = s as Instruction;

                // TODO: is it complex?
                Instruction dest = new Instruction();
                dest.op = src.op.ToLower();
                dest.srca = src.srca;
                dest.srcb = src.srcb;
                dest.dest = src.dest;
                return dest;
            }
            return s;
        }
Ejemplo n.º 3
0
        static void Main(string[] args)
        {
            if (ParseArgs(args) == false)
            {
                DispUsage();
                return;
            }
            if(output_file == null)
            {
                if (input_file != null)
                {
                    FileInfo fi = new FileInfo(input_file);
                    output_file = fi.Name.Substring(0, fi.Name.Length - fi.Extension.Length) + ".o";
                }
                else
                    output_file = "a.out";
            }
            Stream istream = null;
            if (input_file == null)
            {
                // TODO - read from stdin
                DispUsage();
                return;
            }
            else
                istream = new FileStream(input_file, FileMode.Open);

            Parser p = new Parser(new Scanner(istream));
            bool res = p.Parse();
            if (res == false)
                throw new Exception("Parse error");

            // first loop to convert all operands to lowercase, and
            //  expand all complex instructions
            List<Statement> pass1 = new List<Statement>();
            foreach (Statement s in ((StatementList)p.output).list)
                ExpandComplex(s, pass1);

            Dictionary<string, LabelOffset> label_offsets;

            bool changes = false;
            do
            {
                // Reset all section offsets to 0
                foreach (var s in sections.Values)
                {
                    s.cur_offset = 0;
                    s.cur_label = "";
                }

                changes = false;
                // next, add offset information to statements and extract label offsets
                cur_section = sections[".text"];
                label_offsets = new Dictionary<string, LabelOffset>();
                los = label_offsets;
                foreach (Statement s in pass1)
                {
                    if (s == null)
                        continue;
                    if (s is SectionHeader)
                    {
                        var sh = s as SectionHeader;
                        cur_section = sections[sh.name];
                    }

                    s.offset = cur_section.cur_offset;
                    s.section = cur_section;
                    cur_section.cur_offset = s.OffsetAfter(cur_section.cur_offset);

                    if (s is LineLabel)
                    {
                        LineLabel ll = s as LineLabel;
                        ll.abs_name = ll.name;
                        label_offsets[ll.abs_name] = new LabelOffset { Section = cur_section, Offset = ll.offset };

                        if (global_objs.ContainsKey(ll.name))
                            global_objs[ll.name] = cur_section;
                    }


                }

                // do a pass to evaluate all expressions
                cur_section = sections[".text"];
                foreach (Statement s in pass1)
                {
                    if (s == null)
                        continue;

                    if (s is SectionHeader)
                    {
                        var sh = s as SectionHeader;
                        cur_section = sections[sh.name];
                    }

                    if (s is Instruction)
                    {
                        Instruction i = s as Instruction;
                        i.srca = EvaluateOperand(i.srca, label_offsets, cur_section);
                        i.srcb = EvaluateOperand(i.srcb, label_offsets, cur_section);
                        i.dest = EvaluateOperand(i.dest, label_offsets, cur_section);
                    }
                }

                /* Identify those instructions of the form jrel(cc) where we can see
                    for definite that the relocation won't fit */
                List<Statement> pass2 = new List<Statement>();
                foreach (Statement s in pass1)
                {
                    Instruction i = s as Instruction;
                    if (i != null)
                    {
                        if (i.op == "mov" && (i.dest is RegisterOperand) &&
                            (((RegisterOperand)i.dest).val.ToLower() == "pc" ||
                            ((RegisterOperand)i.dest).val.ToLower() == "r0") &&
                            i.cond != null &&
                            i.cond.ctype != Condition.CType.Always)
                        {
                            Relocation r = i.srca as Relocation;
                            if (r != null)
                            {
                                // Do we target a label in this section ?
                                if (r.TargetSection != null && r.TargetSection == i.section)
                                {
                                    // Relocation type will eventually be SRCABREL: S + A - P
                                    // Calculate its value
                                    long r_val = los[r.TargetName].Offset + r.Addend -
                                        i.offset;

                                    // SRCABREL can fit values from -1024 to + 1023
                                    if (r_val < -1024 || r_val > 1023)
                                    {
                                        // Replace with LIT val -> R1; mov(cc) R1 -> PC;

                                        Instruction lit = new Instruction();
                                        lit.op = "lit";
                                        lit.cond = new Condition { ctype = Condition.CType.Always };
                                        lit.dest = new RegisterOperand { val = "R1" };
                                        lit.srca = r;
                                        pass2.Add(lit);

                                        Instruction mov = new Instruction();
                                        mov.op = "mov";
                                        mov.cond = i.cond;
                                        mov.srca = new RegisterOperand { val = "R1" };
                                        mov.dest = new RegisterOperand { val = "PC" };
                                        pass2.Add(mov);

                                        changes = true;

                                        continue;
                                    }
                                }
                            }
                        }
                    }

                    if (s != null)
                        pass2.Add(s);
                }

                pass1 = pass2;
            } while (changes == true);


            // now do the actual encoding
            List<byte> oput;
            cur_section = sections[".text"];
            oput = cur_section.oput;
            string cur_label = "";
            foreach(Statement s in pass1)
            {
                if (s is SectionHeader)
                {
                    var sh = s as SectionHeader;
                    cur_section = sections[sh.name];
                    oput = cur_section.oput;
                }

                if (s is Instruction)
                {
                    Instruction i = s as Instruction;

                    // ensure dest is either null or a valid register
                    uint dest_idx = 0;
                    bool valid = false;
                    if (i.dest != null)
                    {
                        if (i.dest is RegisterOperand)
                        {
                            RegisterOperand r_dest = i.dest as RegisterOperand;
                            string r_dest_str = r_dest.val.ToUpper();
                            if (regs.ContainsKey(r_dest_str))
                            {
                                dest_idx = (uint)regs[r_dest_str];
                                valid = true;
                            }
                        }
                    }
                    else
                        valid = true;
                    if (dest_idx >= 32)
                        valid = false;
                    if (!valid)
                        throw new Exception("Invalid destination register: " + i.ToString());

                    uint srca, srcb, srcab, srcbcond, srcabcond, lit, litr1;
                    bool srca_fits, srcb_fits, srcab_fits, srcbcond_fits,
                        srcabcond_fits, lit_fits, litr1_fits;

                    // Extract data types
                    srca = ExtractData(i.srca, label_offsets, out srca_fits,
                        cur_label, i.offset, 6, false);
                    srcb = ExtractData(i.srcb, label_offsets, out srcb_fits,
                        cur_label, i.offset, 6, false);
                    srcab = ExtractData(i.srca, label_offsets, out srcab_fits,
                        cur_label, i.offset, 12, false);
                    srcbcond = ExtractData(i.srcb, label_offsets, out srcbcond_fits,
                        cur_label, i.offset, 11, false);
                    srcabcond = ExtractData(i.srca, label_offsets, out srcabcond_fits,
                        cur_label, i.offset, 17, false);
                    lit = ExtractData(i.srca, label_offsets, out lit_fits,
                        cur_label, i.offset, 25, true);
                    litr1 = ExtractData(i.srca, label_offsets, out litr1_fits,
                        cur_label, i.offset, 31, true);

                    // Extract relocations
                    Relocation srcar = i.srca as Relocation;
                    Relocation srcbr = i.srcb as Relocation;

                    uint oput_val = 0;
                    // encode literals
                    if (i.op == "lit")
                    {
                        if (i.cond.ctype != Condition.CType.Always)
                            throw new Exception("Cannot use conditions on lit: " + i.ToString());

                        // if dest not specified, assume r1
                        if (i.dest == null)
                            dest_idx = 1;

                        if (dest_idx != 1 && !lit_fits || !litr1_fits)
                        {
                            throw new Exception("Literal value too large: " + i.ToString());
                        }

                        if (dest_idx == 1)
                        {
                            oput_val = 0x80000000U | litr1;
                            if (srcar != null)
                                srcar.Type = binary_library.elf.ElfFile.R_JCA_LITR1;
                        }
                        else
                        {
                            oput_val = 0x40000000U | (dest_idx << 25) | lit;
                            if (srcar != null)
                                srcar.Type = binary_library.elf.ElfFile.R_JCA_LIT;
                        }
                    }
                    else
                    {
                        if (opcodes.ContainsKey(i.op))
                        {
                            // special case jump opcodes to always use pc as dest
                            if (i.op == "jmp" || i.op == "j")
                            {
                                dest_idx = (uint)regs["PC"];
                            }

                            // special case load/store to use 4 byte length unless already specified
                            if (i.op == "load" || i.op == "store")
                            {
                                if (i.srcb == null)
                                {
                                    srcb = 0x24;
                                    srcbcond = 0x404;
                                    srcb_fits = true;
                                    srcbcond_fits = true;
                                }
                            }
                            uint opcode_val = opcodes[i.op];

                            uint cond_val = Condition.cond_vals[i.cond.ctype];
                            uint cond_reg_val = (uint)i.cond.reg_no;

                            // if condition is always, srcab and srcb extend
                            //  into srcabcond and srcbcond respectively
                            bool has_cond_reg = true;
                            if (i.cond.ctype == Condition.CType.Always)
                            {
                                srcab = srcabcond;
                                srcb = srcbcond;
                                srcab_fits = srcabcond_fits;
                                srcb_fits = srcbcond_fits;
                                has_cond_reg = false;
                            }

                            // special case mov - it uses srcab instead of
                            //  srca
                            bool has_srcb = true;
                            if (opcode_val == opcodes["mov"])
                            {
                                srca = srcab;
                                srca_fits = srcab_fits;
                                has_srcb = false;
                            }

                            // ensure all operands fit
                            if (!srca_fits)
                                throw new Exception("First operand in \'" + i.ToString() + "\' is too large");
                            if (has_srcb && !srcb_fits)
                                throw new Exception("Second operand in \'" + i.ToString() + "\' is too large");

                            oput_val = opcode_val << 26 | cond_val << 22 |
                                dest_idx << 17 | srca;
                            if (has_cond_reg)
                                oput_val |= cond_reg_val << 12;
                            if (has_srcb)
                                oput_val |= srcb << 6;

                            if(srcar != null)
                            {
                                if (has_srcb)
                                {
                                    srcar.Type = binary_library.elf.ElfFile.R_JCA_SRCA;
                                    oput_val |= (1U << 5);
                                }
                                else if (has_cond_reg)
                                {
                                    srcar.Type = binary_library.elf.ElfFile.R_JCA_SRCAB;
                                    oput_val |= (1U << 11);
                                }
                                else
                                {
                                    srcar.Type = binary_library.elf.ElfFile.R_JCA_SRCABCOND;
                                    oput_val |= (1U << 16);
                                }

                                if (srcar.IsPCRel)
                                    srcar.Type = srcar.Type - binary_library.elf.ElfFile.R_JCA_SRCA +
                                        binary_library.elf.ElfFile.R_JCA_SRCAREL;
                            }

                            if(srcbr != null)
                            {
                                if (has_cond_reg)
                                {
                                    srcbr.Type = binary_library.elf.ElfFile.R_JCA_SRCB;
                                    oput_val |= (1U << 11);
                                }
                                else
                                {
                                    srcbr.Type = binary_library.elf.ElfFile.R_JCA_SRCBCOND;
                                    oput_val |= (1U << 16);
                                }

                                if (srcbr.IsPCRel)
                                    srcbr.Type = srcbr.Type - binary_library.elf.ElfFile.R_JCA_SRCA +
                                        binary_library.elf.ElfFile.R_JCA_SRCAREL;
                            }
                        }
                        else
                            throw new Exception("Unknown opcode " + i.ToString());
                    }
                    var bs = BitConverter.GetBytes(oput_val);
                    foreach (byte b in bs)
                        oput.Add(b);

                    if(srcar != null)
                    {
                        srcar.SourceOffset = i.offset;
                        relocs.Add(srcar);
                    }
                    if(srcbr != null)
                    {
                        srcbr.SourceOffset = i.offset;
                        relocs.Add(srcbr);
                    }
                }
                else if(s is DataDirective)
                {
                    DataDirective dd = s as DataDirective;

                    // Compress string and label members to integers
                    List<int> data = new List<int>();

                    foreach(var ddi in dd.data)
                    {
                        var e = ddi.Evaluate(new MakeState(label_offsets, cur_section));

                        switch(e.Type)
                        {
                            case Expression.EvalResult.ResultType.String:
                                foreach (char c in e.strval)
                                    data.Add((int)c);
                                break;
                            case Expression.EvalResult.ResultType.Int:
                                data.Add(e.intval);
                                break;
                            default:
                                throw new Exception("Unsupported type in data directive at " + s.ToString());
                        }
                    }

                    // Then output depending on ddtype
                    int b_count = 1;
                    switch (dd.directive)
                    {
                        case DataDirective.DDType.Byte:
                            b_count = 1;
                            break;
                        case DataDirective.DDType.Word:
                            b_count = 2;
                            break;
                        case DataDirective.DDType.DWord:
                            b_count = 4;
                            break;

                    }
                    foreach (int data_i in data)
                    {
                        byte[] data_b = BitConverter.GetBytes(data_i);
                        for (int data_bi = 0; data_bi < b_count; data_bi++)
                        {
                            if (data_bi < data_b.Length)
                                oput.Add(data_b[data_bi]);
                            else
                                oput.Add(0);
                        }
                    }
                }
                else if(s is LineLabel)
                {
                    LineLabel ll = s as LineLabel;
                    cur_label = ll.name;
                }
            }

            // Generate ELF output
            var fs_obj = new System.IO.FileStream(output_file, 
                System.IO.FileMode.Create,
                System.IO.FileAccess.Write);
            var bw_obj = new System.IO.BinaryWriter(fs_obj);
            Elf.GenerateELF(bw_obj);
            bw_obj.Close();

            // Generate binary output
            /*
            string oput_bin = "test.bin";
            string oput_hex = "C:\\Users\\jncro\\Documents\\fpga\\cpu\\fware2.hex";

            System.IO.FileStream fs_bin = new System.IO.FileStream(oput_bin,
                System.IO.FileMode.Create, System.IO.FileAccess.Write);
            System.IO.BinaryWriter bw_bin = new System.IO.BinaryWriter(fs_bin);
            foreach (byte b in oput)
                bw_bin.Write(b);
            bw_bin.Close();*/

            // Generate HEX output
            /*
            System.IO.FileStream fs_hex = new System.IO.FileStream(oput_hex,
                System.IO.FileMode.Create, System.IO.FileAccess.Write);
            System.IO.StreamWriter sw_hex = new System.IO.StreamWriter(fs_hex, Encoding.ASCII);
            uint addr = 0;
            foreach(byte b in oput)
            {
                StringBuilder sb = new StringBuilder();
                sb.Append(":01");
                sb.Append(addr.ToString("X4"));
                sb.Append("00");
                sb.Append(b.ToString("X2"));

                uint csum = 01 + addr + (addr >> 8) + b;
                csum &= 0xffU;
                csum = 0x100U - csum;
                csum &= 0xffU;
                sb.Append(csum.ToString("X2"));

                addr++;
                sw_hex.WriteLine(sb.ToString());
            }
            sw_hex.WriteLine(":00000001FF");
            sw_hex.Close(); */
        }