library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_arith.all;
use ieee.std_logic_unsigned.all;

use work.sercon_types.all;

entity top_master_controller is

  generic(
    no_slaves:natural:=16
    );
  
  port(
    rstin: in std_logic;
    clkin: in std_logic;
    -- usb interface:
    sx2_ifclk: out std_logic;
    sx2_int: in std_logic;
    sx2_ready: in std_logic;
    sx2_reset: out std_logic;
    sx2_sloe: out std_logic;
    sx2_slrd: out std_logic;
    sx2_slwr: out std_logic;
    sx2_pkt_end: out std_logic;
    sx2_fifo_address:out std_logic_vector(2 downto 0);
    sx2_flag_a: in std_logic;
    sx2_flag_b: in std_logic;
    sx2_flag_c: in std_logic;
    sx2_wakeup: out std_logic;
    sx2_n_cs  : out std_logic;
    sx2_fifo_data: inout std_logic_vector(15 downto 0);
    usb_nc: in std_logic;
    --
    tck:inout std_logic;
    tms:inout std_logic;
    tdi:inout std_logic;
    tdo:in std_logic;
    --
    lvds_enable: out std_logic;
    --
    slave_clk: out std_logic_vector(no_slaves-1 downto 0);
    --
    spill_start: out std_logic_vector(no_slaves-1 downto 0);
    --
    -- ext_spill_active:std_logic;
    --
    -- interfaces to the TTL buffers:
    noe0: out std_logic;
    dir0: out std_logic;
    indicator: out std_logic_vector(7 downto 0);

    noe1: out std_logic;
    dir1: out std_logic;
    trig_in_se: in std_logic_vector(7 downto 0);
    
    trig_in_p: in std_logic_vector(7 downto 0);
    trig_in_n: in std_logic_vector(7 downto 0)    
    );

end entity top_master_controller;

architecture v0 of top_master_controller is

  constant int_high:std_logic:='1';
  constant int_low:std_logic:='0';
  
  component sx2_ui
    port(
      rstin: in std_logic;
      clkin: in std_logic;
      --
      sysclk: out std_logic;
      logic_reset: out std_logic;

      -- usb interface:
      sx2_ifclk: out std_logic;
      sx2_int: in std_logic;
      sx2_ready: in std_logic;
      sx2_reset: out std_logic;
      sx2_sloe: out std_logic;
      sx2_slrd: out std_logic;
      sx2_slwr: out std_logic;
      sx2_pkt_end: out std_logic;
      sx2_fifo_address:out std_logic_vector(2 downto 0);
      sx2_flag_a: in std_logic;
      sx2_flag_b: in std_logic;
      sx2_flag_c: in std_logic;
      sx2_wakeup: out std_logic;
      sx2_n_cs  : out std_logic;
      sx2_fifo_data: inout std_logic_vector(15 downto 0);
      usb_nc: in std_logic;
      --
      flush_sx2_buffers: in std_logic:='0';
      -- user configuration interface:
      config_control: out sercon_ctrl;
      config_src: out sercon_bus;
      config_dest: in sercon_bus;
      -- data pipe for block transfers into the design (from the pc):
      wren: out std_logic;
      full: in std_logic;
      data_from_pc: out std_logic_vector(15 downto 0);
      -- data pipe for block transfers out of the design (to the pc):
      rden: out std_logic;
      empty: in std_logic;
      data_to_pc: in std_logic_vector(15 downto 0)
      );
  end component sx2_ui;
  
  signal int_logic_reset:std_logic;
  signal int_sysclk: std_logic;

  signal int_data_to_pc:std_logic_vector(15 downto 0);
  signal int_trigger_record_empty: std_logic;
  signal int_trigger_record_rden: std_logic;
  signal int_trigger_record_wren: std_logic;
  signal int_trigger_record_full: std_logic;
  signal int_trigger_record_overflow: std_logic;

  
  constant int_reg_block_size:natural:=6;
  signal int_reg_block:long_word_array(int_reg_block_size-1 downto 0);

  signal int_config_ctrl:sercon_ctrl;
  signal int_config_bus_0:sercon_bus;
  signal int_config_bus_1:sercon_bus;
  signal int_config_bus_2:sercon_bus;
  signal int_config_bus_3:sercon_bus;
  signal int_config_bus_dest:sercon_bus;

  signal int_trigger:std_logic_vector(31 downto 0);
  signal int_status:std_logic_vector(31 downto 0);
    
  component sercon_block
    generic(
      n_regs : natural:=3;
      bit_width : natural:=sercon_bit_width
      );
    port(
      ctrl : in sercon_ctrl;
      sbus_in : in sercon_bus;
      sbus_out : out sercon_bus;
      pdout : out long_word_array(n_regs-1 downto 0)
      );
  end component sercon_block;

  component sercon_trig
    generic(
      bit_width : natural:=32
      );
    port(
      ctrl : in sercon_ctrl;
      sbus_in : in sercon_bus;
      sbus_out : out sercon_bus;
      pdout : out std_logic_vector(bit_width-1 downto 0);
      pdin : in std_logic_vector(bit_width-1 downto 0)
      );
  end component sercon_trig;

  component sercon_info
    port(
      ctrl : in sercon_ctrl;
      sbus_in : in sercon_bus;
      sbus_out : out sercon_bus
      );
  end component sercon_info;

  component sercon_stat
    generic(
      bit_width : natural:=32
      );
    port(
      ctrl : in sercon_ctrl;
      sbus_in : in sercon_bus;
      sbus_out : out sercon_bus;
      pdin : in std_logic_vector(bit_width-1 downto 0)
      );
  end component sercon_stat;

  
  component trig_output
    port(
      clk : in std_logic;
      trig_in : in std_logic;
      trig_out : out std_logic
      );
  end component trig_output;

  --
  --
  component ddr_clk_gen
    port(
      rst : in std_logic;
      clkin  : in std_logic;
      logic_reset : out std_logic;
      clk : out std_logic;
      clkb : out std_logic

      );
  end component ddr_clk_gen;

  component slave_clk_driver
    port(
      rst : in std_logic;
      clk : in std_logic;
      clkb : in std_logic;
      clk_out : out std_logic
      );
  end component slave_clk_driver;
  
  signal int_clk0_40: std_logic;
  signal int_clk180_40: std_logic;
  signal int_logic_reset1: std_logic;

  signal int_spill_start: std_logic;
  signal int_spill_start_delayed: std_logic;
  
--   component trigger_record_buf
--     port(
--       din : in std_logic_vector(15 downto 0);
--       rd_clk : in std_logic;
--       rd_en : in std_logic;
--       rst : in std_logic;
--       wr_clk : in std_logic;
--       wr_en : in std_logic;
--       dout : out std_logic_vector(15 downto 0);
--       empty : out std_logic;
--       full : out std_logic
--       );
--   end component trigger_record_buf;

  
  component spill_emulator
    port(
      rst : in std_logic;
      clk : in std_logic;
      buffer_rst: in std_logic;
      reset_length : in std_logic_vector(15 downto 0);
      bx_count_start : in std_logic_vector(12 downto 0);
      bx_length: in std_logic_vector(7 downto 0);
      bt_length : in std_logic_vector(12 downto 0);

      busy: out std_logic;
      spill_start : in std_logic;
      spill_active : out std_logic;
      bx_end : out std_logic;
      
      start_tt: in std_logic_vector(31 downto 0);
      end_tt: in std_logic_vector(31 downto 0);
      test_trigger: out std_logic;
      
      trigger_input : in std_logic_vector(15 downto 0);

      ro_clk: in std_logic;
      buf_overflow : out std_logic;
      buf_empty : out std_logic;
      buf_rden : in std_logic;
      buf_data : out std_logic_vector(15 downto 0)
      );
  end component spill_emulator;

  signal int_busy: std_logic;
  signal int_reset_length:std_logic_vector(15 downto 0);
  signal int_bx_count_start:std_logic_vector(12 downto 0);
  signal int_bx_length: std_logic_vector(7 downto 0);
  signal int_bt_length:std_logic_vector(12 downto 0);
  -- signal int_spill_start:std_logic;
  signal int_spill_active:std_logic;
  signal int_bx_end:std_logic;
  signal int_trigger_input:std_logic_vector(15 downto 0);
  signal int_buf_overflow:std_logic;
  signal int_buf_empty:std_logic;
  signal int_buf_rden:std_logic;
  signal int_buf_data:std_logic_vector(15 downto 0);

  signal int_start_tt: std_logic_vector(31 downto 0);
  signal int_end_tt: std_logic_vector(31 downto 0);
  signal int_test_trigger: std_logic;
  
  signal int_ttl_config:std_logic_vector(2 downto 0);
  
  
  component simple_trigger_input_latch
    port(
      srst : in std_logic;
      clk : in std_logic;
      enable : in std_logic_vector(15 downto 0);
      invert_mask : in std_logic_vector(15 downto 0);
      trig_in_se : in std_logic_vector(7 downto 0);
      trig_in_p : in std_logic_vector(7 downto 0);
      trig_in_n : in std_logic_vector(7 downto 0);
      trig_out : out std_logic_vector(15 downto 0);
      trig_out_rt: out std_logic_vector(15 downto 0)
      );
  end component simple_trigger_input_latch;

  signal int_stl_enable:std_logic_vector(15 downto 0);
  signal int_stl_invert_mask: std_logic_vector(15 downto 0);
  signal int_trig_rt: std_logic_vector(15 downto 0);

  signal int_clock_lock:std_logic;
  signal int_tms: std_logic;
  signal int_tdi: std_logic;
  signal int_tdo: std_logic;
  signal int_jtag_driver_busy: std_logic;
  component jtag_driver
    port(
      rst : in std_logic;
      clk : in std_logic;
      busy: out std_logic;
      clock_lock : in std_logic;
      int_tms : in std_logic;
      int_tdi : in std_logic;
      int_tdo : out std_logic;
      tck : inout std_logic;
      tms : inout std_logic;
      tdi : inout std_logic;
      tdo : in std_logic
      );
  end component jtag_driver;


  signal int_sx2_buffer_flush: std_logic;
  
begin

   u_sx2_ui:sx2_ui
    port map(
      rstin=>rstin,
      clkin=>clkin,
      --
      sysclk=>int_sysclk,
      logic_reset=>int_logic_reset,

      -- usb interface=>,
      sx2_ifclk=>sx2_ifclk,
      sx2_int=>sx2_int,
      sx2_ready=>sx2_ready,
      sx2_reset=>sx2_reset,
      sx2_sloe=>sx2_sloe,
      sx2_slrd=>sx2_slrd,
      sx2_slwr=>sx2_slwr,
      sx2_pkt_end=>sx2_pkt_end,
      sx2_fifo_address=>sx2_fifo_address,
      sx2_flag_a=>sx2_flag_a,
      sx2_flag_b=>sx2_flag_b,
      sx2_flag_c=>sx2_flag_c,
      sx2_wakeup=>sx2_wakeup,
      sx2_n_cs  =>sx2_n_cs,
      sx2_fifo_data=>sx2_fifo_data,
      usb_nc=>usb_nc,
      --
      flush_sx2_buffers=>int_sx2_buffer_flush,

      -- user configuration interface=>,
      config_control=>int_config_ctrl,
      config_src=>int_config_bus_0,
      config_dest=>int_config_bus_dest,
      
      -- data pipe for block transfers into the design (from the pc)=>,
      wren=>open,--int_loopback_wren,
      full=>int_low,--int_loopback_full,
      data_from_pc=>open,--int_data_from_pc,
      -- data pipe for block transfers out of the design (to the pc)=>,
      rden=>int_trigger_record_rden,
      empty=>int_trigger_record_empty,
      data_to_pc=>int_data_to_pc
      );

   int_sx2_buffer_flush<=int_trigger(3);
   
   --
   -- configuration, control & status section:
   -- 
   
   u_sercon_block:sercon_block
     generic map(
       n_regs=>int_reg_block_size,
       bit_width=>sercon_bit_width
       )
     port map(
       ctrl=>int_config_ctrl,
       sbus_in=>int_config_bus_0,
       sbus_out=>int_config_bus_1,
       pdout=>int_reg_block
       );

   u_sercon_trig:sercon_trig
     generic map(
       bit_width=>32
       )
     port map(
       ctrl=>int_config_ctrl,
       sbus_in=>int_config_bus_1,
       sbus_out=>int_config_bus_2,
       pdout=>int_trigger,
       pdin=>int_status
       );

   
   u_sercon_stat:sercon_stat
     generic map(
       bit_width=>32
       )
     port map(
       ctrl=>int_config_ctrl,
       sbus_in=>int_config_bus_2,
       sbus_out=>int_config_bus_3,
       pdin=>int_status);

   u_sercon_info:sercon_info
     port map(
       ctrl=>int_config_ctrl,
       sbus_in=>int_config_bus_3,
       sbus_out=>int_config_bus_dest
       );


   -- in-system updates hook. 
   int_clock_lock<=int_reg_block(5)(0);
   int_tms<=int_reg_block(5)(1);
   int_tdi<=int_reg_block(5)(2);
   int_status(3)<=int_tdo;
   int_status(4)<=int_jtag_driver_busy;
   
   u_jtag_driver:jtag_driver
     port map(
       rst=>int_logic_reset,
       clk=>int_sysclk,
       busy=>int_jtag_driver_busy, 
       clock_lock=>int_clock_lock,
       int_tms=>int_tms,
       int_tdi=>int_tdi,
       int_tdo=>int_tdo,
       tck=>tck,
       tms=>tms,
       tdi=>tdi,
       tdo=>tdo);


   -- 
   -- ddr clock generation:
   -- 
   u_ddr_clk_gen:ddr_clk_gen
     port map(
       rst=>int_logic_reset,
       clkin =>int_sysclk,
       logic_reset=>int_logic_reset1,
       clk=>int_clk0_40,   
       clkb=>int_clk180_40
       );
   
   
   -- 
   -- spill start registers:
   --
   -- map the trigger bit to the
   -- spill start regs:
   int_spill_start<=int_trigger(0);
   
   u_gen_trig_output:for i in 0 to (no_slaves-1)
   generate
     u_trig_output:trig_output
       port map(
         clk=>int_clk0_40,
         trig_in=>int_spill_start,
         trig_out=>spill_start(i)
         );
   end generate u_gen_trig_output;

   
   -- models the delay to ensure that the
   -- internal spill emulator isn't
   -- triggered too early:
   u_trig_internal:trig_output
     port map(
       clk=>int_clk0_40,
       trig_in=>int_spill_start,
       trig_out=>int_spill_start_delayed
       );
   
   
   -- temporary:
   indicator(0)<=int_trigger(1);
   indicator(1)<=int_trigger(2);
   indicator(2)<=int_ttl_config(0);  
   indicator(3)<=int_ttl_config(1);
   indicator(4)<=int_ttl_config(2);
   indicator(5)<=int_test_trigger;
   indicator(6)<=int_spill_active;
   indicator(7)<=int_bx_end;
   

   ------------------------------
   -- spill emulator configuration
   -- mappings: 
   
   int_reset_length<=int_reg_block(0)(15 downto 0);
   int_bx_count_start<=int_reg_block(0)(28 downto 16);

   int_ttl_config(2 downto 0)<=int_reg_block(0)(31 downto 29);
   
   
   int_bx_length<=int_reg_block(1)(7 downto 0); 
   int_bt_length<=int_reg_block(1)(20 downto 8);
   --int_spill_start<=;
   --int_trigger_input<=;


   --int_bx_end<=;
   int_status(0)<=int_spill_active;
   int_status(1)<=int_buf_overflow;
   int_status(2)<=int_trigger_record_empty;
   int_status(5)<=int_busy;

   int_status(31 downto 16)<=int_trig_rt;
   
   int_status(15 downto 6)<="0000000000";
   
   ------------------------------
   -- 
   -- spill emulator instance:
   -- 
   u_spill_emulator:spill_emulator
     port map(
       rst=>int_logic_reset1,
       clk=>int_clk0_40,
       buffer_rst=>int_trigger(4),
       reset_length=>int_reset_length,
       bx_length=>int_bx_length,
       bx_count_start=>int_bx_count_start,
       bt_length=>int_bt_length,
       busy=>int_busy,
       spill_start=>int_spill_start_delayed,
       spill_active=>int_spill_active,
       bx_end=>int_bx_end,

       start_tt=>int_start_tt,
       end_tt=>int_end_tt, 
       test_trigger=>int_test_trigger,
       
       trigger_input=>int_trigger_input,

       ro_clk=>int_sysclk,
       buf_overflow=>int_buf_overflow,
       buf_empty=>int_trigger_record_empty,
       buf_rden=>int_trigger_record_rden,
       buf_data=>int_data_to_pc);


   -- the trigger input latch and mappings:
   int_stl_enable<=int_reg_block(2)(15 downto 0);
   int_stl_invert_mask<=int_reg_block(2)(31 downto 16);

   int_start_tt<=int_reg_block(3);
   int_end_tt<=int_reg_block(4);
   
   

   u_simple_trigger_input_latch:simple_trigger_input_latch
     port map(
       srst=>int_bx_end,
       clk=>int_clk0_40,
       enable=>int_stl_enable,
       invert_mask=>int_stl_invert_mask,
       trig_in_se=>trig_in_se,
       trig_in_p=>trig_in_p,
       trig_in_n=>trig_in_n,
       trig_out=>int_trigger_input,
       trig_out_rt=>int_trig_rt
       );
      
   
   --
   -- instance the number of slave clock outputs
   -- required:
   -- 
   u_gen_slave_clks:for i in 0 to (no_slaves-1)
   generate
     u_cd:slave_clk_driver
       port map(
         rst=>int_logic_reset1, 
         clk=>int_clk0_40,
         clkb=>int_clk180_40,
         clk_out=>slave_clk(i)
         );
   end generate u_gen_slave_clks;
   
   -- fix the lvds outputs on:
   lvds_enable<='1';

   -- output enabled, direction: output from the card
   noe0<='0';
   dir0<='1';

   -- output enabled, direction: input to the card
   noe1<='0';
   dir1<='0';
   
end architecture v0;
