3. Hardware description

UðzÞ

K ¼ k

where

62 Field - Programmable Gate Array

Eq. (17) by z�<sup>1</sup>

Further simplification yields

Solving the above equation for UðzÞ we have:

Expanding terms:

It is well known that:

which is quite similar to Eq. (14).

and

<sup>E</sup>ðz<sup>Þ</sup> <sup>¼</sup> <sup>K</sup> <sup>z</sup> <sup>þ</sup> <sup>A</sup>

<sup>A</sup> <sup>¼</sup> <sup>ω</sup>1Ts � <sup>2</sup> ω1Ts þ 2

<sup>B</sup> <sup>¼</sup> <sup>ω</sup>2Ts � <sup>2</sup> ω2Ts þ 2

From a digital point of view, Eq. (17) is still inconvenient. In order to obtain a suitable digital representation, it is necessary to represent this equation as a difference equation. This can be performed by multiplying the numerator and the denominator of the right-hand side of

<sup>E</sup>ðz<sup>Þ</sup> <sup>¼</sup> <sup>K</sup> <sup>1</sup> <sup>þ</sup> Az�<sup>1</sup>

<sup>U</sup>ðzÞ þ BUðzÞz�<sup>1</sup> <sup>¼</sup> KEðzÞ þ KAEðzÞz�<sup>1</sup>

<sup>U</sup>ðzÞ ¼ KEðzÞ þ KAEðzÞz�<sup>1</sup> � BUðzÞz�<sup>1</sup>

is delayed by one sample. Thus, the lead compensator takes the following form:

UðzÞ

<sup>U</sup>ðzÞð<sup>1</sup> <sup>þ</sup> Bz�<sup>1</sup>

therefore, the discrete lead compensator filter can be expressed as:

. This is equivalent to the shifting operation in the time domain, where the signal

1 þ Bz�<sup>1</sup>

Þ ¼ KEðzÞð<sup>1</sup> <sup>þ</sup> Az�<sup>1</sup>

Þ

EðzÞ ¼ eðkÞ (18)

<sup>E</sup>ðzÞz�<sup>1</sup> <sup>¼</sup> <sup>e</sup>ð<sup>k</sup> � <sup>1</sup><sup>Þ</sup> (19)

uðkÞ ¼ KeðkÞ þ KAeðk � 1Þ � Buðk � 1Þ (20)

ω1Ts þ 2 ω2Ts þ 2

<sup>z</sup> <sup>þ</sup> <sup>B</sup> (17)

There are important features that the reader must consider before starting the description process. First, the nature of the feedback signal should be considered. If the sensor which measures the variable to be controlled has an analogue nature, it is necessary to use an analogue to digital converter (ADC) which has an output with a fixed bit width. In order to avoid performing arithmetic operations between signals of different bit width, it is strongly suggested that the setpoint or reference has the same bit width as the measured variable. Additionally, if the error signal has a wide bus width, let us say wider than 16 bits, this signal can be saturated in order to avoid wider bus widths in preceding computations.

The second aspect to consider is the number and characteristics of the embedded multipliers or DSP slices that the target device possesses. Most of the FPGAs available in the market have multipliers with a fixed bus width, 18 · 18 bits for instance. For any other bus-width, the synthesis tool shall use logic resources to build a customized multiplier instead of using those available in the hardware. This bad practice leads to major resource utilization.

In summary, the error signal and the controller gains shall have a bus width, which matches the bus width of the available embedded multipliers. For example, the available multipliers have an 18 · 18 bus width, the error signal has 16 bits width, and the controller gains are required to have a fixed point format 16.16. Then a possible solution that does not imply the usage of a customized multiplier is to expand the bus width of error and gains to 18 and 36 bits, respectively, being in the latter signal, 18 bits for the integer part and the remaining 18 bits for the fractional part. Thus, the synthesis tool would use two 18 · 18 embedded multipliers. Above is possible whenever the bus width of error signal and gains be the multiple of the bus width of the embedded multipliers and while the extension of the signals preserves their signs.

Finally, the controller output must be congruent with the nature of the actuators. If we deal with an analogue actuator, it is necessary to include a digital to analogue converter (DAC) which, as the case of the ADC, has a fixed bus width; therefore, the controller output must agree such width. However, depending on the polynomial degree of the filter and the bus width of the used multipliers, the controller output eventually could have a wider bus width; so, it would be necessary to saturate and truncate decimal data from the controller output signal.

In this section, we shall describe the design of a PID digital controller; however, the reader could easily modify the proposed design for most of the control above laws. The resultant design is implemented in VHDL; it is validated in a cosimulation environment, and finally, it is tested in a real-life application to control the position of a brushed DC servo motor.

The PID digital filter seen as a black-box module is depicted in Figure 1. The ERR signal represents the error signal, which is the difference between the setpoint and the feedback data. Similarly, the signals Q0, Q1, and Q2 are the controller gains, and their value depends on Kp, Ti, Td, and Ts as it is explained in previous sections. On the other side, the UOUT signal is the filter output, which is feed forwardly to the actuator. CLK and RST are the master clock and master reset signals, respectively.

Table 1 summarizes the signals properties of the PID\_Digital\_Controller module. It is important to clear that the error signal and the controller gains have 16 and 32 bits of width,

Figure 1. Black-box module of PID digital filter.


Table 1. List of signals properties of PID digital controller.

respectively; above to match the standard data size of most of the common programming languages; however, these signals are internally expanded to 18 and 36 bits in order to use two 18 · 18 embedded multipliers as previously mentioned. Additionally, the controller gains are given in a fixed point format 16.16, i.e., the 16 most significant bits represent the integer part while the 16 less significant represent the fractional part.

Figure 2 illustrates a block diagram of the digital PID controller. This module comprises five standard load registers, two multiplexors, a multiplier, an adder, a saturator, and a finite state machine (FSM). White blocks represent pure combinational processes, whereas gray ones represent sequential and synchronous processes.

The data path starts at the input registers. At this point, the multiplexors bypass the corresponding signal error and controller gains selected by the SEL signal, which is driven by the FSM, the multiplier and adder accumulate this product with the previous result and so on

Figure 2. Block diagram of digital PID controller.

the next terms. At the final stage, a saturator trims the bus width of the controller output and saturates its value to 16 bits.

Signals EK0, EK1, and EK2 have 16 bits of width; however, at the multiplexor output, their sign is extended two bits, i.e., the EMUX signal has 18 bits of width. Similarly, the signals Q0, Q1, and Q2 have 32 bits, and at the multiplexor output, QMUX, these signals are extended to 36 bits. The product of error signal as per its corresponding coefficient has 54 bits; nevertheless, this signal is extended again in order to avoid a possible overflow because of the recurrent addition with previous results. Thus, given that there are three sums involved in the solution of the control algorithm, the signal MULT is extended three bits more to obtain a bus width of 57 bits finally. Signals ACCUM and URES also have a 57 bits bus width.

The pipelined structure of registers at the top-left corner, depicted in Figure 2, is planned to latch the error signals eðkÞ, eðk � 1Þ, and eðk � 2Þ when signal TS is asserted. On the other hand, the register located at the top-right corner together with the adder perform the accumulation process through the assertion of signal LDS. And finally, the last register in the data path serves only as a holder for the final result of the algorithm. This latter register loads data when LDR is asserted.

Figure 3 illustrates the operation of the Digital\_PID\_Controller\_FSM; it includes five states. The first state is an idle state, which waits for the assertion of the sampling signal TS. Second, third, and fourth states perform the multiplication and accumulation of the filter terms, and such partial results are added to the previous final result. The fifth state only asserts the signal LDR to latch the final result and jumps directly to the first state in order to repeat the whole process.

The following source code corresponds to the top-level entity of the design. Its architecture is structural since it is composed of many other components as mentioned above, in total there are 12 instances and 3 concurrent assignations.

Code 1. Digital\_PID\_Controller.vhd. Library IEEE;

use IEEE.std\_logic\_1164.all;

respectively; above to match the standard data size of most of the common programming languages; however, these signals are internally expanded to 18 and 36 bits in order to use two 18 · 18 embedded multipliers as previously mentioned. Additionally, the controller gains are given in a fixed point format 16.16, i.e., the 16 most significant bits represent the integer

Signal name Direction Bus width Description

CLK Input 1 Master clock TS Input 1 Sampling signal

RST Input 1 Active low master reset

Q0 Input 32 Filter coefficient q0 Q1 Input 32 Filter coefficient q1 Q2 Input 32 Filter coefficient q2 UOUT Output 16 Controller output

ERR Input 16 Two's complement error signal

Figure 2 illustrates a block diagram of the digital PID controller. This module comprises five standard load registers, two multiplexors, a multiplier, an adder, a saturator, and a finite state machine (FSM). White blocks represent pure combinational processes, whereas gray ones

The data path starts at the input registers. At this point, the multiplexors bypass the corresponding signal error and controller gains selected by the SEL signal, which is driven by the FSM, the multiplier and adder accumulate this product with the previous result and so on

part while the 16 less significant represent the fractional part.

represent sequential and synchronous processes.

Table 1. List of signals properties of PID digital controller.

Figure 1. Black-box module of PID digital filter.

64 Field - Programmable Gate Array

```
Entity Digital_PID_Filter is
  port(
  RST : in std_logic;
  CLK : in std_logic;
  TS : in std_logic;
  ERR: in std_logic_vector(15 downto 0);
  Q0 : in std_logic_vector(31 downto 0);
  Q1 : in std_logic_vector(31 downto 0);
  Q2 : in std_logic_vector(31 downto 0);
  UOUT : out std_logic_vector(15 downto 0)
  );
end Digital_PID_Controller;
Architecture Structural of Digital_PID_Controller is
Component Digital_PID_Controller_FSM is port(
  RST : in std_logic;
  CLK : in std_logic;
  TS : in std_logic;
  LDS : out std_logic;
  LDR : out std_logic;
  SEL : out std_logic_vector(1 downto 0));
end Component;
Component LoadRegister is generic(n : integer := 8);
port(
RST : in std_logic;
CLK : in std_logic;
LDR : in std_logic;
DIN : in std_logic_vector(n � 1 downto 0);
DOUT : out std_logic_vector(n � 1 downto 0));
end Component;
```
Component Multiplexor3To1 is generic(n : integer := 8); port( DIN0 : in std\_logic\_vector(n - 1 downto 0); DIN1 : in std\_logic\_vector(n - 1 downto 0); DIN2 : in std\_logic\_vector(n - 1 downto 0); SEL : in std\_logic\_vector(1 downto 0); DOUT : out std\_logic\_vector(n - 1 downto 0)); end Component; Component Multiplier is generic(m, n : integer := 9); port( OPA : in std\_logic\_vector(m - 1 downto 0); OPB : in std\_logic\_vector(n - 1 downto 0); RES : out std\_logic\_vector((m + n - 1) downto 0)); end Component; Component Adder is generic(n : integer := 8); port( OPA : in std\_logic\_vector(n - 1 downto 0); OPB : in std\_logic\_vector(n - 1 downto 0); RES : out std\_logic\_vector(n - 1 downto 0)); end Component; Component Saturator57To16 is port( DIN : in std\_logic\_vector(56 downto 0); DOUT : out std\_logic\_vector(15 downto 0)); end Component; --Signals declaration--------------------------------------------------------- signal LDS : std\_logic; signal LDR : std\_logic; signal SEL : std\_logic\_vector(1 downto 0); signal EK0 : std\_logic\_vector(15 downto 0); signal EK1 : std\_logic\_vector(15 downto 0);

Entity Digital\_PID\_Filter is

end Digital\_PID\_Controller;

RST : in std\_logic; CLK : in std\_logic; TS : in std\_logic;

LDS : out std\_logic; LDR : out std\_logic;

end Component;

RST : in std\_logic; CLK : in std\_logic; LDR : in std\_logic;

end Component;

port(

ERR: in std\_logic\_vector(15 downto 0); Q0 : in std\_logic\_vector(31 downto 0); Q1 : in std\_logic\_vector(31 downto 0); Q2 : in std\_logic\_vector(31 downto 0);

UOUT : out std\_logic\_vector(15 downto 0)

Architecture Structural of Digital\_PID\_Controller is

Component Digital\_PID\_Controller\_FSM is port(

SEL : out std\_logic\_vector(1 downto 0));

DIN : in std\_logic\_vector(n � 1 downto 0);

DOUT : out std\_logic\_vector(n � 1 downto 0));

Component LoadRegister is generic(n : integer := 8);


RST : in std\_logic; CLK : in std\_logic; TS : in std\_logic;

66 Field - Programmable Gate Array

port(

);

signal EK2 : std\_logic\_vector(15 downto 0); signal EAUX : std\_logic\_vector(15 downto 0); signal EMUX : std\_logic\_vector(17 downto 0); signal QAUX : std\_logic\_vector(31 downto 0); signal QMUX : std\_logic\_vector(35 downto 0); signal MULT : std\_logic\_vector(53 downto 0); signal MULE : std\_logic\_vector(56 downto 0); signal USUM : std\_logic\_vector(56 downto 0); signal ACCU : std\_logic\_vector(56 downto 0); signal URES : std\_logic\_vector(56 downto 0); begin


EMUX <= EAUX(15) & EAUX(15) & EAUX;

QMUX <= QAUX(31) & QAUX(31) & QAUX(31) & QAUX(31) & QAUX;

MULE <= MULT(53) & MULT(53) & MULT(53) & MULT;


U01 : Digital\_PID\_Controller\_FSM port map(RST, CLK, TS, LDS, LDR, SEL);

U02 : LoadRegister generic map(16) port map(RST, CLK, TS, ERR, EK0);

U03 : LoadRegister generic map(16) port map(RST, CLK, TS, EK0, EK1);

U04 : LoadRegister generic map(16) port map(RST, CLK, TS, EK1, EK2);

U05 : Multiplexor3To1 generic map(16) port map(EK0, EK1, EK2, SEL, EAUX);

U06 : Multiplexor3To1 generic map(32) port map(Q0, Q1, Q2, SEL, QAUX);

U07 : Multiplier generic map(18, 36) port map(EMUX, QMUX, MULT);

U08 : Adder generic map(57) port map(MULE, ACCU, USUM);

U09 : LoadRegister generic map(57) port map(RST, CLK, LDS, USUM, ACCU);

U10 : LoadRegister generic map(57) port map(RST, CLK, LDR, ACCU, URES);

U11 : Saturator57To16 port map(URES, UOUT);


end Structural;

Figure 3. Finite state machine of the digital PID filter.

signal EK2 : std\_logic\_vector(15 downto 0);

68 Field - Programmable Gate Array

begin

signal EAUX : std\_logic\_vector(15 downto 0); signal EMUX : std\_logic\_vector(17 downto 0); signal QAUX : std\_logic\_vector(31 downto 0); signal QMUX : std\_logic\_vector(35 downto 0); signal MULT : std\_logic\_vector(53 downto 0); signal MULE : std\_logic\_vector(56 downto 0); signal USUM : std\_logic\_vector(56 downto 0); signal ACCU : std\_logic\_vector(56 downto 0); signal URES : std\_logic\_vector(56 downto 0);


MULE <= MULT(53) & MULT(53) & MULT(53) & MULT; --Component instances------------------------------------------------------

QMUX <= QAUX(31) & QAUX(31) & QAUX(31) & QAUX(31) & QAUX;

U01 : Digital\_PID\_Controller\_FSM port map(RST, CLK, TS, LDS, LDR, SEL);

U05 : Multiplexor3To1 generic map(16) port map(EK0, EK1, EK2, SEL, EAUX);

U09 : LoadRegister generic map(57) port map(RST, CLK, LDS, USUM, ACCU); U10 : LoadRegister generic map(57) port map(RST, CLK, LDR, ACCU, URES);

U06 : Multiplexor3To1 generic map(32) port map(Q0, Q1, Q2, SEL, QAUX);

U07 : Multiplier generic map(18, 36) port map(EMUX, QMUX, MULT);

U08 : Adder generic map(57) port map(MULE, ACCU, USUM);

U11 : Saturator57To16 port map(URES, UOUT);

end Structural;


U02 : LoadRegister generic map(16) port map(RST, CLK, TS, ERR, EK0); U03 : LoadRegister generic map(16) port map(RST, CLK, TS, EK0, EK1); U04 : LoadRegister generic map(16) port map(RST, CLK, TS, EK1, EK2);

EMUX <= EAUX(15) & EAUX(15) & EAUX;

The following code corresponds to the implementation of the FSM depicted in Figure 3. It has a behavioral architecture since it is composed by a couple of processes; the first one includes the combinational logic, which performs the state transitions and sets the output logic. The second process emulates the behavior of a D-type flip-flop, which updates the data with each rising-edge of the master clock signal.

Code 2. Digital\_PID\_Controller\_FSM.vhd. Library IEEE; use IEEE.std\_logic\_1164.all; Entity Digital\_PID\_Controller\_FSM is port( RST : in std\_logic; CLK : in std\_logic;

```
TS : in std_logic;
  LDS : out std_logic;
  LDR : out std_logic;
  SEL : out std_logic_vector(1 downto 0)
  );
end Digital_PID_Controller_FSM;
Architecture Behavioral of Digital_PID_Controller_FSM is
signal Sp, Sn : std_logic_vector(2 downto 0);
begin
  combinational : process(Sp, TS)
  begin
case Sp is
when "000" =>
LDS <= '0';
LDR <= '0';
SEL <= "XX";
if TS = '1' then
Sn <= "001";
else
Sn <= Sp;
end if;
when "001" =>
LDS <= '1';
LDR <= '0';
SEL <= "00";
Sn <= "010";
when "010" =>
LDS <= '1';
LDR <= '0';
```

```
SEL <= "01";
Sn <= "011";
when "011" =>
LDS <= '1';
LDR <= '0';
SEL <= "10";
Sn <= "100";
when others =>
LDS <= '0';
LDR <= '1';
SEL <= "XX";
Sn <= "000";
end case;
  end process Combinational;
  Sequential : process(RST, CLK)
  begin
if RST = '0' then
Sp <= "000";
elsif CLK'event and CLK = '1' then
Sp <= Sn;
end if;
  end process Sequential;
```
TS : in std\_logic;

70 Field - Programmable Gate Array

);

begin

begin case Sp is

LDS <= '0'; LDR <= '0';

SEL <= "XX"; if TS = '1' then Sn <= "001";

else

Sn <= Sp;

when "001" =>

when "010" =>

LDS <= '1'; LDR <= '0';

LDS <= '1'; LDR <= '0'; SEL <= "00"; Sn <= "010";

end if;

when "000" =>

LDS : out std\_logic; LDR : out std\_logic;

SEL : out std\_logic\_vector(1 downto 0)

signal Sp, Sn : std\_logic\_vector(2 downto 0);

Architecture Behavioral of Digital\_PID\_Controller\_FSM is

end Digital\_PID\_Controller\_FSM;

combinational : process(Sp, TS)

end Behavioral;

The LoadRegister module is labeled as Register in Figure 2. The objective of this module is to store some particular value. While LDR is asserted, this module stores the value present at the input DIN, and the result is reflected in the output until the next clock event. When LDR is low, the register preserves the last latched value.

Code 3. LoadRegister.vhd. Library IEEE; use IEEE.std\_logic\_1164.all;

```
Entity LoadRegister is
generic(n : integer := 8);
port(
RST : in std_logic;
CLK : in std_logic;
LDR : in std_logic;
DIN : in std_logic_vector(n � 1 downto 0);
DOUT : out std_logic_vector(n � 1 downto 0)
);
end LoadRegister;
Architecture Behavioral of LoadRegister is
signal Qp, Qn : std_logic_vector(n � 1 downto 0);
begin
Combinational : process(Qp, LDR, DIN)
begin
if LDR = '1' then
Qn <= DIN;
else
Qn <= Qp;
end if;
DOUT <= Qp;
end process Combinational;
Sequential : process(RST, CLK)
begin
if RST = '0' then
Qp <= (others => '0');
elsif CLK'event and CLK = '1' then
Qp <= Qn;
end if;
```
end process Sequential;

end Behavioral;

Entity LoadRegister is generic(n : integer := 8);

72 Field - Programmable Gate Array

RST : in std\_logic; CLK : in std\_logic; LDR : in std\_logic;

end LoadRegister;

DIN : in std\_logic\_vector(n � 1 downto 0);

Architecture Behavioral of LoadRegister is

Combinational : process(Qp, LDR, DIN)

signal Qp, Qn : std\_logic\_vector(n � 1 downto 0);

DOUT : out std\_logic\_vector(n � 1 downto 0)

port(

);

begin

begin

else

if LDR = '1' then

Qn <= DIN;

Qn <= Qp;

DOUT <= Qp;

if RST = '0' then

Qp <= Qn;

end if;

Qp <= (others => '0');

end process Combinational;

Sequential : process(RST, CLK)

elsif CLK'event and CLK = '1' then

end if;

begin

The multiplexor in the following code allows directing each sample of the error signal with their corresponding coefficient.

Code 4. Multiplexor3To1.vhd. Library IEEE;

use IEEE.std\_logic\_1164.all;

Entity Multiplexor3To1 is

generic(n : integer := 8);

port(

DIN0 : in std\_logic\_vector(n - 1 downto 0);

DIN1 : in std\_logic\_vector(n - 1 downto 0);

DIN2 : in std\_logic\_vector(n - 1 downto 0);

SEL : in std\_logic\_vector(1 downto 0);

DOUT : out std\_logic\_vector(n - 1 downto 0)

);

end Multiplexor3To1;

Architecture DataFlow of Multiplexor3To1 is

begin

With SEL Select DOUT <=

DIN0 when "00", DIN1 when "01", DIN2 when "10", (others =>'0') when others;

end DataFlow;

The following module performs an arithmetic sum between two vectors. It is worth to note that this module does not depend on the clock.

Code 5. Adder.vhd. Library IEEE; use IEEE.std\_logic\_1164.all; use IEEE.std\_logic\_unsigned.all; Entity Adder is generic(n : integer := 8);

port(

OPA : in std\_logic\_vector(n � 1 downto 0); OPB : in std\_logic\_vector(n � 1 downto 0);

RES : out std\_logic\_vector(n � 1 downto 0)

);

end Adder;

Architecture DataFlow of Adder is

begin

RES <= OPA + OPB;

end DataFlow;

Similarly, the multiplier performs an arithmetic product between two vectors; however, it is important to preserve the sign of the result; therefore, it is included in the IEEE.std\_logic\_arith library.

Code 6. Multiplier.vhd. Library IEEE; use IEEE.std\_logic\_1164.all; use IEEE.std\_logic\_arith.all; Entity Multiplier is generic(m, n : integer := 9); port( OPA : in std\_logic\_vector(m � 1 downto 0); OPB : in std\_logic\_vector(n � 1 downto 0); RES : out std\_logic\_vector((m + n � 1) downto 0) ); end Multiplier; Architecture DataFlow of Multiplier is begin RES <= signed(OPA) \* signed(OPB); end DataFlow;

The last module is provided in the Code 7, which is used to limit the output. For this particular case, the controller output has been adjusted to 16 bits in order to convert this value to an analogue signal using a DAC. Since the controller gains are given in a fixed point format 16.16, the less significant bits of the controller output are trimmed, i.e., only the integer part of the control output is considered during the digital to analogue conversion.

port(

74 Field - Programmable Gate Array

);

end Adder;

RES <= OPA + OPB;

Code 6. Multiplier.vhd.

use IEEE.std\_logic\_1164.all; use IEEE.std\_logic\_arith.all;

generic(m, n : integer := 9);

OPA : in std\_logic\_vector(m � 1 downto 0); OPB : in std\_logic\_vector(n � 1 downto 0);

Architecture DataFlow of Multiplier is

RES <= signed(OPA) \* signed(OPB);

RES : out std\_logic\_vector((m + n � 1) downto 0)

end DataFlow;

Library IEEE;

Entity Multiplier is

begin

library.

port(

);

begin

end Multiplier;

end DataFlow;

OPA : in std\_logic\_vector(n � 1 downto 0);

OPB : in std\_logic\_vector(n � 1 downto 0);

RES : out std\_logic\_vector(n � 1 downto 0)

Similarly, the multiplier performs an arithmetic product between two vectors; however, it is important to preserve the sign of the result; therefore, it is included in the IEEE.std\_logic\_arith

Architecture DataFlow of Adder is

```
Code 7. Saturator57To16.vhd.
Library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.std_logic_arith.all;
Entity Saturator57To16 is
port(
DIN : in std_logic_vector(56 downto 0);
DOUT : out std_logic_vector(15 downto 0)
);
end Saturator57To16;
Architecture Behavioral of Saturator57To16 is
constant UMAX : std_logic_vector(56 downto 0) := '0' & X"0000007FFF0000";
constant UMIN : std_logic_vector(56 downto 0) := '1' & X"FFFFFF80010000";
begin
process(DIN)
begin
if signed(DIN) > signed(UMAX) then
DOUT <= UMAX(31 downto 16);
elsif signed(DIN) < signed(UMIN) then
DOUT <= UMIN(31 downto 16);
else
DOUT <= DIN(31 downto 16);
end if;
end process;
end Behavioral;
```