------------------------------------------------------------------------------
--  Copyright (C) 2011, Kenichi Kurimoto
--
--  This program is free software; you can redistribute it and/or modify
--  it under the terms of the GNU General Public License as published by
--  the Free Software Foundation; either version 2 of the License, or
--  (at your option) any later version.
--
--  This program is distributed in the hope that it will be useful,
--  but WITHOUT ANY WARRANTY; without even the implied warranty of
--  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
--  GNU General Public License for more details.
--
--  You should have received a copy of the GNU General Public License
--  along with this program; if not, write to the Free Software
--  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA 
-----------------------------------------------------------------------------
-- Entity:      yccambaif
-- File:        yccambaif.vhd
-- Author:      Kenichi Kurimoto 
-- Description: amba slave insterface for upsample + YCbCr-RGB translation
------------------------------------------------------------------------------

library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

library grlib;
use grlib.amba.all;
use grlib.stdlib.all;
use grlib.devices.all;

library techmap;
use techmap.gencomp.all;

entity yccambaif is
   generic (
      memtech : integer := DEFMEMTECH;
      shindex : integer := 0;
      haddr  : integer := 0;
      hmask  : integer := 16#fff#;
      hirq   : integer := 0;      
      pindex : integer := 0;
      paddr  : integer := 0;
      pmask  : integer := 16#fff#);
   port (
      rst   : in std_ulogic;
      clk   : in std_ulogic;
      ahbsi : in ahb_slv_in_type;
      ahbso : out ahb_slv_out_type;
      apbi  : in apb_slv_in_type;
      apbo  : out apb_slv_out_type;
      kready : in std_logic;
      kstrobe : out std_logic;
      kdata   : out std_logic_vector(11 downto 0);
      samp_fact : out std_logic;
      error : in std_logic_vector(2 downto 0);
      xmcumax : out std_logic_vector(5 downto 0);
      ymcumax : out std_logic_vector(4 downto 0);
      incaddy  : out std_logic_vector(15 downto 0);
      incaddmcux : out std_logic_vector(15 downto 0);
      incaddmcuy : out std_logic_vector(10 downto 0);
      fbstartadd : out std_logic_vector(31 downto 0);
      startgen : out std_logic;
      kstrobeq : out std_logic;
      kdataq : out std_logic_vector(7 downto 0)
   );
end;

architecture rtl of yccambaif is

constant shconfig : ahb_config_type := (
 0 => ahb_device_reg( VENDOR_CONTRIB, CONTRIB_CORE1, 0, 0, hirq),
 4 => ahb_membar(haddr, '0', '0', hmask),
 others => zero32);
  
constant pconfig : apb_config_type := (
 0 => ahb_device_reg( VENDOR_CONTRIB, CONTRIB_CORE1, 0, 0, 0),
 1 => apb_iobar(paddr, pmask));
 
type ahbs_reg is record
   get : std_logic;
   hdata    : std_logic_vector(11 downto 0);
   written : std_ulogic;
   getq : std_logic;
   hdataq : std_logic_vector(7 downto 0);
   writtenq : std_ulogic;
end record;

type apbs_reg is record
   sampf : std_logic;
   xmcumax  : std_logic_vector(5 downto 0);
   ymcumax  : std_logic_vector(4 downto 0);
   incaddy : std_logic_vector(15 downto 0);
   incaddmcux : std_logic_vector(15 downto 0);
   incaddmcuy : std_logic_vector(10 downto 0);
   fbstartadd : std_logic_vector(31 downto 0);
   error_reg : std_logic_vector(2 downto 0);
end record;

type all_reg is record
   hreg : ahbs_reg;
   preg : apbs_reg;
end record;

signal r, rin : all_reg;

begin
comb : process (r, rst, ahbsi, apbi, kready, error)
      variable v : all_reg;
      variable apbwrite : std_logic;
      variable vprdata : std_logic_vector(31 downto 0);
      variable virq : std_logic_vector(NAHBIRQ-1 downto 0);
      variable vstartgen : std_logic;
    begin

   v := r;
   vprdata := (others => '0'); 
   virq := (others => '0');
   v.hreg.written := '0';
   v.hreg.writtenq := '0';
   vstartgen := '0';
   
-- apb controle part
   apbwrite := apbi.psel(pindex) and apbi.pwrite and apbi.penable;
   vprdata := (others => '0');
   case apbi.paddr(5 downto 2) is
   when "0000" =>
      if apbwrite = '1' then
         v.preg.fbstartadd := apbi.pwdata(31 downto 0);
      end if;
      vprdata := r.preg.fbstartadd(31 downto 0);
   when "0001" =>
      if apbwrite = '1' then
         v.preg.sampf := apbi.pwdata(22);
         v.preg.ymcumax := apbi.pwdata(21 downto 17);
         v.preg.xmcumax := apbi.pwdata(16 downto 11);
         v.preg.incaddmcuy := apbi.pwdata(10 downto 0);
      end if;
      vprdata := "0000000000" & r.preg.ymcumax & r.preg.xmcumax & r.preg.incaddmcuy;
   when "0010" => 
      if apbwrite = '1' then
         v.preg.incaddy := apbi.pwdata(31 downto 16);
         v.preg.incaddmcux := apbi.pwdata(15 downto 0);
      end if;
      vprdata := r.preg.incaddy & r.preg.incaddmcux;
   when "0011" =>
      if apbwrite = '1' then
          if  apbi.pwdata(31) = '1' then
              vstartgen := '1'; 
          end if;        
--          v.preg.error_reg(2) := apbi.pwdata(31);
      end if;
      vprdata := r.preg.error_reg(2) & "0000000000000000000000000000" & r.preg.error_reg(2 downto 0);
   when others =>
   end case;  

   v.hreg.get := '0';
-- ahb slave input part
   if (ahbsi.hready = '1') and (ahbsi.hsel(shindex) = '1') then
       if (ahbsi.haddr(15 downto 0) = "0000000000000000") and (ahbsi.hwrite = '1') and (ahbsi.htrans = HTRANS_NONSEQ) then
           v.hreg.get := '1';
       end if;
   end if;
   if r.hreg.get = '1' then
        v.hreg.hdata(11 downto 0) := ahbsi.hwdata(11 downto 0);
        v.hreg.written := '1';            
   end if;
   
-- quant value input
    v.hreg.getq := '0';
    if (ahbsi.hready = '1') and (ahbsi.hsel(shindex) = '1') then
        if (ahbsi.haddr(15 downto 0) = "0000000000000100") and (ahbsi.hwrite = '1') and (ahbsi.htrans = HTRANS_NONSEQ) then
            v.hreg.getq := '1';
        end if;
    end if;
    if r.hreg.getq = '1' then
         v.hreg.hdataq(7 downto 0) := ahbsi.hwdata(7 downto 0);
         v.hreg.writtenq := '1';            
    end if; 

-- error reg
   if error(0) = '1' then
       v.preg.error_reg(0) := '1';
   end if;
   if error(1) = '1' then
       v.preg.error_reg(1) := '1';
   end if;
   if error(2) = '1' then
       v.preg.error_reg(2) := '1';
   end if;


-- reset part
   if rst = '0' then
         v.hreg.hdata := (others => '0');
         v.hreg.written := '0';
         v.hreg.get := '0';
         v.hreg.getq := '0';
         v.hreg.writtenq := '0';
         v.preg.xmcumax := (others => '0');
         v.preg.ymcumax := (others => '0');
         v.preg.incaddy := (others => '0');
         v.preg.incaddmcux := (others => '0');
         v.preg.incaddmcuy := (others => '0');
         v.preg.error_reg := (others => '0');
   end if;
   
-- signal
   rin <= v;   
   apbo.prdata <= vprdata;
   ahbso.hirq <= virq;
   ahbso.hrdata <= kready & "0000000000000000000" & r.hreg.hdata;
   startgen <= vstartgen;
   kstrobe <= r.hreg.written;
   kdata <= r.hreg.hdata;
   xmcumax <= r.preg.xmcumax;
   ymcumax <= r.preg.ymcumax;
   incaddy <= r.preg.incaddy;
   incaddmcux <= r.preg.incaddmcux;
   incaddmcuy <= r.preg.incaddmcuy;
   fbstartadd <= r.preg.fbstartadd;
   samp_fact <= r.preg.sampf;
   kstrobeq <= r.hreg.writtenq;
   kdataq <= r.hreg.hdataq;
end process;

   apbo.pirq <= (others => '0');
   apbo.pindex <= pindex;
   apbo.pconfig <= pconfig;
   ahbso.hconfig <= shconfig;
   ahbso.hresp <= "00";
   ahbso.hsplit <= (others => '0');
   ahbso.hcache <= '0';
   ahbso.hready <= '1';
   ahbso.hindex <= shindex;
   
-- registers 
reg : process(clk)
begin
   if rising_edge(clk) then
        r <= rin;
   end if;
end process;


end;
   
