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

Subversion Repositories ion

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

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
    pc_mtc0 :               t_word;
65 60 ja_rd
 
66
    pc_m :                  t_pc_queue;
67
 
68
    reg_hi, reg_lo :        t_word;
69
    prev_hi, prev_lo :      t_word;
70
    negate_reg_lo :         std_logic;
71
    mdiv_count_reg :        std_logic_vector(5 downto 0);
72
    prev_count_reg :        std_logic_vector(5 downto 0);
73
 
74
    data_rd_vma :           std_logic;
75 112 ja_rd
    p1_rbank_we :           std_logic;
76 60 ja_rd
    code_rd_vma :           std_logic;
77
    data_byte_we :          std_logic_vector(3 downto 0);
78
 
79 96 ja_rd
    present_data_wr_addr :  t_word;
80 60 ja_rd
    present_data_wr :       t_word;
81
    present_data_rd_addr :  t_word;
82
    present_code_rd_addr :  t_pc;
83
 
84
    pending_data_rd_addr :  t_word;
85
    pending_data_wr_addr :  t_word;
86
    pending_data_wr_pc :    t_word;
87
    pending_data_wr :       t_word;
88
    pending_data_wr_we :    std_logic_vector(3 downto 0);
89
 
90
    word_loaded :           t_word;
91
 
92
    mdiv_address :          t_word;
93
    mdiv_pending :          boolean;
94
 
95 112 ja_rd
    exception :             std_logic;
96
    exception_pc :          t_word;
97
 
98 60 ja_rd
    data_rd_address :       t_word;
99
    load :                  std_logic;
100
 
101
    read_pending :          boolean;
102
    write_pending :         boolean;
103 112 ja_rd
    debug :                 t_word;
104 84 ja_rd
 
105
    -- Log trigger --------------------------------------------------
106
    -- Enable logging after fetching from a given address -----------
107
    log_trigger_address :   t_word;
108
    log_triggered :         boolean;
109 60 ja_rd
end record t_log_info;
110
 
111
procedure log_cpu_activity(
112
                signal clk :    in std_logic;
113
                signal reset :  in std_logic;
114
                signal done :   in std_logic;
115
                entity_name :   string;
116
                signal info :   inout t_log_info;
117
                signal_name :   string;
118 84 ja_rd
                trigger_addr :  in t_word;
119 60 ja_rd
                file l_file :   TEXT);
120
 
121
 
122
end package;
123
 
124
package body mips_tb_pkg is
125
 
126
procedure log_cpu_status(
127 84 ja_rd
                signal info :   inout t_log_info;
128 60 ja_rd
                file l_file :   TEXT) is
129
variable i : integer;
130
variable ri : std_logic_vector(7 downto 0);
131
variable full_pc, temp, temp2 : t_word;
132
variable k : integer := 2;
133 152 ja_rd
variable log_trap_status : boolean := false;
134 60 ja_rd
begin
135
 
136 84 ja_rd
    -- Trigger logging if the CPU fetches from trigger address
137
    if (info.log_trigger_address(31 downto 2) = info.present_code_rd_addr) and
138
       info.code_rd_vma='1' then
139
        info.log_triggered <= true;
140
 
141
        assert 1=0
142
        report "Log triggered by fetch from address 0x"& hstr(info.log_trigger_address)
143
        severity note;
144
    end if;
145
 
146 60 ja_rd
    -- This is the address of the opcode that triggered the changed we're
147
    -- about to log
148
    full_pc := info.pc_m(k);
149
 
150 112 ja_rd
    -- Log memory writes ----------------------------------------
151
    if info.write_pending then
152
        if conv_integer(info.pending_data_wr_pc) <= conv_integer(full_pc) then
153 60 ja_rd
 
154
            ri := X"0" & info.pending_data_wr_we;
155
            temp := info.pending_data_wr;
156
            if info.pending_data_wr_we(3)='0' then
157
                temp := temp and X"00ffffff";
158
            end if;
159
            if info.pending_data_wr_we(2)='0' then
160
                temp := temp and X"ff00ffff";
161
            end if;
162
            if info.pending_data_wr_we(1)='0' then
163
                temp := temp and X"ffff00ff";
164
            end if;
165
            if info.pending_data_wr_we(0)='0' then
166
                temp := temp and X"ffffff00";
167
            end if;
168 84 ja_rd
            if info.log_triggered then
169
                print(l_file, "("& hstr(info.pending_data_wr_pc) &") ["&
170
                    hstr(info.pending_data_wr_addr) &"] |"&
171
                    hstr(ri)& "|="&
172
                    hstr(temp)& " WR" );
173
            end if;
174 112 ja_rd
            info.debug <= info.pending_data_wr_pc;
175 60 ja_rd
            info.write_pending <= false;
176 112 ja_rd
        end if;
177
    end if;
178 60 ja_rd
 
179 112 ja_rd
    -- Log register bank activity.
180
    -- NOTE: in previous versions we used to do this only at the 1st cycle of
181
    --- instructions, mistakenly. Reg changes need to be logged as soon as 
182
    -- they happen.
183
    if true then --info.code_rd_vma='1' then
184
 
185
        -- Log register changes -------------------------------------
186
        ri := X"00";
187
        for i in 0 to 31 loop
188
            if info.prev_rbank(i)/=info.rbank(i)
189
               and info.prev_rbank(i)(0)/='U' then
190
                if info.log_triggered then
191
                    print(l_file, "("& hstr(info.pc_m(k-0))& ") "&
192
                        "["& hstr(ri)& "]="& hstr(info.rbank(i)));
193
                end if;
194 84 ja_rd
            end if;
195 112 ja_rd
            ri := ri + 1;
196
        end loop;
197 60 ja_rd
 
198
        -- Log aux register changes ---------------------------------
199 152 ja_rd
 
200
        -- Mult/div module, register LO
201 60 ja_rd
        if info.prev_lo /= info.reg_lo and info.prev_lo(0)/='U' then
202
            -- Adjust opcode PC when LO came from the mul module
203
            if info.mdiv_pending then
204
                temp2 := info.mdiv_address;
205
                info.mdiv_pending <= false;
206
            else
207 112 ja_rd
                temp2 := info.pc_m(k-2);
208 60 ja_rd
            end if;
209
 
210
            -- we're observing the value of reg_lo, but the mult core
211
            -- will output the negated value in some cases. We
212
            -- have to mimic that behavior.
213
            if info.negate_reg_lo='1' then
214
                -- negate reg_lo before displaying
215
                temp := not info.reg_lo;
216
                temp := temp + 1;
217 84 ja_rd
                if info.log_triggered then
218 152 ja_rd
                    -- FIXME removed temporarily until fixed (@note1)
219
                    --print(l_file, "("& hstr(temp2)& ") [LO]="& hstr(temp));
220 84 ja_rd
                end if;
221 60 ja_rd
            else
222 84 ja_rd
                if info.log_triggered then
223 152 ja_rd
                    -- FIXME removed temporarily until fixed (@note1)
224
                    --print(l_file, "("& hstr(temp2)& ") [LO]="& hstr(info.reg_lo));
225 84 ja_rd
                end if;
226 60 ja_rd
            end if;
227
        end if;
228 152 ja_rd
 
229
        -- Mult/div module, register HI
230 60 ja_rd
        if info.prev_hi /= info.reg_hi and info.prev_hi(0)/='U' then
231
            -- Adjust opcode PC when HI came from the mul module
232
            if info.mdiv_pending then
233
                temp2 := info.mdiv_address;
234
                info.mdiv_pending <= false;
235
            else
236 112 ja_rd
                temp2 := info.pc_m(k-2);
237 60 ja_rd
            end if;
238 84 ja_rd
 
239
            if info.log_triggered then
240 152 ja_rd
                -- FIXME removed temporarily until fixed (@note1)
241
                --print(l_file, "("& hstr(temp2)& ") [HI]="& hstr(info.reg_hi));
242 84 ja_rd
            end if;
243 60 ja_rd
        end if;
244 152 ja_rd
 
245
        -- CP0, register EPC
246 60 ja_rd
        if info.prev_epc /= info.cp0_epc and info.cp0_epc(31)/='U'  then
247
            temp := info.cp0_epc & "00";
248 84 ja_rd
            if info.log_triggered then
249 112 ja_rd
                -- The instruction that caused the EP change is the last 
250
                -- recorded trap/syscall exception.
251
                print(l_file, "("& hstr(info.exception_pc)& ") [EP]="& hstr(temp));
252 84 ja_rd
            end if;
253 60 ja_rd
            info.prev_epc <= info.cp0_epc;
254 152 ja_rd
 
255
            log_trap_status := true;
256
        else
257
            log_trap_status := false;
258 60 ja_rd
        end if;
259
 
260 152 ja_rd
        -- CP0, register SR
261
 
262
        -- If SR changed by mtc0 instruction, get the mtc0 address
263
        if info.p1_set_cp0='1' and info.cp0_status(1)='1' then
264
            info.pc_mtc0 <= info.pc_m(k-1);
265
        end if;
266
 
267
        -- Build SR from separate CPU signals
268
        temp := X"000" & "00" & info.cp0_cache_control &
269
                X"00" & "00" & info.cp0_status;
270
        if info.prev_status /= temp and info.cp0_status(0)/='U' then
271
            if info.log_triggered then
272
                if log_trap_status then
273
                    -- The instruction that caused the SR change is the last 
274
                    -- recorded trap/syscall exception.
275
                    print(l_file, "("& hstr(info.exception_pc)& ") [SR]="& hstr(temp));
276
                else
277
                    -- The instruction that caused the change is mtc0
278
                    print(l_file, "("& hstr(info.pc_mtc0)& ") [SR]="& hstr(temp));
279
                end if;
280
            end if;
281
            info.prev_status <= temp;
282
        end if;
283 112 ja_rd
 
284 152 ja_rd
 
285 60 ja_rd
        -- Save present cycle info to compare the next cycle --------
286
        info.prev_rbank <= info.rbank;
287
        info.prev_hi <= info.reg_hi;
288
        info.prev_lo <= info.reg_lo;
289 152 ja_rd
 
290 112 ja_rd
    end if;
291
 
292
    -- Update instruction address table only at the 1st cycle of each 
293
    -- instruction.
294
    if info.code_rd_vma='1' then
295 60 ja_rd
        info.pc_m(3) <= info.pc_m(2);
296
        info.pc_m(2) <= info.pc_m(1);
297
        info.pc_m(1) <= info.pc_m(0);
298
        info.pc_m(0) <= info.present_code_rd_addr & "00";
299
    end if;
300
 
301 112 ja_rd
    -- Log memory reads ------------------------------------------
302
    if info.read_pending and info.load='1' and info.p1_rbank_we='1' then
303
        if info.log_triggered then
304
            print(l_file, "("& hstr(info.pc_m(1)) &") ["&
305
                  hstr(info.pending_data_rd_addr) &"] <"&
306
                  "**"& ">="&
307
                  hstr(info.word_loaded)& " RD" );
308
        end if;
309
        info.read_pending <= false;
310
    end if;
311
 
312
    if info.exception='1' then
313
        info.exception_pc <= info.pc_m(1);
314
    end if;
315
 
316 60 ja_rd
    if info.data_byte_we/="0000" then
317
        info.write_pending <= true;
318
        info.pending_data_wr_we <= info.data_byte_we;
319 96 ja_rd
        info.pending_data_wr_addr <= info.present_data_wr_addr;
320 60 ja_rd
        info.pending_data_wr_pc <= info.pc_m(k-1);
321
        info.pending_data_wr <= info.present_data_wr;
322
    end if;
323
 
324
    if info.data_rd_vma='1' then
325
        info.read_pending <= true;
326
        info.pending_data_rd_addr <= info.present_data_rd_addr;
327
    end if;
328
 
329
    if info.mdiv_count_reg="100000" then
330
        info.mdiv_address <= info.pc_m(1);
331
        info.mdiv_pending <= true;
332
    end if;
333
 
334
    info.prev_count_reg <= info.mdiv_count_reg;
335
 
336
end procedure log_cpu_status;
337
 
338
procedure log_cpu_activity(
339
                signal clk :    in std_logic;
340
                signal reset :  in std_logic;
341
                signal done :   in std_logic;
342
                entity_name :   string;
343
                signal info :   inout t_log_info;
344
                signal_name :   string;
345 84 ja_rd
                trigger_addr :  in t_word;
346 60 ja_rd
                file l_file :   TEXT) is
347
begin
348
    init_signal_spy("/"&entity_name&"/p1_rbank", signal_name&".rbank", 0, -1);
349
    init_signal_spy("/"&entity_name&"/code_rd_addr", signal_name&".present_code_rd_addr", 0, -1);
350
    init_signal_spy("/"&entity_name&"/mult_div/upper_reg", signal_name&".reg_hi", 0, -1);
351
    init_signal_spy("/"&entity_name&"/mult_div/lower_reg", signal_name&".reg_lo", 0, -1);
352
    init_signal_spy("/"&entity_name&"/mult_div/negate_reg", signal_name&".negate_reg_lo", 0, -1);
353
    init_signal_spy("/"&entity_name&"/mult_div/count_reg", signal_name&".mdiv_count_reg", 0, -1);
354
    init_signal_spy("/"&entity_name&"/cp0_epc", signal_name&".cp0_epc", 0, -1);
355 152 ja_rd
    init_signal_spy("/"&entity_name&"/cp0_status", signal_name&".cp0_status", 0, -1);
356
    init_signal_spy("/"&entity_name&"/p1_set_cp0", signal_name&".p1_set_cp0", 0, -1);
357
    init_signal_spy("/"&entity_name&"/cp0_cache_control", signal_name&".cp0_cache_control", 0, -1);
358 60 ja_rd
    init_signal_spy("/"&entity_name&"/data_rd_vma", signal_name&".data_rd_vma", 0, -1);
359 112 ja_rd
    init_signal_spy("/"&entity_name&"/p1_rbank_we", signal_name&".p1_rbank_we", 0, -1);
360 60 ja_rd
    init_signal_spy("/"&entity_name&"/code_rd_vma", signal_name&".code_rd_vma", 0, -1);
361
    init_signal_spy("/"&entity_name&"/p2_do_load", signal_name&".load", 0, -1);
362 96 ja_rd
    init_signal_spy("/"&entity_name&"/data_addr", signal_name&".present_data_wr_addr", 0, -1);
363 60 ja_rd
    init_signal_spy("/"&entity_name&"/data_wr", signal_name&".present_data_wr", 0, -1);
364
    init_signal_spy("/"&entity_name&"/byte_we", signal_name&".data_byte_we", 0, -1);
365
    init_signal_spy("/"&entity_name&"/p2_data_word_rd", signal_name&".word_loaded", 0, -1);
366 96 ja_rd
    init_signal_spy("/"&entity_name&"/data_addr", signal_name&".present_data_rd_addr", 0, -1);
367 112 ja_rd
    init_signal_spy("/"&entity_name&"/p1_exception", signal_name&".exception", 0, -1);
368 60 ja_rd
 
369
    while done='0' loop
370
        wait until clk'event and clk='1';
371
        if reset='1' then
372
            -- FIXME should use real reset vector here
373
            info.pc_m <= (others => X"00000000");
374 84 ja_rd
 
375
            -- By default logging is DISABLED by triggering with an impossible
376
            -- fetch address. Logging must be enabled from outside by 
377
            -- setting log_trigger_address to a suitable value.
378
            info.log_trigger_address <= trigger_addr;
379
            info.log_triggered <= false;
380 112 ja_rd
            info.debug <= (others => '0');
381 60 ja_rd
        else
382
            log_cpu_status(info, l_file);
383
        end if;
384
    end loop;
385
 
386
 
387
end procedure log_cpu_activity;
388
 
389
 
390
 
391
end package body;

powered by: WebSVN 2.1.0

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