HW 10 Solutions

------

--Function: to_bcd - Converts 16 bit input to BCD.

-- If input > 9999 then returns x"9999".

-- Input: binary - 16 bit unsigned value.

-- Returns: BCD unsigned.

-- Ussage: BCD <= to_bcd(binary);

------

function to_bcd(binary: std_logic_vector) return STD_LOGIC_VECTOR is

variable rsr : std_logic_vector(15 downto 0); -- Shift reg for BCD result

variable bsr : std_logic_vector(15 downto 0); -- Shift reg for binary input

variable correction : std_logic_vector(15 downto 0); -- Add to do BCD correction

begin

if CONV_INTEGER(binary) > 9999 then

rsr := x"9999";

else

rsr := (others => '0');

bsr := binary;

for i in 1 to 16 loop

rsr := rsr(14 downto 0) & bsr(15);

bsr := bsr(14 downto 0) & '0';

if i < 16 then

for j in 0 to 3 loop

if rsr(4*j+3 downto 4*j) >= "0101" then

correction(4*j+3 downto 4*j) := "0011";

else

correction(4*j+3 downto 4*j) := "0000";

end if;

end loop;

rsr := rsr + correction;

end if;

end loop;

end if;

return rsr;

end;

------

-- Function: LOG2 - Returns integer of 16 bit input unless LOG2

-- is negative then 0 is returned.

-- Inputs: x - a 16 bit std_logic_vector

-- Returns: 8 bit std_logic_vector containg integer of log base 2

-- Ussage: log <= Log2(X);

------

function log2(x: std_logic_vector) return std_logic_vector is

variable log: std_logic_vector(7 downto 0);

begin

log := (others => '0');

for i in x'length - 1 downto 0 loop

if x(i) = '1' then

log := conv_std_logic_vector(i, 8);

exit;

end if;

exit when log /= 0;

end loop;

return(log);

end;

------

-- Function: Div_by_3 - Divides input by 3

-- Inputs: X - a std_logic_vector

-- Returns: a std_logic_vector

-- Note that both standart logic vectors must be of the form

-- std_logic_vector(n downto 0), and n is the same for

-- both the input and the output.

-- Do not make assumptions about the value of n.

-- The function must work for any n > 2.

------

--Because of the accumerlation of rounding errors this version

-- Can be off by as significant amount. I got 8 based on my test bench.

function Div_by_3(x: std_logic_vector) return std_logic_vector is

variable Sum, P: std_logic_vector(x'length - 1 downto 0);

begin

Sum := (others => '0');

P := x;

while P /= 0 loop

P := "00" & P(x'length - 1 downto 2);

Sum := Sum + P;

end loop;

return(Sum);

end;

-- Better_div_by_3 - Fixes rounding problem in div_by_3 function.

-- This is acomplinsished by working with double the size of the input

function Better_Div_by_3(x: std_logic_vector) return

std_logic_vector is

constant n: integer := x'length;

variable Big_Sum, Big_P: std_logic_vector(2*n - 1 downto 0);

variable Sum: std_logic_vector(n-1 downto 0);

begin

Big_Sum := (others => '0');

Big_P(2*n-1 downto n) := x;

Big_P(n-1 downto 0) := (others => '0');

while Big_P /= 0 loop

Big_P := "00" & Big_P(2*n - 1 downto 2);

Big_Sum := Big_Sum + Big_P;

end loop;

Sum := big_sum(2*n - 1 downto n); -- put integer part in sum

if big_sum(n-1) = '1' then

sum := sum + 1; -- Round up sum

end if;

return(sum);

end;

My Test Benches

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 entity tb;

architecture test of tb is

SIGNAL CLK: std_logic := '0';

SIGNAL RES: std_logic := '1';

SIGNAL EN : std_logic := '0';

SIGNAL CNT1, CNT2, CNT3: std_logic_vector(15 downto 0);

begin

U1: ENTITY work.BCDINC(arch1) PORT MAP(CLK, RES, EN, CNT1);

U2: ENTITY work.BCDINC(arch2) PORT MAP(CLK, RES, EN, CNT2);

U3: ENTITY work.BCDINC(arch3) PORT MAP(CLK, RES, EN, CNT3);

RES <= '1', '0' after 10 ns;

CLK <= not CLK after 1 ns;

EN <= not EN after 2 ns;

assert CNT1 = CNT2 report "CNT1 differs from CNT2";

assert CNT2 = CNT3 report "CNT2 differs from CNT3";

assert CNT1 = CNT2 report "CNT1 differs from CNT3";

end test;

-- tb_div_by_3.vhd Version 1.0 by Dr. Jerry H. Tucker

-- Test bench for to_bcd.vhd

-- Created 10/7/08

library IEEE;

use IEEE.STD_LOGIC_1164.ALL;

use IEEE.STD_LOGIC_ARITH.ALL;

use IEEE.STD_LOGIC_UNSIGNED.ALL;

use work.all;

use pkg_func.all;

-- uses to_bcd in package pkg_func.vhd

entity tb is

end tb;

architecture test of tb is

signal bi, ans, ansb: std_logic_vector(15 downto 0) := x"0000";

signal int, int_ans, err, int_b, errb, max_err: integer := 0;

begin

-- Use shift register to generate values.

bi <= bi + x"0001" after 5 ns;

int <= conv_integer(bi)/3; -- Get integer value of binary

int_ans <= conv_integer(ans);

ans <= div_by_3(bi);

ansb <= better_div_by_3(bi);

int_b <= conv_integer(ansb);

err <= int - int_ans;

errb <= int - int_b;

max_err <= err when err > max_err else max_err;

end test;

-- tb_log2.vhd Version 1.0 by Dr. Jerry H. Tucker

-- Test bench for to_bcd.vhd

-- Created 10/7/08

library IEEE;

use IEEE.STD_LOGIC_1164.ALL;

use IEEE.STD_LOGIC_ARITH.ALL;

use IEEE.STD_LOGIC_UNSIGNED.ALL;

use work.all;

use pkg_func.all;

-- uses to_bcd in package pkg_func.vhd

entity tb is

end tb;

architecture test of tb is

signal bi: std_logic_vector(15 downto 0) := x"ffff";

signal log: std_logic_vector(7 downto 0);

signal i: integer;

begin

bi <= not bi(0) & bi(15 downto 1) after 5 ns;

log <= log2(bi);

i <= conv_integer(log);

end test;

1