From 8e49e9b08708f1a5a9711e89a9424b4295773225 Mon Sep 17 00:00:00 2001 From: the great greene arkleseizure Date: Sat, 12 Oct 2013 08:17:43 +0100 Subject: fish --- m6522_tb.vhd | 378 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 378 insertions(+) create mode 100644 m6522_tb.vhd (limited to 'm6522_tb.vhd') diff --git a/m6522_tb.vhd b/m6522_tb.vhd new file mode 100644 index 0000000..3e4262d --- /dev/null +++ b/m6522_tb.vhd @@ -0,0 +1,378 @@ +-- BBC Micro for Altera DE1 +-- +-- Copyright (c) 2011 Mike Stirling +-- +-- All rights reserved +-- +-- Redistribution and use in source and synthezised forms, with or without +-- modification, are permitted provided that the following conditions are met: +-- +-- * Redistributions of source code must retain the above copyright notice, +-- this list of conditions and the following disclaimer. +-- +-- * Redistributions in synthesized form must reproduce the above copyright +-- notice, this list of conditions and the following disclaimer in the +-- documentation and/or other materials provided with the distribution. +-- +-- * Neither the name of the author nor the names of other contributors may +-- be used to endorse or promote products derived from this software without +-- specific prior written agreement from the author. +-- +-- * License is granted for non-commercial use only. A fee may not be charged +-- for redistributions as source code or in synthesized/hardware form without +-- specific prior written agreement from the author. +-- +-- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +-- AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, +-- THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +-- PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE +-- LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +-- CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +-- SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +-- INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +-- CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +-- ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +-- POSSIBILITY OF SUCH DAMAGE. +-- + +library IEEE; +use IEEE.STD_LOGIC_1164.ALL; +use IEEE.NUMERIC_STD.ALL; + +entity m6522_tb is +end entity; + +architecture tb of m6522_tb is + +component M6522 is + port ( + + I_RS : in std_logic_vector(3 downto 0); + I_DATA : in std_logic_vector(7 downto 0); + O_DATA : out std_logic_vector(7 downto 0); + O_DATA_OE_L : out std_logic; + + I_RW_L : in std_logic; + I_CS1 : in std_logic; + I_CS2_L : in std_logic; + + O_IRQ_L : out std_logic; -- note, not open drain + -- port a + I_CA1 : in std_logic; + I_CA2 : in std_logic; + O_CA2 : out std_logic; + O_CA2_OE_L : out std_logic; + + I_PA : in std_logic_vector(7 downto 0); + O_PA : out std_logic_vector(7 downto 0); + O_PA_OE_L : out std_logic_vector(7 downto 0); + + -- port b + I_CB1 : in std_logic; + O_CB1 : out std_logic; + O_CB1_OE_L : out std_logic; + + I_CB2 : in std_logic; + O_CB2 : out std_logic; + O_CB2_OE_L : out std_logic; + + I_PB : in std_logic_vector(7 downto 0); + O_PB : out std_logic_vector(7 downto 0); + O_PB_OE_L : out std_logic_vector(7 downto 0); + + I_P2_H : in std_logic; -- high for phase 2 clock ____----__ + RESET_L : in std_logic; + ENA_4 : in std_logic; -- clk enable + CLK : in std_logic + ); +end component; + +signal rs : std_logic_vector(3 downto 0) := "0000"; +signal di : std_logic_vector(7 downto 0) := "00000000"; +signal do : std_logic_vector(7 downto 0); +signal n_d_oe : std_logic; +signal r_nw : std_logic := '1'; +signal cs1 : std_logic := '0'; +signal n_cs2 : std_logic := '0'; +signal n_irq : std_logic; +signal ca1_in : std_logic := '0'; +signal ca2_in : std_logic := '0'; +signal ca2_out : std_logic; +signal n_ca2_oe : std_logic; +signal pa_in : std_logic_vector(7 downto 0) := "00000000"; +signal pa_out : std_logic_vector(7 downto 0); +signal n_pa_oe : std_logic_vector(7 downto 0); +signal cb1_in : std_logic := '0'; +signal cb1_out : std_logic; +signal n_cb1_oe : std_logic; +signal cb2_in : std_logic := '0'; +signal cb2_out : std_logic; +signal n_cb2_oe : std_logic; +signal pb_in : std_logic_vector(7 downto 0) := "00000000"; +signal pb_out : std_logic_vector(7 downto 0); +signal n_pb_oe : std_logic_vector(7 downto 0); + +signal phase2 : std_logic := '0'; +signal n_reset : std_logic := '0'; +signal clken : std_logic := '0'; +signal clock : std_logic := '0'; + +begin + + uut: m6522 port map ( + rs, di, do, n_d_oe, + r_nw, cs1, n_cs2, n_irq, + ca1_in, ca2_in, ca2_out, n_ca2_oe, + pa_in, pa_out, n_pa_oe, + cb1_in, cb1_out, n_cb1_oe, + cb2_in, cb2_out, n_cb2_oe, + pb_in, pb_out, n_pb_oe, + phase2, n_reset, clken, clock + ); + + clock <= not clock after 125 ns; -- 4x 1 MHz + phase2 <= not phase2 after 500 ns; + clken <= '1'; -- all cycles enabled + + process + begin + wait for 1 us; + -- Release reset + n_reset <= '1'; + end process; + + process + + procedure reg_write( + a : in std_logic_vector(3 downto 0); + d : in std_logic_vector(7 downto 0)) is + begin + wait until falling_edge(phase2); + rs <= a; + di <= d; + cs1 <= '1'; + r_nw <= '0'; + wait until falling_edge(phase2); + cs1 <= '0'; + r_nw <= '1'; + end procedure; + + procedure reg_read( + a : in std_logic_vector(3 downto 0)) is + begin + wait until falling_edge(phase2); + rs <= a; + cs1 <= '1'; + r_nw <= '1'; + wait until falling_edge(phase2); + cs1 <= '0'; + end procedure; + + begin + wait for 2 us; + + -- Set port A and B to output + reg_write("0010","11111111"); + reg_write("0011","11111111"); + + -- Write to port B + reg_write("0000","10101010"); + -- Write to port B + reg_write("0000","01010101"); + -- Write to port A (no handshake) + reg_write("1111","10101010"); + -- Write to port A (with handshake) + reg_write("0001","01010101"); + + -- Set port A and B to input + reg_write("0010","00000000"); + reg_write("0011","00000000"); + + -- Apply input stimuli and read from ports + pa_in <= "10101010"; + pb_in <= "01010101"; + reg_read("0000"); + reg_read("0001"); + + -- Test CA1 interrupt + ca1_in <= '0'; + reg_write("1100","00000001"); -- PCR - interrupt on rising edge + reg_write("1101","01111111"); -- Clear interrupts + reg_write("1110","01111111"); -- Disable all interrupts + reg_write("1110","10000010"); -- Enable CA1 interrupt + ca1_in <= '1'; -- Trigger event + wait for 2 us; + reg_read("1101"); + reg_read("0001"); -- Should clear interrupt + wait for 2 us; + reg_write("1100","00000000"); -- PCR - interrupt on falling edge + ca1_in <= '0'; -- Trigger event + wait for 2 us; + reg_read("1101"); + reg_write("1101","00000010"); -- Should clear interrupt + wait for 2 us; + reg_write("1110","00000010"); -- Disable CA1 interrupt + + -- Test CB1 interrupt + cb1_in <= '0'; + reg_write("1100","00010000"); -- PCR - interrupt on rising edge + reg_write("1101","01111111"); -- Clear interrupts + reg_write("1110","01111111"); -- Disable all interrupts + reg_write("1110","10010000"); -- Enable CB1 interrupt + cb1_in <= '1'; -- Trigger event + wait for 2 us; + reg_read("1101"); + reg_read("0000"); -- Should clear interrupt + wait for 2 us; + reg_write("1100","00000000"); -- PCR - interrupt on falling edge + cb1_in <= '0'; -- Trigger event + wait for 2 us; + reg_read("1101"); + reg_write("1101","00010000"); -- Should clear interrupt + wait for 2 us; + reg_write("1110","00010000"); -- Disable CA1 interrupt + + -- Test CA2 interrupt modes + reg_write("1101","01111111"); -- Clear interrupts + reg_write("1110","01111111"); -- Disable all interrupts + reg_write("1110","10000001"); -- Enable CA2 interrupt + -- mode 2 (+ve edge, clear on read/write) + reg_write("1100","00000100"); -- PCR + ca2_in <= '1'; -- Trigger event + wait for 2 us; + reg_read("1101"); + reg_read("1111"); -- Should not clear interrupt + reg_read("0001"); -- Should clear interrupt + wait for 2 us; + -- mode 0 (-ve edge, clear on read/write) + reg_write("1100","00000000"); -- PCR + ca2_in <= '0'; -- Trigger event + wait for 2 us; + reg_read("1101"); + reg_read("1111"); -- Should not clear interrupt + reg_read("0001"); -- Should clear interrupt + wait for 2 us; + -- mode 3 (+ve edge, don't clear on read/write) + reg_write("1100","00000110"); + ca2_in <= '1'; -- Trigger event + wait for 2 us; + reg_read("1101"); + reg_read("1111"); -- Should not clear interrupt + reg_read("0001"); -- Should not clear interrupt + reg_write("1101","00000001"); -- Should clear interrupt + wait for 2 us; + -- mode 1 (-ve edge, don't clear on read/write) + reg_write("1100","00000010"); + ca2_in <= '0'; -- Trigger event + wait for 2 us; + reg_read("1101"); + reg_read("1111"); -- Should not clear interrupt + reg_read("0001"); -- Should not clear interrupt + reg_write("1101","00000001"); -- Should clear interrupt + wait for 2 us; + + -- Test CA2 output modes + -- mode 4 (set low on read/write of ORA, set high on CA1 interrupt edge) + reg_write("1100","00001000"); + -- mode 5 (set low for 1 cycle on read/write ORA) + reg_write("1100","00001010"); + -- mode 6 (held low) + reg_write("1100","00001100"); + -- mode 7 (held high) + reg_write("1100","00001110"); + + -- Test CB2 interrupt modes + reg_write("1101","01111111"); -- Clear interrupts + reg_write("1110","01111111"); -- Disable all interrupts + reg_write("1110","10001000"); -- Enable CB2 interrupt + -- mode 2 (+ve edge, clear on read/write) + reg_write("1100","01000000"); -- PCR + cb2_in <= '1'; -- Trigger event + wait for 2 us; + reg_read("1101"); + reg_read("0000"); -- Should clear interrupt + wait for 2 us; + -- mode 0 (-ve edge, clear on read/write) + reg_write("1100","00000000"); -- PCR + cb2_in <= '0'; -- Trigger event + wait for 2 us; + reg_read("1101"); + reg_read("0000"); -- Should clear interrupt + wait for 2 us; + -- mode 3 (+ve edge, don't clear on read/write) + reg_write("1100","01100000"); + cb2_in <= '1'; -- Trigger event + wait for 2 us; + reg_read("1101"); + reg_read("0000"); -- Should not clear interrupt + reg_write("1101","00001000"); -- Should clear interrupt + wait for 2 us; + -- mode 1 (-ve edge, don't clear on read/write) + reg_write("1100","00100000"); + cb2_in <= '0'; -- Trigger event + wait for 2 us; + reg_read("1101"); + reg_read("0000"); -- Should not clear interrupt + reg_write("1101","00001000"); -- Should clear interrupt + wait for 2 us; + + -- Test CB2 output modes + -- mode 4 (set low on read/write of ORA, set high on CA1 interrupt edge) + reg_write("1100","10000000"); + -- mode 5 (set low for 1 cycle on read/write ORA) + reg_write("1100","10100000"); + -- mode 6 (held low) + reg_write("1100","11000000"); + -- mode 7 (held high) + reg_write("1100","11100000"); + + -- Timer 1 timeout + reg_write("1101","01111111"); -- Clear interrupts + reg_write("1110","01111111"); -- Disable all interrupts + reg_write("1110","11000000"); -- Enable timer 1 interrupt + -- Count to 16 + reg_write("0100","00010000"); + reg_write("0101","00000000"); + wait for 50 us; + -- Count to 16 + reg_write("0100","00010000"); + reg_write("0101","00000000"); -- Should clear interrupt + wait for 50 us; + reg_read("0100"); -- Should clear interrupt + + -- Timer 2 timeout + reg_write("1101","01111111"); -- Clear interrupts + reg_write("1110","01111111"); -- Disable all interrupts + reg_write("1110","10100000"); -- Enable timer 2 interrupt + -- Count to 16 + reg_write("1000","00010000"); + reg_write("1001","00000000"); + wait for 50 us; + -- Count to 16 + reg_write("1000","00010000"); + reg_write("1001","00000000"); -- Should clear interrupt + wait for 50 us; + reg_read("1000"); -- Should clear interrupt + + -- Timer 2 test similar to BBC usage (speech interrupt) + -- PB6 high + pb_in(6) <= '1'; + reg_write("1101","01111111"); -- Clear interrupts + reg_write("1110","01111111"); -- Disable all interrupts + reg_write("1011","00100000"); -- Timer 2 PB6 counter mode + reg_write("1000","00000001"); -- Start at 1 + reg_write("1001","00000000"); + reg_write("1110","10100000"); -- Enable timer 2 interrupt + wait for 5 us; + -- Generate falling edge + pb_in(6) <= '0'; + wait for 5 us; + -- Clear interrupt + reg_write("1101","00100000"); + -- Zero timer high byte + reg_write("1001","00000000"); + + wait; + end process; + +end architecture; -- cgit v1.2.3