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

Subversion Repositories ion

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

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 193 ja_rd
-- Maximum line size of for console output log. Lines longer than this will be
53
-- truncated.
54
constant CONSOLE_LOG_LINE_SIZE : integer := 1024*4;
55
 
56
 
57 60 ja_rd
type t_pc_queue is array(0 to 3) of t_word;
58
 
59
type t_log_info is record
60
    rbank :                 t_rbank;
61
    prev_rbank :            t_rbank;
62
 
63
    cp0_epc :               t_pc;
64
    prev_epc :              t_pc;
65 152 ja_rd
    cp0_status :            std_logic_vector(5 downto 0);
66
    cp0_cache_control :     std_logic_vector(1 downto 0);
67
    prev_status :           t_word;
68
    p1_set_cp0 :            std_logic;
69 157 ja_rd
    p1_rfe :                std_logic;
70 152 ja_rd
    pc_mtc0 :               t_word;
71 60 ja_rd
 
72
    pc_m :                  t_pc_queue;
73
 
74
    reg_hi, reg_lo :        t_word;
75
    prev_hi, prev_lo :      t_word;
76
    negate_reg_lo :         std_logic;
77
    mdiv_count_reg :        std_logic_vector(5 downto 0);
78
    prev_count_reg :        std_logic_vector(5 downto 0);
79
 
80
    data_rd_vma :           std_logic;
81 112 ja_rd
    p1_rbank_we :           std_logic;
82 60 ja_rd
    code_rd_vma :           std_logic;
83
    data_byte_we :          std_logic_vector(3 downto 0);
84
 
85 96 ja_rd
    present_data_wr_addr :  t_word;
86 60 ja_rd
    present_data_wr :       t_word;
87
    present_data_rd_addr :  t_word;
88
    present_code_rd_addr :  t_pc;
89
 
90
    pending_data_rd_addr :  t_word;
91
    pending_data_wr_addr :  t_word;
92
    pending_data_wr_pc :    t_word;
93
    pending_data_wr :       t_word;
94
    pending_data_wr_we :    std_logic_vector(3 downto 0);
95
 
96
    word_loaded :           t_word;
97
 
98 193 ja_rd
    uart_tx :               std_logic;
99
    io_wr_data :            t_word;
100
 
101 60 ja_rd
    mdiv_address :          t_word;
102
    mdiv_pending :          boolean;
103
 
104 112 ja_rd
    exception :             std_logic;
105
    exception_pc :          t_word;
106
 
107 60 ja_rd
    data_rd_address :       t_word;
108
    load :                  std_logic;
109
 
110
    read_pending :          boolean;
111
    write_pending :         boolean;
112 112 ja_rd
    debug :                 t_word;
113 84 ja_rd
 
114 193 ja_rd
    -- Console log line buffer --------------------------------------
115
    con_line_buf :         string(1 to CONSOLE_LOG_LINE_SIZE);
116
    con_line_ix :          integer;
117
 
118 84 ja_rd
    -- Log trigger --------------------------------------------------
119
    -- Enable logging after fetching from a given address -----------
120
    log_trigger_address :   t_word;
121
    log_triggered :         boolean;
122 60 ja_rd
end record t_log_info;
123
 
124
procedure log_cpu_activity(
125
                signal clk :    in std_logic;
126
                signal reset :  in std_logic;
127 193 ja_rd
                signal done :   in std_logic;
128
                mcu_entity :    string;
129
                cpu_name :      string;
130 60 ja_rd
                signal info :   inout t_log_info;
131
                signal_name :   string;
132 84 ja_rd
                trigger_addr :  in t_word;
133 193 ja_rd
                file l_file :   TEXT;
134
                file con_file : TEXT);
135 60 ja_rd
 
136
 
137
end package;
138
 
139
package body mips_tb_pkg is
140
 
141
procedure log_cpu_status(
142 84 ja_rd
                signal info :   inout t_log_info;
143 193 ja_rd
                file l_file :   TEXT;
144
                file con_file : TEXT) is
145 60 ja_rd
variable i : integer;
146
variable ri : std_logic_vector(7 downto 0);
147
variable full_pc, temp, temp2 : t_word;
148
variable k : integer := 2;
149 193 ja_rd
variable log_trap_status :      boolean := false;
150
variable uart_data : integer;
151 60 ja_rd
begin
152
 
153 84 ja_rd
    -- Trigger logging if the CPU fetches from trigger address
154
    if (info.log_trigger_address(31 downto 2) = info.present_code_rd_addr) and
155
       info.code_rd_vma='1' then
156
        info.log_triggered <= true;
157
 
158
        assert 1=0
159
        report "Log triggered by fetch from address 0x"& hstr(info.log_trigger_address)
160
        severity note;
161
    end if;
162
 
163 60 ja_rd
    -- This is the address of the opcode that triggered the changed we're
164
    -- about to log
165
    full_pc := info.pc_m(k);
166
 
167 112 ja_rd
    -- Log memory writes ----------------------------------------
168
    if info.write_pending then
169
        if conv_integer(info.pending_data_wr_pc) <= conv_integer(full_pc) then
170 60 ja_rd
 
171
            ri := X"0" & info.pending_data_wr_we;
172
            temp := info.pending_data_wr;
173
            if info.pending_data_wr_we(3)='0' then
174
                temp := temp and X"00ffffff";
175
            end if;
176
            if info.pending_data_wr_we(2)='0' then
177
                temp := temp and X"ff00ffff";
178
            end if;
179
            if info.pending_data_wr_we(1)='0' then
180
                temp := temp and X"ffff00ff";
181
            end if;
182
            if info.pending_data_wr_we(0)='0' then
183
                temp := temp and X"ffffff00";
184
            end if;
185 84 ja_rd
            if info.log_triggered then
186
                print(l_file, "("& hstr(info.pending_data_wr_pc) &") ["&
187
                    hstr(info.pending_data_wr_addr) &"] |"&
188
                    hstr(ri)& "|="&
189
                    hstr(temp)& " WR" );
190
            end if;
191 112 ja_rd
            info.debug <= info.pending_data_wr_pc;
192 60 ja_rd
            info.write_pending <= false;
193 112 ja_rd
        end if;
194
    end if;
195 60 ja_rd
 
196 112 ja_rd
    -- Log register bank activity.
197
    -- NOTE: in previous versions we used to do this only at the 1st cycle of
198
    --- instructions, mistakenly. Reg changes need to be logged as soon as 
199
    -- they happen.
200
    if true then --info.code_rd_vma='1' then
201
 
202
        -- Log register changes -------------------------------------
203
        ri := X"00";
204
        for i in 0 to 31 loop
205
            if info.prev_rbank(i)/=info.rbank(i)
206
               and info.prev_rbank(i)(0)/='U' then
207
                if info.log_triggered then
208
                    print(l_file, "("& hstr(info.pc_m(k-0))& ") "&
209
                        "["& hstr(ri)& "]="& hstr(info.rbank(i)));
210
                end if;
211 84 ja_rd
            end if;
212 112 ja_rd
            ri := ri + 1;
213
        end loop;
214 60 ja_rd
 
215
        -- Log aux register changes ---------------------------------
216 152 ja_rd
 
217
        -- Mult/div module, register LO
218 60 ja_rd
        if info.prev_lo /= info.reg_lo and info.prev_lo(0)/='U' then
219
            -- Adjust opcode PC when LO came from the mul module
220
            if info.mdiv_pending then
221
                temp2 := info.mdiv_address;
222
                info.mdiv_pending <= false;
223
            else
224 112 ja_rd
                temp2 := info.pc_m(k-2);
225 60 ja_rd
            end if;
226
 
227
            -- we're observing the value of reg_lo, but the mult core
228
            -- will output the negated value in some cases. We
229
            -- have to mimic that behavior.
230
            if info.negate_reg_lo='1' then
231
                -- negate reg_lo before displaying
232
                temp := not info.reg_lo;
233
                temp := temp + 1;
234 84 ja_rd
                if info.log_triggered then
235 152 ja_rd
                    -- FIXME removed temporarily until fixed (@note1)
236
                    --print(l_file, "("& hstr(temp2)& ") [LO]="& hstr(temp));
237 84 ja_rd
                end if;
238 60 ja_rd
            else
239 84 ja_rd
                if info.log_triggered then
240 152 ja_rd
                    -- FIXME removed temporarily until fixed (@note1)
241
                    --print(l_file, "("& hstr(temp2)& ") [LO]="& hstr(info.reg_lo));
242 84 ja_rd
                end if;
243 60 ja_rd
            end if;
244
        end if;
245 152 ja_rd
 
246
        -- Mult/div module, register HI
247 60 ja_rd
        if info.prev_hi /= info.reg_hi and info.prev_hi(0)/='U' then
248
            -- Adjust opcode PC when HI came from the mul module
249
            if info.mdiv_pending then
250
                temp2 := info.mdiv_address;
251
                info.mdiv_pending <= false;
252
            else
253 112 ja_rd
                temp2 := info.pc_m(k-2);
254 60 ja_rd
            end if;
255 84 ja_rd
 
256
            if info.log_triggered then
257 152 ja_rd
                -- FIXME removed temporarily until fixed (@note1)
258
                --print(l_file, "("& hstr(temp2)& ") [HI]="& hstr(info.reg_hi));
259 84 ja_rd
            end if;
260 60 ja_rd
        end if;
261 152 ja_rd
 
262
        -- CP0, register EPC
263 60 ja_rd
        if info.prev_epc /= info.cp0_epc and info.cp0_epc(31)/='U'  then
264
            temp := info.cp0_epc & "00";
265 84 ja_rd
            if info.log_triggered then
266 112 ja_rd
                -- The instruction that caused the EP change is the last 
267
                -- recorded trap/syscall exception.
268
                print(l_file, "("& hstr(info.exception_pc)& ") [EP]="& hstr(temp));
269 84 ja_rd
            end if;
270 60 ja_rd
            info.prev_epc <= info.cp0_epc;
271 152 ja_rd
 
272
            log_trap_status := true;
273
        else
274
            log_trap_status := false;
275 60 ja_rd
        end if;
276
 
277 152 ja_rd
        -- CP0, register SR
278
 
279
        -- If SR changed by mtc0 instruction, get the mtc0 address
280 157 ja_rd
        if (info.p1_set_cp0='1' or info.p1_rfe='1') and info.cp0_status(1)='1' then
281 152 ja_rd
            info.pc_mtc0 <= info.pc_m(k-1);
282
        end if;
283
 
284
        -- Build SR from separate CPU signals
285
        temp := X"000" & "00" & info.cp0_cache_control &
286
                X"00" & "00" & info.cp0_status;
287
        if info.prev_status /= temp and info.cp0_status(0)/='U' then
288
            if info.log_triggered then
289
                if log_trap_status then
290
                    -- The instruction that caused the SR change is the last 
291
                    -- recorded trap/syscall exception.
292
                    print(l_file, "("& hstr(info.exception_pc)& ") [SR]="& hstr(temp));
293
                else
294
                    -- The instruction that caused the change is mtc0
295
                    print(l_file, "("& hstr(info.pc_mtc0)& ") [SR]="& hstr(temp));
296
                end if;
297
            end if;
298
            info.prev_status <= temp;
299
        end if;
300 112 ja_rd
 
301 152 ja_rd
 
302 60 ja_rd
        -- Save present cycle info to compare the next cycle --------
303
        info.prev_rbank <= info.rbank;
304
        info.prev_hi <= info.reg_hi;
305
        info.prev_lo <= info.reg_lo;
306 152 ja_rd
 
307 112 ja_rd
    end if;
308
 
309
    -- Update instruction address table only at the 1st cycle of each 
310
    -- instruction.
311
    if info.code_rd_vma='1' then
312 60 ja_rd
        info.pc_m(3) <= info.pc_m(2);
313
        info.pc_m(2) <= info.pc_m(1);
314
        info.pc_m(1) <= info.pc_m(0);
315
        info.pc_m(0) <= info.present_code_rd_addr & "00";
316
    end if;
317
 
318 112 ja_rd
    -- Log memory reads ------------------------------------------
319
    if info.read_pending and info.load='1' and info.p1_rbank_we='1' then
320
        if info.log_triggered then
321
            print(l_file, "("& hstr(info.pc_m(1)) &") ["&
322
                  hstr(info.pending_data_rd_addr) &"] <"&
323
                  "**"& ">="&
324
                  hstr(info.word_loaded)& " RD" );
325
        end if;
326
        info.read_pending <= false;
327
    end if;
328
 
329
    if info.exception='1' then
330
        info.exception_pc <= info.pc_m(1);
331
    end if;
332
 
333 60 ja_rd
    if info.data_byte_we/="0000" then
334
        info.write_pending <= true;
335
        info.pending_data_wr_we <= info.data_byte_we;
336 96 ja_rd
        info.pending_data_wr_addr <= info.present_data_wr_addr;
337 60 ja_rd
        info.pending_data_wr_pc <= info.pc_m(k-1);
338
        info.pending_data_wr <= info.present_data_wr;
339
    end if;
340
 
341
    if info.data_rd_vma='1' then
342
        info.read_pending <= true;
343
        info.pending_data_rd_addr <= info.present_data_rd_addr;
344
    end if;
345
 
346
    if info.mdiv_count_reg="100000" then
347
        info.mdiv_address <= info.pc_m(1);
348
        info.mdiv_pending <= true;
349
    end if;
350
 
351
    info.prev_count_reg <= info.mdiv_count_reg;
352
 
353 193 ja_rd
    -- Log data sent to UART ---------------------------------------------------
354
 
355
 
356
    -- TX data may come from the high or low byte (opcodes.s
357
    -- uses high byte, no_op.c uses low)
358
    if info.uart_tx = '1' then
359
        uart_data := conv_integer(unsigned(info.io_wr_data(7 downto 0)));
360
 
361
        -- UART TX data goes to output after a bit of line-buffering
362
        -- and editing
363
        if uart_data = 10 then
364
            -- CR received: print output string and clear it
365
            print(con_file, info.con_line_buf(1 to info.con_line_ix));
366
            info.con_line_ix <= 1;
367
            for i in 1 to info.con_line_buf'high loop
368
               info.con_line_buf(i) <= ' ';
369
            end loop;
370
        elsif uart_data = 13 then
371
            -- ignore LF
372
        else
373
            -- append char to output string
374
            if info.con_line_ix < info.con_line_buf'high then
375
                info.con_line_buf(info.con_line_ix) <= character'val(uart_data);
376
                info.con_line_ix <= info.con_line_ix + 1;
377
            end if;
378
        end if;
379
    end if;
380
 
381
 
382 60 ja_rd
end procedure log_cpu_status;
383
 
384
procedure log_cpu_activity(
385
                signal clk :    in std_logic;
386
                signal reset :  in std_logic;
387
                signal done :   in std_logic;
388 193 ja_rd
                mcu_entity :    string;
389
                cpu_name :      string;
390 60 ja_rd
                signal info :   inout t_log_info;
391
                signal_name :   string;
392 84 ja_rd
                trigger_addr :  in t_word;
393 193 ja_rd
                file l_file :   TEXT;
394
                file con_file : TEXT) is
395 60 ja_rd
begin
396 206 ja_rd
    init_signal_spy("/"&mcu_entity&"/"&cpu_name&"/p1_rbank", signal_name&".rbank", 0);
397
    init_signal_spy("/"&mcu_entity&"/"&cpu_name&"/code_rd_addr", signal_name&".present_code_rd_addr", 0);
398
    init_signal_spy("/"&mcu_entity&"/"&cpu_name&"/mult_div/upper_reg", signal_name&".reg_hi", 0);
399
    init_signal_spy("/"&mcu_entity&"/"&cpu_name&"/mult_div/lower_reg", signal_name&".reg_lo", 0);
400
    init_signal_spy("/"&mcu_entity&"/"&cpu_name&"/mult_div/negate_reg", signal_name&".negate_reg_lo", 0);
401
    init_signal_spy("/"&mcu_entity&"/"&cpu_name&"/mult_div/count_reg", signal_name&".mdiv_count_reg", 0);
402
    init_signal_spy("/"&mcu_entity&"/"&cpu_name&"/cp0_epc", signal_name&".cp0_epc", 0);
403
    init_signal_spy("/"&mcu_entity&"/"&cpu_name&"/cp0_status", signal_name&".cp0_status", 0);
404
    init_signal_spy("/"&mcu_entity&"/"&cpu_name&"/p1_set_cp0", signal_name&".p1_set_cp0", 0);
405
    init_signal_spy("/"&mcu_entity&"/"&cpu_name&"/p1_rfe", signal_name&".p1_rfe", 0);
406
    init_signal_spy("/"&mcu_entity&"/"&cpu_name&"/cp0_cache_control", signal_name&".cp0_cache_control", 0);
407
    init_signal_spy("/"&mcu_entity&"/"&cpu_name&"/data_rd_vma", signal_name&".data_rd_vma", 0);
408
    init_signal_spy("/"&mcu_entity&"/"&cpu_name&"/p1_rbank_we", signal_name&".p1_rbank_we", 0);
409
    init_signal_spy("/"&mcu_entity&"/"&cpu_name&"/code_rd_vma", signal_name&".code_rd_vma", 0);
410
    init_signal_spy("/"&mcu_entity&"/"&cpu_name&"/p2_do_load", signal_name&".load", 0);
411
    init_signal_spy("/"&mcu_entity&"/"&cpu_name&"/data_addr", signal_name&".present_data_wr_addr", 0);
412
    init_signal_spy("/"&mcu_entity&"/"&cpu_name&"/data_wr", signal_name&".present_data_wr", 0);
413
    init_signal_spy("/"&mcu_entity&"/"&cpu_name&"/byte_we", signal_name&".data_byte_we", 0);
414
    init_signal_spy("/"&mcu_entity&"/"&cpu_name&"/p2_data_word_rd", signal_name&".word_loaded", 0);
415
    init_signal_spy("/"&mcu_entity&"/"&cpu_name&"/data_addr", signal_name&".present_data_rd_addr", 0);
416
    init_signal_spy("/"&mcu_entity&"/"&cpu_name&"/p1_exception", signal_name&".exception", 0);
417
    init_signal_spy("/"&mcu_entity&"/uart_write", signal_name&".uart_tx", 0);
418
    init_signal_spy("/"&mcu_entity&"/mpu_io_wr_data", signal_name&".io_wr_data", 0);
419 193 ja_rd
 
420
    -- We force both 'rdy' uart outputs to speed up the simulation (since the
421
    -- UART operation is not simulated, just logged).
422
    signal_force("/"&mcu_entity&"/uart_tx_rdy", "1", 0 ms, freeze, -1 ms, 0);
423
    signal_force("/"&mcu_entity&"/uart_rx_rdy", "1", 0 ms, freeze, -1 ms, 0);
424
    -- And we force the UART RX data to a predictable value until we implement
425
    -- UART RX simulation, eventually.
426
    signal_force("/"&mcu_entity&"/uart_data_rx", "00000000", 0 ms, freeze, -1 ms, 0);
427
 
428 60 ja_rd
    while done='0' loop
429
        wait until clk'event and clk='1';
430
        if reset='1' then
431
            -- FIXME should use real reset vector here
432
            info.pc_m <= (others => X"00000000");
433 84 ja_rd
 
434
            -- By default logging is DISABLED by triggering with an impossible
435
            -- fetch address. Logging must be enabled from outside by 
436
            -- setting log_trigger_address to a suitable value.
437
            info.log_trigger_address <= trigger_addr;
438
            info.log_triggered <= false;
439 112 ja_rd
            info.debug <= (others => '0');
440 193 ja_rd
 
441
            info.con_line_ix <= 1; -- uart log line buffer is empty
442 60 ja_rd
        else
443 193 ja_rd
            log_cpu_status(info, l_file, con_file);
444 60 ja_rd
        end if;
445
    end loop;
446
 
447
 
448
end procedure log_cpu_activity;
449
 
450
 
451
 
452
end package body;

powered by: WebSVN 2.1.0

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