-- -- Copyright 1991 -- EDN Magazine -- The VHDL Technology Group -- All Rights Reserved -- -- File name : z80.testbench.vhdl -- Title : Z80 Microprocessor -- Notes : This testbench needs the Z80_parser and -- Std_DevelopersKit to execute. It functions as -- as connection between the parsed Sentry test -- patterns and the Z80 model. -- Author(s) : M. Markowitz ( EDN Magazine ) -- : W. Billowitch ( VHDL Technology Group ) -- -------------------------------------------------------------------- -- MODIFICATION HISTORY : -- -------------------------------------------------------------------- -- version no:| author:| mod. date:| changes made: -- V0.100 | mcm | 09/15/91 | Original Code -- V0.101 | mcm | 09/27/91 | removed most of expected response process. -- V0.102 | mkd | 10/05/91 | adding code to read input masks and data. -- -------------------------------------------------------------------- -- V0.102 | mkd | 10/05/91 | adding code to read input masks and data. -- V0.103 | mcm | 12/02/91 | Moved output strobe to 50 nsec and added debug signals -- V0.104 | mcm | 01/14/92 | Modified to use Z80_shell -- V0.105 | mcm | 01/29/92 | Modified to accept new pad ring with IO cells -- -------------------------------------------------------------------- LIBRARY std_developerskit; use std_developerskit.std_iopak.all, STD.TEXTIO.all; Library Z80_support; Use work.Z80_support.all; library ieee; use ieee.std_logic_1164.all; Use work.z80_parser.all; Entity Z80_testbench1 is end Z80_testbench1; Architecture Testbench1 of Z80_testbench1 is Component Z80_shell Port ( ADDRO_15 : OUT std_logic; ADDRO_14 : OUT std_logic; ADDRO_13 : OUT std_logic; ADDRO_12 : OUT std_logic; ADDRO_11 : OUT std_logic; ADDRO_10 : OUT std_logic; ADDRO_9 : OUT std_logic; ADDRO_8 : OUT std_logic; ADDRO_7 : OUT std_logic; ADDRO_6 : OUT std_logic; ADDRO_5 : OUT std_logic; ADDRO_4 : OUT std_logic; ADDRO_3 : OUT std_logic; ADDRO_2 : OUT std_logic; ADDRO_1 : OUT std_logic; ADDRO_0 : OUT std_logic; DATA_7 : INOUT std_logic; DATA_6 : INOUT std_logic; DATA_5 : INOUT std_logic; DATA_4 : INOUT std_logic; DATA_3 : INOUT std_logic; DATA_2 : INOUT std_logic; DATA_1 : INOUT std_logic; DATA_0 : INOUT std_logic; MREQO_n : OUT std_logic; -- Memory Request ( Active Low, three-state ) BUSACKO_n: BUFFER std_logic; -- Bus Acknowledge ( Active Low ) BUSREQI_n: IN std_logic; -- Bus Request ( Active Low ) HALTO_n : BUFFER std_logic; -- Halt State ( Active Low ) INTI_n : IN std_logic; -- Interrupt Request ( Active Low ) IORQO_n : OUT std_logic; -- Input/Output Request ( Active Low, three-state ) NMII_n : IN std_logic; -- Nonmaskable Interrupt ( Negative-edge triggered ) RDO_n : OUT std_logic; -- Read ( Active low, three-state ) RESET_n : IN std_logic; -- Reset ( Active low ) WAITI_n : IN std_logic; -- Wait ( Active low ) WRO_n : OUT std_logic; -- Write ( Active low, three-state ) RFSHO_n : BUFFER std_logic; -- Refresh ( Active low ) M1O_n : BUFFER std_logic; -- M1 Cycle ( Active low ) CLKI : IN std_logic -- CLOCK SIGNAL, not really of type std_logic ); end Component; TYPE error_states is (none, addr, data, a_d, other, mixed); -- MCM SIGNAL NET_Addr : std_logic_vector ( 15 downto 0 ); SIGNAL NET_Data : std_logic_vector ( 7 downto 0 ); SIGNAL NET_MREQ_n : std_logic; SIGNAL NET_BUSACK_n : std_logic; SIGNAL NET_BUSREQ_n : std_logic; SIGNAL NET_HALT_n : std_logic; SIGNAL NET_INT_n : std_logic; SIGNAL NET_IORQ_n : std_logic; SIGNAL NET_NMI_n : std_logic; SIGNAL NET_RD_n : std_logic; SIGNAL NET_RST_n : std_logic; SIGNAL NET_WAIT_n : std_logic; SIGNAL NET_WR_n : std_logic; SIGNAL NET_RFSH_n : std_logic; SIGNAL NET_M1_n : std_logic; SIGNAL NET_CLK : std_logic := '0'; SIGNAL Screw_up : error_states := none; -- MCM SIGNAL wrong_bit : std_logic_vector(15 downto 0); -- MCM FILE file_indata : TEXT IS IN "z80_input.dat"; --+----------------------------------------------------------------------------- --| Function Name : z80_Tester --| --| Overloading : None --| --| Purpose : This procedure gets current monitor masks, --| current driver masks, Drivers, and Expected --| values from the input data file --| --| --| --| Parameters : --| f_ptr : IN TEXT; --| l_num : INOUT INTEGER; --| M_Masks : IN Monitor_Masks_Table; --| D_Masks : IN Driver_Masks_Table; --| f_count : OUT INTEGER; --| c_mmask : OUT std_logic_vector; --| c_dmask : OUT std_logic_vector; --| Drivers : OUT std_logic_vector; --| Expected : OUT std_logic_vector --| Result : --| --| NOTE : --|----------------------------------------------------------------------------- procedure z80_tester (VARIABLE f_ptr : IN TEXT; VARIABLE l_num : INOUT INTEGER; VARIABLE M_Masks : IN Monitor_Masks_Table; VARIABLE D_Masks : IN Driver_Masks_Table; VARIABLE f_count : OUT INTEGER; VARIABLE c_mmask : OUT std_logic_vector; VARIABLE c_dmask : OUT std_logic_vector; VARIABLE Drivers : OUT std_logic_vector; VARIABLE Expected : OUT std_logic_vector ) IS variable line_buf : string (1 To 128); variable l : line; variable token : string(1 TO 32); variable index : Integer; variable idx : Integer; variable ch : character; VARIABLE Data_Slices : std_logic_vector(1 TO 60); VARIABLE current_dmask : std_logic_vector(1 TO 60); VARIABLE current_mmask : std_logic_vector(1 TO 60); BEGIN WHILE (NOT ENDFILE(f_ptr)) LOOP fgetline(line_buf, f_ptr, l); line_buf := To_Upper(line_buf); l_num := l_num + 1; idx := 1; index := 1; index := get_NonBlank(line_buf, idx); get_word(line_buf, index, token); IF (StrNCmp(token, "REM", 3) = 0) THEN assert false report " z80_tester --- this is a REM line " & To_String(l_num) severity NOTE; ELSIF (StrNCmp(token, "ENABLE", 6) = 0) THEN -- enable the current masks Enable_Statement(line_buf, index, l_num, M_Masks, D_Masks, current_mmask, current_dmask); c_mmask := current_mmask; c_dmask := current_dmask; ELSIF (StrNCmp(token, "SET", 3) = 0) THEN -- IF set F or SET FC, read data and apply it for count times Set_F_Statement(line_buf, index, l_num, f_count); -- get the input channel data by calling procedure get_channel_data -- from the z80_parser.pkg get_channel_data(f_ptr, l_num, Data_Slices); -- set the drivers and expected values -- mapping of Drivers variable to Data, and other input pins Drivers(7 DOWNTO 0) := Data_Slices(17 TO 24); -- Data(7 downto 0) Drivers(8) := Data_Slices(33); -- INT_n; Drivers(9) := Data_Slices(34); -- WAIT_n; Drivers(10) := Data_Slices(35); -- BUSREQ_n Drivers(11) := Data_Slices(48); -- NMI_n Drivers(12) := Data_Slices(57); -- RESET_n -- mapping of Expected to Address, Data and other -- signals to be monitored Expected(15 DOWNTO 0) := Data_Slices(1 TO 16); -- Address(15 DOWNTO 0) Expected(23 DOWNTO 16) := Data_Slices(17 TO 24); -- Data(7) to Data(0) Expected(24) := Data_Slices(26); -- RD_n Expected(25) := Data_Slices(27); -- WR_n Expected(26) := Data_Slices(28); -- MREQ_n Expected(27) := Data_Slices(29); -- IORQ_n Expected(28) := Data_Slices(31); -- M1_n Expected(29) := Data_Slices(36); -- BUSACK_n Expected(30) := Data_Slices(39); -- HALT_n Expected(31) := Data_Slices(40); -- RFSH_n EXIT; END IF; END LOOP; RETURN; END; --+----------------------------------------------------------------------------- --| Function Name : Response_z80 --| --| Overloading : None --| --| Purpose : This procedure compares the expected channels values --| with the actual signals and assert error messages if --| if they differ --| --| Parameters : --| l_num : IN INTEGER; --| c_mmask : IN std_logic_vector , this is monitor mask --| if '1' then monitor the channel --| otherwise donot monitor --| --| Expected : IN std_logic_vector --| Screw_up : INOUT error_states; -- MCM --| Wrong_bit : OUT std_logic_vector -- MCM --| Result : --| --| NOTE : --|----------------------------------------------------------------------------- procedure Response_z80 (CONSTANT l_num : IN Integer; VARIABLE c_mmask : IN std_logic_vector; VARIABLE Expected : IN std_logic_vector; SIGNAL Screw_up : INOUT error_states; -- MCM SIGNAL wrong_bit : OUT std_logic_vector -- MCM ) IS VARIABLE current_mmask : std_logic_vector(1 TO 60):= c_mmask; VARIABLE Expected_data : std_logic_vector(31 DOWNTO 0):= Expected; VARIABLE indx : Integer := 15; VARIABLE data_idx : Integer := 7; BEGIN screw_up <= none; wrong_bit <= "0000000000000000"; -- MCM -- observe address FOR i IN 1 TO 16 LOOP IF (current_mmask(i) = '1') THEN -- Monitor if monitor mask is '1' Assert NET_Addr(indx) = Expected_data(indx) report " Response_z80 --- error in signal NET_Addr(" & To_String(indx) &")" & " at line number " &To_String(l_num) & " of the input data file " severity Error; If ( NET_Addr(indx) /= Expected_data(indx) ) then -- MCM screw_up <= addr; -- MCM wrong_bit(indx)<= '1'; -- MCM end if; -- MCM END IF; indx := indx - 1; END LOOP; -- observe data indx := 23; -- MCM FOR i IN 17 TO 24 LOOP IF (current_mmask(i) = '1') THEN -- Monitor if monitor mask is '1' Assert NET_Data(data_idx) = Expected_data(indx) report " Response_z80 --- error in signal NET_Data(" & To_String(data_idx) &")" & " at line number " &To_String(l_num) & " of the input data file " severity Error; If ( NET_Data(data_idx) /= Expected_data(indx) ) then -- MCM if ( screw_up = none ) then -- MCM screw_up <= data; -- MCM wrong_bit(i-17)<= '1'; -- MCM elsif ( screw_up = addr ) then -- MCM screw_up <= a_d; -- MCM end if; -- MCM end if; -- MCM END IF; indx := indx - 1; data_idx := data_idx - 1; END LOOP; IF (current_mmask(26) = '1') THEN Assert NET_RD_n = Expected_data(24) report " Response_z80 --- error in signal NET_RD_n " & " at line number " &To_String(l_num) & " of the input data file " severity Error; If ( NET_RD_n /= Expected_data(24) ) then -- MCM if ( screw_up = none ) then -- MCM screw_up <= other; -- MCM else -- MCM screw_up <= mixed; -- MCM end if; -- MCM end if; -- MCM END IF; IF (current_mmask(27) = '1') THEN Assert NET_WR_n = Expected_data(25) report " Response_z80 --- error in signal NET_WR_n " & " at line number " &To_String(l_num) & " of the input data file " severity Error; If ( NET_WR_n /= Expected_data(25) ) then -- MCM if ( screw_up = none ) then -- MCM screw_up <= other; -- MCM else -- MCM screw_up <= mixed; -- MCM end if; -- MCM end if; -- MCM END IF; IF (current_mmask(28) = '1') THEN Assert NET_MREQ_n = Expected_data(26) report " Response_z80 --- error in signal NET_MREQ_n " & " at line number " &To_String(l_num) & " of the input data file " severity Error; If ( NET_MREQ_n /= Expected_data(26) ) then -- MCM if ( screw_up = none ) then -- MCM screw_up <= other; -- MCM else -- MCM screw_up <= mixed; -- MCM end if; -- MCM end if; -- MCM END IF; IF (current_mmask(29) = '1') THEN Assert NET_IORQ_n = Expected_data(27) report " Response_z80 --- error in signal NET_IORQ_n " & " at line number " &To_String(l_num) & " of the input data file " severity Error; If ( NET_IORQ_n /= Expected_data(27) ) then -- MCM if ( screw_up = none ) then -- MCM screw_up <= other; -- MCM else -- MCM screw_up <= mixed; -- MCM end if; -- MCM end if; -- MCM END IF; IF (current_mmask(31) = '1') THEN Assert NET_M1_n = Expected_data(28) report " Response_z80 --- error in signal NET_M1_n " & " at line number " &To_String(l_num) & " of the input data file " severity Error; If ( NET_M1_n /= Expected_data(28) ) then -- MCM if ( screw_up = none ) then -- MCM screw_up <= other; -- MCM else -- MCM screw_up <= mixed; -- MCM end if; -- MCM end if; -- MCM END IF; IF (current_mmask(36) = '1') THEN Assert NET_BUSACK_n = Expected_data(29) report " Response_z80 --- error in signal NET_BUSACK_n " & " at line number " &To_String(l_num) & " of the input data file " severity Error; If ( NET_BUSACK_n /= Expected_data(29) ) then -- MCM if ( screw_up = none ) then -- MCM screw_up <= other; -- MCM else -- MCM screw_up <= mixed; -- MCM end if; -- MCM end if; -- MCM END IF; IF (current_mmask(39) = '1') THEN Assert NET_HALT_n = Expected_data(30) report " Response_z80 --- error in signal NET_HALT_n " & " at line number " &To_String(l_num) & " of the input data file " severity Error; If ( NET_HALT_n /= Expected_data(30) ) then -- MCM if ( screw_up = none ) then -- MCM screw_up <= other; -- MCM else -- MCM screw_up <= mixed; -- MCM end if; -- MCM end if; -- MCM END IF; IF (current_mmask(40) = '1') THEN Assert NET_RFSH_n = Expected_data(31) report " Response_z80 --- error in signal NET_RFSH_n " & " at line number " &To_String(l_num) & " of the input data file " severity Error; If ( NET_RFSH_n /= Expected_data(31) ) then -- MCM if ( screw_up = none ) then -- MCM screw_up <= other; -- MCM else -- MCM screw_up <= mixed; -- MCM end if; -- MCM end if; -- MCM END IF; END; ------------------------------------------------------------------------------ begin U1 : z80_shell ------------------------------------------------------ port map ( NET_Addr(15), NET_Addr(14), NET_Addr(13), NET_Addr(12), NET_Addr(11), NET_Addr(10), NET_Addr(9), NET_Addr(8), NET_Addr(7), NET_Addr(6), NET_Addr(5), NET_Addr(4), NET_Addr(3), NET_Addr(2), NET_Addr(1), NET_Addr(0), NET_DATA(7), NET_DATA(6), NET_DATA(5), NET_DATA(4), NET_DATA(3), NET_DATA(2), NET_DATA(1), NET_DATA(0), NET_MREQ_n, NET_BUSACK_n, NET_BUSREQ_n, NET_HALT_n, NET_INT_n, NET_IORQ_n, NET_NMI_n, NET_RD_n, NET_RST_n, NET_WAIT_n, NET_WR_n, NET_RFSH_n, NET_M1_n, NET_CLK ); gen_clock : process -- This process runs the RZ clock begin -- which goes high at 25 nsec and wait for 25 ns; -- returns to low at 75 nsec NET_CLK <= '1'; -- within each 100 nsec clock period. wait for 50 ns; -- NET_CLK <= '0'; -- wait for 25 ns; -- end process; -- --------------------------------------------------------------------------------- Driver_Senser : process VARIABLE Monitor_Masks : Monitor_Masks_Table; VARIABLE Driver_Masks : Driver_Masks_Table; VARIABLE Data_Slices : std_logic_vector(1 TO 60); VARIABLE current_dmasks : std_logic_vector(1 TO 60); VARIABLE current_mmasks : std_logic_vector(1 TO 60); VARIABLE Driver : std_logic_vector(12 downto 0); VARIABLE Expected : std_logic_vector(31 DOWNTO 0); VARIABLE fc_count : INTEGER; VARIABLE line_num : Integer := 0; VARIABLE indx : INTEGER; begin assert false report " Commencing z80_tests " severity note; -- call procedure Build_Masks from z80_parser.pkg to build the monitor masks -- and data masks. Build_Masks(file_indata, line_num, Monitor_Masks, Driver_Masks); fc_count := 0; WHILE (NOT ENDFILE(file_indata)) LOOP IF rising_edge(NET_CLK) then -- call z80_tester to get current_driver_mask, current monitor_masks and -- Driver data and Expected data If (fc_count = 0) THEN z80_tester(file_indata, line_num, Monitor_Masks, Driver_Masks, fc_count, current_mmasks, current_dmasks, Driver, Expected); end if; wait for 25 ns; -- drive the z80. set the driver pins to the -- drivers from channels if driver mask is '1' else -- set to 'Z' indx := 0; -- apply the Driver for fc_count times fc_count := fc_count - 1; FOR i IN 17 TO 24 LOOP IF (current_dmasks(i) = '1') THEN -- drive NET_Data(indx) <= Driver(indx); ELSE NET_Data(indx) <= 'Z'; END IF; indx := indx + 1; END LOOP; IF (current_dmasks(33) = '1') THEN NET_INT_n <= Driver(8); ELSE NET_INT_n <= 'Z'; END IF; IF (current_dmasks(34) = '1') THEN NET_WAIT_n <= Driver(9); ELSE NET_WAIT_n <= 'Z'; END IF; IF (current_dmasks(35) = '1') THEN NET_BUSREQ_n <= Driver(10); ELSE NET_BUSREQ_n <= 'Z'; END IF; IF (current_dmasks(48) = '1') THEN NET_NMI_n <= Driver(11); ELSE NET_NMI_n <= 'Z'; END IF; IF (current_dmasks(57) = '1') THEN NET_RST_n <= Driver(12); ELSE NET_RST_n <= 'Z'; END IF; -- see the responses by calling procedure Response_z80 (line_num, current_mmasks, Expected, Screw_up, Wrong_bit ); END IF; wait on NET_CLK; END LOOP; wait; END process; end Testbench1; Configuration Z80_shell_Testbench1_cfg of Z80_testbench1 is for Testbench1 for U1 : Z80_shell use configuration work.Z80_shell_cfg; end for; end for; end Z80_shell_Testbench1_cfg;