Ejemplo n.º 1
0
            public RegisterDependencyNode Copy()
            {
                RegisterDependencyNode copy = new RegisterDependencyNode(m_operand_type);

                copy.m_allocated_reg = m_allocated_reg;
                copy.m_immediate_arg = m_immediate_arg;
                copy.m_is_locked = m_is_locked;
                copy.m_dependency = m_dependency == null? null : new DepPair(m_dependency.m_inst_num, m_dependency.m_oper_num);

                foreach (DepPair d in m_dependents)
                {
                    copy.m_dependents.Add(new DepPair(d.m_inst_num, d.m_oper_num));
                }

                return copy;
            }
Ejemplo n.º 2
0
        public ProgramInfo(string[] lines, CheatSheet cheat_sheet)
        {
            RegisterOwnerNode[] reg_to_inst = new RegisterOwnerNode[128];

            Regex opcode_operand_comment_splitter = new Regex(@"([A-Za-z]+)\s+([^;]*)(;*)");
            Regex label_rest_of_line_splitter = new Regex(@"^([a-zA-Z_\.][a-zA-Z0-9_]*):(.*)");

            // matches ".macro_begin SomeMacro var1, var2 ,var3 , var4"
            //Regex macro_arg_splitter = new Regex
            //(
            //	@"^\b*\.macro_begin\s+([a-zA-Z_][a-zA-Z0-9_]*)\s+([a-zA-Z_][a-zA-Z0-9_]*)(?:\s*,\s*([a-zA-Z_][a-zA-Z0-9_]*))*"
            //);

            Regex register_extractor = new Regex(@"\$(\d+)");

            m_log = "";

            int lines_of_actual_code = 0;

            // todo: stop overusing trim
            for (int line_num = 0; line_num < lines.Length; ++line_num)
            {
                string current_line = lines[line_num].Trim();

                // early out to skip whole line comments
                if (current_line == "" || current_line[0] == ';')
                {
                    continue;
                }

                Match match;

                // macro processing
                string macro_begin_token = ".macro_begin";
                if (current_line.StartsWith(macro_begin_token))
                {
                    current_line = current_line.Substring(macro_begin_token.Length);
                    string[] args = current_line.Split(new char[] {',',' '}, StringSplitOptions.RemoveEmptyEntries);
                    int num_args = args.Length;

                    if (num_args <= 2)
                    {
                        ErrorMacroWrongNumArgs(line_num);
                        return;
                    }

                    int macro_start_line = line_num;
                    string macro_name = args[0];

                    while (current_line.StartsWith(".macro_end") == false && line_num < lines.Length)
                    {
                        current_line = lines[line_num++].Trim();
                    }

                    // either we found the macro end or we have an unterminated macro
                    if (current_line.StartsWith(".macro_end"))
                    {
                        --line_num;
                        continue;
                    }
                    else
                    {
                        ErrorUnterminatedMacro(macro_start_line, macro_name);
                        return;
                    }
                }

                // deal with labels alone on a line and labels with code after them
                match = label_rest_of_line_splitter.Match(current_line);
                if (match.Success)
                {
                    string lab_to_add = match.Groups[1].Value;

                    // disallow duplicate labels
                    if (m_label_table.ContainsKey(lab_to_add))
                    {
                        ErrorLabelDuplicate(line_num, lab_to_add);
                        return;
                    }

                    // add label to table, and see if there was anything after the label
                    m_label_table.Add(lab_to_add, lines_of_actual_code);

                    // set the current line to everything after the label and continue
                    current_line = match.Groups[2].Value.Trim();

                    // if this is a label by itself, continue.
                    if (current_line == "" || current_line[0] == ';')
                    {
                        continue;
                    }
                }

                match = opcode_operand_comment_splitter.Match(current_line);
                if (match.Success)
                {
                    string opcode = match.Groups[1].Value;

                    // make sure the opcode exists
                    Program.Instruction inst;
                    if (!cheat_sheet.LookupInstruction(opcode, out inst))
                    {
                        ErrorInvalidOpcode(line_num, opcode);
                        return;
                    }

                    InstructionNode dependency_node = new InstructionNode(opcode, inst);
                    dependency_node.m_original_inst_num = m_original_program.Count;
                    m_original_program.Add(dependency_node);
                    ++m_instruction_cnt[inst.m_pipeline == Program.Pipe.EVEN? 0 : 1];

                    // dont allow jumps in the middle of the code. Todo: check branch target as well
                    if (dependency_node.IsBranch(cheat_sheet) && line_num < lines.Length - 1)
                    {
                        ErrorInvalidBranchSlot(line_num);
                        return;
                    }
                    else if (dependency_node.IsBranch(cheat_sheet) == false && line_num == lines.Length - 1)
                    {
                        ErrorLastInstructionNotBranch(line_num);
                        return;
                    }

                    // don't do anything for opcodes that dont require operands
                    int num_expected_operands = inst.GetNumExpectedOperands();
                    if (num_expected_operands > 0)
                    {
                        // group 2 must be opcodes. If it starts with a semicolon, we are missing the proper operands
                        if (match.Groups[2].Value.Length < 1 || match.Groups[2].Value[0] == ';' || match.Groups[2].Value == "")
                        {
                            ErrorNoOperands(line_num, opcode, num_expected_operands);
                            return;
                        }

                        // now the real work begins.  Verify the operands are what they should be
                        string operands_match = match.Groups[2].Value;
                        string[] operands = operands_match.Trim().Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries);

                        // wrong number of operands
                        if (operands.Length != num_expected_operands)
                        {
                            ErrorWrongNumOperands(line_num, opcode, num_expected_operands, operands.Length);
                            return;
                        }

                        // verify operand types are what they should be
                        for (int o = 0; o < num_expected_operands; ++o)
                        {
                            string trimmed_operand = operands[o].Trim();

                            // if the operand is a label to jump to, replace it with the label address
                            if (m_label_table.ContainsKey( trimmed_operand ))
                            {
                                trimmed_operand = m_label_table[trimmed_operand].ToString();
                            }

                            // original register number
                            int original_reg_num = -1;
                            int operand_offset = -1;

                            bool operand_type_valid = Program.OperandInfo.GetOperandValues(inst.m_operand_types[o], trimmed_operand, out original_reg_num, out operand_offset);
                            if (!operand_type_valid)
                            {
                                ErrorInvalidOperandType(line_num, opcode, o, inst.m_operand_types[o]);
                                return;
                            }

                            if (original_reg_num > 127)
                            {
                                ErrorRegisterGt127(line_num, o);
                                return;
                            }

                            // add this to the dependency tree
                            RegisterDependencyNode operand_dependency_node = new RegisterDependencyNode(inst.m_operand_types[o]);
                            dependency_node.m_reg_info.Add(operand_dependency_node);
                            operand_dependency_node.m_allocated_reg = original_reg_num;
                            operand_dependency_node.m_immediate_arg = operand_offset;

                            //check for input dependencies on other registers (as opposed to literals)
                            if (inst.m_operand_types[o] == Program.OperandInfo.OperandType.INPUT_REG ||
                                inst.m_operand_types[o] == Program.OperandInfo.OperandType.BASE_REG_AND_SIGNED_LITERAL_OFFSET ||
                                inst.m_operand_types[o] == Program.OperandInfo.OperandType.BASE_REG_AND_SIGNED_LITERAL_OFFSET)
                            {
                                if (original_reg_num >= 0 && reg_to_inst[original_reg_num] != null)
                                {
                                    // if this input register was written to by a previous instruction, then we depend on that instruction
                                    //is_root_node = false;
                                    reg_to_inst[original_reg_num].m_times_used++;
                                    operand_dependency_node.m_dependency = new DepPair(reg_to_inst[original_reg_num].m_owner, 0);
                                    m_original_program[reg_to_inst[original_reg_num].m_owner].m_reg_info[0].m_dependents.Add(new DepPair(lines_of_actual_code, o));
                                }
                            }
                        }

                        // register ownership and removal of unused instructions
                        if (inst.m_operand_types[0] == Program.OperandInfo.OperandType.OUTPUT_REG)
                        {
                            string trimmed_operand = operands[0].Trim();
                            int reg_num = -1;
                            match = register_extractor.Match(trimmed_operand);
                            if (match.Success && int.TryParse(match.Groups[1].Value, out reg_num))
                            {
                                // look at the previous register owner. If between when it wrote its value and now the register is
                                // never used, this is probably an unused instruction and should be removed!
                                if (reg_to_inst[reg_num] != null && reg_to_inst[reg_num].m_times_used == 0)
                                {
                                    // mark this and remove it later, making sure to fix up the odd/even inst count,
                                    // labels, indices, pointers, and who knows what else needs to be fixed :)
                                    int unused_inst_line = reg_to_inst[reg_num].m_owner;
                                    EliminateUnusedInstructionChain(unused_inst_line, reg_to_inst);
                                }

                                // assign register ownership
                                reg_to_inst[reg_num] = new RegisterOwnerNode(lines_of_actual_code);
                            }
                        }
                    }

                    ++lines_of_actual_code;
                }
                else
                {
                    m_program_status.m_error_line = line_num;
                   	m_program_status.m_error_msg = "Parse error. Line: " + line_num.ToString();
                    m_program_status.m_status = ProgramStatus.Status.STATUS_PARSE_ERROR;
                    return;
                }
            }

            // lock the final owners of all regs
            for (int r = 0; r < 128; ++r)
            {
                if (reg_to_inst[r] != null && reg_to_inst[r].m_owner != -1 && m_original_program[reg_to_inst[r].m_owner].m_include_in_schedule == true)
                {
                    m_original_program[reg_to_inst[r].m_owner].m_reg_info[0].m_is_locked = true;
                }
            }
        }