// print hazards to main window
 public void printRAW(ref App.Cpu cpu)
 {
     foreach (string s in cpu.Hazards)
     {
         warn.Items.Add(s);
     }
 }
 public MainWindow()
 {
     InitializeComponent();
     // instantiate a new cpu object
     cpu = new App.Cpu();
     // print out the valid instructions
     printValidInst();
 }
        // method to output forwarded instructions to gui
        public void printForwarded(ref App.Cpu cpu)
        {
            foreach (List <char> s in cpu.Forwarding)
            {
                string line = "";

                foreach (char c in s)
                {
                    line += c;
                }

                opt.Items.Add(line);
            }
        }
        // method to output stalled instructions to gui
        public void printStalled(ref App.Cpu cpu)
        {
            foreach (List <char> s in cpu.Stalled)
            {
                string line = "";

                foreach (char c in s)
                {
                    line += c;
                }

                notOpt.Items.Add(line);
            }
        }
        // method to detect and print WAW hazards
        private void printWAW(ref App.Cpu cpu)
        {
            List <string> waw = new List <string>();

            // iterate through the instructino list
            for (int i = 0; i < cpu.Pipeline.Count(); i++)
            {
                string     currDest = cpu.Pipeline[i].destReg;
                List <int> codeLine = new List <int>();

                if (currDest != null && !waw.Contains(currDest))
                {
                    string wawList = "Warning: Potential WAW hazard. The following lines have the same destination:";

                    // check all instructions that come later
                    for (int n = i + 1; n < cpu.Pipeline.Count(); n++)
                    {
                        string nextDest = cpu.Pipeline[n].destReg;

                        // if there is a WAW
                        if (currDest == nextDest)
                        {
                            waw.Add(currDest);
                            // if the current codeline isn't already in the list
                            if (!codeLine.Contains(i))
                            {
                                // add that line to the list
                                codeLine.Add(i);
                            }
                            // add future line to the list
                            codeLine.Add(n);
                        }
                    }
                    // if the codeline list isn't empty
                    if (codeLine.Count() > 0)
                    {
                        // iterate through and add to wawList
                        foreach (int line in codeLine)
                        {
                            wawList += " " + line;
                        }
                        // add to the hazard warnings list
                        wawList += ". Be careful when executing out-of-order.";
                        warn.Items.Add(wawList);
                    }
                }
            }
        }
        //method to dectect and print WAR hazards
        private void printWAR(ref App.Cpu cpu)
        {
            // iterate through the instruction list
            for (int i = 0; i < cpu.Pipeline.Count(); i++)
            {
                string     currSrc1 = cpu.Pipeline[i].srcReg1;
                string     currSrc2 = null;
                string     output   = "Warning: Potential WAR hazard. The following lines have a destination that line ";
                List <int> codeLine = new List <int>();

                // determine # of registers depending on instruction type
                if (cpu.Pipeline[i] is App.RType rtype)
                {
                    currSrc2 = rtype.srcReg2;
                }
                else if (cpu.Pipeline[i] is App.Store store)
                {
                    currSrc2 = store.srcReg2;
                }
                // iterate through the list again and compare destination outputs to source registers
                for (int n = 0; n < cpu.Pipeline.Count(); n++)
                {
                    string dest = cpu.Pipeline[n].destReg;

                    if (i != n && (dest == currSrc1 || dest == currSrc2) && dest != null)
                    {
                        codeLine.Add(n);
                    }
                }
                // if hazards were found, add to string
                if (codeLine.Count() > 0)
                {
                    output += i + " uses as a source:";

                    foreach (int num in codeLine)
                    {
                        output += " " + num;
                    }
                    // output string
                    output += ". Be careful when executing out-of-order.";
                    warn.Items.Add(output);
                }
            }
        }
        // method to create pipeline with forwarding
        public void forward(ref App.Cpu cpu)
        {
            for (int i = 0; i < cpu.Pipeline.Count; i++)
            {
                // add new line to pipeline
                cpu.Forwarding.Add(new List <char>());

                // if first in list, don't need stalls
                if (i == 0)
                {
                    cpu.Forwarding[i].Add('F');
                    cpu.Forwarding[i].Add('D');
                    cpu.Forwarding[i].Add('X');
                    cpu.Forwarding[i].Add('M');
                    cpu.Forwarding[i].Add('W');
                }
                // else if (i == 1)
                else
                {
                    // figure out how many to indent if based on previous D
                    int indent = cpu.Forwarding[i - 1].FindIndex(item => item == 'D');

                    // add indents
                    for (int n = 0; n < indent; n++)
                    {
                        cpu.Forwarding[i].Add(' ');
                    }
                    // add stalls if need if memory is unified
                    if (cpu.separateMem == false)
                    {
                        int  column = indent;
                        int  count  = 1;
                        bool safe   = false;

                        while (safe == false && count <= 4 && i - count >= 0)
                        {
                            // what cycle mem acces is on previous cycle
                            int memAccess = cpu.Forwarding[i - count].FindIndex(item => item == 'M');

                            if (memAccess == column)
                            {
                                cpu.Forwarding[i].Add('-');
                                column++;
                                count = 1;
                            }
                            else
                            {
                                count++;
                            }
                        }
                    }

                    // add F stage
                    cpu.Forwarding[i].Add('F');

                    // if the current instruction is an R Type
                    if (cpu.Pipeline[i] is App.RType)
                    {
                        // cast as R Type
                        var tempInst = cpu.Pipeline[i] as App.RType;

                        // start count at 1
                        int count = 1;

                        // check 4 instructions back
                        while (i - count >= 0 && count < 4)
                        {
                            // if there is a RAW hazard
                            if (cpu.Pipeline[i - count].destReg == tempInst.srcReg1 || cpu.Pipeline[i - count].destReg == tempInst.srcReg2)
                            {
                                // check instruction for when register is needed
                                char need = cpu.Pipeline[i].forwNeed;
                                // check instruction for when register is available
                                char avail = cpu.Pipeline[i - count].forwAvail;

                                // use needNum to find difference
                                int needNum;

                                switch (need)
                                {
                                case 'F':
                                    needNum = 0;
                                    break;

                                case 'D':
                                    needNum = 1;
                                    break;

                                case 'X':
                                    needNum = 2;
                                    break;

                                case 'M':
                                    needNum = 3;
                                    break;

                                case 'W':
                                    needNum = 4;
                                    break;

                                default:
                                    needNum = 5;
                                    break;
                                }

                                // only have F right now, so calculate how many spaces needed based on F index
                                int j = cpu.Forwarding[i].FindIndex(item => item == 'F');
                                j += needNum;

                                int k = cpu.Forwarding[i - count].FindIndex(item => item == avail);

                                int diff = k - j;

                                // if arrow is pointing backwards
                                if (diff > 0)
                                {
                                    // add stalls
                                    for (int n = 0; n < diff; n++)
                                    {
                                        cpu.Forwarding[i].Add('-');
                                    }
                                }
                            }
                            count++;
                        }
                    }

                    // if the current instruction is load type
                    else if (cpu.Pipeline[i] is App.Load)
                    {
                        // cast as R Type
                        var tempInst = cpu.Pipeline[i] as App.Load;

                        // start count at 1
                        int count = 1;

                        // check 4 instructions back
                        while (i - count >= 0 && count < 4)
                        {
                            // if there is a RAW hazard
                            if (cpu.Pipeline[i - count].destReg == tempInst.srcReg1)
                            {
                                // check instruction for when register is needed
                                char need = cpu.Pipeline[i].forwNeed;
                                // check instruction for when register is available
                                char avail = cpu.Pipeline[i - count].forwAvail;

                                // use needNum to find difference
                                int needNum;

                                switch (need)
                                {
                                case 'F':
                                    needNum = 0;
                                    break;

                                case 'D':
                                    needNum = 1;
                                    break;

                                case 'X':
                                    needNum = 2;
                                    break;

                                case 'M':
                                    needNum = 3;
                                    break;

                                case 'W':
                                    needNum = 4;
                                    break;

                                default:
                                    needNum = 5;
                                    break;
                                }

                                // only have F right now, so calculate how many spaces needed based on F index
                                int j = cpu.Forwarding[i].FindIndex(item => item == 'F');
                                j += needNum;

                                int k = cpu.Forwarding[i - count].FindIndex(item => item == avail);

                                int diff = k - j;

                                // if arrow is pointing backwards
                                if (diff > 0)
                                {
                                    // add stalls
                                    for (int n = 0; n < diff; n++)
                                    {
                                        cpu.Forwarding[i].Add('-');
                                    }
                                }
                            }
                            count++;
                        }
                    }

                    // if the current instruction is store type
                    else if (cpu.Pipeline[i] is App.Store)
                    {
                        // cast as R Type
                        var tempInst = cpu.Pipeline[i] as App.Store;

                        // start count at 1
                        int count = 1;

                        // check 4 instructions back
                        while (i - count >= 0 && count < 4)
                        {
                            // if there is a RAW hazard
                            if (cpu.Pipeline[i - count].destReg == tempInst.srcReg1 || cpu.Pipeline[i - count].destReg == tempInst.srcReg2)
                            {
                                // check instruction for when register is needed
                                char need = cpu.Pipeline[i].forwNeed;
                                // check instruction for when register is available
                                char avail = cpu.Pipeline[i - count].forwAvail;

                                // use needNum to find difference
                                int needNum;

                                switch (need)
                                {
                                case 'F':
                                    needNum = 0;
                                    break;

                                case 'D':
                                    needNum = 1;
                                    break;

                                case 'X':
                                    needNum = 2;
                                    break;

                                case 'M':
                                    needNum = 3;
                                    break;

                                case 'W':
                                    needNum = 4;
                                    break;

                                default:
                                    needNum = 5;
                                    break;
                                }

                                // only have F right now, so calculate how many spaces needed based on F index
                                int j = cpu.Forwarding[i].FindIndex(item => item == 'F');
                                j += needNum;

                                int k = cpu.Forwarding[i - count].FindIndex(item => item == avail);

                                int diff = k - j;

                                // if arrow is pointing backwards
                                if (diff > 0)
                                {
                                    // add stalls
                                    for (int n = 0; n < diff; n++)
                                    {
                                        cpu.Forwarding[i].Add('-');
                                    }
                                }
                            }
                            count++;
                        }
                    }
                    // add rest of stages
                    cpu.Forwarding[i].Add('D');
                    cpu.Forwarding[i].Add('X');
                    cpu.Forwarding[i].Add('M');
                    cpu.Forwarding[i].Add('W');
                }
            }
        }