ruby: Removed static members in RubyPort including hitcallback

Removed static members in RubyPort and removed the ruby request unique id.
This commit is contained in:
Brad Beckmann 2010-01-29 20:29:33 -08:00
parent a579d3e43c
commit 1feae85017
10 changed files with 118 additions and 155 deletions

View file

@ -338,5 +338,12 @@ enumeration(TransientRequestType, desc="...", default="TransientRequestType_Unde
LocalTransient, desc="";
}
// Request Status
enumeration(RequestStatus, desc="...", default="RequestStatus_NULL") {
Ready, desc="The sequencer is ready and the request does not alias";
Issued, desc="The sequencer successfully issued the request";
BufferFull, desc="Can not issue because the sequencer is full";
Aliased, desc="This request aliased with a currently outstanding request";
LlscFailed, desc="The write failed in the Load-Link Store-Conditional pair";
NULL, desc="";
}

View file

@ -132,7 +132,11 @@ void libruby_init(const char* cfg_filename)
RubyPortHandle libruby_get_port(const char* port_name, void (*hit_callback)(int64_t access_id))
{
return static_cast<RubyPortHandle>(RubySystem::getPort(port_name, hit_callback));
//
// Fix me: Hit callback is now a non-static member function pointer of
// RubyPort and cannot be set to an arbitrary global function
//
return NULL;//static_cast<RubyPortHandle>(RubySystem::getPort(port_name, hit_callback));
}
RubyPortHandle libruby_get_port_by_name(const char* port_name)

View file

@ -4,6 +4,7 @@
#include <stdint.h>
#include <ostream>
#include "mem/packet.hh"
typedef void* RubyPortHandle;
enum RubyRequestType {
@ -31,11 +32,26 @@ struct RubyRequest {
uint64_t pc;
RubyRequestType type;
RubyAccessMode access_mode;
PacketPtr pkt;
unsigned proc_id;
RubyRequest() {}
RubyRequest(uint64_t _paddr, uint8_t* _data, int _len, uint64_t _pc, RubyRequestType _type, RubyAccessMode _access_mode, unsigned _proc_id = 100)
: paddr(_paddr), data(_data), len(_len), pc(_pc), type(_type), access_mode(_access_mode), proc_id(_proc_id)
RubyRequest(uint64_t _paddr,
uint8_t* _data,
int _len,
uint64_t _pc,
RubyRequestType _type,
RubyAccessMode _access_mode,
PacketPtr _pkt,
unsigned _proc_id = 100)
: paddr(_paddr),
data(_data),
len(_len),
pc(_pc),
type(_type),
access_mode(_access_mode),
pkt(_pkt),
proc_id(_proc_id)
{}
};
@ -71,12 +87,6 @@ RubyPortHandle libruby_get_port(const char* name, void (*hit_callback)(int64_t a
RubyPortHandle libruby_get_port_by_name(const char* name);
/**
* libruby_issue_request error return codes
*/
#define LIBRUBY_BUFFER_FULL -2
#define LIBRUBY_ALIASED_REQUEST -3
/**
* issue_request returns a unique access_id to identify the ruby
* transaction. This access_id is later returned to the caller via

View file

@ -85,7 +85,8 @@ void TraceRecord::issueRequest() const
RubySystem::getBlockSizeBytes(),
m_pc_address.getAddress(),
m_type,
RubyAccessMode_User);
RubyAccessMode_User,
NULL);
// Clear out the sequencer
while (!m_sequencer_ptr->empty()) {

View file

@ -24,7 +24,7 @@ void DMASequencer::init()
m_data_block_mask = ~ (~0 << RubySystem::getBlockSizeBits());
}
int64_t DMASequencer::makeRequest(const RubyRequest & request)
RequestStatus DMASequencer::makeRequest(const RubyRequest & request)
{
uint64_t paddr = request.paddr;
uint8_t* data = request.data;
@ -44,7 +44,8 @@ int64_t DMASequencer::makeRequest(const RubyRequest & request)
case RubyRequestType_RMW_Read:
case RubyRequestType_RMW_Write:
case RubyRequestType_NUM:
assert(0);
panic("DMASequencer::makeRequest does not support the RubyRequestType");
return RequestStatus_NULL;
}
assert(!m_is_busy); // only support one outstanding DMA request
@ -56,7 +57,7 @@ int64_t DMASequencer::makeRequest(const RubyRequest & request)
active_request.len = len;
active_request.bytes_completed = 0;
active_request.bytes_issued = 0;
active_request.id = makeUniqueRequestID();
active_request.pkt = request.pkt;
SequencerMsg msg;
msg.getPhysicalAddress() = Address(paddr);
@ -76,7 +77,7 @@ int64_t DMASequencer::makeRequest(const RubyRequest & request)
m_mandatory_q_ptr->enqueue(msg);
active_request.bytes_issued += msg.getLen();
return active_request.id;
return RequestStatus_Issued;
}
void DMASequencer::issueNext()
@ -84,14 +85,14 @@ void DMASequencer::issueNext()
assert(m_is_busy == true);
active_request.bytes_completed = active_request.bytes_issued;
if (active_request.len == active_request.bytes_completed) {
m_hit_callback(active_request.id);
ruby_hit_callback(active_request.pkt);
m_is_busy = false;
return;
}
SequencerMsg msg;
msg.getPhysicalAddress() = Address(active_request.start_paddr +
active_request.bytes_completed);
active_request.bytes_completed);
assert((msg.getPhysicalAddress().getAddress() & m_data_block_mask) == 0);
msg.getLineAddress() = line_address(msg.getPhysicalAddress());

View file

@ -15,7 +15,7 @@ struct DMARequest {
int bytes_completed;
int bytes_issued;
uint8* data;
int64_t id;
PacketPtr pkt;
};
class DMASequencer :public RubyPort {
@ -24,9 +24,7 @@ public:
DMASequencer(const Params *);
void init();
/* external interface */
int64_t makeRequest(const RubyRequest & request);
bool isReady(const RubyRequest & request, bool dont_set = false) { assert(0); return false;};
// void issueRequest(uint64_t paddr, uint8* data, int len, bool rw);
RequestStatus makeRequest(const RubyRequest & request);
bool busy() { return m_is_busy;}
/* SLICC callback */

View file

@ -32,10 +32,6 @@
#include "mem/ruby/slicc_interface/AbstractController.hh"
#include "cpu/rubytest/RubyTester.hh"
uint16_t RubyPort::m_num_ports = 0;
RubyPort::RequestMap RubyPort::pending_cpu_requests;
RubyPort::RubyPort(const Params *p)
: MemObject(p)
{
@ -47,12 +43,9 @@ RubyPort::RubyPort(const Params *p)
m_controller = NULL;
m_mandatory_q_ptr = NULL;
m_port_id = m_num_ports++;
m_request_cnt = 0;
m_hit_callback = ruby_hit_callback;
pio_port = NULL;
physMemPort = NULL;
assert(m_num_ports <= 2048); // see below for reason
}
void RubyPort::init()
@ -169,8 +162,7 @@ RubyPort::M5Port::recvTiming(PacketPtr pkt)
//dsm: based on SimpleTimingPort::recvTiming(pkt);
//
// After checking for pio responses, the remainder of packets
// received by ruby should only be M5 requests, which should never
// The received packets should only be M5 requests, which should never
// get nacked. There used to be code to hanldle nacks here, but
// I'm pretty sure it didn't work correctly with the drain code,
// so that would need to be fixed if we ever added it back.
@ -185,18 +177,21 @@ RubyPort::M5Port::recvTiming(PacketPtr pkt)
return true;
}
//
// Save the port in the sender state object to be used later to
// route the response
//
pkt->senderState = new SenderState(this, pkt->senderState);
//
// Check for pio requests and directly send them to the dedicated
// pio port.
//
if (!isPhysMemAddress(pkt->getAddr())) {
assert(ruby_port->pio_port != NULL);
//
// Save the port in the sender state object to be used later to
// route the response
//
pkt->senderState = new SenderState(this, pkt->senderState);
DPRINTF(MemoryAccess,
"Request for address 0x%#x is assumed to be a pio request\n",
pkt->getAddr());
return ruby_port->pio_port->sendTiming(pkt);
}
@ -225,41 +220,49 @@ RubyPort::M5Port::recvTiming(PacketPtr pkt)
type = RubyRequestType_ST;
} else if (pkt->isReadWrite()) {
type = RubyRequestType_RMW_Write;
} else {
panic("Unsupported ruby packet type\n");
}
RubyRequest ruby_request(pkt->getAddr(), pkt->getPtr<uint8_t>(),
pkt->getSize(), pc, type,
RubyAccessMode_Supervisor);
RubyRequest ruby_request(pkt->getAddr(),
pkt->getPtr<uint8_t>(),
pkt->getSize(),
pc,
type,
RubyAccessMode_Supervisor,
pkt);
// Submit the ruby request
int64_t req_id = ruby_port->makeRequest(ruby_request);
if (req_id == -1) {
return false;
RequestStatus requestStatus = ruby_port->makeRequest(ruby_request);
if (requestStatus == RequestStatus_Issued) {
return true;
}
// Save the request for the callback
RubyPort::pending_cpu_requests[req_id] = new RequestCookie(pkt, this);
return true;
DPRINTF(MemoryAccess,
"Request for address #x did not issue because %s\n",
pkt->getAddr(),
RequestStatus_to_string(requestStatus));
SenderState* senderState = safe_cast<SenderState*>(pkt->senderState);
pkt->senderState = senderState->saved;
delete senderState;
return false;
}
void
RubyPort::ruby_hit_callback(int64_t req_id)
RubyPort::ruby_hit_callback(PacketPtr pkt)
{
//
// Note: This single fuction can be called by cpu and dma ports,
// as well as the functional port.
// Retrieve the request port from the sender State
//
RequestMap::iterator i = pending_cpu_requests.find(req_id);
if (i == pending_cpu_requests.end())
panic("could not find pending request %d\n", req_id);
RequestCookie *cookie = i->second;
pending_cpu_requests.erase(i);
Packet *pkt = cookie->pkt;
M5Port *port = cookie->m5Port;
delete cookie;
RubyPort::SenderState *senderState =
safe_cast<RubyPort::SenderState *>(pkt->senderState);
M5Port *port = senderState->port;
assert(port != NULL);
// pop the sender state from the packet
pkt->senderState = senderState->saved;
delete senderState;
port->hitCallback(pkt);
}

View file

@ -37,6 +37,7 @@
#include "mem/mem_object.hh"
#include "mem/tport.hh"
#include "mem/physical.hh"
#include "mem/protocol/RequestStatus.hh"
#include "params/RubyPort.hh"
@ -105,16 +106,7 @@ public:
Port *getPort(const std::string &if_name, int idx);
virtual int64_t makeRequest(const RubyRequest & request) = 0;
void registerHitCallback(void (*hit_callback)(int64_t request_id)) {
//
// Can't assign hit_callback twice and by default it is set to the
// RubyPort's default callback function.
//
assert(m_hit_callback == ruby_hit_callback);
m_hit_callback = hit_callback;
}
virtual RequestStatus makeRequest(const RubyRequest & request) = 0;
//
// Called by the controller to give the sequencer a pointer.
@ -124,55 +116,17 @@ public:
protected:
const string m_name;
void (*m_hit_callback)(int64_t);
int64_t makeUniqueRequestID() {
// The request ID is generated by combining the port ID with a request count
// so that request IDs can be formed concurrently by multiple threads.
// IDs are formed as follows:
//
//
// 0 PortID Request Count
// +----+---------------+-----------------------------------------------------+
// | 63 | 62-48 | 47-0 |
// +----+---------------+-----------------------------------------------------+
//
//
// This limits the system to a maximum of 2^11 == 2048 components
// and 2^48 ~= 3x10^14 requests per component
int64_t id = (static_cast<uint64_t>(m_port_id) << 48) | m_request_cnt;
m_request_cnt++;
// assert((m_request_cnt & (1<<48)) == 0);
return id;
}
void ruby_hit_callback(PacketPtr pkt);
void hit(PacketPtr pkt);
int m_version;
AbstractController* m_controller;
MessageBuffer* m_mandatory_q_ptr;
PioPort* pio_port;
//
// The pending request map is protected so that the Sequencer can access it.
// This is a temporary fix until the libruby inteface is cleaned
//
struct RequestCookie {
Packet *pkt;
M5Port *m5Port;
RequestCookie(Packet *p, M5Port *m5p)
: pkt(p), m5Port(m5p)
{}
};
typedef std::map<int64_t, RequestCookie*> RequestMap;
static RequestMap pending_cpu_requests;
private:
static uint16_t m_num_ports;
uint16_t m_port_id;
uint64_t m_request_cnt;
static void ruby_hit_callback(int64_t req_id);
uint16_t m_port_id;
uint64_t m_request_cnt;
M5Port* physMemPort;

View file

@ -45,11 +45,6 @@
#include "params/RubySequencer.hh"
//Sequencer::Sequencer(int core_id, MessageBuffer* mandatory_q)
#define LLSC_FAIL -2
long int already = 0;
Sequencer *
RubySequencerParams::create()
{
@ -352,30 +347,18 @@ void Sequencer::hitCallback(SequencerRequest* srequest, DataBlock& data) {
// Note: RubyPort will access it's sender state before the RubyTester.
//
if (m_usingRubyTester) {
//
// Since the hit callback func only takes a request id, we must iterate
// through the requests and update the packet's subBlock here.
// All this would be fixed if we could attach a M5 pkt pointer to the
// ruby request, however that change will break the libruby interface so
// we'll hold off on that for now.
//
RequestMap::iterator i = pending_cpu_requests.find(srequest->id);
if (i == pending_cpu_requests.end())
panic("could not find pending request %d\n", srequest->id);
RequestCookie *cookie = i->second;
Packet *pkt = cookie->pkt;
RubyTester::SenderState* testerSenderState;
testerSenderState = safe_cast<RubyTester::SenderState*>(pkt->senderState);
testerSenderState = safe_cast<RubyTester::SenderState*>( \
safe_cast<RubyPort::SenderState*>(ruby_request.pkt->senderState)->saved);
testerSenderState->subBlock->mergeFrom(data);
}
m_hit_callback(srequest->id);
ruby_hit_callback(ruby_request.pkt);
delete srequest;
}
// Returns true if the sequencer already has a load or store outstanding
int Sequencer::isReady(const RubyRequest& request) {
RequestStatus Sequencer::getRequestStatus(const RubyRequest& request) {
bool is_outstanding_store = m_writeRequestTable.exist(line_address(Address(request.paddr)));
bool is_outstanding_load = m_readRequestTable.exist(line_address(Address(request.paddr)));
if ( is_outstanding_store ) {
@ -386,7 +369,7 @@ int Sequencer::isReady(const RubyRequest& request) {
} else {
m_store_waiting_on_store_cycles++;
}
return LIBRUBY_ALIASED_REQUEST;
return RequestStatus_Aliased;
} else if ( is_outstanding_load ) {
if ((request.type == RubyRequestType_ST) ||
(request.type == RubyRequestType_RMW_Write) ) {
@ -394,14 +377,14 @@ int Sequencer::isReady(const RubyRequest& request) {
} else {
m_load_waiting_on_load_cycles++;
}
return LIBRUBY_ALIASED_REQUEST;
return RequestStatus_Aliased;
}
if (m_outstanding_count >= m_max_outstanding_requests) {
return LIBRUBY_BUFFER_FULL;
return RequestStatus_BufferFull;
}
return 1;
return RequestStatus_Ready;
}
bool Sequencer::empty() const {
@ -409,20 +392,21 @@ bool Sequencer::empty() const {
}
int64_t Sequencer::makeRequest(const RubyRequest & request)
RequestStatus Sequencer::makeRequest(const RubyRequest & request)
{
assert(Address(request.paddr).getOffset() + request.len <= RubySystem::getBlockSizeBytes());
int ready = isReady(request);
if (ready > 0) {
int64_t id = makeUniqueRequestID();
SequencerRequest *srequest = new SequencerRequest(request, id, g_eventQueue_ptr->getTime());
assert(Address(request.paddr).getOffset() + request.len <=
RubySystem::getBlockSizeBytes());
RequestStatus status = getRequestStatus(request);
if (status == RequestStatus_Ready) {
SequencerRequest *srequest = new SequencerRequest(request,
g_eventQueue_ptr->getTime());
bool found = insertRequest(srequest);
if (!found) {
if (request.type == RubyRequestType_Locked_Write) {
// NOTE: it is OK to check the locked flag here as the mandatory queue will be checked first
// ensuring that nothing comes between checking the flag and servicing the store
if (!m_dataCache_ptr->isLocked(line_address(Address(request.paddr)), m_version)) {
return LLSC_FAIL;
return RequestStatus_LlscFailed;
}
else {
m_dataCache_ptr->clearLocked(line_address(Address(request.paddr)));
@ -431,14 +415,15 @@ int64_t Sequencer::makeRequest(const RubyRequest & request)
issueRequest(request);
// TODO: issue hardware prefetches here
return id;
return RequestStatus_Issued;
}
else {
assert(0);
return 0;
panic("Sequencer::makeRequest should never be called if the request"\
"is already outstanding\n");
return RequestStatus_NULL;
}
} else {
return ready;
return status;
}
}

View file

@ -56,11 +56,12 @@ class RubySequencerParams;
struct SequencerRequest {
RubyRequest ruby_request;
int64_t id;
Time issue_time;
SequencerRequest(const RubyRequest & _ruby_request, int64_t _id, Time _issue_time)
: ruby_request(_ruby_request), id(_id), issue_time(_issue_time)
SequencerRequest(const RubyRequest & _ruby_request,
Time _issue_time)
: ruby_request(_ruby_request),
issue_time(_issue_time)
{}
};
@ -85,9 +86,8 @@ public:
void writeCallback(const Address& address, DataBlock& data);
void readCallback(const Address& address, DataBlock& data);
// called by Tester or Simics
int64_t makeRequest(const RubyRequest & request);
int isReady(const RubyRequest& request);
RequestStatus makeRequest(const RubyRequest & request);
RequestStatus getRequestStatus(const RubyRequest& request);
bool empty() const;
void print(ostream& out) const;