// -*- c++ -*-
//
// cpu.cc:
//
#include <iostream>
#include "cpu.h"

using namespace std;

//
// constructor
//
cpu::cpu()
{
    machdep = new mips; 

    cycle_time = 0;
}

//
// destructor
//
cpu::~cpu()
{
    delete machdep;
}

//
// cpu class member functions
//
void
cpu::connect_memory(memory *mem)
{
    this->mem = mem;
    machdep->connect_memory(mem);
}

void
cpu::connect_icache(cache *icache)
{
    this->icache = icache;
    machdep->connect_icache(icache);
}

void
cpu::connect_dcache(cache *dcache)
{
    this->dcache = dcache;
    machdep->connect_dcache(dcache);
}

void
cpu::execute(sim_addr init_pc, sim_addr init_sp)
{
    int phase = 0;

    machdep->reset();

    machdep->set_pc(init_pc);
    machdep->set_reg(29, init_sp);	// set initial value for SP

    cout << "program start" << endl;
    cout << "PC=" << hex << machdep->get_pc() << endl;
    cout << "SP=" << hex << machdep->get_reg(29) << endl;

    while (machdep->is_running()) {	// instruction cycle
	cout << "********** cycle=" << dec << cycle_time
	     << " **********" << endl;

	machdep->reset_stall_condition();

	switch (phase) {
	case 0:
            machdep->IF(); phase++; break;
	case 1:
	    machdep->IS(); phase++; break;
	case 2:
	    machdep->RR(); phase++; break;
	case 3:
	    machdep->EX(); phase++; break;
	case 4:
	    machdep->MA(); phase++; break;
	case 5:
	    machdep->WB(); phase = 0; break;
	}
	// stall check
	if (machdep->is_stalled())
	    phase = (phase == 0)? 5: phase-1;

	// update cache
	icache->update();
	dcache->update();

	cycle_time++;		// increment cycle counter
    }

    cout << "program finished" << endl;
}

// end of cpu.cc