----------------------------------------------------------------------------------
-- Company: 
-- Engineer: 
-- 
-- Create Date: 08/18/2017 09:24:38 AM
-- Design Name: 
-- Module Name: ahb_master_wr - 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_unsigned.all;
use ieee.numeric_std.all;
--use ieee.math_real.all;
use std.textio.all;
library grlib;
use grlib.amba.all;
use grlib.stdlib.all;
use grlib.devices.all;

library work;
use work.ahb_mst_pkg.all;


entity ahb_master_wr is
  generic(hindex  : integer range 0 to NAHBMST-1  := 0);
  port(clk        : in  std_logic;
       resetn     : in  std_logic;
       ahbi       : in  ahb_mst_in_type;
       ahbo       : out ahb_mst_out_type;
       fifo_rd_in : in fifo_rd_in_type;
       fifo_rd_out: out fifo_rd_out_type;
       error_s    : out std_logic);
end ahb_master_wr;

architecture rtl of ahb_master_wr is

--type   TYPE_STATE is (Idle, BusReq, Control, Empty, Data);
type   TYPE_STATE is (Idle, BusReq, Control, Data);
type reg_type is record
  state   : TYPE_STATE;
  wr_addr : std_logic_vector(31 downto 0);
  busreq  : std_logic;
  fifo_rd_en : std_logic;
end record;

constant hconfig : ahb_config_type := (
  0 => ahb_device_reg ( VENDOR_GAISLER, GAISLER_AHBUART, 0, 0, 0),
  others => zero32);

constant start_addr : std_logic_vector(31 downto 0) := X"40000000";

signal r, rin : reg_type;

begin
  
  -- ahb ouptuts with fixed values 
  ahbo.hirq    <= (others => '0');
  ahbo.hconfig <= hconfig;  
  ahbo.hindex  <= hindex;

  -- ahb master interface combinatorial process
  ahb_comb: process(ahbi, r, fifo_rd_in)
  variable v       : reg_type;
  -- AHB outputs
  --variable hbusreq : std_ulogic;
  variable hlock   : std_ulogic;
  variable htrans  : std_logic_vector(1 downto 0);
  variable haddr   : std_logic_vector(31 downto 0);
  variable hwrite  : std_ulogic;
  variable hsize   : std_logic_vector(2 downto 0);
  variable hburst  : std_logic_vector(2 downto 0);
  variable hprot   : std_logic_vector(3 downto 0);
  variable hwdata  : std_logic_vector(31 downto 0);
  -- AHB inputs
  variable hresp   : std_logic_vector(1 downto 0);
  variable addr_incr : std_logic;

  begin
    
    --default
    
    v := r;
    v.fifo_rd_en := '0';
    htrans := HTRANS_IDLE;
    --hbusreq:= '0';
    error_s <= '0';
    
    hsize := HSIZE_WORD;
    --haddr := (others=>'0');
    
    case r.state is
    when Idle =>
      if (fifo_rd_in.almost_full = '1') then -- start reading out from fifo when it is almost full and write to memory
        v.state := BusReq;
        v.busreq := '1';                     -- assert HBUSREQ signal
      end if;
    when BusReq =>
      if (ahbi.hgrant(hindex) = '1' and ahbi.hready = '1') then    -- when the bus request is granted
        v.state := Control;                                          -- switch to empty state since the data is asserted by fifo one clock cycle after rd_en goes high
      end if;
--    when Empty =>
--        v.state := Control;                  -- r.rd_en goes high here
    when Control =>
      v.fifo_rd_en := '1';                                       -- assert rin.rd_en
      v.state := Data;
      htrans := HTRANS_NONSEQ;               -- first transfer is non-sequential
      --hsize := HSIZE_WORD;                   
      v.wr_addr := r.wr_addr+4;
    when Data =>
      --htrans := HTRANS_SEQ;               -- subsequent transfers are sequential
      if(ahbi.hready = '1' and ahbi.hresp = HRESP_OKAY) then
        if(fifo_rd_in.empty = '0') then      -- if the fifo is not empty continue with transactions
            if (ahbi.hgrant(hindex) = '1' and ahbi.hready = '1') then  -- if we still have bus access, continue
                v.state := Control;
                --v.wr_addr := r.wr_addr+4;
                --v.fifo_rd_en := '1';                                       -- assert rin.rd_en
            else
                v.state := BusReq;                                      -- request bus again
            end if;
        else
            v.state := Idle;
            v.busreq   := '0';
        end if;
      elsif(ahbi.hresp = HRESP_SPLIT or ahbi.hresp = HRESP_RETRY) then
          v.state := Data;
          error_s <= '1';
      elsif(ahbi.hresp = HRESP_ERROR) then
          v.state := Idle;
          error_s <= '1';
      end if;
    end case;  
    
    
    -- fixed values for single transfer
    hburst := HBURST_INCR;
    hlock  := '0';
    hwdata := fifo_rd_in.data;
      
    -- drive ports

    ahbo.hbusreq <= r.busreq;
    ahbo.hlock   <= hlock;
    ahbo.htrans  <= htrans;
    ahbo.haddr   <= r.wr_addr ;
    ahbo.hwrite  <= '1';
    ahbo.hsize   <= hsize;
    ahbo.hburst  <= hburst;
--    if nbo = "00" then ahbo.hprot <= "11" & su & '0';
--    else ahbo.hprot <= "11" & su & '1'; end if;
    ahbo.hprot <= "1101";
    ahbo.hwdata  <= ahbdrivedata(hwdata);
    
    fifo_rd_out.rd_en <= r.fifo_rd_en;
        
    rin <= v;

  end process;
  
  ahb_reg: process(clk)
  begin
    if rising_edge(clk) then
      if resetn = '0' then
        r.state <= Idle;
        r.wr_addr <= start_addr;
        r.busreq <= '0';
        r.fifo_rd_en <= '0';
      else
        r <= rin;
      end if;
    end if;
  end process;


end rtl;
