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

--
-- VHDL-description of a single virtual FAUmachine node
--

library expect;
use expect.types.ALL;
use expect.procedures.ALL;

-- node-internal things are prefixed with int_ in this example.
-- I have tried to avoid using names which are identical to keywords or
-- predefined components, so it is clear, which names can be freely
-- chosen and which cannot.
-- node-external things are prefixed with ext_. node-external things in
-- this case include interfaces, which other nodes can access.

-- ####################################################################
-- define an entity named 'node'
-- ####################################################################
-- define interface of entity 'node'
entity node is
	-- variable definitions, used later on.
	-- the 'generic' statement includes (in parentheses) a list of
	-- variable definitions separated by semicolons. name of
	-- variable, type and value are given.
	generic(
		version : integer := 0;
		memsize : integer := 128;
		disksize : integer := 2000
	);
	-- the interface (port) of this entity consists of its network
	-- interface "ext_eth0" which is connected to the ethernet 'ethbus'
	-- you could use this to connect several nodes to an ethernet
	-- cable.
	-- the 'port' statement includes (in parentheses) a list of
	-- port-names (e.g. "ext_eth0") and their types (e.g.
	-- "inout ethbus"). There is a colon between port-name and type.
	-- the port-name/type pairs are separated by semicolons.
	port(
		ext_eth0 : inout ethbus
		-- add more ports here (e.g. if you have more than one
		-- ethernet-card you should probably have a separate
		-- port here for each card. you'll also need a semicolon
		-- after the first card (and don't put a semicolon after
		-- the last definition before the closing parenthesis!)
		-- ext_eth1 : inout ethbus;
		-- ext_eth2 : inout ethbus
	);
end node;

-- define structural internals of entity 'node'
-- use whatever you want instead of "structural", it is ignored anyway
architecture structural of node is
	-- === internal busses ========================================
	-- there shouldn't be any need to change this definition of the
	-- busses

	-- for FAUmachine we use signals to model busses. the elements in
	-- the list are separated by semicolons. for each signal the
	-- name (e.g. int_mem) and the type (e.g. membus) must be given.

	-- define frontside bus. type membus is predefined.
	-- cpu, memory and mem2isa-bridge will be connected to this
	signal	int_mem : membus;

	-- define isa bus. type isabus is predefined.
	-- mem2isa-bridge, idectrl and ethcard will be connected to this
	signal	int_ps2_kbd : ps2bus;
	signal	int_ps2_mouse : ps2bus;
	signal	int_isa : isabus;
	signal	int_eth : ethbus;

	-- define ide bus. type ide_bus is predefined.
	-- idectrl and idedisk will be connected to this
	signal	int_ide : ide_bus;

	-- define serial bus. type serialbus is predefined.
	-- connect one serial component

	signal int_serial0 : serialbus;
	signal int_serial1 : serialbus;

	-- wire from monitor to gfx adapter

	signal int_gfx : gfxbus;

	-- === end of internal busses definition ======================

	-- === signals used by expect =================================
	signal	poweron, reset : boolean;
	signal  screen_shot : integer;

	SIGNAL	gfx_match : integer_array(1 TO 4);

	signal	output0 : character;

	signal	found0 : boolean;
	signal	found1 : boolean;
	signal	cdrom : boolean;

	signal	inject : boolean;

	signal	press, release : character;

	-- === end of signals used by expect ==========================

begin
	-- === expect interface =======================================
	pc : ctrl port map(
		isa =>int_isa,
		keyboard => int_ps2_kbd,
		mouse => int_ps2_mouse,
		poweron => poweron,
		reset => reset
	);
	-- === end expect interface ===================================

	cpu0 : cpu 
		port map( mem => int_mem );

	mem0 : memory generic map( size => memsize )
			port map( mem => int_mem );

	northsouth : mem2isa port map( mem => int_mem, isa => int_isa );

	--
	-- not really used in this example
	--
	kbd : keyboard
		port map( ps2 => int_ps2_kbd,
			press => press,
			release => release );
	mouse : mouse
		port map( ps2 => int_ps2_mouse);
	video : vga
		port map( mem => int_mem,
			gfx => int_gfx );
	mon : monitor
		port map(gfx => int_gfx, screen_shot => screen_shot);

	idectrl0 : idectrl
		port map( isa => int_isa,
			ide => int_ide );

	eth0 : ne2000
		port map( isa => int_isa,
			eth => ext_eth0 );

	bridge : network_router
		port map(eth => ext_eth0);

	hd0  : idedisk
		generic map ( unit => 0,
			size => disksize )
		port map( ide => int_ide );

	cdrom0  : idecdrom
		generic map(unit => 1)
		port map( ide => int_ide );

	serial0 : serial
		port map(isa => int_isa, serial => int_serial0);

	serial1 : serial
		port map(isa => int_isa,
			serial => int_serial1);

	terminal0 : serial_terminal
		port map( recv => output0,
			serial => int_serial0);

	-- internet_access : serial_ip
	--	port map(serial => int_serial1);

	-- === installation script =====================================

	installation_script : PROCESS
		VARIABLE result : boolean;
	BEGIN
		gfx_match(1) <= -1;
		WAIT FOR 1;
		
		ASSERT false REPORT "powering on node for initial installation" SEVERITY note;
		poweron <= true;

		-- wait for lilo prompt
                gfx_match'shortcut_in("/mon%match_rectangle/1");
		gfx_match'shortcut_in_activate("2/-1/-1/-1/-1/../screenshots/lilo.ppm");
		WAIT ON gfx_match(1) UNTIL 0 <= gfx_match(1) FOR 90000;
	
		IF gfx_match(1)'EVENT = 0 THEN
			screen_shot <= 1;
			WAIT FOR 1000;
			ASSERT false REPORT "timed out" SEVERITY failure;
		END IF;
		gfx_match'shortcut_in_deactivate;

		-- ready to boot
		found0'shortcut_in("/terminal0%match/0");

		
		ASSERT false REPORT "waiting for: login prompt" SEVERITY note;
		found0'shortcut_in_activate(" login: ");
		wait on found0 until found0 for 150000;
		found0'shortcut_in_deactivate;
		ASSERT found0 REPORT "timed out" SEVERITY failure;
		wait on found0 until not found0;

		
		ASSERT false REPORT "waiting for: shell prompt" SEVERITY note;
		found0'shortcut_in_activate(":~# ");
		send_string(output0, "root\0d", 100);
		wait on found0 until found0 for 30000;
		found0'shortcut_in_deactivate;
		ASSERT found0 REPORT "timed out" SEVERITY failure;
		wait on found0 until not found0;


		ASSERT false REPORT "configure nic" SEVERITY note;
		found0'shortcut_in_activate("1:~# ");	--FEHLER
		send_string(output0, "ifconfig eth0 inet 10.1.1.10 netmask 255.255.255.0 broadcast 10.1.1.255\0d", 100);
		send_string(output0, "cat /etc/network/interfaces\0d", 100);
		wait on found0 until found0 for 3000000;
		found0'shortcut_in_deactivate;
		ASSERT found0 REPORT "timed out" SEVERITY failure;
		wait on found0 until not found0;


		ASSERT false REPORT "ping me" SEVERITY note;
		found0'shortcut_in_activate(" 0% packet loss");
		send_string(output0, "ping -c 4 10.1.1.10\0d", 100);
		wait on found0 until found0 for 30000;
		found0'shortcut_in_deactivate;
		ASSERT found0 REPORT "timed out" SEVERITY failure;
		wait on found0 until not found0;


		ASSERT false REPORT "waiting for: power down" SEVERITY note;
		found0'shortcut_in_activate("Power down.");
		send_string(output0, "halt\0d", 100);
		wait on found0 until found0 for 60000;
		found0'shortcut_in_deactivate;
		ASSERT found0 REPORT "timed out" SEVERITY failure;
		wait on found0 until not found0;

		ASSERT false REPORT "powering system off" SEVERITY note;
		poweron <= false;

		ASSERT false REPORT "test finished" SEVERITY note;
		WAIT;
	END PROCESS installation_script;
end structural;
-- ####################################################################
-- end of definition of entity 'node'
-- ####################################################################
