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