systemc: Add some common test include files.

These are "common" in the sense that they're not in a particular test
directory, but I think they're only used by one test.

Change-Id: I4ffd209d04ed0e5253085810913827b87412b302
Reviewed-on: https://gem5-review.googlesource.com/11272
Reviewed-by: Gabe Black <gabeblack@google.com>
Maintainer: Gabe Black <gabeblack@google.com>
This commit is contained in:
Gabe Black
2018-06-15 20:02:54 -07:00
parent dc0b98dcdc
commit eba0ab506b
23 changed files with 10751 additions and 0 deletions

View File

@@ -62,6 +62,7 @@ if env['USE_SYSTEMC']:
}
ext_dir = Dir('..').Dir('ext')
test_dir = Dir('.')
class SystemCTestBin(Executable):
def __init__(self, test):
super(SystemCTestBin, self).__init__(test.target, *test.sources)
@@ -75,6 +76,7 @@ if env['USE_SYSTEMC']:
env['CCFLAGS'] = \
filter(lambda f: f not in to_remove, env['CCFLAGS'])
env.Append(CPPPATH=test_dir.Dir('include'))
env.Append(CPPPATH=ext_dir)
super(SystemCTestBin, cls).declare_all(env)

View File

@@ -0,0 +1,166 @@
/*****************************************************************************
Licensed to Accellera Systems Initiative Inc. (Accellera) under one or
more contributor license agreements. See the NOTICE file distributed
with this work for additional information regarding copyright ownership.
Accellera licenses this file to you under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with the
License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied. See the License for the specific language governing
permissions and limitations under the License.
*****************************************************************************/
//====================================================================
// Nov 06, 2008
//
// Updated by:
// Xiaopeng Qiu, JEDA Technologies, Inc
// Email: qiuxp@jedatechnologies.net
//
// To fix violations of TLM2.0 rules, which are detected by JEDA
// TLM2.0 checker.
//
//====================================================================
#ifndef __CORE_DECOUPLING_LT_INITIATOR_H__
#define __CORE_DECOUPLING_LT_INITIATOR_H__
#include "tlm.h"
#include "tlm_utils/simple_initiator_socket.h"
#include "tlm_utils/tlm_quantumkeeper.h"
//#include <systemc>
#include <cassert>
//#include <iostream>
class CoreDecouplingLTInitiator : public sc_core::sc_module
{
public:
typedef tlm::tlm_generic_payload transaction_type;
typedef tlm_utils::simple_initiator_socket<CoreDecouplingLTInitiator> initiator_socket_type;
public:
initiator_socket_type socket;
public:
SC_HAS_PROCESS(CoreDecouplingLTInitiator);
CoreDecouplingLTInitiator(sc_core::sc_module_name name,
unsigned int nrOfTransactions = 0x5,
unsigned int baseAddress = 0) :
sc_core::sc_module(name),
socket("socket"),
mNrOfTransactions(nrOfTransactions),
mBaseAddress(baseAddress),
mTransactionCount(0)
{
tlm_utils::tlm_quantumkeeper::set_global_quantum(sc_core::sc_time(500, sc_core::SC_NS));
mQuantumKeeper.reset();
// Initiator thread
SC_THREAD(run);
}
bool initTransaction(transaction_type& trans)
{
if (mTransactionCount < mNrOfTransactions) {
trans.set_address(mBaseAddress + 4*mTransactionCount);
mData = mTransactionCount;
trans.set_command(tlm::TLM_WRITE_COMMAND);
} else if (mTransactionCount < 2 * mNrOfTransactions) {
trans.set_address(mBaseAddress + 4*(mTransactionCount - mNrOfTransactions));
mData = 0;
trans.set_command(tlm::TLM_READ_COMMAND);
} else {
return false;
}
trans.set_data_ptr(reinterpret_cast<unsigned char*>(&mData));
trans.set_data_length(4);
trans.set_streaming_width(4);
trans.set_response_status(tlm::TLM_INCOMPLETE_RESPONSE);
++mTransactionCount;
return true;
}
void logStartTransation(transaction_type& trans)
{
if (trans.get_command() == tlm::TLM_WRITE_COMMAND) {
std::cout << name() << ": Send write request: A = 0x"
<< std::hex << (unsigned int)trans.get_address()
<< ", D = 0x" << mData << std::dec
<< " @ " << mQuantumKeeper.get_current_time()
<< " (" << sc_core::sc_time_stamp() << " + "
<< mQuantumKeeper.get_local_time() << ")"
<< std::endl;
} else {
std::cout << name() << ": Send read request: A = 0x"
<< std::hex << (unsigned int)trans.get_address()
<< " @ " << mQuantumKeeper.get_current_time()
<< " (" << sc_core::sc_time_stamp() << " + "
<< mQuantumKeeper.get_local_time() << ")"
<< std::endl;
}
}
void logEndTransaction(transaction_type& trans)
{
if (trans.get_response_status() != tlm::TLM_OK_RESPONSE) {
std::cout << name() << ": Received error response @ "
<< mQuantumKeeper.get_current_time()
<< " (" << sc_core::sc_time_stamp() << " + "
<< mQuantumKeeper.get_local_time() << ")"
<< std::endl;
} else {
std::cout << name() << ": Received ok response";
if (trans.get_command() == tlm::TLM_READ_COMMAND) {
std::cout << ": D = 0x" << std::hex << mData << std::dec;
}
std::cout << " @ " << mQuantumKeeper.get_current_time()
<< " (" << sc_core::sc_time_stamp() << " + "
<< mQuantumKeeper.get_local_time() << ")"
<< std::endl;
}
}
void run()
{
transaction_type trans;
while (initTransaction(trans)) {
logStartTransation(trans);
// exec instr
sc_core::sc_time t = mQuantumKeeper.get_local_time();
socket->b_transport(trans, t);
mQuantumKeeper.set(t);
// Target may have added a delay to the quantum -> sync if needed
if (mQuantumKeeper.need_sync()) {
std::cout << "Sync'ing..." << std::endl;
mQuantumKeeper.sync();
}
logEndTransaction(trans);
}
wait();
}
private:
unsigned int mNrOfTransactions;
unsigned int mBaseAddress;
unsigned int mTransactionCount;
unsigned int mData;
tlm_utils::tlm_quantumkeeper mQuantumKeeper;
};
#endif

View File

@@ -0,0 +1,176 @@
/*****************************************************************************
Licensed to Accellera Systems Initiative Inc. (Accellera) under one or
more contributor license agreements. See the NOTICE file distributed
with this work for additional information regarding copyright ownership.
Accellera licenses this file to you under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with the
License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied. See the License for the specific language governing
permissions and limitations under the License.
*****************************************************************************/
#ifndef __EXPLICIT_AT_TARGET_H__
#define __EXPLICIT_AT_TARGET_H__
#include "tlm.h"
#include "tlm_utils/simple_target_socket.h"
//#include <systemc>
#include <cassert>
#include <vector>
#include <queue>
//#include <iostream>
class ExplicitATTarget : public sc_core::sc_module
{
public:
typedef tlm::tlm_generic_payload transaction_type;
typedef tlm::tlm_phase phase_type;
typedef tlm::tlm_sync_enum sync_enum_type;
typedef tlm_utils::simple_target_socket<ExplicitATTarget> target_socket_type;
public:
target_socket_type socket;
public:
SC_HAS_PROCESS(ExplicitATTarget);
ExplicitATTarget(sc_core::sc_module_name name) :
sc_core::sc_module(name),
socket("socket"),
mCurrentTransaction(0)
{
// register nb_transport method
socket.register_nb_transport_fw(this, &ExplicitATTarget::myNBTransport);
socket.register_transport_dbg(this, &ExplicitATTarget::transport_dbg);
SC_THREAD(beginResponse)
}
sync_enum_type myNBTransport(transaction_type& trans, phase_type& phase, sc_core::sc_time& t)
{
if (phase == tlm::BEGIN_REQ) {
sc_dt::uint64 address = trans.get_address();
assert(address < 400);
// This target only supports one transaction at a time
// This will only work with LT initiators
assert(mCurrentTransaction == 0);
unsigned int& data = *reinterpret_cast<unsigned int*>(trans.get_data_ptr());
if (trans.get_command() == tlm::TLM_WRITE_COMMAND) {
std::cout << name() << ": Received write request: A = 0x"
<< std::hex << (unsigned int)address << ", D = 0x" << data
<< std::dec << " @ " << sc_core::sc_time_stamp()
<< std::endl;
*reinterpret_cast<unsigned int*>(&mMem[address]) = data;
// Synchronization on demand (eg need to assert an interrupt)
mResponseEvent.notify(t);
mCurrentTransaction = &trans;
// End request phase
phase = tlm::END_REQ;
return tlm::TLM_UPDATED;
} else {
std::cout << name() << ": Received read request: A = 0x"
<< std::hex << (unsigned int)address
<< std::dec << " @ " << sc_core::sc_time_stamp()
<< std::endl;
data = *reinterpret_cast<unsigned int*>(&mMem[address]);
trans.set_response_status(tlm::TLM_OK_RESPONSE);
// Finish transaction (use timing annotation)
t += sc_core::sc_time(100, sc_core::SC_NS);
return tlm::TLM_COMPLETED;
}
} else if (phase == tlm::END_RESP) {
// Transaction finished
mCurrentTransaction = 0;
return tlm::TLM_COMPLETED;
}
// Not possible
assert(0); exit(1);
// return tlm::TLM_COMPLETED; //unreachable code
}
void beginResponse()
{
while (true) {
// Wait for next synchronization request
wait(mResponseEvent);
assert(mCurrentTransaction);
// start response phase
phase_type phase = tlm::BEGIN_RESP;
sc_core::sc_time t = sc_core::SC_ZERO_TIME;
// Set response data
mCurrentTransaction->set_response_status(tlm::TLM_OK_RESPONSE);
assert(mCurrentTransaction->get_command() == tlm::TLM_WRITE_COMMAND);
sc_dt::uint64 address = mCurrentTransaction->get_address();
assert(address < 400);
*reinterpret_cast<unsigned int*>(mCurrentTransaction->get_data_ptr()) =
*reinterpret_cast<unsigned int*>(&mMem[address]);
// We are synchronized, we can read/write sc_signals, wait,...
// Wait before sending the response
wait(50, sc_core::SC_NS);
if (socket->nb_transport_bw(*mCurrentTransaction, phase, t) == tlm::TLM_COMPLETED) {
mCurrentTransaction = 0;
} else {
// Initiator will call nb_transport(trans, END_RESP, t)
}
}
}
unsigned int transport_dbg(transaction_type& r)
{
if (r.get_address() >= 400) return 0;
unsigned int tmp = (int)r.get_address();
unsigned int num_bytes;
if (tmp + r.get_data_length() >= 400) {
num_bytes = 400 - tmp;
} else {
num_bytes = r.get_data_length();
}
if (!r.is_read() && !r.is_write()) {
return 0;
}
if (r.is_read()) {
for (unsigned int i = 0; i < num_bytes; ++i) {
r.get_data_ptr()[i] = mMem[i + tmp];
}
} else {
for (unsigned int i = 0; i < num_bytes; ++i) {
mMem[i + tmp] = r.get_data_ptr()[i];
}
}
return num_bytes;
}
private:
unsigned char mMem[400];
sc_core::sc_event mResponseEvent;
transaction_type* mCurrentTransaction;
};
#endif

View File

@@ -0,0 +1,124 @@
/*****************************************************************************
Licensed to Accellera Systems Initiative Inc. (Accellera) under one or
more contributor license agreements. See the NOTICE file distributed
with this work for additional information regarding copyright ownership.
Accellera licenses this file to you under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with the
License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied. See the License for the specific language governing
permissions and limitations under the License.
*****************************************************************************/
#ifndef __EXPLICIT_LT_TARGET_H__
#define __EXPLICIT_LT_TARGET_H__
#include "tlm.h"
#include "tlm_utils/simple_target_socket.h"
//#include <systemc>
#include <cassert>
#include <vector>
#include <queue>
//#include <iostream>
class ExplicitLTTarget : public sc_core::sc_module
{
public:
typedef tlm::tlm_generic_payload transaction_type;
typedef tlm::tlm_phase phase_type;
typedef tlm::tlm_sync_enum sync_enum_type;
typedef tlm_utils::simple_target_socket<ExplicitLTTarget> target_socket_type;
public:
target_socket_type socket;
public:
SC_HAS_PROCESS(ExplicitLTTarget);
ExplicitLTTarget(sc_core::sc_module_name name) :
sc_core::sc_module(name),
socket("socket")
{
// register nb_transport method
socket.register_b_transport(this, &ExplicitLTTarget::myBTransport);
socket.register_transport_dbg(this, &ExplicitLTTarget::transport_dbg);
}
void myBTransport(transaction_type& trans, sc_core::sc_time& t)
{
sc_dt::uint64 address = trans.get_address();
assert(address < 400);
unsigned int& data = *reinterpret_cast<unsigned int*>(trans.get_data_ptr());
if (trans.get_command() == tlm::TLM_WRITE_COMMAND) {
std::cout << name() << ": Received write request: A = 0x"
<< std::hex << (unsigned int)address << ", D = 0x" << data
<< std::dec << " @ " << sc_core::sc_time_stamp()
<< std::endl;
*reinterpret_cast<unsigned int*>(&mMem[address]) = data;
// Synchronization on demand (eg need to assert an interrupt)
// Wait for passed timing annotation + wait for an extra 50 ns
wait(t + sc_core::sc_time(50, sc_core::SC_NS));
t = sc_core::SC_ZERO_TIME;
// We are synchronized, we can read/write sc_signals, wait,...
*reinterpret_cast<unsigned int*>(trans.get_data_ptr()) =
*reinterpret_cast<unsigned int*>(&mMem[address]);
} else {
std::cout << name() << ": Received read request: A = 0x"
<< std::hex << (unsigned int)address
<< std::dec << " @ " << sc_core::sc_time_stamp()
<< std::endl;
data = *reinterpret_cast<unsigned int*>(&mMem[address]);
// Finish transaction (use timing annotation)
t += sc_core::sc_time(100, sc_core::SC_NS);
}
trans.set_response_status(tlm::TLM_OK_RESPONSE);
}
unsigned int transport_dbg(transaction_type& r)
{
if (r.get_address() >= 400) return 0;
unsigned int tmp = (int)r.get_address();
unsigned int num_bytes;
if (tmp + r.get_data_length() >= 400) {
num_bytes = 400 - tmp;
} else {
num_bytes = r.get_data_length();
}
if (!r.is_read() && !r.is_write()) {
return 0;
}
if (r.is_read()) {
for (unsigned int i = 0; i < num_bytes; ++i) {
r.get_data_ptr()[i] = mMem[i + tmp];
}
} else {
for (unsigned int i = 0; i < num_bytes; ++i) {
mMem[i + tmp] = r.get_data_ptr()[i];
}
}
return num_bytes;
}
private:
unsigned char mMem[400];
};
#endif

View File

@@ -0,0 +1,92 @@
SimpleLTInitiator1/SimpleLTTarget1
----------------------------------
- LT Initiator/Target model using the base (standard) tlm socket
- Added support for DMI in SimpleLTTarget1
SimpleLTInitiator1_DMI
----------------------
- uses DMI transactions, the DMI structure is using the DMI-hint
to check if a DMI request would make sense.
- uses a single transport_dbg transaction at end_of_simulation()
SimpleLTInitiator2/SimpleLTTarget2
----------------------------------
- LT Initiator/Target model using the convenience tlm socket
- Target and Initiator model use the REGISTER_DEBUGTRANSPORT macro to register
a transport callback to the socket
- Added support for DMI handling, callback registration with
REGISTER_DMI
- SimpleLTTarget2 does not register the transport_dbg callback, so that
we are able to test this case in bus_dmi.
SimpleLTInitiator2_DMI
----------------------
- uses DMI transactions, but ignoring the DMI hint
- uses a single transport_dbg transaction at end_of_simulation()
SimpleLTInitiator3
------------------
- LT Initiator model using the convenience tlm socket
- Initiator model uses the endEvent of the socket to wait until the
transaction is finished
SimpleLTInitiator3_DMI
----------------------
- based on SimpleInitiator3, uses DMI (without DMI hint)
SimpleATInitiator1/SimpleATTarget1
----------------------------------
- AT Initiator/Target model implementing the AT protocol
- one call of nb_transport for each timing point in the protocol (BEGIN_REQ,
END_REQ, BEGIN_RESP and END_RESP)
SimpleATInitiator2/SimpleATTarget2
----------------------------------
- AT Initiator/Target model implementing the AT protocol with timing annotation
- only a call of nb_transport for the start of a phase (BEGIN_REQ and
BEGIN_RESP)
- end of a phase is notified via timing annotation (t argument)
CoreDecouplingLTInitiator
-------------------------
- LT Initiator using 'Core Decoupling'
ExplicitLTTarget
----------------
- LT Target that uses explicit timing (calls wait)
- added support for debug transactions
ExplicitLTTarget
----------------
- AT Target, only registers nb_transport
SimpleBus
---------
- Simple bus model
- Runtime switcheable between LT and AT (can only switch if no transactions
are pending)
- No limitation on number of pending transactions (all targets that can return
false must support multiple transactions)
- added support for DMI and debug transactions
- LT mode:
-- Forward nb_transport calls to initiator/targets
-- Only one active request/response phase
- AT mode:
-- Incoming transactions are queued
-- AT protocol is executed from a different SC_THREAD
-- A target is notified immediately of the end of a transaction (using timing
annotation). This is needed because the initiator can re-use the
transaction (and the target may use the transaction pointer to identify the
transaction)

View File

@@ -0,0 +1,333 @@
/*****************************************************************************
Licensed to Accellera Systems Initiative Inc. (Accellera) under one or
more contributor license agreements. See the NOTICE file distributed
with this work for additional information regarding copyright ownership.
Accellera licenses this file to you under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with the
License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied. See the License for the specific language governing
permissions and limitations under the License.
*****************************************************************************/
//====================================================================
// Nov 06, 2008
//
// Updated by:
// Xiaopeng Qiu, JEDA Technologies, Inc
// Email: qiuxp@jedatechnologies.net
//
// To fix violations of TLM2.0 rules, which are detected by JEDA
// TLM2.0 checker.
//
//====================================================================
#ifndef __SIMPLE_AT_INITIATOR1_H__
#define __SIMPLE_AT_INITIATOR1_H__
#include "tlm.h"
#include "tlm_utils/simple_initiator_socket.h"
//#include <systemc>
#include <cassert>
#include <queue>
//#include <iostream>
class SimpleATInitiator1 : public sc_core::sc_module
{
public:
typedef tlm::tlm_generic_payload transaction_type;
typedef tlm::tlm_phase phase_type;
typedef tlm::tlm_sync_enum sync_enum_type;
typedef tlm_utils::simple_initiator_socket<SimpleATInitiator1> initiator_socket_type;
public:
// extended transaction, holds tlm_generic_payload + data storage
template <typename DT>
class MyTransaction : public transaction_type
{
public:
MyTransaction()
{
this->set_data_ptr(reinterpret_cast<unsigned char*>(&mData));
}
MyTransaction(tlm::tlm_mm_interface* mm) : transaction_type(mm)
{
this->set_data_ptr(reinterpret_cast<unsigned char*>(&mData));
}
void setData(DT& data) { mData = data; }
DT getData() const { return mData; }
private:
DT mData;
};
typedef MyTransaction<unsigned int> mytransaction_type;
// Dummy Transaction Pool
class SimplePool : public tlm::tlm_mm_interface
{
public:
SimplePool() {}
mytransaction_type* claim()
{
mytransaction_type* t = new mytransaction_type(this);
t->acquire();
return t;
}
void release(mytransaction_type* t)
{
t->release();
}
void free(tlm::tlm_generic_payload* t)
{
t->reset();
delete t;
}
};
public:
initiator_socket_type socket;
public:
SC_HAS_PROCESS(SimpleATInitiator1);
SimpleATInitiator1(sc_core::sc_module_name name,
unsigned int nrOfTransactions = 0x5,
unsigned int baseAddress = 0x0) :
sc_core::sc_module(name),
socket("socket"),
ACCEPT_DELAY(10, sc_core::SC_NS),
mNrOfTransactions(nrOfTransactions),
mBaseAddress(baseAddress),
mTransactionCount(0),
mCurrentTransaction(0)
{
// register nb_transport method
socket.register_nb_transport_bw(this, &SimpleATInitiator1::myNBTransport);
// Initiator thread
SC_THREAD(run);
SC_METHOD(endResponse)
sensitive << mEndResponseEvent;
dont_initialize();
}
bool initTransaction(mytransaction_type*& trans)
{
if (mTransactionCount < mNrOfTransactions) {
trans = transPool.claim();
trans->set_address(mBaseAddress + 4*mTransactionCount);
trans->setData(mTransactionCount);
trans->set_command(tlm::TLM_WRITE_COMMAND);
} else if (mTransactionCount < 2 * mNrOfTransactions) {
trans = transPool.claim();
trans->set_address(mBaseAddress + 4*(mTransactionCount - mNrOfTransactions));
trans->set_command(tlm::TLM_READ_COMMAND);
} else {
return false;
}
trans->set_data_length(4);
trans->set_streaming_width(4);
++mTransactionCount;
return true;
}
void logStartTransation(mytransaction_type& trans)
{
if (trans.get_command() == tlm::TLM_WRITE_COMMAND) {
std::cout << name() << ": Send write request: A = 0x"
<< std::hex << (unsigned int)trans.get_address()
<< ", D = 0x" << trans.getData() << std::dec
<< " @ " << sc_core::sc_time_stamp() << std::endl;
} else {
std::cout << name() << ": Send read request: A = 0x"
<< std::hex << (int)trans.get_address() << std::dec
<< " @ " << sc_core::sc_time_stamp() << std::endl;
}
}
void logEndTransaction(mytransaction_type& trans)
{
if (trans.get_response_status() != tlm::TLM_OK_RESPONSE) {
std::cout << name() << ": Received error response @ "
<< sc_core::sc_time_stamp() << std::endl;
} else {
std::cout << name() << ": Received ok response";
if (trans.get_command() == tlm::TLM_READ_COMMAND) {
std::cout << ": D = 0x" << trans.getData() << std::dec;
}
std::cout << " @ " << sc_core::sc_time_stamp() << std::endl;
}
}
//
// Simple AT Initiator
// - Request must be accepted by the target before the next request can be
// send
// - Responses can come out of order
// - Responses will be accepted after fixed delay
//
void run()
{
phase_type phase;
sc_core::sc_time t;
mytransaction_type* ptrans;
while (initTransaction(ptrans)) {
// Create transaction and initialise phase and t
mytransaction_type& trans = *ptrans;
phase = tlm::BEGIN_REQ;
t = sc_core::SC_ZERO_TIME;
logStartTransation(trans);
switch (socket->nb_transport_fw(trans, phase, t)) {
case tlm::TLM_COMPLETED:
// Transaction Finished, wait for the returned delay
wait(t);
logEndTransaction(trans);
transPool.release(&trans);
break;
case tlm::TLM_ACCEPTED:
case tlm::TLM_UPDATED:
switch (phase) {
case tlm::BEGIN_REQ:
// Request phase not yet finished
// Wait until end of request phase before sending new request
// FIXME
mCurrentTransaction = &trans;
wait(mEndRequestPhase);
mCurrentTransaction = 0;
break;
case tlm::END_REQ:
// Request phase ended
if (t != sc_core::SC_ZERO_TIME) {
// Wait until end of request time before sending new request
wait(t);
}
break;
case tlm::BEGIN_RESP:
// Request phase ended and response phase already started
if (t != sc_core::SC_ZERO_TIME) {
// Wait until end of request time before sending new request
wait(t);
}
if (mEndResponseQueue.empty()) {
// Notify end of response phase after ACCEPT delay
mEndResponseEvent.notify(ACCEPT_DELAY);
}
mEndResponseQueue.push(&trans);
break;
case tlm::END_RESP: // fall-through
default:
// A target should never return with these phases
// If phase == END_RESP, nb_transport should have returned true
assert(0); exit(1);
break;
}
break;
default:
assert(0); exit(1);
};
}
wait();
}
sync_enum_type myNBTransport(transaction_type& trans, phase_type& phase, sc_core::sc_time& t)
{
switch (phase) {
case tlm::END_REQ:
assert(t == sc_core::SC_ZERO_TIME); // FIXME: can t != 0?
// Request phase ended
mEndRequestPhase.notify(sc_core::SC_ZERO_TIME);
return tlm::TLM_ACCEPTED;
case tlm::BEGIN_RESP:
{
assert(t == sc_core::SC_ZERO_TIME); // FIXME: can t != 0?
// Notify end of request phase if run thread is waiting for it
// FIXME
if (&trans == mCurrentTransaction) {
mEndRequestPhase.notify(sc_core::SC_ZERO_TIME);
}
assert(dynamic_cast<mytransaction_type*>(&trans));
mytransaction_type* myTrans = static_cast<mytransaction_type*>(&trans);
assert(myTrans);
if (mEndResponseQueue.empty()) {
// Notify end of response phase after ACCEPT delay
mEndResponseEvent.notify(ACCEPT_DELAY);
}
mEndResponseQueue.push(myTrans);
return tlm::TLM_ACCEPTED;
}
case tlm::BEGIN_REQ: // fall-through
case tlm::END_RESP: // fall-through
default:
// A target should never call nb_transport with these phases
assert(0); exit(1);
// return tlm::TLM_COMPLETED; //unreachable code
};
}
void endResponse()
{
assert(!mEndResponseQueue.empty());
// end response phase
phase_type phase = tlm::END_RESP;
sc_core::sc_time t = sc_core::SC_ZERO_TIME;
mytransaction_type* trans = mEndResponseQueue.front();
assert(trans);
mEndResponseQueue.pop();
#if ( ! NDEBUG )
sync_enum_type r = socket->nb_transport_fw(*trans, phase, t);
#endif /* ! NDEBUG */
assert(r == tlm::TLM_COMPLETED); // FIXME: target should return TLM_COMPLETED?
assert(t == sc_core::SC_ZERO_TIME); // t must be SC_ZERO_TIME
logEndTransaction(*trans);
transPool.release(trans);
if (!mEndResponseQueue.empty()) {
// Notify end of response phase after ACCEPT delay
mEndResponseEvent.notify(ACCEPT_DELAY);
}
}
private:
const sc_core::sc_time ACCEPT_DELAY;
private:
unsigned int mNrOfTransactions;
unsigned int mBaseAddress;
SimplePool transPool;
unsigned int mTransactionCount;
sc_core::sc_event mEndRequestPhase;
std::queue<mytransaction_type*> mEndResponseQueue;
sc_core::sc_event mEndResponseEvent;
transaction_type* mCurrentTransaction;
};
#endif

View File

@@ -0,0 +1,306 @@
/*****************************************************************************
Licensed to Accellera Systems Initiative Inc. (Accellera) under one or
more contributor license agreements. See the NOTICE file distributed
with this work for additional information regarding copyright ownership.
Accellera licenses this file to you under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with the
License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied. See the License for the specific language governing
permissions and limitations under the License.
*****************************************************************************/
//====================================================================
// Nov 06, 2008
//
// Updated by:
// Xiaopeng Qiu, JEDA Technologies, Inc
// Email: qiuxp@jedatechnologies.net
//
// To fix violations of TLM2.0 rules, which are detected by JEDA
// TLM2.0 checker.
//
//====================================================================
#ifndef __SIMPLE_AT_INITIATOR2_H__
#define __SIMPLE_AT_INITIATOR2_H__
#include "tlm.h"
#include "tlm_utils/simple_initiator_socket.h"
//#include <systemc>
#include <cassert>
#include <queue>
//#include <iostream>
class SimpleATInitiator2 : public sc_core::sc_module
{
public:
typedef tlm::tlm_generic_payload transaction_type;
typedef tlm::tlm_phase phase_type;
typedef tlm::tlm_sync_enum sync_enum_type;
typedef tlm_utils::simple_initiator_socket<SimpleATInitiator2> initiator_socket_type;
public:
// extended transaction, holds tlm_generic_payload + data storage
template <typename DT>
class MyTransaction : public transaction_type
{
public:
MyTransaction()
{
this->set_data_ptr(reinterpret_cast<unsigned char*>(&mData));
}
MyTransaction(tlm::tlm_mm_interface* mm) : transaction_type(mm)
{
this->set_data_ptr(reinterpret_cast<unsigned char*>(&mData));
}
void setData(DT& data) { mData = data; }
DT getData() const { return mData; }
private:
DT mData;
};
typedef MyTransaction<unsigned int> mytransaction_type;
// Dummy Transaction Pool
class SimplePool : public tlm::tlm_mm_interface
{
public:
SimplePool() {}
mytransaction_type* claim()
{
mytransaction_type* t = new mytransaction_type(this);
t->acquire();
return t;
}
void release(mytransaction_type* t)
{
t->release();
}
void free(tlm::tlm_generic_payload* t)
{
t->reset();
delete t;
}
};
public:
initiator_socket_type socket;
public:
SC_HAS_PROCESS(SimpleATInitiator2);
SimpleATInitiator2(sc_core::sc_module_name name,
unsigned int nrOfTransactions = 0x5,
unsigned int baseAddress = 0) :
sc_core::sc_module(name),
socket("socket"),
ACCEPT_DELAY(10, sc_core::SC_NS),
mNrOfTransactions(nrOfTransactions),
mBaseAddress(baseAddress),
mTransactionCount(0),
mCurrentTransaction(0)
{
// register nb_transport method
socket.register_nb_transport_bw(this, &SimpleATInitiator2::myNBTransport);
// Initiator thread
SC_THREAD(run);
}
bool initTransaction(mytransaction_type*& trans)
{
if (mTransactionCount < mNrOfTransactions) {
trans = transPool.claim();
trans->set_address(mBaseAddress + 4*mTransactionCount);
trans->setData(mTransactionCount);
trans->set_command(tlm::TLM_WRITE_COMMAND);
} else if (mTransactionCount < 2 * mNrOfTransactions) {
trans = transPool.claim();
trans->set_address(mBaseAddress + 4*(mTransactionCount - mNrOfTransactions));
trans->set_command(tlm::TLM_READ_COMMAND);
} else {
return false;
}
trans->set_data_length(4);
trans->set_streaming_width(4);
++mTransactionCount;
return true;
}
void logStartTransation(mytransaction_type& trans)
{
if (trans.get_command() == tlm::TLM_WRITE_COMMAND) {
std::cout << name() << ": Send write request: A = 0x"
<< std::hex << (unsigned int)trans.get_address()
<< ", D = 0x" << trans.getData() << std::dec
<< " @ " << sc_core::sc_time_stamp() << std::endl;
} else {
std::cout << name() << ": Send read request: A = 0x"
<< std::hex << (unsigned int)trans.get_address() << std::dec
<< " @ " << sc_core::sc_time_stamp() << std::endl;
}
}
void logEndTransaction(mytransaction_type& trans)
{
if (trans.get_response_status() != tlm::TLM_OK_RESPONSE) {
std::cout << name() << ": Received error response @ "
<< sc_core::sc_time_stamp() << std::endl;
} else {
std::cout << name() << ": Received ok response";
if (trans.get_command() == tlm::TLM_READ_COMMAND) {
std::cout << ": D = 0x" << std::hex << trans.getData() << std::dec;
}
std::cout << " @ " << sc_core::sc_time_stamp() << std::endl;
}
}
//
// Simple AT Initiator
// - Request must be accepted by the target before the next request can be
// send
// - Responses can come out of order
// - Responses will be accepted after fixed delay
//
void run()
{
phase_type phase;
sc_core::sc_time t;
mytransaction_type* ptrans;
while (initTransaction(ptrans)) {
// Create transaction and initialise phase and t
mytransaction_type& trans = *ptrans;
phase = tlm::BEGIN_REQ;
t = sc_core::SC_ZERO_TIME;
logStartTransation(trans);
switch (socket->nb_transport_fw(trans, phase, t)) {
case tlm::TLM_COMPLETED:
// Transaction Finished, wait for the returned delay
wait(t);
logEndTransaction(trans);
transPool.release(&trans);
break;
case tlm::TLM_ACCEPTED:
case tlm::TLM_UPDATED:
switch (phase) {
case tlm::BEGIN_REQ:
// Request phase not yet finished
// Wait until end of request phase before sending new request
// FIXME
mCurrentTransaction = &trans;
wait(mEndRequestPhase);
mCurrentTransaction = 0;
break;
case tlm::END_REQ:
// Request phase ended
if (t != sc_core::SC_ZERO_TIME) {
// Wait until end of request time before sending new request
wait(t);
}
break;
case tlm::BEGIN_RESP:
// Request phase ended and response phase already started
if (t != sc_core::SC_ZERO_TIME) {
// Wait until end of request time before sending new request
wait(t);
}
// Notify end of response phase after ACCEPT delay
t += ACCEPT_DELAY;
phase = tlm::END_RESP;
socket->nb_transport_fw(trans, phase, t);
logEndTransaction(trans);
transPool.release(&trans);
break;
case tlm::END_RESP: // fall-through
default:
// A target should never return with these phases
// If phase == END_RESP, nb_transport should have returned true
assert(0); exit(1);
break;
}
break;
default:
assert(0); exit(1);
};
}
wait();
}
sync_enum_type myNBTransport(transaction_type& trans, phase_type& phase, sc_core::sc_time& t)
{
switch (phase) {
case tlm::END_REQ:
assert(t == sc_core::SC_ZERO_TIME); // FIXME: can t != 0?
// Request phase ended
mEndRequestPhase.notify(sc_core::SC_ZERO_TIME);
return tlm::TLM_ACCEPTED;
case tlm::BEGIN_RESP:
{
assert(t == sc_core::SC_ZERO_TIME); // FIXME: can t != 0?
// Notify end of request phase if run thread is waiting for it
// FIXME
if (&trans == mCurrentTransaction) {
mEndRequestPhase.notify(sc_core::SC_ZERO_TIME);
}
assert(dynamic_cast<mytransaction_type*>(&trans));
mytransaction_type* myTrans = static_cast<mytransaction_type*>(&trans);
assert(myTrans);
// Notify end of response phase after ACCEPT delay
t += ACCEPT_DELAY;
phase = tlm::END_RESP;
logEndTransaction(*myTrans);
transPool.release(myTrans);
return tlm::TLM_COMPLETED;
}
case tlm::BEGIN_REQ: // fall-through
case tlm::END_RESP: // fall-through
default:
// A target should never call nb_transport with these phases
assert(0); exit(1);
// return tlm::TLM_COMPLETED; //unreachable code
};
}
private:
const sc_core::sc_time ACCEPT_DELAY;
private:
unsigned int mNrOfTransactions;
unsigned int mBaseAddress;
SimplePool transPool;
unsigned int mTransactionCount;
sc_core::sc_event mEndRequestPhase;
transaction_type* mCurrentTransaction;
};
#endif

View File

@@ -0,0 +1,211 @@
/*****************************************************************************
Licensed to Accellera Systems Initiative Inc. (Accellera) under one or
more contributor license agreements. See the NOTICE file distributed
with this work for additional information regarding copyright ownership.
Accellera licenses this file to you under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with the
License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied. See the License for the specific language governing
permissions and limitations under the License.
*****************************************************************************/
#ifndef __SIMPLE_AT_TARGET1_H__
#define __SIMPLE_AT_TARGET1_H__
#include "tlm.h"
#include "tlm_utils/simple_target_socket.h"
//#include <systemc>
#include <cassert>
#include <vector>
#include <queue>
//#include <iostream>
class SimpleATTarget1 : public sc_core::sc_module
{
public:
typedef tlm::tlm_generic_payload transaction_type;
typedef tlm::tlm_phase phase_type;
typedef tlm::tlm_sync_enum sync_enum_type;
typedef tlm_utils::simple_target_socket<SimpleATTarget1> target_socket_type;
public:
target_socket_type socket;
public:
SC_HAS_PROCESS(SimpleATTarget1);
SimpleATTarget1(sc_core::sc_module_name name) :
sc_core::sc_module(name),
socket("socket"),
ACCEPT_DELAY(25, sc_core::SC_NS),
RESPONSE_DELAY(100, sc_core::SC_NS)
{
// register nb_transport method
socket.register_nb_transport_fw(this, &SimpleATTarget1::myNBTransport);
SC_METHOD(endRequest)
sensitive << mEndRequestEvent;
dont_initialize();
SC_METHOD(beginResponse)
sensitive << mBeginResponseEvent;
dont_initialize();
SC_METHOD(endResponse)
sensitive << mEndResponseEvent;
dont_initialize();
}
//
// Simple AT target
// - Request is accepted after ACCEPT delay (relative to end of prev request
// phase)
// - Response is started after RESPONSE delay (relative to end of prev resp
// phase)
//
sync_enum_type myNBTransport(transaction_type& trans, phase_type& phase, sc_core::sc_time& t)
{
if (phase == tlm::BEGIN_REQ) {
// transactions may be kept in queue after the initiator has send END_REQ
trans.acquire();
sc_dt::uint64 address = trans.get_address();
assert(address < 400);
unsigned int& data = *reinterpret_cast<unsigned int*>(trans.get_data_ptr());
if (trans.get_command() == tlm::TLM_WRITE_COMMAND) {
std::cout << name() << ": Received write request: A = 0x"
<< std::hex << (unsigned int)address << ", D = 0x"
<< data << std::dec
<< " @ " << sc_core::sc_time_stamp() << std::endl;
*reinterpret_cast<unsigned int*>(&mMem[address]) = data;
} else {
std::cout << name() << ": Received read request: A = 0x"
<< std::hex << (unsigned int)address << std::dec
<< " @ " << sc_core::sc_time_stamp() << std::endl;
data = *reinterpret_cast<unsigned int*>(&mMem[address]);
}
// Notify end of request phase after ACCEPT delay
if (mEndRequestQueue.empty()) {
mEndRequestEvent.notify(t + ACCEPT_DELAY);
}
mEndRequestQueue.push(&trans);
// AT-noTA target
// - always return false
// - seperate call to indicate end of phase (do not update phase or t)
return tlm::TLM_ACCEPTED;
} else if (phase == tlm::END_RESP) {
// response phase ends after t
mEndResponseEvent.notify(t);
return tlm::TLM_COMPLETED;
}
// Not possible
assert(0); exit(1);
// return tlm::TLM_COMPLETED; //unreachable code
}
void endRequest()
{
assert(!mEndRequestQueue.empty());
// end request phase of oldest transaction
phase_type phase = tlm::END_REQ;
sc_core::sc_time t = sc_core::SC_ZERO_TIME;
transaction_type* trans = mEndRequestQueue.front();
assert(trans);
mEndRequestQueue.pop();
#if ( ! NDEBUG )
sync_enum_type r = socket->nb_transport_bw(*trans, phase, t);
#endif /* ! NDEBUG */
assert(r == tlm::TLM_ACCEPTED); // FIXME: initiator should return TLM_ACCEPTED?
assert(t == sc_core::SC_ZERO_TIME); // t must be SC_ZERO_TIME
// Notify end of request phase for next transaction after ACCEPT delay
if (!mEndRequestQueue.empty()) {
mEndRequestEvent.notify(ACCEPT_DELAY);
}
if (mResponseQueue.empty()) {
// Start processing transaction
// Notify begin of response phase after RESPONSE delay
mBeginResponseEvent.notify(RESPONSE_DELAY);
}
mResponseQueue.push(trans);
}
void beginResponse()
{
assert(!mResponseQueue.empty());
// start response phase of oldest transaction
phase_type phase = tlm::BEGIN_RESP;
sc_core::sc_time t = sc_core::SC_ZERO_TIME;
transaction_type* trans = mResponseQueue.front();
assert(trans);
// Set response data
trans->set_response_status(tlm::TLM_OK_RESPONSE);
if (trans->get_command() == tlm::TLM_READ_COMMAND) {
sc_dt::uint64 address = trans->get_address();
assert(address < 400);
*reinterpret_cast<unsigned int*>(trans->get_data_ptr()) =
*reinterpret_cast<unsigned int*>(&mMem[address]);
}
switch (socket->nb_transport_bw(*trans, phase, t)) {
case tlm::TLM_COMPLETED:
// response phase ends after t
mEndResponseEvent.notify(t);
break;
case tlm::TLM_ACCEPTED:
case tlm::TLM_UPDATED:
// initiator will call nb_transport to indicate end of response phase
break;
default:
assert(0); exit(1);
};
}
void endResponse()
{
assert(!mResponseQueue.empty());
mResponseQueue.front()->release();
mResponseQueue.pop();
if (!mResponseQueue.empty()) {
// Start processing next transaction
// Notify begin of response phase after RESPONSE delay
mBeginResponseEvent.notify(RESPONSE_DELAY);
}
}
private:
const sc_core::sc_time ACCEPT_DELAY;
const sc_core::sc_time RESPONSE_DELAY;
private:
unsigned char mMem[400];
std::queue<transaction_type*> mEndRequestQueue;
sc_core::sc_event mEndRequestEvent;
std::queue<transaction_type*> mResponseQueue;
sc_core::sc_event mBeginResponseEvent;
sc_core::sc_event mEndResponseEvent;
};
#endif

View File

@@ -0,0 +1,178 @@
/*****************************************************************************
Licensed to Accellera Systems Initiative Inc. (Accellera) under one or
more contributor license agreements. See the NOTICE file distributed
with this work for additional information regarding copyright ownership.
Accellera licenses this file to you under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with the
License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied. See the License for the specific language governing
permissions and limitations under the License.
*****************************************************************************/
#ifndef __SIMPLE_AT_TARGET2_H__
#define __SIMPLE_AT_TARGET2_H__
#include "tlm.h"
#include "tlm_utils/simple_target_socket.h"
//#include <systemc>
#include <cassert>
#include <vector>
#include <queue>
//#include <iostream>
class SimpleATTarget2 : public sc_core::sc_module
{
public:
typedef tlm::tlm_generic_payload transaction_type;
typedef tlm::tlm_phase phase_type;
typedef tlm::tlm_sync_enum sync_enum_type;
typedef tlm_utils::simple_target_socket<SimpleATTarget2> target_socket_type;
public:
target_socket_type socket;
public:
SC_HAS_PROCESS(SimpleATTarget2);
SimpleATTarget2(sc_core::sc_module_name name) :
sc_core::sc_module(name),
socket("socket"),
ACCEPT_DELAY(25, sc_core::SC_NS),
RESPONSE_DELAY(100, sc_core::SC_NS)
{
// register nb_transport method
socket.register_nb_transport_fw(this, &SimpleATTarget2::myNBTransport);
SC_METHOD(beginResponse)
sensitive << mBeginResponseEvent;
dont_initialize();
SC_METHOD(endResponse)
sensitive << mEndResponseEvent;
dont_initialize();
}
//
// Simple AT-TA target
// - Request is accepted after fixed delay (relative to end of prev request
// phase)
// - Response is started after fixed delay (relative to end of prev resp
// phase)
//
sync_enum_type myNBTransport(transaction_type& trans,
phase_type& phase,
sc_core::sc_time& t)
{
if (phase == tlm::BEGIN_REQ) {
// transactions may be kept in queue after the initiator has send END_REQ
trans.acquire();
sc_dt::uint64 address = trans.get_address();
assert(address < 400);
unsigned int& data = *reinterpret_cast<unsigned int*>(trans.get_data_ptr());
if (trans.get_command() == tlm::TLM_WRITE_COMMAND) {
std::cout << name() << ": Received write request: A = 0x"
<< std::hex << (unsigned int)address << ", D = 0x" << data
<< std::dec << " @ " << sc_core::sc_time_stamp()
<< std::endl;
*reinterpret_cast<unsigned int*>(&mMem[address]) = data;
} else {
std::cout << name() << ": Received read request: A = 0x"
<< std::hex << (unsigned int)address
<< std::dec << " @ " << sc_core::sc_time_stamp()
<< std::endl;
data = *reinterpret_cast<unsigned int*>(&mMem[address]);
}
// End request phase after accept delay
t += ACCEPT_DELAY;
phase = tlm::END_REQ;
if (mResponseQueue.empty()) {
// Start processing transaction after accept delay
// Notify begin of response phase after accept delay + response delay
mBeginResponseEvent.notify(t + RESPONSE_DELAY);
}
mResponseQueue.push(&trans);
// AT-noTA target
// - always return false
// - immediately return delay to indicate end of phase
return tlm::TLM_UPDATED;
} else if (phase == tlm::END_RESP) {
// response phase ends after t
mEndResponseEvent.notify(t);
return tlm::TLM_COMPLETED;
}
// Not possible
assert(0); exit(1);
// return tlm::TLM_COMPLETED; //unreachable code
}
void beginResponse()
{
assert(!mResponseQueue.empty());
// start response phase of oldest transaction
phase_type phase = tlm::BEGIN_RESP;
sc_core::sc_time t = sc_core::SC_ZERO_TIME;
transaction_type* trans = mResponseQueue.front();
assert(trans);
// Set response data
trans->set_response_status(tlm::TLM_OK_RESPONSE);
if (trans->get_command() == tlm::TLM_READ_COMMAND) {
sc_dt::uint64 address = trans->get_address();
assert(address < 400);
*reinterpret_cast<unsigned int*>(trans->get_data_ptr()) =
*reinterpret_cast<unsigned int*>(&mMem[address]);
}
if (socket->nb_transport_bw(*trans, phase, t) == tlm::TLM_COMPLETED) {
// response phase ends after t
mEndResponseEvent.notify(t);
} else {
// initiator will call nb_transport to indicate end of response phase
}
}
void endResponse()
{
assert(!mResponseQueue.empty());
mResponseQueue.front()->release();
mResponseQueue.pop();
// Start processing next transaction when previous response is accepted.
// Notify begin of response phase after RESPONSE delay
if (!mResponseQueue.empty()) {
mBeginResponseEvent.notify(RESPONSE_DELAY);
}
}
private:
const sc_core::sc_time ACCEPT_DELAY;
const sc_core::sc_time RESPONSE_DELAY;
private:
unsigned char mMem[400];
std::queue<transaction_type*> mResponseQueue;
sc_core::sc_event mBeginResponseEvent;
sc_core::sc_event mEndResponseEvent;
};
#endif

View File

@@ -0,0 +1,378 @@
/*****************************************************************************
Licensed to Accellera Systems Initiative Inc. (Accellera) under one or
more contributor license agreements. See the NOTICE file distributed
with this work for additional information regarding copyright ownership.
Accellera licenses this file to you under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with the
License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied. See the License for the specific language governing
permissions and limitations under the License.
*****************************************************************************/
#ifndef __SIMPLEBUSAT_H__
#define __SIMPLEBUSAT_H__
//#include <systemc>
#include "tlm.h"
#include "tlm_utils/simple_target_socket.h"
#include "tlm_utils/simple_initiator_socket.h"
#include "tlm_utils/peq_with_get.h"
template <int NR_OF_INITIATORS, int NR_OF_TARGETS>
class SimpleBusAT : public sc_core::sc_module
{
public:
typedef tlm::tlm_generic_payload transaction_type;
typedef tlm::tlm_phase phase_type;
typedef tlm::tlm_sync_enum sync_enum_type;
typedef tlm_utils::simple_target_socket_tagged<SimpleBusAT> target_socket_type;
typedef tlm_utils::simple_initiator_socket_tagged<SimpleBusAT> initiator_socket_type;
public:
target_socket_type target_socket[NR_OF_INITIATORS];
initiator_socket_type initiator_socket[NR_OF_TARGETS];
public:
SC_HAS_PROCESS(SimpleBusAT);
SimpleBusAT(sc_core::sc_module_name name) :
sc_core::sc_module(name),
mRequestPEQ("requestPEQ"),
mResponsePEQ("responsePEQ")
{
for (unsigned int i = 0; i < NR_OF_INITIATORS; ++i) {
target_socket[i].register_nb_transport_fw(this, &SimpleBusAT::initiatorNBTransport, i);
target_socket[i].register_transport_dbg(this, &SimpleBusAT::transportDebug, i);
target_socket[i].register_get_direct_mem_ptr(this, &SimpleBusAT::getDMIPointer, i);
}
for (unsigned int i = 0; i < NR_OF_TARGETS; ++i) {
initiator_socket[i].register_nb_transport_bw(this, &SimpleBusAT::targetNBTransport, i);
initiator_socket[i].register_invalidate_direct_mem_ptr(this, &SimpleBusAT::invalidateDMIPointers, i);
}
SC_THREAD(RequestThread);
SC_THREAD(ResponseThread);
}
//
// Dummy decoder:
// - address[31-28]: portId
// - address[27-0]: masked address
//
unsigned int getPortId(const sc_dt::uint64& address)
{
return (unsigned int)address >> 28;
}
sc_dt::uint64 getAddressOffset(unsigned int portId)
{
return portId << 28;
}
sc_dt::uint64 getAddressMask(unsigned int portId)
{
return 0xfffffff;
}
unsigned int decode(const sc_dt::uint64& address)
{
// decode address:
// - return initiator socket id
return getPortId(address);
}
//
// AT protocol
//
void RequestThread()
{
while (true) {
wait(mRequestPEQ.get_event());
transaction_type* trans;
while ((trans = mRequestPEQ.get_next_transaction())!=0) {
unsigned int portId = decode(trans->get_address());
assert(portId < NR_OF_TARGETS);
initiator_socket_type* decodeSocket = &initiator_socket[portId];
trans->set_address(trans->get_address() & getAddressMask(portId));
// Fill in the destination port
PendingTransactionsIterator it = mPendingTransactions.find(trans);
assert(it != mPendingTransactions.end());
it->second.to = decodeSocket;
phase_type phase = tlm::BEGIN_REQ;
sc_core::sc_time t = sc_core::SC_ZERO_TIME;
// FIXME: No limitation on number of pending transactions
// All targets (that return false) must support multiple transactions
switch ((*decodeSocket)->nb_transport_fw(*trans, phase, t)) {
case tlm::TLM_ACCEPTED:
case tlm::TLM_UPDATED:
// Transaction not yet finished
if (phase == tlm::BEGIN_REQ) {
// Request phase not yet finished
wait(mEndRequestEvent);
} else if (phase == tlm::END_REQ) {
// Request phase finished, but response phase not yet started
wait(t);
} else if (phase == tlm::BEGIN_RESP) {
mResponsePEQ.notify(*trans, t);
// Not needed to send END_REQ to initiator
continue;
} else { // END_RESP
assert(0); exit(1);
}
// only send END_REQ to initiator if BEGIN_RESP was not already send
if (it->second.from) {
phase = tlm::END_REQ;
t = sc_core::SC_ZERO_TIME;
(*it->second.from)->nb_transport_bw(*trans, phase, t);
}
break;
case tlm::TLM_COMPLETED:
// Transaction finished
mResponsePEQ.notify(*trans, t);
// reset to destination port (we must not send END_RESP to target)
it->second.to = 0;
wait(t);
break;
default:
assert(0); exit(1);
};
}
}
}
void ResponseThread()
{
while (true) {
wait(mResponsePEQ.get_event());
transaction_type* trans;
while ((trans = mResponsePEQ.get_next_transaction())!=0) {
PendingTransactionsIterator it = mPendingTransactions.find(trans);
assert(it != mPendingTransactions.end());
phase_type phase = tlm::BEGIN_RESP;
sc_core::sc_time t = sc_core::SC_ZERO_TIME;
target_socket_type* initiatorSocket = it->second.from;
// if BEGIN_RESP is send first we don't have to send END_REQ anymore
it->second.from = 0;
switch ((*initiatorSocket)->nb_transport_bw(*trans, phase, t)) {
case tlm::TLM_COMPLETED:
// Transaction finished
wait(t);
break;
case tlm::TLM_ACCEPTED:
case tlm::TLM_UPDATED:
// Transaction not yet finished
wait(mEndResponseEvent);
break;
default:
assert(0); exit(1);
};
// forward END_RESP to target
if (it->second.to) {
phase = tlm::END_RESP;
t = sc_core::SC_ZERO_TIME;
#if ( ! NDEBUG )
sync_enum_type r = (*it->second.to)->nb_transport_fw(*trans, phase, t);
#endif /* ! NDEBUG */
assert(r == tlm::TLM_COMPLETED);
}
mPendingTransactions.erase(it);
trans->release();
}
}
}
//
// interface methods
//
sync_enum_type initiatorNBTransport(int initiator_id,
transaction_type& trans,
phase_type& phase,
sc_core::sc_time& t)
{
if (phase == tlm::BEGIN_REQ) {
trans.acquire();
addPendingTransaction(trans, 0, initiator_id);
mRequestPEQ.notify(trans, t);
} else if (phase == tlm::END_RESP) {
mEndResponseEvent.notify(t);
return tlm::TLM_COMPLETED;
} else {
std::cout << "ERROR: '" << name()
<< "': Illegal phase received from initiator." << std::endl;
assert(false); exit(1);
}
return tlm::TLM_ACCEPTED;
}
sync_enum_type targetNBTransport(int portId,
transaction_type& trans,
phase_type& phase,
sc_core::sc_time& t)
{
if (phase != tlm::END_REQ && phase != tlm::BEGIN_RESP) {
std::cout << "ERROR: '" << name()
<< "': Illegal phase received from target." << std::endl;
assert(false); exit(1);
}
mEndRequestEvent.notify(t);
if (phase == tlm::BEGIN_RESP) {
mResponsePEQ.notify(trans, t);
}
return tlm::TLM_ACCEPTED;
}
unsigned int transportDebug(int initiator_id, transaction_type& trans)
{
unsigned int portId = decode(trans.get_address());
assert(portId < NR_OF_TARGETS);
initiator_socket_type* decodeSocket = &initiator_socket[portId];
trans.set_address( trans.get_address() & getAddressMask(portId) );
return (*decodeSocket)->transport_dbg(trans);
}
bool limitRange(unsigned int portId, sc_dt::uint64& low, sc_dt::uint64& high)
{
sc_dt::uint64 addressOffset = getAddressOffset(portId);
sc_dt::uint64 addressMask = getAddressMask(portId);
if (low > addressMask) {
// Range does not overlap with addressrange for this target
return false;
}
low += addressOffset;
if (high > addressMask) {
high = addressOffset + addressMask;
} else {
high += addressOffset;
}
return true;
}
bool getDMIPointer(int initiator_id,
transaction_type& trans,
tlm::tlm_dmi& dmi_data)
{
// FIXME: DMI not supported for AT bus?
sc_dt::uint64 address = trans.get_address();
unsigned int portId = decode(address);
assert(portId < NR_OF_TARGETS);
initiator_socket_type* decodeSocket = &initiator_socket[portId];
sc_dt::uint64 maskedAddress = address & getAddressMask(portId);
trans.set_address(maskedAddress);
bool result =
(*decodeSocket)->get_direct_mem_ptr(trans, dmi_data);
if (result)
{
// Range must contain address
assert(dmi_data.get_start_address() <= maskedAddress);
assert(dmi_data.get_end_address() >= maskedAddress);
}
// Should always succeed
sc_dt::uint64 start, end;
start = dmi_data.get_start_address();
end = dmi_data.get_end_address();
limitRange(portId, start, end);
dmi_data.set_start_address(start);
dmi_data.set_end_address(end);
return result;
}
void invalidateDMIPointers(int portId,
sc_dt::uint64 start_range,
sc_dt::uint64 end_range)
{
// FIXME: probably faster to always invalidate everything?
if ((portId >= 0) && !limitRange(portId, start_range, end_range)) {
// Range does not fall into address range of target
return;
}
for (unsigned int i = 0; i < NR_OF_INITIATORS; ++i) {
(target_socket[i])->invalidate_direct_mem_ptr(start_range, end_range);
}
}
private:
void addPendingTransaction(transaction_type& trans,
initiator_socket_type* to,
int initiatorId)
{
const ConnectionInfo info = { &target_socket[initiatorId], to };
assert(mPendingTransactions.find(&trans) == mPendingTransactions.end());
mPendingTransactions[&trans] = info;
}
private:
struct ConnectionInfo {
target_socket_type* from;
initiator_socket_type* to;
};
typedef std::map<transaction_type*, ConnectionInfo> PendingTransactions;
typedef typename PendingTransactions::iterator PendingTransactionsIterator;
typedef typename PendingTransactions::const_iterator PendingTransactionsConstIterator;
private:
PendingTransactions mPendingTransactions;
tlm_utils::peq_with_get<transaction_type> mRequestPEQ;
sc_core::sc_event mBeginRequestEvent;
sc_core::sc_event mEndRequestEvent;
tlm_utils::peq_with_get<transaction_type> mResponsePEQ;
sc_core::sc_event mBeginResponseEvent;
sc_core::sc_event mEndResponseEvent;
};
#endif

View File

@@ -0,0 +1,193 @@
/*****************************************************************************
Licensed to Accellera Systems Initiative Inc. (Accellera) under one or
more contributor license agreements. See the NOTICE file distributed
with this work for additional information regarding copyright ownership.
Accellera licenses this file to you under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with the
License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied. See the License for the specific language governing
permissions and limitations under the License.
*****************************************************************************/
#ifndef __SIMPLEBUSLT_H__
#define __SIMPLEBUSLT_H__
//#include <systemc>
#include "tlm.h"
#include "tlm_utils/simple_target_socket.h"
#include "tlm_utils/simple_initiator_socket.h"
template <int NR_OF_INITIATORS, int NR_OF_TARGETS>
class SimpleBusLT : public sc_core::sc_module
{
public:
typedef tlm::tlm_generic_payload transaction_type;
typedef tlm::tlm_phase phase_type;
typedef tlm::tlm_sync_enum sync_enum_type;
typedef tlm_utils::simple_target_socket_tagged<SimpleBusLT> target_socket_type;
typedef tlm_utils::simple_initiator_socket_tagged<SimpleBusLT> initiator_socket_type;
public:
target_socket_type target_socket[NR_OF_INITIATORS];
initiator_socket_type initiator_socket[NR_OF_TARGETS];
public:
SC_HAS_PROCESS(SimpleBusLT);
SimpleBusLT(sc_core::sc_module_name name) :
sc_core::sc_module(name)
{
for (unsigned int i = 0; i < NR_OF_INITIATORS; ++i) {
target_socket[i].register_b_transport(this, &SimpleBusLT::initiatorBTransport, i);
target_socket[i].register_transport_dbg(this, &SimpleBusLT::transportDebug, i);
target_socket[i].register_get_direct_mem_ptr(this, &SimpleBusLT::getDMIPointer, i);
}
for (unsigned int i = 0; i < NR_OF_TARGETS; ++i) {
initiator_socket[i].register_invalidate_direct_mem_ptr(this, &SimpleBusLT::invalidateDMIPointers, i);
}
}
//
// Dummy decoder:
// - address[31-28]: portId
// - address[27-0]: masked address
//
unsigned int getPortId(const sc_dt::uint64& address)
{
return (unsigned int)address >> 28;
}
sc_dt::uint64 getAddressOffset(unsigned int portId)
{
return portId << 28;
}
sc_dt::uint64 getAddressMask(unsigned int portId)
{
return 0xfffffff;
}
unsigned int decode(const sc_dt::uint64& address)
{
// decode address:
// - return initiator socket id
return getPortId(address);
}
//
// interface methods
//
//
// LT protocol
// - forward each call to the target/initiator
//
void initiatorBTransport(int SocketId,
transaction_type& trans,
sc_core::sc_time& t)
{
initiator_socket_type* decodeSocket;
unsigned int portId = decode(trans.get_address());
assert(portId < NR_OF_TARGETS);
decodeSocket = &initiator_socket[portId];
trans.set_address(trans.get_address() & getAddressMask(portId));
(*decodeSocket)->b_transport(trans, t);
}
unsigned int transportDebug(int SocketId,
transaction_type& trans)
{
unsigned int portId = decode(trans.get_address());
assert(portId < NR_OF_TARGETS);
initiator_socket_type* decodeSocket = &initiator_socket[portId];
trans.set_address( trans.get_address() & getAddressMask(portId) );
return (*decodeSocket)->transport_dbg(trans);
}
bool limitRange(unsigned int portId, sc_dt::uint64& low, sc_dt::uint64& high)
{
sc_dt::uint64 addressOffset = getAddressOffset(portId);
sc_dt::uint64 addressMask = getAddressMask(portId);
if (low > addressMask) {
// Range does not overlap with addressrange for this target
return false;
}
low += addressOffset;
if (high > addressMask) {
high = addressOffset + addressMask;
} else {
high += addressOffset;
}
return true;
}
bool getDMIPointer(int SocketId,
transaction_type& trans,
tlm::tlm_dmi& dmi_data)
{
sc_dt::uint64 address = trans.get_address();
unsigned int portId = decode(address);
assert(portId < NR_OF_TARGETS);
initiator_socket_type* decodeSocket = &initiator_socket[portId];
sc_dt::uint64 maskedAddress = address & getAddressMask(portId);
trans.set_address(maskedAddress);
bool result =
(*decodeSocket)->get_direct_mem_ptr(trans, dmi_data);
if (result)
{
// Range must contain address
assert(dmi_data.get_start_address() <= maskedAddress);
assert(dmi_data.get_end_address() >= maskedAddress);
}
// Should always succeed
sc_dt::uint64 start, end;
start = dmi_data.get_start_address();
end = dmi_data.get_end_address();
limitRange(portId, start, end);
dmi_data.set_start_address(start);
dmi_data.set_end_address(end);
return result;
}
void invalidateDMIPointers(int port_id,
sc_dt::uint64 start_range,
sc_dt::uint64 end_range)
{
// FIXME: probably faster to always invalidate everything?
if (!limitRange(port_id, start_range, end_range)) {
// Range does not fall into address range of target
return;
}
for (unsigned int i = 0; i < NR_OF_INITIATORS; ++i) {
(target_socket[i])->invalidate_direct_mem_ptr(start_range, end_range);
}
}
};
#endif

View File

@@ -0,0 +1,162 @@
/*****************************************************************************
Licensed to Accellera Systems Initiative Inc. (Accellera) under one or
more contributor license agreements. See the NOTICE file distributed
with this work for additional information regarding copyright ownership.
Accellera licenses this file to you under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with the
License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied. See the License for the specific language governing
permissions and limitations under the License.
*****************************************************************************/
//====================================================================
// Nov 06, 2008
//
// Updated by:
// Xiaopeng Qiu, JEDA Technologies, Inc
// Email: qiuxp@jedatechnologies.net
//
// To fix violations of TLM2.0 rules, which are detected by JEDA
// TLM2.0 checker.
//
//====================================================================
#ifndef __SIMPLE_LT_INITIATOR1_H__
#define __SIMPLE_LT_INITIATOR1_H__
#include "tlm.h" /// TLM definitions
#include <cassert> /// STD assert ()
class SimpleLTInitiator1 :
public sc_core::sc_module,
public virtual tlm::tlm_bw_transport_if<>
{
public:
typedef tlm::tlm_generic_payload transaction_type;
typedef tlm::tlm_phase phase_type;
typedef tlm::tlm_sync_enum sync_enum_type;
typedef tlm::tlm_fw_transport_if<> fw_interface_type;
typedef tlm::tlm_bw_transport_if<> bw_interface_type;
typedef tlm::tlm_initiator_socket<32> initiator_socket_type;
public:
initiator_socket_type socket;
public:
SC_HAS_PROCESS(SimpleLTInitiator1);
SimpleLTInitiator1(sc_core::sc_module_name name,
unsigned int nrOfTransactions = 0x5,
unsigned int baseAddress = 0x0) :
sc_core::sc_module(name),
socket("socket"),
mNrOfTransactions(nrOfTransactions),
mBaseAddress(baseAddress),
mTransactionCount(0)
{
// Bind this initiator's interface to the initiator socket
socket(*this);
// Initiator thread
SC_THREAD(run);
}
bool initTransaction(transaction_type& trans)
{
if (mTransactionCount < mNrOfTransactions) {
trans.set_address(mBaseAddress + 4*mTransactionCount);
mData = mTransactionCount;
trans.set_command(tlm::TLM_WRITE_COMMAND);
} else if (mTransactionCount < 2 * mNrOfTransactions) {
trans.set_address(mBaseAddress + 4*(mTransactionCount - mNrOfTransactions));
mData = 0;
trans.set_command(tlm::TLM_READ_COMMAND);
} else {
return false;
}
trans.set_data_ptr(reinterpret_cast<unsigned char*>(&mData));
trans.set_data_length(4);
trans.set_streaming_width(4);
trans.set_dmi_allowed(false);
trans.set_response_status(tlm::TLM_INCOMPLETE_RESPONSE);
++mTransactionCount;
return true;
}
void logStartTransation(transaction_type& trans)
{
if (trans.get_command() == tlm::TLM_WRITE_COMMAND) {
std::cout << name() << ": Send write request: A = 0x"
<< std::hex << (unsigned int)trans.get_address()
<< ", D = 0x" << mData << std::dec
<< " @ " << sc_core::sc_time_stamp() << std::endl;
} else {
std::cout << name() << ": Send read request: A = 0x"
<< std::hex << (unsigned int)trans.get_address() << std::dec
<< " @ " << sc_core::sc_time_stamp() << std::endl;
}
}
void logEndTransaction(transaction_type& trans)
{
if (trans.get_response_status() != tlm::TLM_OK_RESPONSE) {
std::cout << name() << ": Received error response @ "
<< sc_core::sc_time_stamp() << std::endl;
} else {
std::cout << name() << ": Received ok response";
if (trans.get_command() == tlm::TLM_READ_COMMAND) {
std::cout << ": D = 0x" << std::hex << mData << std::dec;
}
std::cout << " @ " << sc_core::sc_time_stamp() << std::endl;
}
}
void run()
{
transaction_type trans;
sc_core::sc_time t(sc_core::SC_ZERO_TIME);
while (initTransaction(trans)) {
logStartTransation(trans);
socket->b_transport(trans, t);
wait(t);
logEndTransaction(trans);
t = sc_core::SC_ZERO_TIME;
}
wait();
}
tlm::tlm_sync_enum nb_transport_bw(transaction_type &,phase_type &,sc_core::sc_time & )
{
assert(0); // should never happen
return tlm::TLM_COMPLETED;
}
void invalidate_direct_mem_ptr(sc_dt::uint64 start_range,
sc_dt::uint64 end_range)
{
// No DMI support: ignore
}
private:
sc_core::sc_event mEndEvent;
unsigned int mNrOfTransactions;
unsigned int mBaseAddress;
unsigned int mTransactionCount;
unsigned int mData;
};
#endif

View File

@@ -0,0 +1,305 @@
/*****************************************************************************
Licensed to Accellera Systems Initiative Inc. (Accellera) under one or
more contributor license agreements. See the NOTICE file distributed
with this work for additional information regarding copyright ownership.
Accellera licenses this file to you under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with the
License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied. See the License for the specific language governing
permissions and limitations under the License.
*****************************************************************************/
//====================================================================
// Nov 06, 2008
//
// Updated by:
// Xiaopeng Qiu, JEDA Technologies, Inc
// Email: qiuxp@jedatechnologies.net
//
// To fix violations of TLM2.0 rules, which are detected by JEDA
// TLM2.0 checker.
//
//====================================================================
#ifndef __SIMPLE_LT_INITIATOR1_DMI_H__
#define __SIMPLE_LT_INITIATOR1_DMI_H__
#include "tlm.h"
#include <systemc>
#include <cassert>
#include <iostream>
#include <iomanip>
class SimpleLTInitiator1_dmi :
public sc_core::sc_module,
public virtual tlm::tlm_bw_transport_if<>
{
public:
typedef tlm::tlm_generic_payload transaction_type;
typedef tlm::tlm_dmi dmi_type;
typedef tlm::tlm_phase phase_type;
typedef tlm::tlm_sync_enum sync_enum_type;
typedef tlm::tlm_fw_transport_if<> fw_interface_type;
typedef tlm::tlm_bw_transport_if<> bw_interface_type;
typedef tlm::tlm_initiator_socket<> initiator_socket_type;
public:
initiator_socket_type socket;
public:
SC_HAS_PROCESS(SimpleLTInitiator1_dmi);
SimpleLTInitiator1_dmi(sc_core::sc_module_name name,
unsigned int nrOfTransactions = 0x5,
unsigned int baseAddress = 0x0) :
sc_core::sc_module(name),
socket("socket"),
mNrOfTransactions(nrOfTransactions),
mBaseAddress(baseAddress),
mTransactionCount(0)
{
invalidate(mDMIData);
// Bind this initiator's interface to the initiator socket
socket(*this);
// Initiator thread
SC_THREAD(run);
}
bool initTransaction(transaction_type& trans)
{
// initialize DMI hint:
trans.set_dmi_allowed(false);
if (mTransactionCount < mNrOfTransactions) {
trans.set_address(mBaseAddress + 4*mTransactionCount);
mData = mTransactionCount;
trans.set_command(tlm::TLM_WRITE_COMMAND);
} else if (mTransactionCount < 2 * mNrOfTransactions) {
trans.set_address(mBaseAddress + 4*(mTransactionCount-mNrOfTransactions));
mData = 0;
trans.set_command(tlm::TLM_READ_COMMAND);
} else {
return false;
}
trans.set_data_ptr(reinterpret_cast<unsigned char*>(&mData));
trans.set_data_length(4);
trans.set_streaming_width(4);
++mTransactionCount;
return true;
}
void logStartTransation(transaction_type& trans)
{
if (trans.get_command() == tlm::TLM_WRITE_COMMAND) {
std::cout << name() << ": Send write request: A = 0x"
<< std::hex << (unsigned int)trans.get_address()
<< ", D = 0x" << mData << std::dec
<< " @ " << sc_core::sc_time_stamp() << std::endl;
} else {
std::cout << name() << ": Send read request: A = 0x"
<< std::hex << (unsigned int)trans.get_address() << std::dec
<< " @ " << sc_core::sc_time_stamp() << std::endl;
}
}
void logEndTransaction(transaction_type& trans)
{
if (trans.get_response_status() != tlm::TLM_OK_RESPONSE) {
std::cout << name() << ": Received error response @ "
<< sc_core::sc_time_stamp() << std::endl;
} else {
std::cout << name() << ": Received ok response";
if (trans.get_command() == tlm::TLM_READ_COMMAND) {
std::cout << ": D = 0x" << std::hex << mData << std::dec;
}
std::cout << " @ " << sc_core::sc_time_stamp() << std::endl;
}
}
void run()
{
transaction_type trans;
phase_type phase;
sc_core::sc_time t;
while (initTransaction(trans)) {
// Create transaction and initialise phase and t
phase = tlm::BEGIN_REQ;
t = sc_core::SC_ZERO_TIME;
logStartTransation(trans);
///////////////////////////////////////////////////////////
// DMI handling:
// We use the DMI hint to check if it makes sense to ask for
// DMI pointers. The pattern is:
// - if the address is covered by a DMI region do a DMI access
// - otherwise do a normal transaction
// -> check if we get a DMI hint and acquire the DMI pointers if it is
// set
///////////////////////////////////////////////////////////
// Check if the address is covered by our DMI region
if ( (trans.get_address() >= mDMIData.get_start_address()) &&
(trans.get_address() <= mDMIData.get_end_address()) ) {
// We can handle the data here. As the logEndTransaction is assuming
// something to happen in the data structure, we really need to
// do this:
trans.set_response_status(tlm::TLM_OK_RESPONSE);
sc_dt::uint64 tmp = trans.get_address() - mDMIData.get_start_address();
if (trans.get_command() == tlm::TLM_WRITE_COMMAND) {
*(unsigned int*)&mDMIData.get_dmi_ptr()[tmp] = mData;
} else {
mData = *(unsigned int*)&mDMIData.get_dmi_ptr()[tmp];
}
// Do the wait immediately. Note that doing the wait here eats almost
// all the performance anyway, so we only gain something if we're
// using temporal decoupling.
if (trans.get_command() == tlm::TLM_WRITE_COMMAND) {
wait(mDMIData.get_write_latency());
} else {
wait(mDMIData.get_read_latency());
}
logEndTransaction(trans);
} else { // we need a full transaction
sc_dt::uint64 addr = trans.get_address(); //Save address before it is mutated
socket->b_transport(trans, t);
wait(t);
logEndTransaction(trans);
// Acquire DMI pointer on is available:
if (trans.is_dmi_allowed())
{
dmi_type tmp;
tmp.init();
trans.set_address(addr); //restore address, in case it was mutated.
trans.set_write();
if ( socket->get_direct_mem_ptr(trans, tmp)
&& tmp.is_write_allowed() )
{
mDMIData = tmp;
}
}
}
}
wait();
}
sync_enum_type nb_transport_bw(transaction_type& trans, phase_type& phase, sc_core::sc_time& t)
{
// We should never be called
assert(0);
return tlm::TLM_COMPLETED;
}
void invalidate(dmi_type& dmiData)
{
dmiData.set_start_address(1);
dmiData.set_end_address(0);
}
// Invalidate DMI pointer(s)
void invalidate_direct_mem_ptr(sc_dt::uint64 start_range,
sc_dt::uint64 end_range)
{
// do the invalidation if there is an address range overlap
if (start_range <= mDMIData.get_end_address ()&&
end_range >= mDMIData.get_start_address()) {
std::cout << name() << ": got DMI pointer invalidation"
<< " @ " << sc_core::sc_time_stamp() << std::endl;
invalidate(mDMIData);
} else {
std::cout << name() << ": ignored DMI invalidation for addresses "
<< std::hex << start_range << ", "
<< end_range << std::dec
<< " @ " << sc_core::sc_time_stamp() << std::endl;
}
}
// Test for transport_dbg:
// FIXME: use a configurable address
void end_of_simulation()
{
std::cout << name() << ", <<SimpleLTInitiator1>>:" << std::endl
<< std::endl;
unsigned char data[32];
transaction_type trans;
trans.set_address(mBaseAddress);
trans.set_data_length(32);
trans.set_data_ptr(data);
trans.set_read();
unsigned int n = socket->transport_dbg(trans);
std::cout << "Mem @" << std::hex << mBaseAddress << std::endl;
unsigned int j = 0;
if (n > 0)
{
// always align endianness, so that we don't get a diff when
// printing the raw data
int e_start = 0;
int e_end = 4;
int e_increment = 1;
if (!tlm::host_has_little_endianness())
{
e_start = 3;
e_end = -1;
e_increment = -1;
}
for (unsigned int i=0; i<n; i+=4)
{
for (int k=e_start; k!=e_end; k+=e_increment)
{
std::cout << std::setw(2) << std::setfill('0')
<< (int)data[i+k];
j++;
if (j==16) {
j=0;
std::cout << std::endl;
} else {
std::cout << " ";
}
}
}
}
else
{
std::cout << "ERROR: debug transaction didn't give data." << std::endl;
}
std::cout << std::dec << std::endl;
}
private:
dmi_type mDMIData;
sc_core::sc_event mEndEvent;
unsigned int mNrOfTransactions;
unsigned int mBaseAddress;
unsigned int mTransactionCount;
unsigned int mData;
};
#endif

View File

@@ -0,0 +1,151 @@
/*****************************************************************************
Licensed to Accellera Systems Initiative Inc. (Accellera) under one or
more contributor license agreements. See the NOTICE file distributed
with this work for additional information regarding copyright ownership.
Accellera licenses this file to you under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with the
License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied. See the License for the specific language governing
permissions and limitations under the License.
*****************************************************************************/
//====================================================================
// Nov 06, 2008
//
// Updated by:
// Xiaopeng Qiu, JEDA Technologies, Inc
// Email: qiuxp@jedatechnologies.net
//
// To fix violations of TLM2.0 rules, which are detected by JEDA
// TLM2.0 checker.
//
//====================================================================
#ifndef __SIMPLE_LT_INITIATOR2_H__
#define __SIMPLE_LT_INITIATOR2_H__
#include "tlm.h"
#include "tlm_utils/simple_initiator_socket.h"
//#include <systemc>
#include <cassert>
//#include <iostream>
class SimpleLTInitiator2 : public sc_core::sc_module
{
public:
typedef tlm::tlm_generic_payload transaction_type;
typedef tlm::tlm_phase phase_type;
typedef tlm::tlm_sync_enum sync_enum_type;
typedef tlm_utils::simple_initiator_socket<SimpleLTInitiator2> initiator_socket_type;
public:
initiator_socket_type socket;
public:
SC_HAS_PROCESS(SimpleLTInitiator2);
SimpleLTInitiator2(sc_core::sc_module_name name,
unsigned int nrOfTransactions = 0x5,
unsigned int baseAddress = 0x0) :
sc_core::sc_module(name),
socket("socket"),
mNrOfTransactions(nrOfTransactions),
mBaseAddress(baseAddress),
mTransactionCount(0)
{
// Initiator thread
SC_THREAD(run);
}
bool initTransaction(transaction_type& trans)
{
if (mTransactionCount < mNrOfTransactions) {
trans.set_address(mBaseAddress + 4*mTransactionCount);
mData = mTransactionCount;
trans.set_command(tlm::TLM_WRITE_COMMAND);
} else if (mTransactionCount < 2 * mNrOfTransactions) {
trans.set_address(mBaseAddress + 4*(mTransactionCount - mNrOfTransactions));
mData = 0;
trans.set_command(tlm::TLM_READ_COMMAND);
} else {
return false;
}
trans.set_data_ptr(reinterpret_cast<unsigned char*>(&mData));
trans.set_data_length(4);
trans.set_streaming_width(4);
trans.set_dmi_allowed(false);
trans.set_response_status(tlm::TLM_INCOMPLETE_RESPONSE);
++mTransactionCount;
return true;
}
void logStartTransation(transaction_type& trans)
{
if (trans.get_command() == tlm::TLM_WRITE_COMMAND) {
std::cout << name() << ": Send write request: A = 0x"
<< std::hex << (unsigned int)trans.get_address()
<< ", D = 0x" << mData << std::dec
<< " @ " << sc_core::sc_time_stamp() << std::endl;
} else {
std::cout << name() << ": Send read request: A = 0x"
<< std::hex << (unsigned int)trans.get_address() << std::dec
<< " @ " << sc_core::sc_time_stamp() << std::endl;
}
}
void logEndTransaction(transaction_type& trans)
{
if (trans.get_response_status() != tlm::TLM_OK_RESPONSE) {
std::cout << name() << ": Received error response @ "
<< sc_core::sc_time_stamp() << std::endl;
} else {
std::cout << name() << ": Received ok response";
if (trans.get_command() == tlm::TLM_READ_COMMAND) {
std::cout << ": D = 0x" << std::hex << mData << std::dec;
}
std::cout << " @ " << sc_core::sc_time_stamp() << std::endl;
}
}
void run()
{
transaction_type trans;
sc_core::sc_time t;
while (initTransaction(trans)) {
// Create transaction and initialise t
t = sc_core::SC_ZERO_TIME;
logStartTransation(trans);
socket->b_transport(trans, t);
wait(t);
logEndTransaction(trans);
}
wait();
}
private:
sc_core::sc_event mEndEvent;
unsigned int mNrOfTransactions;
unsigned int mBaseAddress;
unsigned int mTransactionCount;
unsigned int mData;
};
#endif

View File

@@ -0,0 +1,299 @@
/*****************************************************************************
Licensed to Accellera Systems Initiative Inc. (Accellera) under one or
more contributor license agreements. See the NOTICE file distributed
with this work for additional information regarding copyright ownership.
Accellera licenses this file to you under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with the
License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied. See the License for the specific language governing
permissions and limitations under the License.
*****************************************************************************/
//====================================================================
// Nov 06, 2008
//
// Updated by:
// Xiaopeng Qiu, JEDA Technologies, Inc
// Email: qiuxp@jedatechnologies.net
//
// To fix violations of TLM2.0 rules, which are detected by JEDA
// TLM2.0 checker.
//
//====================================================================
#ifndef __SIMPLE_LT_INITIATOR2_DMI_H__
#define __SIMPLE_LT_INITIATOR2_DMI_H__
#include "tlm.h"
#include "tlm_utils/simple_initiator_socket.h"
#include <systemc>
#include <cassert>
#include <iostream>
#include <iomanip>
#include <map>
class SimpleLTInitiator2_dmi : public sc_core::sc_module
{
public:
typedef tlm::tlm_generic_payload transaction_type;
typedef tlm::tlm_dmi dmi_type;
typedef tlm::tlm_phase phase_type;
typedef tlm::tlm_sync_enum sync_enum_type;
typedef tlm_utils::simple_initiator_socket<SimpleLTInitiator2_dmi> initiator_socket_type;
public:
initiator_socket_type socket;
public:
SC_HAS_PROCESS(SimpleLTInitiator2_dmi);
SimpleLTInitiator2_dmi(sc_core::sc_module_name name,
unsigned int nrOfTransactions = 0x5,
unsigned int baseAddress = 0x0) :
sc_core::sc_module(name),
socket("socket"),
mNrOfTransactions(nrOfTransactions),
mBaseAddress(baseAddress),
mTransactionCount(0)
{
mDMIDataReads.first.set_start_address(1);
mDMIDataReads.first.set_end_address(0);
mDMIDataWrites.first.set_start_address(1);
mDMIDataWrites.first.set_end_address(0);
// register invalidate method
socket.register_invalidate_direct_mem_ptr(this, &SimpleLTInitiator2_dmi::invalidate_direct_mem_ptr);
// Initiator thread
SC_THREAD(run);
}
bool initTransaction(transaction_type& trans)
{
if (mTransactionCount < mNrOfTransactions) {
trans.set_address(mBaseAddress + 4*mTransactionCount);
mData = mTransactionCount;
trans.set_command(tlm::TLM_WRITE_COMMAND);
} else if (mTransactionCount < 2 * mNrOfTransactions) {
trans.set_address(mBaseAddress + 4*(mTransactionCount-mNrOfTransactions));
mData = 0;
trans.set_command(tlm::TLM_READ_COMMAND);
} else {
return false;
}
trans.set_data_ptr(reinterpret_cast<unsigned char*>(&mData));
trans.set_data_length(4);
trans.set_streaming_width(4);
trans.set_dmi_allowed(false);
trans.set_response_status(tlm::TLM_INCOMPLETE_RESPONSE);
++mTransactionCount;
return true;
}
void logStartTransation(transaction_type& trans)
{
if (trans.get_command() == tlm::TLM_WRITE_COMMAND) {
std::cout << name() << ": Send write request: A = 0x"
<< std::hex << (unsigned int)trans.get_address()
<< ", D = 0x" << mData << std::dec
<< " @ " << sc_core::sc_time_stamp() << std::endl;
} else {
std::cout << name() << ": Send read request: A = 0x"
<< std::hex << (unsigned int)trans.get_address() << std::dec
<< " @ " << sc_core::sc_time_stamp() << std::endl;
}
}
void logEndTransaction(transaction_type& trans)
{
if (trans.get_response_status() != tlm::TLM_OK_RESPONSE) {
std::cout << name() << ": Received error response @ "
<< sc_core::sc_time_stamp() << std::endl;
} else {
std::cout << name() << ": Received ok response";
if (trans.get_command() == tlm::TLM_READ_COMMAND) {
std::cout << ": D = 0x" << std::hex << mData << std::dec;
}
std::cout << " @ " << sc_core::sc_time_stamp() << std::endl;
}
}
std::pair<dmi_type, bool>& getDMIData(const transaction_type& trans)
{
if (trans.get_command() == tlm::TLM_READ_COMMAND) {
return mDMIDataReads;
} else { // WRITE
return mDMIDataWrites;
}
}
void run()
{
transaction_type trans;
sc_core::sc_time t;
while (initTransaction(trans)) {
// Create transaction and initialise t
t = sc_core::SC_ZERO_TIME;
logStartTransation(trans);
///////////////////////////////////////////////////////////
// DMI handling:
// We do *not* use the DMI hint to check if it makes sense to ask for
// DMI pointers. So the pattern is:
// - if the address is not covered by a DMI region try to acquire DMI
// pointers
// - if we have a DMI pointer, do the DMI "transaction"
// - otherwise fall back to a normal transaction
///////////////////////////////////////////////////////////
std::pair<dmi_type, bool>& dmi_data = getDMIData(trans);
// Check if we need to acquire a DMI pointer
if((trans.get_address() < dmi_data.first.get_start_address()) ||
(trans.get_address() > dmi_data.first.get_end_address()) )
{
sc_dt::uint64 address = trans.get_address(); //save original address
dmi_data.second =
socket->get_direct_mem_ptr(trans,
dmi_data.first);
trans.set_address(address);
}
// Do DMI "transaction" if we have a valid region
if (dmi_data.second &&
(trans.get_address() >= dmi_data.first.get_start_address()) &&
(trans.get_address() <= dmi_data.first.get_end_address()) )
{
// We can handle the data here. As the logEndTransaction is assuming
// something to happen in the data structure, we really need to
// do this:
trans.set_response_status(tlm::TLM_OK_RESPONSE);
sc_dt::uint64 tmp = trans.get_address() - dmi_data.first.get_start_address();
if (trans.get_command() == tlm::TLM_WRITE_COMMAND)
{
*(unsigned int*)&dmi_data.first.get_dmi_ptr()[tmp] = mData;
}
else
{
mData = *(unsigned int*)&dmi_data.first.get_dmi_ptr()[tmp];
}
// Do the wait immediately. Note that doing the wait here eats almost
// all the performance anyway, so we only gain something if we're
// using temporal decoupling.
if (trans.get_command() == tlm::TLM_WRITE_COMMAND) {
wait(dmi_data.first.get_write_latency());
} else {
wait(dmi_data.first.get_read_latency());
}
}
else // we need a full transaction
{
socket->b_transport(trans, t);
wait(t);
}
logEndTransaction(trans);
}
wait();
}
// Invalidate DMI pointer(s)
void invalidate_direct_mem_ptr(sc_dt::uint64 start_range,
sc_dt::uint64 end_range)
{
// FIXME: probably faster to always invalidate everything?
if (start_range <= mDMIDataReads.first.get_end_address ()&&
end_range >= mDMIDataReads.first.get_start_address()) {
mDMIDataReads.second = false;
}
if (start_range <= mDMIDataWrites.first.get_end_address ()&&
end_range >= mDMIDataWrites.first.get_start_address()) {
mDMIDataWrites.second = false;
}
}
// Test for transport_dbg, this one should fail in bus_dmi as we address
// a target that doesn't support transport_dbg:
// FIXME: use a configurable address
void end_of_simulation()
{
std::cout << name() << ", <<SimpleLTInitiator1>>:" << std::endl
<< std::endl;
unsigned char data[32];
transaction_type trans;
trans.set_address(mBaseAddress);
trans.set_data_length(32);
trans.set_data_ptr(data);
trans.set_read();
unsigned int n = socket->transport_dbg(trans);
std::cout << "Mem @" << std::hex << mBaseAddress << std::endl;
unsigned int j = 0;
if (n > 0)
{
// always align endianness, so that we don't get a diff when
// printing the raw data
int e_start = 0;
int e_end = 4;
int e_increment = 1;
if (!tlm::host_has_little_endianness())
{
e_start = 3;
e_end = -1;
e_increment = -1;
}
for (unsigned int i=0; i<n; i+=4)
{
for (int k=e_start; k!=e_end; k+=e_increment)
{
std::cout << std::setw(2) << std::setfill('0')
<< (int)data[i+k];
j++;
if (j==16) {
j=0;
std::cout << std::endl;
} else {
std::cout << " ";
}
}
}
}
else
{
std::cout << "OK: debug transaction didn't give data." << std::endl;
}
std::cout << std::dec << std::endl;
}
private:
std::pair<dmi_type, bool> mDMIDataReads;
std::pair<dmi_type, bool> mDMIDataWrites;
sc_core::sc_event mEndEvent;
unsigned int mNrOfTransactions;
unsigned int mBaseAddress;
unsigned int mTransactionCount;
unsigned int mData;
};
#endif

View File

@@ -0,0 +1,152 @@
/*****************************************************************************
Licensed to Accellera Systems Initiative Inc. (Accellera) under one or
more contributor license agreements. See the NOTICE file distributed
with this work for additional information regarding copyright ownership.
Accellera licenses this file to you under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with the
License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied. See the License for the specific language governing
permissions and limitations under the License.
*****************************************************************************/
//====================================================================
// Nov 06, 2008
//
// Updated by:
// Xiaopeng Qiu, JEDA Technologies, Inc
// Email: qiuxp@jedatechnologies.net
//
// To fix violations of TLM2.0 rules, which are detected by JEDA
// TLM2.0 checker.
//
//====================================================================
#ifndef __SIMPLE_LT_INITIATOR3_H__
#define __SIMPLE_LT_INITIATOR3_H__
#include "tlm.h"
#include "tlm_utils/simple_initiator_socket.h"
//#include <systemc>
#include <cassert>
//#include <iostream>
class SimpleLTInitiator3 : public sc_core::sc_module
{
public:
typedef tlm::tlm_generic_payload transaction_type;
typedef tlm::tlm_phase phase_type;
typedef tlm::tlm_sync_enum sync_enum_type;
typedef tlm_utils::simple_initiator_socket<SimpleLTInitiator3> initiator_socket_type;
public:
initiator_socket_type socket;
public:
SC_HAS_PROCESS(SimpleLTInitiator3);
SimpleLTInitiator3(sc_core::sc_module_name name,
unsigned int nrOfTransactions = 0x5,
unsigned int baseAddress = 0x0) :
sc_core::sc_module(name),
socket("socket"),
mNrOfTransactions(nrOfTransactions),
mBaseAddress(baseAddress),
mTransactionCount(0)
{
// Initiator thread
SC_THREAD(run);
}
bool initTransaction(transaction_type& trans)
{
if (mTransactionCount < mNrOfTransactions) {
trans.set_address(mBaseAddress + 4*mTransactionCount);
mData = mTransactionCount;
trans.set_command(tlm::TLM_WRITE_COMMAND);
} else if (mTransactionCount < 2 * mNrOfTransactions) {
trans.set_address(mBaseAddress + 4*(mTransactionCount-mNrOfTransactions));
mData = 0;
trans.set_command(tlm::TLM_READ_COMMAND);
} else {
return false;
}
trans.set_data_ptr(reinterpret_cast<unsigned char*>(&mData));
trans.set_data_length(4);
trans.set_streaming_width(4);
trans.set_dmi_allowed(false);
trans.set_response_status(tlm::TLM_INCOMPLETE_RESPONSE);
++mTransactionCount;
return true;
}
void logStartTransation(transaction_type& trans)
{
if (trans.get_command() == tlm::TLM_WRITE_COMMAND) {
std::cout << name() << ": Send write request: A = 0x"
<< std::hex << (unsigned int)trans.get_address()
<< ", D = 0x" << mData << std::dec
<< " @ " << sc_core::sc_time_stamp() << std::endl;
} else {
std::cout << name() << ": Send read request: A = 0x"
<< std::hex << (unsigned int)trans.get_address() << std::dec
<< " @ " << sc_core::sc_time_stamp() << std::endl;
}
}
void logEndTransaction(transaction_type& trans)
{
if (trans.get_response_status() != tlm::TLM_OK_RESPONSE) {
std::cout << name() << ": Received error response @ "
<< sc_core::sc_time_stamp() << std::endl;
} else {
std::cout << name() << ": Received ok response";
if (trans.get_command() == tlm::TLM_READ_COMMAND) {
std::cout << ": D = 0x" << std::hex << mData << std::dec;
}
std::cout << " @ " << sc_core::sc_time_stamp() << std::endl;
}
}
void run()
{
transaction_type trans;
sc_core::sc_time t;
while (initTransaction(trans)) {
// Create transaction and initialise t
t = sc_core::SC_ZERO_TIME;
logStartTransation(trans);
socket->b_transport(trans, t);
// Transaction Finished, wait for the returned delay
wait(t);
logEndTransaction(trans);
}
wait();
}
private:
sc_core::sc_event mEndEvent;
unsigned int mNrOfTransactions;
unsigned int mBaseAddress;
unsigned int mTransactionCount;
unsigned int mData;
};
#endif

View File

@@ -0,0 +1,244 @@
/*****************************************************************************
Licensed to Accellera Systems Initiative Inc. (Accellera) under one or
more contributor license agreements. See the NOTICE file distributed
with this work for additional information regarding copyright ownership.
Accellera licenses this file to you under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with the
License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied. See the License for the specific language governing
permissions and limitations under the License.
*****************************************************************************/
//====================================================================
// Nov 06, 2008
//
// Updated by:
// Xiaopeng Qiu, JEDA Technologies, Inc
// Email: qiuxp@jedatechnologies.net
//
// To fix violations of TLM2.0 rules, which are detected by JEDA
// TLM2.0 checker.
//
//====================================================================
#ifndef __SIMPLE_LT_INITIATOR3_DMI_H__
#define __SIMPLE_LT_INITIATOR3_DMI_H__
#include "tlm.h"
#include "tlm_utils/simple_initiator_socket.h"
#include <systemc>
#include <cassert>
#include <iostream>
#include <map>
class SimpleLTInitiator3_dmi : public sc_core::sc_module
{
public:
typedef tlm::tlm_generic_payload transaction_type;
typedef tlm::tlm_dmi dmi_type;
typedef tlm::tlm_phase phase_type;
typedef tlm::tlm_sync_enum sync_enum_type;
typedef tlm_utils::simple_initiator_socket<SimpleLTInitiator3_dmi> initiator_socket_type;
public:
initiator_socket_type socket;
public:
SC_HAS_PROCESS(SimpleLTInitiator3_dmi);
SimpleLTInitiator3_dmi(sc_core::sc_module_name name,
unsigned int nrOfTransactions = 0x5,
unsigned int baseAddress = 0x0) :
sc_core::sc_module(name),
socket("socket"),
mNrOfTransactions(nrOfTransactions),
mBaseAddress(baseAddress),
mTransactionCount(0)
{
mDMIDataReads.first.set_start_address(1);
mDMIDataReads.first.set_end_address(0);
mDMIDataWrites.first.set_start_address(1);
mDMIDataWrites.first.set_end_address(0);
socket.register_invalidate_direct_mem_ptr(this, &SimpleLTInitiator3_dmi::invalidate_direct_mem_ptr);
// Initiator thread
SC_THREAD(run);
}
bool initTransaction(transaction_type& trans)
{
if (mTransactionCount < mNrOfTransactions) {
trans.set_address(mBaseAddress + 4*mTransactionCount);
mData = mTransactionCount;
trans.set_command(tlm::TLM_WRITE_COMMAND);
} else if (mTransactionCount < 2 * mNrOfTransactions) {
trans.set_address(mBaseAddress + 4*(mTransactionCount-mNrOfTransactions));
mData = 0;
trans.set_command(tlm::TLM_READ_COMMAND);
} else {
return false;
}
trans.set_data_ptr(reinterpret_cast<unsigned char*>(&mData));
trans.set_data_length(4);
trans.set_streaming_width(4);
trans.set_dmi_allowed(false);
trans.set_response_status(tlm::TLM_INCOMPLETE_RESPONSE);
++mTransactionCount;
return true;
}
void logStartTransation(transaction_type& trans)
{
if (trans.get_command() == tlm::TLM_WRITE_COMMAND) {
std::cout << name() << ": Send write request: A = 0x"
<< std::hex << (unsigned int)trans.get_address()
<< ", D = 0x" << mData << std::dec
<< " @ " << sc_core::sc_time_stamp() << std::endl;
} else {
std::cout << name() << ": Send read request: A = 0x"
<< std::hex << (unsigned int)trans.get_address() << std::dec
<< " @ " << sc_core::sc_time_stamp() << std::endl;
}
}
void logEndTransaction(transaction_type& trans)
{
if (trans.get_response_status() != tlm::TLM_OK_RESPONSE) {
std::cout << name() << ": Received error response @ "
<< sc_core::sc_time_stamp() << std::endl;
} else {
std::cout << name() << ": Received ok response";
if (trans.get_command() == tlm::TLM_READ_COMMAND) {
std::cout << ": D = 0x" << std::hex << mData << std::dec;
}
std::cout << " @ " << sc_core::sc_time_stamp() << std::endl;
}
}
std::pair<dmi_type, bool>& getDMIData(const transaction_type& trans)
{
if (trans.get_command() == tlm::TLM_READ_COMMAND) {
return mDMIDataReads;
} else { // WRITE
return mDMIDataWrites;
}
}
void run()
{
transaction_type trans;
sc_core::sc_time t;
while (initTransaction(trans)) {
// Create transaction and initialise t
t = sc_core::SC_ZERO_TIME;
logStartTransation(trans);
///////////////////////////////////////////////////////////
// DMI handling:
// We do *not* use the DMI hint to check if it makes sense to ask for
// DMI pointers. So the pattern is:
// - if the address is not covered by a DMI region try to acquire DMI
// pointers
// - if we have a DMI pointer, do the DMI "transaction"
// - otherwise fall back to a normal transaction
///////////////////////////////////////////////////////////
std::pair<dmi_type, bool>& dmi_data = getDMIData(trans);
// Check if we need to acquire a DMI pointer
if((trans.get_address() < dmi_data.first.get_start_address()) ||
(trans.get_address() > dmi_data.first.get_end_address()) )
{
sc_dt::uint64 address = trans.get_address(); //save original address
dmi_data.second =
socket->get_direct_mem_ptr(trans,
dmi_data.first);
trans.set_address(address);
}
// Do DMI "transaction" if we have a valid region
if (dmi_data.second &&
(trans.get_address() >= dmi_data.first.get_start_address()) &&
(trans.get_address() <= dmi_data.first.get_end_address()) )
{
// We can handle the data here. As the logEndTransaction is assuming
// something to happen in the data structure, we really need to
// do this:
trans.set_response_status(tlm::TLM_OK_RESPONSE);
sc_dt::uint64 tmp = trans.get_address() - dmi_data.first.get_start_address();
if (trans.get_command() == tlm::TLM_WRITE_COMMAND)
{
*(unsigned int*)&dmi_data.first.get_dmi_ptr()[tmp] = mData;
}
else
{
mData = *(unsigned int*)&dmi_data.first.get_dmi_ptr()[tmp];
}
// Do the wait immediately. Note that doing the wait here eats almost
// all the performance anyway, so we only gain something if we're
// using temporal decoupling.
if (trans.get_command() == tlm::TLM_WRITE_COMMAND) {
wait(dmi_data.first.get_write_latency());
} else {
wait(dmi_data.first.get_read_latency());
}
}
else // we need a full transaction
{
socket->b_transport(trans, t);
// wait for the returned delay
wait(t);
}
logEndTransaction(trans);
}
wait();
}
// Invalidate DMI pointer(s)
void invalidate_direct_mem_ptr(sc_dt::uint64 start_range,
sc_dt::uint64 end_range)
{
// FIXME: probably faster to always invalidate everything?
if (start_range <= mDMIDataReads.first.get_end_address ()&&
end_range >= mDMIDataReads.first.get_start_address()) {
mDMIDataReads.second = false;
}
if (start_range <= mDMIDataWrites.first.get_end_address ()&&
end_range >= mDMIDataWrites.first.get_start_address()) {
mDMIDataWrites.second = false;
}
}
private:
std::pair<dmi_type, bool> mDMIDataReads;
std::pair<dmi_type, bool> mDMIDataWrites;
sc_core::sc_event mEndEvent;
unsigned int mNrOfTransactions;
unsigned int mBaseAddress;
unsigned int mTransactionCount;
unsigned int mData;
};
#endif

View File

@@ -0,0 +1,158 @@
/*****************************************************************************
Licensed to Accellera Systems Initiative Inc. (Accellera) under one or
more contributor license agreements. See the NOTICE file distributed
with this work for additional information regarding copyright ownership.
Accellera licenses this file to you under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with the
License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied. See the License for the specific language governing
permissions and limitations under the License.
*****************************************************************************/
#ifndef __SIMPLE_LT_TARGET1_H__
#define __SIMPLE_LT_TARGET1_H__
#include "tlm.h"
#include <cassert>
#include <vector>
class SimpleLTTarget1 :
public sc_core::sc_module,
public virtual tlm::tlm_fw_transport_if<>
{
public:
typedef tlm::tlm_generic_payload transaction_type;
typedef tlm::tlm_phase phase_type;
typedef tlm::tlm_sync_enum sync_enum_type;
typedef tlm::tlm_fw_transport_if<> fw_interface_type;
typedef tlm::tlm_bw_transport_if<> bw_interface_type;
typedef tlm::tlm_target_socket<32> target_socket_type;
public:
target_socket_type socket;
public:
SC_HAS_PROCESS(SimpleLTTarget1);
SimpleLTTarget1(sc_core::sc_module_name name, bool invalidate = false) :
sc_core::sc_module(name),
socket("socket"),
m_invalidate(invalidate)
{
// Bind this target's interface to the target socket
socket(*this);
if (invalidate)
{
SC_METHOD(invalidate_dmi_method);
sensitive << m_invalidate_dmi_event;
dont_initialize();
m_invalidate_dmi_time = sc_core::sc_time(25, sc_core::SC_NS);
}
}
sync_enum_type nb_transport_fw(transaction_type& trans, phase_type& phase, sc_core::sc_time& t)
{
//Target never calls wait, so we can do this
b_transport(trans, t);
return tlm::TLM_COMPLETED;
}
void b_transport(transaction_type& trans, sc_core::sc_time &t)
{
sc_dt::uint64 address = trans.get_address();
assert(address < 400);
unsigned int& data = *reinterpret_cast<unsigned int*>(trans.get_data_ptr());
if (trans.get_command() == tlm::TLM_WRITE_COMMAND) {
std::cout << name() << ": Received write request: A = 0x"
<< std::hex << (unsigned int)address
<< ", D = 0x" << data << std::dec
<< " @ " << sc_core::sc_time_stamp() << std::endl;
*reinterpret_cast<unsigned int*>(&mMem[address]) = data;
t+= sc_core::sc_time(10, sc_core::SC_NS);
} else {
std::cout << name() << ": Received read request: A = 0x"
<< std::hex << (unsigned int)address << std::dec
<< " @ " << sc_core::sc_time_stamp() << std::endl;
data = *reinterpret_cast<unsigned int*>(&mMem[address]);
t += sc_core::sc_time(100, sc_core::SC_NS);
}
trans.set_response_status(tlm::TLM_OK_RESPONSE);
trans.set_dmi_allowed(true);
}
unsigned int transport_dbg(transaction_type& r)
{
if (r.get_address() >= 400) return 0;
unsigned int tmp = (int)r.get_address();
unsigned int num_bytes;
if (tmp + r.get_data_length() >= 400) {
num_bytes = 400 - tmp;
} else {
num_bytes = r.get_data_length();
}
if (r.is_read()) {
for (unsigned int i = 0; i < num_bytes; ++i) {
r.get_data_ptr()[i] = mMem[i + tmp];
}
} else {
for (unsigned int i = 0; i < num_bytes; ++i) {
mMem[i + tmp] = r.get_data_ptr()[i];
}
}
return num_bytes;
}
bool get_direct_mem_ptr(transaction_type& trans,
tlm::tlm_dmi& dmi_data)
{
sc_dt::uint64 address = trans.get_address();
if (m_invalidate) m_invalidate_dmi_event.notify(m_invalidate_dmi_time);
if (address < 400) {
dmi_data.allow_read_write();
dmi_data.set_start_address(0x0);
dmi_data.set_end_address(399);
dmi_data.set_dmi_ptr(mMem);
dmi_data.set_read_latency(sc_core::sc_time(100, sc_core::SC_NS));
dmi_data.set_write_latency(sc_core::sc_time(10, sc_core::SC_NS));
return true;
} else {
// should not happen
dmi_data.set_start_address(trans.get_address());
dmi_data.set_end_address(trans.get_address());
return false;
}
}
void invalidate_dmi_method()
{
sc_dt::uint64 start_address = 0x0;
sc_dt::uint64 end_address = 399;
socket->invalidate_direct_mem_ptr(start_address, end_address);
}
private:
unsigned char mMem[400];
bool m_invalidate;
sc_core::sc_event m_invalidate_dmi_event;
sc_core::sc_time m_invalidate_dmi_time;
};
#endif

View File

@@ -0,0 +1,149 @@
/*****************************************************************************
Licensed to Accellera Systems Initiative Inc. (Accellera) under one or
more contributor license agreements. See the NOTICE file distributed
with this work for additional information regarding copyright ownership.
Accellera licenses this file to you under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with the
License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied. See the License for the specific language governing
permissions and limitations under the License.
*****************************************************************************/
#ifndef __SIMPLE_LT_TARGET2_H__
#define __SIMPLE_LT_TARGET2_H__
#include "tlm.h"
#include "tlm_utils/passthrough_target_socket.h"
#include <cassert>
#include <vector>
class SimpleLTTarget2 : public sc_core::sc_module
{
public:
typedef tlm::tlm_generic_payload transaction_type;
typedef tlm::tlm_phase phase_type;
typedef tlm::tlm_sync_enum sync_enum_type;
typedef tlm_utils::passthrough_target_socket<SimpleLTTarget2> target_socket_type;
public:
target_socket_type socket;
public:
SimpleLTTarget2(sc_core::sc_module_name name) :
sc_core::sc_module(name),
socket("socket")
{
// register nb_transport method
socket.register_b_transport(this, &SimpleLTTarget2::myBTransport);
socket.register_nb_transport_fw(this, &SimpleLTTarget2::myNBTransport);
socket.register_get_direct_mem_ptr(this, &SimpleLTTarget2::myGetDMIPtr);
// TODO: we don't register the transport_dbg callback here, so we
// can test if something bad happens
// REGISTER_DEBUGTRANSPORT(socket, transport_dbg, 0);
}
void myBTransport(transaction_type& trans,
sc_core::sc_time& t)
{
sc_dt::uint64 address = trans.get_address();
assert(address < 400);
unsigned int& data = *reinterpret_cast<unsigned int*>(trans.get_data_ptr());
if (trans.get_command() == tlm::TLM_WRITE_COMMAND) {
std::cout << name() << ": Received write request: A = 0x"
<< std::hex << (unsigned int)address
<< ", D = 0x" << data << std::dec
<< " @ " << sc_core::sc_time_stamp() << std::endl;
*reinterpret_cast<unsigned int*>(&mMem[address]) = data;
t += sc_core::sc_time(10, sc_core::SC_NS);
} else {
std::cout << name() << ": Received read request: A = 0x"
<< std::hex << (unsigned int)address << std::dec
<< " @ " << sc_core::sc_time_stamp() << std::endl;
data = *reinterpret_cast<unsigned int*>(&mMem[address]);
t += sc_core::sc_time(100, sc_core::SC_NS);
}
trans.set_response_status(tlm::TLM_OK_RESPONSE);
trans.set_dmi_allowed(true);
}
sync_enum_type myNBTransport(transaction_type& trans,
phase_type& phase,
sc_core::sc_time& t)
{
assert(phase == tlm::BEGIN_REQ);
// Never blocks, so call b_transport implementation
myBTransport(trans, t);
// LT target
// - always return TLM_COMPLETED
// - not necessary to update phase (if TLM_COMPLETED is returned)
return tlm::TLM_COMPLETED;
}
unsigned int transport_dbg(transaction_type& r)
{
if (r.get_address() >= 400) return 0;
unsigned int tmp = (int)r.get_address();
unsigned int num_bytes;
if (tmp + r.get_data_length() >= 400) {
num_bytes = 400 - tmp;
} else {
num_bytes = r.get_data_length();
}
if (r.is_read()) {
for (unsigned int i = 0; i < num_bytes; ++i) {
r.get_data_ptr()[i] = mMem[i + tmp];
}
} else {
for (unsigned int i = 0; i < num_bytes; ++i) {
mMem[i + tmp] = r.get_data_ptr()[i];
}
}
return num_bytes;
}
bool myGetDMIPtr(transaction_type& trans,
tlm::tlm_dmi& dmi_data)
{
sc_dt::uint64 address = trans.get_address();
if (address < 400) {
dmi_data.allow_read_write();
dmi_data.set_start_address(0x0);
dmi_data.set_end_address(399);
dmi_data.set_dmi_ptr(mMem);
dmi_data.set_read_latency(sc_core::sc_time(100, sc_core::SC_NS));
dmi_data.set_write_latency(sc_core::sc_time(10, sc_core::SC_NS));
return true;
} else {
// should not happen
dmi_data.set_start_address(address);
dmi_data.set_end_address(address);
return false;
}
}
private:
unsigned char mMem[400];
};
#endif

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff