Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -162,3 +162,4 @@ cython_debug/
# and can be added to the global gitignore or merged into this file. For a more nuclear
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
#.idea/
tests/cmake/_deps
49 changes: 48 additions & 1 deletion src/peakrdl_halcpp/halnode.py
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,10 @@ def get_docstring(self) -> str:
def _halfactory(inst: Node, env: 'RDLEnvironment', parent: Optional['Node'] = None) -> Optional['Node']:
"""HAL node factory method adapted from systemrdl Node class."""
if isinstance(inst, FieldNode):
return HalFieldNode(inst)
if inst.get_property("intwidth", default=None) or inst.get_property("fracwidth", default=None):
return HalFixpFieldNode(inst)
else:
return HalFieldNode(inst)
elif isinstance(inst, RegNode):
return HalRegNode(inst)
elif isinstance(inst, RegfileNode):
Expand Down Expand Up @@ -243,6 +246,50 @@ def get_enums(self):

return False, None, None, None, None, None

class HalFixpFieldNode(HalFieldNode, FieldNode):
"""HalFixpFieldNode class inheriting from HalBaseNode class and systemrdl FieldNode class.

Class methods:

- :func:`get_enums`
"""

@property
def fracwidth(self) -> int:
intwidth: int|None = self.get_property("intwidth", default=None)
fracwidth: int|None = self.get_property("fracwidth", default=None)

if fracwidth:
return int(fracwidth)
elif intwidth:
return self.width - intwidth

raise ValueError("One of intwidth or fracwidth properties need to be defined fro FixpFieldNode")

@property
def intwidth(self) -> int:
intwidth: int|None = self.get_property("intwidth", default=None)
fracwidth: int|None = self.get_property("fracwidth", default=None)

if intwidth:
return int(intwidth)
elif fracwidth:
return self.width - fracwidth

raise ValueError("One of intwidth or fracwidth properties need to be defined fro FixpFieldNode")

@property
def cpp_access_type(self) -> str:
"""C++ access right template selection."""
if self.is_sw_readable and self.is_sw_writable:
return "FixpFieldRW"
elif self.is_sw_writable and not self.is_sw_readable:
return "FixpFieldWO"
elif self.is_sw_readable:
return "FixpFieldRO"
else:
raise ValueError(f'Node field access rights are not found \
{self.inst.inst_name}')

class HalRegNode(HalBaseNode, RegNode):
"""HalRegNode class inheriting from HalBaseNode class and systemrdl RegNode class.
Expand Down
243 changes: 243 additions & 0 deletions src/peakrdl_halcpp/include/fixp_field_node.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,243 @@
#ifndef _FIXP_FIELD_NODE_H_
#define _FIXP_FIELD_NODE_H_

#include <stdint.h>
#include <type_traits>
#include <tuple>
#include "halcpp_utils.h"

namespace halcpp
{
template <uint32_t START_INT_BIT,
uint32_t END_INT_BIT,
uint32_t START_FRAC_BIT,
uint32_t END_FRAC_BIT,
typename PARENT_TYPE>
class FixpFieldBase
{
public:
/**
* @brief Return the absolute address of the node.
*
*/
static constexpr uint32_t get_abs_addr() { return PARENT_TYPE().get_abs_addr(); }

/**
* @brief Return the width of the field noe.
*
*/
static constexpr uint32_t get_width() { return width; }
static constexpr uint32_t get_int_width() { return width_int; }
static constexpr uint32_t get_frac_width() { return width_frac; }

/**
* @brief Calculate the field mask.
*
* Example: START_BIT = 3, width = 4 => field_mask = 0000 0000 0111 1000
*/
static constexpr uint32_t field_mask()
{
static_assert(width <= 32, "Register cannot be bigger than 32 bits");
return (~0u) ^ (bit_mask() << START_INT_BIT);
}

/**
* @brief Calculate the bit mask.
*
* Example: width = 4 => bit_mask = 0000 0000 0000 1111
*/
static constexpr uint32_t bit_mask()
{
return (((1u << (width)) - 1));
}



protected:
using parent_type = PARENT_TYPE;

static constexpr uint32_t start_bit = START_INT_BIT;
static constexpr uint32_t start_int_bit = START_INT_BIT;
static constexpr uint32_t end_int_bit = END_INT_BIT;
static constexpr uint32_t start_frac_bit = START_FRAC_BIT;
static constexpr uint32_t end_frac_bit = END_FRAC_BIT;
static constexpr uint32_t end_bit = END_FRAC_BIT;

static constexpr uint32_t width = end_bit - start_bit + 1;
static constexpr uint32_t width_int = end_int_bit - start_int_bit + 1;
static constexpr uint32_t width_frac = end_frac_bit - start_frac_bit + 1;


using dataType = float;
};

template <typename BASE_TYPE>
class FixpFieldWrMixin : public BASE_TYPE
{
public:
using parent = typename BASE_TYPE::parent_type;

/**
* @brief Check if the field has a set operation (write capability).
*/
static constexpr bool has_set() { return true; };

/**
* @brief Set the value of the field.
*
* @param val The value to set.
*/
static inline void set(typename BASE_TYPE::dataType val)
{
uint32_t fixp_val = float_to_fixp(val);
if constexpr (node_has_get_v<parent>)
parent::set((parent::get() & BASE_TYPE::field_mask()) | ((fixp_val & BASE_TYPE::bit_mask()) << BASE_TYPE::start_bit));
else
parent::set(fixp_val << BASE_TYPE::start_bit);
}

static inline uint32_t float_to_fixp(typename BASE_TYPE::dataType val){
return val * (1<<BASE_TYPE::width_frac);
}

/**
* @brief Set the value of the field using a constant.
*
* @tparam CONST_WIDTH The width of the constant.
* @tparam CONST_VAL The value of the constant.
* @param a The constant value to set.
*/
template <uint32_t CONST_WIDTH, uint32_t CONST_VAL>
static inline void set(const Const<CONST_WIDTH, CONST_VAL> &a)
{
static_assert(CONST_WIDTH == BASE_TYPE::width, "Constant is not the same width as field");
set((typename BASE_TYPE::dataType)a.val);
}
};

template <typename BASE_TYPE>
class FixpFieldRdMixin : public BASE_TYPE
{
private:
using parent = typename BASE_TYPE::parent_type;

public:
/**
* @brief Check if the field has a get operation (read capability).
*/
static constexpr bool has_get() { return true; };

/**
* @brief Return the value of the field.
*/
static typename BASE_TYPE::dataType get()
{
// Read the full register, mask, and shift it to get the field value
uint32_t fixp_val = (parent::get() & ~BASE_TYPE::field_mask()) >> BASE_TYPE::start_bit;

return fixp_to_float(fixp_val);
}

static inline float fixp_to_float(uint32_t val){
return (float)val / (1<<BASE_TYPE::width_frac);
}

/**
* @brief Implicit conversion operator to convert the field value to another type.
*
* @tparam T The type to convert to.
* @return The value of the field converted to the specified type.
*/
template <typename T>
inline operator const T()
{
return static_cast<T>(get());
}
};


template <typename... FieldMixins> // TODO merge this with RegNode?
class FixpFieldNode : public FieldMixins...
{
private:
template <typename DT, typename T>
void call_set([[maybe_unused]] const DT &val) const
{
if constexpr (node_has_set_v<T>)
T::set(val);
}

template <typename DT, typename T, typename T1, typename... Ts>
void call_set(const DT val) const
{
call_set<DT, T>(val);
call_set<DT, T1, Ts...>(val);
}

public:
template <typename Tp, typename T = void>
typename std::enable_if<std::disjunction_v<node_has_set<FieldMixins>...>, T>::type
operator=(Tp val)
{
call_set<Tp, FieldMixins...>(val);
}

// template <int32_t IDX>
// static constexpr auto at()
// {
// // Get the type of the first mixin from the tuple of FieldMixins types
// using first_mixin = typename std::tuple_element<0, std::tuple<FieldMixins...>>::type;
// // Define the parent type using the parent type of the first mixin
// using parent_type = typename first_mixin::parent;
//
// // Check if the given index is within the bounds of the width of the first mixin
// static_assert(IDX < static_cast<int32_t>(first_mixin::width));
// static_assert(IDX >= -1);
// // Calculate the index to be used for accessing the mixin based on the given index
// constexpr uint32_t idx = IDX == -1 ? first_mixin::width - 1 : IDX;
//
// // Calculate the number of mixins in the tuple
// constexpr std::size_t num_of_mixins = sizeof...(FieldMixins);
//
// // Define the base type using the calculated index and parent type
// using base_type = FieldBase<idx, idx, parent_type>;
//
// // Check if there's only one mixin
// if constexpr (num_of_mixins == 1)
// {
// // If the mixin has a 'get' function, return a FieldNode with a read mixin
// if constexpr (node_has_get_v<first_mixin>)
// return FieldNode<FieldRdMixin<base_type>>();
// // If the mixin has a 'set' function, return a FieldNode with a write mixin
// if constexpr (node_has_set_v<first_mixin>)
// return FieldNode<FieldWrMixin<base_type>>();
// }
// // If there are two mixins
// else if constexpr (num_of_mixins == 2)
// {
// // Return a FieldNode with both write and read mixins
// return FieldNode<FieldWrMixin<base_type>, FieldRdMixin<base_type>>();
// }
// }
};

template <uint32_t START_INT_BIT, uint32_t END_INT_BIT, uint32_t START_FRAC_BIT, uint32_t END_FRAC_BIT, typename PARENT_TYPE>
using FixpFieldRO = FixpFieldNode<FixpFieldRdMixin<FixpFieldBase<START_INT_BIT, END_INT_BIT, START_FRAC_BIT, END_FRAC_BIT, PARENT_TYPE>>>;

/**
* @brief Alias for FieldNode representing a write-only field.
*/
template <uint32_t START_INT_BIT, uint32_t END_INT_BIT, uint32_t START_FRAC_BIT, uint32_t END_FRAC_BIT, typename PARENT_TYPE>
using FixpFieldWO = FixpFieldNode<FixpFieldWrMixin<FixpFieldBase<START_INT_BIT, END_INT_BIT, START_FRAC_BIT, END_FRAC_BIT, PARENT_TYPE>>>;

/**
* @brief Alias for FieldNode representing a read-write field.
*/
template <uint32_t START_INT_BIT, uint32_t END_INT_BIT, uint32_t START_FRAC_BIT, uint32_t END_FRAC_BIT, typename PARENT_TYPE>
using FixpFieldRW = FixpFieldNode<FixpFieldWrMixin<FixpFieldBase<START_INT_BIT, END_INT_BIT, START_FRAC_BIT, END_FRAC_BIT, PARENT_TYPE>>,
FixpFieldRdMixin<FixpFieldBase<START_INT_BIT, END_INT_BIT, START_FRAC_BIT, END_FRAC_BIT, PARENT_TYPE>>>;
}


#endif

1 change: 1 addition & 0 deletions src/peakrdl_halcpp/include/halcpp_base.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#include <type_traits>
#include "halcpp_utils.h"
#include "field_node.h"
#include "fixp_field_node.h"
#include "reg_node.h"
#include "regfile_node.h"
#include "array_nodes.h"
Expand Down
26 changes: 15 additions & 11 deletions src/peakrdl_halcpp/templates/addrmap.h.j2
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ namespace {{ halnode.orig_type_name }}_nm
{
public:
{% for s, v, d in enum_strings|zip(enum_values, enum_desc) %}
static const halcpp::Const<{{ const_width }}, {{ v }}> {{ s }}; // {{ d }}
static inline const halcpp::Const<{{ const_width }}, {{ v }}> {{ s }}; // {{ d }}
{% endfor %}
};
{% endif %}
Expand All @@ -53,7 +53,11 @@ namespace {{ halnode.orig_type_name }}_nm

{# Add the fields to the register #}
{% for f in r.halchildren(children_type=HalFieldNode, skip_buses=skip_buses) %}
static halcpp::{{ f.cpp_access_type }}<{{ f.low }}, {{ f.high }}, TYPE> {{ f.inst_name }};
{% if f.__class__.__name__ == "HalFixpFieldNode" %}
static inline halcpp::{{ f.cpp_access_type }}<{{ f.low }}, {{ f.low + f.intwidth-1 }}, {{ f.low + f.intwidth }}, {{ f.high }}, TYPE> {{ f.inst_name }};
{% else %}
static inline halcpp::{{ f.cpp_access_type }}<{{ f.low }}, {{ f.high }}, TYPE> {{ f.inst_name }};
{% endif %}
{% endfor %}
{# Inherit the overloaded '=' operator from the base class if register can be write from software #}
{% if r.has_sw_writable %}
Expand All @@ -77,7 +81,7 @@ namespace {{ halnode.orig_type_name }}_nm
{
public:
{% for s, v, d in enum_strings|zip(enum_values, enum_desc) %}
static const halcpp::Const<{{ const_width }}, {{ v }}> {{ s }}; // {{ d }}
static inline const halcpp::Const<{{ const_width }}, {{ v }}> {{ s }}; // {{ d }}
{% endfor %}
};
{% endif %}
Expand All @@ -93,7 +97,7 @@ namespace {{ halnode.orig_type_name }}_nm

{# Add the fields to the register #}
{% for f in r.halchildren(children_type=HalFieldNode, skip_buses=skip_buses) %}
static halcpp::{{ f.cpp_access_type }}<{{ f.low }}, {{ f.high }}, TYPE> {{ f.inst_name }};
static inline halcpp::{{ f.cpp_access_type }}<{{ f.low }}, {{ f.high }}, TYPE> {{ f.inst_name }};
{% endfor %}
{# Inherit the overloaded '=' operator from the base class if register can be write from software #}
{% if r.has_sw_writable %}
Expand All @@ -114,7 +118,7 @@ namespace {{ halnode.orig_type_name }}_nm
using TYPE = {{ rf.orig_type_name|upper }}{{ rf.get_cls_tmpl_params() }};

{% for c in rf.halchildren((HalRegNode, HalRegfileNode), skip_buses=skip_buses) %}
static {{ c.orig_type_name|upper }}<0x{{ "%0x"|format(c.address_offset|int) }}, {{ c.width }}, TYPE> {{ c.inst_name }};
static inline {{ c.orig_type_name|upper }}<0x{{ "%0x"|format(c.address_offset|int) }}, {{ c.width }}, TYPE> {{ c.inst_name }};
{% endfor %}
};
{% endfor %}
Expand All @@ -140,17 +144,17 @@ public:

{% for c in halnode.halchildren(skip_buses=skip_buses) %}
{% if c.__class__.__name__ == "HalRegNode" and c.is_array %}
static halcpp::RegArrayNode<{{ halnode.orig_type_name }}_nm::{{ c.orig_type_name|upper }}, 0x{{ "%0x"|format(c.address_offset|int) }}, {{ c.width }}, {{ c.array_stride }}, TYPE , {{ c.array_dimensions|join(', ') }}> {{ c.inst_name }};
static inline halcpp::RegArrayNode<{{ halnode.orig_type_name }}_nm::{{ c.orig_type_name|upper }}, 0x{{ "%0x"|format(c.address_offset|int) }}, {{ c.width }}, {{ c.array_stride }}, TYPE , {{ c.array_dimensions|join(', ') }}> {{ c.inst_name }};
{% elif c.__class__.__name__ == "HalRegNode" %}
static {{ halnode.orig_type_name }}_nm::{{ c.orig_type_name|upper }}<0x{{ "%0x"|format(c.address_offset|int) }}, {{ c.width }}, TYPE> {{ c.inst_name }};
static inline {{ halnode.orig_type_name }}_nm::{{ c.orig_type_name|upper }}<0x{{ "%0x"|format(c.address_offset|int) }}, {{ c.width }}, TYPE> {{ c.inst_name }};
{% elif c.__class__.__name__ == "HalRegfileNode" and c.is_array %}
static halcpp::RegfileArrayNode<{{ halnode.orig_type_name }}_nm::{{ c.orig_type_name|upper }}, 0x{{ "%0x"|format(c.address_offset|int) }}, {{ c.array_stride }}, TYPE , {{ c.array_dimensions|join(', ') }}> {{ c.inst_name }};
static inline halcpp::RegfileArrayNode<{{ halnode.orig_type_name }}_nm::{{ c.orig_type_name|upper }}, 0x{{ "%0x"|format(c.address_offset|int) }}, {{ c.array_stride }}, TYPE , {{ c.array_dimensions|join(', ') }}> {{ c.inst_name }};
{% elif c.__class__.__name__ == "HalRegfileNode" %}
static {{ halnode.orig_type_name }}_nm::{{ c.orig_type_name|upper }}<0x{{ "%0x"|format(c.address_offset|int) }}, TYPE> {{ c.inst_name }};
static inline {{ halnode.orig_type_name }}_nm::{{ c.orig_type_name|upper }}<0x{{ "%0x"|format(c.address_offset|int) }}, TYPE> {{ c.inst_name }};
{% elif c.__class__.__name__ == "HalMemNode" %}
static {{ halnode.orig_type_name }}_nm::{{ c.parent.orig_type_name|upper }}<0x{{ "%0x"|format(c.address_offset|int) }}, {{ c.size }}, TYPE> {{ c.inst_name }};
static inline {{ halnode.orig_type_name }}_nm::{{ c.parent.orig_type_name|upper }}<0x{{ "%0x"|format(c.address_offset|int) }}, {{ c.size }}, TYPE> {{ c.inst_name }};
{% else %}
static {{ halutils.get_extern(c)|upper }}<0x{{ "%0x"|format(c.address_offset|int) }}, TYPE> {{ c.inst_name }};
static inline {{ halutils.get_extern(c)|upper }}<0x{{ "%0x"|format(c.address_offset|int) }}, TYPE> {{ c.inst_name }};
{% endif %}
{% endfor %}
};
Expand Down
Loading