----------------------------------------------------------------------------------
-- Company: 
-- Engineer: 
-- 
-- Create Date:    15:52:22 12/30/2008 
-- Design Name: 
-- Module Name:    toplevel - Behavioral 
-- Project Name: 
-- Target Devices: 
-- Tool versions: 
-- Description: 
--
-- Dependencies: 
--
-- Revision: 
-- Revision 0.01 - File Created
-- Additional Comments: 
--
----------------------------------------------------------------------------------
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;

---- Uncomment the following library declaration if instantiating
---- any Xilinx primitives in this code.
--library UNISIM;
--use UNISIM.VComponents.all;

use work.T80_Pack.all;

entity toplevel is
    Port (
      -- Clock (50 MHz)
      CLKIN_50M : in  STD_LOGIC;
      -- VGA out
      RED, GREEN, BLUE : out STD_LOGIC_VECTOR(3 downto 0);
      HSYNC, VSYNC : out STD_LOGIC;
      -- PS2 Keyboard
      PS2_CLK1, PS2_DATA1 : inout STD_LOGIC;
      -- LEDs
      LED : out STD_LOGIC_VECTOR(7 downto 0);
      -- Buttons
      BTN_NORTH : in STD_LOGIC;
      BTN_SOUTH : in STD_LOGIC;
      BTN_EAST  : in STD_LOGIC;
      BTN_WEST  : in STD_LOGIC;
      ROT_CENTER : in STD_LOGIC;
      -- Switches - 3=Enable IORQ breakpoint, 2,1,0=N/A
      SW : in STD_LOGIC_VECTOR(3 downto 0);
      -- SPI for Atmel Dataflash
      SPI_MISO              : in    std_logic;
      SPI_MOSI              : out   std_logic;
      SPI_SCK               : out   std_logic;
      SPI_SS_B              : out   std_logic := '1';
      DATAFLASH_WP          : out   std_logic;
      DATAFLASH_RST         : out   std_logic;
       -- LCD interface
      LCD_DB                : inout std_logic_vector(7 downto 0);
      LCD_E, LCD_RS, LCD_RW : out   std_logic
      );
end toplevel;

architecture Behavioral of toplevel is
  component dcm_in50
    port (
      CLKIN_IN        : in  std_logic;
      RST_IN          : in  std_logic;
      CLKFX_OUT       : out std_logic;
      CLKIN_IBUFG_OUT : out std_logic;
      CLK0_OUT        : out std_logic;
      LOCKED_OUT      : out std_logic);
  end component;
  
component memory
    port (
      DATA_I     : in  STD_LOGIC_VECTOR (7 downto 0);
      DATA_O     : out STD_LOGIC_VECTOR (7 downto 0);
      ADDR_I     : in  STD_LOGIC_VECTOR (15 downto 0);
      RD_N       : in  STD_LOGIC;
      WR_N       : in  STD_LOGIC;
      MREQ_N     : in  STD_LOGIC;
      CLK        : in  STD_LOGIC;
      CLKEN      : in STD_LOGIC;
      VID_DATA_O : out STD_LOGIC_VECTOR(7 downto 0);
      VID_ADDR_I : in  STD_LOGIC_VECTOR(9 downto 0);
      VID_CLK    : in  STD_LOGIC);
  end component;

component T80se
  generic (
    Mode : integer := 0;
    T2Write : integer := 0;
    IOWait : integer := 0);
  port (
    RESET_n : in  std_logic;
    CLK_n   : in  std_logic;
    CLKEN   : in  std_logic;
    WAIT_n  : in  std_logic;
    INT_n   : in  std_logic;
    NMI_n   : in  std_logic;
    BUSRQ_n : in  std_logic;
    M1_n    : out std_logic;
    MREQ_n  : out std_logic;
    IORQ_n  : out std_logic;
    RD_n    : out std_logic;
    WR_n    : out std_logic;
    RFSH_n  : out std_logic;
    HALT_n  : out std_logic;
    BUSAK_n : out std_logic;
    A       : out std_logic_vector(15 downto 0);
    DI     : in  std_logic_vector(7 downto 0);
    DO    : out std_logic_vector(7 downto 0));
end component;

component video
  port (
    CLK              : in  std_logic;
    DATA_I           : in  std_logic_vector(7 downto 0);
    ADDR_O           : out std_logic_vector(9 downto 0);
    RED, GREEN, BLUE : out std_logic_vector(3 downto 0);
    VSYNC, HSYNC     : out std_logic);
end component;

component keyboard
  port (
    PS2_CLK    : inout std_logic;
    PS2_DATA   : inout std_logic;
    CLK_16M    : in    std_logic;
    IORQ_n     : in    std_logic;
    RD_n, WR_n : in    std_logic;
    DATA_I     : in    std_logic_vector(7 downto 0);
    DATA_O     : out   std_logic_vector(7 downto 0);
    DEBUG      : out   std_logic_vector(7 downto 0));
end component;

component uart
  port (
    CLK_16M            : in  std_logic;
    DATA_I             : in  std_logic_vector(7 downto 0);
    ADDR_I             : in  std_logic_vector(1 downto 0);
    IORQ_n, RD_n, WR_n : in  std_logic;
    DATA_O             : out std_logic_vector(7 downto 0);
    -- SPI for Atmel Dataflash
    SPI_MISO              : in    std_logic;
    SPI_MOSI              : out   std_logic;
    SPI_SCK               : out   std_logic;
    SPI_SS_B              : out   std_logic := '1';
    DATAFLASH_WP          : out   std_logic;
    DATAFLASH_RST         : out   std_logic;
     -- LCD interface
    LCD_DB                : inout std_logic_vector(7 downto 0);
    LCD_E, LCD_RS, LCD_RW : out   std_logic;
    -- Buttons
    BTN_NORTH : in STD_LOGIC;
    BTN_SOUTH : in STD_LOGIC;
    BTN_EAST  : in STD_LOGIC;
    BTN_WEST  : in STD_LOGIC;
    ROT_CENTER : in STD_LOGIC);
end component;

signal CLK_16M, CLK_25M : std_logic;

signal z80cpu_addr: std_logic_vector(15 downto 0);
signal z80cpu_datao, z80cpu_datai, memory_datao: std_logic_vector(7 downto 0);
signal z80cpu_mreq_n, z80cpu_iorq_n, z80cpu_wr_n, z80cpu_rd_n,
       z80cpu_clken, z80cpu_halt_n, z80cpu_busak_n, z80cpu_m1_n,
       z80cpu_rfsh_n, z80cpu_reset_n: std_logic;

signal video_datai : std_logic_vector(7 downto 0);
signal video_addro : std_logic_vector(9 downto 0);

signal red_out, blue_out, green_out : std_logic_vector(3 downto 0);
signal hsync_out, vsync_out : std_logic;

signal keyb_datao : std_logic_vector(7 downto 0);
signal keyb_iorq_n : std_logic;

signal uart_datao : std_logic_vector(7 downto 0);
signal uart_iorq_n : std_logic;

-- shift register for z80 CLKEN
-- signal z80cpu_clken_gen : std_logic_vector(1 downto 0) := "01";  -- = 8 MHz
-- signal z80cpu_clken_gen : std_logic_vector(3 downto 0) := "0001";  -- = 4 MHz
 signal z80cpu_clken_gen : std_logic_vector(7 downto 0) := "00000001";  -- = 2 MHz
-- signal z80cpu_clken_gen : std_logic_vector(255 downto 0) := X"0000000000000000000000000000000000000000000000000000000000000001";  -- = 62.5 KHz
signal stop : std_logic := '0';
begin
dcm_in50_inst: dcm_in50
    port map (
      CLKIN_IN        => CLKIN_50M,
      RST_IN          => '0',
      CLKFX_OUT       => CLK_16M,
      CLKIN_IBUFG_OUT => open,
      CLK0_OUT        => CLK_25M,
      LOCKED_OUT      => open);
    
clken: process(CLK_16M)
  begin
    if rising_edge(CLK_16M) then
      z80cpu_clken_gen <= z80cpu_clken_gen((z80cpu_clken_gen'left-1) downto 0)
                          & z80cpu_clken_gen(z80cpu_clken_gen'left);
      if BTN_NORTH = '1' then
        stop <= '0';
      elsif (z80cpu_iorq_n = '0') and (SW(3) = '1') then
        stop <= '1';
      end if;
    end if;
  end process;

z80cpu_clken <= '1' when (stop = '0') and (z80cpu_clken_gen(z80cpu_clken_gen'left) = '1') else
                '0';

z80cpu_reset_n <= '0' when (BTN_SOUTH = '1') else
                  '1';
  
z80cpu_datai <= memory_datao when z80cpu_mreq_n = '0' else
                keyb_datao when (z80cpu_iorq_n = '0') and (z80cpu_addr(2 downto 0) = "000") else
                uart_datao when (z80cpu_iorq_n = '0') and (z80cpu_addr(2 downto 0) = "001") else
                uart_datao when (z80cpu_iorq_n = '0') and (z80cpu_addr(2 downto 0) = "010") else
                "XXXXXXXX";

z80cpu_inst : T80se port map (
  RESET_n => z80cpu_reset_n,
  CLK_n   => CLK_16M,
  CLKEN   => z80cpu_clken,
  WAIT_n  => '1',
  INT_n   => '1',
  NMI_n   => '1',
  BUSRQ_n => '1',
  M1_n    => z80cpu_m1_n,
  MREQ_n  => z80cpu_mreq_n,
  IORQ_n  => z80cpu_iorq_n,
  RD_n    => z80cpu_rd_n,
  WR_n    => z80cpu_wr_n,
  RFSH_n  => z80cpu_rfsh_n,
  HALT_n  => z80cpu_halt_n,
  BUSAK_n => z80cpu_busak_n,
  A       => z80cpu_addr,
  DI      => z80cpu_datai,
  DO      => z80cpu_datao);


--LED <= z80cpu_iorq_n & z80cpu_rd_n & z80cpu_wr_n & z80cpu_addr(1) & "0000";
  
memory_inst: memory port map(	DATA_I => z80cpu_datao,
                                DATA_O => memory_datao,
                                ADDR_I => z80cpu_addr,
                                RD_N => z80cpu_rd_n,
                                WR_N => z80cpu_wr_n,
                                MREQ_N => z80cpu_mreq_n,
                                CLK => CLK_16M,
                                CLKEN => z80cpu_clken,
                                VID_DATA_O => video_datai,
                                VID_ADDR_I => video_addro,
                                VID_CLK => CLK_25M);


keyb_iorq_n <= '0' when (z80cpu_iorq_n = '0') and (z80cpu_addr(2 downto 0) = "000") else
               '1';
  
keyboard_inst : keyboard port map (
  PS2_CLK  => PS2_CLK1,
  PS2_DATA => PS2_DATA1,
  CLK_16M  => CLK_16M,
  IORQ_n   => keyb_iorq_n,
  RD_n     => z80cpu_rd_n,
  WR_n     => z80cpu_wr_n,
  DATA_I   => z80cpu_datao,
  DATA_O   => keyb_datao,
  DEBUG    => LED);

uart_iorq_n <= '0' when (z80cpu_iorq_n = '0') and ((z80cpu_addr(2 downto 0) = "001") or
                                                   (z80cpu_addr(2 downto 0) = "010")) else
               '1';
  
uart_inst : uart port map (
  CLK_16M => CLK_16M,
  DATA_I  => z80cpu_datao,
  ADDR_I  => z80cpu_addr(1 downto 0),
  RD_n    => z80cpu_rd_n,
  WR_n    => z80cpu_wr_n,
  IORQ_n  => uart_iorq_n,
  DATA_O  => uart_datao,
  SPI_MISO => SPI_MISO,
  SPI_MOSI => SPI_MOSI,
  SPI_SCK  => SPI_SCK,
  SPI_SS_B => SPI_SS_B,
  DATAFLASH_WP => DATAFLASH_WP,
  DATAFLASH_RST => DATAFLASH_RST,
  LCD_DB => LCD_DB,
  LCD_E  => LCD_E,
  LCD_RS => LCD_RS,
  LCD_RW => LCD_RW,
  BTN_NORTH => BTN_NORTH,
  BTN_EAST  => BTN_EAST,
  BTN_SOUTH => BTN_SOUTH,
  BTN_WEST  => BTN_WEST,
  ROT_CENTER => ROT_CENTER
  );
  
video_inst : video port map (
  CLK    => CLK_25M,
  DATA_I => video_datai,
  ADDR_O => video_addro,
  RED    => red_out,
  GREEN  => green_out,
  BLUE   => blue_out,
  VSYNC  => vsync_out,
  HSYNC  => hsync_out);

RED <= red_out;
GREEN <= green_out;
BLUE <= blue_out;
HSYNC <= hsync_out;
VSYNC <= vsync_out;
end Behavioral;

