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

using namespace std;

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

    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);		// set initial PC
    machdep->set_sp(init_sp);		// set initial SP

    cout << "program start" << endl;
    cout << "PC=" << hex << machdep->get_pc() << endl;
    cout << "SP=" << hex << machdep->get_sp() << 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->ID(); phase++; break;
	case 2:
	    machdep->EX(); phase++; break;
	case 3:
	    machdep->MA(); phase++; break;
	case 4:
	    machdep->WB(); phase = 0; break;
	}
	// stall check
	if (machdep->is_stalled())
	    phase = (phase == 0)? 4: phase-1;
        else {
            // multi-cycle execution check
            // (repeat EX, MA, and WB until completion)
            if (machdep->is_multicycle_execution())
                phase = (phase == 0)? 2: phase;
        }

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

	cycle_time++;		// increment cycle counter
    }

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

// end of cpu.cc