Show simplememory.h syntax highlighted
// LICENSETEXT
//
// Copyright (C) 2005,2006 :
// GreenSocs Ltd
// (http://www.greensocs.com/),
//
// email: info@greensocs.com
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
//
// ENDLICENSETEXT
#include <systemc.h>
#include <list>
using std::list;
#include "gstlm/gstlm/tlm.h"
#include "gstlm/protocol/generic.h"
#include "gstlm/userAPI/basicPorts.h"
#include "gstlm/gstlm/tlm_slave_if.h"
using namespace tlm;
#include <iomanip>
#define DELAY(x) 10*x, SC_NS
class simplememory
: public sc_module,
public tlm_b_if<GenericTransaction_P>,
public tlm_slave_if<MAddr>
{
public:
GenericTargetPort target_port;
typedef GenericTargetPort::accessHandle accessHandle;
typedef GenericTargetPort::phaseHandle phaseHandle;
unsigned char MEM[MEMSIZE];
std::list<std::pair<accessHandle, phaseHandle > > waiting;
bool inWrite;
int m_delay;
MAddr m_base, m_high;
// simplememory functions
void react();
void PVTProcess(GenericTargetPort::accessHandle, GenericTargetPort::phaseHandle);
int IPmodel( GenericTargetPort::accessHandle t);
// tlm_b_if implementation
void b_transact(GenericTransaction_P);
// tlm_slave_if implementation
virtual void setAddress(MAddr base, MAddr high);
virtual void getAddress(MAddr& base, MAddr& high);
SC_HAS_PROCESS(simplememory);
/**
* Constructor.
* @param name_ Module name.
* @param delay_ Access delay in cycles.
*/
simplememory(sc_module_name name_, int delay_) :
sc_module(name_),
target_port("tport"),
inWrite(false),
m_delay(delay_),
m_base(0),
m_high(0)
{
target_port.bind_b_if(*this);
SC_METHOD(react);
sensitive << target_port.default_event();
dont_initialize();
}
};
void simplememory::b_transact( GenericTransaction_P t)
{
(void) IPmodel(t); // we dont care about timing
}
void simplememory::react()
{
GenericTargetPort::accessHandle tah=target_port.get_transactionHandle();
GenericTargetPort::phaseHandle p=target_port.get_phase();
PVTProcess(tah,p);
}
/* This method plays out the protocol. We can do this how we like, so long as we
* stick to the generic protocol. We can hard wire in some number, ask the IP
* block, be random, whatever. These numbers determin which "real" bus protocol
* we are essencially modelling */
void simplememory::PVTProcess( GenericTargetPort::accessHandle tah, GenericTargetPort::phaseHandle p)
{
switch (p.state) {
case GenericPhase::RequestValid:
{
if (inWrite) {
//keep writes in order !!!
GSTRACE("I am busy... can't process this write for now");
waiting.push_back(std::pair<GenericTargetPort::accessHandle, GenericTargetPort::phaseHandle > (tah,p));
}
else {
target_port.AckRequest(tah, p, DELAY(1));
if (tah->get_mCmd() == Generic_MCMD_RD) {
GSTRACE("accepted READ cmd, sending data now.");
target_port.Response(tah, p, DELAY(IPmodel(tah)));
} else {
GSTRACE("accepted WRITE cmd (in 1 cycle), now waiting for data.");
inWrite=true;
}
}
}
break;
case GenericPhase::DataAccepted:
{
GSTRACE("master sent DataAccepted. Transaction finished OK.");
}
break;
case GenericPhase::DataValid:
{
GSTRACE("receiving data from master.");
MasterDataType my_data;
my_data.set(tah->get_mData());
// dump data to screen
cout<<name()<<" @ "<<sc_time_stamp()<<"/"<<sc_delta_count()
<<": got data [size="<<my_data.byte_size()<<"] {";
for (unsigned int i=0; i<my_data.byte_size(); i++) {
cout<<my_data[i]<<flush;
}
cout<<"}"<<endl;
tah->get_mData(MasterDataType( & MEM[tah->get_mAddr()-m_base] ,tah->get_mBurstLength() ));
// send DataAck
target_port.AckData(tah,p,DELAY(tah->get_mBurstLength()-1));
inWrite =false;
if (!waiting.empty()) {
GSTRACE(" RE-AWAKE pending write ");
std::pair<GenericTargetPort::accessHandle, GenericTargetPort::phaseHandle >
pair =waiting.front();
waiting.pop_front();
PVTProcess(pair.first,pair.second);
}
}
break;
case GenericPhase::ResponseAccepted:
{
GSTRACE("master sent ResponseAccepted. Transaction finished OK.");
}
break;
default:
{
SC_REPORT_ERROR( sc_core::SC_ID_INTERNAL_ERROR_, "Phase not recognized" );
}
break;
}
}
/* Here is what the user should end up writing
a very simple model,
to work in a 'co-war' like environment, where the model writer thinks about
timing up front, then this model can return a timing number, or a strucutre
of timing numbers if required */
int simplememory::IPmodel( GenericTargetPort::accessHandle t)
{
switch (t->get_mCmd()) {
case Generic_MCMD_RD:
GSTRACE("processing blocking READ");
cout<<"BurstL: "<<t->get_mBurstLength()<<endl
<<"Addr: "<<(t->get_mAddr()-m_base)<<endl
<<"Data: "<<(MEM[t->get_mAddr()-m_base])<<endl
<<flush;
t->set_sData(MasterDataType( & MEM[t->get_mAddr()-m_base] ,t->get_mBurstLength() ));
return m_delay;
break;
case Generic_MCMD_WR:
GSTRACE("processing blocking WRITE");
t->get_mData(MasterDataType( & MEM[t->get_mAddr()-m_base] ,t->get_mBurstLength() ));
return m_delay*2;
break;
}
return 0;
}
void simplememory:: setAddress(MAddr base, MAddr high)
{
m_base =base;
m_high =high;
}
void simplememory:: getAddress(MAddr& base, MAddr& high)
{
base =m_base;
high =m_high;
}
See more files for this project here