--------------------------------------------------------------------------------
-- AVALON SCALER
--------------------------------------------------------------------------------
-- DO 10/2018
--------------------------------------------------------------------------------
LIBRARY ieee;
USE ieee.std_logic_1164.ALL;
USE ieee.numeric_std.ALL;

USE std.textio.ALL;

LIBRARY work;
USE work.base_pack.ALL;

ENTITY tb_ascal IS

END ENTITY tb_ascal;

--------------------------------------------------------------------------------

ARCHITECTURE beh OF tb_ascal IS

  FUNCTION to_std_logic (a : boolean) RETURN std_logic IS
  BEGIN
    IF a THEN RETURN '1';
         ELSE RETURN '0';
    END IF;
  END FUNCTION to_std_logic;
  PROCEDURE wure(
    SIGNAL clk : IN std_logic;
    CONSTANT n : IN natural:=1) IS
  BEGIN
    FOR i IN 1 TO n LOOP
      WAIT UNTIL rising_edge(clk);
    END LOOP;
  END PROCEDURE wure;
  CONSTANT HexString : string(1 TO 16):="0123456789ABCDEF";
  
  -- Conversion unsigned -> Chaîne hexadécimale
  FUNCTION To_HString(v : unsigned) RETURN string IS
    VARIABLE r : string(1 TO ((v'length)+3)/4);
    VARIABLE x : unsigned(1 TO v'length);
    VARIABLE i,j : integer;
  BEGIN
    x:=v;
    i:=1;
    j:=1;
    r:=(OTHERS =>' ');
    WHILE i<v'length LOOP
      IF x(i)='X' OR x(i+1)='X' OR x(i+2)='X' OR x(i+3)='X' THEN
        r(j):='X';
      ELSIF x(i)='U' OR x(i+1)='U' OR x(i+2)='U' OR x(i+3)='U' THEN
        r(j):='U';
      ELSIF x(i)='Z' OR x(i+1)='Z' OR x(i+2)='Z' OR x(i+3)='Z' THEN
        r(j):='Z';
      ELSIF x(i)='H' OR x(i+1)='H' OR x(i+2)='H' OR x(i+3)='H' THEN
        r(j):='H';
      ELSIF x(i)='L' OR x(i+1)='L' OR x(i+2)='L' OR x(i+3)='L' THEN
        r(j):='L';
      ELSIF x(i)='W' OR x(i+1)='W' OR x(i+2)='W' OR x(i+3)='W' THEN
        r(j):='W';
      ELSE
        r(j):=HexString(to_integer(unsigned(x(i TO i+3)))+1);
      END IF;
      i:=i+4;
      j:=j+1;
    END LOOP;
    RETURN r;
  END FUNCTION To_HString;
  
  CONSTANT NPOLY : natural :=2;
  CONSTANT FRAC  : natural :=4;
  
  COMPONENT ascal IS
    GENERIC (
      RAMBASE : unsigned(31 DOWNTO 0);
      RO      : boolean;
      FRAC    : natural RANGE 4 TO 6 :=4;
      NPOLY   : natural RANGE 0 TO 2 :=2;
      FORMAT  : natural RANGE 1 TO 8;
      N_DW    : natural RANGE 32 TO 128;
      N_AW    : natural RANGE 8 TO 32;
      N_BURST : natural);
    PORT (
      i_r               : IN  unsigned(7 DOWNTO 0);
      i_g               : IN  unsigned(7 DOWNTO 0);
      i_b               : IN  unsigned(7 DOWNTO 0);
      i_hs              : IN  std_logic;
      i_vs              : IN  std_logic;
      i_fl              : IN  std_logic;
      i_de              : IN  std_logic;
      i_ce              : IN  std_logic;
      i_clk             : IN  std_logic;
      o_r               : OUT unsigned(7 DOWNTO 0);
      o_g               : OUT unsigned(7 DOWNTO 0);
      o_b               : OUT unsigned(7 DOWNTO 0);
      o_hs              : OUT std_logic;
      o_vs              : OUT std_logic;
      o_de              : OUT std_logic;
      o_ce              : IN  std_logic;
      o_clk             : IN  std_logic;
      iauto             : IN  std_logic;
      himin             : IN  natural RANGE 0 TO 4095;
      himax             : IN  natural RANGE 0 TO 4095;
      vimin             : IN  natural RANGE 0 TO 4095;
      vimax             : IN  natural RANGE 0 TO 4095;
      run               : IN  std_logic;
      mode              : IN  unsigned(4 DOWNTO 0);
      htotal            : IN  natural RANGE 0 TO 4095;
      hsstart           : IN  natural RANGE 0 TO 4095;
      hsend             : IN  natural RANGE 0 TO 4095;
      hdisp             : IN  natural RANGE 0 TO 4095;
      hmin              : IN  natural RANGE 0 TO 4095;
      hmax              : IN  natural RANGE 0 TO 4095;
      vtotal            : IN  natural RANGE 0 TO 4095;
      vsstart           : IN  natural RANGE 0 TO 4095;
      vsend             : IN  natural RANGE 0 TO 4095;
      vdisp             : IN  natural RANGE 0 TO 4095;
      vmin              : IN  natural RANGE 0 TO 4095;
      vmax              : IN  natural RANGE 0 TO 4095;
      poly_clk          : IN std_logic;
      poly_dw           : IN unsigned(8 DOWNTO 0);
      poly_a            : IN unsigned(NPOLY+FRAC+2 DOWNTO 0);
      poly_wr           : IN std_logic;
      avl_clk           : IN  std_logic;
      avl_waitrequest   : IN  std_logic;
      avl_readdata      : IN  std_logic_vector(N_DW-1 DOWNTO 0);
      avl_readdatavalid : IN  std_logic;
      avl_burstcount    : OUT std_logic_vector(7 DOWNTO 0);
      avl_writedata     : OUT std_logic_vector(N_DW-1 DOWNTO 0);
      avl_address       : OUT std_logic_vector(N_AW-1 DOWNTO 0);
      avl_write         : OUT std_logic;
      avl_read          : OUT std_logic;
      avl_byteenable    : OUT std_logic_vector(N_DW/8-1 DOWNTO 0);
      reset_na          : IN  std_logic);
  END COMPONENT ascal;

  SIGNAL i_r             : unsigned(7 DOWNTO 0);
  SIGNAL i_g             : unsigned(7 DOWNTO 0);
  SIGNAL i_b             : unsigned(7 DOWNTO 0);
  SIGNAL i_hs            : std_logic;
  SIGNAL i_vs            : std_logic;
  SIGNAL i_fl            : std_logic;
  SIGNAL i_de            : std_logic;
  SIGNAL i_ce            : std_logic;
  SIGNAL i_clk           : std_logic :='0';
  SIGNAL o_r             : unsigned(7 DOWNTO 0);
  SIGNAL o_g             : unsigned(7 DOWNTO 0);
  SIGNAL o_b             : unsigned(7 DOWNTO 0);
  SIGNAL o_hs            : std_logic;
  SIGNAL o_vs            : std_logic;
  SIGNAL o_de            : std_logic;
  SIGNAL o_ce            : std_logic;
  SIGNAL o_clk           : std_logic :='0';
  SIGNAL iauto           : std_logic;
  SIGNAL himin           : natural RANGE 0 TO 4095;
  SIGNAL himax           : natural RANGE 0 TO 4095;
  SIGNAL vimin           : natural RANGE 0 TO 4095;
  SIGNAL vimax           : natural RANGE 0 TO 4095;
  SIGNAL run             : std_logic;
  SIGNAL mode            : unsigned(4 DOWNTO 0);
  SIGNAL htotal          : natural RANGE 0 TO 4095;
  SIGNAL hsstart         : natural RANGE 0 TO 4095;
  SIGNAL hsend           : natural RANGE 0 TO 4095;
  SIGNAL hdisp           : natural RANGE 0 TO 4095;
  SIGNAL hmin            : natural RANGE 0 TO 4095;
  SIGNAL hmax            : natural RANGE 0 TO 4095;
  SIGNAL vtotal          : natural RANGE 0 TO 4095;
  SIGNAL vsstart         : natural RANGE 0 TO 4095;
  SIGNAL vsend           : natural RANGE 0 TO 4095;
  SIGNAL vdisp           : natural RANGE 0 TO 4095;
  SIGNAL vmin            : natural RANGE 0 TO 4095;
  SIGNAL vmax            : natural RANGE 0 TO 4095;
  SIGNAL avl_clk         : std_logic :='0';
  SIGNAL avl_waitrequest : std_logic;
  SIGNAL avl_readdata    : std_logic_vector(127 DOWNTO 0);
  SIGNAL avl_readdatavalid : std_logic;
  SIGNAL avl_burstcount  : std_logic_vector(7 DOWNTO 0);
  SIGNAL avl_writedata   : std_logic_vector(127 DOWNTO 0);
  SIGNAL avl_address     : std_logic_vector(19 DOWNTO 0);
  SIGNAL avl_write       : std_logic;
  SIGNAL avl_read        : std_logic;
  SIGNAL avl_byteenable  : std_logic_vector(15 DOWNTO 0);
  SIGNAL reset_na        : std_logic;


  SIGNAL sgs_ad       : uv15;
  SIGNAL sgs_dw       : uv8;
  SIGNAL sgs_dr       : uv8;
  SIGNAL sgs_req      : std_logic;
  SIGNAL sgs_ack      : std_logic;
  SIGNAL sgs_wr       : std_logic;
  SIGNAL sgs_int      : std_logic;
  SIGNAL sgs_intack   : std_logic;
  SIGNAL sgs_ivec     : uv8;
  SIGNAL sgs_vid_rgb  : uv3;
  SIGNAL sgs_vid_de   : std_logic;
  SIGNAL sgs_vid_hsyn : std_logic;
  SIGNAL sgs_vid_vsyn : std_logic;
  SIGNAL sgs_vid_ce   : std_logic;
  SIGNAL sgs_sound    : uv8;
  SIGNAL sgs_pot1     : uv8;
  SIGNAL sgs_pot2     : uv8;
  SIGNAL sgs_np       : std_logic;
  SIGNAL sgs_reset    : std_logic;
  SIGNAL sgs_clk      : std_logic :='0';
  SIGNAL sgs_reset_na : std_logic;

  SIGNAL poly_clk     : std_logic;
  SIGNAL poly_dw      : unsigned(8 DOWNTO 0);
  SIGNAL poly_a       : unsigned(NPOLY+FRAC+2 DOWNTO 0);
  SIGNAL poly_wr      : std_logic;

  FILE fil : text OPEN write_mode IS "mem.log";

  TYPE arr_uv128 IS ARRAY (natural RANGE <>) OF unsigned(127 DOWNTO 0);
  SHARED VARIABLE mem : arr_uv128(0 TO 2**15-1);
  
  SIGNAL ihtotal          : natural RANGE 0 TO 4095;
  SIGNAL ihsstart         : natural RANGE 0 TO 4095;
  SIGNAL ihsend           : natural RANGE 0 TO 4095;
  SIGNAL ihdisp           : natural RANGE 0 TO 4095;
  SIGNAL ivtotal          : natural RANGE 0 TO 4095;
  SIGNAL ivsstart         : natural RANGE 0 TO 4095;
  SIGNAL ivsend           : natural RANGE 0 TO 4095;
  SIGNAL ivdisp           : natural RANGE 0 TO 4095;


  
BEGIN

  avl_clk<=NOT avl_clk AFTER 0.5 us / 100;

  reset_na<='0','1' AFTER 1.1 us;

  ----------------------------------------------------------
  i_ascal: ascal
    GENERIC MAP (
      RAMBASE => x"00000000",
      RO      => false,
      FORMAT  => 8,
      N_DW    => 128,
      N_AW    => 20,
      N_BURST => 256)
    PORT MAP (
      i_r               => i_r,
      i_g               => i_g,
      i_b               => i_b,
      i_hs              => i_hs,
      i_vs              => i_vs,
      i_fl              => i_fl,
      i_de              => i_de,
      i_ce              => i_ce,
      i_clk             => i_clk,
      o_r               => o_r,
      o_g               => o_g,
      o_b               => o_b,
      o_hs              => o_hs,
      o_vs              => o_vs,
      o_de              => o_de,
      o_ce              => o_ce,
      o_clk             => o_clk,
      iauto             => iauto,
      himin             => himin,
      himax             => himax,
      vimin             => vimin,
      vimax             => vimax,
      run               => run,
      mode              => mode,
      htotal            => htotal,
      hsstart           => hsstart,
      hsend             => hsend,
      hdisp             => hdisp,
      hmin              => hmin,
      hmax              => hmax,
      vtotal            => vtotal,
      vsstart           => vsstart,
      vsend             => vsend,
      vdisp             => vdisp,
      vmin              => vmin,
      vmax              => vmax,
      poly_clk          => poly_clk,
      poly_dw           => poly_dw,
      poly_a            => poly_a,
      poly_wr           => poly_wr,
      avl_clk           => avl_clk,
      avl_waitrequest   => avl_waitrequest,
      avl_readdata      => avl_readdata,
      avl_readdatavalid => avl_readdatavalid,
      avl_burstcount    => avl_burstcount,
      avl_writedata     => avl_writedata,
      avl_address       => avl_address,
      avl_write         => avl_write,
      avl_read          => avl_read,
      avl_byteenable    => avl_byteenable,
      reset_na          => reset_na);
  
  ----------------------------------------------------------
  AvaleW:PROCESS IS
    VARIABLE a : unsigned(15 DOWNTO 0);
  BEGIN
    wure(avl_clk);
    IF avl_write='1' AND avl_waitrequest='0' THEN
      a:=unsigned(avl_address(15 DOWNTO 0));
      FOR i IN 0 TO 15 LOOP
        mem(to_integer(a)+i):=unsigned(avl_writedata);
        wure(avl_clk);
      END LOOP;
    END IF;
  END PROCESS AvaleW;

  AvaleR:PROCESS IS
    VARIABLE a : unsigned(15 DOWNTO 0);
  BEGIN
    avl_readdatavalid<='0';
    wure(avl_clk);
    IF avl_read='1' AND avl_waitrequest='0' THEN
      a:=unsigned(avl_address(15 DOWNTO 0));
      wure(avl_clk);
      FOR i IN 0 TO 7 LOOP
        avl_readdata<=std_logic_vector(mem(to_integer(a)+i));
        avl_readdatavalid<='1';
        wure(avl_clk);
      END LOOP;
      --avl_readdatavalid<='0';
      --wure(avl_clk);
      --avl_readdatavalid<='0';
      --wure(avl_clk);
      --avl_readdatavalid<='0';
      --wure(avl_clk);
      
      FOR i IN 8 TO 15 LOOP
        avl_readdata<=std_logic_vector(mem(to_integer(a)+i));
        avl_readdatavalid<='1';
        wure(avl_clk);
      END LOOP;
      
    END IF;
  END PROCESS AvaleR;
  
  PROCESS IS
  BEGIN
    wure(avl_clk);
    avl_waitrequest<='0';
    WAIT;
    --wure(avl_clk,5);
    --avl_waitrequest<='0';
    --wure(avl_clk,2);
    --avl_waitrequest<='1';
    --wure(avl_clk,3);
    --avl_waitrequest<='0';
  END PROCESS;
  
  ----------------------------------------------------------
  Trace:PROCESS IS
    VARIABLE rad,wad : unsigned(19 DOWNTO 0);
    VARIABLE rcpt,rlen,wcpt,wlen : natural RANGE 0 TO 255;
    VARIABLE rdata,wdata : arr_uv128(0 TO 15);
    VARIABLE rpend,wpend : boolean;
    VARIABLE lout : line;
  BEGIN
    wure(avl_clk);
    IF avl_read='1' AND avl_waitrequest='0' THEN
      rad:=unsigned(avl_address);
      rpend:=true;
      rcpt:=0;
      rlen:=to_integer(unsigned(avl_burstcount));
    END IF;
    IF rpend AND avl_readdatavalid='1' THEN
      rdata(rcpt):=unsigned(avl_readdata);
      rcpt:=rcpt+1;
      IF rcpt=rlen THEN
        rpend:=false;
        write(lout,string'("R : " & to_hstring(rad) & ": "));
        FOR i IN 0 TO rlen-1 LOOP
          write(lout,to_hstring(rdata(i)) & " ");
        END LOOP;
        write (lout,now);
        writeline(fil,lout);
      END IF;
    END IF;
    IF avl_write='1' AND avl_waitrequest='0' THEN
      IF NOT wpend THEN
        wad:=unsigned(avl_address);
        wpend:=true;
        wcpt:=1;
        wlen:=to_integer(unsigned(avl_burstcount));
        wdata(0):=unsigned(avl_writedata);
      ELSE
        wdata(wcpt):=unsigned(avl_writedata);
        wcpt:=wcpt+1;
        IF wcpt=wlen THEN
          write(lout,string'("W : " & to_hstring(wad) & ": "));
          FOR i IN 0 TO wlen-1 LOOP
            write(lout,to_hstring(wdata(i)) & " ");
          END LOOP;
          write (lout,now);
          writeline(fil,lout);
          wpend:=false;
        END IF;
      END IF;
    END IF;
    
  END PROCESS Trace;
    
  ----------------------------------------------------------
  sgs2636_1: ENTITY work.sgs2636
    PORT MAP (
      ad       => sgs_ad,
      dw       => sgs_dw,
      dr       => sgs_dr,
      req      => sgs_req,
      ack      => sgs_ack,
      wr       => sgs_wr,
      int      => sgs_int,
      intack   => sgs_intack,
      ivec     => sgs_ivec,
      vid_rgb  => sgs_vid_rgb,
      vid_de   => sgs_vid_de,
      vid_hsyn => sgs_vid_hsyn,
      vid_vsyn => sgs_vid_vsyn,
      vid_ce   => sgs_vid_ce,
      sound    => sgs_sound,
      pot1     => sgs_pot1,
      pot2     => sgs_pot2,
      np       => sgs_np,
      reset    => sgs_reset,
      clk      => sgs_clk,
      reset_na => sgs_reset_na);
  
  sgs_clk<=NOT sgs_clk AFTER 0.5 us / 50;
  sgs_reset_na<='0','1' AFTER 1.1 us;
  sgs_reset<='1','0' AFTER 3 us;
  i_de<=sgs_vid_de;
  i_hs<=sgs_vid_hsyn;
  i_vs<=sgs_vid_vsyn;
  i_ce<=sgs_vid_ce;
  i_clk<=sgs_clk;
  i_r<=(OTHERS =>sgs_vid_rgb(2));
  i_g<=(OTHERS =>sgs_vid_rgb(1));
  i_b<=(OTHERS =>sgs_vid_rgb(0));
  sgs_req<='0';
  --ihdisp<=184;
  --ihsstart<=200;
  --ihsend<=226;
  --ihtotal <=227;
  
  --ivdisp<=268;
  --ivsstart<=269;
  --ivsend <=311;
  --ivtotal <=312;

  --PROCESS IS
  --BEGIN
  --  i_ce<='1';
  --  WAIT UNTIL rising_edge(i_clk);
  --  i_ce<='0';
  --  WAIT UNTIL rising_edge(i_clk);
  --  i_ce<='0';
  --  WAIT UNTIL rising_edge(i_clk);
  --END PROCESS;
  
  --III:PROCESS IS
  --  VARIABLE hcpt,vcpt : natural RANGE 0 TO 4095;
  --BEGIN
  --  WAIT UNTIL rising_edge(i_clk);
  --  IF i_ce='1' THEN
  --    IF hcpt<ihtotal THEN
  --      hcpt:=hcpt+1;
  --    ELSE
  --      hcpt:=0;
  --      IF vcpt<ivtotal THEN
  --        vcpt:=vcpt+1;
  --      ELSE
  --        vcpt:=0;
  --      END IF;
  --    END IF;
      
  --    i_de<=to_std_logic(hcpt<ihdisp AND vcpt<ivdisp);
  --    i_hs<=to_std_logic(hcpt>=ihsstart AND hcpt<ihsend);
  --    i_vs<=to_std_logic(vcpt>=ivsstart AND vcpt<ivsend);

  --    i_r<=to_unsigned(hcpt/256,8);
  --    i_g<=to_unsigned(hcpt MOD 256,8);
  --    i_b<=to_unsigned(vcpt MOD 256,8);
  --  END IF;
  --END PROCESS III;

--    i_clk<=NOT i_clk AFTER 0.5 us / 20 / 3;

  
  ----------------------------------------------------------
  iauto<='1';
  --CONSTANT MODELINE_1024_768_60Hz_65MHz : type_modeline := (--65.00,
  --  1024,1048,1184,1344,768,771,777,806,'0','0');
  -- hdisp hsyncstart hsyncend htotal vdisp vsyncstart vsyncend vtotal 

  o_clk<=NOT o_clk AFTER 0.5 us / 65;
  o_ce<='1';


  --1920x1080@60 PCLK=148.5MHz CEA
--reg  [11:0] WIDTH  = 1920;
--reg  [11:0] HFP    = 88;
--reg  [11:0] HS     = 48;
--reg  [11:0] HBP    = 148;
--reg  [11:0] HEIGHT = 1080;
--reg  [11:0] VFP    = 4;
--reg  [11:0] VS     = 5;
--reg  [11:0] VBP    = 36;
--reg  [11:0] VSET   = 0;
  hdisp<=1920;
  hsstart<=1920+88;
  hsend<=1920+88+48;
  htotal<=1920+88+48+148;
  hmin<=0;
  hmax<=hdisp;
  
  vdisp<=1080;
  vsstart<=1080+4;
  vsend<=1080+4+5;
  vtotal<=1080+4+5+36;
  vmin<=0;
  vmax<=vdisp;

  
  --hdisp<=1024;
  --hsstart<=1048;
  --hsend<=1184;
  --htotal<=1344;
  --hmin<=0;
  --hmax<=hdisp;
  
  --vdisp<=768;
  --vsstart<=771;
  --vsend<=777;
  --vtotal<=806;
  --vmin<=0;
  --vmax<=vdisp;

  
  run<='1';

  mode<="00000";
  
  
END ARCHITECTURE beh;
