Commit 350f2b58 authored by Grzegorz Daniluk's avatar Grzegorz Daniluk

adding simple testbench for z7_axi_gpio_expander

parent 5582fd3c
target = "xilinx"
action = "simulation"
sim_tool = "modelsim"
top_module = "sim_top_ps_gpio"
syn_device = "XC7Z010"
files = [ "gpio_axi.vhd", "sim_top_ps_gpio.vhd" ]
modules = { "local" : ["../../../"] }
memory-map:
bus: axi4-lite-32
name: axi_gpio
description: Simple AXI GPIO with register map compatible with Xilinx Zynq-7 PS GPIO
children:
- reg:
name: out_b0
description: Bank0 out register
width: 32
access: wo
address: 0x0000a040
- reg:
name: out_b1
description: Bank1 out register
width: 32
access: wo
address: 0x0000a044
- reg:
name: in_b0
description: Bank0 in register
width: 32
access: ro
address: 0x0000a060
- reg:
name: in_b1
description: Bank1 in register
width: 32
access: ro
address: 0x0000a064
- reg:
name: dir_b0
description: Bank0 dir register
width: 32
access: wo
address: 0x0000a204
- reg:
name: oen_b0
description: Bank0 oen register
width: 32
access: wo
address: 0x0000a208
- reg:
name: dir_b1
description: Bank1 dir register
width: 32
access: wo
address: 0x0000a244
- reg:
name: oen_b1
description: Bank1 oen register
width: 32
access: wo
address: 0x0000a248
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity axi_gpio is
port (
aclk : in std_logic;
areset_n : in std_logic;
awvalid : in std_logic;
awready : out std_logic;
awaddr : in std_logic_vector(15 downto 2);
awprot : in std_logic_vector(2 downto 0);
wvalid : in std_logic;
wready : out std_logic;
wdata : in std_logic_vector(31 downto 0);
wstrb : in std_logic_vector(3 downto 0);
bvalid : out std_logic;
bready : in std_logic;
bresp : out std_logic_vector(1 downto 0);
arvalid : in std_logic;
arready : out std_logic;
araddr : in std_logic_vector(15 downto 2);
arprot : in std_logic_vector(2 downto 0);
rvalid : out std_logic;
rready : in std_logic;
rdata : out std_logic_vector(31 downto 0);
rresp : out std_logic_vector(1 downto 0);
-- Bank0 out register
out_b0_o : out std_logic_vector(31 downto 0);
-- Bank1 out register
out_b1_o : out std_logic_vector(31 downto 0);
-- Bank0 in register
in_b0_i : in std_logic_vector(31 downto 0);
-- Bank1 in register
in_b1_i : in std_logic_vector(31 downto 0);
-- Bank0 dir register
dir_b0_o : out std_logic_vector(31 downto 0);
-- Bank0 oen register
oen_b0_o : out std_logic_vector(31 downto 0);
-- Bank1 dir register
dir_b1_o : out std_logic_vector(31 downto 0);
-- Bank1 oen register
oen_b1_o : out std_logic_vector(31 downto 0)
);
end axi_gpio;
architecture syn of axi_gpio is
signal rd_int : std_logic;
signal wr_int : std_logic;
signal rd_ack_int : std_logic;
signal wr_ack_int : std_logic;
signal dato : std_logic_vector(31 downto 0);
signal axi_wip : std_logic;
signal axi_wdone : std_logic;
signal axi_rip : std_logic;
signal axi_rdone : std_logic;
signal out_b0_reg : std_logic_vector(31 downto 0);
signal out_b1_reg : std_logic_vector(31 downto 0);
signal dir_b0_reg : std_logic_vector(31 downto 0);
signal oen_b0_reg : std_logic_vector(31 downto 0);
signal dir_b1_reg : std_logic_vector(31 downto 0);
signal oen_b1_reg : std_logic_vector(31 downto 0);
signal reg_rdat_int : std_logic_vector(31 downto 0);
signal rd_ack1_int : std_logic;
begin
-- AW, W and B channels
wr_int <= (awvalid and wvalid) and not axi_wip;
awready <= axi_wip and wr_ack_int;
wready <= axi_wip and wr_ack_int;
bvalid <= axi_wdone;
process (aclk, areset_n) begin
if areset_n = '0' then
axi_wip <= '0';
axi_wdone <= '0';
elsif rising_edge(aclk) then
axi_wip <= (awvalid and wvalid) and not axi_wdone;
axi_wdone <= wr_ack_int or (axi_wdone and not bready);
end if;
end process;
bresp <= "00";
-- AR and R channels
rd_int <= arvalid and not axi_rip;
arready <= axi_rip and rd_ack_int;
rvalid <= axi_rdone;
process (aclk, areset_n) begin
if areset_n = '0' then
axi_rip <= '0';
axi_rdone <= '0';
rdata <= (others => '0');
elsif rising_edge(aclk) then
axi_rip <= arvalid and not axi_rdone;
if rd_ack_int = '1' then
rdata <= dato;
end if;
axi_rdone <= rd_ack_int or (axi_rdone and not rready);
end if;
end process;
rresp <= "00";
-- Assign outputs
out_b0_o <= out_b0_reg;
out_b1_o <= out_b1_reg;
dir_b0_o <= dir_b0_reg;
oen_b0_o <= oen_b0_reg;
dir_b1_o <= dir_b1_reg;
oen_b1_o <= oen_b1_reg;
-- Process for write requests.
process (aclk, areset_n) begin
if areset_n = '0' then
wr_ack_int <= '0';
out_b0_reg <= "00000000000000000000000000000000";
out_b1_reg <= "00000000000000000000000000000000";
dir_b0_reg <= "00000000000000000000000000000000";
oen_b0_reg <= "00000000000000000000000000000000";
dir_b1_reg <= "00000000000000000000000000000000";
oen_b1_reg <= "00000000000000000000000000000000";
elsif rising_edge(aclk) then
wr_ack_int <= '0';
case awaddr(15 downto 2) is
when "10100000010000" =>
-- Register out_b0
if wr_int = '1' then
out_b0_reg <= wdata;
end if;
wr_ack_int <= wr_int;
when "10100000010001" =>
-- Register out_b1
if wr_int = '1' then
out_b1_reg <= wdata;
end if;
wr_ack_int <= wr_int;
when "10100000011000" =>
-- Register in_b0
when "10100000011001" =>
-- Register in_b1
when "10100010000001" =>
-- Register dir_b0
if wr_int = '1' then
dir_b0_reg <= wdata;
end if;
wr_ack_int <= wr_int;
when "10100010000010" =>
-- Register oen_b0
if wr_int = '1' then
oen_b0_reg <= wdata;
end if;
wr_ack_int <= wr_int;
when "10100010010001" =>
-- Register dir_b1
if wr_int = '1' then
dir_b1_reg <= wdata;
end if;
wr_ack_int <= wr_int;
when "10100010010010" =>
-- Register oen_b1
if wr_int = '1' then
oen_b1_reg <= wdata;
end if;
wr_ack_int <= wr_int;
when others =>
wr_ack_int <= wr_int;
end case;
end if;
end process;
-- Process for registers read.
process (aclk, areset_n) begin
if areset_n = '0' then
rd_ack1_int <= '0';
reg_rdat_int <= (others => 'X');
elsif rising_edge(aclk) then
reg_rdat_int <= (others => '0');
case araddr(15 downto 2) is
when "10100000010000" =>
-- out_b0
rd_ack1_int <= rd_int;
when "10100000010001" =>
-- out_b1
rd_ack1_int <= rd_int;
when "10100000011000" =>
-- in_b0
reg_rdat_int <= in_b0_i;
rd_ack1_int <= rd_int;
when "10100000011001" =>
-- in_b1
reg_rdat_int <= in_b1_i;
rd_ack1_int <= rd_int;
when "10100010000001" =>
-- dir_b0
rd_ack1_int <= rd_int;
when "10100010000010" =>
-- oen_b0
rd_ack1_int <= rd_int;
when "10100010010001" =>
-- dir_b1
rd_ack1_int <= rd_int;
when "10100010010010" =>
-- oen_b1
rd_ack1_int <= rd_int;
when others =>
rd_ack1_int <= rd_int;
end case;
end if;
end process;
-- Process for read requests.
process (araddr, reg_rdat_int, rd_ack1_int, rd_int) begin
-- By default ack read requests
dato <= (others => '0');
case araddr(15 downto 2) is
when "10100000010000" =>
-- out_b0
dato <= reg_rdat_int;
rd_ack_int <= rd_ack1_int;
when "10100000010001" =>
-- out_b1
dato <= reg_rdat_int;
rd_ack_int <= rd_ack1_int;
when "10100000011000" =>
-- in_b0
dato <= reg_rdat_int;
rd_ack_int <= rd_ack1_int;
when "10100000011001" =>
-- in_b1
dato <= reg_rdat_int;
rd_ack_int <= rd_ack1_int;
when "10100010000001" =>
-- dir_b0
dato <= reg_rdat_int;
rd_ack_int <= rd_ack1_int;
when "10100010000010" =>
-- oen_b0
dato <= reg_rdat_int;
rd_ack_int <= rd_ack1_int;
when "10100010010001" =>
-- dir_b1
dato <= reg_rdat_int;
rd_ack_int <= rd_ack1_int;
when "10100010010010" =>
-- oen_b1
dato <= reg_rdat_int;
rd_ack_int <= rd_ack1_int;
when others =>
rd_ack_int <= rd_int;
end case;
end process;
end syn;
vsim -t 10fs work.sim_top_ps_gpio -voptargs="+acc"
set StdArithNoWarnings 1
set NumericStdNoWarnings 1
do wave.do
radix -hexadecimal
run 200ms
wave zoomfull
radix -hexadecimal
-------------------------------------------------------------------------------
-- Title : AXI PS_GPIO Expander for Zynq-7 Testbench
-- Project : General Cores
-------------------------------------------------------------------------------
-- File : sim_top_ps_gpio.vhd
-- Author : Grzegorz Daniluk <grzegorz.daniluk@cern.ch>
-- Company : CERN
-- Platform : FPGA-generics
-- Standard : VHDL '93
-------------------------------------------------------------------------------
-- Description:
--
-- This is a very simple testbench for axi_gpio_expander for Zynq-7. It
-- instantiates AXI GPIO module that simulates simplified register map of Zynq-7
-- PS GPIO. Therefore no PS BFM is required and simulation can be performed
-- using xsim or GHDL.
--
-------------------------------------------------------------------------------
-- Copyright (c) 2019 CERN
--------------------------------------------------------------------------------
-- Copyright and related rights are licensed under the Solderpad Hardware
-- License, Version 2.0 (the "License"); you may not use this file except
-- in compliance with the License. You may obtain a copy of the License at
-- http://solderpad.org/licenses/SHL-2.0.
-- Unless required by applicable law or agreed to in writing, software,
-- hardware and materials distributed under this License is distributed on an
-- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
-- or implied. See the License for the specific language governing permissions
-- and limitations under the License.
--------------------------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use ieee.std_logic_misc.all;
entity sim_top_ps_gpio is
end sim_top_ps_gpio;
architecture behav of sim_top_ps_gpio is
constant c_PERIOD : time := 10 ns;
constant c_NUM : integer := 54;
signal clk, rst_n : std_logic;
signal ARVALID : std_logic;
signal AWVALID : std_logic;
signal BREADY : std_logic;
signal RREADY : std_logic;
signal WVALID : std_logic;
signal ARADDR : std_logic_vector (31 downto 0);
signal AWADDR : std_logic_vector (31 downto 0);
signal WDATA : std_logic_vector (31 downto 0);
signal WSTRB : std_logic_vector (3 downto 0);
signal ARREADY : std_logic;
signal AWREADY : std_logic;
signal BVALID : std_logic;
signal RVALID : std_logic;
signal WREADY : std_logic;
signal BRESP : std_logic_vector (1 downto 0);
signal RRESP : std_logic_vector (1 downto 0);
signal RDATA : std_logic_vector (31 downto 0);
signal error_b1 : std_logic;
signal out_b0 : std_logic_vector(31 downto 0);
signal out_b1 : std_logic_vector(31 downto 0);
signal dir_b0 : std_logic_vector(31 downto 0);
signal dir_b1 : std_logic_vector(31 downto 0);
signal oen_b0 : std_logic_vector(31 downto 0);
signal oen_b1 : std_logic_vector(31 downto 0);
signal gpio_out : std_logic_vector(c_NUM-1 downto 0);
signal gpio_oe : std_logic_vector(c_NUM-1 downto 0);
signal gpio_dir : std_logic_vector(c_NUM-1 downto 0);
signal gpio_in : std_logic_vector(c_NUM-1 downto 0);
begin
CLK_GEN: process
begin
clk <= '0';
wait for c_PERIOD/2;
clk <= '1';
wait for c_PERIOD/2;
end process;
rst_n <= '0', '1' after c_PERIOD*20;
U_EXP: entity work.axi_gpio_expander
generic map ( g_num => c_NUM)
port map (
clk_i => clk,
rst_n_i => rst_n,
gpio_out => gpio_out,
gpio_oe => gpio_oe,
gpio_dir => gpio_dir,
gpio_in => gpio_in,
ARVALID => ARVALID,
AWVALID => AWVALID,
BREADY => BREADY,
RREADY => RREADY,
WVALID => WVALID,
ARADDR => ARADDR,
AWADDR => AWADDR,
WDATA => WDATA,
WSTRB => WSTRB,
ARREADY => ARREADY,
AWREADY => AWREADY,
BVALID => BVALID,
RLAST => '0',
RVALID => RVALID,
WREADY => WREADY,
BRESP => BRESP,
RRESP => RRESP,
RDATA => RDATA);
U_GPIO: entity work.axi_gpio
port map (
aclk => clk,
areset_n => rst_n,
arvalid => ARVALID,
awvalid => AWVALID,
bready => BREADY,
rready => RREADY,
wvalid => WVALID,
araddr => ARADDR(15 downto 2),
awaddr => AWADDR(15 downto 2),
wdata => WDATA,
wstrb => WSTRB,
arready => ARREADY,
awready => AWREADY,
bvalid => BVALID,
rvalid => RVALID,
wready => WREADY,
bresp => BRESP,
rresp => RRESP,
rdata => RDATA,
awprot => (others=>'0'),
arprot => (others=>'0'),
-- Bank0 out register
out_b0_o => out_b0,
-- Bank1 out register
out_b1_o => out_b1,
-- Bank0 in register
in_b0_i => out_b0,
-- Bank1 in register
in_b1_i => out_b1,
-- Bank0 dir register
dir_b0_o => dir_b0,
-- Bank0 oen register
oen_b0_o => oen_b0,
-- Bank1 dir register
dir_b1_o => dir_b1,
-- Bank1 oen register
oen_b1_o => oen_b1);
error_b1 <= or_reduce(out_b1(31 downto 22));
STIM_DIR_GEN: process
begin
wait until rst_n = '1';
gpio_dir <= "01" & x"abcdef3456789";
wait for 1 us;
while true loop
gpio_dir <= gpio_dir(49 downto 0) & gpio_dir(53 downto 50);
wait for 1 us;
end loop;
wait;
end process;
STIM_OE_GEN: process
begin
wait until rst_n = '1';
gpio_oe <= "01" & x"abcdef3456789";
wait for 600 ns;
while true loop
gpio_oe <= gpio_oe(49 downto 0) & gpio_dir(53 downto 50);
wait for 1 us;
end loop;
wait;
end process;
STIM_GEN: process
begin
wait until rst_n = '1';
-- wait until rising_edge(clk);
for i in 0 to c_NUM-1 loop
gpio_out <= (others=>'0');
gpio_out(i) <= '1';
wait for 220 ns;
end loop;
wait;
end process;
end behav;
onerror {resume}
quietly WaveActivateNextPane {} 0
add wave -noupdate /sim_top_ps_gpio/clk
add wave -noupdate /sim_top_ps_gpio/rst_n
add wave -noupdate -expand -group AXI /sim_top_ps_gpio/ARVALID
add wave -noupdate -expand -group AXI /sim_top_ps_gpio/AWVALID
add wave -noupdate -expand -group AXI /sim_top_ps_gpio/BREADY
add wave -noupdate -expand -group AXI /sim_top_ps_gpio/RREADY
add wave -noupdate -expand -group AXI /sim_top_ps_gpio/WVALID
add wave -noupdate -expand -group AXI /sim_top_ps_gpio/ARADDR
add wave -noupdate -expand -group AXI /sim_top_ps_gpio/AWADDR
add wave -noupdate -expand -group AXI /sim_top_ps_gpio/WDATA
add wave -noupdate -expand -group AXI /sim_top_ps_gpio/WSTRB
add wave -noupdate -expand -group AXI /sim_top_ps_gpio/ARREADY
add wave -noupdate -expand -group AXI /sim_top_ps_gpio/AWREADY
add wave -noupdate -expand -group AXI /sim_top_ps_gpio/BVALID
add wave -noupdate -expand -group AXI /sim_top_ps_gpio/RVALID
add wave -noupdate -expand -group AXI /sim_top_ps_gpio/WREADY
add wave -noupdate -expand -group AXI /sim_top_ps_gpio/BRESP
add wave -noupdate -expand -group AXI /sim_top_ps_gpio/RRESP
add wave -noupdate -expand -group AXI /sim_top_ps_gpio/RDATA
add wave -noupdate /sim_top_ps_gpio/error_b1
add wave -noupdate /sim_top_ps_gpio/out_b0
add wave -noupdate /sim_top_ps_gpio/out_b1
add wave -noupdate /sim_top_ps_gpio/dir_b0
add wave -noupdate /sim_top_ps_gpio/dir_b1
add wave -noupdate /sim_top_ps_gpio/oen_b0
add wave -noupdate /sim_top_ps_gpio/oen_b1
add wave -noupdate /sim_top_ps_gpio/gpio_out
add wave -noupdate /sim_top_ps_gpio/gpio_oe
add wave -noupdate /sim_top_ps_gpio/gpio_dir
add wave -noupdate /sim_top_ps_gpio/gpio_in
add wave -noupdate /sim_top_ps_gpio/U_EXP/state
add wave -noupdate /sim_top_ps_gpio/U_EXP/gpio_oe_prev
add wave -noupdate /sim_top_ps_gpio/U_EXP/gpio_dir_prev
add wave -noupdate /sim_top_ps_gpio/U_EXP/gpio_out_prev
add wave -noupdate /sim_top_ps_gpio/U_EXP/gpio_oe_changed
add wave -noupdate /sim_top_ps_gpio/U_EXP/gpio_dir_changed
add wave -noupdate /sim_top_ps_gpio/U_EXP/gpio_out_changed
add wave -noupdate /sim_top_ps_gpio/U_EXP/refresh_all
add wave -noupdate /sim_top_ps_gpio/U_EXP/current_bank
TreeUpdate [SetDefaultTree]
WaveRestoreCursors {{Cursor 1} {0 fs} 0}
quietly wave cursor active 0
configure wave -namecolwidth 150
configure wave -valuecolwidth 100
configure wave -justifyvalue left
configure wave -signalnamewidth 1
configure wave -snapdistance 10
configure wave -datasetprefix 0
configure wave -rowmargin 4
configure wave -childrowmargin 2
configure wave -gridoffset 0
configure wave -gridperiod 1
configure wave -griddelta 40
configure wave -timeline 0
configure wave -timelineunits fs
update
WaveRestoreZoom {0 fs} {5780 fs}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment