public void update_wb_mode()
        {
            bool prev_wb_mode = wb_mode;

            wb_mode = mwbmode.is_wb_mode(cid);
            if (wb_mode)
            {
                Stat.mctrls[cid].wbmode_fraction.Collect();
            }

            if (prev_wb_mode == false && wb_mode == true)
            {
                //stats
                ts_start_wbmode = cycles;
                if (ts_end_wbmode != -1)
                {
                    Stat.mctrls[cid].wbmode_distance.Collect((int)(ts_start_wbmode - ts_end_wbmode));
                }

                /*
                 * if (cid == 0) {
                 *  Console.WriteLine("=====Start: {0,8}======================================", cycles);
                 *  Console.Write("\t");
                 *  for (uint b = 0; b < bmax; b++) {
                 *      Console.Write("{0,4}", readqs[0, b].Count);
                 *  }
                 *  Console.WriteLine();
                 *
                 *  Console.Write("\t");
                 *  for (uint b = 0; b < bmax; b++) {
                 *      Console.Write("{0,4}", writeqs[0, b].Count);
                 *  }
                 *  Console.WriteLine();
                 * }
                 */

                //stats: longest write transaction
                int longest_transaction = 0;
                for (uint r = 0; r < rmax; r++)
                {
                    for (uint b = 0; b < bmax; b++)
                    {
                        List <Req> q = writeqs[r, b];
                        Dictionary <ulong, int> dict = new Dictionary <ulong, int>();
                        foreach (Req req in q)
                        {
                            if (!dict.ContainsKey(req.addr.rowid))
                            {
                                dict.Add(req.addr.rowid, 0);
                            }
                            dict[req.addr.rowid] += 1;
                        }

                        foreach (int transaction in dict.Values)
                        {
                            if (transaction > longest_transaction)
                            {
                                longest_transaction = transaction;
                            }
                        }
                    }
                }
                Stat.mctrls[cid].wbmode_longest_transaction.Collect(longest_transaction);

                /*
                 * if (cid == 0)
                 *  Console.WriteLine("Longest Transaction: {0}", longest_transaction);
                 */

                //flush/drain reads
                reads_to_drain = 0;
                for (uint r = 0; r < rmax; r++)
                {
                    for (uint b = 0; b < bmax; b++)
                    {
                        List <Cmd> cmdq = cmdqs[r, b];
                        if (cmdq.Count == 0)
                        {
                            continue;
                        }

                        //only column command
                        if (cmdq.Count == 1)
                        {
                            //increment the number of reads to drain during the first part of the writeback mode
                            Dbg.Assert(cmdq[0].type == Cmd.TypeEnum.READ || cmdq[0].type == Cmd.TypeEnum.WRITE);
                            if (cmdq[0].type == Cmd.TypeEnum.READ)
                            {
                                reads_to_drain++;
                                cmdq[0].is_drain = true;
                            }
                            continue;
                        }

                        //activate+column command
                        Dbg.Assert(cmdq.Count == 2);
                        Dbg.Assert(cmdq[0].type == Cmd.TypeEnum.ACTIVATE);
                        Dbg.Assert(cmdq[1].type == Cmd.TypeEnum.READ || cmdq[1].type == Cmd.TypeEnum.WRITE);

                        //write requests don't matter
                        if (cmdq[1].type == Cmd.TypeEnum.WRITE)
                        {
                            continue;
                        }

                        //don't flush read request
                        if (Config.mctrl.read_bypass)
                        {
                            if (writeqs[r, b].Count == 0)
                            {
                                continue;
                            }
                        }

                        //flush read request
                        Req req = cmdq[1].req;

                        List <Req> inflightq = get_inflight_q(req);
                        Req        last_req  = inflightq[inflightq.Count - 1];
                        Dbg.Assert(last_req.block_addr == req.block_addr);
                        inflightq.RemoveAt(inflightq.Count - 1);

                        if (Config.proc.cache_insertion_policy == "PFA")
                        {
                            Measurement.NVMResetRowBufferChange(req);
                        }

                        List <Req> q = get_q(req);
                        //         Dbg.Assert(q.Count <= q.Capacity);
                        q.Add(req);

                        //flush read command
                        cmdq.RemoveRange(0, 2);

                        if (Config.proc.cache_insertion_policy == "PFA")
                        {
                            Measurement.NVM_bus_conflict_reset(req.pid);
                        }
                    }
                }
            }
            else if (prev_wb_mode == true && wb_mode == false)
            {
                //stats
                ts_end_wbmode = cycles;
                Stat.mctrls[cid].wbmode_length.Collect((int)(ts_end_wbmode - ts_start_wbmode));

                /*
                 * if (cid == 0) {
                 *  Console.WriteLine("Length: {0}", cycles-ts_start_wbmode);
                 *  Console.WriteLine("Rds: {0}", rds_per_wb_mode);
                 *  Console.WriteLine("Wrs: {0}", wbs_per_wb_mode);
                 *  Console.WriteLine("=====End: {0,8}======================================", cycles);
                 * }
                 */

                Stat.mctrls[cid].rds_per_wb_mode.Collect(rds_per_wb_mode);
                Stat.mctrls[cid].wbs_per_wb_mode.Collect(wbs_per_wb_mode);
                rds_per_wb_mode = 0;
                wbs_per_wb_mode = 0;

                //flush/drain writes
                writes_to_drain = 0;
                foreach (List <Cmd> cmdq in cmdqs)
                {
                    if (cmdq.Count == 0)
                    {
                        continue;
                    }

                    //only column command
                    if (cmdq.Count == 1)
                    {
                        //increment the number of reads to drain during the first part of the writeback mode
                        Dbg.Assert(cmdq[0].type == Cmd.TypeEnum.READ || cmdq[0].type == Cmd.TypeEnum.WRITE);
                        if (cmdq[0].type == Cmd.TypeEnum.WRITE)
                        {
                            writes_to_drain++;
                            cmdq[0].is_drain = true;
                        }
                        continue;
                    }

                    //activate+column command
                    Dbg.Assert(cmdq.Count == 2);
                    Dbg.Assert(cmdq[0].type == Cmd.TypeEnum.ACTIVATE);
                    Dbg.Assert(cmdq[1].type == Cmd.TypeEnum.READ || cmdq[1].type == Cmd.TypeEnum.WRITE);

                    if (cmdq[1].type == Cmd.TypeEnum.READ)
                    {
                        continue;
                    }

                    //flush read request
                    Req req = cmdq[1].req;

                    List <Req> inflightq = get_inflight_q(req);
                    Req        last_req  = inflightq[inflightq.Count - 1];
                    Dbg.Assert(last_req.block_addr == req.block_addr);
                    inflightq.RemoveAt(inflightq.Count - 1);

                    if (Config.proc.cache_insertion_policy == "PFA")
                    {
                        Measurement.NVMResetRowBufferChange(req);
                    }

                    List <Req> q = get_q(req);
                    //       Dbg.Assert(q.Count <= q.Capacity);

                    q.Add(req);

                    //flush read command
                    cmdq.RemoveRange(0, 2);

                    if (Config.proc.cache_insertion_policy == "PFA")
                    {
                        Measurement.NVM_bus_conflict_reset(req.pid);
                    }
                }
            }
        }
        private void issue_cmd(Cmd cmd)
        {
            MemAddr addr = cmd.addr;

            /*
             * if (cid == 0 && wb_mode) {
             *  Console.Write("@{0}\t", cycles - ts_start_wbmode);
             *  for (uint b = 0; b < addr.bid; b++) {
             *      Console.Write("{0,4}", "-");
             *  }
             *  Console.Write("{0,4}", cmd.type.ToString()[0]);
             *  for (uint b = addr.bid; b < bmax; b++) {
             *      Console.Write("{0,4}", "-");
             *  }
             *  Console.WriteLine();
             * }
             */

            List <Cmd> cmd_q = cmdqs[addr.rid, addr.bid];

            Dbg.Assert(cmd == cmd_q[0]);
            cmd_q.RemoveAt(0);
            BankStat bank_stat = Stat.banks[addr.cid, addr.rid, addr.bid];
            BusStat  bus_stat  = Stat.busses[addr.cid];

            //writeback mode stats
            if (wb_mode)
            {
                if (cmd.type == Cmd.TypeEnum.READ)
                {
                    rds_per_wb_mode++;
                }
                else if (cmd.type == Cmd.TypeEnum.WRITE)
                {
                    wbs_per_wb_mode++;
                }
            }

            //string dbg;
            switch (cmd.type)
            {
            case Cmd.TypeEnum.ACTIVATE:
                activate(addr);

                /*dbg = String.Format("@{0,6} DRAM ACTI: Channel {1}, Rank {2}, Bank {3}, Row {4}, Col {5}",
                 *  cycles, cid, addr.rid, addr.bid, addr.rowid, addr.colid);*/
                //stats
                bank_stat.cmd_activate.Collect();
                bank_stat.utilization.Collect(timing.tRCD);

                //shadow row-buffer id
                shadow_rowid_per_procrankbank[cmd.pid, addr.rid, addr.bid] = addr.rowid;
                break;

            case Cmd.TypeEnum.PRECHARGE:
                precharge(addr);

                /*dbg = String.Format("@{0,6} DRAM PREC: Channel {1}, Rank {2}, Bank {3}, Row {4}, Col {5}",
                 *  cycles, cid, addr.rid, addr.bid, addr.rowid, addr.colid);*/
                //stats
                bank_stat.cmd_precharge.Collect();
                bank_stat.utilization.Collect(timing.tRP);
                break;

            case Cmd.TypeEnum.READ:
                read(addr);

                if (Config.proc.cache_insertion_policy == "PFA")
                {
                    Measurement.NVM_bus_conflict_reset(cmd.req.pid);
                }

                /*dbg = String.Format("@{0,6} DRAM READ: Channel {1}, Rank {2}, Bank {3}, Row {4}, Col {5}",
                 *  cycles, cid, addr.rid, addr.bid, addr.rowid, addr.colid);*/

                //writeback mode
                if (wb_mode && cmd.is_drain)
                {
                    Dbg.Assert(reads_to_drain > 0);
                    reads_to_drain--;
                }

                //stats
                bank_stat.cmd_read.Collect();
                bank_stat.utilization.Collect(timing.tCL);
                bus_stat.access.Collect();
                bus_stat.utilization.Collect(timing.tBL);
                break;

            case Cmd.TypeEnum.WRITE:
                write(addr);

                if (Config.proc.cache_insertion_policy == "PFA")
                {
                    Measurement.NVM_bus_conflict_reset(cmd.req.pid);
                }

                /*dbg = String.Format("@{0,6} DRAM WRTE: Channel {1}, Rank {2}, Bank {3}, Row {4}, Col {5}",
                 *  cycles, cid, addr.rid, addr.bid, addr.rowid, addr.colid);*/

                //writeback mode
                if (!wb_mode && cmd.is_drain)
                {
                    Dbg.Assert(writes_to_drain > 0);
                    writes_to_drain--;
                }
                else
                {
                    mwbmode.issued_write_cmd(cmd);
                }

                //stats
                bank_stat.cmd_write.Collect();
                bank_stat.utilization.Collect(timing.tCL);
                bus_stat.access.Collect();
                bus_stat.utilization.Collect(timing.tBL);
                break;

            default:
                //should never get here
                throw new System.Exception("DRAM: Invalid Cmd.");
            }
            //Debug.WriteLine(dbg);
        }