library IEEE;
use IEEE.std_logic_1164.all;

package mvl_pack is
  
	type PLAmtrx is array (integer range <>, integer range <>) of std_logic;
  	function PLAout(PLA: PLAmtrx; Input: std_logic_vector)
	return std_logic_vector;

  component And2
	generic(DELAY: time:=10 ns);
	port(A1,A2: in std_logic; Z: out std_logic);
  end component;
  component And3
	generic(DELAY: time:=10 ns);
	port(A1,A2,A3: in std_logic; Z: out std_logic);
  end component;
  component And4
	generic(DELAY: time:=10 ns);
	port(A1,A2,A3,A4: in std_logic; Z: out std_logic);
  end component;
  component Or2
	generic(DELAY: time:=10 ns);
	port(A1,A2: in std_logic; Z: out std_logic);
  end component;
  component Or3
	generic(DELAY: time:=10 ns);
	port(A1,A2,A3: in std_logic; Z: out std_logic);
  end component;
  component Or4
	generic(DELAY: time:=10 ns);
	port(A1,A2,A3,A4: in std_logic; Z: out std_logic);
  end component;
  component Nand2
	generic(DELAY: time:=10 ns);
	port(A1,A2: in std_logic; Z: out std_logic);
  end component;
  component Nand3
	generic(DELAY: time:=10 ns);
	port(A1,A2,A3: in std_logic; Z: out std_logic);
  end component;
  component Nand4
	generic(DELAY: time:=10 ns);
	port(A1,A2,A3,A4: in std_logic; Z: out std_logic);
  end component;
  component Nor2
	generic(DELAY: time:=10 ns);
	port(A1,A2: in std_logic; Z: out std_logic);
  end component;
  component Nor3
	generic(DELAY: time:=10 ns);
	port(A1,A2,A3: in std_logic; Z: out std_logic);
  end component;
  component Nor4
	generic(DELAY: time:=10 ns);
	port(A1,A2,A3,A4: in std_logic; Z: out std_logic);
  end component;
  component Inverter
	generic(DELAY: time:=10 ns);
	port(A: in std_logic; Z: out std_logic);
  end component;
  component Xor2
	generic(DELAY: time:=10 ns);
	port(A1,A2: in std_logic; Z: out std_logic);
  end component;
  component Tbuf
	generic(DELAY: time:=10 ns);
	port(A1,C: in std_logic; Z: out std_logic);
  end component;
end mvl_pack;

package body mvl_pack is
--	The following funtion produces the PLA output according to the PLA
--		specification (PLAmtrx) and the PLA inputs.
--	The steps in this function are as follows:
--	1) Start at the first row of the PLAmtrx
--	2) Determine whether the given inputs match the PLA inputs in the 
--			current row
--	3) If the inputs match current PLA row, then OR the current outputs with
--		the PLA outputs
--	4) Repeat steps (2) and (3) for all rows in the PLA matrix

function PLAout (PLA: PLAmtrx; Input: std_logic_vector) 
		return std_logic_vector is
	alias In1: std_logic_vector(Input'length-1 downto 0) is Input;
	variable match: std_logic;
	variable PLAcol, step: integer;
	variable PLArow: std_logic_vector(PLA'length(2)-1 downto 0);
	variable PLAinp: std_logic_vector(Input'length-1 downto 0);	
	variable Output: 
		std_logic_vector((PLA'length(2)-Input'length-1) downto 0);
begin
	Output := (others=>'0');	-- Initialize output to all zeros
	if PLA'left(2) > PLA'right(2) then step := -1; else step := 1;
	end if;
		LP1:  for row in PLA'range loop	--Scan each row of PLA
		match := '1';				-- Assume match for now
		PLAcol := PLA'left(2);

		LP2: for col in PLArow'range loop	-- Copy row of PLA table
			PLArow(col) := PLA(row,PLAcol);	
			PLAcol := PLAcol + step;
		end loop LP2;
		PLAinp := PLArow(PLArow'high downto PLArow'high-Input'length+1);
		
		LP3:  for col in In1'range loop	-- Scan each input column
				if IN1(col) /= PLAinp(col) and PLAinp(col) /= 'X' then
					match := '0'; exit;		-- mismatched row
				end if;
		end loop LP3;

		if (match = '1') then
			Output := Output or PLArow(Output'range);
		end if;
	end loop LP1;
	return Output;
end PLAout;												

end mvl_pack;

library ieee;
use ieee.std_logic_1164.all;

entity And2 is
  generic(DELAY:time:=10 ns);
  port(A1,A2: in std_logic;
	   Z: out std_logic);
end And2;
architecture concur of And2 is
begin
  Z<=A1 and A2 after DELAY;
end;

library ieee;
use ieee.std_logic_1164.all;

entity And3 is
  generic(DELAY:time:=10 ns);
  port(A1,A2,A3: in std_logic;
	   Z: out std_logic);
end And3;
architecture concur of And3 is
begin
  Z<=A1 and A2 and A3 after DELAY;
end;

library ieee;
use ieee.std_logic_1164.all;

entity And4 is
  generic(DELAY:time:=10 ns);
  port(A1,A2,A3,A4: in std_logic;
	   Z: out std_logic);
end And4;
architecture concur of And4 is
begin
  Z<=A1 and A2 and A3 and A4 after DELAY;
end;

library ieee;
use ieee.std_logic_1164.all;

entity Or2 is
  generic(DELAY:time:=10 ns);
  port(A1,A2: in std_logic;
	   Z: out std_logic);
end Or2;
architecture concur of Or2 is
begin
  Z<=A1 or A2 after DELAY;
end;

library ieee;
use ieee.std_logic_1164.all;

entity Or3 is
  generic(DELAY:time:=10 ns);
  port(A1,A2,A3: in std_logic;
	   Z: out std_logic);
end Or3;
architecture concur of Or3 is
begin
  Z<=A1 or A2 or A3 after DELAY;
end;

library ieee;
use ieee.std_logic_1164.all;

entity Or4 is
  generic(DELAY:time:=10 ns);
  port(A1,A2,A3,A4: in std_logic;
	   Z: out std_logic);
end Or4;
architecture concur of Or4 is
begin
  Z<=A1 or A2 or A3 or A4 after DELAY;
end;

library ieee;
use ieee.std_logic_1164.all;

entity Nand2 is
  generic(DELAY:time:=10 ns);
  port(A1,A2: in std_logic;
	   Z: out std_logic);
end Nand2;
architecture concur of Nand2 is
begin
  Z<=not(A1 and A2) after DELAY;
end;

library ieee;
use ieee.std_logic_1164.all;

entity Nand3 is
  generic(DELAY:time:=10 ns);
  port(A1,A2,A3: in std_logic;
	   Z: out std_logic);
end Nand3;
architecture concur of Nand3 is
begin
  Z<=not(A1 and A2 and A3) after DELAY;
end;

library ieee;
use ieee.std_logic_1164.all;

entity Nand4 is
  generic(DELAY:time:=10 ns);
  port(A1,A2,A3,A4: in std_logic;
	   Z: out std_logic);
end Nand4;
architecture concur of Nand4 is
begin
  Z<=not(A1 and A2 and A3 and A4) after DELAY;
end;

library ieee;
use ieee.std_logic_1164.all;

entity Nor2 is
  generic(DELAY:time:=10 ns);
  port(A1,A2: in std_logic;
	   Z: out std_logic);
end Nor2;
architecture concur of Nor2 is
begin
  Z<=not(A1 or A2) after DELAY;
end;

library ieee;
use ieee.std_logic_1164.all;

entity Nor3 is
  generic(DELAY:time:=10 ns);
  port(A1,A2,A3: in std_logic;
	   Z: out std_logic);
end Nor3;
architecture concur of Nor3 is
begin
  Z<=not(A1 or A2 or A3) after DELAY;
end;

library ieee;
use ieee.std_logic_1164.all;

entity Nor4 is
  generic(DELAY:time:=10 ns);
  port(A1,A2,A3,A4: in std_logic;
	   Z: out std_logic);
end Nor4;
architecture concur of Nor4 is
begin
  Z<=not(A1 or A2 or A3 or A4) after DELAY;
end;

library ieee;
use ieee.std_logic_1164.all;

entity Inverter is
  generic(DELAY:time:=10 ns);
  port(A: in std_logic;
	   Z: out std_logic);
end Inverter;
architecture concur of Inverter is
begin
  Z<=not A after DELAY;
end;

library ieee;
use ieee.std_logic_1164.all;

entity Xor2 is
  generic(DELAY:time:=10 ns);
  port(A1,A2: in std_logic;
	   Z: out std_logic);
end Xor2;
architecture concur of Xor2 is
begin
  Z<=A1 xor A2 after DELAY;
end;

library ieee;
use ieee.std_logic_1164.all;

entity Tbuf is
  generic(DELAY:time:=10 ns);
  port(A1,C: in std_logic;
	   Z: out std_logic);
end Tbuf;
architecture concur of Tbuf is
begin
  Z <= A1 when C='0' else 'Z' after DELAY; 
end;
 
