This section discusses all possible declarations that are allowed
in an Arx component descripition. Declarations can be
made in the first part of a component description, before the
occerrence of keyword begin
.
There are two categories of declarations in Arx:
Line-style declarations are characterized by the occurence of a keyword related to the declaration for each declared item. There are three type of line-style declarations:
In the code, they should occur in the order given above.
Section-style declarations are characterized by a single keyword indicating the declaration type followed by one or more items of the declared type. The following section-style declarations exist:
There is no imposed order on the declaration as long as the principle of define before use is respected. It is possible to have multiple sections of the same type, e.g. a section of constant declarations followed by register declarations in which the constants are used and then a second section of constant declarations and a section of variable declarations in which reference is made to the second section of constants.
Below, each type of declaration is discussed in a separate section.
Generics create the possibility to parameterize a hardware description. Typical paramters are word lengths, memory depths, etc. A generic declaration has the following form:
<generic name>: generic <data type> = <value>
The following line of Arx code contains an example of a generic declaration:
word_length: generic integer = 8
The page on instantiation explains how generics can be used in hierarchical hardware descriptions.
The current version of Arx does not support negative constants for <value>.
Generic types take the concept of parameterizability a step further and make it possible to change data types in a component at instantiation time. One can say that the use of generic types enhances Arx with type polymorphism.
The syntax for a generic type declaration is:
<generic type name>: generic type = <type value>
The following line of Arx code contains an example of a generic type declaration:
T_IO: generic type = bitvector(8)
The page on instantiation explains how generic types can be used in hierarchical hardware descriptions and how they can be combined with generics. An example of polymorphic instantiation is provided there.
The I/O declaration specifies the signals with which a component interfaces with the external world. An I/O signal is either an input or an output. Bidrectional signals are not supported. An I/O declaration has the following form:
<signal name>: <direction> <type>
The two possible values for <direction> are in
for an input signal
and out
for an output signal. <type> can be any allowed type (see
the page on data types),
including the type name of a generic type.
The following lines of Arx code contain a few examples of I/O declarations:
data_in: in bitvector(8) clear: in bit data_out: out bitvector(8)
Examples of I/O declarations in the context of entire component descriptions can be found on the pages explaining components and instantiation.
Constants are mechanism to assign a symbolic name to entities the value of which can be computed at compile time. As opposed to generics, their values cannot be directly changed at instantiation time. They can be changed indirectly, though, when the value of a constant is an expression that depends on a generic. A section of constant declarations has the following syntax:
constant +{ <name>: <type> = <value> }+
So, <value> can be an expression that evaluates to a constant at
compile time. The Arx code below shows an example of a
constant-declaration section (where word_length
is supposed to be a generic):
constant height: integer = 648 width : integer = 2*height hwl : integer = word_length/2
Types that are only relevant locally inside a component can be defined in the type-declaration section of the declarations. They assign a symbolic name to a type and make it possible to use this symbolic name for the types of local signals. In this way, they keep component descriptions flexible. If data types inside a description need to be modified, it is sufficient to revise the type declarations.
As opposed to
the declarations mentioned above, the keyword type
needs to be
used to indicate the start of the type-declaration section.
The following syntax is used:
type +{ <type name> : <type> }+
The code fragment below shows a set of type declarations that could be
used for intermediate types in a chain of additions where the result
is each time one bit wider than the input (word_length
is supposed
to be a generic or a constant):
type T_in : signed(word_length) T_in_p1: signed(word_length+1) T_in_p2: signed(word_length+2)
Register signals, i.e. signals that keep their value from one clock cyle to the next (see also the explanation of register-transfer level modeling), are declared in a register-declaration section which has the following syntax:
register +{ <name> *{, <name>}* : <type> = <reset value> }+
It is mandatory that all registers receive a reset value which should
be provided after the equal sign (=
).
Here is an example of a register-declaration section (T1
and T2
are
supposed to be generic or locally declared types):
register a, b: T1 = 0 c : T2 = 511 p, q: boolean = true
As opposed to register signals, variable signals are memoryless. They correspond to wires in hardware and are found in the combinational-logic part of the register-transfer level model. Their declaration is very similar to the one of registers, except for the fact that no reset value should be provided:
variable +{ <name> +{, <name>}* : <type> }+
If the above example declared variables instead of registers, it would look like this:
variable a, b: T1 c : T2 p, q: boolean