Forum Discussion
Altera_Forum
Honored Contributor
11 years ago --- Quote Start --- But to be more precise, I want the actual implementation of the Avalon MM Slave (there should be some typical skeleton VHDL functionality except for the Avalon MM ports right? --- Quote End --- Its pretty straight-forward to code the Avalon-MM interface handshake, eg., here's an Avalon-MM to RAM wrapper/adapter ...
-- ----------------------------------------------------------------
-- avs_ram_interface.vhd
-- ----------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
-- ----------------------------------------------------------------
entity avs_ram_interface is
generic (
ADDR_WIDTH : integer := 5; -- 2 x M512
BYTEEN_WIDTH : integer := 4;
DATA_WIDTH : integer := 32
);
port (
-- Reset and clock
rstN : in std_logic;
clk : in std_logic;
-- Avalon Slave Interface
avs_read : in std_logic;
avs_write : in std_logic;
avs_addr : in std_logic_vector( ADDR_WIDTH-1 downto 0);
avs_byteen : in std_logic_vector(BYTEEN_WIDTH-1 downto 0);
avs_wrdata : in std_logic_vector( DATA_WIDTH-1 downto 0);
avs_rddata : out std_logic_vector( DATA_WIDTH-1 downto 0);
avs_rdvalid : out std_logic;
avs_wait : out std_logic;
-- RAM interface
ram_wren : out std_logic;
ram_addr : out std_logic_vector( ADDR_WIDTH-1 downto 0);
ram_byteen : out std_logic_vector(BYTEEN_WIDTH-1 downto 0);
ram_wrdata : out std_logic_vector( DATA_WIDTH-1 downto 0);
ram_rddata : in std_logic_vector( DATA_WIDTH-1 downto 0)
);
end entity;
-- ----------------------------------------------------------------
architecture slave of avs_ram_interface is
-- Read valid pipeline
signal rdvalid : std_logic_vector(2 downto 1);
begin
-- ------------------------------------------------------------
-- Wait-request handshake
-- ------------------------------------------------------------
--
process(clk, rstN)
begin
if (rstN = '0') then
-- High during reset per Avalon verification suite
avs_wait <= '1';
elsif rising_edge(clk) then
avs_wait <= '0';
end if;
end process;
-- ------------------------------------------------------------
-- Read data valid pipeline
-- ------------------------------------------------------------
--
process(clk, rstN)
begin
if (rstN = '0') then
rdvalid <= (others => '0');
elsif rising_edge(clk) then
rdvalid(1) <= avs_read;
rdvalid(2) <= rdvalid(1);
end if;
end process;
avs_rdvalid <= rdvalid(2);
-- ------------------------------------------------------------
-- RAM interface (pass-through connections)
-- ------------------------------------------------------------
--
ram_wren <= avs_write;
ram_addr <= avs_addr;
ram_byteen <= avs_byteen;
ram_wrdata <= avs_wrdata;
avs_rddata <= ram_rddata;
end architecture;
Similarly, here's some control registers code ...
-- ----------------------------------------------------------------
-- avs_spi_master_registers.vhd
-- ----------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;
-- Control library
library control;
use control.utilities_pkg.all;
use control.components.all;
-- ----------------------------------------------------------------
entity avs_spi_master_registers is
generic (
-- SPI select width (number of devices)
SWIDTH : integer := 1
);
port (
rstN : in std_logic;
clk : in std_logic;
-- --------------------------------------------------------
-- Avalon-MM slave interface
-- --------------------------------------------------------
--
avs_write : in std_logic;
avs_read : in std_logic;
avs_addr : in std_logic_vector( 2 downto 0);
avs_byteen : in std_logic_vector( 3 downto 0);
avs_wrdata : in std_logic_vector(31 downto 0);
avs_rddata : out std_logic_vector(31 downto 0);
avs_rdvalid : out std_logic;
avs_wait : out std_logic;
-- --------------------------------------------------------
-- Control/status
-- --------------------------------------------------------
--
spi_enable : out std_logic;
spi_manual : out std_logic;
spi_done : in std_logic;
spi_miso : in std_logic;
spi_width : out std_logic_vector( 4 downto 0);
spi_baud : out std_logic_vector(31 downto 0);
spi_wrdata : out std_logic_vector(31 downto 0);
spi_rddata : in std_logic_vector(31 downto 0);
spi_sel : out std_logic_vector(SWIDTH-1 downto 0)
);
end entity;
-- ----------------------------------------------------------------
architecture mixed of avs_spi_master_registers is
-- ------------------------------------------------------------
-- Register offsets
-- ------------------------------------------------------------
--
constant REG_SPI_CONTROL : integer := 16#00#;
constant REG_SPI_STATUS : integer := 16#01#;
constant REG_SPI_WIDTH : integer := 16#02#;
constant REG_SPI_BAUD : integer := 16#03#;
--
constant REG_SPI_WRDATA : integer := 16#04#;
constant REG_SPI_RDDATA : integer := 16#05#;
constant REG_SPI_SEL : integer := 16#06#;
--
-- First unused address
constant REG_LAST : integer := 16#07#;
-- ------------------------------------------------------------
-- Address parameters
-- ------------------------------------------------------------
--
constant ADDR_WIDTH : integer := avs_addr'length;
constant ADDR_MAX : integer := 2**ADDR_WIDTH;
-- ------------------------------------------------------------
-- Signals
-- ------------------------------------------------------------
--
-- Input registers
signal avs_write_in : std_logic;
signal avs_read_in : std_logic;
signal avs_addr_in : std_logic_vector(ADDR_WIDTH-1 downto 0);
signal avs_byteen_in : std_logic_vector( 3 downto 0);
signal avs_wrdata_in : std_logic_vector(31 downto 0);
-- Read data multiplexer
type rddata_mux_t is array (0 to ADDR_MAX-1) of
std_logic_vector(31 downto 0);
signal rddata_mux : rddata_mux_t;
-- Address decoder write-enable outputs
signal en : std_logic_vector(ADDR_MAX-1 downto 0);
begin
-- ------------------------------------------------------------
-- Input registers
-- ------------------------------------------------------------
--
process(clk, rstN)
begin
if (rstN = '0') then
avs_write_in <= '0';
avs_read_in <= '0';
avs_addr_in <= (others => '0');
avs_byteen_in <= (others => '0');
avs_wrdata_in <= (others => '0');
elsif rising_edge(clk) then
avs_write_in <= avs_write;
avs_read_in <= avs_read;
avs_addr_in <= avs_addr;
avs_byteen_in <= avs_byteen;
avs_wrdata_in <= avs_wrdata;
end if;
end process;
-- ------------------------------------------------------------
-- Wait acknowledge
-- ------------------------------------------------------------
--
-- The registers can accept write/read transactions on every
-- clock so the wait signal never asserts, other than at reset.
--
process(clk, rstN)
begin
if (rstN = '0') then
-- Assert wait-request during reset
avs_wait <= '1';
elsif rising_edge(clk) then
avs_wait <= '0';
end if;
end process;
-- ------------------------------------------------------------
-- Read-data and valid handshake
-- ------------------------------------------------------------
--
-- The output data is registered, as are the input controls,
-- so there is a two clock pipeline delay from the acceptance
-- of a read command to the delivery of read data.
--
process(clk,rstN)
begin
if (rstN = '0') then
avs_rdvalid <= '0';
avs_rddata <= (others => '0');
elsif rising_edge(clk) then
-- Read-data valid
avs_rdvalid <= avs_read_in;
-- Read-data
avs_rddata <= rddata_mux(to_int(avs_addr_in));
end if;
end process;
-- ------------------------------------------------------------
-- Write enable address decoder
-- ------------------------------------------------------------
--
u1: address_decoder
generic map (
ADDR_WIDTH => ADDR_WIDTH,
ADDR_MAX => ADDR_MAX
)
port map (
addr => avs_addr_in,
wr_in => avs_write_in,
wr_out => en
);
-- ============================================================
-- Registers
-- ============================================================
--
-- ------------------------------------------------------------
-- Control
-- ------------------------------------------------------------
--
u2: control_register
generic map (
BYTEEN_WIDTH => 4,
DATA_WIDTH => 32,
CONTROL_WIDTH => 2,
DEFAULT_VALUE => 0
)
port map (
clk => clk,
rstN => rstN,
wren => en(REG_SPI_CONTROL),
byteen => avs_byteen_in,
wrdata => avs_wrdata_in,
rddata => rddata_mux(REG_SPI_CONTROL),
control(0) => spi_enable,
control(1) => spi_manual
);
(I had to snip the end of that code to be within the text limit). From this code, you can see how you can pipeline the Avalon-MM signals to process write and read transactions. Cheers, Dave