Project

General

Profile

Download (8.62 KB) Statistics
| Branch: | Tag: | Revision:
1
--------------------------------------------------------------------------------
2
--| @file core.vhd
3
--| @brief This contains the CPU, memory and interrupt handler instances
4
--|
5
--| @author     Richard James Howe.
6
--| @copyright  Copyright 2013,2017 Richard James Howe.
7
--| @license    MIT
8
--| @email      howe.r.j.89@gmail.com
9
--|
10
--| @todo Make a test bench for the H2 core for executing small sections of
11
--| code, in succession, and testing the response. 
12
--------------------------------------------------------------------------------
13

    
14
library ieee,work;
15
use ieee.std_logic_1164.all;
16
use work.util.n_bits;
17
use work.h2_pkg.all;
18

    
19
package core_pkg is
20
	type cpu_debug_interface is record
21
		pc:        address;
22
		insn:      word;
23
		dwe:       std_ulogic;
24
		dre:       std_ulogic;
25
		din:       word;
26
		dout:      word;
27
		daddr:     address;
28
	end record;
29

    
30
	component core is
31
	generic(number_of_interrupts: positive := 8);
32
	port(
33
		-- synthesis translate_off
34
		debug:           out cpu_debug_interface;
35
		-- synthesis translate_on
36

    
37
		clk:             in   std_ulogic;
38
		rst:             in   std_ulogic;
39

    
40
		stop:            in   std_ulogic; -- Halts the CPU
41

    
42
		io_wr:           out  std_ulogic; -- I/O Write enable
43
		io_re:           out  std_ulogic; -- hardware *READS* can have side effects
44
		io_din:          in   word;
45
		io_dout:         out  word:= (others => 'X');
46
		io_daddr:        out  word:= (others => 'X');
47

    
48
		-- Interrupts
49
		cpu_irq:         in std_ulogic;
50
		cpu_irc:         in std_ulogic_vector(number_of_interrupts - 1 downto 0);
51
		cpu_irc_mask:    in std_ulogic_vector(number_of_interrupts - 1 downto 0);
52
		cpu_irc_mask_we: in std_ulogic);
53
	end component;
54

    
55
	component interrupt_request_handler is
56
	generic(
57
		number_of_interrupts:   positive := 8;
58
		lowest_interrupt_first: boolean  := true);
59
	port(
60
		clk:     in  std_ulogic;
61
		rst:     in  std_ulogic;
62

    
63
		irq_i:   in  std_ulogic;
64
		irc_i:   in  std_ulogic_vector(number_of_interrupts - 1 downto 0);
65

    
66
		mask:    in  std_ulogic_vector(number_of_interrupts - 1 downto 0);
67
		mask_we: in  std_ulogic;
68

    
69
		irq_o:   out std_ulogic;
70
		addr_o:  out std_ulogic_vector(n_bits(number_of_interrupts) - 1 downto 0));
71
	end component;
72
end package;
73

    
74
----- CPU ----------------------------------------------------------------------
75

    
76
library ieee,work;
77
use ieee.std_logic_1164.all;
78
use work.util.n_bits;
79
use work.core_pkg.all;
80
use work.h2_pkg.all;
81
use work.util.file_format;
82
use work.util.FILE_HEX;
83

    
84
entity core is
85
	generic(number_of_interrupts: positive := 8);
86
	port(
87
		-- synthesis translate_off
88
		debug:           out cpu_debug_interface;
89
		-- synthesis translate_on
90

    
91
		clk:             in   std_ulogic;
92
		rst:             in   std_ulogic;
93

    
94
		stop:            in   std_ulogic; -- Halts the CPU
95

    
96
		io_wr:           out  std_ulogic; -- I/O Write enable
97
		io_re:           out  std_ulogic; -- hardware *READS* can have side effects
98
		io_din:          in   word;
99
		io_dout:         out  word := (others => 'X');
100
		io_daddr:        out  word := (others => 'X');
101

    
102
		-- Interrupts
103
		cpu_irq:         in std_ulogic;
104
		cpu_irc:         in std_ulogic_vector(number_of_interrupts - 1 downto 0);
105
		cpu_irc_mask:    in std_ulogic_vector(number_of_interrupts - 1 downto 0);
106
		cpu_irc_mask_we: in std_ulogic);
107
end;
108

    
109
architecture structural of core is
110
	constant interrupt_address_length: natural     := n_bits(number_of_interrupts);
111
	constant file_name:                string      := "h2.hex";
112
	constant file_type:                file_format := FILE_HEX;
113

    
114
	signal pc:    address   := (others => '0'); -- Program counter
115
	signal insn:  word      := (others => '0'); -- Instruction issued by program counter
116
	signal dwe:   std_ulogic := '0'; -- Write enable
117
	signal dre:   std_ulogic := '0'; -- Read enable
118
	signal din:   word      := (others => '0');
119
	signal dout:  word      := (others => '0');
120
	signal daddr: address   := (others => '0');
121

    
122
	signal h2_irq:       std_ulogic := '0';
123
	signal h2_irq_addr:  std_ulogic_vector(interrupt_address_length - 1 downto 0) := (others=>'0');
124
begin
125
	-- synthesis translate_off
126
	debug.pc    <= pc;
127
	debug.insn  <= insn;
128
	debug.dwe   <= dwe;
129
	debug.dre   <= dre;
130
	debug.din   <= din;
131
	debug.dout  <= dout;
132
	debug.daddr <= daddr;
133
	-- synthesis translate_on
134

    
135
	irqh_0: work.core_pkg.interrupt_request_handler
136
	generic map(number_of_interrupts => number_of_interrupts)
137
	port map(
138
		clk    => clk,
139
		rst    => rst,
140

    
141
		irq_i  => cpu_irq,
142
		irc_i  => cpu_irc,
143

    
144
		irq_o  => h2_irq,
145
		addr_o => h2_irq_addr,
146

    
147
		mask    => cpu_irc_mask,
148
		mask_we => cpu_irc_mask_we);
149

    
150
	h2_0: work.h2_pkg.h2 -- The actual CPU instance (H2)
151
	generic map(interrupt_address_length => interrupt_address_length)
152
	port map(
153
		clk       =>    clk,
154
		rst       =>    rst,
155

    
156
		-- External interface with the 'outside world'
157
		stop      =>  stop,
158
		io_wr     =>  io_wr,
159
		io_re     =>  io_re,
160
		io_din    =>  io_din,
161
		io_dout   =>  io_dout,
162
		io_daddr  =>  io_daddr,
163

    
164
		irq       =>  h2_irq,
165
		irq_addr  =>  h2_irq_addr,
166

    
167
		-- Instruction and instruction address to CPU
168
		pc        =>  pc,
169
		insn      =>  insn,
170
		-- Fetch/Store
171
		dwe       =>  dwe,
172
		dre       =>  dre,
173
		din       =>  din,
174
		dout      =>  dout,
175
		daddr     =>  daddr);
176

    
177
	mem_h2_0: entity work.dual_port_block_ram
178
	generic map(
179
		addr_length   => address'length,
180
		data_length   => word'length,
181
		file_name     => file_name,
182
		file_type     => file_type)
183
	port map(
184
		-- Port A, Read only, CPU instruction/address
185
		a_clk   =>    clk,
186
		a_dwe   =>    '0',
187
		a_dre   =>    '1',
188
		a_addr  =>    pc,
189
		a_din   =>    (others => '0'),
190
		a_dout  =>    insn,
191
		-- Port B, Read/Write controlled by CPU instructions
192
		b_clk   =>    clk,
193
		b_dwe   =>    dwe,
194
		b_dre   =>    dre,
195
		b_addr  =>    daddr,
196
		b_din   =>    dout,
197
		b_dout  =>    din);
198

    
199
end architecture;
200

    
201
--------------------------------------------------------------------------------
202
--| @brief Interrupt request handler, while the CPU can handle interrupts
203
--|        it does not to a good job of it. This allows customization of
204
--|        priority.
205
--|
206
--| @author     Richard James Howe.
207
--| @copyright  Copyright 2017 Richard James Howe.
208
--| @license    MIT
209
--| @email      howe.r.j.89@gmail.com
210
--|
211
--| This is a simple interrupt handler, interrupts are decoded in priority
212
--| order which can be set by a generic. If an interrupt occurs and then
213
--| another interrupt of the same type occurs before it has been processed
214
--| the second interrupt will be lost.
215
--|
216
--------------------------------------------------------------------------------
217

    
218
library ieee,work;
219
use ieee.std_logic_1164.all;
220
use ieee.numeric_std.all;
221
use ieee.math_real.all; -- only needed for calculations relating to generics
222
use work.util.reg;
223
use work.util.n_bits;
224
use work.util.select_bit;
225
use work.util.priority;
226

    
227
entity interrupt_request_handler is
228
	generic(
229
		number_of_interrupts:   positive := 8;
230
		lowest_interrupt_first: boolean  := true);
231
	port(
232
		clk:     in  std_ulogic;
233
		rst:     in  std_ulogic;
234

    
235
		irq_i:   in  std_ulogic;
236
		irc_i:   in  std_ulogic_vector(number_of_interrupts - 1 downto 0);
237

    
238
		mask:    in  std_ulogic_vector(number_of_interrupts - 1 downto 0);
239
		mask_we: in  std_ulogic;
240

    
241
		irq_o:   out std_ulogic;
242
		addr_o:  out std_ulogic_vector(n_bits(number_of_interrupts) - 1 downto 0));
243
end;
244

    
245
architecture rtl of interrupt_request_handler is
246
	constant addr_length: natural := n_bits(number_of_interrupts);
247
	signal irq_n: std_ulogic := '0';
248
	signal irc_n: std_ulogic_vector(irc_i'range) := (others => '0');
249

    
250
	signal addr:  std_ulogic_vector(addr_length - 1 downto 0) := (others => '0');
251
	signal irq:   std_ulogic := '0';
252

    
253
	signal mask_n: std_ulogic_vector(mask'range) := (others => '0');
254
begin
255

    
256
	irq_in: entity work.reg
257
		generic map(
258
			N      => 1)
259
		port map(
260
			clk    =>  clk,
261
			rst    =>  rst,
262
			we     =>  '1',
263
			di(0)  =>  irq_i,
264
			do(0)  =>  irq_n);
265

    
266
	irc_in: entity work.reg
267
		generic map(
268
			N    => number_of_interrupts)
269
		port map(
270
			clk  =>  clk,
271
			rst  =>  rst,
272
			we   =>  '1',
273
			di   =>  irc_i,
274
			do   =>  irc_n);
275

    
276
	irc_mask: entity work.reg generic map(
277
			N    => number_of_interrupts)
278
		port map(
279
			clk  =>  clk,
280
			rst  =>  rst,
281
			we   =>  mask_we,
282
			di   =>  mask,
283
			do   =>  mask_n);
284

    
285
	process(irc_n, irq_n, mask_n)
286
		variable addr_n: std_ulogic_vector(addr'range) := (others => '0');
287
	begin
288
		addr_n := priority(irc_n, not lowest_interrupt_first);
289
		addr <= addr_n;
290
		if select_bit(mask_n, addr_n) = '1' then
291
			irq <= irq_n;
292
		else
293
			irq <= '0';
294
		end if;
295
	end process;
296

    
297
	irq_out: entity work.reg
298
		generic map(
299
			N      => 1)
300
		port map(
301
			clk    =>  clk,
302
			rst    =>  rst,
303
			we     =>  '1',
304
			di(0)  =>  irq,
305
			do(0)  =>  irq_o);
306

    
307
	addr_out: entity work.reg
308
		generic map(
309
			N      => addr_length)
310
		port map(
311
			clk    =>  clk,
312
			rst    =>  rst,
313
			we     =>  '1',
314
			di     =>  addr,
315
			do     =>  addr_o);
316

    
317
end architecture;
(1-1/21)