forth-cpu
/
core.vhd
306 строк · 8.8 Кб
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--------------------------------------------------------------------------------
11
12library ieee, work;
13use ieee.std_logic_1164.all;
14use work.util.n_bits;
15use work.util.common_generics;
16use work.h2_pkg.all;
17
18package core_pkg is
19type cpu_debug_interface is record
20pc: address;
21insn: word;
22dwe: std_ulogic;
23dre: std_ulogic;
24din: word;
25dout: word;
26daddr: address;
27end record;
28
29component core is
30generic(g: common_generics; number_of_interrupts: positive := 8);
31port(
32-- synthesis translate_off
33debug: out cpu_debug_interface;
34-- synthesis translate_on
35
36clk: in std_ulogic;
37rst: in std_ulogic;
38
39stop: in std_ulogic; -- Halts the CPU
40
41io_wr: out std_ulogic; -- I/O Write enable
42io_re: out std_ulogic; -- hardware *READS* can have side effects
43io_din: in word;
44io_dout: out word:= (others => 'X');
45io_daddr: out word:= (others => 'X');
46
47-- Interrupts
48cpu_irc: in std_ulogic_vector(number_of_interrupts - 1 downto 0);
49cpu_irc_mask: in std_ulogic_vector(number_of_interrupts - 1 downto 0);
50cpu_irc_mask_we: in std_ulogic);
51end component;
52
53component interrupt_request_handler is
54generic(
55g: common_generics;
56number_of_interrupts: positive := 8;
57lowest_interrupt_first: boolean := true);
58port(
59clk: in std_ulogic;
60rst: in std_ulogic;
61
62irq_i: in std_ulogic;
63irc_i: in std_ulogic_vector(number_of_interrupts - 1 downto 0);
64
65mask: in std_ulogic_vector(number_of_interrupts - 1 downto 0);
66mask_we: in std_ulogic;
67
68irq_o: out std_ulogic;
69addr_o: out std_ulogic_vector(n_bits(number_of_interrupts) - 1 downto 0));
70end component;
71end package;
72
73----- CPU ----------------------------------------------------------------------
74library ieee,work;
75use ieee.std_logic_1164.all;
76use work.core_pkg.all;
77use work.h2_pkg.all;
78use work.util.n_bits;
79use work.util.common_generics;
80use work.util.file_format;
81use work.util.file_hex;
82use work.util.or_reduce;
83
84entity core is
85generic(g: common_generics; number_of_interrupts: positive := 8);
86port(
87-- synthesis translate_off
88debug: out cpu_debug_interface;
89-- synthesis translate_on
90
91clk: in std_ulogic;
92rst: in std_ulogic;
93
94stop: in std_ulogic; -- Halts the CPU
95
96io_wr: out std_ulogic; -- I/O Write enable
97io_re: out std_ulogic; -- hardware *READS* can have side effects
98io_din: in word;
99io_dout: out word := (others => 'X');
100io_daddr: out word := (others => 'X');
101
102-- Interrupts
103cpu_irc: in std_ulogic_vector(number_of_interrupts - 1 downto 0);
104cpu_irc_mask: in std_ulogic_vector(number_of_interrupts - 1 downto 0);
105cpu_irc_mask_we: in std_ulogic);
106end;
107
108architecture structural of core is
109constant interrupt_address_length: natural := n_bits(number_of_interrupts);
110constant file_name: string := "h2.hex";
111constant file_type: file_format := file_hex;
112signal pc: address := (others => '0'); -- Program counter
113signal insn: word := (others => '0'); -- Instruction issued by program counter
114signal dwe: std_ulogic := '0'; -- Write enable
115signal dre: std_ulogic := '0'; -- Read enable
116signal din: word := (others => '0');
117signal dout: word := (others => '0');
118signal daddr: address := (others => '0');
119signal irc_edges: std_ulogic_vector(cpu_irc'range) := (others => '0');
120signal irq_edges: std_ulogic := '0';
121signal h2_irq: std_ulogic := '0';
122signal h2_irq_addr: std_ulogic_vector(interrupt_address_length - 1 downto 0) := (others=>'0');
123begin
124-- synthesis translate_off
125debug.pc <= pc;
126debug.insn <= insn;
127debug.dwe <= dwe;
128debug.dre <= dre;
129debug.din <= din;
130debug.dout <= dout;
131debug.daddr <= daddr;
132-- synthesis translate_on
133
134-- Ensure all interrupts occur are rising edge triggered
135edges: work.util.rising_edge_detectors
136generic map(g => g, N => cpu_irc'length)
137port map(
138clk => clk,
139rst => rst,
140di => cpu_irc,
141do => irc_edges);
142
143irq_edges <= or_reduce(irc_edges);
144
145irqh_0: work.core_pkg.interrupt_request_handler
146generic map(g => g, number_of_interrupts => number_of_interrupts)
147port map(
148clk => clk,
149rst => rst,
150
151irq_i => irq_edges,
152irc_i => irc_edges,
153
154irq_o => h2_irq,
155addr_o => h2_irq_addr,
156
157mask => cpu_irc_mask,
158mask_we => cpu_irc_mask_we);
159
160h2_0: work.h2_pkg.h2 -- The actual CPU instance (H2)
161generic map(asynchronous_reset => g.asynchronous_reset, delay => g.delay, interrupt_address_length => interrupt_address_length)
162port map(
163clk => clk,
164rst => rst,
165
166-- External interface with the 'outside world'
167stop => stop,
168io_wr => io_wr,
169io_re => io_re,
170io_din => io_din,
171io_dout => io_dout,
172io_daddr => io_daddr,
173
174irq => h2_irq,
175irq_addr => h2_irq_addr,
176
177-- Instruction and instruction address to CPU
178pc => pc,
179insn => insn,
180-- Fetch/Store
181dwe => dwe,
182dre => dre,
183din => din,
184dout => dout,
185daddr => daddr);
186
187mem_h2_0: entity work.dual_port_block_ram
188generic map(
189g => g,
190addr_length => address'length,
191data_length => word'length,
192file_name => file_name,
193file_type => file_type)
194port map(
195-- Port A, Read only, CPU instruction/address
196a_clk => clk,
197a_dwe => '0',
198a_dre => '1',
199a_addr => pc,
200a_din => (others => '0'),
201a_dout => insn,
202-- Port B, Read/Write controlled by CPU instructions
203b_clk => clk,
204b_dwe => dwe,
205b_dre => dre,
206b_addr => daddr,
207b_din => dout,
208b_dout => din);
209
210end architecture;
211
212--------------------------------------------------------------------------------
213--| @brief Interrupt request handler, while the CPU can handle interrupts
214--| it does not to a good job of it. This allows customization of
215--| priority.
216--|
217--| @author Richard James Howe.
218--| @copyright Copyright 2017, 2019 Richard James Howe.
219--| @license MIT
220--| @email howe.r.j.89@gmail.com
221--|
222--| This is a simple interrupt handler, interrupts are decoded in priority
223--| order which can be set by a generic. If an interrupt occurs and then
224--| another interrupt of occurs before it has been processed the second
225--| interrupt will be lost.
226--|
227--------------------------------------------------------------------------------
228
229library ieee,work;
230use ieee.std_logic_1164.all;
231use ieee.numeric_std.all;
232use ieee.math_real.all; -- only needed for calculations relating to generics
233use work.util.reg;
234use work.util.n_bits;
235use work.util.select_bit;
236use work.util.priority;
237use work.util.common_generics;
238
239entity interrupt_request_handler is
240generic(
241g: common_generics;
242number_of_interrupts: positive := 8;
243lowest_interrupt_first: boolean := true);
244port(
245clk: in std_ulogic;
246rst: in std_ulogic;
247
248irq_i: in std_ulogic;
249irc_i: in std_ulogic_vector(number_of_interrupts - 1 downto 0);
250
251mask: in std_ulogic_vector(number_of_interrupts - 1 downto 0);
252mask_we: in std_ulogic;
253
254irq_o: out std_ulogic;
255addr_o: out std_ulogic_vector(n_bits(number_of_interrupts) - 1 downto 0));
256end;
257
258architecture rtl of interrupt_request_handler is
259constant addr_length: natural := n_bits(number_of_interrupts);
260signal irq_n: std_ulogic := '0';
261signal irc_n: std_ulogic_vector(irc_i'range) := (others => '0');
262
263signal addr: std_ulogic_vector(addr_length - 1 downto 0) := (others => '0');
264signal irq: std_ulogic := '0';
265
266signal mask_n: std_ulogic_vector(mask'range) := (others => '0');
267begin
268irq_in: entity work.reg
269generic map(g => g, N => 1)
270port map(
271clk => clk,
272rst => rst,
273we => '1',
274di(0) => irq_i,
275do(0) => irq_n);
276
277irc_in: entity work.reg
278generic map(g => g, N => number_of_interrupts)
279port map(
280clk => clk,
281rst => rst,
282we => '1',
283di => irc_i,
284do => irc_n);
285
286irc_mask: entity work.reg generic map(g => g, N => number_of_interrupts)
287port map(
288clk => clk,
289rst => rst,
290we => mask_we,
291di => mask,
292do => mask_n);
293
294process(irc_n, irq_n, mask_n)
295variable addr_n: std_ulogic_vector(addr'range) := (others => '0');
296begin
297addr_n := priority(irc_n, not lowest_interrupt_first);
298addr_o <= addr_n after g.delay;
299if select_bit(mask_n, addr_n) = '1' then
300irq_o <= irq_n after g.delay;
301else
302irq_o <= '0' after g.delay;
303end if;
304end process;
305
306end architecture;
307