Browse Source

Updated documentation

pull/3/head
Eyck Jentzsch 1 year ago
parent
commit
6e0a8f8d25

+ 25
- 4
incl/scc/configurable_tracer.h View File

@@ -38,10 +38,13 @@
#include <cci_configuration>

namespace scc {

/**
*
*/
class configurable_tracer : public scc::tracer {
public:
/**
* constructs a tracer object
*
* @param name basename of the trace file(s)
* @param type type of trace file for transactions
@@ -49,24 +52,42 @@ public:
* @param default value of attribute enableTracing if not defined by module or CCIs
*/
configurable_tracer(const std::string&&, file_type, bool = true, bool = false);

/**
* constructs a tracer object
*
* @param name basename of the trace file(s)
* @param type type of trace file for transactions
* @param enable enable VCD (signal based) tracing
* @param default value of attribute enableTracing if not defined by module or CCIs
*/
configurable_tracer(const std::string& name, file_type type, bool enable_vcd = true, bool default_enable = false)
:configurable_tracer(std::string(name), type, enable_vcd, default_enable)
{}

/**
* destructor
*/
~configurable_tracer();

/**
* adds default trace control attribute of name 'enableTracing' to each sc_module in a design hierarchy
*/
void add_control() {
for (auto *o : sc_core::sc_get_top_level_objects(sc_core::sc_curr_simcontext)) augment_object_hierarchical(o);
}

protected:
//! the default for tracing if no attribute is configured
const bool default_trace_enable;
//! depth-first walk thru the design hierarchy and trace signals resp. call trace() function
void descend(const sc_core::sc_object *) override;
//! check for existence of 'enableTracing' attribute and return value of default otherwise
bool get_trace_enabled(const sc_core::sc_object *, bool = false);
//! add the 'enableTracing' attribute to sc_module
void augment_object_hierarchical(const sc_core::sc_object *);
//! the originator of cci values
cci::cci_originator cci_originator;
//! the cci broker
cci::cci_broker_handle cci_broker;
//! array of created cci parameter
std::vector<cci::cci_param_untyped *> params;
};


+ 64
- 19
incl/scc/configurer.h View File

@@ -13,12 +13,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*******************************************************************************/
/*
* configurer.h
*
* Created on: 27.09.2017
* Author: eyck
*/

#ifndef _SYSC_CONFIGURER_H_
#define _SYSC_CONFIGURER_H_
@@ -29,29 +23,71 @@
#include <json/json.h>

namespace scc {

/**
* a class to configure a design hierarchy using a JSON input file
*/
class configurer : public sc_core::sc_object {
public:
using base_type = sc_core::sc_object;

/**
* create a configurer using a JSON input file
* @param filename
*/
configurer(const std::string &filename);

/**
* no default constructor
*/
configurer() = delete;

/**
* no copy constructor
*
* @param
*/
configurer(const configurer &) = delete;

/**
* no move constructor
*
* @param
*/
configurer(configurer &&) = delete;

/**
* no copy assignment
*
* @param
* @return
*/
configurer &operator=(const configurer &) = delete;

/**
* no move assignment
*
* @param
* @return
*/
configurer &operator=(configurer &&) = delete;

/**
* configure the design hierarchy using the input file
*/
void configure();

/**
* dump the design hierarchy as text
*
* @param os the output stream, std::cout by default
* @param obj if not null specifies the root object of the dump
*/
void dump_hierarchy(std::ostream &os = std::cout, sc_core::sc_object *obj = nullptr);

/**
* dump the parameters of a design hierarchy to output stream
*
* @param os the output stream, std::cout by default
* @param obj if not null specifies the root object of the dump
*/
void dump_configuration(std::ostream &os = std::cout, sc_core::sc_object *obj = nullptr);

/**
* set a value a some attribute (sc_attribute or cci_param)
*
* @param hier_name the hierarchical name of the attribute
* @param value the value to put
*/
template <typename T> void set_value(const std::string &hier_name, T value) {
cci::cci_param_handle param_handle = cci_broker.get_param_handle(hier_name);
if (param_handle.is_valid()) {
@@ -70,9 +106,18 @@ public:
}
}
}

/**
* set a value of an sc_attribute from given configuration
*
* @param attr_base
* @param owner
*/
void set_configuration_value(sc_core::sc_attr_base *attr_base, sc_core::sc_object *owner);

/**
* find the configurer in the design hierarchy
*
* @return
*/
static configurer &instance() {
configurer *inst = dynamic_cast<configurer *>(sc_core::sc_find_object("configurer"));
sc_assert("No configurer instantiated when using it" && inst != nullptr);

+ 27
- 11
incl/scc/ext_attribute.h View File

@@ -13,12 +13,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*******************************************************************************/
/*
* atrribute_mixin.h
*
* Created on: 27.09.2017
* Author: eyck
*/

#ifndef _SCC_EXT_ATTRIBUTE_H_
#define _SCC_EXT_ATTRIBUTE_H_
@@ -27,28 +21,50 @@
#include "utilities.h"

namespace scc {
/**
* extended attribute inheriting from sc_attribute
*/
template <typename T> class ext_attribute : public sc_core::sc_attribute<T> {
public:
using base_type = sc_core::sc_attribute<T>;

/**
* create an extended attribute based on name and owner with default value
*
* @param name_
* @param owner
*/
ext_attribute(const std::string &name_, sc_core::sc_module *owner)
: base_type(name_)
, owner(owner) {
owner->add_attribute(*this);
configurer::instance().set_configuration_value(this, owner);
}

/**
* create an extended attribute based on name, value and owner
*
* @param name_
* @param value_
* @param owner
*/
ext_attribute(const std::string &name_, const T &value_, sc_core::sc_module *owner)
: base_type(name_, value_)
, owner(owner) {
owner->add_attribute(*this);
configurer::instance().set_configuration_value(this, owner);
}

/**
* no copy constructor
*
* @param a
*/
ext_attribute(const ext_attribute<T> &a) = delete;

/**
* a default destructor
*/
~ext_attribute() = default;

/**
* the owner of this attribute (a backward reference)
*/
const sc_core::sc_module *owner;
};
};

+ 17
- 10
incl/scc/initiator_mixin.h View File

@@ -23,7 +23,9 @@
#include <tlm>

namespace scc {

/**
* an initiator socket mixin adding default implementation of callback functions similar to tlm::simple_initiator_socket
*/
template <typename BASE_TYPE, typename TYPES = tlm::tlm_base_protocol_types> class initiator_mixin : public BASE_TYPE {
public:
using transaction_type = typename TYPES::tlm_payload_type;
@@ -33,26 +35,31 @@ public:
using bw_interface_type = tlm::tlm_bw_transport_if<TYPES>;

public:
/**
* the default constructor automatically generating a name
*/
initiator_mixin()
: BASE_TYPE(sc_core::sc_gen_unique_name("initiator_mixin_socket"))
, bw_if(this->name()) {
this->m_export.bind(bw_if);
}

explicit initiator_mixin(const char *n)
: BASE_TYPE(n)
: initiator_mixin(sc_core::sc_gen_unique_name("initiator_mixin_socket")) {}
/**
* constructor with explicit instance name
*
* @param name the instance name
*/
explicit initiator_mixin(const sc_core::sc_module_name &name)
: BASE_TYPE(name)
, bw_if(this->name()) {
this->m_export.bind(bw_if);
}
/**
* register a non-blocking backward path callback function
*
* @param cb the callback function
*/
void
register_nb_transport_bw(std::function<sync_enum_type(transaction_type &, phase_type &, sc_core::sc_time &)> cb) {
void register_nb_transport_bw(std::function<sync_enum_type(transaction_type &, phase_type &, sc_core::sc_time &)> cb) {
bw_if.set_transport_function(cb);
}
/**
* register an invalidate DMI callback function
*
* @param cb the callback function
*/

+ 14
- 9
incl/scc/memory.h View File

@@ -13,12 +13,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*******************************************************************************/
/*
* memory.h
*
* Created on: Nov 4, 2016
* Author: eyck
*/

#ifndef _SYSC_MEMORY_H_
#define _SYSC_MEMORY_H_
@@ -34,20 +28,31 @@

namespace scc {

// simple memory model
// TODO: add attributes/parameters to configure access time and type (DMI allowed, read only, etc)
/**
* simple memory model
*
* TODO: add some more attributes/parameters to configure access time and type (DMI allowed, read only, etc)
*/
template <unsigned long long SIZE, unsigned BUSWIDTH = 32, bool LOG_ACCESS = false>
class memory : public sc_core::sc_module {
public:
//! the target socket to connect to TLM
scc::target_mixin<tlm::tlm_target_socket<BUSWIDTH>> target;

/**
* constructor with explicit instance name
*
* @param nm
*/
memory(const sc_core::sc_module_name &nm);

protected:
//! the real memory structure
util::sparse_array<uint8_t, SIZE> mem;

private:
//!! handle the memory operation independent on interface function used
int handle_operation(tlm::tlm_generic_payload &trans);
//! handle the dmi functionality
bool handle_dmi(tlm::tlm_generic_payload &gp, tlm::tlm_dmi &dmi_data);
};


+ 15
- 2
incl/scc/perf_estimator.h View File

@@ -21,8 +21,13 @@
#include <systemc>

namespace scc {

/**
* a performance estimator
* it records the time stamps a various time points (start and end of simulation) and calculates
* some performance figures
*/
class perf_estimator : public sc_core::sc_module {
//! some internal data structure to record a time stamp
struct time_stamp {
boost::posix_time::ptime wall_clock_stamp;
double proc_clock_stamp;
@@ -44,14 +49,22 @@ class perf_estimator : public sc_core::sc_module {
};

public:
//! yes, we have some SystemC processes
SC_HAS_PROCESS(perf_estimator);// NOLINT
/**
* default constructor
*/
perf_estimator();
/**
* the destructor
*/
virtual ~perf_estimator();

protected:
//! SystemC callbacks
void start_of_simulation() override;
void end_of_simulation() override;
//! the recorded time stamps
time_stamp sos, eos;
};


+ 141
- 64
incl/scc/register.h View File

@@ -13,12 +13,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*******************************************************************************/
/*
* register.h
*
* Created on: Nov 16, 2016
* Author: developer
*/

#ifndef _SYSC_REGISTER_H_
#define _SYSC_REGISTER_H_
@@ -36,7 +30,9 @@
namespace scc {

namespace impl {

/**
* some template classes and functions to calculate mask values
*/
template <typename T, bool = std::is_integral<T>::value> class helper {};

template <typename T> class helper<T, true> {
@@ -59,18 +55,24 @@ template <typename Type> constexpr Type get_max_uval() {
return std::numeric_limits<Type>::is_signed ? -1 : std::numeric_limits<Type>::max();
}

/**
* a simple register implementation taking a certain data type. The sc_register does not hold the value itself,
* this needs to be provided. It only provides som resource access interface and handled callbacks for read and
* write accesses
*/
template <typename DATATYPE>
class sc_register : public sc_core::sc_object, public resource_access_if, public traceable {
public:
using this_type = class sc_register<DATATYPE>;
/**
* the constructor
*
* @param nm
* @param storage
* @param reset_val
* @param owner
* @param rdmask
* @param wrmask
* @param nm the instance name
* @param storage the storage data structure
* @param reset_val the reset value
* @param owner the owning object which needs to implement the resettable interface
* @param rdmask the SW read mask
* @param wrmask the SW write mask
*/
sc_register(sc_core::sc_module_name nm, DATATYPE &storage, const DATATYPE reset_val, resetable &owner,
DATATYPE rdmask = get_max_uval<DATATYPE>(), DATATYPE wrmask = get_max_uval<DATATYPE>())
@@ -81,7 +83,9 @@ public:
, storage(storage) {
owner.register_resource(this);
}

/**
* the destructor
*/
~sc_register() = default;

/**
@@ -90,7 +94,7 @@ public:
*/
size_t size() const override { return sizeof(DATATYPE); }
/**
*
* reset the register
*/
void reset() override {
DATATYPE r(res_val);
@@ -98,11 +102,13 @@ public:
storage = r;
}
/**
* write function from resource_access_if
*
* @param data
* @param length
* @param offset
* @return
* @param data data to write
* @param length size of data to write
* @param offset offset within register
* @param d annotated delay if loosly-timed access
* @return true if access is successful
*/
bool write(const uint8_t *data, size_t length, uint64_t offset, sc_core::sc_time d) override {
assert("Access out of range" && offset + length <= sizeof(DATATYPE));
@@ -114,11 +120,13 @@ public:
return true;
}
/**
* read function from resource_access_if
*
* @param data
* @param length
* @param offset
* @return
* @param data data buffer to read
* @param length size of data to read
* @param offset offset within register
* @param d annotated delay if loosly-timed access
* @return true if access is successful
*/
bool read(uint8_t *data, size_t length, uint64_t offset, sc_core::sc_time d) const override {
assert("Access out of range" && offset + length <= sizeof(DATATYPE));
@@ -132,11 +140,12 @@ public:
return true;
}
/**
* debug write function from resource_access_if
*
* @param data
* @param length
* @param offset
* @return
* @param data data to write
* @param length size of data to write
* @param offset offset within register
* @return true if access is successful
*/
bool write_dbg(const uint8_t *data, size_t length, uint64_t offset) override {
assert("Offset out of range" && offset == 0);
@@ -145,11 +154,12 @@ public:
return true;
}
/**
* debug read function from resource_access_if
*
* @param data
* @param length
* @param offset
* @return
* @param data data buffer to read
* @param length size of data to read
* @param offset offset within register
* @return true if access is successful
*/
bool read_dbg(uint8_t *data, size_t length, uint64_t offset) const override {
assert("Offset out of range" && offset == 0);
@@ -158,22 +168,25 @@ public:
return true;
}
/**
*
* cast operator
*/
operator DATATYPE() const { return storage; }
/**
* get the storage
*
* @return
* @return copy of the underlying datatype
*/
DATATYPE get() const { return storage; }
/**
* put value to storage
*
* @param o
* @param data the data to store
*/
void put(DATATYPE o) const { storage = o; }
void put(DATATYPE data) const { storage = data; }
/**
* copy assignment
*
* @param other
* @param other the data
* @return
*/
this_type &operator=(DATATYPE other) {
@@ -181,6 +194,7 @@ public:
return *this;
}
/**
* unary or
*
* @param other
* @return
@@ -190,6 +204,7 @@ public:
return *this;
}
/**
* unary and
*
* @param other
* @return
@@ -199,6 +214,8 @@ public:
return *this;
}
/**
* set the read callback triggered upon a read request without forwarding the annotated time
* this is primary for backward compatibility
*
* @param read_cb
*/
@@ -206,11 +223,14 @@ public:
rd_cb = [read_cb](const this_type &reg, DATATYPE &data, sc_core::sc_time delay) { return read_cb(reg, data); };
}
/**
* set the read callback triggered upon a read request
*
* @param read_cb
*/
void set_read_cb(std::function<bool(const this_type &, DATATYPE &, sc_core::sc_time)> read_cb) { rd_cb = read_cb; }
/**
* set the write callback triggered upon a write request without forwarding the annotated time
* this is primary for backward compatibility
*
* @param write_cb
*/
@@ -218,18 +238,22 @@ public:
wr_cb = [write_cb](this_type &reg, DATATYPE &data, sc_core::sc_time delay) { return write_cb(reg, data); };
}
/**
* set the write callback triggered upon a write request
*
* @param write_cb
*/
void set_write_cb(std::function<bool(this_type &, DATATYPE &, sc_core::sc_time)> write_cb) { wr_cb = write_cb; }
/**
* trace the register value to the given trace file
*
* @param trf
*/
void trace(sc_core::sc_trace_file *trf) const override { sc_trace(trf, storage, this->name()); }
//! the reset value
const DATATYPE res_val;
//! the SW read mask
const DATATYPE rdmask;
//! the SW write mask
const DATATYPE wrmask;

private:
@@ -241,9 +265,11 @@ private:
util::delegate<bool(this_type &, DATATYPE &, sc_core::sc_time)> wr_dlgt;
};
}
//! import the implementation into the scc namespace
template <typename DATATYPE> using sc_register = impl::sc_register<typename impl::helper<DATATYPE>::Type>;

/**
* an indexed register aka a register file of a certain type
*/
template <typename DATATYPE, size_t SIZE, size_t START = 0>
class sc_register_indexed : public indexed_resource_access_if {
public:
@@ -251,7 +277,16 @@ public:

using value_type = sc_register<DATATYPE>;
using pointer = value_type *;

/**
* the constructor
*
* @param nm
* @param storage
* @param reset_val
* @param owner
* @param rdmask
* @param wrmask
*/
sc_register_indexed(sc_core::sc_module_name nm, std::array<DATATYPE, SIZE> &storage, const DATATYPE reset_val,
resetable &owner,
BASE_DATA_TYPE rdmask = std::numeric_limits<BASE_DATA_TYPE>::is_signed
@@ -265,54 +300,96 @@ public:
std::stringstream ss;
ss << nm << idx;
new (_reg_field + idx)
sc_register<DATATYPE>(ss.str().c_str(), storage[idx], reset_val, owner, rdmask, wrmask);
sc_register<DATATYPE>(sc_core::sc_module_name(ss.str().c_str()), storage[idx], reset_val, owner, rdmask, wrmask);
}
}

/**
* the destructor
*/
~sc_register_indexed() override {
// for (size_t idx = START; idx < (START + SIZE); ++idx)
// (_reg_field + idx)->~sc_register<DATATYPE>();
free(_reg_field);
}

/**
* get the size of the register file
*
* @return the size
*/
size_t size() override { return SIZE; };

/**
* set the read callback triggered upon a read request without forwarding the annotated time
* this is primary for backward compatibility
*
* @param read_cb
*/
void set_read_cb(std::function<bool(const sc_register<DATATYPE> &, DATATYPE &)> read_cb) {
for (std::unique_ptr<sc_register<DATATYPE>> reg : *this) reg->add_read_cb(read_cb);
}

/**
* set the read callback triggered upon a read request
*
* @param read_cb
*/
void set_read_cb(std::function<bool(const sc_register<DATATYPE> &, DATATYPE &, sc_core::sc_time)> read_cb) {
for (std::unique_ptr<sc_register<DATATYPE>> reg : *this) reg->add_read_cb(read_cb);
}

/**
* set the write callback triggered upon a write request without forwarding the annotated time
* this is primary for backward compatibility
*
* @param write_cb
*/
void set_write_cb(std::function<bool(sc_register<DATATYPE> &, DATATYPE &)> write_cb) {
for (std::unique_ptr<sc_register<DATATYPE>> reg : *this) reg->add_write_cb(write_cb);
}

/**
* set the write callback triggered upon a write request
*
* @param write_cb
*/
void set_write_cb(std::function<bool(sc_register<DATATYPE> &, DATATYPE &, sc_core::sc_time)> write_cb) {
for (std::unique_ptr<sc_register<DATATYPE>> reg : *this) reg->add_write_cb(write_cb);
}

// Element access.
indexed_resource_access_if::reference operator[](size_t __n) noexcept override { return *(_reg_field + __n); }

indexed_resource_access_if::const_reference operator[](size_t __n) const noexcept override {
return *(_reg_field + __n);
}

reference at(size_t __n) override {
assert("access out of bound" && __n < SIZE);
return *(_reg_field + __n);
/**
* Element access operator
*
* @param idx the index
* @return the data reference at the index
*/
reference operator[](size_t idx) noexcept override { return *(_reg_field + idx); }
/**
* const element access operator
*
* @param idx
* @return the data reference at the index
*/
const_reference operator[](size_t idx) const noexcept override { return *(_reg_field + idx); }
/**
* Element access operator
*
* @param idx the index
* @return the data reference at the index
*/
reference at(size_t idx) override {
assert("access out of bound" && idx < SIZE);
return *(_reg_field + idx);
}
const_reference at(size_t __n) const override {
assert("access out of bound" && __n < SIZE);
return *(_reg_field + __n);
/**
* const element access operator
*
* @param idx
* @return the data reference at the index
*/
const_reference at(size_t idx) const override {
assert("access out of bound" && idx < SIZE);
return *(_reg_field + idx);
}

private:
value_type *_reg_field;
};

/**
* alias class to map template argument read an write mask to constructor arguments
*/
template <typename DATATYPE, DATATYPE WRMASK = impl::get_max_uval<DATATYPE>(),
DATATYPE RDMASK = impl::get_max_uval<DATATYPE>()>
class sc_register_masked : public sc_register<DATATYPE> {

+ 66
- 17
incl/scc/report.h View File

@@ -13,12 +13,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*******************************************************************************/
/*
* logging.h
*
* Created on: Nov 24, 2016
* Author: developer
*/

#ifndef _SYSC_REPORT_H_
#define _SYSC_REPORT_H_
@@ -37,34 +31,83 @@ namespace scc {

/**
* initializes the SystemC logging system to use logging::Logger with a particular logging level
*
* @param level the logging level
*/
void init_logging(logging::log_level level = logging::WARNING);

/**
* the logger class
*/
template <sc_core::sc_severity SEVERITY> struct ScLogger {
/**
* the constructor
*
* @param file file where the log entry originates
* @param line the line where the log entry originates
* @param level the log level
*/
ScLogger(const char *file, int line, sc_core::sc_verbosity level = sc_core::SC_MEDIUM)
: t(nullptr)
, file(file)
, line(line)
, level(level){};

/**
* no default constructor
*/
ScLogger() = delete;

/**
* no copy constructor
* @param
*/
ScLogger(const ScLogger &) = delete;

/**
* no move constructor
* @param
*/
ScLogger(ScLogger &&) = delete;
/**
* no copy assignment
* @param
* @return
*/
ScLogger &operator=(const ScLogger &) = delete;

/**
* no move assignment
* @param
* @return
*/
ScLogger &operator=(ScLogger &&) = delete;
/**
* the destructor generating the SystemC report
*/
virtual ~ScLogger() {
::sc_core::sc_report_handler::report(SEVERITY, t ? t : "SystemC", os.str().c_str(), level, file, line);
}

inline ScLogger &type() { return *this; }

/**
* reset the category of the log entry
*
* @return
*/
inline ScLogger &type() {
this->t=nullptr;
return *this;
}
/**
* set the category of the log entry
*
* @param t
* @return
*/
inline ScLogger &type(const char *t) {
this->t = const_cast<char *>(t);
return *this;
}

inline std::ostringstream &get() { return os; };
/**
* return the underlying ostringstream
*
* @return the output stream collecting the log message
*/
inline std::ostream &get() { return os; };

protected:
std::ostringstream os;
@@ -73,22 +116,28 @@ protected:
const int line;
const sc_core::sc_verbosity level;
};
//! macro for debug trace lavel output
#define SCDBGTRC(...) \
if (::sc_core::sc_report_handler::get_verbosity_level() >= sc_core::SC_DEBUG) \
::scc::ScLogger<::sc_core::SC_INFO>(__FILE__, __LINE__, sc_core::SC_DEBUG).type(__VA_ARGS__).get()
//! macro for trace level output
#define SCTRACE(...) \
if (::sc_core::sc_report_handler::get_verbosity_level() >= sc_core::SC_FULL) \
::scc::ScLogger<::sc_core::SC_INFO>(__FILE__, __LINE__, sc_core::SC_FULL).type(__VA_ARGS__).get()
//! macro for debug level output
#define SCDEBUG(...) \
if (::sc_core::sc_report_handler::get_verbosity_level() >= sc_core::SC_HIGH) \
::scc::ScLogger<::sc_core::SC_INFO>(__FILE__, __LINE__, sc_core::SC_HIGH).type(__VA_ARGS__).get()
//! macro for info level output
#define SCINFO(...) \
if (::sc_core::sc_report_handler::get_verbosity_level() >= sc_core::SC_MEDIUM) \
::scc::ScLogger<::sc_core::SC_INFO>(__FILE__, __LINE__, sc_core::SC_MEDIUM).type(__VA_ARGS__).get()
//! macro for warning level output
#define SCWARN(...) \
::scc::ScLogger<::sc_core::SC_WARNING>(__FILE__, __LINE__, sc_core::SC_MEDIUM).type(__VA_ARGS__).get()
//! macro for error level output
#define SCERR(...) ::scc::ScLogger<::sc_core::SC_ERROR>(__FILE__, __LINE__, sc_core::SC_MEDIUM).type(__VA_ARGS__).get()
//! macro for fatal message output
#define SCFATAL(...) \
::scc::ScLogger<::sc_core::SC_FATAL>(__FILE__, __LINE__, sc_core::SC_MEDIUM).type(__VA_ARGS__).get()
}

+ 10
- 10
incl/scc/resetable.h View File

@@ -13,12 +13,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*******************************************************************************/
/*
* resettable.h
*
* Created on: Nov 16, 2016
* Author: developer
*/

#ifndef _SYSC_RESETTABLE_H_
#define _SYSC_RESETTABLE_H_
@@ -31,27 +25,33 @@ namespace scc {
class resetable {
public:
/**
*
* the default destructor
*/
virtual ~resetable() = default;
/**
*
* begin the reset state
*/
void reset_start() {
_in_reset = true;
for (auto res : resources) res->reset();
}
/**
*
* finish the reset state
*/
void reset_stop() {
for (auto res : resources) res->reset();
_in_reset = false;
}
/**
* get the current state of this reset domain
*
* @return tru if reset is active
*/
bool in_reset() { return _in_reset; }
/**
* register a resource with this reset domain
*
* @param res
* @param res the resource belonging to this reset domain
*/
void register_resource(resource_access_if *res) { resources.push_back(res); }


+ 50
- 42
incl/scc/resource_access_if.h View File

@@ -13,12 +13,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*******************************************************************************/
/*
* resource_access_if.h
*
* Created on: Nov 16, 2016
* Author: developer
*/

#ifndef _SYSC_RESOURCE_ACCESS_IF_H_
#define _SYSC_RESOURCE_ACCESS_IF_H_
@@ -28,60 +22,71 @@
#include <sysc/kernel/sc_time.h>

namespace scc {

/**
* interface defining access to a resource
*/
class resource_access_if {
public:
/**
*
* the destructor
*/
virtual ~resource_access_if() = default;
/**
* return the size of the resource
*
* @return
* @return the size
*/
virtual std::size_t size() const = 0;
/**
*
* reset the resource
*/
virtual void reset() = 0;
// functional accesses
/**
* write to the resource
*
* @param data
* @param length
* @param offset
* @return
* @param data data to write
* @param length length of data to write
* @param offset offset of the data to write
* @param d the annotated delay
* @return true it the access is successful
*/
virtual bool write(const uint8_t *data, std::size_t length, uint64_t offset = 0,
sc_core::sc_time d = sc_core::SC_ZERO_TIME) = 0;
/**
* read the data from the resource
*
* @param data
* @param length
* @param offset
* @return
* @param data buffer to read the data into
* @param length length of data to read
* @param offset offset of the data to read
* @param d the annotated delay
* @return true it the access is successful
*/
virtual bool read(uint8_t *data, std::size_t length, uint64_t offset = 0,
sc_core::sc_time d = sc_core::SC_ZERO_TIME) const = 0;
// non-functional/debug accesses
/**
* debug write to the resource
*
* @param data
* @param length
* @param offset
* @return
* @param data data to write
* @param length length of data to write
* @param offset offset of the data to write
* @return true it the access is successful
*/
virtual bool write_dbg(const uint8_t *data, std::size_t length, uint64_t offset = 0) = 0;
/**
* debug read the data from the resource
*
* @param data
* @param length
* @param offset
* @return
* @param data buffer to read the data into
* @param length length of data to read
* @param offset offset of the data to read
* @return true it the access is successful
*/
virtual bool read_dbg(uint8_t *data, std::size_t length, uint64_t offset = 0) const = 0;
};

/**
* interface defining access to an indexed resource
*/
class indexed_resource_access_if {
public:
using value_type = resource_access_if;
@@ -92,39 +97,42 @@ public:
using iterator = resource_access_if *;
using const_iterator = const resource_access_if *;
/**
*
* the destructor
*/
virtual ~indexed_resource_access_if() = default;
/**
*
* get the size of the resource
* @return
*/
virtual std::size_t size() = 0;
// Element access.
/**
* Element access.
*
* @param __n
* @return
* @param idx
* @return the data
*/
virtual reference operator[](std::size_t __n) noexcept = 0;
virtual reference operator[](std::size_t idx) noexcept = 0;
/**
* const element access.
*
* @param __n
* @return
* @param idx
* @return the data
*/
virtual const_reference operator[](std::size_t __n) const noexcept = 0;
virtual const_reference operator[](std::size_t idx) const noexcept = 0;
/**
* Element access.
*
* @param __n
* @return
* @param idx
* @return the data
*/
virtual reference at(std::size_t __n) = 0;
virtual reference at(std::size_t idx) = 0;
/**
* const element access.
*
* @param __n
* @return
* @param idx
* @return the data
*/
virtual const_reference at(std::size_t __n) const = 0;
virtual const_reference at(std::size_t idx) const = 0;
};
}
#endif /* _SYSC_RESOURCE_ACCESS_IF_H_ */

+ 39
- 12
incl/scc/router.h View File

@@ -13,12 +13,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*******************************************************************************/
/*
* router.h
*
* Created on: Nov 5, 2016
* Author: eyck
*/

#ifndef _SYSC_ROUTER_H_
#define _SYSC_ROUTER_H_
@@ -41,14 +35,15 @@ public:
using intor_sckt = scc::initiator_mixin<scv4tlm::tlm_rec_initiator_socket<BUSWIDTH>>;
using target_sckt = scc::target_mixin<scv4tlm::tlm_rec_target_socket<BUSWIDTH>>;
/**
*
* the array of target sockets
*/
sc_core::sc_vector<target_sckt> target;
/**
*
* the array of initiator sockets
*/
sc_core::sc_vector<intor_sckt> initiator;
/**
* constructs a router
*
* @param nm
* @param slave_cnt
@@ -60,24 +55,55 @@ public:
*/
~router() = default;
/**
* bind the initiator socket of the router to some target giving a base and size
*
* @param socket
* @param idx
* @param base
* @param size
* @param remap
*/
template<typename TYPE>
void bind_target(TYPE& socket, size_t idx, uint64_t base, uint64_t size, bool remap = true){
set_target_range(idx, base, size, remap);
initiator[idx].bind(socket);
}
/**
* bind the initiator socket of the router to some target and name it
*
* @param socket
* @param idx
* @param name
*/
template<typename TYPE>
void bind_target(TYPE& socket, size_t idx, std::string name){
set_target_name(idx, name);
initiator[idx].bind(socket);
}
/**
* define a base address of a socket. This will be added to the address of each access
* coming thru this socket
*
* @param idx
* @param base
*/
void set_initiator_base(size_t idx, uint64_t base) { ibases[idx] = base; }
/**
* define the default target socket. If no target address range is hit the access is routed to this socket.
* If this is not defined a address error response is generated
*
* @param idx
*/
void set_default_target(size_t idx) { default_idx = idx; }
/**
* establish a mapping between socket naem name and socket index
* establish a mapping between socket name and socket index
*
* @param idx
* @param name
*/
void set_target_name(size_t idx, std::string name) { target_name_lut.insert(std::make_pair(name, idx)); }
/**
* establish a mapping between a named socket and a target address range
*
* @param idx
* @param base
@@ -86,13 +112,14 @@ public:
*/
void add_target_range(std::string name, uint64_t base, uint64_t size, bool remap = true);
/**
* establish a mapping between a socket and a target address range
*
* @param name
* @param base
* @param size
* @param remap
*/
void add_target_range(size_t idx, uint64_t base, uint64_t size, bool remap = true);
void set_target_range(size_t idx, uint64_t base, uint64_t size, bool remap = true);
/**
* tagged blocking transport method
*
@@ -110,8 +137,8 @@ public:
* @return
*/
bool get_direct_mem_ptr(int i, tlm::tlm_generic_payload &trans, tlm::tlm_dmi &dmi_data);
// tagged debug transaction method
/**
* tagged debug transaction method
*
* @param i
* @param trans
@@ -171,7 +198,7 @@ router<BUSWIDTH>::router(const sc_core::sc_module_name &nm, unsigned slave_cnt,
}

template <unsigned BUSWIDTH>
void router<BUSWIDTH>::add_target_range(size_t idx, uint64_t base, uint64_t size, bool remap) {
void router<BUSWIDTH>::set_target_range(size_t idx, uint64_t base, uint64_t size, bool remap) {
tranges[idx].base = base;
tranges[idx].size = size;
tranges[idx].remap = remap;

+ 2
- 2
incl/scc/scv_tr_db.h View File

@@ -22,13 +22,13 @@
*/
void scv_tr_sqlite_init();
/**
*initializes the infrastructure to use a compressed text based transaction recording database
* initializes the infrastructure to use a compressed text based transaction recording database
*/
void scv_tr_compressed_init();

#ifdef USE_EXTENDED_DB
/**
*initializes the infrastructure to use a binary transaction recording database
* initializes the infrastructure to use a binary transaction recording database
*/
void scv_tr_binary_init();
/**

+ 10
- 2
incl/scc/tagged_initiator_mixin.h View File

@@ -23,7 +23,9 @@
#include <tlm>

namespace scc {

/**
*
*/
template <typename BASE_TYPE, typename TYPES = tlm::tlm_base_protocol_types>
class tagged_initiator_mixin : public BASE_TYPE {
public:
@@ -34,12 +36,18 @@ public:
using bw_interface_type = tlm::tlm_bw_transport_if<TYPES>;

public:
/**
*
*/
tagged_initiator_mixin()
: BASE_TYPE(sc_core::sc_gen_unique_name("tagged_initiator_socket"))
, bw_if(this->name()) {
this->m_export.bind(bw_if);
}

/**
*
* @param n
*/
explicit tagged_initiator_mixin(const char *n)
: BASE_TYPE(n)
, bw_if(this->name()) {

+ 18
- 14
incl/scc/target_mixin.h View File

@@ -26,10 +26,12 @@
#include <tlm_utils/peq_with_get.h>

namespace scc {

template <typename base_type, typename TYPES = tlm::tlm_base_protocol_types> class target_mixin : public base_type {
friend class fw_process;
friend class bw_process;
/**
* an target socket mixin adding default implementation of callback functions similar to tlm::simple_target_socket
*/
template <typename BASE_TYPE, typename TYPES = tlm::tlm_base_protocol_types> class target_mixin : public BASE_TYPE {
// friend class fw_process;
// friend class bw_process;

public:
using transaction_type = typename TYPES::tlm_payload_type;
@@ -40,32 +42,32 @@ public:

public:
/**
*
* default constructor
*/
target_mixin()
: target_mixin(sc_core::sc_gen_unique_name("target_mixin_socket")) {}
/**
* constructor with explicit instance name
*
* @param n
*/
explicit target_mixin(const char *n)
: base_type(n)
explicit target_mixin(const sc_core::sc_module_name &n)
: BASE_TYPE(n)
, m_fw_process(this)
, m_bw_process(this)
, m_current_transaction(nullptr) {
bind(m_fw_process);
}

using base_type::bind;

// bw transport must come thru us.
//! make bind of base class available
using BASE_TYPE::bind;
/**
* return the bw_process interface
*
* @return
*/
tlm::tlm_bw_transport_if<TYPES> *operator->() { return &m_bw_process; }
// REGISTER_XXX
/**
* register a non-blocking forward path callback function
*
* @param cb
*/
@@ -75,6 +77,7 @@ public:
m_fw_process.set_nb_transport_ptr(cb);
}
/**
* register a blocking forward path callback function
*
* @param cb
*/
@@ -91,6 +94,7 @@ public:
m_fw_process.set_transport_dbg_ptr(cb);
}
/**
* register a DMI callback function
*
* @param cb
*/
@@ -102,11 +106,11 @@ public:
private:
// make call on bw path.
sync_enum_type bw_nb_transport(transaction_type &trans, phase_type &phase, sc_core::sc_time &t) {
return base_type::operator->()->nb_transport_bw(trans, phase, t);
return BASE_TYPE::operator->()->nb_transport_bw(trans, phase, t);
}

void bw_invalidate_direct_mem_ptr(sc_dt::uint64 s, sc_dt::uint64 e) {
base_type::operator->()->invalidate_direct_mem_ptr(s, e);
BASE_TYPE::operator->()->invalidate_direct_mem_ptr(s, e);
}

// Helper class to handle bw path calls

+ 12
- 2
incl/scc/time2tick.h View File

@@ -20,12 +20,22 @@
#include "utilities.h"

namespace scc {
/**
* translate a tick-less clock (sc_time based) to boolean clock
*/
struct time2tick : public sc_core::sc_module {
//! yes, we have processes
SC_HAS_PROCESS(time2tick);// NOLINT
//! the clock input
sc_core::sc_in<sc_core::sc_time> clk_i;
//! the clock output
sc_core::sc_out<bool> clk_o;

time2tick(sc_core::sc_module_name nm)
/**
* the constructor
*
* @param nm
*/
explicit time2tick(sc_core::sc_module_name nm)
: sc_core::sc_module(nm) {
SC_THREAD(clocker);
}

+ 26
- 36
incl/scc/tlm_target.h View File

@@ -13,12 +13,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*******************************************************************************/
/*
* tlmtarget.h
*
* Created on: Nov 16, 2016
* Author: developer
*/

#ifndef _SYSC_TLM_TARGET_H_
#define _SYSC_TLM_TARGET_H_
@@ -42,43 +36,47 @@ template <unsigned int BUSWIDTH = 32> class tlm_target {
public:
using this_type = tlm_target<BUSWIDTH>;
/**
* the constructor
*
* @param clock
*/
tlm_target(sc_core::sc_time &clock);
/**
*
* the socket
*/
scc::target_mixin<scv4tlm::tlm_rec_target_socket<BUSWIDTH>> socket;
/**
* the blocking transport callback
*
* @param
* @param
*/
void b_tranport_cb(tlm::tlm_generic_payload &, sc_core::sc_time &);
/**
* the debug transport callback
*
* @param
* @return
*/
unsigned int tranport_dbg_cb(tlm::tlm_generic_payload &);
/**
* add a resource to this target at a certain address within the socket address range
*
* @param i
* @param base_addr
* @param rai the resource to add
* @param base_addr the offset of the resource (from address 0)
*/
void addResource(resource_access_if &i, uint64_t base_addr) {
socket_map.addEntry(std::make_pair(&i, base_addr), base_addr, i.size());
void addResource(resource_access_if &rai, uint64_t base_addr) {
socket_map.addEntry(std::make_pair(&rai, base_addr), base_addr, rai.size());
}
/**
*
* @param ii
* @param base_addr
* add an indexed resource to this target at a certain address within the socket address range
* @param irai the resource to add
* @param base_addr the offset of the resource (from address 0)
*/
void addResource(indexed_resource_access_if &ii, uint64_t base_addr) {
for (size_t idx = 0; idx < ii.size(); ++idx) {
socket_map.addEntry(std::make_pair(&ii[idx], base_addr), base_addr, ii[idx].size());
base_addr += ii[idx].size();
void addResource(indexed_resource_access_if &irai, uint64_t base_addr) {
for (size_t idx = 0; idx < irai.size(); ++idx) {
socket_map.addEntry(std::make_pair(&irai[idx], base_addr), base_addr, irai[idx].size());
base_addr += irai[idx].size();
}
}

@@ -88,29 +86,21 @@ private:
protected:
util::range_lut<std::pair<resource_access_if *, uint64_t>> socket_map;
};

/**
* helper structure to define a address range for a socket
*/
template <unsigned BUSWIDTH = 32> struct target_memory_map_entry {
tlm::tlm_target_socket<BUSWIDTH> &target;
sc_dt::uint64 start;
sc_dt::uint64 size;
};

template <unsigned int BUSWIDTH = 32, unsigned RANGES = 1> class tlm_multi_rangetarget : public tlm_target<BUSWIDTH> {
public:
using this_type = tlm_multi_rangetarget<BUSWIDTH, RANGES>;

tlm_multi_rangetarget(sc_core::sc_time &clock, std::array<addr_range, RANGES> addr_rngs)
: tlm_target<BUSWIDTH>(clock)
, addr_ranges(addr_rngs) {}

tlm_multi_rangetarget(sc_core::sc_time &clock)
: tlm_target<BUSWIDTH>(clock)
, addr_ranges({}) {}

const std::array<addr_range, RANGES> addr_ranges;

protected:
util::range_lut<resource_access_if *> socket_map;
/**
* helper structure to define a named address range
*/
template <unsigned BUSWIDTH = 32> struct target_name_map_entry {
std::string name;
sc_dt::uint64 start;
sc_dt::uint64 size;
};

} /* namespace scc */

+ 6
- 8
incl/scc/traceable.h View File

@@ -13,12 +13,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*******************************************************************************/
/*
* tracable.h
*
* Created on: Nov 9, 2016
* Author: developer
*/

#ifndef _SCC_TRACABLE_H_
#define _SCC_TRACABLE_H_
@@ -28,14 +22,18 @@ class sc_trace_file;
}

namespace scc {

/**
* interface defining a traceable component, this overlaps with the trace function of sc_core::sc_object
* in fact it is a signalling interface
*/
class traceable {
public:
/**
*
* the destructor
*/
virtual ~traceable() = default;
/**
* trace the elements of the object to the trace file
*
* @param trf the tracefile to use
*/

+ 8
- 11
incl/scc/tracer.h View File

@@ -13,12 +13,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*******************************************************************************/
/*
* tracer.h
*
* Created on: Nov 9, 2016
* Author: developer
*/

#ifndef _SCC_TRACER_H_
#define _SCC_TRACER_H_
@@ -36,22 +30,25 @@ class sc_trace_file;
}

namespace scc {

/**
* a component traversing the SystemC object hierarchy and tracing the objects
*/
class tracer : public sc_core::sc_module {
public:
/**
*
* enum defining the transaction trace output type
*/
enum file_type { NONE, TEXT, COMPRESSED, SQLITE/*, BINARY, LEVEL*/ };
/**
* the constructor
*
* @param name basename of the trace file(s)
* @param name base name of the trace file(s)
* @param type type of trace file for transactions
* @param enable enable VCD (signal based) tracing
* @param enable enable VCD (signal and POD) tracing
*/
tracer(const std::string &&, file_type, bool = true);
/**
*
* the destructor
*/
virtual ~tracer() override;


+ 46
- 18
incl/scc/utilities.h View File

@@ -41,11 +41,11 @@ template <typename T, typename... Args> std::unique_ptr<T> make_unique(Args &&..
}
}
#endif
//! macros to simplify constructor lists
#define NAMED(X, ...) X(#X, ##__VA_ARGS__)
#define NAMEDD(X, T, ...) X(std::make_unique<T>(#X, ##__VA_ARGS__))
#define NAMEDC(X, T, I, ...) X(T::create<I>(#X, ##__VA_ARGS__))
//! macros to simplify declaration of members to trace
#define TRACE_VAR(F, X) sc_core::sc_trace(F, X, std::string(this->name()) + "." #X)
#define TRACE_ARR(F, X, I) \
sc_core::sc_trace(F, X[I], (std::string(this->name()) + "." #X "(" + std::to_string(I) + ")").c_str());
@@ -70,33 +70,32 @@ void sc_trace(sc_trace_file *, const sc_time &, const std::string &);
void sc_trace(sc_trace_file *, const sc_time &, const char *);
#endif
/**
* trace function for sc_time
*
* @param
* @param
* @param
* @param the trace file
* @param the data to trace
* @param the hierarchical name of the data
*/
template <> void sc_trace(sc_trace_file *, const sc_in<sc_time> &, const std::string &);
/**
* trace function for sc_time
*
* @param
* @param
* @param
* @param the trace file
* @param the port carrying the data to trace
* @param the hierarchical name of the data
*/
template <> void sc_trace(sc_trace_file *, const sc_inout<sc_time> &, const std::string &);
/**
*
* @param val
* @return
*/
}
// user-define literals for easy time creation
// user-defined literals for easy time creation
/**
* UDL for second
*
* @param val
* @return
*/
inline sc_core::sc_time operator"" _sec(long double val) { return sc_core::sc_time(val, sc_core::SC_SEC); }
/**
* UDL for second
*
* @param val
* @return
@@ -105,72 +104,90 @@ inline sc_core::sc_time operator"" _sec(unsigned long long val) {
return sc_core::sc_time(double(val), sc_core::SC_SEC);
}
/**
* UDL for millisecond
*
* @param val
* @return
*/
inline sc_core::sc_time operator"" _ms(long double val) { return sc_core::sc_time(val, sc_core::SC_MS); }
/**
* UDL for millisecond
*
* @param val
* @return
*/
inline sc_core::sc_time operator"" _ms(unsigned long long val) { return sc_core::sc_time(double(val), sc_core::SC_MS); }
/**
* UDL for microsecond
*
* @param val
* @return
*/
inline sc_core::sc_time operator"" _us(long double val) { return sc_core::sc_time(val, sc_core::SC_US); }
/**
* UDL for microsecond
*
* @param val
* @return
*/
inline sc_core::sc_time operator"" _us(unsigned long long val) { return sc_core::sc_time(double(val), sc_core::SC_US); }
/**
* UDL for nanosecond
*
* @param val
* @return
*/
inline sc_core::sc_time operator"" _ns(long double val) { return sc_core::sc_time(val, sc_core::SC_NS); }
/**
* UDL for nanosecond
*
* @param val
* @return
*/
inline sc_core::sc_time operator"" _ns(unsigned long long val) { return sc_core::sc_time(double(val), sc_core::SC_NS); }
/**
* UDL for picosecond
*
* @param val
* @return
*/
inline sc_core::sc_time operator"" _ps(long double val) { return sc_core::sc_time(val, sc_core::SC_PS); }
/**
* UDL for picosecond
*
* @param val
* @return
*/
inline sc_core::sc_time operator"" _ps(unsigned long long val) { return sc_core::sc_time(double(val), sc_core::SC_PS); }
/**
* UDL for femtosecond
*
* @param val
* @return
*/
inline sc_core::sc_time operator"" _fs(long double val) { return sc_core::sc_time(val, sc_core::SC_FS); }
/**
* UDL for femtosecond
*
* @param val
* @return
*/
inline sc_core::sc_time operator"" _fs(unsigned long long val) { return sc_core::sc_time(double(val), sc_core::SC_FS); }
//! UDL for kilobyte
inline constexpr uint64_t operator"" _kB(unsigned long long val) { return val * 1 << 10; }
//! UDL for megabyte
inline constexpr uint64_t operator"" _MB(unsigned long long val) { return val * 1 << 20; }
//! UDL for gigabyte
inline constexpr uint64_t operator"" _GB(unsigned long long val) { return val * 1 << 30; }

namespace scc {

/**
* case-insensitive string compare
*
* @param a string a
* @param b string b
* @return result of std::equal
*/
inline bool icompare(std::string const &a, std::string const &b) {
if (a.length() == b.length()) {
return std::equal(b.begin(), b.end(), a.begin(),
@@ -179,7 +196,13 @@ inline bool icompare(std::string const &a, std::string const &b) {
return false;
}
}

/**
* parse a time value from given strings
*
* @param value the string to parse
* @param unit the unit string
* @return the parsed sc_core::sc_time value
*/
inline sc_core::sc_time parse_from_string(std::string value, std::string unit) noexcept {
std::string::size_type offs{0};
double t_val = std::stod(value, &offs);
@@ -193,7 +216,12 @@ inline sc_core::sc_time parse_from_string(std::string value, std::string unit) n
}
return sc_core::SC_ZERO_TIME;
}

/**
* parse a time value from a given string
*
* @param value the string to parse
* @return the parsed sc_core::sc_time value
*/
inline sc_core::sc_time parse_from_string(std::string value) noexcept {
std::string::size_type offs{0};
double t_val = std::stod(value, &offs);

+ 7
- 12
incl/util/ities.h View File

@@ -74,7 +74,13 @@ constexpr size_t bit_count(uint32_t u) {
return ((uCount + (uCount >> 3)) & 030707070707) % 63;
}
#endif

/**
* split a given string using specified separator
*
* @param s the string to split
* @param separator the separator char
* @return vector of splitted strings
*/
inline std::vector<std::string> split(const std::string &s, char seperator) {
std::vector<std::string> output;
std::string::size_type prev_pos = 0, pos = 0;
@@ -86,16 +92,5 @@ inline std::vector<std::string> split(const std::string &s, char seperator) {
output.push_back(s.substr(prev_pos, pos - prev_pos)); // Last word
return output;
}

// std::vector<std::string> split(std::string& str, char split_char){
// std::vector<std::string> res;
// auto split_pos=str.find_first_of(split_char);
// decltype(split_pos) start{0};
// while(start!=str.length()){
// res.push_back(str.substr(start, start-split_pos));
// start=std::min(split_pos+1, str.length());
// }
// return res;
//}
}
#endif /* _UTIL_ITIES_H_ */

+ 85
- 17
incl/util/logging.h View File

@@ -28,39 +28,70 @@
#include <sys/time.h>
#include <vector>

//! log level definitions
#define LEVELS(L) L(NONE) L(FATAL) L(ERROR) L(WARNING) L(INFO) L(DEBUG) L(TRACE)
#define DO_DESCRIPTION(e) #e,
#define DO_ENUM(e) e,

namespace logging {
//! array holding string representations of log levels
static std::array<const char *const, 7> buffer = {{LEVELS(DO_DESCRIPTION)}};
//! enum defining the log levels
enum log_level { LEVELS(DO_ENUM) };

/**
* safely convert an integer into a log level
* @param logLevel the integer
* @return the log level
*/
inline log_level as_log_level(int logLevel) {
assert(logLevel >= NONE && logLevel <= TRACE);
std::array<const log_level, 7> m = {{NONE, FATAL, ERROR, WARNING, INFO, DEBUG, TRACE}};
return m[logLevel];
}

/**
* get the current host time as string
* @return
*/
inline std::string now_time();

/**
* the logger class
*/
template <typename T> class Log {
public:
/**
* default constructor
*/
Log() = default;

/**
* no copy constructor
*
* @param
*/
Log(const Log &) = delete;

/**
* no copy assignment constructor
*
* @param
* @return
*/
Log &operator=(const Log &) = delete;

/**
* the destructor
*/
virtual ~Log() {
os << std::endl;
T::output(os.str());
// TODO: use a more specific exception
if (get_last_log_level() == FATAL) abort();
}

std::ostringstream &get(log_level level = INFO, const char *category = "") {
/**
* get the underlying ostringstream for a certain log level and category
*
* @param level the log level
* @param category the category string
* @return the underlying output stream
*/
std::ostream &get(log_level level = INFO, const char *category = "") {
if (print_time()) os << "- " << now_time() << " ";
if (print_severity()) {
os << std::setw(7) << std::left << to_string(level);
@@ -70,14 +101,28 @@ public:
get_last_log_level() = level;
return os;
};

/**
* get a reference to the configured logging level
*
* @return the logging level
*/
static log_level &reporting_level() {
static log_level reportingLevel = WARNING;
return reportingLevel;
}

/**
* translate a lg level to a string
*
* @param level the log level
* @return the string representing the log level
*/
static std::string to_string(log_level level) { return std::string(get_log_level_cstr()[level]); };

/**
* parse a log level from a string
*
* @param level the string representing the log level
* @return the log level
*/
static log_level from_string(const std::string &level) {
for (unsigned int i = NONE; i <= TRACE; i++)
if (!strncasecmp(level.c_str(), (const char *)(get_log_level_cstr() + i),
@@ -86,12 +131,20 @@ public:
Log<T>().Get(WARNING) << "Unknown logging level '" << level << "'. Using INFO level as default.";
return INFO;
}

/**
* get the reference to the flag indicating if the current host time should be part of the log
*
* @return the print time flag
*/
static bool &print_time() {
static bool flag = true;
return flag;
}

/**
* get the reference to the flag indicating if severity should be part of the log
*
* @return the print severity flag
*/
static bool &print_severity() {
static bool flag = true;
return flag;
@@ -105,13 +158,25 @@ protected:
static const char *const *get_log_level_cstr() { return buffer.data(); };
std::ostringstream os;
};

/**
* the output writer
*/
template <typename CATEGORY> class Output2FILE : CATEGORY {
public:
/**
* get the file handle of the underlying output file (or stdout)
*
* @return the file handle
*/
static FILE *&stream() {
static FILE *pStream = stdout;
return pStream;
}
/**
* write an output string to the file
*
* @param msg the string to write
*/
static void output(const std::string &msg) {
static std::mutex mtx;
std::lock_guard<std::mutex> lock(mtx);
@@ -121,6 +186,7 @@ public:
fflush(pStream);
}
};
//! the default logging category
class DEFAULT {};

#if defined(WIN32) || defined(_WIN32) || defined(__WIN32__)
@@ -178,12 +244,13 @@ inline std::string now_time() {
strftime(buffer.data(), buffer.size(), "%X", localtime_r(&t, &r));
struct timeval tv;
gettimeofday(&tv, nullptr);
memset(result.data(), 100, 1);
sprintf(result.data(), "%s.%03ld", buffer.data(), (long)tv.tv_usec / 1000);
return result.data();
}

#endif // WIN32
// a print function for a vector
//! a print function for a vector
template <typename T> std::ostream &operator<<(std::ostream &stream, const std::vector<T> &vector) {
copy(vector.begin(), vector.end(), std::ostream_iterator<T>(stream, ","));
return stream;
@@ -194,6 +261,7 @@ template <typename T> std::ostream &operator<<(std::ostream &stream, const std::
#undef CAT

#ifndef NDEBUG
//! check only in debug mode
#define ASSERT(condition, message) \
do { \
if (!(condition)) { \
@@ -207,7 +275,7 @@ template <typename T> std::ostream &operator<<(std::ostream &stream, const std::
do { \
} while (false)
#endif
//! check always
#define CHECK(condition, message) \
do { \
if (!(condition)) { \

+ 13
- 8
incl/util/range_lut.h View File

@@ -26,18 +26,21 @@
#include <string>

namespace util {

/**
* range based lookup table
*/
template <typename T> class range_lut {
//! the type of lut entry
enum entry_type { BEGIN_RANGE = 1, END_RANGE = 2, SINGLE_BYTE_RANGE = 3 };
//! the lut entry
struct lut_entry {
T index;
entry_type type;
};

public:
/**
* constructor or the lookup table
*
* @param null_entry the entry to be used for empty slots
*/
range_lut(T null_entry)
@@ -45,6 +48,7 @@ public:
/**
* add an T to the lut covering the range starting at base_addr until
* base_addr+size-1
*
* @param i the entry
* @param base_addr the base address
* @param size the size of the occupied range
@@ -52,12 +56,14 @@ public:
void addEntry(T i, uint64_t base_addr, uint64_t size);
/**
* remove an entry with value i of type T
*
* @param i the entry to be found
* @return true if the entry is found and removed, false otherwise
*/
bool removeEntry(T i);
/**
* get number of entries in the lookup table
*
* @return the size of the underlying container
*/