VHDL Circuit Design

Modelling and simulation of a polynomial evaluator

Aniekan Umanah
9 min readMay 20, 2021

Hello There! In this article we will become acquainted with and gain experience using VHDL (very high description language) code by evaluating a polynomial function. The design and modelling of digital circuitry will be done with the Quartus Prime software and a hardware description language (HDL) called VHDL. The VHDL code will be compiled and simulated using the ModelSim software, allowing the design’s functionality to be validated.

The GitHub repository containing the code used in this experiments, can be found at:

VHDL

VHDL is an international IEEE standard specification programming language for representing complex digital circuits at various levels of abstraction quickly and easily. VHDL allows for full control of the design process:

  • Design entry — design and develop the circuits.
  • Hardware generation — compile designs and generate the hardware.
  • Test sequence generation — develop test-benches.
  • Documentation — document design.
  • Verification — verify/simulate the actual circuit structure.
  • Design management — manage the full design process.

Abstraction Domains

VHDL can be used to describe electronic hardware at a variety of abstraction levels. We would look at two:

  • Structural — component is described in terms of an interconnection of more primitive parts.
  • Behavioural — component is described by defining its inputs and outputs response. Algorithmic code.

Structure

A VHDL programme requires three main elements to enable the software interpret the relevant operations:

  1. Libraries: specify the libraries for the relevant operation/ functions to be interpreted.
  2. Entity: defines the interface of the hardware element in terms of inputs and outputs. i.e the pin connections in a device.
  3. Architecture: describes the circuit is structured, and at what level it operates. All statements within an architecture are executed in parallel.

There can only be one design entity in the library with a given name and compromise of ENTITY declarations and one or more ARCHITECTURE bodies.

Polynomial Evaluator

Using a high level of abstraction, the code in the figure below models a digital circuit that evaluates a polynomial function for a fixed ‘x’ parameter value and four input variables (a0 to a3). The polynomial function is as follows:

Block representation of input and output signals
High-level VHDL Code — Polynomial Evaluator

NOTE: a3 is the first input, followed by a2 and so on, with the values of x fixed. All of the values a, x, and fx are integers. Every clock cycle, the value of fx is updated. Rearranged function to the same format as developed in the VHDL code:

The process is a sequential logic input that assigns ai a random value at each clock interval, and a condition is given for the reset to be set to 1 for a short period of time before and during the clock edge during the first clock transition. Reg1 is assigned the value of ai added to the corresponding register value and multiplied by x for the remainder of the process. As a result of the output being outside the process, fx receives reg1 + ai as an incorrect interim value and a correct value.

Verify operation of code:

The code is compiled and simulated on a waveform with the variables below. Assuming ai input values range from 0 - 7, and enter in series with a3 first. The x input value ranges from 0 - 3. The clock signal was set to a period of 50ns per cycle. since statements within the architecture are concurrent, fx would output two values: interim and correct.

Waveform analysis

From the figure we can see that a1 = 5, a2 = 6, a3 = 2, a0 = 0, and x = 3. We can calculate the theoretical outputs:

1st clock transition (+ve) trigger: (clk’EVENT AND clk =’1')

IF res = ‘1’ THEN reg1 =’0’:

reg1 <= 0,

ELSE reg1 = x * (ai +reg1);

reg1 <= x * (a3 + reg1) = 3 * (5 + 0) = 15,

fx <= reg1 + ai;

fx <= reg1 + a2 = 15 + 6 = 21

2nd clock transition (+ve) trigger: (clk’EVENT AND clk =’1')

ELSE reg1 = x * (ai +reg1);

reg1 <= x * (a2 + reg1) = 3 * (6 + 15) = 63,

fx <= reg1 + ai;

fx <= reg1 + a1 = 63+ 2= 65

3rd clock transition (+ve) trigger: (clk’EVENT AND clk =’1')

ELSE reg1 = x * (ai +reg1);

reg1 <= x * (a1 + reg1) = 3 * (2 + 63) = 195,

fx <= reg1 + ai;

fx <= reg1 + a0 = 195+ 0 = 195

The polynomial performs as expected!

Refinement

Although integer-defined I/Os are useful for testing code, in real-time development, getting the information to the final FPGA/ASICs design necessitates a low-level approach. The entities must be represented by a series of pins. Our input ranges remain the same, but they are now represented as bit inputs, with 3 bits input data (000 to 111) for ai and 2 bits input data (00 to 11) for x. The vector ranges from 0 to 7, and from 0 to 3 respectively. Because the input data is now a binary word, we must determine the size of the output vector to accommodate the polynomial’s maximum possible output.

The maximum value for ai and x are 7 and 3 respectively, therfore:

When two binary numbers are summed together, the output values can be up to the larger number plus one bit, and when you multiply two binary numbers together, the length of the result can be the sum of the two numbers being multiplied. As a result,

  • ai + reg1 could have a total of (9 + 1) = 10 bits
  • x * (ai + reg1) could be up to (10 + 2) = 12 bits
  • In actuality, the operator ‘+’ does not account for the overflow bits, limiting the final output to 11 bits.

It has been determined that fx must yield 9 bits. The right-hand side of the equation, reg1 = x *(ai + reg1), must be modified to restrict its output size to match fx. This involves ensuring that only the necessary parts of reg1 are used for calculation. Hence:

The output must also be adapted:

Low-level code

The code has been modified correctly, but it can still be refined further to use fewer resources. Based on the earlier theoretical calculations, we know that the codes will output the final answer after the third clock transition. The maximum value of reg1 in the 3rd transition will be:

This mean, the minimum size of register reg1 on the left hand side of the <=,

On the right hand side of the <= sign, the maximum number of bits which need to be taken:

The result lenght of the register has been reduced from 11 to 9 bits. The modified code:

Low-level refined code

Verify operation of code: binary(integer)

The code is compiled and output waveform is obserevd. The random vales assigned to ai: a3 = 000 (0), a2 = 101 (5), a1 = 100 (4), a0 = 001 (1). x is assigned 11 (3).

Waveform analysis

Theoretical output: fx

1st clock transition (+ve) trigger: (clk’EVENT AND clk =’1')

fx <= x*a3 + a2 = (3*0) + 5 = 5

2nd clock transition (+ve) trigger: (clk’EVENT AND clk =’1')

fx <= a1 + x*a2 + x²*a3 = 4 + (3*5) +(3³* 0) = 19

3rd clock transition (+ve) trigger: (clk’EVENT AND clk =’1')

fx <= a0 + x.a1 + x²*a2 + x³*a3 = 1 + (3*4) + (3²*5) + (3³*0)= 58

Results correspond!

Controlling the output

As the polynomial function is developed, the code outputs incorrect interim values of fx as well as correct values of fx before outputting the overall correct value after 4 clock pulses. We can modify the code so only the valid outputs are displayed at the output. We would use a rind counter to implement this.

The following have been identified in the code:

  • A SIGNAL register called control is specified and a default value is given
  • To write out the output of fx, an additional register (SIGNAL called datafinal has been used to allow an operation within an IF statement — to write to a register, which can then be used outside of the statement and process).
  • The control register is shifted so that it can function as a rind counter. The 1 in the register is shifted through the register every clock cycle and rotated back to the beginning every 4 clocks.
  • When bit 1 of the control register is ‘1’ (3rd clock pulse), the polynomial output at this clock cycle’s edge is calculated and written into the datafinal register.
  • Outside the process the contents of datafinal are written into the the output fx.
Control register operation
Waveform Analysis

Only the overall correct value is output!

Generic term

The code can be modified to produce any size polynomial or input vector. We use the GENERIC term to accomplish this. This enables the parameter selection to be assigned a value, that can then be used to define the sizes of the ENTITY inputs and outputs, as well as the internal registers (signals).

Let's assume the we want to use values of a or x (vector size) that are 2 to 4 bits wide. First we would determine the largest possible size range and use that to set the size of the output fx. In this case both ai and x would be 4 bits inputs, 2⁴ = 16 bits (0 to 15). Therefore, using the fx_max equation in refinement, the maximum number of bits that can be output is equal to 16.

Generic code

The following have been identified in the code:

  • GENERIC parameters n1, n2, n3, n4: specified as positive values.

The output waveform is the same as previous. We can modify the values of n1, and n2, and examine the result.

Make ai 4bit input and x 3bit input:

GENERIC (n1: positive:= 4; -- 4 bit input
n2: positive:= 3; -- 3 bit input
n3: positive:= 3;
n4: positive:= 16); -- 16 bit output
.
.
.
ELSIF (res = '0') THEN
reg1 <= x * (ai + reg1(n3-4 downto 0));
Waveform analysis

Verify operation:

From the figure: a3 = 0000 (0), a2 = 0111 (7), a1 = 0101 (5), a0 = 0010 (2)

3rd clock transition (+ve) trigger: (clk’EVENT AND clk =’1')

fx <= a0 + x.a1 + x²*a2 + x³*a3 = 2+ (2*5) + (2²*7) + (2³*0)= 40

Successful!

Conclusion

The code was simulated and tested using some test vectors and theoretically calculated to check if code operated as it should. Then code was then modified to emulate real time FPGA development and test using bit vectors. The code was then controlled to output the valid results using and this was then made to be generic.

Hope you found this useful, see you soon!

--

--