#!/usr/local/bin/perl

use strict;
my $ADDER_WIDTH = 16;

print << 'EOF';
--
-- EE510 Spring 2001
-- Fujinaka, Hisashi T
--

package globals is
	constant ADDER_WIDTH	: integer := 3;
end globals;

library ieee;
use ieee.std_logic_1164.all;
use work.all;
use globals.all;

entity au_test is
end au_test;

architecture mytest of au_test is
	signal a_in		: std_logic_vector(ADDER_WIDTH downto 0);
	signal b_in		: std_logic_vector(ADDER_WIDTH downto 0);
	signal carry_in		: std_logic;
	signal inv_a_in		: std_logic;
	signal inv_b_in		: std_logic;
	signal sum_out	: std_logic_vector(ADDER_WIDTH downto 0);
	signal carry_out	: std_logic;
	component au port(
		a_in		: in std_logic_vector(ADDER_WIDTH downto 0);
		b_in		: in std_logic_vector(ADDER_WIDTH downto 0);
		carry_in	: in std_logic;
		inv_a_in	: in std_logic;
		inv_b_in	: in std_logic;
		a_out		: out std_logic_vector(ADDER_WIDTH downto 0);
		a_xor_b_out	: out std_logic_vector(ADDER_WIDTH downto 0);
		sum_out		: out std_logic_vector(ADDER_WIDTH downto 0);
		carry_out	: out std_logic;
		inv_a_out	: out std_logic;
		inv_b_out	: out std_logic);
	end component;

type test_vector is record
	a_in		: std_logic_vector(ADDER_WIDTH downto 0);
	b_in		: std_logic_vector(ADDER_WIDTH downto 0);
	carry_in	: std_logic;
	inv_a_in	: std_logic;
	inv_b_in	: std_logic;
	a_out		: std_logic_vector(ADDER_WIDTH downto 0);
--	a_xor_b_out	: std_logic_vector(ADDER_WIDTH downto 0);
	sum_out		: std_logic_vector(ADDER_WIDTH downto 0);
	carry_out	: std_logic;
--	inv_a_out	: std_logic;
--	inv_b_out	: std_logic;
end record;

type test_vector_array is array(natural range <>) of test_vector;
constant test_vectors: test_vector_array := (
EOF

for (my $l = 0; $l < 2; $l++) {
	for (my $i = 0; $i < 2; $i++) {
		for (my $j = 0; $j < $ADDER_WIDTH; $j++) {
			for (my $k = 0; $k < $ADDER_WIDTH; $k++) {
				my $sum = 0;
				my $carry = 0;
				if ($l == 1) {
					$sum = (($i + $j + ((($ADDER_WIDTH -1) - $k) & hex("f"))) & hex("f"));
					$carry = int(($i + $j + ((($ADDER_WIDTH -1) - $k) & hex("f")))/($ADDER_WIDTH));
				} else {
					$sum = ($i + $j + $k) % $ADDER_WIDTH;
					$carry = int(($i + $j + $k)/($ADDER_WIDTH));
				}
				printf "\t(a_in => \"%04b\", b_in=> \"%04b\", carry_in => '%01b', inv_a_in => '0', inv_b_in => '%01b', a_out => \"%04b\", sum_out => \"%04b\", carry_out => '%01b'),\n", $j, $k, $i, $l, $j, $sum, $carry;
			}
		}
	}
}

print << 'EOF';
);
begin
	uut: au port map(a_in => a_in, b_in => b_in, carry_in => carry_in, inv_a_in => inv_a_in, inv_b_in => inv_b_in, sum_out => sum_out, carry_out => carry_out);
	verify: process
		variable vector: test_vector;
		variable errors: boolean := false;

	begin
		for i in test_vectors'range loop
			-- get vector i
			vector := test_vectors(i);

			a_in <= vector.a_in;
			b_in <= vector.b_in;
			carry_in <= vector.carry_in;
			inv_a_in <= vector.inv_a_in;
			inv_b_in <= vector.inv_b_in;

			wait for 2 ns;

			if (sum_out /= vector.sum_out) then
				assert false
					report "out is wrong";
				errors := true;
			end if;
			if (carry_out /= vector.carry_out) then
				assert false
					report "carry is wrong";
				errors := true;
			end if;
		end loop;

		assert not errors
			report "Test vectors failed."
			severity note;
		assert errors
			report "Test vectors passed."
			severity note;
		wait;
	end process;
end;
EOF
