204 lines
6.6 KiB
C++
204 lines
6.6 KiB
C++
#ifndef EXAMPLEINITIATOR_H
|
|
#define EXAMPLEINITIATOR_H
|
|
|
|
#include <stdlib.h>
|
|
#include <iostream>
|
|
|
|
#include "MemoryManager.h"
|
|
#include "common/dramExtensions.h"
|
|
#include "TracePlayer.h"
|
|
|
|
struct ExampleInitiator : sc_module
|
|
{
|
|
// TLM-2 socket, defaults to 32-bits wide, base protocol
|
|
tlm_utils::simple_initiator_socket<ExampleInitiator> socket;
|
|
|
|
SC_CTOR(ExampleInitiator)
|
|
: socket("socket"),
|
|
request_in_progress(0),
|
|
m_peq(this, &ExampleInitiator::peq_cb)
|
|
{
|
|
socket.register_nb_transport_bw(this, &ExampleInitiator::nb_transport_bw);
|
|
SC_THREAD(thread_process);
|
|
}
|
|
|
|
void thread_process()
|
|
{
|
|
tlm::tlm_generic_payload *trans;
|
|
tlm::tlm_phase phase;
|
|
sc_time delay;
|
|
|
|
dump_mem();
|
|
init_mem();
|
|
dump_mem();
|
|
|
|
for (int i = 0; i < 64; i++)
|
|
data[i] = 0x55;
|
|
|
|
// Generate 2 write transactions
|
|
for (int i = 0; i < 2; i++) {
|
|
int adr = i * 64;
|
|
|
|
tlm::tlm_command cmd = tlm::TLM_WRITE_COMMAND;
|
|
|
|
// Grab a new transaction from the memory manager
|
|
trans = m_mm.allocate();
|
|
trans->acquire();
|
|
|
|
trans->set_command( cmd );
|
|
trans->set_address( adr );
|
|
trans->set_data_ptr( reinterpret_cast<unsigned char *>(&data[0]) );
|
|
trans->set_data_length( 64 );
|
|
trans->set_streaming_width( 4 );
|
|
trans->set_byte_enable_ptr( 0 );
|
|
trans->set_dmi_allowed( false );
|
|
trans->set_response_status( tlm::TLM_INCOMPLETE_RESPONSE );
|
|
|
|
// ExampleInitiator must honor BEGIN_REQ/END_REQ exclusion rule
|
|
if (request_in_progress)
|
|
wait(end_request_event);
|
|
request_in_progress = trans;
|
|
phase = tlm::BEGIN_REQ;
|
|
|
|
// Timing annotation models processing time of initiator prior to call
|
|
delay = sc_time(100000, SC_PS);
|
|
|
|
cout << "Address " << hex << adr << " new, cmd=" << (cmd ? "write" : "read")
|
|
<< ", data=" << hex << data[0] << " at time " << sc_time_stamp()
|
|
<< " in " << name() << endl;
|
|
|
|
GenerationExtension *genExtension = new GenerationExtension(sc_time_stamp());
|
|
trans->set_auto_extension(genExtension);
|
|
|
|
|
|
// Non-blocking transport call on the forward path
|
|
tlm::tlm_sync_enum status;
|
|
status = socket->nb_transport_fw( *trans, phase, delay );
|
|
|
|
// Check value returned from nb_transport_fw
|
|
if (status == tlm::TLM_UPDATED) {
|
|
// The timing annotation must be honored
|
|
m_peq.notify( *trans, phase, delay );
|
|
} else if (status == tlm::TLM_COMPLETED) {
|
|
// The completion of the transaction necessarily ends the BEGIN_REQ phase
|
|
request_in_progress = 0;
|
|
|
|
// The target has terminated the transaction
|
|
check_transaction( *trans );
|
|
|
|
// Allow the memory manager to free the transaction object
|
|
trans->release();
|
|
}
|
|
|
|
wait( sc_time(500, SC_NS) );
|
|
|
|
dump_mem();
|
|
}
|
|
|
|
wait( sc_time(500, SC_NS) );
|
|
sc_stop();
|
|
}
|
|
|
|
void init_mem()
|
|
{
|
|
unsigned char buffer[64];
|
|
for (int i = 0; i < 64; i++) {
|
|
buffer[i] = 0xff;
|
|
}
|
|
|
|
for (int addr = 0; addr < 128; addr += 64) {
|
|
tlm::tlm_generic_payload trans;
|
|
trans.set_command( tlm::TLM_WRITE_COMMAND );
|
|
trans.set_address( addr );
|
|
trans.set_data_ptr( buffer );
|
|
trans.set_data_length( 64 );
|
|
|
|
socket->transport_dbg( trans );
|
|
}
|
|
}
|
|
|
|
void dump_mem()
|
|
{
|
|
for (int addr = 0; addr < 128; addr += 64) {
|
|
unsigned char buffer[64];
|
|
tlm::tlm_generic_payload trans;
|
|
trans.set_command( tlm::TLM_READ_COMMAND );
|
|
trans.set_address( addr );
|
|
trans.set_data_ptr( buffer );
|
|
trans.set_data_length( 64 );
|
|
|
|
socket->transport_dbg( trans );
|
|
|
|
cout << "\nMemory dump\n";
|
|
for (int i = 0; i < 64; i++)
|
|
cout << "mem[" << addr + i << "] = " << hex << (int)buffer[i] << endl;
|
|
}
|
|
}
|
|
|
|
// TLM-2 backward non-blocking transport method
|
|
|
|
virtual tlm::tlm_sync_enum nb_transport_bw( tlm::tlm_generic_payload &trans,
|
|
tlm::tlm_phase &phase, sc_time &delay )
|
|
{
|
|
m_peq.notify( trans, phase, delay );
|
|
return tlm::TLM_ACCEPTED;
|
|
}
|
|
|
|
// Payload event queue callback to handle transactions from target
|
|
// Transaction could have arrived through return path or backward path
|
|
|
|
void peq_cb(tlm::tlm_generic_payload &trans, const tlm::tlm_phase &phase)
|
|
{
|
|
if (phase == tlm::END_REQ || (&trans == request_in_progress
|
|
&& phase == tlm::BEGIN_RESP)) {
|
|
// The end of the BEGIN_REQ phase
|
|
request_in_progress = 0;
|
|
end_request_event.notify();
|
|
} else if (phase == tlm::BEGIN_REQ || phase == tlm::END_RESP)
|
|
SC_REPORT_FATAL("TLM-2", "Illegal transaction phase received by initiator");
|
|
|
|
if (phase == tlm::BEGIN_RESP) {
|
|
check_transaction( trans );
|
|
|
|
// Send final phase transition to target
|
|
tlm::tlm_phase fw_phase = tlm::END_RESP;
|
|
sc_time delay = sc_time(60000, SC_PS);
|
|
socket->nb_transport_fw( trans, fw_phase, delay );
|
|
// Ignore return value
|
|
|
|
// Allow the memory manager to free the transaction object
|
|
trans.release();
|
|
}
|
|
}
|
|
|
|
// Called on receiving BEGIN_RESP or TLM_COMPLETED
|
|
void check_transaction(tlm::tlm_generic_payload &trans)
|
|
{
|
|
if ( trans.is_response_error() ) {
|
|
char txt[100];
|
|
sprintf(txt, "Transaction returned with error, response status = %s",
|
|
trans.get_response_string().c_str());
|
|
SC_REPORT_ERROR("TLM-2", txt);
|
|
}
|
|
|
|
tlm::tlm_command cmd = trans.get_command();
|
|
uint64_t adr = trans.get_address();
|
|
int *ptr = reinterpret_cast<int *>( trans.get_data_ptr() );
|
|
|
|
cout << hex << adr << " check, cmd=" << (cmd ? "write" : "read")
|
|
<< ", data=" << hex << *ptr << " at time " << sc_time_stamp()
|
|
<< " in " << name() << endl;
|
|
|
|
if (cmd == tlm::TLM_READ_COMMAND)
|
|
assert( *ptr == -int(adr) );
|
|
}
|
|
|
|
MemoryManager m_mm;
|
|
unsigned char data[64];
|
|
tlm::tlm_generic_payload *request_in_progress;
|
|
sc_event end_request_event;
|
|
tlm_utils::peq_with_cb_and_phase<ExampleInitiator> m_peq;
|
|
};
|
|
|
|
#endif // EXAMPLEINITIATOR_H
|