THDL++ tutorial - basics
What is THDL++?
THDL++ is a new generation hardware definition language, that provides the flexibility and scalability of C++ while having fully VHDL-compatible semantics. The key elements are, as in VHDL, entities, signals, processes and functions, but you can increase their flexibility exponentially by using inheritance, templates and policy classes. This tutorial covers all supported language features from the very basics up to advanced ones.
Requirements
To understand this tutorial, a basic knowledge of VHDL and C is required. It is also recommended to get familiar with C++ templates and policy classes before experimenting with advanced THDL++ features.
Entities, signals and processes
Let's start with creating a very trivial "divide input clock by 2" entity. Here is a sample VHDL code for that:
use IEEE.STD_LOGIC_1164.ALL;
entity Divider_Entity is
Port (
Input_Clock : in std_logic;
Output_Clock : out std_logic
);
end entity Divider_Entity;
architecture Behavioral of Divider_Entity is
signal Temp_Clock : std_logic;
begin
main : process (Input_Clock) is
begin
if rising_edge(Input_Clock) then
Temp_Clock <= not Temp_Clock;
end if;
end process main;
Output_Clock <= Temp_Clock;
end architecture Behavioral;
Let's now create an equivalent entity in THDL++. Start VisualHDL, select "New Project", choose "empty project". Finally, choose "File->New Source File", type in "test" as the file name, and enter the following text in the editor:
{
port
{
in logic InputClock;
out logic OutputClock;
}
signal logic TempClock = '0'; //Initial value is 0
process main (InputClock.rising)
{
TempClock = !TempClock;
}
OutputClock = TempClock;
}
simulate_entity(DividerEntity);
The simulate_entity statement defines the root entity that is used when generating code for simulation. If you have Xilinx ISE toolchain installed, you can press F7 to build ISIM simulation model, or F5 to build and run it. If you don't have the Xilinx tools, simply press Ctrl+F7 to generate VHDL code and examine the generated .vhd files, that appear in the Project Explorer.
Note that you did not define any clock generation statements here, so, you won't see much in the simulator. To put some life into our example, remove or comment out the simulate_entity statement and add the following code to the end of the file:
{
DividerEntity divider(
InputClock = auto,
OutputClock = auto
);
process GenerateClock ()
{
divider.InputClock = '0';
wait(10ns);
divider.InputClock = '1';
wait(10ns);
}
}
simulate_entity(ClockTest);
Formalization
Let's define the syntax for THDL++ entities, signals and processes formally. Please note that THDL++ supports both C++-style comments (//) and VHDL-style comments (--). Although no C-style comments (/*) are supported, you can easily comment/uncomment a block of lines by selecting them in VisualHDL editor and pressing the '/' key.
Entities
The general syntax for defining entities is the following:
{
//Entity contents
}
Entities can contain everything, that VHDL entities can: ports, signals, processes, implicit processes. Additionally, THDL++ entities can contain classes, functions, constants and typedefs. Unlike VHDL, there is no explicit requirement to list ports before signals; the THDL++ compiler automatically figures out the correct parsing order. Note that every THDL++ entity used in the design will be compiled to a corresponding VHDL entity having the same set of ports, signals and processes.
Signals and ports
Signals and ports can be declared using 2 syntax forms. Blocks:
{
TypeName SignalName;
TypeName2 SignalName2[, SignalName3];
}
and independent declarations:
The port declarations are similar, but require explicit direction specification (in, out or inout).
Types
THDL++ supports all main VHDL data types, however, it uses C-style names:
THDL++ type | Equivalent VHDL type |
int | integer |
bool | boolean |
logic | std_logic with unsigned operations |
ulogic | std_logic with unsigned operations |
slogic | std_logic with signed operations |
void | N/A |
bool | boolean |
Vectors are defined almost like in C:
signal logic[index1 to index2] SignalName2;
signal logic[size1][size2] SignalName3;
Note that logic[N] is equivalent to VHDL std_logic_vector(N - 1 downto 0). Also, there is only one "to" keyword (unlike to/downto in VHDL).
Hint: you can make your code more readable by using typedefs. Here is an example:
{
typedef logic[16] CodeWord;
typedef CodeWord[8] ArrayType;
port
{
in ArrayType Input;
out ArrayType Output;
}
}
Note that ArrayType can now be used from any entity using its full name. Example:
{
signal TestEntity.ArrayType MyArraySignal;
}
Processes
THDL++ signals and processes inherit the VHDL semantics. Moreover, every processes is compiled to exactly one VHDL process. Here is the syntax:
{
//Process body
}
The sensitivity list can either simply enumerate some signals, like in VHDL, or use one of special forms:
Sensitivity list syntax | VHDL equivalent |
SignalName.rising | The resulting VHDL process will be sensitive to SignalName and its body will be enclosed into "if rising_edge(SignalName)" block. |
SignalName.falling | Similar to SignalName.rising |
any | The resulting VHDL process will be sensitive to ALL signals read from the process. THDL++ compiler will automatically generate the sensitivity list based on process body. |
The process body syntax is very similar to C/C++ one. You can declare local variables at random places, you can use ++, +=, &=,^= and similar operators, you can use either single-statement or multiple-statement if and for statements. You can even use the foreach() statement to enumerate components or compile-time lists. The process body syntax is described in the next section.
Implicit processes
The implicit processes should be declared inside entities, exactly like in VHDL. Anything in the form of "signal = expression;" can be treated as an implicit process.
Assignment operators
Unlike VHDL, THDL++ does not enforce different assignment operators for signals and processes. The C-style '=' operator replaces them both. However, you can still use the VHDL-style ':=' and '<=' operators, if you want to enforce the signal/variable checks.