EGRE 365

HW 08

Due 10/1/08

Complete the sgnext function in tb_sgnext_func. Hand in you source along with a simulation from 0 to 50 ns and from 50 ns to 100 ns.

tb_sgnext_func

LIBRARY IEEE;

use IEEE.STD_LOGIC_1164.ALL;

use IEEE.STD_LOGIC_ARITH.ALL;

use IEEE.STD_LOGIC_UNSIGNED.ALL;

use work.all;

entity tb is end entity tb;


architecture test of tb is

signal CNT: std_logic_vector(7 downto 0) := (others => '0');

signal EXT: std_logic_vector(15 downto 0) := (others => '0');

-- Complete the function sgnext to extend the sign of 8 bit n to 16 bits.

function sgnext(n: in std_logic_vector(7 downto 0))

return std_logic_vector is

variable nex: std_logic_vector(15 downto 0) := (others => '0');

begin

-- Enter your code here

nex(7 downto 0) := n;

nex(15 downto 8) := (others => n(7));

return nex;

end;

-- Use Johnson counter to test sgnext.

begin

CNT <= NOT CNT(0) & CNT(7 downto 1) after 10 ns;

EXT <= sgnext(CNT);

end test;

VHDL Subprograms

We have used processes extensively. VHDL also provides for creating subprograms.

A subprogram defines a sequential algorithm that performs a certain computation. There are two types of subprograms:

1. Functions

a.  Computes a single value

b. Executes in zero simulation time.

2. Procedures

a.  May be used to partition large behavioral descriptions.

b. May return zero of more values.

c.  May contain wait statements so that it does not execute in zero simulation time.

We will consider functions.

2

A function may be declared in the declarative part of the block in which it is used. The max function below is only visible to the architecture test.

LIBRARY IEEE;

USE work.all;

USE IEEE.Std_Logic_1164.all;

use IEEE.STD_LOGIC_ARITH.ALL;

use IEEE.STD_LOGIC_UNSIGNED.ALL;

ENTITY tb is END tb ;

ARCHITECTURE Test OF tb IS

------

-- Function: max - Returns max of two integers.

-- Note: max is a local function used only

-- within this Architecture

------

function max(L, R: INTEGER) return INTEGER is

begin

if L > R then

return L;

else

return R;

end if;

end;

------

signal x, y, z: integer range 0 to 10;

BEGIN

x <= (x + 1) mod 10 after 10 ns;

y <= (y - 1) mod 10 after 10 ns;

z <= max(x, y);

end;
If you have a general-purpose function you probable should place it in a package so that it can be made visible as needed. Consider the example below, which will serve as out introduction to both packages and functions.

-- pkg_func V 3.0 10/12/06

library IEEE;

use IEEE.STD_LOGIC_1164.ALL;

use IEEE.NUMERIC_STD.ALL;

package pkg_func is

function clamp (X: SIGNED; N: INTEGER) return SIGNED;

function To_MO(X: SIGNED) return UNSIGNED;

end pkg_func;

library IEEE;

use IEEE.STD_LOGIC_1164.ALL;

use IEEE.NUMERIC_STD.ALL;

package body pkg_func is

------

-- Function: max - Returns maximum of two integers.

-- Note: max is a local function can be used only

-- within this package.

-- Input: X - Two's complement M bit signed number

-- N - number of output bits.

-- Returns: X - Clamped to N bits.

-- Assumes: M > N

------

function max(L, R: INTEGER) return INTEGER is

begin

if L > R then

return L;

else

return R;

end if;

end;


------

-- Function: CLAMP - Converts M bit two's complement number to N bit two's

-- complement number. If input is outside N bit range output

-- is limited to maximum magnitude expressible with N bits.

-- i.e. Output is clamped to + or - N bit maximum.

-- Input: X - Two's complement M bit signed number

-- N - number of output bits.

-- Returns: X - Clamped to N bits.

-- Assumes: M > N

------

function clamp (X: SIGNED; N: INTEGER) return SIGNED is

constant M: INTEGER := X'length;

variable Y: SIGNED(N-1 downto 0);

variable Z: unsigned(M-1 downto 0);

begin

Z := unsigned(X);

if (X(M-1) = '0') and

(Z(M-2 downto N-1) /= 0) then

-- clamp positive

Y(N-2 downto 0) := (others => '1');

Y(N-1) := '0';

elsif (Z(M-1) = '1') and (not (Z(M-2 downto n-1)) /= 0) then

-- clamp negative

Y(N-2 downto 0) := (others => '0');

Y(N-1) := '1';

else

-- in range

Y := signed(z(M-1)&z(N-2 downto 0));

end if;

return Y;

end clamp;


------

--Function: to_MO - Converts n bit Two's complement number to

-- n bit magnitude offset. i.e. Most negative X returns all 0's

-- and most positive X returns all 1's.

-- For example if X is a 3 bit number

-- -4 = 100 returns 000 = 0

-- -3 = 101 returns 001 = 1

-- -2 = 110 returns 010 = 2

-- -1 = 111 returns 011 = 3

-- 0 = 000 returns 100 = 4

-- 1 = 001 returns 101 = 5

-- 2 = 010 returns 110 = 6

-- 3 = 011 returns 111 = 7

-- Input: X - Two's compliment n bit signed number

-- Returns: Y - Sign magnetude unsigned n bit number

-- Ussage: Y_unsigned <= to_mo(X_signed);

------

function To_MO(X: SIGNED) return UNSIGNED is

constant N: INTEGER := X'length;

variable Y: unsigned(N-1 downto 0);

begin

-- Fix the line below.

-- Y := unsigned(X);

Y := unsigned(not X(N-1) & X(N-2 downto 0));

return Y;

end To_MO;

end pkg_func;

2

My test bench with after the to_MO function has been completed.

LIBRARY IEEE;

USE work.all;

USE IEEE.Std_Logic_1164.all;

use ieee.numeric_std.all;

use pkg_func.all;

entity tb is

end tb;

architecture test of tb is

signal X: signed(4 downto 0) := "11111";

signal XC: signed(3 downto 0);

signal XMO: unsigned(4 downto 0);

signal iX, iXC, iXMO, iXCa: integer;

begin

XC <= clamp(x, 4);

XMO <= to_MO(X);

-- Use LFSR to generate random X values

X <= (X(2) xor X(0)) & X(4 downto 1) after 10 ns;

iX <= to_integer(X);

iXC <= to_integer(XC);

iXMO <= to_integer(XMO);

with ix select iXCa <= -8 when -16 to -8,

7 when 7 to 15,

ix when others;

end test;

begin

XC <= clamp(x, 4);

XMO <= to_MO(X);

-- Use LFSR to generate random X values

X <= (X(2) xor X(0)) & X(4 downto 1) after 10 ns;

iX <= to_integer(X);

iXC <= to_integer(XC);

iXMO <= to_integer(XMO);

with ix select iXCa <= -8 when -16 to -8,

7 when 7 to 15,

ix when others;

end test;

2