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

Subversion Repositories ion

[/] [ion/] [trunk/] [src/] [mips_tb2_template.vhdl] - Blame information for rev 42

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

Line No. Rev Author Line
1 42 ja_rd
--##############################################################################
2
-- This file was generated automatically from '/src/mips_tb2_template.vhdl'.
3
-- 
4
--------------------------------------------------------------------------------
5
-- Simulation test bench TB2 -- not synthesizable.
6
--
7
-- Simulates the CPU core connected to a simulated external static RAM and an
8
-- internal BRAM block through a stub (i.e. empty).
9
-- BRAM is initialized with the program object code, and SRAM is initialized 
10
-- with data secions from program. 
11
-- The makefile for the source samples include targets to build simulation test 
12
-- benches using this template, use them as usage examples.
13
--
14
-- The memory setup is meant to test the basic 'dummy' cache. 
15
-- 
16
-- Console output (at addresses compatible to Plasma's) is logged to text file
17
-- "hw_sim_console_log.txt".
18
-- IMPORTANT: The code that echoes UART TX data to the simulation console does
19
-- line buffering; it will not print anything until it gets a CR (0x0d), and
20
-- will ifnore LFs (0x0a). Bear this in mind if you see no output when you 
21
-- expect it.
22
--
23
-- WARNING: Will only work on Modelsim; uses custom library SignalSpy.
24
--##############################################################################
25
 
26
library ieee,modelsim_lib;
27
use ieee.std_logic_1164.all;
28
use ieee.std_logic_arith.all;
29
use ieee.std_logic_unsigned.all;
30
use work.mips_pkg.all;
31
 
32
 
33
use work.mips_pkg.all;
34
 
35
use modelsim_lib.util.all;
36
use std.textio.all;
37
use work.txt_util.all;
38
 
39
entity @entity_name@ is
40
end;
41
 
42
 
43
architecture @arch_name@ of @entity_name@ is
44
 
45
-------------------------------------------------------------------------------
46
-- Simulation parameters
47
 
48
-- Master clock period
49
constant T : time           := 20 ns;
50
-- Time the UART is unavailable after writing to the TX register
51
-- WARNING: slite does not simulate this. The logs may be different when > 0.0!
52
constant SIMULATED_UART_TX_TIME : time := 0.0 us;
53
 
54
-- Simulation length in clock cycles 
55
-- 2000 is enough for 'hello' sample, 22000 enough for 10 digits of pi
56
constant SIMULATION_LENGTH : integer := @sim_len@;
57
 
58
-- Simulated external SRAM size in 32-bit words 
59
constant SRAM_SIZE : integer := @xram_size@;
60
-- Ext. SRAM address length (memory is 16 bits wide so it needs an extra address bit)
61
constant SRAM_ADDR_SIZE : integer := log2(SRAM_SIZE)+1;
62
 
63
 
64
-- BRAM table and interface signals --------------------------------------------
65
constant BRAM_SIZE : integer := @code_table_size@;
66
constant BRAM_ADDR_SIZE : integer := @code_addr_size@;
67
subtype t_bram_address is std_logic_vector(BRAM_ADDR_SIZE-1 downto 0);
68
-- (this table holds one byte-slice; the RAM will have 4 of these)
69
type t_bram is array(0 to BRAM_SIZE-1) of std_logic_vector(7 downto 0);
70
 
71
signal bram_rd_addr :       t_bram_address;
72
signal bram_wr_addr :       t_bram_address;
73
signal bram_rd_data :       t_word;
74
signal bram_wr_data :       t_word;
75
signal bram_byte_we :       std_logic_vector(3 downto 0);
76
 
77
-- bram0 is LSB, bram3 is MSB
78
signal bram3 : t_bram := (@code3@);
79
signal bram2 : t_bram := (@code2@);
80
signal bram1 : t_bram := (@code1@);
81
signal bram0 : t_bram := (@code0@);
82
 
83
-- This is a 16-bit SRAM split in 2 byte slices; so each slice will have two
84
-- bytes for each word of SRAM_SIZE
85
type t_sram is array(0 to SRAM_SIZE*2-1) of std_logic_vector(7 downto 0);
86
signal sram1 : t_sram := (@data31@);
87
signal sram0 : t_sram := (@data20@);
88
 
89
 
90
signal data_uart :          std_logic_vector(31 downto 0);
91
signal data_uart_status :   std_logic_vector(31 downto 0);
92
signal uart_tx_rdy :        std_logic := '1';
93
signal uart_rx_rdy :        std_logic := '1';
94
 
95
--------------------------------------------------------------------------------
96
 
97
signal clk :                std_logic := '0';
98
signal reset :              std_logic := '1';
99
signal interrupt :          std_logic := '0';
100
signal done :               std_logic := '0';
101
 
102
-- interface to asynchronous 16-bit-wide external SRAM
103
signal sram_address :       std_logic_vector(SRAM_ADDR_SIZE-1 downto 1);
104
signal sram_databus :       std_logic_vector(15 downto 0);
105
signal sram_byte_we_n :     std_logic_vector(1 downto 0);
106
signal sram_oe_n :          std_logic;
107
 
108
-- interface cpu-cache
109
signal cpu_data_rd_addr :   t_word;
110
signal cpu_data_rd_vma :    std_logic;
111
signal cpu_data_rd :        t_word;
112
signal cpu_code_rd_addr :   t_pc;
113
signal cpu_code_rd :        t_word;
114
signal cpu_code_rd_vma :    std_logic;
115
signal cpu_data_wr_addr :   t_pc;
116
signal cpu_data_wr :        t_word;
117
signal cpu_byte_we :        std_logic_vector(3 downto 0);
118
signal cpu_mem_wait :       std_logic;
119
 
120
-- interface to i/o
121
signal io_rd_data :         std_logic_vector(31 downto 0);
122
signal io_wr_data :         std_logic_vector(31 downto 0);
123
signal io_rd_addr :         std_logic_vector(31 downto 2);
124
signal io_wr_addr :         std_logic_vector(31 downto 2);
125
signal io_rd_vma :          std_logic;
126
signal io_byte_we :         std_logic_vector(3 downto 0);
127
 
128
 
129
--------------------------------------------------------------------------------
130
-- Logging signals
131
 
132
-- These are internal CPU signal mirrored using Modelsim's SignalSpy
133
signal rbank :              t_rbank;
134
signal pc, cp0_epc :        std_logic_vector(31 downto 2);
135
signal reg_hi, reg_lo :     t_word;
136
signal negate_reg_lo :      std_logic;
137
signal ld_upper_byte :      std_logic;
138
signal ld_upper_hword :     std_logic;
139
signal data_rd_vma :        std_logic;
140
signal code_rd_vma :        std_logic;
141
signal data_rd_address :    std_logic_vector(31 downto 0);
142
 
143
 
144
-- Log file
145
file l_file: TEXT open write_mode is "hw_sim_log.txt";
146
 
147
-- Console output log file
148
file con_file: TEXT open write_mode is "hw_sim_console_log.txt";
149
 
150
-- Maximum line size of for console output log. Lines longer than this will be
151
-- truncated.
152
constant CONSOLE_LOG_LINE_SIZE : integer := 1024*4;
153
 
154
-- Console log line buffer
155
signal con_line_buf :       string(1 to CONSOLE_LOG_LINE_SIZE);
156
signal con_line_ix :        integer := 1;
157
 
158
-- Debug signals ---------------------------------------------------------------
159
 
160
 
161
signal full_rd_addr :       std_logic_vector(31 downto 0);
162
signal full_wr_addr :       std_logic_vector(31 downto 0);
163
signal full_code_addr :     std_logic_vector(31 downto 0);
164
 
165
 
166
begin
167
 
168
    cpu: entity work.mips_cpu
169
    port map (
170
        interrupt   => '0',
171
 
172
        data_rd_addr=> cpu_data_rd_addr,
173
        data_rd_vma => cpu_data_rd_vma,
174
        data_rd     => cpu_data_rd,
175
 
176
        code_rd_addr=> cpu_code_rd_addr,
177
        code_rd     => cpu_code_rd,
178
        code_rd_vma => cpu_code_rd_vma,
179
 
180
        data_wr_addr=> cpu_data_wr_addr,
181
        data_wr     => cpu_data_wr,
182
        byte_we     => cpu_byte_we,
183
 
184
        mem_wait    => cpu_mem_wait,
185
 
186
        clk         => clk,
187
        reset       => reset
188
    );
189
 
190
    cache: entity work.mips_cache_stub
191
    generic map (
192
        BRAM_ADDR_SIZE => BRAM_ADDR_SIZE,
193
        SRAM_ADDR_SIZE => SRAM_ADDR_SIZE
194
    )
195
    port map (
196
        clk             => clk,
197
        reset           => reset,
198
 
199
        -- Interface to CPU core
200
        data_rd_addr    => cpu_data_rd_addr,
201
        data_rd         => cpu_data_rd,
202
        data_rd_vma     => cpu_data_rd_vma,
203
 
204
        code_rd_addr    => cpu_code_rd_addr,
205
        code_rd         => cpu_code_rd,
206
        code_rd_vma     => cpu_code_rd_vma,
207
 
208
        data_wr_addr    => cpu_data_wr_addr,
209
        byte_we         => cpu_byte_we,
210
        data_wr         => cpu_data_wr,
211
 
212
        mem_wait        => cpu_mem_wait,
213
 
214
        -- interface to FPGA i/o devices
215
        io_rd_data      => io_rd_data,
216
        io_wr_data      => io_wr_data,
217
        io_rd_addr      => io_rd_addr,
218
        io_wr_addr      => io_wr_addr,
219
        io_rd_vma       => io_rd_vma,
220
        io_byte_we      => io_byte_we,
221
 
222
        -- interface to synchronous 32-bit-wide FPGA BRAM
223
        bram_rd_data    => bram_rd_data,
224
        bram_wr_data    => bram_wr_data,
225
        bram_rd_addr    => bram_rd_addr,
226
        bram_wr_addr    => bram_wr_addr,
227
        bram_byte_we    => bram_byte_we,
228
 
229
        -- interface to asynchronous 16-bit-wide external SRAM
230
        sram_address    => sram_address,
231
        sram_databus    => sram_databus,
232
        sram_byte_we_n  => sram_byte_we_n,
233
        sram_oe_n       => sram_oe_n
234
    );
235
 
236
    ---------------------------------------------------------------------------
237
    -- Master clock: free running clock used as main module clock
238
    run_master_clock:
239
    process(done, clk)
240
    begin
241
        if done = '0' then
242
            clk <= not clk after T/2;
243
        end if;
244
    end process run_master_clock;
245
 
246
    drive_uut:
247
    process
248
    variable l : line;
249
    begin
250
        wait for T*4;
251
        reset <= '0';
252
 
253
        wait for T*SIMULATION_LENGTH;
254
 
255
        -- Flush console output to log console file (in case the end of the
256
        -- simulation caugh an unterminated line in the buffer)
257
        if con_line_ix > 1 then
258
            write(l, con_line_buf(1 to con_line_ix));
259
            writeline(con_file, l);
260
        end if;
261
 
262
        print("TB0 finished");
263
        done <= '1';
264
        wait;
265
 
266
    end process drive_uut;
267
 
268
    full_rd_addr <= cpu_data_rd_addr;
269
    full_wr_addr <= cpu_data_wr_addr & "00";
270
    full_code_addr <= cpu_code_rd_addr & "00";
271
 
272
    data_ram_block:
273
    process(clk)
274
    begin
275
        if clk'event and clk='1' then
276
            if reset='0' then
277
                bram_rd_data <=
278
                    bram3(conv_integer(unsigned(bram_rd_addr))) &
279
                    bram2(conv_integer(unsigned(bram_rd_addr))) &
280
                    bram1(conv_integer(unsigned(bram_rd_addr))) &
281
                    bram0(conv_integer(unsigned(bram_rd_addr)));
282
 
283
                if bram_byte_we(3)='1' then
284
                    bram3(conv_integer(unsigned(bram_wr_addr))) <= cpu_data_wr(31 downto 24);
285
                end if;
286
                if bram_byte_we(2)='1' then
287
                    bram2(conv_integer(unsigned(bram_wr_addr))) <= cpu_data_wr(23 downto 16);
288
                end if;
289
                if bram_byte_we(1)='1' then
290
                    bram1(conv_integer(unsigned(bram_wr_addr))) <= cpu_data_wr(15 downto  8);
291
                end if;
292
                if bram_byte_we(0)='1' then
293
                    bram0(conv_integer(unsigned(bram_wr_addr))) <= cpu_data_wr( 7 downto  0);
294
                end if;
295
            end if;
296
        end if;
297
    end process data_ram_block;
298
 
299
    sram_databus <=
300
        sram1(conv_integer(unsigned(sram_address))) &
301
        sram0(conv_integer(unsigned(sram_address)))   when sram_oe_n='0'
302
        else (others => 'Z');
303
 
304
    -- Do a very basic simulation of an external SRAM
305
    simulated_sram:
306
    process(sram_byte_we_n, sram_address)
307
    begin
308
        -- FIXME should add OE\ to control logic
309
        if sram_byte_we_n'event or sram_address'event then
310
            if sram_byte_we_n(1)='0' then
311
                sram1(conv_integer(unsigned(sram_address))) <= sram_databus(15 downto  8);
312
            end if;
313
            if sram_byte_we_n(0)='0' then
314
                sram0(conv_integer(unsigned(sram_address))) <= sram_databus( 7 downto  0);
315
            end if;
316
        end if;
317
    end process simulated_sram;
318
 
319
 
320
    simulated_io:
321
    process(clk)
322
    variable i : integer;
323
    variable uart_data : integer;
324
    begin
325
        if clk'event and clk='1' then
326
 
327
            if io_byte_we/="0000" then
328
                if io_wr_addr(31 downto 28)=X"2" then
329
                    -- Write to UART
330
 
331
                    -- If we're simulating the UART TX time, pulse RDY low
332
                    if SIMULATED_UART_TX_TIME > 0 us then
333
                        uart_tx_rdy <= '0', '1' after SIMULATED_UART_TX_TIME;
334
                    end if;
335
 
336
                    -- TX data may come from the high or low byte (opcodes.s
337
                    -- uses high byte, no_op.c uses low)
338
                    if io_byte_we(0)='1' then
339
                        uart_data := conv_integer(unsigned(io_wr_data(7 downto 0)));
340
                    else
341
                        uart_data := conv_integer(unsigned(io_wr_data(31 downto 24)));
342
                    end if;
343
 
344
                    -- UART TX data goes to output after a bit of line-buffering
345
                    -- and editing
346
                    if uart_data = 10 then
347
                        -- CR received: print output string and clear it
348
                        print(con_file, con_line_buf(1 to con_line_ix));
349
                        con_line_ix <= 1;
350
                        for i in 1 to con_line_buf'high loop
351
                           con_line_buf(i) <= ' ';
352
                        end loop;
353
                    elsif uart_data = 13 then
354
                        -- ignore LF
355
                    else
356
                        -- append char to output string
357
                        if con_line_ix < con_line_buf'high then
358
                            con_line_buf(con_line_ix) <= character'val(uart_data);
359
                            con_line_ix <= con_line_ix + 1;
360
                        end if;
361
                    end if;
362
                end if;
363
            end if;
364
        end if;
365
    end process simulated_io;
366
 
367
    -- UART read registers; only status, and hardwired, for the time being
368
    data_uart <= data_uart_status;
369
    data_uart_status <= X"0000000" & "00" & uart_tx_rdy & uart_rx_rdy;
370
 
371
 
372
    signalspy_rbank:
373
    process
374
    begin
375
        init_signal_spy("/@entity_name@/cpu/p1_rbank", "rbank", 0, -1);
376
        init_signal_spy("/@entity_name@/cpu/p0_pc_reg", "pc", 0, -1);
377
        init_signal_spy("/@entity_name@/cpu/mult_div/upper_reg", "reg_hi", 0, -1);
378
        init_signal_spy("/@entity_name@/cpu/mult_div/lower_reg", "reg_lo", 0, -1);
379
        init_signal_spy("/@entity_name@/cpu/mult_div/negate_reg", "negate_reg_lo", 0, -1);
380
        init_signal_spy("/@entity_name@/cpu/cp0_epc", "cp0_epc", 0, -1);
381
        init_signal_spy("/@entity_name@/cpu/p2_ld_upper_byte", "ld_upper_byte", 0, -1);
382
        init_signal_spy("/@entity_name@/cpu/p2_ld_upper_byte", "ld_upper_hword", 0, -1);
383
        init_signal_spy("/@entity_name@/cpu/data_rd_vma", "data_rd_vma", 0, -1);
384
        init_signal_spy("/@entity_name@/cpu/code_rd_vma", "code_rd_vma", 0, -1);
385
        wait;
386
    end process signalspy_rbank;
387
 
388
 
389
    log_cpu_activity:
390
    process(clk)
391
    variable prev_rbank : t_rbank := (others => X"00000000");
392
    variable ri : std_logic_vector(7 downto 0);
393
    variable full_pc : t_word := (others => '0');
394
    variable prev_pc : t_word := (others => '0');
395
    variable prev_hi : t_word := (others => '0');
396
    variable prev_lo : t_word := (others => '0');
397
    variable prev_epc : std_logic_vector(31 downto 2) := (others => '0');
398
    variable wr_data : t_word := (others => '0');
399
    variable temp : t_word := (others => '0');
400
    variable size : std_logic_vector(7 downto 0) := X"00";
401
    variable prev_vma_data : std_logic := '0';
402
    variable prev_rd_addr : t_word := (others => '0');
403
    variable prev_rd_data : t_word := (others => '0');
404
    variable rd_size : std_logic_vector(7 downto 0) := X"00";
405
    begin
406
        -- we'll be sampling control & data signals at falling edge, when 
407
        -- they're stable
408
        if clk'event and clk='0' then
409
            if reset='0' then
410
                -- log loads (data only)
411
                -- IMPORTANT: memory reads should be logged first because we're
412
                -- logging them the cycle after they actually happen. If you put
413
                -- the log code after any other log, the order of the operations 
414
                -- will appear wrong in the log even though it is not.
415
                if prev_vma_data='1' and cpu_mem_wait='0' then
416
                    if ld_upper_hword='1' then
417
                        rd_size := X"04";
418
                    elsif ld_upper_byte='1' then
419
                        rd_size := X"02";
420
                    else
421
                        rd_size := X"01";
422
                    end if;
423
                    print(l_file, "("& hstr(prev_pc) &") ["& hstr(prev_rd_addr) &"] <"&
424
                          "**"&
425
                          --hstr(rd_size)& 
426
                          ">="& hstr(cpu_data_rd)& " RD");
427
                end if;
428
 
429
                prev_rd_data := cpu_data_rd;
430
                if cpu_mem_wait='0' then
431
                    prev_vma_data := data_rd_vma;
432
                    prev_rd_addr := full_rd_addr;
433
                end if;
434
 
435
                -- log register changes
436
                ri := X"00";
437
                for i in 0 to 31 loop
438
                    if prev_rbank(i)/=rbank(i) then
439
                        print(l_file, "("& hstr(full_pc)& ") ["& hstr(ri)& "]="& hstr(rbank(i)));
440
                    end if;
441
                    ri := ri + 1;
442
                end loop;
443
 
444
                -- log aux register changes, only when pipeline is not stalled
445
                if prev_lo /= reg_lo and reg_lo(0)/='U' and code_rd_vma='1' then
446
                    -- we're observing the value of reg_lo, but the mult core
447
                    -- will output the negated value in some cases. We
448
                    -- have to mimic that behavior.
449
                    if negate_reg_lo='1' then
450
                        -- negate reg_lo before displaying
451
                        prev_lo := not reg_lo;
452
                        prev_lo := prev_lo + 1;
453
                        print(l_file, "("& hstr(full_pc)& ") [LO]="& hstr(prev_lo));
454
                    else
455
                        print(l_file, "("& hstr(full_pc)& ") [LO]="& hstr(reg_lo));
456
                    end if;
457
                end if;
458
                if prev_hi /= reg_hi and reg_hi(0)/='U' and code_rd_vma='1' then
459
                    print(l_file, "("& hstr(full_pc)& ") [HI]="& hstr(reg_hi));
460
                end if;
461
                if prev_epc /= cp0_epc and cp0_epc(31)/='U'  then
462
                    temp := cp0_epc & "00";
463
                    print(l_file, "("& hstr(full_pc)& ") [EP]="& hstr(temp));
464
                end if;
465
 
466
                -- 'remember' last value of hi and lo only when pipeline is not
467
                -- stalled; that's because we don't want to be tracking the
468
                -- changing values when mul/div is running (because the SW 
469
                -- simulator doesn't)
470
                if code_rd_vma='1' then
471
                    prev_hi := reg_hi;
472
                    prev_lo := reg_lo;
473
                end if;
474
 
475
 
476
                full_pc := pc & "00";
477
                prev_pc := full_pc;
478
                prev_rbank := rbank;
479
                prev_epc := cp0_epc;
480
 
481
                -- log writes
482
                if cpu_byte_we/="0000" then
483
                    wr_data := X"00000000";
484
                    if cpu_byte_we(3)='1' then
485
                        wr_data(31 downto 24) := cpu_data_wr(31 downto 24);
486
                    end if;
487
                    if cpu_byte_we(2)='1' then
488
                        wr_data(23 downto 16) := cpu_data_wr(23 downto 16);
489
                    end if;
490
                    if cpu_byte_we(1)='1' then
491
                        wr_data(15 downto  8) := cpu_data_wr(15 downto  8);
492
                    end if;
493
                    if cpu_byte_we(0)='1' then
494
                        wr_data( 7 downto  0) := cpu_data_wr( 7 downto  0);
495
                    end if;
496
                    size := "0000" & cpu_byte_we; -- mask, really
497
                    print(l_file, "("& hstr(full_pc) &") ["& hstr(full_wr_addr) &"] |"& hstr(size)& "|="& hstr(wr_data)& " WR" );
498
                end if;
499
 
500
                if full_code_addr(31 downto 28)="1111" then
501
                    print(l_file, "ERROR: Code addressed upper memory area" );
502
                end if;
503
 
504
            end if;
505
        end if;
506
    end process log_cpu_activity;
507
 
508
end architecture @arch_name@;

powered by: WebSVN 2.1.0

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