Line 1... |
Line 1... |
--------------------------------------------------------------------------------
|
--------------------------------------------------------------------------------
|
-- mips_tb_pkg.vhdl -- Functions and data for the simulation test benches.
|
-- mips_tb_pkg.vhdl -- Functions and data for the simulation test benches.
|
--------------------------------------------------------------------------------
|
--------------------------------------------------------------------------------
|
-- Most of this file deals with the 'simulation log': the CPU execution history
|
-- Most of this file deals with the 'simulation log': the CPU execution history
|
-- is logged to a text file for easy comparison to a similaro log written by the
|
-- is logged to a text file for easy comparison to a similar log written by the
|
-- software simulator. This is meant as a debugging tool and is explained to
|
-- software simulator. This is meant as a debugging tool and is explained in
|
-- some detail in the project doc.
|
-- some detail in the project doc.
|
-- It is used as a verification tool at least while no better verification test
|
-- It is used as a verification tool at least while no other verification test
|
-- bench exists.
|
-- bench exists.
|
--------------------------------------------------------------------------------
|
--------------------------------------------------------------------------------
|
-- FIXME Console logging code should be here too
|
-- FIXME Console logging code should be here too
|
--------------------------------------------------------------------------------
|
--------------------------------------------------------------------------------
|
-- WARNING:
|
-- WARNING:
|
-- This package contains arguably the worst code of the project; in order
|
-- This package contains arguably the worst code of the project; in order
|
-- to expedite things, a number of trial-and-error hacks have been performed on
|
-- to expedite things, a number of trial-and-error hacks have been performed on
|
-- the code below. Mostly, the adjustment of the displayed PC.
|
-- the code below. Mostly, the adjustment of the displayed PC.
|
-- This is just the kind of hdl you don't want prospective employers to see :)
|
-- This is just the kind of hdl you don't want prospective employers to see :)
|
|
-- At least the synthesis tools never get to see it, it's simulation only.
|
--
|
--
|
-- The problem is: each change in the CPU state is logged in a text line, in
|
-- The problem is: each change in the CPU state is logged in a text line, in
|
-- which the address of the instruction that caused the change is included.
|
-- which the address of the instruction that caused the change is included.
|
-- From outside the CPU it is not always trivial to find out what instruction
|
-- From outside the CPU it is not always trivial to find out what instruction
|
-- caused what change (pipeline delays, cache stalls, etc.).
|
-- caused what change (pipeline delays, cache stalls, etc.).
|
-- I think the logging rules should be pretty stable now but I might have to
|
-- I think the logging rules should be pretty stable now but I might have to
|
-- tweak them again as the cache implementation changes. Eventually I aim to
|
-- tweak them again as the cache implementation changes. Eventually I aim to
|
-- make this code fully independent of the cache implementation; it should
|
-- make this code fully independent of the cache implementation; it should
|
-- only depend on the cpu. I will do this step by step, as I do all the rest.
|
-- only depend on the cpu. I will do this step by step, as I do all the rest.
|
--------------------------------------------------------------------------------
|
--------------------------------------------------------------------------------
|
|
-- NOTES (tagged in the code as @note1, etc.):
|
|
--
|
|
-- note1:
|
|
-- The multiplier LO/HI register change logging has been disabled (commented
|
|
-- out) until fixed (it fails in code sample 'adventure').
|
|
-- Please note it's the LOGGING that fails, not the instruction.
|
|
--
|
|
--------------------------------------------------------------------------------
|
|
|
library ieee,modelsim_lib;
|
library ieee,modelsim_lib;
|
use ieee.std_logic_1164.all;
|
use ieee.std_logic_1164.all;
|
use ieee.std_logic_arith.all;
|
use ieee.std_logic_arith.all;
|
use ieee.std_logic_unsigned.all;
|
use ieee.std_logic_unsigned.all;
|
Line 46... |
Line 55... |
rbank : t_rbank;
|
rbank : t_rbank;
|
prev_rbank : t_rbank;
|
prev_rbank : t_rbank;
|
|
|
cp0_epc : t_pc;
|
cp0_epc : t_pc;
|
prev_epc : t_pc;
|
prev_epc : t_pc;
|
|
cp0_status : std_logic_vector(5 downto 0);
|
|
cp0_cache_control : std_logic_vector(1 downto 0);
|
|
prev_status : t_word;
|
|
p1_set_cp0 : std_logic;
|
|
pc_mtc0 : t_word;
|
|
|
pc_m : t_pc_queue;
|
pc_m : t_pc_queue;
|
|
|
reg_hi, reg_lo : t_word;
|
reg_hi, reg_lo : t_word;
|
prev_hi, prev_lo : t_word;
|
prev_hi, prev_lo : t_word;
|
Line 114... |
Line 128... |
file l_file : TEXT) is
|
file l_file : TEXT) is
|
variable i : integer;
|
variable i : integer;
|
variable ri : std_logic_vector(7 downto 0);
|
variable ri : std_logic_vector(7 downto 0);
|
variable full_pc, temp, temp2 : t_word;
|
variable full_pc, temp, temp2 : t_word;
|
variable k : integer := 2;
|
variable k : integer := 2;
|
|
variable log_trap_status : boolean := false;
|
begin
|
begin
|
|
|
-- Trigger logging if the CPU fetches from trigger address
|
-- Trigger logging if the CPU fetches from trigger address
|
if (info.log_trigger_address(31 downto 2) = info.present_code_rd_addr) and
|
if (info.log_trigger_address(31 downto 2) = info.present_code_rd_addr) and
|
info.code_rd_vma='1' then
|
info.code_rd_vma='1' then
|
Line 179... |
Line 194... |
end if;
|
end if;
|
ri := ri + 1;
|
ri := ri + 1;
|
end loop;
|
end loop;
|
|
|
-- Log aux register changes ---------------------------------
|
-- Log aux register changes ---------------------------------
|
|
|
|
-- Mult/div module, register LO
|
if info.prev_lo /= info.reg_lo and info.prev_lo(0)/='U' then
|
if info.prev_lo /= info.reg_lo and info.prev_lo(0)/='U' then
|
-- Adjust opcode PC when LO came from the mul module
|
-- Adjust opcode PC when LO came from the mul module
|
if info.mdiv_pending then
|
if info.mdiv_pending then
|
temp2 := info.mdiv_address;
|
temp2 := info.mdiv_address;
|
info.mdiv_pending <= false;
|
info.mdiv_pending <= false;
|
Line 196... |
Line 213... |
if info.negate_reg_lo='1' then
|
if info.negate_reg_lo='1' then
|
-- negate reg_lo before displaying
|
-- negate reg_lo before displaying
|
temp := not info.reg_lo;
|
temp := not info.reg_lo;
|
temp := temp + 1;
|
temp := temp + 1;
|
if info.log_triggered then
|
if info.log_triggered then
|
print(l_file, "("& hstr(temp2)& ") [LO]="& hstr(temp));
|
-- FIXME removed temporarily until fixed (@note1)
|
|
--print(l_file, "("& hstr(temp2)& ") [LO]="& hstr(temp));
|
end if;
|
end if;
|
else
|
else
|
if info.log_triggered then
|
if info.log_triggered then
|
print(l_file, "("& hstr(temp2)& ") [LO]="& hstr(info.reg_lo));
|
-- FIXME removed temporarily until fixed (@note1)
|
|
--print(l_file, "("& hstr(temp2)& ") [LO]="& hstr(info.reg_lo));
|
end if;
|
end if;
|
end if;
|
end if;
|
end if;
|
end if;
|
|
|
|
-- Mult/div module, register HI
|
if info.prev_hi /= info.reg_hi and info.prev_hi(0)/='U' then
|
if info.prev_hi /= info.reg_hi and info.prev_hi(0)/='U' then
|
-- Adjust opcode PC when HI came from the mul module
|
-- Adjust opcode PC when HI came from the mul module
|
if info.mdiv_pending then
|
if info.mdiv_pending then
|
temp2 := info.mdiv_address;
|
temp2 := info.mdiv_address;
|
info.mdiv_pending <= false;
|
info.mdiv_pending <= false;
|
else
|
else
|
temp2 := info.pc_m(k-2);
|
temp2 := info.pc_m(k-2);
|
end if;
|
end if;
|
|
|
if info.log_triggered then
|
if info.log_triggered then
|
print(l_file, "("& hstr(temp2)& ") [HI]="& hstr(info.reg_hi));
|
-- FIXME removed temporarily until fixed (@note1)
|
|
--print(l_file, "("& hstr(temp2)& ") [HI]="& hstr(info.reg_hi));
|
end if;
|
end if;
|
end if;
|
end if;
|
|
|
|
-- CP0, register EPC
|
if info.prev_epc /= info.cp0_epc and info.cp0_epc(31)/='U' then
|
if info.prev_epc /= info.cp0_epc and info.cp0_epc(31)/='U' then
|
temp := info.cp0_epc & "00";
|
temp := info.cp0_epc & "00";
|
if info.log_triggered then
|
if info.log_triggered then
|
-- The instruction that caused the EP change is the last
|
-- The instruction that caused the EP change is the last
|
-- recorded trap/syscall exception.
|
-- recorded trap/syscall exception.
|
print(l_file, "("& hstr(info.exception_pc)& ") [EP]="& hstr(temp));
|
print(l_file, "("& hstr(info.exception_pc)& ") [EP]="& hstr(temp));
|
end if;
|
end if;
|
info.prev_epc <= info.cp0_epc;
|
info.prev_epc <= info.cp0_epc;
|
|
|
|
log_trap_status := true;
|
|
else
|
|
log_trap_status := false;
|
|
end if;
|
|
|
|
-- CP0, register SR
|
|
|
|
-- If SR changed by mtc0 instruction, get the mtc0 address
|
|
if info.p1_set_cp0='1' and info.cp0_status(1)='1' then
|
|
info.pc_mtc0 <= info.pc_m(k-1);
|
|
end if;
|
|
|
|
-- Build SR from separate CPU signals
|
|
temp := X"000" & "00" & info.cp0_cache_control &
|
|
X"00" & "00" & info.cp0_status;
|
|
if info.prev_status /= temp and info.cp0_status(0)/='U' then
|
|
if info.log_triggered then
|
|
if log_trap_status then
|
|
-- The instruction that caused the SR change is the last
|
|
-- recorded trap/syscall exception.
|
|
print(l_file, "("& hstr(info.exception_pc)& ") [SR]="& hstr(temp));
|
|
else
|
|
-- The instruction that caused the change is mtc0
|
|
print(l_file, "("& hstr(info.pc_mtc0)& ") [SR]="& hstr(temp));
|
|
end if;
|
|
end if;
|
|
info.prev_status <= temp;
|
end if;
|
end if;
|
|
|
|
|
-- Save present cycle info to compare the next cycle --------
|
-- Save present cycle info to compare the next cycle --------
|
info.prev_rbank <= info.rbank;
|
info.prev_rbank <= info.rbank;
|
info.prev_hi <= info.reg_hi;
|
info.prev_hi <= info.reg_hi;
|
info.prev_lo <= info.reg_lo;
|
info.prev_lo <= info.reg_lo;
|
|
|
--info.pc_m(3) <= info.pc_m(2);
|
|
--info.pc_m(2) <= info.pc_m(1);
|
|
--info.pc_m(1) <= info.pc_m(0);
|
|
--info.pc_m(0) <= info.present_code_rd_addr & "00";
|
|
|
|
end if;
|
end if;
|
|
|
-- Update instruction address table only at the 1st cycle of each
|
-- Update instruction address table only at the 1st cycle of each
|
-- instruction.
|
-- instruction.
|
if info.code_rd_vma='1' then
|
if info.code_rd_vma='1' then
|
Line 304... |
Line 350... |
init_signal_spy("/"&entity_name&"/mult_div/upper_reg", signal_name&".reg_hi", 0, -1);
|
init_signal_spy("/"&entity_name&"/mult_div/upper_reg", signal_name&".reg_hi", 0, -1);
|
init_signal_spy("/"&entity_name&"/mult_div/lower_reg", signal_name&".reg_lo", 0, -1);
|
init_signal_spy("/"&entity_name&"/mult_div/lower_reg", signal_name&".reg_lo", 0, -1);
|
init_signal_spy("/"&entity_name&"/mult_div/negate_reg", signal_name&".negate_reg_lo", 0, -1);
|
init_signal_spy("/"&entity_name&"/mult_div/negate_reg", signal_name&".negate_reg_lo", 0, -1);
|
init_signal_spy("/"&entity_name&"/mult_div/count_reg", signal_name&".mdiv_count_reg", 0, -1);
|
init_signal_spy("/"&entity_name&"/mult_div/count_reg", signal_name&".mdiv_count_reg", 0, -1);
|
init_signal_spy("/"&entity_name&"/cp0_epc", signal_name&".cp0_epc", 0, -1);
|
init_signal_spy("/"&entity_name&"/cp0_epc", signal_name&".cp0_epc", 0, -1);
|
|
init_signal_spy("/"&entity_name&"/cp0_status", signal_name&".cp0_status", 0, -1);
|
|
init_signal_spy("/"&entity_name&"/p1_set_cp0", signal_name&".p1_set_cp0", 0, -1);
|
|
init_signal_spy("/"&entity_name&"/cp0_cache_control", signal_name&".cp0_cache_control", 0, -1);
|
init_signal_spy("/"&entity_name&"/data_rd_vma", signal_name&".data_rd_vma", 0, -1);
|
init_signal_spy("/"&entity_name&"/data_rd_vma", signal_name&".data_rd_vma", 0, -1);
|
init_signal_spy("/"&entity_name&"/p1_rbank_we", signal_name&".p1_rbank_we", 0, -1);
|
init_signal_spy("/"&entity_name&"/p1_rbank_we", signal_name&".p1_rbank_we", 0, -1);
|
init_signal_spy("/"&entity_name&"/code_rd_vma", signal_name&".code_rd_vma", 0, -1);
|
init_signal_spy("/"&entity_name&"/code_rd_vma", signal_name&".code_rd_vma", 0, -1);
|
init_signal_spy("/"&entity_name&"/p2_do_load", signal_name&".load", 0, -1);
|
init_signal_spy("/"&entity_name&"/p2_do_load", signal_name&".load", 0, -1);
|
init_signal_spy("/"&entity_name&"/data_addr", signal_name&".present_data_wr_addr", 0, -1);
|
init_signal_spy("/"&entity_name&"/data_addr", signal_name&".present_data_wr_addr", 0, -1);
|