Started from SystemC-Quickstart

This commit is contained in:
2018-11-30 11:08:08 +01:00
commit 262f093eb5
28 changed files with 1638 additions and 0 deletions

18
components/components.h Normal file
View File

@ -0,0 +1,18 @@
/*
* components.h
*
* Created on: 02.12.2018
* Author: eyck
*/
#ifndef COMPONENTS_H_
#define COMPONENTS_H_
//#include "tx_example_mods.h"
#include <systemc.h>
#include "logging.h"
#include "initiator.h"
#include "router.h"
#include "target.h"
#endif /* COMPONENTS_H_ */

136
components/initiator.cpp Normal file
View File

@ -0,0 +1,136 @@
/*
* initiator.cpp
*
* Created on: 02.12.2018
* Author: eyck
*/
#include "initiator.h"
#include "logging.h"
Initiator::Initiator(::sc_core::sc_module_name nm)
: socket("socket") // Construct and name socket
, dmi_ptr_valid(false)
{
// Register callbacks for incoming interface method calls
socket.register_invalidate_direct_mem_ptr(this, &Initiator::invalidate_direct_mem_ptr);
SC_THREAD(thread_process);
}
void Initiator::thread_process() {
{
// TLM-2 generic payload transaction, reused across calls to b_transport, DMI and debug
tlm::tlm_generic_payload* trans = new tlm::tlm_generic_payload;
sc_time delay = sc_time(10, SC_NS);
// Generate a random sequence of reads and writes
for (int i = 256-64; i < 256+64; i += 4)
{
int data;
tlm::tlm_command cmd = static_cast<tlm::tlm_command>(rand() % 2);
if (cmd == tlm::TLM_WRITE_COMMAND) data = 0xFF000000 | i;
// Use DMI if it is available
if (dmi_ptr_valid && sc_dt::uint64(i) >= dmi_data.get_start_address()
&& sc_dt::uint64(i) <= dmi_data.get_end_address())
{
// Bypass transport interface and use direct memory interface
// Implement target latency
if ( cmd == tlm::TLM_READ_COMMAND )
{
assert( dmi_data.is_read_allowed() );
memcpy(&data, dmi_data.get_dmi_ptr() + i - dmi_data.get_start_address(), 4);
wait( dmi_data.get_read_latency() );
}
else if ( cmd == tlm::TLM_WRITE_COMMAND )
{
assert( dmi_data.is_write_allowed() );
memcpy(dmi_data.get_dmi_ptr() + i - dmi_data.get_start_address(), &data, 4);
wait( dmi_data.get_write_latency() );
}
LOG_INFO << "DMI = { " << (cmd ? 'W' : 'R') << ", " << hex << i
<< " } , data = " << hex << data << " at time " << sc_time_stamp();
}
else
{
trans->set_command( cmd );
trans->set_address( i );
trans->set_data_ptr( reinterpret_cast<unsigned char*>(&data) );
trans->set_data_length( 4 );
trans->set_streaming_width( 4 ); // = data_length to indicate no streaming
trans->set_byte_enable_ptr( 0 ); // 0 indicates unused
trans->set_dmi_allowed( false ); // Mandatory initial value
trans->set_response_status( tlm::TLM_INCOMPLETE_RESPONSE ); // Mandatory initial value
#ifdef INJECT_ERROR
if (i > 90) trans->set_streaming_width(2);
#endif
// Other fields default: byte enable = 0, streaming width = 0, DMI_hint = false, no extensions
socket->b_transport( *trans, delay ); // Blocking transport call
// Initiator obliged to check response status
if ( trans->is_response_error() )
{
// Print response string
char txt[100];
sprintf(txt, "Error from b_transport, response status = %s",
trans->get_response_string().c_str());
SC_REPORT_ERROR("TLM-2", txt);
}
// Check DMI hint
if ( trans->is_dmi_allowed() )
{
// *********************************************
// Re-use transaction object for DMI. Reset the address because it could
// have been modified by the interconnect on the previous transport call
// *********************************************
trans->set_address( i );
dmi_ptr_valid = socket->get_direct_mem_ptr( *trans, dmi_data );
}
LOG_INFO << "trans = { " << (cmd ? 'W' : 'R') << ", " << hex << i
<< " } , data = " << hex << data << " at time " << sc_time_stamp();
}
}
// Use debug transaction interface to dump memory contents, reusing same transaction object
sc_dt::uint64 A = 128;
trans->set_address(A);
trans->set_read();
trans->set_data_length(256);
unsigned char* data = new unsigned char[256];
trans->set_data_ptr(data);
unsigned int n_bytes = socket->transport_dbg( *trans );
for (unsigned int i = 0; i < n_bytes; i += 4)
{
LOG_INFO << "mem[" << (A + i) << "] = "
<< *(reinterpret_cast<unsigned int*>( &data[i] ));
}
A = 256;
trans->set_address(A);
trans->set_data_length(128);
n_bytes = socket->transport_dbg( *trans );
for (unsigned int i = 0; i < n_bytes; i += 4)
{
LOG_INFO << "mem[" << (A + i) << "] = "
<< *(reinterpret_cast<unsigned int*>( &data[i] ));
}
}
}

36
components/initiator.h Normal file
View File

@ -0,0 +1,36 @@
#ifndef INITIATOR_H
#define INITIATOR_H
#include "systemc"
using namespace sc_core;
using namespace sc_dt;
using namespace std;
#include "tlm.h"
#include "tlm_utils/simple_initiator_socket.h"
// Initiator module generating generic payload transactions
struct Initiator: sc_module
{
// TLM-2 socket, defaults to 32-bits wide, base protocol
tlm_utils::simple_initiator_socket<Initiator> socket;
SC_HAS_PROCESS(Initiator);
Initiator( ::sc_core::sc_module_name );
void thread_process();
// TLM-2 backward DMI method
void invalidate_direct_mem_ptr(sc_dt::uint64 start_range, sc_dt::uint64 end_range){
// Ignore range and invalidate all DMI pointers regardless
dmi_ptr_valid = false;
}
bool dmi_ptr_valid;
tlm::tlm_dmi dmi_data;
};
#endif

115
components/logging.cpp Normal file
View File

@ -0,0 +1,115 @@
/*
* logging.cpp
*
* Created on: 24.12.2018
* Author: eyck
*/
#include "logging.h"
#include <systemc>
#include <deque>
#include <array>
#include <sstream>
#include <iomanip>
using namespace sc_core;
enum log_level {NONE, FATAL, ERROR, WARNING, INFO, DEBUG, TRACE};
namespace {
static std::deque<std::string> msg_buf;
inline log_level verbosity2log(int verb) {
if (verb >= sc_core::SC_FULL) return TRACE;
if (verb >= sc_core::SC_HIGH) return DEBUG;
return INFO;
}
std::string time2string(const sc_core::sc_time &t) {
const std::array<const char *, 6> time_units{"fs", "ps", "ns", "us", "ms", "s "};
const std::array<uint64_t, 6> multiplier{1ULL,
1000ULL,
1000ULL * 1000,
1000ULL * 1000 * 1000,
1000ULL * 1000 * 1000 * 1000,
1000ULL * 1000 * 1000 * 1000 * 1000};
std::ostringstream oss;
const sc_core::sc_time_tuple tt{t};
const auto val = tt.value();
if (!val) {
oss << "0 s";
} else {
const unsigned scale = tt.unit();
const auto fs_val = val * multiplier[scale];
for (int j = multiplier.size() - 1; j >= scale; --j) {
if (fs_val > multiplier[j]) {
const auto i = val / multiplier[j - scale];
const auto f = val % multiplier[j - scale];
oss << i << '.' << std::setw(3 * (j - scale)) << std::setfill('0') << std::left << f << ' '
<< time_units[j];
break;
}
}
}
return oss.str();
}
const std::string compose_message(const sc_report &rep) {
std::stringstream os;
os << "[" << std::setw(20) << time2string(sc_core::sc_time_stamp()) << "] ";
if (rep.get_id() >= 0)
os << "("
<< "IWEF"[rep.get_severity()] << rep.get_id() << ") ";
os << rep.get_msg_type();
if (*rep.get_msg()) os << ": " << rep.get_msg();
if (rep.get_severity() > SC_INFO) {
std::array<char, 16> line_number_str;
os << " [FILE:" << rep.get_file_name() << ":" << rep.get_line_number() << "]";
sc_simcontext *simc = sc_get_curr_simcontext();
if (simc && sc_is_running()) {
const char *proc_name = rep.get_process_name();
if (proc_name) os << "[PROCESS:" << proc_name << "]";
}
}
return os.str();
}
void report_handler(const sc_report &rep, const sc_actions &actions) {
std::array<const log_level, 4> map = {{INFO, WARNING, ERROR, FATAL}};
if (actions & SC_DISPLAY) {
auto level = rep.get_severity() > sc_core::SC_INFO ? map[rep.get_severity()] : verbosity2log(rep.get_verbosity());
msg_buf.push_back(compose_message(rep));
}
if (actions & SC_STOP) sc_stop();
if (actions & SC_ABORT) abort();
if (actions & SC_THROW) throw rep;
}
}
bool has_output(){
return !msg_buf.empty();
}
std::string get_output(){
std::string ret = msg_buf.front();
msg_buf.pop_front();
return ret;
}
void init_logging(unsigned level) {
const std::array<int, 8> verbosity = {SC_NONE, // Logging::NONE
SC_LOW, // Logging::FATAL
SC_LOW, // Logging::ERROR
SC_LOW, // Logging::WARNING
SC_MEDIUM, // Logging::INFO
SC_HIGH, // logging::DEBUG
SC_FULL, // logging::TRACE
SC_DEBUG}; // logging::TRACE+1
sc_report_handler::set_verbosity_level(verbosity[level]);
sc_report_handler::set_handler(report_handler);
}

42
components/logging.h Normal file
View File

@ -0,0 +1,42 @@
/*
* logging.h
*
* Created on: 24.12.2018
* Author: eyck
*/
#ifndef LOGGING_H_
#define LOGGING_H_
#include <string>
#include <sstream>
#include <systemc.h>
bool has_output();
std::string get_output();
void init_logging(unsigned level);
class Log {
public:
Log(const char* file, int line):messageLevel(sc_core::SC_INFO), file(file), line(line){};
Log(const Log&) = delete;
Log& operator =(const Log&) = delete;
virtual ~Log(){
::sc_core::sc_report_handler::report(messageLevel, "", os.str().c_str(), file, line );
}
std::ostringstream& Get(sc_core::sc_severity level = sc_core::SC_INFO){
messageLevel = level;
return os;
}
protected:
std::ostringstream os;
sc_core::sc_severity messageLevel;
const char* file;
int line;
};
#define LOG(level) Log(__FILE__, __LINE__).Get(level)
#define LOG_INFO Log(__FILE__, __LINE__).Get(sc_core::SC_INFO)
#define LOG_WARN Log(__FILE__, __LINE__).Get(sc_core::SC_WARNING)
#define LOG_ERR Log(__FILE__, __LINE__).Get(sc_core::SC_ERROR)
#endif /* LOGGING_H_ */

133
components/router.h Normal file
View File

@ -0,0 +1,133 @@
#ifndef ROUTER_H
#define ROUTER_H
#include "systemc"
using namespace sc_core;
using namespace sc_dt;
using namespace std;
#include "tlm.h"
#include "tlm_utils/simple_initiator_socket.h"
#include "tlm_utils/simple_target_socket.h"
// *********************************************
// Generic payload blocking transport router
// *********************************************
template<unsigned int N_TARGETS>
struct Router: sc_module
{
// TLM-2 socket, defaults to 32-bits wide, base protocol
tlm_utils::simple_target_socket<Router> target_socket;
// *********************************************
// Use tagged sockets to be able to distinguish incoming backward path calls
// *********************************************
sc_core::sc_vector<tlm_utils::simple_initiator_socket_tagged<Router>> initiator_socket;
SC_CTOR(Router)
: target_socket("target_socket")
, initiator_socket("socket", N_TARGETS)
{
// Register callbacks for incoming interface method calls
target_socket.register_b_transport( this, &Router::b_transport);
target_socket.register_get_direct_mem_ptr(this, &Router::get_direct_mem_ptr);
target_socket.register_transport_dbg( this, &Router::transport_dbg);
for (unsigned int i = 0; i < N_TARGETS; i++)
{
char txt[20];
sprintf(txt, "socket_%d", i);
// *********************************************
// Register callbacks for incoming interface method calls, including tags
// *********************************************
initiator_socket[i].register_invalidate_direct_mem_ptr(this, &Router::invalidate_direct_mem_ptr, i);
}
}
// ****************
// FORWARD PATH
// ****************
// TLM-2 blocking transport method
virtual void b_transport( tlm::tlm_generic_payload& trans, sc_time& delay )
{
sc_dt::uint64 address = trans.get_address();
sc_dt::uint64 masked_address;
unsigned int target_nr = decode_address( address, masked_address);
// Modify address within transaction
trans.set_address( masked_address );
// Forward transaction to appropriate target
initiator_socket[target_nr]->b_transport( trans, delay );
}
// TLM-2 forward DMI method
virtual bool get_direct_mem_ptr(tlm::tlm_generic_payload& trans,
tlm::tlm_dmi& dmi_data)
{
sc_dt::uint64 masked_address;
unsigned int target_nr = decode_address( trans.get_address(), masked_address );
trans.set_address( masked_address );
bool status = initiator_socket[target_nr]->get_direct_mem_ptr( trans, dmi_data );
// Calculate DMI address of target in system address space
dmi_data.set_start_address( compose_address( target_nr, dmi_data.get_start_address() ));
dmi_data.set_end_address ( compose_address( target_nr, dmi_data.get_end_address() ));
return status;
}
// TLM-2 debug transaction method
virtual unsigned int transport_dbg(tlm::tlm_generic_payload& trans)
{
sc_dt::uint64 masked_address;
unsigned int target_nr = decode_address( trans.get_address(), masked_address );
trans.set_address( masked_address );
// Forward debug transaction to appropriate target
return initiator_socket[target_nr]->transport_dbg( trans );
}
// ****************
// BACKWARD PATH
// ****************
// **************************
// Tagged backward DMI method
// **************************
virtual void invalidate_direct_mem_ptr(int id,
sc_dt::uint64 start_range,
sc_dt::uint64 end_range)
{
// Reconstruct address range in system memory map
sc_dt::uint64 bw_start_range = compose_address( id, start_range );
sc_dt::uint64 bw_end_range = compose_address( id, end_range );
target_socket->invalidate_direct_mem_ptr(bw_start_range, bw_end_range);
}
// ****************
// ROUTER INTERNALS
// ****************
// Simple fixed address decoding
inline unsigned int decode_address( sc_dt::uint64 address, sc_dt::uint64& masked_address )
{
unsigned int target_nr = static_cast<unsigned int>( (address >> 8) & 0x3 );
masked_address = address & 0xFF;
return target_nr;
}
inline sc_dt::uint64 compose_address( unsigned int target_nr, sc_dt::uint64 address)
{
return (target_nr << 8) | (address & 0xFF);
}
};
#endif

View File

@ -0,0 +1,18 @@
/*
* router_example.cpp
*
* Created on: 02.12.2018
* Author: eyck
*/
#include "top.h"
int sc_main(int argc, char* argv[])
{
Top top("top");
sc_start();
return 0;
}

102
components/target.cpp Normal file
View File

@ -0,0 +1,102 @@
/*
* target.cpp
*
* Created on: 02.12.2018
* Author: eyck
*/
#include "target.h"
void Memory::b_transport(tlm::tlm_generic_payload& trans, sc_time& delay) {
tlm::tlm_command cmd = trans.get_command();
sc_dt::uint64 adr = trans.get_address() / 4;
unsigned char* ptr = trans.get_data_ptr();
unsigned int len = trans.get_data_length();
unsigned char* byt = trans.get_byte_enable_ptr();
unsigned int wid = trans.get_streaming_width();
// Obliged to check address range and check for unsupported features,
// i.e. byte enables, streaming, and bursts
// Can ignore extensions
// Generate the appropriate error response
if (adr >= SIZE) {
trans.set_response_status( tlm::TLM_ADDRESS_ERROR_RESPONSE );
return;
}
if (byt != 0) {
trans.set_response_status( tlm::TLM_BYTE_ENABLE_ERROR_RESPONSE );
return;
}
if (len > 4 || wid < len) {
trans.set_response_status( tlm::TLM_BURST_ERROR_RESPONSE );
return;
}
wait(delay);
delay = SC_ZERO_TIME;
// Obliged to implement read and write commands
if ( cmd == tlm::TLM_READ_COMMAND )
memcpy(ptr, &mem[adr], len);
else if ( cmd == tlm::TLM_WRITE_COMMAND )
memcpy(&mem[adr], ptr, len);
// Set DMI hint to indicated that DMI is supported
trans.set_dmi_allowed(true);
// Obliged to set response status to indicate successful completion
trans.set_response_status( tlm::TLM_OK_RESPONSE );
}
bool Memory::get_direct_mem_ptr(tlm::tlm_generic_payload& trans,
tlm::tlm_dmi& dmi_data)
{
// Permit read and write access
dmi_data.allow_read_write();
// Set other details of DMI region
dmi_data.set_dmi_ptr( reinterpret_cast<unsigned char*>( &mem[0] ) );
dmi_data.set_start_address( 0 );
dmi_data.set_end_address( SIZE*4-1 );
dmi_data.set_read_latency( LATENCY );
dmi_data.set_write_latency( LATENCY );
return true;
}
Memory::Memory(sc_core::sc_module_name nm)
: socket("socket"), LATENCY(10, SC_NS)
{
// Register callbacks for incoming interface method calls
socket.register_b_transport( this, &Memory::b_transport);
socket.register_get_direct_mem_ptr(this, &Memory::get_direct_mem_ptr);
socket.register_transport_dbg( this, &Memory::transport_dbg);
// Initialize memory with random data
for (int i = 0; i < SIZE; i++)
mem[i] = 0xAA000000 | (mem_nr << 20) | (rand() % 256);
++mem_nr;
}
// TLM-2 debug transaction method
unsigned int Memory::transport_dbg(tlm::tlm_generic_payload& trans)
{
tlm::tlm_command cmd = trans.get_command();
sc_dt::uint64 adr = trans.get_address() / 4;
unsigned char* ptr = trans.get_data_ptr();
unsigned int len = trans.get_data_length();
// Calculate the number of bytes to be actually copied
unsigned int num_bytes = (len < (SIZE - adr) * 4) ? len : (SIZE - adr) * 4;
if ( cmd == tlm::TLM_READ_COMMAND )
memcpy(ptr, &mem[adr], num_bytes);
else if ( cmd == tlm::TLM_WRITE_COMMAND )
memcpy(&mem[adr], ptr, num_bytes);
return num_bytes;
}

46
components/target.h Normal file
View File

@ -0,0 +1,46 @@
#ifndef TARGET_H
#define TARGET_H
// Needed for the simple_target_socket
#define SC_INCLUDE_DYNAMIC_PROCESSES
#include "systemc"
using namespace sc_core;
using namespace sc_dt;
using namespace std;
#include "tlm.h"
#include "tlm_utils/simple_target_socket.h"
// Target module representing a simple memory
struct Memory: sc_module
{
// TLM-2 socket, defaults to 32-bits wide, base protocol
tlm_utils::simple_target_socket<Memory> socket;
enum { SIZE = 256 };
const sc_time LATENCY;
SC_HAS_PROCESS(Memory);
Memory(sc_core::sc_module_name nm);
protected:
// TLM-2 blocking transport method
void b_transport( tlm::tlm_generic_payload& trans, sc_time& delay );
// TLM-2 forward DMI method
bool get_direct_mem_ptr(tlm::tlm_generic_payload& trans,
tlm::tlm_dmi& dmi_data);
// TLM-2 debug transaction method
unsigned int transport_dbg(tlm::tlm_generic_payload& trans);
int mem[SIZE];
static unsigned int mem_nr;
};
unsigned int Memory::mem_nr = 0;
#endif

33
components/top.h Normal file
View File

@ -0,0 +1,33 @@
#ifndef TOP_H
#define TOP_H
#include "initiator.h"
#include "target.h"
#include "router.h"
SC_MODULE(Top)
{
Initiator* initiator;
Router<4>* router;
Memory* memory[4];
SC_CTOR(Top)
{
// Instantiate components
initiator = new Initiator("initiator");
router = new Router<4>("router");
for (int i = 0; i < 4; i++)
{
char txt[20];
sprintf(txt, "memory_%d", i);
memory[i] = new Memory(txt);
}
// Bind sockets
initiator->socket.bind( router->target_socket );
for (int i = 0; i < 4; i++)
router->initiator_socket[i].bind( memory[i]->socket );
}
};
#endif

44
components/tx_example.cpp Normal file
View File

@ -0,0 +1,44 @@
// -*- C++ -*- <this line is for emacs to recognize it as C++ code>
/*****************************************************************************
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.
*****************************************************************************/
// this code compiles and runs with our latest prototype for this specification
#include "txtop.h"
int sc_main (int argc , char *argv[])
{
scv_startup();
scv_tr_text_init();
scv_tr_db db("transaction_example.txlog");
scv_tr_db::set_default_db(&db);
tx_top top("top");
// Accellera SystemC >=2.2 got picky about multiple drivers.
// Disable check for bus simulation.
sc_report_handler::set_actions(SC_ID_MORE_THAN_ONE_SIGNAL_DRIVER_, SC_DO_NOTHING);
// run the simulation
sc_start(1.0, SC_MS);
return 0;
}

View File

@ -0,0 +1,140 @@
// -*- C++ -*- <this line is for emacs to recognize it as C++ code>
/*****************************************************************************
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.
*****************************************************************************/
// this code compiles and runs with our latest prototype for this specification
#include "tx_example_mods.h"
rw_task_if::data_t rw_pipelined_transactor::read(const rw_task_if::addr_t*
addr) {
addr_phase.lock();
scv_tr_handle h = read_gen.begin_transaction(*addr);
scv_tr_handle h1 = addr_gen.begin_transaction(*addr,"addr_phase",h);
wait(clk->posedge_event());
bus_addr = *addr;
addr_req = 1;
wait(addr_ack->posedge_event());
wait(clk->negedge_event());
addr_req = 0;
wait(addr_ack->negedge_event());
addr_gen.end_transaction(h1);
addr_phase.unlock();
data_phase.lock();
scv_tr_handle h2 = data_gen.begin_transaction("data_phase",h);
wait(data_rdy->posedge_event());
data_t data = bus_data.read();
wait(data_rdy->negedge_event());
data_gen.end_transaction(h2);
read_gen.end_transaction(h,data);
data_phase.unlock();
return data;
}
void rw_pipelined_transactor::write(const write_t * req) {
scv_tr_handle h = write_gen.begin_transaction(req->addr);
// ...
write_gen.end_transaction(h,req->data);
}
void test::main() {
// simple sequential tests
for (int i=0; i<3; i++) {
rw_task_if::addr_t addr = i;
rw_task_if::data_t data = transactor->read(&addr);
cout << "at time " << sc_time_stamp() << ": ";
cout << "received data : " << data << endl;
}
scv_smart_ptr<rw_task_if::addr_t> addr;
for (int i=0; i<3; i++) {
addr->next();
rw_task_if::data_t data = transactor->read( addr->get_instance() );
cout << "data for address " << *addr << " is " << data << endl;
}
scv_smart_ptr<rw_task_if::write_t> write;
for (int i=0; i<3; i++) {
write->next();
transactor->write( write->get_instance() );
cout << "send data : " << write->data << endl;
}
scv_smart_ptr<int> data;
scv_bag<int> distribution;
distribution.push(1,40);
distribution.push(2,60);
data->set_mode(distribution);
for (int i=0;i<3; i++) { data->next(); process(data); }
}
void design::addr_phase() {
while (1) {
while (addr_req.read() != 1) {
wait(addr_req->value_changed_event());
}
sc_uint<8> _addr = bus_addr.read();
bool _rw = rw.read();
int cycle = rand() % 10 + 1;
while (cycle-- > 0) {
wait(clk->posedge_event());
}
addr_ack = 1;
wait(clk->posedge_event());
addr_ack = 0;
outstandingAddresses.push_back(_addr);
outstandingType.push_back(_rw);
cout << "at time " << sc_time_stamp() << ": ";
cout << "received request for memory address " << _addr << endl;
}
}
void design::data_phase() {
while (1) {
while (outstandingAddresses.empty()) {
wait(clk->posedge_event());
}
int cycle = rand() % 10 + 1;
while (cycle-- > 0) {
wait(clk->posedge_event());
}
if (outstandingType.front() == 0) {
cout << "reading memory address " << outstandingAddresses.front()
<< " with value " << memory[outstandingAddresses.front().to_ulong()] << endl;
bus_data = memory[outstandingAddresses.front().to_ulong()];
data_rdy = 1;
wait(clk->posedge_event());
data_rdy = 0;
} else {
cout << "not implemented yet" << endl;
}
outstandingAddresses.pop_front();
outstandingType.pop_front();
}
}

View File

@ -0,0 +1,136 @@
// -*- C++ -*- <this line is for emacs to recognize it as C++ code>
/*****************************************************************************
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.
*****************************************************************************/
// this code compiles and runs with our latest prototype for this specification
#include <scv.h>
#include <systemc.h>
// hack to fake a true fifo_mutex
#define fifo_mutex sc_mutex
const unsigned ram_size = 256;
class rw_task_if : virtual public sc_interface {
public:
typedef sc_uint<8> addr_t;
typedef sc_uint<8> data_t;
struct write_t {
addr_t addr;
data_t data;
};
virtual data_t read(const addr_t*) = 0;
virtual void write(const write_t*) = 0;
};
SCV_EXTENSIONS(rw_task_if::write_t) {
public:
scv_extensions<rw_task_if::addr_t> addr;
scv_extensions<rw_task_if::data_t> data;
SCV_EXTENSIONS_CTOR(rw_task_if::write_t) {
SCV_FIELD(addr);
SCV_FIELD(data);
}
};
class pipelined_bus_ports : public sc_module {
public:
sc_in< bool > clk;
sc_inout< bool > rw;
sc_inout< bool > addr_req;
sc_inout< bool > addr_ack;
sc_inout< sc_uint<8> > bus_addr;
sc_inout< bool > data_rdy;
sc_inout< sc_uint<8> > bus_data;
SC_CTOR(pipelined_bus_ports)
: clk("clk"), rw("rw"),
addr_req("addr_req"),
addr_ack("addr_ack"), bus_addr("bus_addr"),
data_rdy("data_rdy"), bus_data("bus_data") {}
};
class rw_pipelined_transactor
: public rw_task_if,
public pipelined_bus_ports {
fifo_mutex addr_phase;
fifo_mutex data_phase;
scv_tr_stream pipelined_stream;
scv_tr_stream addr_stream;
scv_tr_stream data_stream;
scv_tr_generator<sc_uint<8>, sc_uint<8> > read_gen;
scv_tr_generator<sc_uint<8>, sc_uint<8> > write_gen;
scv_tr_generator<sc_uint<8> > addr_gen;
scv_tr_generator<sc_uint<8> > data_gen;
public:
rw_pipelined_transactor(sc_module_name nm) :
pipelined_bus_ports(nm),
addr_phase("addr_phase"),
data_phase("data_phase"),
pipelined_stream("pipelined_stream", "transactor"),
addr_stream("addr_stream", "transactor"),
data_stream("data_stream", "transactor"),
read_gen("read",pipelined_stream,"addr","data"),
write_gen("write",pipelined_stream,"addr","data"),
addr_gen("addr",addr_stream,"addr"),
data_gen("data",data_stream,"data")
{}
virtual data_t read(const addr_t* p_addr);
virtual void write(const write_t * req);
};
class test : public sc_module {
public:
sc_port< rw_task_if > transactor;
SC_CTOR(test) {
SC_THREAD(main);
}
void main();
};
class write_constraint : virtual public scv_constraint_base {
public:
scv_smart_ptr<rw_task_if::write_t> write;
SCV_CONSTRAINT_CTOR(write_constraint) {
SCV_CONSTRAINT( write->addr() <= ram_size );
SCV_CONSTRAINT( write->addr() != write->data() );
}
};
inline void process(scv_smart_ptr<int> data) {}
class design : public pipelined_bus_ports {
std::list< sc_uint<8> > outstandingAddresses;
std::list< bool > outstandingType;
sc_uint<8> memory[ram_size];
public:
SC_HAS_PROCESS(design);
design(sc_module_name nm) : pipelined_bus_ports(nm) {
for (unsigned i=0; i<ram_size; ++i) { memory[i] = i; }
SC_THREAD(addr_phase);
SC_THREAD(data_phase);
}
void addr_phase();
void data_phase();
};

49
components/txtop.cpp Normal file
View File

@ -0,0 +1,49 @@
/*
* top1.cpp
*
* Created on: 02.12.2018
* Author: eyck
*/
#include "txtop.h"
using namespace sc_core;
tx_top::tx_top(sc_core::sc_module_name nm)
: sc_module(nm)
, clk("clk", 20.0, SC_NS, 0.5 ,0.0, SC_NS, true)
, rw("rw")
, addr_req("addr_reg")
, addr_ack("addr_ack")
, bus_addr("bus_addr")
, data_rdy("data_rdy")
, bus_data("bus_data")
, t("t")
, tr("tr")
, duv("duv")
{
// TODO Auto-generated constructor stub
// connect them up
t.transactor(tr);
tr.clk(clk);
tr.rw(rw);
tr.addr_req(addr_req);
tr.addr_ack(addr_ack);
tr.bus_addr(bus_addr);
tr.data_rdy(data_rdy);
tr.bus_data(bus_data);
duv.clk(clk);
duv.rw(rw);
duv.addr_req(addr_req);
duv.addr_ack(addr_ack);
duv.bus_addr(bus_addr);
duv.data_rdy(data_rdy);
duv.bus_data(bus_data);
}
tx_top::~tx_top() {
// TODO Auto-generated destructor stub
}

31
components/txtop.h Normal file
View File

@ -0,0 +1,31 @@
/*
* top1.h
*
* Created on: 02.12.2018
* Author: eyck
*/
#ifndef TXTOP_H_
#define TXTOP_H_
#include "tx_example_mods.h"
#include <systemc>
class tx_top: public sc_core::sc_module {
public:
tx_top(sc_core::sc_module_name nm);
virtual ~tx_top();
sc_core::sc_clock clk;
sc_core::sc_signal< bool > rw;
sc_core::sc_signal< bool > addr_req;
sc_core::sc_signal< bool > addr_ack;
sc_core::sc_signal< sc_dt::sc_uint<8> > bus_addr;
sc_core::sc_signal< bool > data_rdy;
sc_core::sc_signal< sc_dt::sc_uint<8> > bus_data;
test t;
rw_pipelined_transactor tr;
design duv;
};
#endif /* TXTOP_H_ */