------------------------------------------------------------------------------
--  This file is a part of the GRLIB VHDL IP LIBRARY
--  Copyright (C) 2003 - 2008, Gaisler Research
--  Copyright (C) 2008 - 2014, Aeroflex Gaisler
--  Copyright (C) 2015 - 2019, Cobham Gaisler
--
--  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 
--============================================================================--
-- Design unit  : DMA2AHB_TestPackage (package declaration)
--
-- File name    : dma2ahb_tp.vhd
--
-- Purpose      : Interface package for AMBA AHB master interface with DMA input
--
-- Reference    : AMBA(TM) Specification (Rev 2.0), ARM IHI 0011A,
--                13th May 1999, issue A, first release, ARM Limited
--                The document can be retrieved from http://www.arm.com
--                AMBA is a trademark of ARM Limited.
--                ARM is a registered trademark of ARM Limited.
--
-- Note         : Naming convention according to AMBA(TM) Specification:
--                Signal names are in upper case, except for the following:
--                   A lower case 'n' in the name indicates that the signal
--                   is active low.
--                   Constant names are in upper case.
--                The least significant bit of an array is located to the right,
--                carrying the index number zero.
--
-- Limitations  : See DMA2AHB VHDL core
--
-- Library      : {independent}
--
-- Authors      : Aeroflex Gaisler AB
--
-- Contact      : mailto:support@gaisler.com
--                http://www.gaisler.com
--
-- Disclaimer   : All information is provided "as is", there is no warranty that
--                the information is correct or suitable for any purpose,
--                neither implicit nor explicit.
--
--------------------------------------------------------------------------------
-- Version  Author   Date           Changes
--
-- 1.4      SH        1 Jul 2005    New package
-- 1.5      SH        1 Sep 2005    New library TOPNET
-- 1.6      SH       20 Sep 2005    Added transparent HSIZE support
-- 1.8      SH       10 Nov 2005    Updated DMA2AHB interface usage
-- 1.9      SH        4 Jan 2006    Burst routines added
--                                  Fault reporting priority and timing improved
-- 1.9.1    SH       12 Jan 2006    Correct DmaComp8
-- 1.9.2    SH       ## ### ####    Corrected compare to allow pull-up
--                                  Adjusted printouts
-- 1.9.3    JA       14 Dec 2007    Support for halfword and byte bursts
-- 1.9.4    MI        4 Aug 2008    Support for Lock
-- 1.9.5    SH        4 Mar 2011    Modifed burst accesses to mimic real hw
--------------------------------------------------------------------------------
library  IEEE;
use      IEEE.Std_Logic_1164.all;
use      IEEE.Numeric_Std.all;

library  Std;
use      Std.Standard.all;
use      Std.TextIO.all;

library  GRLIB;
use      GRLIB.AMBA.all;
use      GRLIB.STDIO.all;
use      GRLIB.DMA2AHB_Package.all;
use      GRLIB.STDLIB.all;

package DMA2AHB_TestPackage is

   -----------------------------------------------------------------------------
   -- Vector of words
   -----------------------------------------------------------------------------
   type Data_Vector  is array (Natural range <> ) of
                                          Std_Logic_Vector(32-1 downto 0);

   -----------------------------------------------------------------------------
   -- Constants for comparison
   -----------------------------------------------------------------------------
   constant DontCare32:    Std_Logic_Vector(31 downto 0) := (others => '-');
   constant DontCare24:    Std_Logic_Vector(23 downto 0) := (others => '-');
   constant DontCare16:    Std_Logic_Vector(15 downto 0) := (others => '-');
   constant DontCare8:     Std_Logic_Vector( 7 downto 0) := (others => '-');

   ----------------------------------------------------------------------------
   -- Constant for calculating burst lengths
   ----------------------------------------------------------------------------
   constant WordSize: integer := 32;

   -----------------------------------------------------------------------------
   -- Initialize AHB interface
   -----------------------------------------------------------------------------
   procedure DMAInit(
      signal   HCLK:          in    Std_ULogic;
      signal   dmai:          out   dma_in_type;
      constant InstancePath:  in    String  := "DMAInit";
      constant ScreenOutput:  in    Boolean := False);


   -----------------------------------------------------------------------------
   -- AMBA AHB write access
   -----------------------------------------------------------------------------
   procedure DMAWriteQuiet(
      constant Address:       in    Std_Logic_Vector(31 downto 0);
      constant Data:          in    Std_Logic_Vector(31 downto 0);
      signal   HCLK:          in    Std_ULogic;
      signal   dmai:          out   dma_in_type;
      signal   dmao:          in    dma_out_type;
      variable TP:            inout Boolean;
      constant InstancePath:  in    String  := "DMAWrite";
      constant ScreenOutput:  in    Boolean := False;
      constant cBack2Back:    in    Boolean := False;
      constant Size:          in    Integer := 32;
      constant Lock:          in    Boolean := False);

   -----------------------------------------------------------------------------
   -- AMBA AHB write access
   -----------------------------------------------------------------------------
   procedure DMAWrite(
      constant Address:       in    Std_Logic_Vector(31 downto 0);
      constant Data:          in    Std_Logic_Vector(31 downto 0);
      signal   HCLK:          in    Std_ULogic;
      signal   dmai:          out   dma_in_type;
      signal   dmao:          in    dma_out_type;
      variable TP:            inout Boolean;
      constant InstancePath:  in    String  := "DMAWrite";
      constant ScreenOutput:  in    Boolean := False;
      constant cBack2Back:    in    Boolean := False;
      constant Size:          in    Integer := 32;
      constant Lock:          in    Boolean := False);

   -----------------------------------------------------------------------------
   -- AMBA AHB read access
   -----------------------------------------------------------------------------
   procedure DMAQuiet(
      constant Address:       in    Std_Logic_Vector(31 downto 0);
      variable Data:          out   Std_Logic_Vector(31 downto 0);
      signal   HCLK:          in    Std_ULogic;
      signal   dmai:          out   dma_in_type;
      signal   dmao:          in    dma_out_type;
      variable TP:            inout Boolean;
      constant InstancePath:  in    String  := "DMAQuiet";
      constant ScreenOutput:  in    Boolean := False;
      constant cBack2Back:    in    Boolean := False;
      constant Size:          in    Integer := 32;
      constant Lock:          in    Boolean := False);

   -----------------------------------------------------------------------------
   -- AMBA AHB read access
   -----------------------------------------------------------------------------
   procedure DMARead(
      constant Address:       in    Std_Logic_Vector(31 downto 0);
      variable Data:          out   Std_Logic_Vector(31 downto 0);
      signal   HCLK:          in    Std_ULogic;
      signal   dmai:          out   dma_in_type;
      signal   dmao:          in    dma_out_type;
      variable TP:            inout Boolean;
      constant InstancePath:  in    String  := "DMARead";
      constant ScreenOutput:  in    Boolean := True;
      constant cBack2Back:    in    Boolean := False;
      constant Size:          in    Integer := 32;
      constant Lock:          in    Boolean := False);

   -----------------------------------------------------------------------------
   -- AMBA AHB read access
   -----------------------------------------------------------------------------
   procedure DMAComp(
      constant Address:       in    Std_Logic_Vector(31 downto 0);
      constant CxData:        in    Std_Logic_Vector(31 downto 0);
      variable RxData:        out   Std_Logic_Vector(31 downto 0);
      signal   HCLK:          in    Std_ULogic;
      signal   dmai:          out   dma_in_type;
      signal   dmao:          in    dma_out_type;
      variable TP:            inout Boolean;
      constant InstancePath:  in    String  := "DMAComp";
      constant ScreenOutput:  in    Boolean := False;
      constant cBack2Back:    in    Boolean := False;
      constant Size:          in    Integer := 32;
      constant Lock:          in    Boolean := False);

   -----------------------------------------------------------------------------
   -- AMBA AHB write access
   -----------------------------------------------------------------------------
   procedure DMAWrite16(
      constant Address:       in    Std_Logic_Vector(31 downto 0);
      constant Data:          in    Std_Logic_Vector(15 downto 0);
      signal   HCLK:          in    Std_ULogic;
      signal   dmai:          out   dma_in_type;
      signal   dmao:          in    dma_out_type;
      variable TP:            inout Boolean;
      constant InstancePath:  in    String  := "DMAWrite16";
      constant ScreenOutput:  in    Boolean := False;
      constant cBack2Back:    in    Boolean := False;
      constant Lock:          in    Boolean := False);

   -----------------------------------------------------------------------------
   -- AMBA AHB read access
   -----------------------------------------------------------------------------
   procedure DMAQuiet16(
      constant Address:       in    Std_Logic_Vector(31 downto 0);
      variable Data:          out   Std_Logic_Vector(15 downto 0);
      signal   HCLK:          in    Std_ULogic;
      signal   dmai:          out   dma_in_type;
      signal   dmao:          in    dma_out_type;
      variable TP:            inout Boolean;
      constant InstancePath:  in    String  := "DMAQuiet16";
      constant ScreenOutput:  in    Boolean := False;
      constant cBack2Back:    in    Boolean := False;
      constant Lock:          in    Boolean := False);

   -----------------------------------------------------------------------------
   -- AMBA AHB read access
   -----------------------------------------------------------------------------
   procedure DMARead16(
      constant Address:       in    Std_Logic_Vector(31 downto 0);
      variable Data:          out   Std_Logic_Vector(15 downto 0);
      signal   HCLK:          in    Std_ULogic;
      signal   dmai:          out   dma_in_type;
      signal   dmao:          in    dma_out_type;
      variable TP:            inout Boolean;
      constant InstancePath:  in    String  := "DMARead16";
      constant ScreenOutput:  in    Boolean := True;
      constant cBack2Back:    in    Boolean := False;
      constant Lock:          in    Boolean := False);

   -----------------------------------------------------------------------------
   -- AMBA AHB read access
   -----------------------------------------------------------------------------
   procedure DMAComp16(
      constant Address:       in    Std_Logic_Vector(31 downto 0);
      constant CxData:        in    Std_Logic_Vector(15 downto 0);
      variable RxData:        out   Std_Logic_Vector(15 downto 0);
      signal   HCLK:          in    Std_ULogic;
      signal   dmai:          out   dma_in_type;
      signal   dmao:          in    dma_out_type;
      variable TP:            inout Boolean;
      constant InstancePath:  in    String  := "DMAComp16";
      constant ScreenOutput:  in    Boolean := False;
      constant cBack2Back:    in    Boolean := False;
      constant Lock:          in    Boolean := False);

   -----------------------------------------------------------------------------
   -- AMBA AHB write access
   -----------------------------------------------------------------------------
   procedure DMAWrite8(
      constant Address:       in    Std_Logic_Vector(31 downto 0);
      constant Data:          in    Std_Logic_Vector( 7 downto 0);
      signal   HCLK:          in    Std_ULogic;
      signal   dmai:          out   dma_in_type;
      signal   dmao:          in    dma_out_type;
      variable TP:            inout Boolean;
      constant InstancePath:  in    String  := "DMAWrite8";
      constant ScreenOutput:  in    Boolean := False;
      constant cBack2Back:    in    Boolean := False;
      constant Lock:          in    Boolean := False);

   -----------------------------------------------------------------------------
   -- AMBA AHB read access
   -----------------------------------------------------------------------------
   procedure DMAQuiet8(
      constant Address:       in    Std_Logic_Vector(31 downto 0);
      variable Data:          out   Std_Logic_Vector( 7 downto 0);
      signal   HCLK:          in    Std_ULogic;
      signal   dmai:          out   dma_in_type;
      signal   dmao:          in    dma_out_type;
      variable TP:            inout Boolean;
      constant InstancePath:  in    String  := "DMAQuiet8";
      constant ScreenOutput:  in    Boolean := False;
      constant cBack2Back:    in    Boolean := False;
      constant Lock:          in    Boolean := False);

   -----------------------------------------------------------------------------
   -- AMBA AHB read access
   -----------------------------------------------------------------------------
   procedure DMARead8(
      constant Address:       in    Std_Logic_Vector(31 downto 0);
      variable Data:          out   Std_Logic_Vector( 7 downto 0);
      signal   HCLK:          in    Std_ULogic;
      signal   dmai:          out   dma_in_type;
      signal   dmao:          in    dma_out_type;
      variable TP:            inout Boolean;
      constant InstancePath:  in    String  := "DMARead8";
      constant ScreenOutput:  in    Boolean := True;
      constant cBack2Back:    in    Boolean := False;
      constant Lock:          in    Boolean := False);

   -----------------------------------------------------------------------------
   -- AMBA AHB read access
   -----------------------------------------------------------------------------
   procedure DMAComp8(
      constant Address:       in    Std_Logic_Vector(31 downto 0);
      constant CxData:        in    Std_Logic_Vector( 7 downto 0);
      variable RxData:        out   Std_Logic_Vector( 7 downto 0);
      signal   HCLK:          in    Std_ULogic;
      signal   dmai:          out   dma_in_type;
      signal   dmao:          in    dma_out_type;
      variable TP:            inout Boolean;
      constant InstancePath:  in    String  := "DMAComp8";
      constant ScreenOutput:  in    Boolean := False;
      constant cBack2Back:    in    Boolean := False;
      constant Lock:          in    Boolean := False);

   -----------------------------------------------------------------------------
   -- AMBA AHB write access
   -----------------------------------------------------------------------------
   procedure DMAWriteQuietBurst(
      constant Address:       in    Std_Logic_Vector(31 downto 0);
      constant Data:          in    Data_Vector;
      signal   HCLK:          in    Std_ULogic;
      signal   dmai:          out   dma_in_type;
      signal   dmao:          in    dma_out_type;
      variable TP:            inout Boolean;
      constant InstancePath:  in    String  := "DMAWrite";
      constant ScreenOutput:  in    Boolean := False;
      constant cBack2Back:    in    Boolean := False;
      constant Size:          in    Integer := 32;
      constant Beat:          in    Integer := 1;
      constant Lock:          in    Boolean := False);

   -----------------------------------------------------------------------------
   -- AMBA AHB write access
   -----------------------------------------------------------------------------
   procedure DMAWriteBurst(
      constant Address:       in    Std_Logic_Vector(31 downto 0);
      constant Data:          in    Data_Vector;
      signal   HCLK:          in    Std_ULogic;
      signal   dmai:          out   dma_in_type;
      signal   dmao:          in    dma_out_type;
      variable TP:            inout Boolean;
      constant InstancePath:  in    String  := "DMAWrite";
      constant ScreenOutput:  in    Boolean := False;
      constant cBack2Back:    in    Boolean := False;
      constant Size:          in    Integer := 32;
      constant Beat:          in    Integer := 1;
      constant Lock:          in    Boolean := False);

   -----------------------------------------------------------------------------
   -- AMBA AHB read access
   -----------------------------------------------------------------------------
   procedure DMAQuietBurst(
      constant Address:       in    Std_Logic_Vector(31 downto 0);
      variable Data:          out   Data_Vector;
      signal   HCLK:          in    Std_ULogic;
      signal   dmai:          out   dma_in_type;
      signal   dmao:          in    dma_out_type;
      variable TP:            inout Boolean;
      constant InstancePath:  in    String  := "DMAQuiet";
      constant ScreenOutput:  in    Boolean := False;
      constant cBack2Back:    in    Boolean := False;
      constant Size:          in    Integer := 32;
      constant Beat:          in    Integer := 1;
      constant Lock:          in    Boolean := False);


   -----------------------------------------------------------------------------
   -- AMBA AHB read access
   -----------------------------------------------------------------------------
   procedure DMAReadBurst(
      constant Address:       in    Std_Logic_Vector(31 downto 0);
      variable Data:          out   Data_Vector;
      signal   HCLK:          in    Std_ULogic;
      signal   dmai:          out   dma_in_type;
      signal   dmao:          in    dma_out_type;
      variable TP:            inout Boolean;
      constant InstancePath:  in    String  := "DMARead";
      constant ScreenOutput:  in    Boolean := True;
      constant cBack2Back:    in    Boolean := False;
      constant Size:          in    Integer := 32;
      constant Beat:          in    Integer := 1;
      constant Lock:          in    Boolean := False);


   -----------------------------------------------------------------------------
   -- AMBA AHB read access
   -----------------------------------------------------------------------------
   procedure DMACompBurst(
      constant Address:       in    Std_Logic_Vector(31 downto 0);
      variable CxData:        in    Data_Vector;
      variable RxData:        out   Data_Vector;
      signal   HCLK:          in    Std_ULogic;
      signal   dmai:          out   dma_in_type;
      signal   dmao:          in    dma_out_type;
      variable TP:            inout Boolean;
      constant InstancePath:  in    String  := "DMAComp";
      constant ScreenOutput:  in    Boolean := False;
      constant cBack2Back:    in    Boolean := False;
      constant Size:          in    Integer := 32;
      constant Beat:          in    Integer := 1;
      constant Lock:          in    Boolean := False);

end package DMA2AHB_TestPackage;

package body DMA2AHB_TestPackage is
   -----------------------------------------------------------------------------
   -- Compare function handling '-'
   -----------------------------------------------------------------------------
   function Compare(O, C: in Std_Logic_Vector) return Boolean is
      variable T:       Std_Logic_Vector(O'Range) := C;
      variable Result:  Boolean;
   begin
      Result := True;
      for i in O'Range loop
          if not (To_X01(O(i))=T(i) or T(i)='-' or T(i)='U') then
            Result   := False;
          end if;
      end loop;
      return Result;
   end function Compare;

   -----------------------------------------------------------------------------
   -- Function declarations
   -----------------------------------------------------------------------------
   function Conv_Std_Logic_Vector(
      constant i:          Integer;
               w:          Integer)
      return               Std_Logic_Vector is
      variable tmp:        Std_Logic_Vector(w-1 downto 0);
   begin
      tmp := Std_Logic_Vector(To_UnSigned(i, w));
      return(tmp);
   end;

   -----------------------------------------------------------------------------
   -- Function declarations
   -----------------------------------------------------------------------------
   function Conv_Integer(
      constant i:          Std_Logic_Vector)
      return               Integer is
      variable tmp:        Integer;
   begin
      tmp := To_Integer(UnSigned(i));
      return(tmp);
   end;

   -----------------------------------------------------------------------------
   -- Synchronisation with respect to clock and with output offset
   -----------------------------------------------------------------------------
   procedure Synchronise(
      signal   Clock:      in    Std_ULogic;
      constant Offset:     in    Time    := 5 ns;
      constant Enable:     in    Boolean := True) is
   begin
      if Enable then
         wait until Clock = '1';                         -- synchronise
         if Offset > 0 ns then
            wait for Offset;                             -- output offset delay
         end if;
      end if;
   end procedure Synchronise;

   -----------------------------------------------------------------------------
   -- Initialize AHB interface
   -----------------------------------------------------------------------------
   procedure DMAInit(
      signal   HCLK:          in    Std_ULogic;
      signal   dmai:          out   dma_in_type;
      constant InstancePath:  in    String  := "DMAInit";
      constant ScreenOutput:  in    Boolean := False) is
      variable L:                   Line;
   begin
      Synchronise(HCLK);
      dmai.Reset     <= '0';
      dmai.Address   <= (others => '0');
      dmai.Request   <= '0';
      dmai.Burst     <= '0';
      dmai.Beat      <= (others => '0');
      dmai.Store     <= '0';
      dmai.Data      <= (others => '0');
      dmai.Size      <= "10";
      dmai.Lock      <= '0';

      if ScreenOutput then
         Write (L, Now, Right, 15);
         Write (L, " : " & InstancePath);
         Write (L, String'(" : AHB initalised"));
         WriteLine(Output, L);
      end if;
   end procedure DMAInit;

   -----------------------------------------------------------------------------
   -- AMBA AHB write access
   -----------------------------------------------------------------------------
   procedure DMAWriteQuiet(
      constant Address:       in    Std_Logic_Vector(31 downto 0);
      constant Data:          in    Std_Logic_Vector(31 downto 0);
      signal   HCLK:          in    Std_ULogic;
      signal   dmai:          out   dma_in_type;
      signal   dmao:          in    dma_out_type;
      variable TP:            inout Boolean;
      constant InstancePath:  in    String  := "DMAWrite";
      constant ScreenOutput:  in    Boolean := False;
      constant cBack2Back:    in    Boolean := False;
      constant Size:          in    Integer := 32;
      constant Lock:          in    Boolean := False) is
      variable L:                   Line;
   begin
      -- do not synchronise when a back-to-back access is requested
      if not cBack2Back then
         Synchronise(HCLK);
      end if;
      dmai.Reset     <= '0';
      dmai.Address   <= Address;
      dmai.Request   <= '1';
      dmai.Burst     <= '0';
      dmai.Beat      <= (others => '0');
      dmai.Store     <= '1';
      dmai.Data      <= Data;
      if    Size=32 then
         dmai.Size      <= HSIZE32;
      elsif Size=16 then
         dmai.Size      <= HSIZE16;
      elsif Size=8 then
         dmai.Size      <= HSIZE8;
      else
         report "Unsupported data width"
            severity Failure;
      end if;

      if Lock then
        dmai.Lock    <= '1';
      else
        dmai.Lock    <= '0';
      end if;

      wait for 1 ns;
      if dmao.Grant='0' then
         while dmao.Grant='0' loop
            Synchronise(HCLK, 0 ns);
         end loop;
      else
         Synchronise(HCLK);
      end if;

      dmai.Reset     <= '0';
      dmai.Request   <= '0';
      dmai.Store     <= '0';
      dmai.Burst     <= '0';

      dmai.Data      <= Data;

      loop
         Synchronise(HCLK);
         while dmao.Ready='0' and dmao.Retry='0' and dmao.Fault='0' loop
            Synchronise(HCLK);
         end loop;

         if dmao.Fault='1' then
            if ScreenOutput then
               Write (L, Now, Right, 15);
               Write (L, " : " & InstancePath);
               Write (L, String'(" : AHB write access, address: "));
               HWrite(L, Address);
               Write (L, String'("  ERROR reponse "));
               WriteLine(Output, L);
            end if;
            TP             := False;
            dmai.Reset     <= '0';
            dmai.Address   <= (others => '0');
            dmai.Data      <= (others => '0');
            dmai.Request   <= '0';
            dmai.Store     <= '0';
            dmai.Burst     <= '0';
            dmai.Beat      <= (others => '0');
            dmai.Size      <= (others => '0');
            dmai.Lock      <= '0';
            Synchronise(HCLK);
            Synchronise(HCLK);
            exit;
         elsif dmao.Ready='1' then
            dmai.Reset     <= '0';
            dmai.Address   <= (others => '0');
            dmai.Data      <= (others => '0');
            dmai.Request   <= '0';
            dmai.Store     <= '0';
            dmai.Burst     <= '0';
            dmai.Beat      <= (others => '0');
            dmai.Size      <= (others => '0');
            dmai.Lock      <= '0';
            exit;
         end if;

         if dmao.Retry='1' then
           if ScreenOutput then
               Write (L, Now, Right, 15);
               Write (L, " : " & InstancePath);
               Write (L, String'(" : AHB write access, address: "));
               HWrite(L, Address);
               Write (L, String'("  RETRY/SPLIT reponse "));
               WriteLine(Output, L);
            end if;
         end if;
      end loop;
   end procedure DMAWriteQuiet;

   -----------------------------------------------------------------------------
   -- AMBA AHB write access
   -----------------------------------------------------------------------------
   procedure DMAWrite(
      constant Address:       in    Std_Logic_Vector(31 downto 0);
      constant Data:          in    Std_Logic_Vector(31 downto 0);
      signal   HCLK:          in    Std_ULogic;
      signal   dmai:          out   dma_in_type;
      signal   dmao:          in    dma_out_type;
      variable TP:            inout Boolean;
      constant InstancePath:  in    String  := "DMAWrite";
      constant ScreenOutput:  in    Boolean := False;
      constant cBack2Back:    in    Boolean := False;
      constant Size:          in    Integer := 32;
      constant Lock:          in    Boolean := False) is
      variable OK:                  Boolean := True;
      variable L:                   Line;
   begin
      DMAWriteQuiet(Address, Data, HCLK, dmai, dmao, OK,
                    InstancePath, True, cBack2Back, Size, Lock);
      if ScreenOutput and OK then
         Write (L, Now, Right, 15);
         Write (L, " : " & InstancePath);
         Write (L, String'(" : AHB write access, address: "));
         HWrite(L, Address);
         Write (L, String'(" : data: "));
         HWrite(L, Data);
         WriteLine(Output, L);
      elsif not OK then
         Write (L, Now, Right, 15);
         Write (L, " : " & InstancePath);
         Write (L, String'(" : AHB write access, address: "));
         HWrite(L, Address);
         Write (L, String'(" : ## Failed ##"));
         WriteLine(Output, L);
         TP    := False;
      end if;
   end procedure DMAWrite;


   -----------------------------------------------------------------------------
   -- AMBA AHB read access
   -----------------------------------------------------------------------------
   procedure DMAQuiet(
      constant Address:       in    Std_Logic_Vector(31 downto 0);
      variable Data:          out   Std_Logic_Vector(31 downto 0);
      signal   HCLK:          in    Std_ULogic;
      signal   dmai:          out   dma_in_type;
      signal   dmao:          in    dma_out_type;
      variable TP:            inout Boolean;
      constant InstancePath:  in    String  := "DMAQuiet";
      constant ScreenOutput:  in    Boolean := False;
      constant cBack2Back:    in    Boolean := False;
      constant Size:          in    Integer := 32;
      constant Lock:          in    Boolean := False) is
      variable L:                   Line;
   begin
      -- do not Synchronise when a back-to-back access is requested
      if not cBack2Back then
         Synchronise(HCLK);
      end if;
      dmai.Reset     <= '0';
      dmai.Address   <= Address;
      dmai.Request   <= '1';
      dmai.Burst     <= '0';
      dmai.Beat      <= (others => '0');
      dmai.Store     <= '0';
      dmai.Data      <= (others => '0');
      if    Size=32 then
         dmai.Size      <= HSIZE32;
      elsif Size=16 then
         dmai.Size      <= HSIZE16;
      elsif Size=8 then
         dmai.Size      <= HSIZE8;
      else
         report "Unsupported data width"
            severity Failure;
      end if;

      if Lock then
        dmai.Lock       <= '1';
      else
        dmai.Lock       <= '0';
      end if;


      wait for 1 ns;
      if dmao.Grant='0' then
         while dmao.Grant='0' loop
            Synchronise(HCLK, 0 ns);
         end loop;
      else
         Synchronise(HCLK);
      end if;

      dmai.Reset     <= '0';
      dmai.Data      <= (others => '0');
      dmai.Request   <= '0';
      dmai.Store     <= '0';
      dmai.Burst     <= '0';
      dmai.Beat      <= (others => '0');

      loop
         Synchronise(HCLK);
         while dmao.Ready='0' and dmao.Retry='0' and dmao.Fault='0' loop
            Synchronise(HCLK);
         end loop;

         if    dmao.Fault='1' then
            if ScreenOutput then
               Write (L, Now, Right, 15);
               Write (L, " : " & InstancePath);
               Write (L, String'(" : AHB read  access, address: "));
               HWrite(L, Address);
               Write (L, String'("  ERROR reponse "));
               WriteLine(Output, L);
            end if;
            TP             := False;
            dmai.Reset     <= '0';
            dmai.Address   <= (others => '0');
            dmai.Data      <= (others => '0');
            dmai.Request   <= '0';
            dmai.Store     <= '0';
            dmai.Burst     <= '0';
            dmai.Beat      <= (others => '0');
            dmai.Size      <= (others => '0');
            Data           := (others => 'X');
            Synchronise(HCLK);
            Synchronise(HCLK);
            exit;
         elsif dmao.Ready='1' then
            Data           := dmao.Data;
            dmai.Address   <= (others => '0');
            dmai.Beat      <= (others => '0');
            dmai.Size      <= (others => '0');
            exit;
         end if;

         if dmao.Retry='1' then
           if ScreenOutput then
               Write (L, Now, Right, 15);
               Write (L, " : " & InstancePath);
               Write (L, String'(" : AHB read  access, address: "));
               HWrite(L, Address);
               Write (L, String'("  RETRY/SPLIT reponse "));
               WriteLine(Output, L);
            end if;
         end if;
      end loop;
   end procedure DMAQuiet;

   -----------------------------------------------------------------------------
   -- AMBA AHB read access
   -----------------------------------------------------------------------------
   procedure DMARead(
      constant Address:       in    Std_Logic_Vector(31 downto 0);
      variable Data:          out   Std_Logic_Vector(31 downto 0);
      signal   HCLK:          in    Std_ULogic;
      signal   dmai:          out   dma_in_type;
      signal   dmao:          in    dma_out_type;
      variable TP:            inout Boolean;
      constant InstancePath:  in    String  := "DMARead";
      constant ScreenOutput:  in    Boolean := True;
      constant cBack2Back:    in    Boolean := False;
      constant Size:          in    Integer := 32;
      constant Lock:          in    Boolean := False) is
      variable OK:                  Boolean := True;
      variable L:                   Line;
      variable Temp:                Std_Logic_Vector(31 downto 0);
   begin
      DMAQuiet(Address, Temp, HCLK, dmai, dmao, OK,
               InstancePath, True, cBack2Back, Size, Lock);
      if ScreenOutput and OK then
         Data := Temp;
         Write (L, Now, Right, 15);
         Write (L, " : " & InstancePath);
         Write (L, String'(" : AHB read  access, address: "));
         HWrite(L, Address);
         Write (L, String'(" : data: "));
         HWrite(L, Temp);
         WriteLine(Output, L);
      elsif OK then
         Data  := Temp;
      else
         Write (L, Now, Right, 15);
         Write (L, " : " & InstancePath);
         Write (L, String'(" : AHB read  access, address: "));
         HWrite(L, Address);
         Write (L, String'(" : ## Failed ##"));
         WriteLine(Output, L);
         Data  := (others => '-');
         TP    := False;
      end if;
   end procedure DMARead;

   -----------------------------------------------------------------------------
   -- AMBA AHB read access
   -----------------------------------------------------------------------------
   procedure DMAComp(
      constant Address:       in    Std_Logic_Vector(31 downto 0);
      constant CxData:        in    Std_Logic_Vector(31 downto 0);
      variable RxData:        out   Std_Logic_Vector(31 downto 0);
      signal   HCLK:          in    Std_ULogic;
      signal   dmai:          out   dma_in_type;
      signal   dmao:          in    dma_out_type;
      variable TP:            inout Boolean;
      constant InstancePath:  in    String  := "DMAComp";
      constant ScreenOutput:  in    Boolean := False;
      constant cBack2Back:    in    Boolean := False;
      constant Size:          in    Integer := 32;
      constant Lock:          in    Boolean := False) is
      variable OK:                  Boolean := True;
      variable L:                   Line;
      variable Data:                Std_Logic_Vector(31 downto 0);
   begin
      DMAQuiet(Address, Data, HCLK, dmai, dmao, OK,
               InstancePath, True, cBack2Back, Size, Lock);
      if    not OK then
         Write (L, Now, Right, 15);
         Write (L, " : " & InstancePath);
         Write (L, String'(" : AHB read  access, address: "));
         HWrite(L, Address);
         Write (L, String'(" : ## Failed ##"));
         WriteLine(Output, L);
         TP       := False;
         RxData   := (others => '-');
      elsif not Compare(Data, CxData) then
         Write (L, Now, Right, 15);
         Write (L, " : " & InstancePath);
         Write (L, String'(" : AHB read  access, address: "));
         HWrite(L, Address);
         Write (L, String'(" : data: "));
         HWrite(L, Data);
         Write (L, String'(" : expected: "));
         HWrite(L, CxData);
         Write (L, String'(" # Error #"));
         WriteLine(Output, L);
         TP       := False;
         RxData   := Data;
      elsif ScreenOutput then
         Write(L, Now, Right, 15);
         Write(L, " : " & InstancePath);
         Write(L, String'(" : AHB read  access, address: "));
         HWrite(L, Address);
         Write(L, String'(" : data: "));
         HWrite(L, Data);
         WriteLine(Output, L);
         RxData   := Data;
      else
         RxData   := Data;
      end if;
   end procedure DMAComp;

   -----------------------------------------------------------------------------
   -- AMBA AHB write access
   -----------------------------------------------------------------------------
   procedure DMAWriteQuiet16(
      constant Address:       in    Std_Logic_Vector(31 downto 0);
      constant Data:          in    Std_Logic_Vector(15 downto 0);
      signal   HCLK:          in    Std_ULogic;
      signal   dmai:          out   dma_in_type;
      signal   dmao:          in    dma_out_type;
      variable TP:            inout Boolean;
      constant InstancePath:  in    String  := "DMAWrite16";
      constant ScreenOutput:  in    Boolean := False;
      constant cBack2Back:    in    Boolean := False;
      constant Lock:          in    Boolean := False) is
   begin
      DMAWriteQuiet(Address, Data & Data, HCLK, dmai, dmao, TP,
                    InstancePath, ScreenOutput, cBack2Back, 16, Lock);
   end procedure DMAWriteQuiet16;

   -----------------------------------------------------------------------------
   -- AMBA AHB write access
   -----------------------------------------------------------------------------
   procedure DMAWrite16(
      constant Address:       in    Std_Logic_Vector(31 downto 0);
      constant Data:          in    Std_Logic_Vector(15 downto 0);
      signal   HCLK:          in    Std_ULogic;
      signal   dmai:          out   dma_in_type;
      signal   dmao:          in    dma_out_type;
      variable TP:            inout Boolean;
      constant InstancePath:  in    String  := "DMAWrite16";
      constant ScreenOutput:  in    Boolean := False;
      constant cBack2Back:    in    Boolean := False;
      constant Lock:          in    Boolean := False) is
   begin
      DMAWrite(Address, Data & Data, HCLK, dmai, dmao, TP,
               InstancePath, ScreenOutput, cBack2Back, 16, Lock);
   end procedure DMAWrite16;

   -----------------------------------------------------------------------------
   -- AMBA AHB read access
   -----------------------------------------------------------------------------
   procedure DMAQuiet16(
      constant Address:       in    Std_Logic_Vector(31 downto 0);
      variable Data:          out   Std_Logic_Vector(15 downto 0);
      signal   HCLK:          in    Std_ULogic;
      signal   dmai:          out   dma_in_type;
      signal   dmao:          in    dma_out_type;
      variable TP:            inout Boolean;
      constant InstancePath:  in    String  := "DMAQuiet16";
      constant ScreenOutput:  in    Boolean := False;
      constant cBack2Back:    in    Boolean := False;
      constant Lock:          in    Boolean := False) is
      variable Tmp:                 Std_Logic_Vector(31 downto 0);
   begin
      DMAQuiet(Address, Tmp, HCLK, dmai, dmao, TP,
               InstancePath, ScreenOutput, cBack2Back, 16, Lock);
      if Address(1)='0' then
         Data  := Tmp(31 downto 16);
      else
         Data  := Tmp(15 downto  0);
      end if;
   end procedure DMAQuiet16;

   -----------------------------------------------------------------------------
   -- AMBA AHB read access
   -----------------------------------------------------------------------------
   procedure DMARead16(
      constant Address:       in    Std_Logic_Vector(31 downto 0);
      variable Data:          out   Std_Logic_Vector(15 downto 0);
      signal   HCLK:          in    Std_ULogic;
      signal   dmai:          out   dma_in_type;
      signal   dmao:          in    dma_out_type;
      variable TP:            inout Boolean;
      constant InstancePath:  in    String  := "DMARead16";
      constant ScreenOutput:  in    Boolean := True;
      constant cBack2Back:    in    Boolean := False;
      constant Lock:          in    Boolean := False) is
      variable Tmp:                 Std_Logic_Vector(31 downto 0);
   begin
      DMARead(Address, Tmp, HCLK, dmai, dmao, TP,
              InstancePath, ScreenOutput, cBack2Back, 16, Lock);
      if Address(1)='0' then
         Data  := Tmp(31 downto 16);
      else
         Data  := Tmp(15 downto  0);
      end if;
   end procedure DMARead16;

   -----------------------------------------------------------------------------
   -- AMBA AHB read access
   -----------------------------------------------------------------------------
   procedure DMAComp16(
      constant Address:       in    Std_Logic_Vector(31 downto 0);
      constant CxData:        in    Std_Logic_Vector(15 downto 0);
      variable RxData:        out   Std_Logic_Vector(15 downto 0);
      signal   HCLK:          in    Std_ULogic;
      signal   dmai:          out   dma_in_type;
      signal   dmao:          in    dma_out_type;
      variable TP:            inout Boolean;
      constant InstancePath:  in    String  := "DMAComp16";
      constant ScreenOutput:  in    Boolean := False;
      constant cBack2Back:    in    Boolean := False;
      constant Lock:          in    Boolean := False) is
      variable TmpRx:               Std_Logic_Vector(31 downto 0);
      variable TmpCx:               Std_Logic_Vector(31 downto 0);
   begin
      if Address(1)='0' then
         TmpCx := CxData & "----------------";
      else
         TmpCx := "----------------" & CxData;
      end if;
      DMAComp(Address, TmpCx, TmpRx, HCLK, dmai, dmao, TP,
              InstancePath, ScreenOutput, cBack2Back, 16, Lock);
      if Address(1)='0' then
         RxData := TmpRx(31 downto 16);
      else
         RxData := TmpRx(15 downto  0);
      end if;
   end procedure DMAComp16;


   -----------------------------------------------------------------------------
   -- AMBA AHB write access
   -----------------------------------------------------------------------------
   procedure DMAWriteQuiet8(
      constant Address:       in    Std_Logic_Vector(31 downto 0);
      constant Data:          in    Std_Logic_Vector( 7 downto 0);
      signal   HCLK:          in    Std_ULogic;
      signal   dmai:          out   dma_in_type;
      signal   dmao:          in    dma_out_type;
      variable TP:            inout Boolean;
      constant InstancePath:  in    String  := "DMAWrite8";
      constant ScreenOutput:  in    Boolean := False;
      constant cBack2Back:    in    Boolean := False;
      constant Lock:          in    Boolean := False) is
   begin
      DMAWriteQuiet(Address, Data & Data & Data & Data, HCLK, dmai, dmao, TP,
                    InstancePath, ScreenOutput, cBack2Back, 8, Lock);
   end procedure DMAWriteQuiet8;

   -----------------------------------------------------------------------------
   -- AMBA AHB write access
   -----------------------------------------------------------------------------
   procedure DMAWrite8(
      constant Address:       in    Std_Logic_Vector(31 downto 0);
      constant Data:          in    Std_Logic_Vector( 7 downto 0);
      signal   HCLK:          in    Std_ULogic;
      signal   dmai:          out   dma_in_type;
      signal   dmao:          in    dma_out_type;
      variable TP:            inout Boolean;
      constant InstancePath:  in    String  := "DMAWrite8";
      constant ScreenOutput:  in    Boolean := False;
      constant cBack2Back:    in    Boolean := False;
      constant Lock:          in    Boolean := False) is
   begin
      DMAWrite(Address, Data & Data & Data & Data, HCLK, dmai, dmao, TP,
               InstancePath, ScreenOutput, cBack2Back, 8, Lock);
   end procedure DMAWrite8;

   -----------------------------------------------------------------------------
   -- AMBA AHB read access
   -----------------------------------------------------------------------------
   procedure DMAQuiet8(
      constant Address:       in    Std_Logic_Vector(31 downto 0);
      variable Data:          out   Std_Logic_Vector( 7 downto 0);
      signal   HCLK:          in    Std_ULogic;
      signal   dmai:          out   dma_in_type;
      signal   dmao:          in    dma_out_type;
      variable TP:            inout Boolean;
      constant InstancePath:  in    String  := "DMAQuiet8";
      constant ScreenOutput:  in    Boolean := False;
      constant cBack2Back:    in    Boolean := False;
      constant Lock:          in    Boolean := False) is
      variable Tmp:                 Std_Logic_Vector(31 downto 0);
   begin
      DMAQuiet(Address, Tmp, HCLK, dmai, dmao, TP,
               InstancePath, ScreenOutput, cBack2Back, 8, Lock);
      if    Address(1 downto 0)="00" then
         Data  := Tmp(31 downto 24);
      elsif Address(1 downto 0)="01" then
         Data  := Tmp(23 downto 16);
      elsif Address(1 downto 0)="10" then
         Data  := Tmp(15 downto  8);
      else
         Data  := Tmp( 7 downto  0);
      end if;
   end procedure DMAQuiet8;

   -----------------------------------------------------------------------------
   -- AMBA AHB read access
   -----------------------------------------------------------------------------
   procedure DMARead8(
      constant Address:       in    Std_Logic_Vector(31 downto 0);
      variable Data:          out   Std_Logic_Vector( 7 downto 0);
      signal   HCLK:          in    Std_ULogic;
      signal   dmai:          out   dma_in_type;
      signal   dmao:          in    dma_out_type;
      variable TP:            inout Boolean;
      constant InstancePath:  in    String  := "DMARead8";
      constant ScreenOutput:  in    Boolean := True;
      constant cBack2Back:    in    Boolean := False;
      constant Lock:          in    Boolean := False) is
      variable Tmp:                 Std_Logic_Vector(31 downto 0);
   begin
      DMARead(Address, Tmp, HCLK, dmai, dmao, TP,
              InstancePath, ScreenOutput, cBack2Back, 8, Lock);
      if    Address(1 downto 0)="00" then
         Data  := Tmp(31 downto 24);
      elsif Address(1 downto 0)="01" then
         Data  := Tmp(23 downto 16);
      elsif Address(1 downto 0)="10" then
         Data  := Tmp(15 downto  8);
      else
         Data  := Tmp( 7 downto  0);
      end if;
   end procedure DMARead8;

   -----------------------------------------------------------------------------
   -- AMBA AHB read access
   -----------------------------------------------------------------------------
   procedure DMAComp8(
      constant Address:       in    Std_Logic_Vector(31 downto 0);
      constant CxData:        in    Std_Logic_Vector( 7 downto 0);
      variable RxData:        out   Std_Logic_Vector( 7 downto 0);
      signal   HCLK:          in    Std_ULogic;
      signal   dmai:          out   dma_in_type;
      signal   dmao:          in    dma_out_type;
      variable TP:            inout Boolean;
      constant InstancePath:  in    String  := "DMAComp8";
      constant ScreenOutput:  in    Boolean := False;
      constant cBack2Back:    in    Boolean := False;
      constant Lock:          in    Boolean := False) is
      variable TmpRx:               Std_Logic_Vector(31 downto 0);
      variable TmpCx:               Std_Logic_Vector(31 downto 0);
   begin
      if    Address(1 downto 0)="00" then
         TmpCx := CxData & "--------" & "--------" & "--------";
      elsif Address(1 downto 0)="01" then
         TmpCx := "--------" & CxData & "--------" & "--------";
      elsif Address(1 downto 0)="10" then
         TmpCx := "--------" & "--------" & CxData & "--------";
      else
         TmpCx := "--------" & "--------" & "--------" & CxData;
      end if;
      DMAComp(Address, TmpCx, TmpRx, HCLK, dmai, dmao, TP,
              InstancePath, ScreenOutput, cBack2Back, 8, Lock);
      if    Address(1 downto 0)="00" then
         RxData := TmpRx(31 downto 24);
      elsif Address(1 downto 0)="01" then
         RxData := TmpRx(23 downto 16);
      elsif Address(1 downto 0)="10" then
         RxData := TmpRx(15 downto  8);
      else
         RxData := TmpRx( 7 downto  0);
      end if;
   end procedure DMAComp8;

   -----------------------------------------------------------------------------
   -- AMBA AHB write access
   -----------------------------------------------------------------------------
   procedure DMAWriteQuietBurst(
      constant Address:       in    Std_Logic_Vector(31 downto 0);
      constant Data:          in    Data_Vector;
      signal   HCLK:          in    Std_ULogic;
      signal   dmai:          out   dma_in_type;
      signal   dmao:          in    dma_out_type;
      variable TP:            inout Boolean;
      constant InstancePath:  in    String  := "DMAWrite";
      constant ScreenOutput:  in    Boolean := False;
      constant cBack2Back:    in    Boolean := False;
      constant Size:          in    Integer := 32;
      constant Beat:          in    Integer := 1;
      constant Lock:          in    Boolean := False) is
      variable L:                   Line;
      constant Count:               Integer := Data'Length*WordSize/Size;
      variable GCount:              Integer := Data'Length*WordSize/Size;
      variable DCount:              Integer := 1;
   begin
      -- do not synchronise when a back-to-back access is requested
      if not cBack2Back then
         Synchronise(HCLK);
      end if;

      dmai.Reset     <= '0';
      dmai.Address   <= Address;
      dmai.Data      <= (others => '0');
      dmai.Request   <= '1';
      dmai.Store     <= '1';
      if Count > 1 then
         dmai.Burst  <= '1';
      else
         dmai.Burst  <= '0';
      end if;
      if    Beat=1 then
         dmai.Beat   <= HINCR;
      elsif Beat=4 then
         dmai.Beat   <= HINCR4;
      elsif Beat=8 then
         dmai.Beat   <= HINCR8;
      elsif Beat=16 then
         dmai.Beat   <= HINCR16;
      else
         report "Unsupported beat"
         severity Failure;
      end if;
      if Size=32 then
         dmai.Size      <= HSIZE32;
      elsif Size=16 then
         dmai.Size      <= HSIZE16;
      elsif Size=8 then
         dmai.Size      <= HSIZE8;
      else
         report "Unsupported data width"
         severity Failure;
      end if;

      if Lock then
        dmai.Lock       <= '1';
      else
        dmai.Lock       <= '0';
      end if;

      -- wait for first grant, indicating start of accesses
      Synchronise(HCLK, 0 ns);
      if dmao.Grant='0' then
         while dmao.Grant='0' loop
            Synchronise(HCLK, 0 ns);
         end loop;
      end if;
      GCount := GCount-1;

      -- first data
      if Size=32 then
         dmai.Data   <= Data(0);
      elsif Size=16 then
         dmai.Data   <= Data(0)(31 downto 16) & Data(0)(31 downto 16);
      elsif Size=8 then
         dmai.Data   <= Data(0)(31 downto 24) & Data(0)(31 downto 24) &
                        Data(0)(31 downto 24) & Data(0)(31 downto 24);
      end if;

      loop
         -- remove request when all grants received
         if dmao.Grant='1' then
            if GCount=0 then
               dmai.Reset     <= '0';
               dmai.Request   <= '0';
               dmai.Store     <= '0';
               dmai.Burst     <= '0';
            else
               GCount         := GCount-1;
            end if;
         end if;

         Synchronise(HCLK, 0 ns);

         while dmao.Grant='0' and dmao.Ready='0' and dmao.OKAY='0' and dmao.Retry='0' and dmao.Fault='0' loop
            Synchronise(HCLK, 0 ns);
         end loop;

         if    dmao.Fault='1' then
            if ScreenOutput then
               Write (L, Now, Right, 15);
               Write (L, " : " & InstancePath);
               Write (L, String'(" : AHB write access, address: "));
               HWrite(L, Conv_Std_Logic_Vector(Conv_Integer(Address)+(DCount-1)*Beat*Size/8, 32));
               Write (L, String'("  ERROR response "));
               WriteLine(Output, L);
            end if;
            TP             := False;
            dmai.Reset     <= '0';
            dmai.Address   <= (others => '0');
            dmai.Data      <= (others => '0');
            dmai.Request   <= '0';
            dmai.Store     <= '0';
            dmai.Burst     <= '0';
            dmai.Beat      <= (others => '0');
            dmai.Size      <= (others => '0');
            Synchronise(HCLK, 0 ns);
            Synchronise(HCLK, 0 ns);
            exit;
         elsif dmao.OKAY='1' then
            -- for each OKAY, provide new data
            if DCount=Count then
               dmai.Address   <= (others => '0');
               dmai.Beat      <= (others => '0');
               dmai.Size      <= (others => '0');
               Synchronise(HCLK, 0 ns);
               while dmao.Ready='0' loop
                  Synchronise(HCLK, 0 ns);
               end loop;
               if GCount/=0 then
                  report "DMAWriteQuietBurst: Too few grants received!"
                  severity Failure;
               end if;
               exit;
            else
               if Size=32 then
                  dmai.Data   <= Data(DCount);
               elsif Size=16 then
                  dmai.Data   <= Data(DCount/2)((31-16*(DCount mod 2)) downto (16-(16*(DCount mod 2)))) &
                                 Data(DCount/2)((31-16*(DCount mod 2)) downto (16-(16*(DCount mod 2))));
               elsif Size=8 then
                  dmai.Data   <= Data(DCount/4)((31-8*(DCount mod 4)) downto (24-(8*(DCount mod 4)))) &
                                 Data(DCount/4)((31-8*(DCount mod 4)) downto (24-(8*(DCount mod 4)))) &
                                 Data(DCount/4)((31-8*(DCount mod 4)) downto (24-(8*(DCount mod 4)))) &
                                 Data(DCount/4)((31-8*(DCount mod 4)) downto (24-(8*(DCount mod 4))));
               end if;
               DCount      := DCount+1;
            end if;
         end if;

         if dmao.Retry='1' then
           if ScreenOutput then
               Write (L, Now, Right, 15);
               Write (L, " : " & InstancePath);
               Write (L, String'(" : AHB write access, address: "));
               HWrite(L, Conv_Std_Logic_Vector(Conv_Integer(Address)+(DCount-1)*Beat*Size/8, 32));
               Write (L, String'("  RETRY/SPLIT response "));
               WriteLine(Output, L);
            end if;
         end if;
      end loop;
   end procedure DMAWriteQuietBurst;

   -----------------------------------------------------------------------------
   -- AMBA AHB write access
   -----------------------------------------------------------------------------
   procedure DMAWriteBurst(
      constant Address:       in    Std_Logic_Vector(31 downto 0);
      constant Data:          in    Data_Vector;
      signal   HCLK:          in    Std_ULogic;
      signal   dmai:          out   dma_in_type;
      signal   dmao:          in    dma_out_type;
      variable TP:            inout Boolean;
      constant InstancePath:  in    String  := "DMAWrite";
      constant ScreenOutput:  in    Boolean := False;
      constant cBack2Back:    in    Boolean := False;
      constant Size:          in    Integer := 32;
      constant Beat:          in    Integer := 1;
      constant Lock:          in    Boolean := False) is
      variable OK:                  Boolean := True;
      variable L:                   Line;
   begin
      DMAWriteQuietBurst(Address, Data, HCLK, dmai, dmao, OK,
                    InstancePath, ScreenOutput, cBack2Back, Size, Beat, Lock);
      if ScreenOutput and OK then
         for i in 0 to Data'Length-1 loop
            Write (L, Now, Right, 15);
            Write (L, " : " & InstancePath);
            Write (L, String'(" : AHB write access, address: "));
            HWrite(L, Conv_Std_Logic_Vector(Conv_Integer(Address)+i*Beat*Size/8, 32));
            Write (L, String'(" : data: "));
            HWrite(L, Data(i));
            WriteLine(Output, L);
         end loop;
      elsif not OK then
         Write (L, Now, Right, 15);
         Write (L, " : " & InstancePath);
         Write (L, String'(" : AHB write access, address: "));
         HWrite(L, Address);
         Write (L, String'(" : ## Failed ##"));
         WriteLine(Output, L);
         TP    := False;
      end if;
   end procedure DMAWriteBurst;
   -----------------------------------------------------------------------------
   -- AMBA AHB read access
   -----------------------------------------------------------------------------
   procedure DMAQuietBurst(
      constant Address:       in    Std_Logic_Vector(31 downto 0);
      variable Data:          out   Data_Vector;
      signal   HCLK:          in    Std_ULogic;
      signal   dmai:          out   dma_in_type;
      signal   dmao:          in    dma_out_type;
      variable TP:            inout Boolean;
      constant InstancePath:  in    String  := "DMAQuiet";
      constant ScreenOutput:  in    Boolean := False;
      constant cBack2Back:    in    Boolean := False;
      constant Size:          in    Integer := 32;
      constant Beat:          in    Integer := 1;
      constant Lock:          in    Boolean := False) is
      variable L:                   Line;
      constant Count:               Integer := Data'Length*WordSize/Size;
      variable GCount:              Integer := Data'Length*WordSize/Size;
      variable DCount:              Integer := 1;
      variable DataPart:            Integer := 0;
   begin
      -- do not synchronise when a back-to-back access is requested
      if not cBack2Back then
         Synchronise(HCLK);
      end if;

      dmai.Reset     <= '0';
      dmai.Address   <= Address;
      dmai.Data      <= (others => '0');
      dmai.Request   <= '1';
      dmai.Store     <= '0';
      if Count > 1 then
         dmai.Burst  <= '1';
      else
         dmai.Burst  <= '0';
      end if;
      if    Beat=1 then
         dmai.Beat   <= HINCR;
      elsif Beat=4 then
         dmai.Beat   <= HINCR4;
      elsif Beat=8 then
         dmai.Beat   <= HINCR8;
      elsif Beat=16 then
         dmai.Beat   <= HINCR16;
      else
         report "Unsupported beat"
         severity Failure;
      end if;
      if Size=32 then
         dmai.Size      <= HSIZE32;
      elsif Size=16 then
         dmai.Size      <= HSIZE16;
         if Address(1 downto 0) = "00" then
            DataPart := 0;
         else
            DataPart := 1;
         end if;
      elsif Size=8 then
         dmai.Size      <= HSIZE8;
         if Address(1 downto 0) = "00" then
            DataPart := 0;
         elsif Address(1 downto 0) = "01" then
            DataPart := 1;
         elsif Address(1 downto 0) = "10" then
            DataPart := 2;
         else
            DataPart := 3;
         end if;
      else
        report "Unsupported data width"
        severity Failure;
      end if;

      if Lock then
        dmai.Lock    <= '1';
      else
        dmai.Lock    <= '0';
      end if;

      -- wait for first grant, indicating start of accesses
      Synchronise(HCLK, 0 ns);
      if dmao.Grant='0' then
         while dmao.Grant='0' loop
            Synchronise(HCLK, 0 ns);
         end loop;
      end if;
      GCount := GCount-1;

      loop
         -- remove request when all grants received
         if dmao.Grant='1' then
            if GCount=0 then
               dmai.Reset     <= '0';
               dmai.Data      <= (others => '0');
               dmai.Request   <= '0';
               dmai.Store     <= '0';
               dmai.Burst     <= '0';
            else
               GCount         := GCount-1;
            end if;
         end if;

         Synchronise(HCLK, 0 ns);

         while dmao.Grant='0' and dmao.Ready='0' and dmao.Retry='0' and dmao.Fault='0' loop
            Synchronise(HCLK, 0 ns);
         end loop;

         if    dmao.Fault='1' then
            if ScreenOutput then
               Write (L, Now, Right, 15);
               Write (L, " : " & InstancePath);
               Write (L, String'(" : AHB read  access, address: "));
               HWrite(L, Conv_Std_Logic_Vector(Conv_Integer(Address)+(DCount-1)*Beat*Size/8, 32));
               Write (L, String'("  ERROR response"));
               WriteLine(Output, L);
            end if;
            TP             := False;
            dmai.Reset     <= '0';
            dmai.Address   <= (others => '0');
            dmai.Data      <= (others => '0');
            dmai.Request   <= '0';
            dmai.Store     <= '0';
            dmai.Burst     <= '0';
            dmai.Beat      <= (others => '0');
            dmai.Size      <= (others => '0');
            Synchronise(HCLK);
            Synchronise(HCLK);
            exit;
         elsif dmao.Ready='1' then
            -- for each READY, store data
            if Size=32 then
               Data(DCount-1)    := dmao.Data;
            elsif Size=16 then
               Data((DCount-1)/2)((31-16*((DCount-1) mod 2)) downto (16-(16*((DCount-1) mod 2)))) :=
                 dmao.Data((31-16*DataPart) downto (16-16*DataPart));
               DataPart := (DataPart + 1) mod 2;
            elsif Size=8 then
               Data((DCount-1)/4)((31-8*((DCount-1) mod 4)) downto (24-(8*((DCount-1) mod 4)))) :=
                 dmao.Data((31-8*DataPart) downto (24-8*DataPart));
               DataPart := (DataPart + 1) mod 4;
            end if;

            if DCount=Count then
               dmai.Address   <= (others => '0');
               dmai.Beat      <= (others => '0');
               dmai.Size      <= (others => '0');
               if GCount/=0 then
                  report "DMAQuietBurst: Too few grants received!"
                  severity Failure;
               end if;
               exit;
            else
               DCount         := DCount+1;
            end if;
         end if;

         if dmao.Retry='1' then
           if ScreenOutput then
               Write (L, Now, Right, 15);
               Write (L, " : " & InstancePath);
               Write (L, String'(" : AHB read  access, address: "));
               HWrite(L, Conv_Std_Logic_Vector(Conv_Integer(Address)+(DCount-1)*Beat*Size/8, 32));
               Write (L, String'("  RETRY/SPLIT response "));
               WriteLine(Output, L);
            end if;
         end if;
      end loop;
   end procedure DMAQuietBurst;

   -----------------------------------------------------------------------------
   -- AMBA AHB read access
   -----------------------------------------------------------------------------
   procedure DMAReadBurst(
      constant Address:       in    Std_Logic_Vector(31 downto 0);
      variable Data:          out   Data_Vector;
      signal   HCLK:          in    Std_ULogic;
      signal   dmai:          out   dma_in_type;
      signal   dmao:          in    dma_out_type;
      variable TP:            inout Boolean;
      constant InstancePath:  in    String  := "DMARead";
      constant ScreenOutput:  in    Boolean := True;
      constant cBack2Back:    in    Boolean := False;
      constant Size:          in    Integer := 32;
      constant Beat:          in    Integer := 1;
      constant Lock:          in    Boolean := False) is
      variable OK:                  Boolean := True;
      variable L:                   Line;
      variable Temp:                Data_Vector(0 to Data'Length-1);
   begin
      DMAQuietBurst(Address, Temp, HCLK, dmai, dmao, OK,
               InstancePath, ScreenOutput, cBack2Back, Size, Beat, Lock);
      if ScreenOutput and OK then
         Data  := Temp;
         for i in 0 to Data'Length-1 loop
            Write (L, Now, Right, 15);
            Write (L, " : " & InstancePath);
            Write (L, String'(" : AHB read  access, address: "));
            HWrite(L, Conv_Std_Logic_Vector(Conv_Integer(Address)+i*Beat*Size/8, 32));
            Write (L, String'(" : data: "));
            HWrite(L, Temp(i));
            WriteLine(Output, L);
         end loop;
      elsif OK then
         Data  := Temp;
      else
         Write (L, Now, Right, 15);
         Write (L, " : " & InstancePath);
         Write (L, String'(" : AHB read  access, address: "));
         HWrite(L, Address);
         Write (L, String'(" : ## Failed ##"));
         WriteLine(Output, L);
         Temp  := (others => (others => '-'));
         Data  := Temp;
         TP    := False;
      end if;
   end procedure DMAReadBurst;


   -----------------------------------------------------------------------------
   -- AMBA AHB read access
   -----------------------------------------------------------------------------
   procedure DMACompBurst(
      constant Address:       in    Std_Logic_Vector(31 downto 0);
      variable CxData:        in    Data_Vector;
      variable RxData:        out   Data_Vector;
      signal   HCLK:          in    Std_ULogic;
      signal   dmai:          out   dma_in_type;
      signal   dmao:          in    dma_out_type;
      variable TP:            inout Boolean;
      constant InstancePath:  in    String  := "DMAComp";
      constant ScreenOutput:  in    Boolean := False;
      constant cBack2Back:    in    Boolean := False;
      constant Size:          in    Integer := 32;
      constant Beat:          in    Integer := 1;
      constant Lock:          in    Boolean := False) is
      variable OK:                  Boolean := True;
      variable L:                   Line;
      variable Data:                Data_Vector(0 to CxData'Length-1);
   begin
      DMAQuietBurst(Address, Data, HCLK, dmai, dmao, OK,
               InstancePath, ScreenOutput, cBack2Back, Size, Beat, Lock);
      if not OK then
         Write (L, Now, Right, 15);
         Write (L, " : " & InstancePath);
         Write (L, String'(" : AHB read  access, address: "));
         HWrite(L, Address);
         Write (L, String'(" : ## Failed ##"));
         WriteLine(Output, L);
         TP       := False;
         Data     := (others => (others => '-'));
         RxData   := Data;
      else
         for i in 0 to Data'Length-1 loop
            if not Compare(Data(i), CxData(i)) then
               Write(L, Now, Right, 15);
               Write(L, " : " & InstancePath);
               Write(L, String'(" : AHB read  access, address: "));
               HWrite(L, Conv_Std_Logic_Vector(Conv_Integer(Address)+i*Beat*Size/8, 32));
               Write(L, String'(" : data: "));
               HWrite(L, Data(i));
               Write(L, String'(" : expected: "));
               HWrite(L, CxData(i));
               Write(L, String'(" # Error #"));
               WriteLine(Output, L);
               TP       := False;
            elsif ScreenOutput then
               Write(L, Now, Right, 15);
               Write(L, " : " & InstancePath);
               Write(L, String'(" : AHB read  access, address: "));
               HWrite(L, Conv_Std_Logic_Vector(Conv_Integer(Address)+i*Beat*Size/8, 32));
               Write(L, String'(" : data: "));
               HWrite(L, Data(i));
               WriteLine(Output, L);
            end if;
         end loop;
         RxData   := Data;
      end if;
   end procedure DMACompBurst;

end package body DMA2AHB_TestPackage; --======================================--

