-- WWW.FPGAArcade.COM
-- REPLAY 1.0
-- Retro Gaming Platform
-- No Emulation No Compromise
--
-- All rights reserved
-- Mike Johnson 2008/2009
--
-- Redistribution and use in source and synthezised forms, with or without
-- modification, are permitted provided that the following conditions are met:
--
-- Redistributions of source code must retain the above copyright notice,
-- this list of conditions and the following disclaimer.
--
-- Redistributions in synthesized form must reproduce the above copyright
-- notice, this list of conditions and the following disclaimer in the
-- documentation and/or other materials provided with the distribution.
--
-- Neither the name of the author nor the names of other contributors may
-- be used to endorse or promote products derived from this software without
-- specific prior written permission.
--
-- THIS CODE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-- AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
-- THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
-- PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE
-- LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-- CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-- SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-- INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-- CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-- ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-- POSSIBILITY OF SUCH DAMAGE.
--
-- You are responsible for any legal issues arising from your use of this code.
--
-- The latest version of this file can be found at: www.FPGAArcade.com
--
-- Email support@fpgaarcade.com
--
-- ===================================================================
--
-- This file was modified to embed Mikes VIC-20 core by W. Scherr
-- Email ws_arcade <at> pin4.at
--
-- $Id: Replay_Top.vhd 387 2014-03-01 21:30:37Z wolfgang.scherr $
--
-- Latest version can be found at: www.pin4.at
--
-- ===================================================================

library ieee;
  use ieee.std_logic_1164.all;
  use ieee.std_logic_unsigned.all;
  use ieee.numeric_std.all;

  use work.replay_pack.all;
  use work.replay_videotiming_pack.all;

library UNISIM;
  use UNISIM.Vcomponents.all;

entity Replay_Top is
  port (
    -- RS232 debug port
    i_rs232_rxd           : in    bit1;
    o_rs232_txd           : out   bit1;
    i_rs232_cts           : in    bit1;
    o_rs232_rts           : out   bit1;
    -- joysticks
    i_joy_a               : in    word( 5 downto 0);
    i_joy_b               : in    word( 5 downto 0);
    -- io
    b_io                  : inout word(54 downto 0);
    b_aux_io              : inout word(39 downto 0);

    i_aux_ip              : in    word(22 downto 0);
    -- dram
    o_mem_addr            : out   word(14 downto 0);
    b_mem_dq              : inout word(15 downto 0);
    b_mem_udqs            : inout bit1; -- Ctrl8
    b_mem_ldqs            : inout bit1; -- Ctrl7
    o_mem_udm             : out   bit1; -- Ctrl6
    o_mem_ldm             : out   bit1; -- Ctrl5
    o_mem_cs              : out   bit1; -- Ctrl4
    o_mem_ras             : out   bit1; -- Ctrl3
    o_mem_cas             : out   bit1; -- Ctrl2
    o_mem_we              : out   bit1; -- Ctrl1
    o_mem_cke             : out   bit1; -- Ctrl0
    o_mem_clk_p           : out   bit1;
    o_mem_clk_n           : out   bit1;
    --
    o_disk_led            : out   bit1;
    o_pwr_led             : out   bit1;
    --
    i_ext_rst_l           : in    bit1; -- pullup
    b_2v5_io_1            : inout bit1;
    b_2v5_io_0            : inout bit1;
    -- video
    o_video_clk_p         : out   bit1;
    o_video_clk_n         : out   bit1;
    o_video_rst_l         : out   bit1; -- Video16
    i_video_int           : in    bit1; -- Video15
    o_video_de            : out   bit1; -- Video14
    o_video_v             : out   bit1; -- Video13
    o_video_h             : out   bit1; -- Video12
    o_video_data          : out   word(11 downto 0);  --Video11..0
    b_video_ddc_clk       : out   bit1;
    b_video_ddc_data      : out   bit1;
    o_video_hsync         : out   bit1;
    o_video_vsync         : out   bit1;
    b_video_spc           : inout bit1;
    b_video_spd           : inout bit1;
    -- audio
    o_audio_lrcin         : out   bit1; -- Audio3
    o_audio_mclk          : out   bit1; -- Audio2
    o_audio_bckin         : out   bit1; -- Audio1
    o_audio_din           : out   bit1; -- Audio0
    --
    b_ps2a_clk            : inout bit1;
    b_ps2a_data           : inout bit1;
    b_ps2b_clk            : inout bit1;
    b_ps2b_data           : inout bit1;

    b_scl                 : inout bit1;
    b_sda                 : inout bit1;

    -- system control
    i_fpga_ctrl0          : in    bit1;
    i_fpga_ctrl1          : in    bit1;
    i_fpga_spi_clk        : in    bit1;
    b_fpga_spi_mosi       : inout bit1;
    b_fpga_spi_miso       : inout bit1;

    -- ssc & config pins
    --i_ssc_tf              : in    bit1; --io_init input during config
    --i_ssc_td              : in    bit1; --io_din  input during config
    --i_ssc_rk              : in    bit1; --io_cclk input during config
    o_ssc_rd              : out   bit1; --io_dout output during config -- vertical sync for MCU (sync OSD update)
    --
    -- clocks
    --
    o_clk_68k             : out   bit1; -- source terminated to connector
    b_clk_aux             : inout bit1; -- direct to connector
    i_clk_a                 : in    bit1;
    i_clk_b                 : in    bit1;
    i_clk_c                 : in    bit1

    );
end;

architecture RTL of Replay_Top is

  constant dla_mem_enable : boolean := false;

  signal clk_spi                : bit1;

  signal clk_vid                : bit1;
  signal clk_vid_90             : bit1;
  signal ena_vid                : bit1;
  signal rst_vid                : bit1;
  signal rst_vid_hard           : bit1;

  signal clk_sys                : bit1; -- note, same at clk_ctl
  signal ena_sys                : bit1;
  signal ena_sub1               : bit1;
  signal ena_sub4               : bit1;
  signal rst_sys                : bit1;

  signal clk_ctl                : bit1;
  signal rst_ctl                : bit1;
  signal rst_ctl_hard           : bit1;
  signal tick_ctl_1us           : bit1;
  signal tick_ctl_100us         : bit1;

  signal rst_aud                : bit1;
  signal clk_aud                : bit1;

  signal clk_ram                : bit1;
  signal clk_ram_90             : bit1;
  signal clk_capture            : bit1;
  signal rst_ram                : bit1;
  signal rst_capture            : bit1;
  signal rst_soft               : bit1;
  signal halt_soft              : bit1;
  --
  signal drive_scl_low          : bit1;
  signal drive_sda_low          : bit1;
  signal drive_spc_low          : bit1;
  signal drive_spd_low          : bit1;

  signal cfg_phase              : word(7 downto 0);
  signal cfg_cal_sel            : word(1 downto 0);

  signal core_ps2_clk           : bit1;
  signal core_ps2_data          : bit1;

  signal ps2a_drive_clk_low     : bit1;
  signal ps2a_drive_data_low    : bit1;
  signal ps2b_drive_clk_low     : bit1;
  signal ps2b_drive_data_low    : bit1;

  signal led : bit1;
  signal tick_pre1 : bit1;
  signal tick : bit1;

  signal ram_addr             :   word(24 downto 2);
  signal ram_data             :    word(63 downto 0);
  signal ram_r_w_l            :    bit1;
  signal ram_valid            :   bit1;

  signal core_audio_l : word(23 downto 0);
  signal core_audio_r : word(23 downto 0);
  signal phy_audio_taken : bit1;

  signal core_vid_rgb             : word(23 downto 0);
  signal core_vid_sync            : r_Vidsync;
  signal core_vid_timing          : r_Vidtiming;
  signal core_vid_std             : r_Vidstd;

  signal cfg_static : word(31 downto 0);
  signal cfg_dynamic : word(31 downto 0);
  signal cfg_ctrl : word(15 downto 0);
  signal cfg_fileio_i : word(7 downto 0);
  signal cfg_fileio : word(7 downto 0);

  signal mode_1541  : bit1;
  signal mode_key   : bit1;

  signal conf_valid : bit1;
  signal conf_taken : bit1;
  signal conf_write : bit1;
  signal conf_wr_core              : bit1 := '0';
  signal conf_wr_1541              : bit1 := '0';
  signal conf_wr_key               : bit1 := '0';

  --
  -- MCH
  --
  signal mch_addr : word(31 downto 0);
  signal mch_read : bit1;
  signal mch_data : word(7 downto 0);
  signal mch_valid : bit1;
  signal mch_taken : bit1;
  signal mch_rd_data : word(7 downto 0);
  signal mch_rd_we : bit1;

  signal mch_ram_taken : word(0 downto 0);
  signal mch_ram_rd_data : array8(0 downto 0);
  signal mch_ram_rd_we : word(0 downto 0);

  signal mch_ddr_taken : bit1;
  signal mch_ddr_rd_data : word(7 downto 0);
  signal mch_ddr_rd_we : bit1;

  signal hp_ddr_taken : bit1;
  signal hp_ddr_valid : bit1;
  signal hp_ddr_we : bit1;
  signal hp_wl : bit1;
  signal hp_ddr_addr : word(25 downto 0);
  signal hp_rdata : word(31 downto 0);
  signal hp_wdata : word(31 downto 0);
  signal hp_wbe   : word(3 downto 0);

  signal media_adr : unsigned(17 downto 0);
  signal media_read : bit1;
  signal media_dat : word(7 downto 0);
  signal diskid_s : word(15 downto 0);
  signal inscnt_s : unsigned(18 downto 0);

  signal init_diskinsert_s : bit1;
  signal writeprotn_s : bit1;

  --
  --
  --
  signal syscon_vid_rgb           : word(23 downto 0);
  signal syscon_vid_sync          : r_Vidsync;
  signal spi_syscon_cs_l : bit1;
  signal spi_fileio_cs_l : bit1;
  signal spi_syscon_miso : bit1;
  signal spi_fileio_miso : bit1;

  signal kb_inhibit : bit1;
  signal kb_we : bit1;
  signal kb_ps2 : word(7 downto 0);
  signal kb_led : word(2 downto 0);

  signal ms_we               : bit1;
  signal ms_posx             : word(11 downto 0);
  signal ms_posy             : word(11 downto 0);
  signal ms_butn             : word( 2 downto 0);

  signal ena_sys_c1 : bit1;
  signal ena_sys_ddr : bit1;

  -- filio defaults - clearly wrong unless I want 1 fd/1hd on atari 800 :) Now implemented yet.
  constant cfg_fileio_cha_ena   : word(3 downto 0) := "1111"; -- FD
  constant cfg_fileio_cha_drv   : word(3 downto 0) := "0001"; -- driver 1 (FD)
  constant cfg_fileio_chb_ena   : word(3 downto 0) := "0011"; -- HD
  constant cfg_fileio_chb_drv   : word(3 downto 0) := "1000"; -- driver 8 (ATA)

begin
  u_spi_bufg  : BUFG  port map (I => i_FPGA_SPI_Clk, O => clk_spi);

  u_ClockGen : entity work.replay_clockgen
  generic map (
    G_DIVIDER             => 11
    )
  port map (
    i_ClK_A               => i_Clk_A,
    i_ClK_B               => i_Clk_B,
    i_ClK_C               => i_Clk_C,
    --
    i_Rst_L               => i_Ext_Rst_L, -- hard reset
    i_Rst_Soft            => rst_soft,    -- NOT DRAM!
    --
    i_Ctl_Phase           => cfg_phase,
    i_Clk_Ctl             => clk_ctl,
    --
    o_Clk_Vid             => clk_vid,
    o_Clk_Vid_90          => clk_vid_90,
    o_Rst_Vid             => rst_vid,
    o_Rst_Vid_Hard        => rst_vid_hard,
    --
    o_Clk_Ctl             => clk_ctl,
    o_Rst_Ctl             => rst_ctl,
    o_Rst_Ctl_Hard        => rst_ctl_hard,
    --
    o_Tick_Ctl_1us        => tick_ctl_1us,
    o_Tick_Ctl_100us      => tick_ctl_100us,
    --
    o_Clk_Aux             => clk_aud,
    o_Rst_Aux             => rst_aud,
    --
    o_Clk_Ram             => clk_ram,
    o_Clk_Ram_90          => clk_ram_90,
    o_Clk_Ram_Capture     => clk_capture,
    o_Rst_Ram             => rst_ram,
    o_Rst_Ram_Capture     => rst_capture
    );

  enas : block
    signal sys_cnt : word(1 downto 0) := (others => '0');
    signal sub_cnt : word(4 downto 0) := (others => '0');
  begin
    -- clk_ram and clk_sys are edge aligned.
    p_sys_cnt : process
    begin
      wait until rising_edge(clk_sys);
      sys_cnt <= sys_cnt + "1";
      sub_cnt <= sub_cnt + "1";

      ena_sys  <= '0';
      if (sys_cnt = "11" ) then -- 0...3 --> divdes by 4 
        ena_sys <= '1';
        sys_cnt <= "00";
      end if;
      ena_sub1 <= '0';
      ena_sub4 <= '0';
      if (sub_cnt = "00101" ) then -- 0...5 --> divdes by 6
        ena_sub4 <= '1';
      end if;
      if (sub_cnt = "01011" ) then -- 6...11 --> divdes by 6
        ena_sub4 <= '1';
      end if;
      if (sub_cnt = "10001" ) then -- 12...17 --> divdes by 6
        ena_sub4 <= '1';
      end if;
      if (sub_cnt = "10111" ) then -- 0...23 --> divdes by 24, -- 18...23 --> divdes by 6 
        ena_sub1 <= '1';
        ena_sub4 <= '1';
        sub_cnt <= "00000";
      end if;
      -- DDR needs divison by 4
      if sub_cnt(1 downto 0)="10" then
        ena_sys_ddr <= '1';
      else
        ena_sys_ddr <= '0';
      end if;
    end process;
    --ena_sys_c1 <= not ena_sub4; --sys_cnt(1);
    ena_sys_c1 <= not sub_cnt(1);

    ena_vid <= '1';
  end block;
  --
  -- clk_ctl is the same as clk_sys, but used with no clock enable
  -- names are to keep domains apart
  --
  clk_sys <= clk_ctl;
  rst_sys <= rst_ctl;
  --
  --
  --

  b_2V5_IO_1   <= 'Z';
  b_2V5_IO_0   <= 'Z';

  o_Clk_68K  <= 'Z';
  b_Clk_Aux  <= 'Z';

  b_tick : block
    signal PreCounter1 : word(15 downto 0);
    signal PreCounter2 : word(11 downto 0);
  begin
    p_count : process
    begin
      wait until rising_edge(clk_vid);
      if (ena_vid = '1') then
        PreCounter1 <= PreCounter1 - "1";

        tick_pre1 <= '0';
        if (PreCounter1 = x"0000") then
          tick_pre1 <= '1';
        end if;
        -- synopsys translate_off
        tick_pre1 <= '1';
        -- synopsys translate_on

        tick <= '0';
        if (tick_pre1 = '1') then
          if (PreCounter2 = x"000") then
            PreCounter2 <= x"19B";
            tick <= '1';
          else
            PreCounter2 <= PreCounter2 - "1";
          end if;
        end if;
      end if;
    end process;
  end block;

  o_Pwr_Led <= not init_diskinsert_s;

  b_IO(22 downto  0) <= (others => 'Z');
  b_IO(28 downto 23) <= (others => 'Z');
  b_IO(34 downto 29) <= (others => 'Z');
  b_IO(54 downto 35) <= (others => 'Z');

  b_Aux_IO(39 downto 36)  <=  (others => 'Z');

  -- prevent forwarding PS/2 to core when OSD is activated
  core_ps2_clk <= b_PS2B_Clk when kb_inhibit='0' else '1';
  core_ps2_data <= b_PS2B_Data when kb_inhibit='0' else '1';

  --
  -- CORE
  --
  u_Core : entity work.Core_Top
  port map (
    i_Clk_Vid             => clk_vid,
    i_Ena_Vid             => ena_vid,
    i_Rst_Vid             => rst_vid,
    --
    i_ClK_Sys             => clk_sys,
    i_Ena_Sys             => ena_sys,
    i_Ena_Sub1            => ena_sub1,
    i_Ena_Sub4            => ena_sub4,
    i_Rst_Sys             => rst_sys,
    --
    i_Joy_A               => i_Joy_A,
    i_Joy_B               => i_Joy_B,
    --
    i_Ms_We               => ms_we,
    i_Ms_PosX             => ms_posx,
    i_Ms_PosY             => ms_posy,
    i_Ms_Butn             => ms_butn,
    --
    i_kb_osd_inhibit      => kb_inhibit,
    i_kb_ps2_we           => kb_we,
    i_kb_ps2              => kb_ps2,
    o_kb_led              => kb_led,
    --
    core_ps2_data => core_ps2_data,
    core_ps2_clk => core_ps2_clk,
    --
    i_Rst_Core            => rst_soft,
    i_Halt_Core           => halt_soft,
    i_HD_Mode             => cfg_dynamic(16),
    i_scn_lvl             => cfg_dynamic(20 downto 19), -- sets scanline strength: "00": off ... "11": maximum
    o_act_led_n           => o_Disk_Led,
    --
    i_Audio_lvl           => cfg_dynamic(18 downto 17),
    o_Audio_l             => core_audio_l,
    o_Audio_R             => core_audio_r,
    i_Audio_Taken         => phy_audio_taken,
    --
    i_cart_ro             => cfg_static(5),          -- readonly-enable
    i_cart_en             => cfg_static(0),          -- at $A000(8k)     '1', --
    i_ram_ext             => cfg_static(4 downto 1), -- at $6000(8k),$4000(8k),$2000(8k),$0400(3k)  "1111", --
    drive_address         => "00",
    --
    o_Vid_RGB             => core_vid_rgb,
    o_Vid_Sync            => core_vid_sync,
    -- sideband info
    o_Vid_Timing          => core_vid_timing,
    o_Vid_Std             => core_Vid_Std,
    -- d64 reader
    diskid_i              => diskid_s,
    media_adr_o           => media_adr,
    media_read_o          => media_read,
    media_dat_i           => media_dat,
    write_prot_n          => writeprotn_s,
    floppy_inserted       => init_diskinsert_s,
    --
    hp_ddr_valid        => hp_ddr_valid,
    hp_ddr_taken        => hp_ddr_taken,
    hp_ddr_addr         => hp_ddr_addr(25 downto 2),
    hp_wl               => hp_wl,
    hp_wbe              => hp_wbe,
    hp_wdata            => hp_wdata,
    hp_rdata            => hp_rdata,
    hp_ddr_wr           => hp_ddr_we,
    --
    i_RS232_RXD         => i_RS232_RXD,
    o_RS232_TXD         => o_RS232_TXD,
    i_RS232_CTS         => i_RS232_CTS,
    o_RS232_RTS         => o_RS232_RTS,
    --debug                 => b_Aux_IO(35 downto 0), -- from 1541 core:   addr(16), di(8), do(8), wrn, ph2, motor, led
                                                      -- from 1541 stream: track(7), sector(8), region(2), bdata(8), byteready, sync, gdata(8), led
    --debug                 => b_Aux_IO(35 downto 0), -- from VIC20:       addr(16), dio(8), hs, vs, atn, clk, dat, <mode(3)>, r_wn, nmi, irq, res
    debug                 => open,
    debugi                => b_IO(2 downto 0),
    -- ROM config
    CONF_WR_KEY           => conf_wr_key,
    CONF_WR_1541          => conf_wr_1541,
    CONF_WR               => conf_wr_core,
    CONF_AI               => mch_addr(15 downto 0),
    CONF_DI               => mch_data,
    -- 
    ram_select            => cfg_dynamic(2 downto 0),
    speed_select          => cfg_dynamic(13 downto 9)
    );

  --                            8                16              1             1           1            1           1           1            1        1          1           1                 2
  b_Aux_IO(35 downto 0) <= mch_data & mch_addr(15 downto 0) & conf_wr_1541 & conf_wr_core & conf_valid & conf_write & '0' & mode_1541 & mch_taken & mch_valid & mch_read & mch_read & mch_addr(1 downto 0);

  -- I/O

  u_joyps2 : entity work.replay_joy_ps2
  port map (
    i_Clk                 => clk_ctl,
    i_Tick_1us            => tick_ctl_1us,
    i_Tick_100us          => tick_ctl_100us,
    i_Rst                 => rst_ctl,
    --
    -- IO Joysticks
    --
    i_Joy_A_l               => i_Joy_A,
    i_Joy_B_l               => i_Joy_B,

    -- IO PS2
    i_PS2A_Clk            => b_PS2A_Clk,
    i_PS2A_Data           => b_PS2A_Data,
-- TODO
    o_PS2A_Drive_Clk_Low  => ps2a_drive_clk_low,
    o_PS2A_Drive_Data_Low => ps2a_drive_data_low,
--
    i_PS2B_Clk            => b_PS2B_Clk,
    i_PS2B_Data           => b_PS2B_Data,
    o_PS2B_Drive_Clk_Low  => ps2b_drive_clk_low,
    o_PS2B_Drive_Data_Low => ps2b_drive_data_low,
    --
    -- to core
    --
    i_Kb_PS2_Leds         => kb_led,
    o_Kb_PS2_We           => kb_we,
    o_Kb_PS2_Data         => kb_ps2,
    --
    o_Ms_We               => ms_we,
    o_Ms_PosX             => ms_posx,
    o_Ms_PosY             => ms_posy,
    o_Ms_Butn             => ms_butn
    );

  b_PS2A_Clk  <= '0' when (ps2a_drive_clk_low  = '1') else 'Z';
  b_PS2A_Data <= '0' when (ps2a_drive_data_low = '1') else 'Z';
  b_PS2B_Clk  <= '0' when (ps2b_drive_clk_low  = '1') else 'Z';
  b_PS2B_Data <= '0' when (ps2b_drive_data_low = '1') else 'Z';

  b_PULLUP : block
  begin
    -- input's have pulls in UCF file
    ps2a_pu_clk  : PULLUP port map (o => b_PS2A_Clk);
    ps2a_pu_data : PULLUP port map (o => b_PS2A_Data);
    ps2b_pu_clk  : PULLUP port map (o => b_PS2B_Clk);
    ps2b_pu_data : PULLUP port map (o => b_PS2B_Data);

    io : for i in 0 to 54 generate
      io_pu  : PULLUP port map (o   => b_IO(i));
    end generate;

    aux : for i in 12 to 39 generate
      auxio_pu  : PULLUP port map (o   => b_Aux_IO(i));
    end generate;

    aux2 : for i in 0 to 3 generate
      auxio_pu  : PULLUP port map (o   => b_Aux_IO(i));
    end generate;

    aux_pu  : PULLUP port map (o => b_Clk_Aux);
    io_1_pu : PULLUP port map (o => b_2V5_IO_1);
    io_0_pu : PULLUP port map (o => b_2V5_IO_0);

  end block;

  --
  -- DRAM is 64MB x 8bit or 16MB x 32bit
  --
  -- (byte) address is 0x03FF FFFF downto 0x0000 0000
  --
  -- we use the first 32MB (x8) for memory on the VIC-20          --> 0x01FF FFFF downto 0x0000 0000
  -- we use the second 32MB (x8) as memory for the 1541 d64 files --> 0x03FF FFFF downto 0x0200 0000

--  mch_ddr_valid <= mch_valid when (mch_addr(31) = '0') else '0';  -- first addresses from 0x00000000 on are DRAM, from 0x80000000 on is for other memory

  u_ddrctrl : entity work.replay_ddrctrl_top
  port map (
    i_Clk_Ram         => clk_ram,
    i_Clk_Ram_90      => clk_ram_90,
    i_Rst_Ram         => rst_ram,
    --
    i_Clk_Capture     => clk_capture,
    i_Rst_Capture     => rst_capture,
    --
    i_Clk_Sys         => clk_sys,
    i_Ena_Sys         => ena_sys_ddr,
    i_Ena_Sys_C1      => ena_sys_C1,
    i_Rst_Sys         => rst_sys,

    -- DDR Signals
    o_RAM_BA          => o_Mem_Addr(14 downto 13),
    o_RAM_Addr        => o_Mem_Addr(12 downto  0),
    --
    o_RAM_CS_L        => o_Mem_CS,
    o_RAM_WE_L        => o_Mem_WE,
    o_RAM_RAS_L       => o_Mem_RAS,
    o_RAM_CAS_L       => o_Mem_CAS,
    --
    o_RAM_DM_L(1)     => o_Mem_UDM,
    o_RAM_DM_L(0)     => o_Mem_LDM,
    b_RAM_DQS(1)      => b_Mem_UDQS,
    b_RAM_DQS(0)      => b_Mem_LDQS,
    b_RAM_DQ          => b_Mem_DQ,
    --
    o_RAM_CKE         => o_Mem_CKE,
    o_RAM_CK_P        => o_Mem_Clk_P,
    o_RAM_CK_N        => o_Mem_Clk_N,
    --
    i_Cfg_Cal_Sel     => cfg_cal_sel,

    -- High Priority - 32 bit i/f
    i_HP_Valid        => hp_ddr_valid,
    o_HP_Taken        => hp_ddr_taken,
    i_HP_Addr         => hp_ddr_addr(25 downto 2),
    i_HP_RW_l         => hp_wl,
    i_HP_W_BE         => hp_wbe,
    i_HP_W_Data       => hp_wdata,
    --
    o_HP_R_Data       => hp_rdata,
    o_HP_R_We         => hp_ddr_we,

    -- Low Priority - 8 bit i/f
    i_LP_Valid        => mch_valid,
    o_LP_Taken        => mch_ddr_taken,
    i_LP_Addr         => mch_addr(25 downto 0),
    i_LP_RW_l         => mch_read,
    i_LP_W_Data       => mch_data,
    --
    o_LP_R_Data       => mch_ddr_rd_data,
    o_LP_R_We         => mch_ddr_rd_we
    );

  -- handling media access when d64 is load via
  -- ARM to DDR (on low-prio channel) 
  media_access : process (clk_sys, rst_sys) is
  begin
    if rst_sys='1' then
      init_diskinsert_s <= '0';
      diskid_s <= x"0000";
      inscnt_s <= (others => '0');
      writeprotn_s <= '0';
    elsif rising_edge(clk_sys) then
      -- handle disk change and fetch disk id
      if mch_read='0' and mch_valid='1' and mch_ddr_taken='0' then
        if mch_addr=x"02000000" then
          init_diskinsert_s <= '0';
          writeprotn_s <= '1';
        elsif mch_addr=x"020165A2" then
          diskid_s(15 downto 8) <= mch_data;
        elsif mch_addr=x"020165A3" then
          diskid_s(7 downto 0)  <= mch_data;
        elsif mch_addr=x"0202AAFF" then
          inscnt_s <= (others => '1');
        end if;
      end if;
      if ena_sub1='1' then
        if inscnt_s/=0 then
          inscnt_s<=inscnt_s-1;
          if inscnt_s=1 then
            init_diskinsert_s <= '1';
            writeprotn_s <= '0';
          end if;
        end if;
      end if;
    end if;
  end process;

  ----------------------------------------------------------
  -- RAM/ROM load process
  ----------------------------------------------------------

  conf_valid <= mch_valid when (mch_addr(31 downto 20) = x"000") else '0';
  conf_write <= conf_valid and ena_sys and not mch_read;   -- 0x000?xxxx --> configuration upload (ROM or PRG)
  mode_1541 <= mch_addr(18);                   -- 0x0004xxxx --> 1541 configuration upload
  mode_key  <= mch_addr(17);                   -- 0x0002xxxx --> keymapping configuration upload

  -- we pass all input also to the core memories in parallel to the DDR ram
  conf_wr_core <= conf_write and mch_valid and (not mode_1541) and (not mode_key);
  conf_wr_1541 <= conf_write and mch_valid and mode_1541;
  conf_wr_key  <= conf_write and mch_valid and mode_key;

  --
  -- System control / On Screen Display
  --
  u_syscon : entity work.replay_syscon
  generic map (
    -- defaults
    g_cfg_static          => x"00000000",
    g_cfg_dynamic         => x"00000000",
    g_cfg_fileio_cha_ena  => cfg_fileio_cha_ena,
    g_cfg_fileio_cha_drv  => cfg_fileio_cha_drv,
    g_cfg_fileio_chb_ena  => cfg_fileio_chb_ena,
    g_cfg_fileio_chb_drv  => cfg_fileio_chb_drv,
    g_cfg_ctrl            => x"0080",
    --
    g_Version             => x"1001" -- top bit DRAM disabled
    )
  port map (
    i_Clk_Vid             => clk_vid,
    i_Ena_Vid             => ena_vid,
    i_Rst_Vid             => rst_vid,
    --
    i_Clk_Ctl             => clk_ctl,
    i_Rst_Ctl             => rst_ctl,
    i_Rst_Ctl_Hard        => rst_ctl_hard,
    --
    o_Rst_Soft            => rst_soft,
    o_Halt                => halt_soft,
    --
    i_SPI_CS_l            => spi_syscon_cs_l,
    i_SPI_Clk             => clk_spi,
    i_SPI_D               => b_FPGA_SPI_MOSI,
    o_SPI_D               => spi_syscon_miso,
    --
    o_VBL                 => o_SSC_RD,
     -- Config
    i_cfg_status          => x"0000",
    --
    o_cfg_Static          => cfg_static,
    o_cfg_Dynamic         => cfg_dynamic,
    o_cfg_fileio_cha      => open,
    o_cfg_fileio_chb      => open,
    o_Cfg_Ctrl            => cfg_ctrl,
    --
    i_Kb_PS2_We           => kb_we,
    i_Kb_PS2_Data         => kb_ps2,
    o_Kb_Inhibit          => kb_inhibit, -- core should use to ignore keypresses when OSD active
    --
    i_Vid_RGB             => core_vid_rgb,
    i_Vid_Sync            => core_vid_sync,
    --
    o_Vid_RGB             => syscon_vid_rgb,
    o_Vid_Sync            => syscon_vid_sync
    --
    );

  cfg_fileio  <= cfg_fileio_i and "00000000"; -- 0 HD, 0 FD
  cfg_phase   <= cfg_ctrl(7 downto 0);  -- 25 ps per tick
  cfg_cal_sel <= cfg_ctrl(9 downto 8);
-- When the transfer is in direct mode from SD card, we need
-- to swap over the in and out pins on the SPI interface (we are now a slave).
-- We cannot drive the output in this case unless the ARM is not.

  spi_fileio_cs_l <= i_FPGA_Ctrl0;
  spi_syscon_cs_l <= i_FPGA_Ctrl1;

  b_FPGA_SPI_MOSI <= 'Z';
  b_FPGA_SPI_MISO <= spi_fileio_miso when (spi_fileio_cs_l = '0') else 'Z';
  b_FPGA_SPI_MISO <= spi_syscon_miso when (spi_syscon_cs_l = '0') else 'Z';

  u_fileio : entity work.replay_fileio
  port map (
  -- handles all disk/tape/HDD/ROM transfers to the SD card/ARM
    i_Clk_Ctl             => clk_ctl,
    i_Rst_Ctl             => rst_ctl,
    --
    i_Ena_Sys             => ena_sys_ddr,
    --
    i_SPI_CS_l            => spi_fileio_cs_l,
    i_SPI_Clk             => clk_spi,
    i_SPI_D               => b_FPGA_SPI_MOSI,
    o_SPI_D               => spi_fileio_miso,
    --
    -- FILE A
    --
    o_fcha_to_core        => open,
    --i_fcha_fm_core        => fcha_fm_core,
    --
    -- FILE B
    --
    o_fchb_to_core        => open,
    --i_fchb_fm_core        => fchb_fm_core,
    --
    -- Memory interface
    --
    o_MCh_Addr            => mch_addr,
    o_Mch_Read            => mch_read,
    o_MCh_Data            => mch_data,
    o_MCh_Flush           => open,
    o_MCh_Valid           => mch_valid,
    i_MCh_Taken           => mch_taken,
    --
    i_MCh_Data            => mch_rd_data,
    i_MCh_We              => mch_rd_we
  );

  -- mch read combine
  mch_taken   <= --conf_taken or
                 mch_ddr_taken;

  mch_rd_data <= mch_ddr_rd_data(7 downto 0);

  mch_rd_we   <= mch_ddr_rd_we;

  --
  -- VIDEO
  --
  u_video : entity work.replay_video
  port map (
    i_Clk_Vid             => clk_vid,
    i_Clk_Vid_90          => clk_vid_90,
    i_Ena_Vid             => ena_vid,
    i_Rst_Vid_Hard        => rst_vid_hard,
    --
    i_Clk_Ctl             => clk_ctl, -- used for i2c bridge
    i_Rst_Ctl             => rst_ctl,
    --
    -- Input video must come from a register clocked with Clk_Video
    i_Vid_RGB             => syscon_vid_rgb,
    i_Vid_Sync            => syscon_vid_sync,
    -- cpu i2c pins
    i_SCL                 => b_SCL,
    i_SDA                 => b_SDA,
    o_Drive_SCL_Low       => drive_scl_low,
    o_Drive_SDA_Low       => drive_sda_low,
    -- video i2c pins
    i_SPC                 => b_Video_SPC,
    i_SPD                 => b_Video_SPD,
    o_Drive_SPC_Low       => drive_spc_low,
    o_Drive_SPD_Low       => drive_spd_low,
    --
    o_Video_Clk_P         => o_Video_Clk_P,
    o_Video_Clk_N         => o_Video_Clk_N,
    o_Video_Rst_L         => o_Video_Rst_L,
    i_Video_Int           => i_Video_Int,
    o_Video_DE            => o_Video_DE,
    o_Video_V             => o_Video_V,
    o_Video_H             => o_Video_H,
    o_Video_Data          => o_Video_Data,
    b_Video_DDC_Clk       => b_Video_DDC_Clk,
    b_Video_DDC_Data      => b_Video_DDC_Data,
    --
    o_Video_HSync         => o_Video_HSync,
    o_Video_VSync         => o_Video_VSync
    );
  --
  b_SCL       <= '0' when (drive_scl_low = '1') else 'Z';
  b_SDA       <= '0' when (drive_sda_low = '1') else 'Z';
  b_Video_SPC <= '0' when (drive_spc_low = '1') else 'Z';
  b_Video_SPD <= '0' when (drive_spd_low = '1') else 'Z';
  --
  -- AUDIO PHY
  --
  u_audio : entity work.replay_audio
  port map (
    i_Clk                 => clk_aud, --sys,
    i_Ena                 => '1',     --ena_sys,
    i_Rst                 => rst_aud, --rst_sys,
    --
    i_Sample_L            => core_audio_l,
    i_Sample_R            => core_audio_r,
    o_Sample_Taken        => phy_audio_taken,
    --
    o_Audio_LRCIN         => o_Audio_LRCIN,
    o_Audio_MCLK          => o_Audio_MCLK,
    o_Audio_BCKIN         => o_Audio_BCKIN,
    o_Audio_DIN           => o_Audio_DIN
    );
  --

  -- memory debugging

  dbg : block is
    --{{{  cs
    component icon
      PORT (
        CONTROL0 : INOUT STD_LOGIC_VECTOR(35 DOWNTO 0)
        );
    end component;

    component ila_1024_63
      PORT (
        CONTROL : INOUT STD_LOGIC_VECTOR(35 DOWNTO 0);
        CLK     : IN STD_LOGIC;
        TRIG0   : IN STD_LOGIC_VECTOR(62 DOWNTO 0)
        );
    end component;

    signal cs_control0   : std_logic_vector(35 downto 0);
    signal cs_clk        : std_logic;
    signal cs_trig       : std_logic_vector(62 downto 0);
    --}}}
  begin
    local_mem_dla : if dla_mem_enable=true generate
      i_icon : icon
        port map (
          CONTROL0 => cs_control0
      );

      i_ila : ila_1024_63
        port map (
          CONTROL => cs_control0,
          CLK     => cs_clk,
          TRIG0   => cs_trig);

      cs_clk       <= clk_ctl;

      cs_trig(62) <= '0';
      cs_trig(61 downto 52) <= "0000000000";

      cs_trig(51 downto 20) <= mch_addr;
      cs_trig(19 downto 12) <= mch_data;

      cs_trig(11) <= hp_ddr_taken;
      cs_trig(10) <= mch_ddr_rd_we;
      cs_trig(9)  <= mch_valid;
      cs_trig(8)  <= mch_ddr_taken;

      cs_trig(7)  <= ena_sys;
      cs_trig(6)  <= conf_valid;
      cs_trig(5)  <= conf_write;
      cs_trig(4)  <= conf_taken;

      cs_trig(3)  <= mch_valid;
      cs_trig(2)  <= mch_read;
      cs_trig(1)  <= mch_rd_we;
      cs_trig(0)  <= mch_taken;

    end generate local_mem_dla;
  end block dbg;
end RTL;
