-- $Id$

-- Copyright (C) 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.

-- FIXME doesn't match the real std_logic_1164 yet.
PACKAGE std_logic_1164 IS
	TYPE std_ulogic IS ('U', 'X', '0', '1', 'Z', 'W', 'L', 'H', '-');
	TYPE std_ulogic_vector IS array (NATURAL range <>) of std_ulogic;

    	FUNCTION resolve_stdlogic(s : std_ulogic_vector) RETURN std_ulogic;

	SUBTYPE std_logic IS resolve_stdlogic std_ulogic;
	TYPE std_logic_vector IS array (NATURAL range <>) of std_logic;

	function "xor"(l: std_ulogic; r: std_ulogic) return std_ulogic;
	function "and"(l: std_ulogic; r: std_ulogic) return std_ulogic;
	function "or"(l: std_ulogic; r: std_ulogic) return std_ulogic;
	function "not"(o: std_ulogic) return std_ulogic;
END PACKAGE std_logic_1164;

PACKAGE BODY std_logic_1164 IS
	function resolve_stdlogic(s : std_ulogic_vector) RETURN	std_ulogic IS
		variable ret : std_ulogic;
	begin
		ret := s(0);

		for i in s'range loop
			case s(i) is
			when 'U' =>
				return 'U';
			when 'X' =>
				case ret is
				when 'U' => return 'U';
				when others => ret := 'X';
				end case;
			when '0' =>
				case ret is
				when 'U' => return 'U';
				when 'X' => ret := 'X';
				when '0' => ret := '0';
				when '1' => ret := 'X';
				when 'Z' => ret := '0';
				when 'W' => ret := '0';
				when 'L' => ret := '0';
				when 'H' => ret := '0';
				when '-' => ret := 'X';
				end case;
			when '1' =>
				case ret is
				when 'U' => return 'U';
				when 'X' => ret := 'X';
				when '0' => ret := 'X';
				when '1' => ret := '1';
				when 'Z' => ret := '1';
				when 'W' => ret := '1';
				when 'L' => ret := '1';
				when 'H' => ret := '1';
				when '-' => ret := 'X';
				end case;
			when 'Z' =>
				case ret is
				when 'U' => return 'U';
				when 'X' => ret := 'X';
				when '0' => ret := '0';
				when '1' => ret := '1';
				when 'Z' => ret := 'Z';
				when 'W' => ret := 'W';
				when 'L' => ret := 'L';
				when 'H' => ret := 'H';
				when '-' => ret := 'X';
				end case;
			when 'W' =>
				case ret is
				when 'U' => return 'U';
				when 'X' => ret := 'X';
				when '0' => ret := '0';
				when '1' => ret := '1';
				when 'Z' => ret := 'W';
				when 'W' => ret := 'W';
				when 'L' => ret := 'W';
				when 'H' => ret := 'W';
				when '-' => ret := 'X';
				end case;
			when 'L' =>
				case ret is
				when 'U' => return 'U';
				when 'X' => ret := 'X';
				when '0' => ret := '0';
				when '1' => ret := '1';
				when 'Z' => ret := 'L';
				when 'W' => ret := 'W';
				when 'L' => ret := 'L';
				when 'H' => ret := 'W';
				when '-' => ret := 'X';
				end case;
			when 'H' =>
				case ret is
				when 'U' => return 'U';
				when 'X' => ret := 'X';
				when '0' => ret := '0';
				when '1' => ret := '1';
				when 'Z' => ret := 'H';
				when 'W' => ret := 'W';
				when 'L' => ret := 'W';
				when 'H' => ret := 'H';
				when '-' => ret := 'X';
				end case;
			when '-' =>
				case ret is
				when 'U' => return 'U';
				when 'X' => ret := 'X';
				when '0' => ret := 'X';
				when '1' => ret := 'X';
				when 'Z' => ret := 'X';
				when 'W' => ret := 'X';
				when 'L' => ret := 'X';
				when 'H' => ret := 'X';
				when '-' => ret := 'X';
				end case;
			end case;
		end loop;

		return ret;
	end;



	function "xor"(l: std_ulogic; r: std_ulogic) return std_ulogic IS
	begin
		case l is
		when 'U' => 
			return 'U';
		when 'X' | 'Z' | 'W' | '-' =>
			case r is
			when 'U' => return 'U';
			when others => return 'X';
			end case;
		when '0' | 'L' => 
			case r is
			when 'U' => return 'U';
			when 'X' => return 'X';
			when '0' => return '0';
			when '1' => return '1';
			when 'Z' => return 'X';
			when 'W' => return 'X';
			when 'L' => return '0';
			when 'H' => return '1';
			when '-' => return 'X';
			end case;
		when '1' | 'H' =>
			case r is
			when 'U' => return 'U';
			when 'X' => return 'X';
			when '0' => return '1';
			when '1' => return '0';
			when 'Z' => return 'X';
			when 'W' => return 'X';
			when 'L' => return '1';
			when 'H' => return '0';
			when '-' => return 'X';
			end case;
		end case;
	end;

	function "and"(l: std_ulogic; r: std_ulogic) return std_ulogic IS
	begin
		case l is
		when '0' | 'L' => 
			return '0';

		when 'U' => 
			case r is
			when '0' | 'L' => return '0';
			when others => return 'U';
			end case;

		when '1' | 'H' =>
			case r is
			when 'U' => return 'U';
			when 'X' => return 'X';
			when '0' => return '0';
			when '1' => return '1';
			when 'Z' => return 'X';
			when 'W' => return 'X';
			when 'L' => return '0';
			when 'H' => return '1';
			when '-' => return 'X';
			end case;

		when 'X' | 'Z' | 'W' | '-' =>
			case r is
			when 'U' => return 'U';
			when 'X' => return 'X';
			when '0' => return '0';
			when '1' => return 'X';
			when 'Z' => return 'X';
			when 'W' => return 'X';
			when 'L' => return '0';
			when 'H' => return 'X';
			when '-' => return 'X';
			end case;

		end case;
	end;

	function "or"(l: std_ulogic; r: std_ulogic) return std_ulogic IS
	begin
		case l is
		when '1' | 'H' => 
			return '1';

		when 'U' => 
			case r is
			when '1' | 'H' => return '1';
			when others => return 'U';
			end case;

		when '0' | 'L' =>
			case r is
			when 'U' => return 'U';
			when 'X' => return 'X';
			when '0' => return '0';
			when '1' => return '1';
			when 'Z' => return 'X';
			when 'W' => return 'X';
			when 'L' => return '0';
			when 'H' => return '1';
			when '-' => return 'X';
			end case;

		when 'X' | 'Z' | 'W' | '-' =>
			case r is
			when 'U' => return 'U';
			when 'X' => return 'X';
			when '0' => return 'X';
			when '1' => return '1';
			when 'Z' => return 'X';
			when 'W' => return 'X';
			when 'L' => return 'X';
			when 'H' => return '1';
			when '-' => return 'X';
			end case;

		end case;
	end;

	function "not"(o: std_ulogic) return std_ulogic IS
	begin
		case o is
		when 'U' =>
			return 'U';

		when 'X' | 'Z' | 'W' | '-' =>
			return 'X';

		when '0' | 'L' =>
			return '1';

		when '1' | 'H' => 
			return '0';

		end case;
	end; 
END PACKAGE;
