OpenCores
URL https://opencores.org/ocsvn/ion/ion/trunk

Subversion Repositories ion

[/] [ion/] [trunk/] [vhdl/] [tb/] [mips_tb_pkg.vhdl] - Blame information for rev 164

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 60 ja_rd
--------------------------------------------------------------------------------
2
-- mips_tb_pkg.vhdl -- Functions and data for the simulation test benches.
3
--------------------------------------------------------------------------------
4
-- Most of this file deals with the 'simulation log': the CPU execution history
5 152 ja_rd
-- is logged to a text file for easy comparison to a similar log written by the
6
-- software simulator. This is meant as a debugging tool and is explained in
7 60 ja_rd
-- some detail in the project doc.
8 152 ja_rd
-- It is used as a verification tool at least while no other verification test
9 60 ja_rd
-- bench exists.
10
--------------------------------------------------------------------------------
11
-- FIXME Console logging code should be here too
12
--------------------------------------------------------------------------------
13
-- WARNING: 
14
-- This package contains arguably the worst code of the project; in order
15
-- to expedite things, a number of trial-and-error hacks have been performed on
16
-- the code below. Mostly, the adjustment of the displayed PC.
17
-- This is just the kind of hdl you don't want prospective employers to see :)
18 152 ja_rd
-- At least the synthesis tools never get to see it, it's simulation only.
19 60 ja_rd
-- 
20
-- The problem is: each change in the CPU state is logged in a text line, in 
21
-- which the address of the instruction that caused the change is included. 
22
-- From outside the CPU it is not always trivial to find out what instruction
23
-- caused what change (pipeline delays, cache stalls, etc.). 
24
-- I think the logging rules should be pretty stable now but I might have to
25
-- tweak them again as the cache implementation changes. Eventually I aim to
26
-- make this code fully independent of the cache implementation; it should
27
-- only depend on the cpu. I will do this step by step, as I do all the rest.
28
--------------------------------------------------------------------------------
29 152 ja_rd
-- NOTES (tagged in the code as @note1, etc.):
30
--
31
-- note1:
32
-- The multiplier LO/HI register change logging has been disabled (commented
33
-- out) until fixed (it fails in code sample 'adventure').
34
-- Please note it's the LOGGING that fails, not the instruction.
35
--
36
--------------------------------------------------------------------------------
37 60 ja_rd
 
38
library ieee,modelsim_lib;
39
use ieee.std_logic_1164.all;
40
use ieee.std_logic_arith.all;
41
use ieee.std_logic_unsigned.all;
42
 
43
use work.mips_pkg.all;
44
 
45
use modelsim_lib.util.all;
46
use std.textio.all;
47
use work.txt_util.all;
48
 
49
 
50
package mips_tb_pkg is
51
 
52
type t_pc_queue is array(0 to 3) of t_word;
53
 
54
type t_log_info is record
55
    rbank :                 t_rbank;
56
    prev_rbank :            t_rbank;
57
 
58
    cp0_epc :               t_pc;
59
    prev_epc :              t_pc;
60 152 ja_rd
    cp0_status :            std_logic_vector(5 downto 0);
61
    cp0_cache_control :     std_logic_vector(1 downto 0);
62
    prev_status :           t_word;
63
    p1_set_cp0 :            std_logic;
64 157 ja_rd
    p1_rfe :                std_logic;
65 152 ja_rd
    pc_mtc0 :               t_word;
66 60 ja_rd
 
67
    pc_m :                  t_pc_queue;
68
 
69
    reg_hi, reg_lo :        t_word;
70
    prev_hi, prev_lo :      t_word;
71
    negate_reg_lo :         std_logic;
72
    mdiv_count_reg :        std_logic_vector(5 downto 0);
73
    prev_count_reg :        std_logic_vector(5 downto 0);
74
 
75
    data_rd_vma :           std_logic;
76 112 ja_rd
    p1_rbank_we :           std_logic;
77 60 ja_rd
    code_rd_vma :           std_logic;
78
    data_byte_we :          std_logic_vector(3 downto 0);
79
 
80 96 ja_rd
    present_data_wr_addr :  t_word;
81 60 ja_rd
    present_data_wr :       t_word;
82
    present_data_rd_addr :  t_word;
83
    present_code_rd_addr :  t_pc;
84
 
85
    pending_data_rd_addr :  t_word;
86
    pending_data_wr_addr :  t_word;
87
    pending_data_wr_pc :    t_word;
88
    pending_data_wr :       t_word;
89
    pending_data_wr_we :    std_logic_vector(3 downto 0);
90
 
91
    word_loaded :           t_word;
92
 
93
    mdiv_address :          t_word;
94
    mdiv_pending :          boolean;
95
 
96 112 ja_rd
    exception :             std_logic;
97
    exception_pc :          t_word;
98
 
99 60 ja_rd
    data_rd_address :       t_word;
100
    load :                  std_logic;
101
 
102
    read_pending :          boolean;
103
    write_pending :         boolean;
104 112 ja_rd
    debug :                 t_word;
105 84 ja_rd
 
106
    -- Log trigger --------------------------------------------------
107
    -- Enable logging after fetching from a given address -----------
108
    log_trigger_address :   t_word;
109
    log_triggered :         boolean;
110 60 ja_rd
end record t_log_info;
111
 
112
procedure log_cpu_activity(
113
                signal clk :    in std_logic;
114
                signal reset :  in std_logic;
115
                signal done :   in std_logic;
116
                entity_name :   string;
117
                signal info :   inout t_log_info;
118
                signal_name :   string;
119 84 ja_rd
                trigger_addr :  in t_word;
120 60 ja_rd
                file l_file :   TEXT);
121
 
122
 
123
end package;
124
 
125
package body mips_tb_pkg is
126
 
127
procedure log_cpu_status(
128 84 ja_rd
                signal info :   inout t_log_info;
129 60 ja_rd
                file l_file :   TEXT) is
130
variable i : integer;
131
variable ri : std_logic_vector(7 downto 0);
132
variable full_pc, temp, temp2 : t_word;
133
variable k : integer := 2;
134 152 ja_rd
variable log_trap_status : boolean := false;
135 60 ja_rd
begin
136
 
137 84 ja_rd
    -- Trigger logging if the CPU fetches from trigger address
138
    if (info.log_trigger_address(31 downto 2) = info.present_code_rd_addr) and
139
       info.code_rd_vma='1' then
140
        info.log_triggered <= true;
141
 
142
        assert 1=0
143
        report "Log triggered by fetch from address 0x"& hstr(info.log_trigger_address)
144
        severity note;
145
    end if;
146
 
147 60 ja_rd
    -- This is the address of the opcode that triggered the changed we're
148
    -- about to log
149
    full_pc := info.pc_m(k);
150
 
151 112 ja_rd
    -- Log memory writes ----------------------------------------
152
    if info.write_pending then
153
        if conv_integer(info.pending_data_wr_pc) <= conv_integer(full_pc) then
154 60 ja_rd
 
155
            ri := X"0" & info.pending_data_wr_we;
156
            temp := info.pending_data_wr;
157
            if info.pending_data_wr_we(3)='0' then
158
                temp := temp and X"00ffffff";
159
            end if;
160
            if info.pending_data_wr_we(2)='0' then
161
                temp := temp and X"ff00ffff";
162
            end if;
163
            if info.pending_data_wr_we(1)='0' then
164
                temp := temp and X"ffff00ff";
165
            end if;
166
            if info.pending_data_wr_we(0)='0' then
167
                temp := temp and X"ffffff00";
168
            end if;
169 84 ja_rd
            if info.log_triggered then
170
                print(l_file, "("& hstr(info.pending_data_wr_pc) &") ["&
171
                    hstr(info.pending_data_wr_addr) &"] |"&
172
                    hstr(ri)& "|="&
173
                    hstr(temp)& " WR" );
174
            end if;
175 112 ja_rd
            info.debug <= info.pending_data_wr_pc;
176 60 ja_rd
            info.write_pending <= false;
177 112 ja_rd
        end if;
178
    end if;
179 60 ja_rd
 
180 112 ja_rd
    -- Log register bank activity.
181
    -- NOTE: in previous versions we used to do this only at the 1st cycle of
182
    --- instructions, mistakenly. Reg changes need to be logged as soon as 
183
    -- they happen.
184
    if true then --info.code_rd_vma='1' then
185
 
186
        -- Log register changes -------------------------------------
187
        ri := X"00";
188
        for i in 0 to 31 loop
189
            if info.prev_rbank(i)/=info.rbank(i)
190
               and info.prev_rbank(i)(0)/='U' then
191
                if info.log_triggered then
192
                    print(l_file, "("& hstr(info.pc_m(k-0))& ") "&
193
                        "["& hstr(ri)& "]="& hstr(info.rbank(i)));
194
                end if;
195 84 ja_rd
            end if;
196 112 ja_rd
            ri := ri + 1;
197
        end loop;
198 60 ja_rd
 
199
        -- Log aux register changes ---------------------------------
200 152 ja_rd
 
201
        -- Mult/div module, register LO
202 60 ja_rd
        if info.prev_lo /= info.reg_lo and info.prev_lo(0)/='U' then
203
            -- Adjust opcode PC when LO came from the mul module
204
            if info.mdiv_pending then
205
                temp2 := info.mdiv_address;
206
                info.mdiv_pending <= false;
207
            else
208 112 ja_rd
                temp2 := info.pc_m(k-2);
209 60 ja_rd
            end if;
210
 
211
            -- we're observing the value of reg_lo, but the mult core
212
            -- will output the negated value in some cases. We
213
            -- have to mimic that behavior.
214
            if info.negate_reg_lo='1' then
215
                -- negate reg_lo before displaying
216
                temp := not info.reg_lo;
217
                temp := temp + 1;
218 84 ja_rd
                if info.log_triggered then
219 152 ja_rd
                    -- FIXME removed temporarily until fixed (@note1)
220
                    --print(l_file, "("& hstr(temp2)& ") [LO]="& hstr(temp));
221 84 ja_rd
                end if;
222 60 ja_rd
            else
223 84 ja_rd
                if info.log_triggered then
224 152 ja_rd
                    -- FIXME removed temporarily until fixed (@note1)
225
                    --print(l_file, "("& hstr(temp2)& ") [LO]="& hstr(info.reg_lo));
226 84 ja_rd
                end if;
227 60 ja_rd
            end if;
228
        end if;
229 152 ja_rd
 
230
        -- Mult/div module, register HI
231 60 ja_rd
        if info.prev_hi /= info.reg_hi and info.prev_hi(0)/='U' then
232
            -- Adjust opcode PC when HI came from the mul module
233
            if info.mdiv_pending then
234
                temp2 := info.mdiv_address;
235
                info.mdiv_pending <= false;
236
            else
237 112 ja_rd
                temp2 := info.pc_m(k-2);
238 60 ja_rd
            end if;
239 84 ja_rd
 
240
            if info.log_triggered then
241 152 ja_rd
                -- FIXME removed temporarily until fixed (@note1)
242
                --print(l_file, "("& hstr(temp2)& ") [HI]="& hstr(info.reg_hi));
243 84 ja_rd
            end if;
244 60 ja_rd
        end if;
245 152 ja_rd
 
246
        -- CP0, register EPC
247 60 ja_rd
        if info.prev_epc /= info.cp0_epc and info.cp0_epc(31)/='U'  then
248
            temp := info.cp0_epc & "00";
249 84 ja_rd
            if info.log_triggered then
250 112 ja_rd
                -- The instruction that caused the EP change is the last 
251
                -- recorded trap/syscall exception.
252
                print(l_file, "("& hstr(info.exception_pc)& ") [EP]="& hstr(temp));
253 84 ja_rd
            end if;
254 60 ja_rd
            info.prev_epc <= info.cp0_epc;
255 152 ja_rd
 
256
            log_trap_status := true;
257
        else
258
            log_trap_status := false;
259 60 ja_rd
        end if;
260
 
261 152 ja_rd
        -- CP0, register SR
262
 
263
        -- If SR changed by mtc0 instruction, get the mtc0 address
264 157 ja_rd
        if (info.p1_set_cp0='1' or info.p1_rfe='1') and info.cp0_status(1)='1' then
265 152 ja_rd
            info.pc_mtc0 <= info.pc_m(k-1);
266
        end if;
267
 
268
        -- Build SR from separate CPU signals
269
        temp := X"000" & "00" & info.cp0_cache_control &
270
                X"00" & "00" & info.cp0_status;
271
        if info.prev_status /= temp and info.cp0_status(0)/='U' then
272
            if info.log_triggered then
273
                if log_trap_status then
274
                    -- The instruction that caused the SR change is the last 
275
                    -- recorded trap/syscall exception.
276
                    print(l_file, "("& hstr(info.exception_pc)& ") [SR]="& hstr(temp));
277
                else
278
                    -- The instruction that caused the change is mtc0
279
                    print(l_file, "("& hstr(info.pc_mtc0)& ") [SR]="& hstr(temp));
280
                end if;
281
            end if;
282
            info.prev_status <= temp;
283
        end if;
284 112 ja_rd
 
285 152 ja_rd
 
286 60 ja_rd
        -- Save present cycle info to compare the next cycle --------
287
        info.prev_rbank <= info.rbank;
288
        info.prev_hi <= info.reg_hi;
289
        info.prev_lo <= info.reg_lo;
290 152 ja_rd
 
291 112 ja_rd
    end if;
292
 
293
    -- Update instruction address table only at the 1st cycle of each 
294
    -- instruction.
295
    if info.code_rd_vma='1' then
296 60 ja_rd
        info.pc_m(3) <= info.pc_m(2);
297
        info.pc_m(2) <= info.pc_m(1);
298
        info.pc_m(1) <= info.pc_m(0);
299
        info.pc_m(0) <= info.present_code_rd_addr & "00";
300
    end if;
301
 
302 112 ja_rd
    -- Log memory reads ------------------------------------------
303
    if info.read_pending and info.load='1' and info.p1_rbank_we='1' then
304
        if info.log_triggered then
305
            print(l_file, "("& hstr(info.pc_m(1)) &") ["&
306
                  hstr(info.pending_data_rd_addr) &"] <"&
307
                  "**"& ">="&
308
                  hstr(info.word_loaded)& " RD" );
309
        end if;
310
        info.read_pending <= false;
311
    end if;
312
 
313
    if info.exception='1' then
314
        info.exception_pc <= info.pc_m(1);
315
    end if;
316
 
317 60 ja_rd
    if info.data_byte_we/="0000" then
318
        info.write_pending <= true;
319
        info.pending_data_wr_we <= info.data_byte_we;
320 96 ja_rd
        info.pending_data_wr_addr <= info.present_data_wr_addr;
321 60 ja_rd
        info.pending_data_wr_pc <= info.pc_m(k-1);
322
        info.pending_data_wr <= info.present_data_wr;
323
    end if;
324
 
325
    if info.data_rd_vma='1' then
326
        info.read_pending <= true;
327
        info.pending_data_rd_addr <= info.present_data_rd_addr;
328
    end if;
329
 
330
    if info.mdiv_count_reg="100000" then
331
        info.mdiv_address <= info.pc_m(1);
332
        info.mdiv_pending <= true;
333
    end if;
334
 
335
    info.prev_count_reg <= info.mdiv_count_reg;
336
 
337
end procedure log_cpu_status;
338
 
339
procedure log_cpu_activity(
340
                signal clk :    in std_logic;
341
                signal reset :  in std_logic;
342
                signal done :   in std_logic;
343
                entity_name :   string;
344
                signal info :   inout t_log_info;
345
                signal_name :   string;
346 84 ja_rd
                trigger_addr :  in t_word;
347 60 ja_rd
                file l_file :   TEXT) is
348
begin
349
    init_signal_spy("/"&entity_name&"/p1_rbank", signal_name&".rbank", 0, -1);
350
    init_signal_spy("/"&entity_name&"/code_rd_addr", signal_name&".present_code_rd_addr", 0, -1);
351
    init_signal_spy("/"&entity_name&"/mult_div/upper_reg", signal_name&".reg_hi", 0, -1);
352
    init_signal_spy("/"&entity_name&"/mult_div/lower_reg", signal_name&".reg_lo", 0, -1);
353
    init_signal_spy("/"&entity_name&"/mult_div/negate_reg", signal_name&".negate_reg_lo", 0, -1);
354
    init_signal_spy("/"&entity_name&"/mult_div/count_reg", signal_name&".mdiv_count_reg", 0, -1);
355
    init_signal_spy("/"&entity_name&"/cp0_epc", signal_name&".cp0_epc", 0, -1);
356 152 ja_rd
    init_signal_spy("/"&entity_name&"/cp0_status", signal_name&".cp0_status", 0, -1);
357
    init_signal_spy("/"&entity_name&"/p1_set_cp0", signal_name&".p1_set_cp0", 0, -1);
358 157 ja_rd
    init_signal_spy("/"&entity_name&"/p1_rfe", signal_name&".p1_rfe", 0, -1);
359 152 ja_rd
    init_signal_spy("/"&entity_name&"/cp0_cache_control", signal_name&".cp0_cache_control", 0, -1);
360 60 ja_rd
    init_signal_spy("/"&entity_name&"/data_rd_vma", signal_name&".data_rd_vma", 0, -1);
361 112 ja_rd
    init_signal_spy("/"&entity_name&"/p1_rbank_we", signal_name&".p1_rbank_we", 0, -1);
362 60 ja_rd
    init_signal_spy("/"&entity_name&"/code_rd_vma", signal_name&".code_rd_vma", 0, -1);
363
    init_signal_spy("/"&entity_name&"/p2_do_load", signal_name&".load", 0, -1);
364 96 ja_rd
    init_signal_spy("/"&entity_name&"/data_addr", signal_name&".present_data_wr_addr", 0, -1);
365 60 ja_rd
    init_signal_spy("/"&entity_name&"/data_wr", signal_name&".present_data_wr", 0, -1);
366
    init_signal_spy("/"&entity_name&"/byte_we", signal_name&".data_byte_we", 0, -1);
367
    init_signal_spy("/"&entity_name&"/p2_data_word_rd", signal_name&".word_loaded", 0, -1);
368 96 ja_rd
    init_signal_spy("/"&entity_name&"/data_addr", signal_name&".present_data_rd_addr", 0, -1);
369 112 ja_rd
    init_signal_spy("/"&entity_name&"/p1_exception", signal_name&".exception", 0, -1);
370 60 ja_rd
 
371
    while done='0' loop
372
        wait until clk'event and clk='1';
373
        if reset='1' then
374
            -- FIXME should use real reset vector here
375
            info.pc_m <= (others => X"00000000");
376 84 ja_rd
 
377
            -- By default logging is DISABLED by triggering with an impossible
378
            -- fetch address. Logging must be enabled from outside by 
379
            -- setting log_trigger_address to a suitable value.
380
            info.log_trigger_address <= trigger_addr;
381
            info.log_triggered <= false;
382 112 ja_rd
            info.debug <= (others => '0');
383 60 ja_rd
        else
384
            log_cpu_status(info, l_file);
385
        end if;
386
    end loop;
387
 
388
 
389
end procedure log_cpu_activity;
390
 
391
 
392
 
393
end package body;

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.