RTL Specification

We will use a simple notation to define exactly what happens in the machine as the clock ticks. The notation is designed to help explain the individual steps taken within the processor as signals move between components. The language we will use allows for multiple operations to occur at the same time, which is what really happens in typical computer systems.

The language we will use is shown below using EBNF notation.


Digital machines work by passing signals through digital components, and synchronizing those movements using a master clock signal. We call the movement of a single signal between any two points in the machine a “transfer”. The places where those signals are held are called “registers”.

We can define the entire data transfer process a machine uses to do its work by creating a set of simple statements describing the movement of each signal between registers in the system. These movements occur at specific moments in time, and are driven by a clock.

The language we are using is called Register Transfer Level, because that is the level of detail we are working at. Working at this level we do not worry about how the clock is generated, or the actual electronics involved in moving data. We just focus on the fact that data moves between points in the system. If you think about it, we are describing what happens on the wires between parts in our system, at a very simple level.

We know there are two kinds of digital components in our systems: combinational and sequential.

Sequential Components

Registers are sequential components. When we work with RTL these registers do no processing of signals, they simply “hold” the values received until needed later. Registers receive a value to store only when directed to do so by a transfer statement naming that register. The register will not deliver that value unless we specify where it is to go using another transfer statement.

Combinational Components

Combinational components receive data and immediately process the bits forming a new set of bits. There is a time delay while this happens, but the process is immediate. If any signal arriving at a combinational component changes, that component immediately begins processing the new data. We will assume that any combinational elements involved in a transfer get their work done fast enough that the final result reaches the next holding point (register) before the clock ticks again.

Working at RTL level, we define the system as a collection of registers and simple signal transfers all driven by a clock. This level of detail is actually precise enough to derive a real machine, and modern systems use this technique in the design phase of construction.


In our system a “component” may include some combinational elements that modify the data received by an incoming signal before it is stored. There also may be additional combinational elements that further process those data bits before they move on in the next step of a sequence. RTL does not consider “components”, it tracks signals as they move, even inside of something we call a “component”.

RTL Notation

RTL focuses mainly on the signal movements between registers. We will augment the notation so we can define the registers involved, even though that is often ignored in such notation.

We will define our RTL language using EBNF:

rtl_spec ::= { register_def | simultaneous_transfer }

Although not commonly found in RTL examples, we will include notation to specify the names of registers and indicate how many bits they hold:

register_def ::= "def" identifier [ "<" size ">" ] ";"

identifier ::=  [A-z][A-Z0-9]+ [ "[" number "]" ] ;

We require all register names to be upper case. The square brackets are used to specify a group of registers. We call this group a memory element.

The actual movement of signals is defined using transfer statements:

simultaneous_transfer ::= [ guard ] transfer { “,” transfer } “;” ;

A “simultaneous_transfer” is the movement of one or more signals at the same point in time. The optional marker at the front of this transfer is used to show steps in a sequence that describes how the machine operates.

The optional “guard” will be discussed later.

transfer ::= destination "<-" source ;

Here destination refer to the component (or components) receiving the data, and source refers to the component delivering the data. Note that the source may involve combinational processing.

Destination Registers

The final resting point for a data transfer is always a sequential component we will call a “register”.

destination ::= register ( "," register } ;

This means a single transfer can be routed to one or more registers. This corresponds to the fact that a wire can be driven by only one source, but may be driving any number of other components.

Registers and they hold data until a clock tick moves things along. The transfer occurs within the time interval of one clock tick. The length of that tick is not specified in this notation.

Source Registers

The data to be transferred originates in another set of registers. Those source data items begin to move on a clock tick. Since combinational components to not stop the movement of data, they only transform (process) it somehow, we can show those calculations using a combinational expression involving the source register set.

source ::= expression ;

expression ::= term { operator term } ;

term ::= [ "NOT" ] term
         | register | constant | "(" expression ")" ;

The available combinational elements we include are these basic operations:

operator ::= "+" | "-" | "AND" | "OR" | "XOR" ;

Basically, these rules say we can form any expression we like involving addition, subtraction, and logical operations on data. The resulting value, after evaluation, is what ends p being transferred over wires,

Literal values can be expressed in standard forms:

constant ::=  number

number :: [ sign ] integer ;

integer ::= decimal | binary | hex ;

decimal ::= digit { digit } ;

digit ::= [0-9] ;

binary = "0b" { 0 | 1 } ;

hex ::= "0x" { hex-digit } ;

hex-digit ::= [0-9a-fA-F] ;

Finally, we name registers as follows:

register ::= register_name [ bit_spec ] ;

register_name ::= [A-Z]{ [A-Z0-9] } ;

We can specify that only certain bits in the register receive this signal. The notation looks like this:

bit_spec ::= "(" bit_range { "," bit_range } ")" ;

bit_range ::= number | number ":" number ;

The bit range specified contiguous bits with in a register. The comma allows combining non-contiguous bits into a single bit chunk.


The number of bits should match for both source and destination registers in any transfer.

Conditional Transfers

Sometimes, we want to only perform a transfer is some condition exists in the machine. The conditions will need to be evaluated and produce logical results. HEre is how we indicate this case:

guard  ::=  condition { "," condition } ":" ;

condition ::= time_marker | expression ;

time_marker ::= t{ [0-9] } ;

Time markers are traditionally used to indicate steps in a series of transfers.

Since we are allowing any expression to be used as a condition, we will evaluate the “true” or “false” value of such an expression based of whtther the resulting signal value is zero or non-sero. Zero indicated fa;se, anuthn else indicated true. (This is how C/C++ does this.)

Simple Example

Here is a simple image, showing a basic circuit. There is one combinational component in this circuit, and one sequential component.


And here is the RTL defining how this circuit functions:

D <- NOT Q ;

The associated Verilog specification for this part of a system looks like this:

module basic-component (
  8 d  ,        // Data Input
  9 clk    ,    // Clock Input
 11 q         // Q output
 12 );
 13 //-----------Input Ports---------------
 14 input d, clk; 
 17 output q;
 20 reg q;
 23 always @ ( posedge clk)
 26 begin
 27   d <= !q;
 28 end
 30 endmodule

You should see that we do not include the clock signal in the RTL, that signal is implied by the transfer statement. We also do not explicitly show simple combinational components. They can always be constructed using possibly complex boolean expressions.

Using RTL

A formal specification of a complete system involves a set of RTL statements. Typical RTL languages offer a few additions not shown here. For example, we can

show how part of the decoder works like this:

DCD[0-4] <- IR[10,3:0], DCD[9:5] <= IR[9:4] ;

This shows that we need to strip our 10 bits, spread our over the instruction code stored in IR.