-- $Id$ 

-- Copyright (C) 2008-2009 FAUmachine Team <info@faumachine.org>.
-- This program is free software. You can redistribute it and/or modify it
-- under the terms of the GNU General Public License, either version 2 of
-- the License, or (at your option) any later version. See COPYING.

ENTITY half_adder IS
	PORT (
		op1 : in boolean;
		op2 : in boolean;
		res : out boolean;
		carry : out boolean
	);
END ENTITY half_adder;

ARCHITECTURE half_adder_impl of half_adder IS
BEGIN
	calc_res : PROCESS (op1, op2)
		variable r : boolean;
	BEGIN
		r := op1 xor op2;
		res <= r after 10 ms;
	END PROCESS;

	calc_carry : PROCESS(op1, op2)
		variable r : boolean;
	BEGIN
		r := op1 and op2;
		carry <= r after 10 ms;
	END PROCESS;
END ARCHITECTURE half_adder_impl;


ENTITY full_adder IS
	PORT (
		op1 : in boolean;
		op2 : in boolean;
		cin : in boolean;
		res : out boolean;
		carry : out boolean
	);
END ENTITY full_adder;

ARCHITECTURE full_adder_impl of full_adder IS
	signal r1 : boolean;
	signal c1 : boolean;
	signal c2 : boolean;

BEGIN
	-- add op1 and op2 and output to s1
	a1 : half_adder port map (
		op1 => op1,
		op2 => op2,
		res => r1,
		carry => c1
	);

	a2 : half_adder port map (
		op1 => r1,
		op2 => cin,
		res => res,
		carry => c2
	);

	calc_cout : process(c1, c2)
		variable r : boolean;
	BEGIN
		r := c1 or c2;
		carry <= r after 10 ms;
	END PROCESS;
		
END ARCHITECTURE full_adder_impl;

ENTITY full_adder_sync IS
	PORT (
		x : in boolean;
		y : in boolean;
		cin : in boolean;
		res : out boolean;
		carry : out boolean;
		clock : in boolean
	);
END ENTITY full_adder_sync;

ARCHITECTURE full_adder_sync_impl of full_adder_sync IS
	signal res_nosync : boolean;
	signal carry_nosync : boolean;
begin
	f : full_adder port map (
		op1 => x,
		op2 => y,
		cin => cin,
		res => res_nosync,
		carry => carry_nosync
	);

	p : process(clock)
	begin
		if (clock) then
			res <= res_nosync;
			carry <= carry_nosync;
		end if;
	end process;
END ARCHITECTURE full_adder_sync_impl;

ENTITY test_bench IS
END ENTITY test_bench;

ARCHITECTURE tb of test_bench IS
	signal a1, a2, cin, res, cout, clk : boolean;
BEGIN
	
	f : full_adder_sync PORT MAP (
		x => a1,
		y => a2,
		cin => cin,
		res => res,
		carry => cout,
		clock => clk
	);

	test : PROCESS
	BEGIN
		a1 <= true;
		a2 <= true;
		cin <= true;
		clk <= true after 100 ms;
		wait on clk;
		clk <= false after 20 ms;
		wait on clk;
		assert (res = true) and (cout = true)
			report "(1 + 1) [1] should be 1 [1]" severity failure;

		a1 <= false;
		a2 <= false;
		cin <= false;
		clk <= true after 100 ms;
		wait on clk;
		clk <= false after 20 ms;
		wait on clk;
		assert (res = false) and (cout = false)
			report "(0 + 0) [0] should be 0 [0]" severity failure;

		a1 <= true;
		a2 <= false;
		cin <= false;
		clk <= true after 100 ms;
		wait on clk;
		clk <= false after 20 ms;
		wait on clk;
		assert (res = true) and (cout = false)
			report "(1 + 0) [0] should be 1 [0]" severity failure;

		a1 <= true;
		a2 <= true;
		cin <= false;
		clk <= true after 100 ms;
		wait on clk;
		clk <= false after 20 ms;
		wait on clk;
		assert (res = false) and (cout = true)
			report "(1 + 1) [0] should be 0 [1]" severity failure;

		a1 <= false;
		a2 <= true;
		cin <= false;
		clk <= true after 100 ms;
		wait on clk;
		clk <= false after 20 ms;
		wait on clk;
		assert (res = true) and (cout = false)
			report "(0 + 1) [0] should be 1 [0]" severity failure;

		a1 <= true;
		a2 <= false;
		cin <= true;
		clk <= true after 100 ms;
		wait on clk;
		clk <= false after 20 ms;
		wait on clk;
		assert (res = false) and (cout = true)
			report "(1 + 0) [1] should be 0 [1]" severity failure;

		a1 <= false;
		a2 <= false;
		cin <= true;
		clk <= true after 100 ms;
		wait on clk;
		clk <= false after 20 ms;
		wait on clk;
		assert (res = true) and (cout = false)
			report "(0 + 0) [1] should be 1 [0]" severity failure;

		a1 <= false;
		a2 <= true;
		cin <= true;
		clk <= true after 100 ms;
		wait on clk;
		clk <= false after 20 ms;
		wait on clk;
		assert (res = false) and (cout = true)
			report "(0 + 1) [1] should be 0 [1]" severity failure;

		assert false report "simulation finished" severity note;
		wait;
	END PROCESS;
END ARCHITECTURE tb;
