THDL++ tutorial - basic templates and inheritance

<<Previous Next >>

Overview

This part of the tutorial presents templates - the key feature of THDL++ language. At a first glance, THDL++ templates are equivalent to VHDL generics. However, unlike VHDL, a template argument can resolve to almost everything: a number, an entity, a function, a policy class, a list, etc. The advanced uses of the templates will be shown in the next chapter of this tutorial, while this chapter will show the basic syntax and give some brief example.

Syntax

The template syntax in THDL++ is similar to C++ syntax:

template <Type1 Arg1, [Type2 Arg2 = default_value]> entity EntityName
{
}

To instantiate a templated entity, simply specify the arguments in angular brackets:

entity_name<arg1, [arg2]> instance_name(
    port1_name = port1_mapping,
    ...
);

Note that for simple entities not having lots of ports you can use the short declaration syntax:

entity entity_name(direction1 type1 port_name1,  ...)
{
);

Specifying port map for such entities will also be easier:

entity_name instance_name(
    port1_mapping,
    ...
);

Note that you can use the full port map syntax for an entity declared with inline port list, but not vice versa.

Example

Let's design a multi-level clock divider with variable amount of stages. E.g. a one-stage divider divides the input clock by 2, however, a 3-stage would divide it by 8:

template <int _Levels> entity ClockDivider(in logic src, out logic divided = '0')
{
    signal logic tmp;

    generate body if (_Levels gt 1)
    {
        ClockDivider<_Levels - 1> subdivider(src, tmp);
    }
    else if (_Levels == 0)
    {
        divided <= src;
    }
    else
    {
        tmp <= src;
    }

    generate proc if (_Levels ge 1)
    {
        process main(tmp.rising)
        {
            divided = !divided;
        }
    }
}

To test the divider in the simulator, add the following code to the file:

entity ClockTest
{
    ClockDivider<3> demo(
    src = auto,
    );

    process GenerateClock ()
    {
        demo.src = '0';
        wait(10ns);
        demo.src = '1';
        wait(10ns);
    }
}

simulate_entity(ClockTest);

Inheritance

Similarly to C++ classes, THDL++ entities can be inherited. For example, for a peripheral connected to a bus you can define the base entity containing all required ports (and some internal signals, auxiliary functions, typedefs and even processes), and simply derive other entities from it. The syntax is the following:

entity entity_name : base_entity_name
{
}

Note that the base keyword used inside an entity context will always refer to the base entity type.

See the next section of the tutorial to learn about really cool uses for THDL++ templates.

<<Previous Next >>