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