processor.cc
// INCLUDE THE CLASS DECLARATION

#include "processor.h"

// INCLUDE EXCEPTION HANDLING

#include "smi_exception.h"

// INCLUDE CLASSES USED IN THE IMPLEMENTATION

#include "smi_channel.h"
#include "smi_message.h"
#include <iostream.h>

//****************************
// CLASS DEFINITION: Processor
//****************************

// CONSTANTS: MUST MATCH THE DEFINITION USED BY THE VERILOG WRAPPER

const unsigned int Processor::CPU_NULL        = 0;
const unsigned int Processor::CPU_CONFIGURE   = 1;
const unsigned int Processor::CPU_INSTRUCTION = 2;
const unsigned int Processor::CPU_IDLE        = 3;
const unsigned int Processor::CPU_OUT         = 4;
const unsigned int Processor::CPU_IN          = 5;
const unsigned int Processor::CPU_DATA        = 6;
const unsigned int Processor::CPU_INTERRUPT   = 7;
const unsigned int Processor::CPU_IRET        = 8;

// CONSTRUCTOR

Processor::Processor(const string& name)
{
    // FETCH THE SMI CHANNEL POINTER

    SMI_Channel* channel = SMI_Channel::instance();

    // ALLOCATE AN SMI REPLY MESSAGE

    d_instruction = channel->newTxMessage();

    // REGISTER THIS MODEL INSTANCE WITH SMI

    channel->add(name, "processor", this);
}

// DESTRUCTOR

Processor::~Processor()
{
    // DELETE THE SMI REPLY MESSAGE

    delete d_instruction;
}

// METHOD: process(rx)

SMI_TxMessage*
Processor::process(const SMI_RxMessage& rx)
{
    // SAVE THE MESSAGE TYPE FOR PROCESSING IN send() OR receive()
    // CHOOSE AN ACTION DEPENDING ON THE MESSAGE TYPE

    switch(d_inbox = rx.integer(0))
    {

    // IF THE MESSAGE TYPE IS "Configure"

    case CPU_CONFIGURE:

        // SET THE ADDRESS BUS WIDTH

        d_addr_width = rx.integer(1);

        // SET THE DATA BUS WIDTH

        d_data_width = rx.integer(2);
        break;

    //  IF THE MESSAGE TYPE IS "Data"

    case CPU_DATA:

        // SAVE THE DATA VALUE FOR PROCESSING IN receive()

        d_return = rx.integer(1);
        break;
    }

    // RETURN ANY REPLY MESSAGE

    return d_instruction;
}

// METHOD: send()

void
Processor::send()
{
    // FETCH THE SMI CHANNEL POINTER

    SMI_Channel* channel = SMI_Channel::instance();

    // LOOP UNTIL AN "Instruction" MESSAGE IS RECEIVED

    for (d_inbox = CPU_NULL; d_inbox != CPU_INSTRUCTION; )
    {
        // PROCESS THE NEXT SMI MESSAGE

        channel->wait();

        // IF THE MESSAGE TYPE WAS "Interrupt"

        if (d_inbox == CPU_INTERRUPT)
        {
            // SAVE THE PENDING INSTRUCTION/REPLY MESSAGE

            SMI_TxMessage* stack = d_instruction;

            // ALLOCATE A NEW PENDING INSTRUCTION/REPLY MESSAGE

            d_instruction = channel->newTxMessage();

            // CALL THE INTERRUPT SERVICE ROUTINE

            interrupt();

            // SET THE PENDING MESSAGE TO "IRet" AND SEND

            d_instruction->append(32, CPU_IRET);
            send();

            // RESTORE THE PENDING INSTRUCTION/REPLY MESSAGE

            delete d_instruction;
            d_instruction = stack;

            // CLEAR THE INCOMING MESSAGE TYPE

            d_inbox = CPU_NULL;
        }
    }
}

// METHOD: receive()

unsigned long
Processor::receive()
{
    // FETCH THE SMI CHANNEL POINTER

    SMI_Channel* channel = SMI_Channel::instance();

    // LOOP UNTIL A "Data" MESSAGE IS RECEIVED

    for (d_inbox = CPU_NULL; d_inbox != CPU_DATA; channel->wait());

    // RETURN THE DATA VALUE TRANSMITTED IN THE "Data" MESSAGE

    return d_return;
}

// METHOD: idle()

void Processor::idle()
{
    // SET THE PENDING MESSAGE TO "Idle" AND SEND

    d_instruction->append(32, CPU_IDLE);
    send();
}

// METHOD: out(address, data)

void
Processor::out(unsigned long address, unsigned long data)
{
    // SET THE PENDING MESSAGE TO "Out" AND SEND

    d_instruction->append(32, CPU_OUT);
    d_instruction->append(d_addr_width, address);
    d_instruction->append(d_data_width, data);
    send();
}

// METHOD: in(address)

unsigned long
Processor::in(unsigned long address)
{
    // SET THE PENDING MESSAGE TO "In" AND SEND

    d_instruction->append(32, CPU_IN);
    d_instruction->append(d_addr_width, address);
    send();

    // RETURN THE DATA VALUE FROM THE "Data" REPLY MESSAGE

    return receive();
}
© Copyright 2000-2001 Adrian Lewis