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

Subversion Repositories light8080

[/] [light8080/] [trunk/] [vhdl/] [test/] [light8080_tb.vhdl] - Blame information for rev 80

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

Line No. Rev Author Line
1 78 ja_rd
--------------------------------------------------------------------------------
2
-- Light8080 simulation test bench.
3
--------------------------------------------------------------------------------
4
-- This test bench was built from a generic template. The details on what tests
5
-- are performed by this test bench can be found in the assembly source for the 
6
-- 8080 program, in file asm\exer.asm.
7
-------------------------------------------------------------------------------- 
8
-- 
9
-- This test bench provides a simulated CPU system to test programs. This test 
10
-- bench does not do any assertions or checks, all assertions are left to the 
11
-- software.
12
--
13
-- The simulated environment has 64KB of RAM covering the whole address map.
14
-- The simulated RAM is initialized with the contents of constant 'obj_code'.
15
-- This constant's contents are generated from some .HEX object code file using 
16
-- a helper script. See the perl script 'util\hexconv.pl' and BAT files in the 
17
-- asm directory.
18
--
19
-- This simulated system provides some means to trigger hardware irq from 
20
-- software, including the specification of the instructions fed to the CPU as 
21
-- interrupt vectors during inta cycles. This is only meant to test interrupt 
22
-- response of the CPU.
23
--
24
-- We will simulate 8 possible irq sources. The software can trigger any one of 
25
-- them by writing at ports 0x010 to 0x011. Port 0x010 holds the irq source to 
26
-- be triggered (0 to 7) and port 0x011 holds the number of clock cycles that 
27
-- will elapse from the end of the instruction that writes to the register to 
28
-- the assertion of intr. Port 0x012 holds the number of cycles intr will remain 
29
-- high. Intr will be asserted for 1 cycle at least, so writing a 0 here is the 
30
-- same as writing 1.
31
--
32
-- When the interrupt is acknowledged and inta is asserted, the test bench reads
33
-- the value at register 0x010 as the irq source, and feeds an instruction to 
34
-- the CPU starting from the RAM address 0040h+source*4.
35
-- That is, address range 0040h-005fh is reserved for the simulated 'interrupt
36
-- vectors', a total of 4 bytes for each of the 8 sources. This allows the 
37
-- software to easily test different interrupt vectors without any hand 
38
-- assembly. All of this is strictly simulation-only stuff.
39
--
40
-- Upon completion, the software must write a value to register 0x020. Writing 
41
-- a 0x055 means 'success', writing a 0x0aa means 'failure'. The write operation
42
-- will stop the simulation. Success and failure conditions are defined by the 
43
-- software.
44
--
45
-- If a time period defined as constant MAX_SIM_LENGTH passes before anything
46
-- is written to io address 0x020, the test bench assumes the software ran away
47
-- and quits with an error message.
48
--------------------------------------------------------------------------------
49
 
50
library ieee;
51
use ieee.std_logic_1164.ALL;
52
use ieee.std_logic_unsigned.all;
53
use ieee.numeric_std.ALL;
54
 
55
use work.obj_code_pkg.all;
56
use work.l80pkg.all;
57
 
58
entity light8080_tb is
59
end entity light8080_tb;
60
 
61
architecture behavior of light8080_tb is
62
 
63
--------------------------------------------------------------------------------
64
-- Simulation parameters
65
 
66
-- T: simulated clock period
67
constant T : time := 100 ns;
68
 
69
-- MAX_SIM_LENGTH: maximum simulation time
70
-- Enough for the tb0, you may need to modify this for other tests.
71
constant MAX_SIM_LENGTH : time := T * 7000;
72
 
73
 
74
--------------------------------------------------------------------------------
75
 
76
signal data_i :           std_logic_vector(7 downto 0) := (others=>'0');
77
signal vma_o  :           std_logic;
78
signal rd_o :             std_logic;
79
signal wr_o :             std_logic;
80
signal io_o :             std_logic;
81
signal data_o :           std_logic_vector(7 downto 0);
82
signal data_mem :         std_logic_vector(7 downto 0);
83
signal addr_o :           std_logic_vector(15 downto 0);
84
signal fetch_o :          std_logic;
85
signal inta_o :           std_logic;
86
signal inte_o :           std_logic;
87
signal intr_i :           std_logic := '0';
88
signal halt_o :           std_logic;
89
 
90
signal reset :            std_logic := '0';
91
signal clk :              std_logic := '1';
92
signal done :             std_logic := '0';
93
 
94
signal irq_vector_byte:   std_logic_vector(7 downto 0);
95
signal irq_source :       integer range 0 to 7;
96
signal cycles_to_intr :   integer range -10 to 255;
97
signal intr_width :       integer range 0 to 255;
98
signal int_vector_index : integer range 0 to 3;
99
signal addr_vector_table: integer range 0 to 65535;
100
 
101
signal con_line_buf :     string(1 to 80);
102
signal con_line_ix :      integer;
103
 
104
 
105
-- Using shared variables for big memory arrays speeds up simulation a lot;
106
-- see Modelsim 6.3 User Manual, section on 'Modelling Memory'.
107
-- WARNING: I have only tested this construct with Modelsim SE 6.3.
108
shared variable ram : ram_t(0 to 65536-1) := objcode_to_bram(obj_code, 65536);
109
 
110
begin
111
 
112
  -- Instantiate the Unit Under Test (UUT)
113
  cpu: entity work.light8080
114
  port map (
115
    clk => clk,
116
    reset => reset,
117
    vma => vma_o,
118
    rd => rd_o,
119
    wr => wr_o,
120
    io => io_o,
121
    fetch => fetch_o,
122
    addr_out => addr_o,
123
    data_in => data_i,
124
    data_out => data_o,
125
 
126
    intr => intr_i,
127
    inte => inte_o,
128
    inta => inta_o,
129
    halt => halt_o
130
  );
131
 
132
 
133
-- clock: run clock until test is done
134
clock:
135
process(done, clk)
136
begin
137
  if done = '0' then
138
    clk <= not clk after T/2;
139
  end if;
140
end process clock;
141
 
142
 
143
-- Drive reset and done 
144
main_test:
145
process
146
begin
147
  -- Load object code on memory -- note this comsumes no simulated time
148
  --load_object_code(obj_code, ram);
149
 
150
  -- Assert reset for at least one full clk period
151
  reset <= '1';
152
  wait until clk = '1';
153
  wait for T/2;
154
  reset <= '0';
155
 
156
  -- Remember to 'cut away' the preceding 3 clk semiperiods from 
157
  -- the wait statement...
158
  wait for (MAX_SIM_LENGTH - T*1.5);
159
 
160
  -- Maximum sim time elapsed, assume the program ran away and
161
  -- stop the clk process asserting 'done' (which will stop the simulation)
162
  done <= '1';
163
 
164
  assert (done = '1')
165
  report "Test timed out."
166
  severity failure;
167
 
168
  wait;
169
end process main_test;
170
 
171
 
172
-- Synchronous RAM covering the whole address map
173
synchronous_ram:
174
process(clk)
175
begin
176
  if (clk'event and clk='1') then
177
    data_mem <= ram(conv_integer(addr_o));
178
    if wr_o = '1' then
179
      ram(conv_integer(addr_o)) := data_o;
180
    end if;
181
  end if;
182
end process synchronous_ram;
183
 
184
 
185
irq_trigger_register:
186
process(clk)
187
begin
188
  if (clk'event and clk='1') then
189
    if reset='1' then
190
      cycles_to_intr <= -10; -- meaning no interrupt pending
191
    else
192
      if io_o='1' and wr_o='1' and addr_o(7 downto 0)=X"11" then
193
        cycles_to_intr <= conv_integer(data_o) + 1;
194
      else
195
        if cycles_to_intr >= 0 then
196
          cycles_to_intr <= cycles_to_intr - 1;
197
        end if;
198
      end if;
199
    end if;
200
  end if;
201
end process irq_trigger_register;
202
 
203
irq_pulse_width_register:
204
process(clk)
205
variable intr_pulse_countdown : integer;
206
begin
207
  if (clk'event and clk='1') then
208
    if reset='1' then
209
      intr_width <= 1;
210
      intr_pulse_countdown := 0;
211
      intr_i <= '0';
212
    else
213
      if io_o='1' and wr_o='1' and addr_o(7 downto 0)=X"12" then
214
        intr_width <= conv_integer(data_o) + 1;
215
      end if;
216
 
217
      if cycles_to_intr = 0 then
218
        intr_i <= '1';
219
        intr_pulse_countdown := intr_width;
220
      elsif intr_pulse_countdown <= 1 then
221
        intr_i <= '0';
222
      else
223
        intr_pulse_countdown := intr_pulse_countdown - 1;
224
      end if;
225
    end if;
226
  end if;
227
end process irq_pulse_width_register;
228
 
229
irq_source_register:
230
process(clk)
231
begin
232
  if (clk'event and clk='1') then
233
    if reset='1' then
234
      irq_source <= 0;
235
    else
236
      if io_o='1' and wr_o='1' and addr_o(7 downto 0)=X"10" then
237
        irq_source <= conv_integer(data_o(2 downto 0));
238
      end if;
239
    end if;
240
  end if;
241
end process irq_source_register;
242
 
243
 
244
-- 'interrupt vector' logic.
245
irq_vector_table:
246
process(clk)
247
begin
248
  if (clk'event and clk='1') then
249
    if vma_o = '1' and rd_o='1' then
250
      if inta_o = '1' then
251
        int_vector_index <= int_vector_index + 1;
252
      else
253
        int_vector_index <= 0;
254
      end if;
255
    end if;
256
    -- this is the address of the byte we'll feed to the CPU
257
    addr_vector_table <= 64+irq_source*4+int_vector_index;
258
  end if;
259
end process irq_vector_table;
260
irq_vector_byte <= ram(addr_vector_table);
261
 
262
data_i <= data_mem when inta_o='0' else irq_vector_byte;
263
 
264
 
265
test_outcome_register:
266
process(clk)
267
variable outcome : std_logic_vector(7 downto 0);
268
begin
269
  if (clk'event and clk='1') then
270
    if io_o='1' and wr_o='1' and addr_o(7 downto 0)=X"20" then
271
    assert (data_o /= X"55") report "Software reports SUCCESS" severity failure;
272
    assert (data_o /= X"aa") report "Software reports FAILURE" severity failure;
273
    assert ((data_o = X"aa") or (data_o = X"55"))
274
    report "Software reports unexpected outcome value."
275
    severity failure;
276
    end if;
277
  end if;
278
end process test_outcome_register;
279
 
280
 
281
dummy_uart_output_reg:
282
process(clk)
283
variable outcome : std_logic_vector(7 downto 0);
284
begin
285
  if (clk'event and clk='1') then
286
    if io_o='1' and wr_o='1' and addr_o(7 downto 0)=X"21" then
287
      -- append char to output string
288
      if con_line_ix < con_line_buf'high then
289
        con_line_buf(con_line_ix) <= character'val(conv_integer(data_o));
290
        con_line_ix <= con_line_ix + 1;
291
      end if;
292
    end if;
293
  end if;
294
end process dummy_uart_output_reg;
295
 
296
 
297
end;

powered by: WebSVN 2.1.0

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