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

Subversion Repositories light8080

[/] [light8080/] [trunk/] [tools/] [hexconv/] [tb_template.vhdl] - Blame information for rev 73

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 73 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
entity light8080_@PROGNAME@ is
56
end entity light8080_@PROGNAME@;
57
 
58
architecture behavior of light8080_@PROGNAME@ is
59
 
60
--------------------------------------------------------------------------------
61
-- Simulation parameters
62
 
63
-- T: simulated clock period
64
constant T : time := 100 ns;
65
 
66
-- MAX_SIM_LENGTH: maximum simulation time
67
constant MAX_SIM_LENGTH : time := T*7000; -- enough for the tb0
68
 
69
 
70
--------------------------------------------------------------------------------
71
 
72
signal data_i :           std_logic_vector(7 downto 0) := (others=>'0');
73
signal vma_o  :           std_logic;
74
signal rd_o :             std_logic;
75
signal wr_o :             std_logic;
76
signal io_o :             std_logic;
77
signal data_o :           std_logic_vector(7 downto 0);
78
signal data_mem :         std_logic_vector(7 downto 0);
79
signal addr_o :           std_logic_vector(15 downto 0);
80
signal fetch_o :          std_logic;
81
signal inta_o :           std_logic;
82
signal inte_o :           std_logic;
83
signal intr_i :           std_logic := '0';
84
signal halt_o :           std_logic;
85
 
86
signal reset :            std_logic := '0';
87
signal clk :              std_logic := '1';
88
signal done :             std_logic := '0';
89
 
90
type t_obj_code is array(integer range <>) of std_logic_vector(7 downto 0);
91
 
92
-- 
93
signal obj_code : t_obj_code(0 to 6143) := (
94
 
95
--@rom_data
96
 
97
);
98
 
99
signal irq_vector_byte:   std_logic_vector(7 downto 0);
100
signal irq_source :       integer range 0 to 7;
101
signal cycles_to_intr :   integer range -10 to 255;
102
signal intr_width :       integer range 0 to 255;
103
signal int_vector_index : integer range 0 to 3;
104
signal addr_vector_table: integer range 0 to 65535;
105
 
106
signal con_line_buf :     string(1 to 80);
107
signal con_line_ix :      integer;
108
 
109
 
110
 
111
type t_ram is array(0 to 65536-1) of std_logic_vector(7 downto 0);
112
 
113
-- Using shared variables for big memory arrays speeds up simulation a lot;
114
-- see Modelsim 6.3 User Manual, section on 'Modelling Memory'.
115
-- WARNING: I have only tested this construct with Modelsim SE 6.3.
116
shared variable ram : t_ram := ( others => X"00");
117
 
118
procedure load_object_code(
119
                signal obj :    in t_obj_code;
120
                memory :        inout t_ram) is
121
variable i : integer;
122
begin
123
 
124
  -- (Assume the array is defined with ascending indices)
125
  for i in obj'left to obj'right loop
126
    memory(i) := obj(i);
127
  end loop;
128
 
129
end procedure load_object_code;
130
 
131
 
132
 
133
begin
134
 
135
  -- Instantiate the Unit Under Test (UUT)
136
  cpu: entity work.light8080
137
  port map (
138
    clk => clk,
139
    reset => reset,
140
    vma => vma_o,
141
    rd => rd_o,
142
    wr => wr_o,
143
    io => io_o,
144
    fetch => fetch_o,
145
    addr_out => addr_o,
146
    data_in => data_i,
147
    data_out => data_o,
148
 
149
    intr => intr_i,
150
    inte => inte_o,
151
    inta => inta_o,
152
    halt => halt_o
153
  );
154
 
155
 
156
-- clock: run clock until test is done
157
clock:
158
process(done, clk)
159
begin
160
  if done = '0' then
161
    clk <= not clk after T/2;
162
  end if;
163
end process clock;
164
 
165
 
166
-- Drive reset and done 
167
main_test:
168
process
169
begin
170
  -- Load object code on memory -- note this comsumes no simulated time
171
  load_object_code(obj_code, ram);
172
 
173
  -- Assert reset for at least one full clk period
174
  reset <= '1';
175
  wait until clk = '1';
176
  wait for T/2;
177
  reset <= '0';
178
 
179
  -- Remember to 'cut away' the preceding 3 clk semiperiods from 
180
  -- the wait statement...
181
  wait for (MAX_SIM_LENGTH - T*1.5);
182
 
183
  -- Maximum sim time elapsed, assume the program ran away and
184
  -- stop the clk process asserting 'done' (which will stop the simulation)
185
  done <= '1';
186
 
187
  assert (done = '1')
188
  report "Test timed out."
189
  severity failure;
190
 
191
  wait;
192
end process main_test;
193
 
194
 
195
-- Synchronous RAM covering the whole address map
196
synchronous_ram:
197
process(clk)
198
begin
199
  if (clk'event and clk='1') then
200
    data_mem <= ram(conv_integer(addr_o));
201
    if wr_o = '1' then
202
      ram(conv_integer(addr_o)) := data_o;
203
    end if;
204
  end if;
205
end process synchronous_ram;
206
 
207
 
208
irq_trigger_register:
209
process(clk)
210
begin
211
  if (clk'event and clk='1') then
212
    if reset='1' then
213
      cycles_to_intr <= -10; -- meaning no interrupt pending
214
    else
215
      if io_o='1' and wr_o='1' and addr_o(7 downto 0)=X"11" then
216
        cycles_to_intr <= conv_integer(data_o) + 1;
217
      else
218
        if cycles_to_intr >= 0 then
219
          cycles_to_intr <= cycles_to_intr - 1;
220
        end if;
221
      end if;
222
    end if;
223
  end if;
224
end process irq_trigger_register;
225
 
226
irq_pulse_width_register:
227
process(clk)
228
variable intr_pulse_countdown : integer;
229
begin
230
  if (clk'event and clk='1') then
231
    if reset='1' then
232
      intr_width <= 1;
233
      intr_pulse_countdown := 0;
234
      intr_i <= '0';
235
    else
236
      if io_o='1' and wr_o='1' and addr_o(7 downto 0)=X"12" then
237
        intr_width <= conv_integer(data_o) + 1;
238
      end if;
239
 
240
      if cycles_to_intr = 0 then
241
        intr_i <= '1';
242
        intr_pulse_countdown := intr_width;
243
      elsif intr_pulse_countdown <= 1 then
244
        intr_i <= '0';
245
      else
246
        intr_pulse_countdown := intr_pulse_countdown - 1;
247
      end if;
248
    end if;
249
  end if;
250
end process irq_pulse_width_register;
251
 
252
irq_source_register:
253
process(clk)
254
begin
255
  if (clk'event and clk='1') then
256
    if reset='1' then
257
      irq_source <= 0;
258
    else
259
      if io_o='1' and wr_o='1' and addr_o(7 downto 0)=X"10" then
260
        irq_source <= conv_integer(data_o(2 downto 0));
261
      end if;
262
    end if;
263
  end if;
264
end process irq_source_register;
265
 
266
 
267
-- 'interrupt vector' logic.
268
irq_vector_table:
269
process(clk)
270
begin
271
  if (clk'event and clk='1') then
272
    if vma_o = '1' and rd_o='1' then
273
      if inta_o = '1' then
274
        int_vector_index <= int_vector_index + 1;
275
      else
276
        int_vector_index <= 0;
277
      end if;
278
    end if;
279
    -- this is the address of the byte we'll feed to the CPU
280
    addr_vector_table <= 64+irq_source*4+int_vector_index;
281
  end if;
282
end process irq_vector_table;
283
irq_vector_byte <= ram(addr_vector_table);
284
 
285
data_i <= data_mem when inta_o='0' else irq_vector_byte;
286
 
287
 
288
test_outcome_register:
289
process(clk)
290
variable outcome : std_logic_vector(7 downto 0);
291
begin
292
  if (clk'event and clk='1') then
293
    if io_o='1' and wr_o='1' and addr_o(7 downto 0)=X"20" then
294
    assert (data_o /= X"55") report "Software reports SUCCESS" severity failure;
295
    assert (data_o /= X"aa") report "Software reports FAILURE" severity failure;
296
    assert ((data_o = X"aa") or (data_o = X"55"))
297
    report "Software reports unexpected outcome value."
298
    severity failure;
299
    end if;
300
  end if;
301
end process test_outcome_register;
302
 
303
 
304
dummy_uart_output_reg:
305
process(clk)
306
variable outcome : std_logic_vector(7 downto 0);
307
begin
308
  if (clk'event and clk='1') then
309
    if io_o='1' and wr_o='1' and addr_o(7 downto 0)=X"21" then
310
      -- append char to output string
311
      if con_line_ix < con_line_buf'high then
312
        con_line_buf(con_line_ix) <= character'val(conv_integer(data_o));
313
        con_line_ix <= con_line_ix + 1;
314
      end if;
315
    end if;
316
  end if;
317
end process dummy_uart_output_reg;
318
 
319
 
320
end;

powered by: WebSVN 2.1.0

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