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