Line 5... |
Line 5... |
--| @author Richard James Howe.
|
--| @author Richard James Howe.
|
--| @copyright Copyright 2013,2017 Richard James Howe.
|
--| @copyright Copyright 2013,2017 Richard James Howe.
|
--| @license MIT
|
--| @license MIT
|
--| @email howe.r.j.89@gmail.com
|
--| @email howe.r.j.89@gmail.com
|
--|
|
--|
|
--| @todo Make a test bench for the H2 core for executing small sections of
|
|
--| code, in succession, and testing the response.
|
|
--------------------------------------------------------------------------------
|
--------------------------------------------------------------------------------
|
|
|
library ieee,work;
|
library ieee,work;
|
use ieee.std_logic_1164.all;
|
use ieee.std_logic_1164.all;
|
use work.util.n_bits;
|
use work.util.n_bits;
|
|
use work.util.common_generics;
|
use work.h2_pkg.all;
|
use work.h2_pkg.all;
|
|
|
package core_pkg is
|
package core_pkg is
|
type cpu_debug_interface is record
|
type cpu_debug_interface is record
|
pc: address;
|
pc: address;
|
Line 26... |
Line 25... |
dout: word;
|
dout: word;
|
daddr: address;
|
daddr: address;
|
end record;
|
end record;
|
|
|
component core is
|
component core is
|
generic(number_of_interrupts: positive := 8);
|
generic(g: common_generics; number_of_interrupts: positive := 8);
|
port(
|
port(
|
-- synthesis translate_off
|
-- synthesis translate_off
|
debug: out cpu_debug_interface;
|
debug: out cpu_debug_interface;
|
-- synthesis translate_on
|
-- synthesis translate_on
|
|
|
Line 44... |
Line 43... |
io_din: in word;
|
io_din: in word;
|
io_dout: out word:= (others => 'X');
|
io_dout: out word:= (others => 'X');
|
io_daddr: out word:= (others => 'X');
|
io_daddr: out word:= (others => 'X');
|
|
|
-- Interrupts
|
-- Interrupts
|
cpu_irq: in std_ulogic;
|
|
cpu_irc: in std_ulogic_vector(number_of_interrupts - 1 downto 0);
|
cpu_irc: in std_ulogic_vector(number_of_interrupts - 1 downto 0);
|
cpu_irc_mask: in std_ulogic_vector(number_of_interrupts - 1 downto 0);
|
cpu_irc_mask: in std_ulogic_vector(number_of_interrupts - 1 downto 0);
|
cpu_irc_mask_we: in std_ulogic);
|
cpu_irc_mask_we: in std_ulogic);
|
end component;
|
end component;
|
|
|
component interrupt_request_handler is
|
component interrupt_request_handler is
|
generic(
|
generic(
|
|
g: common_generics;
|
number_of_interrupts: positive := 8;
|
number_of_interrupts: positive := 8;
|
lowest_interrupt_first: boolean := true);
|
lowest_interrupt_first: boolean := true);
|
port(
|
port(
|
clk: in std_ulogic;
|
clk: in std_ulogic;
|
rst: in std_ulogic;
|
rst: in std_ulogic;
|
Line 70... |
Line 69... |
addr_o: out std_ulogic_vector(n_bits(number_of_interrupts) - 1 downto 0));
|
addr_o: out std_ulogic_vector(n_bits(number_of_interrupts) - 1 downto 0));
|
end component;
|
end component;
|
end package;
|
end package;
|
|
|
----- CPU ----------------------------------------------------------------------
|
----- CPU ----------------------------------------------------------------------
|
|
|
library ieee,work;
|
library ieee,work;
|
use ieee.std_logic_1164.all;
|
use ieee.std_logic_1164.all;
|
use work.util.n_bits;
|
|
use work.core_pkg.all;
|
use work.core_pkg.all;
|
use work.h2_pkg.all;
|
use work.h2_pkg.all;
|
|
use work.util.n_bits;
|
|
use work.util.common_generics;
|
use work.util.file_format;
|
use work.util.file_format;
|
use work.util.FILE_HEX;
|
use work.util.file_hex;
|
|
use work.util.or_reduce;
|
|
|
entity core is
|
entity core is
|
generic(number_of_interrupts: positive := 8);
|
generic(g: common_generics; number_of_interrupts: positive := 8);
|
port(
|
port(
|
-- synthesis translate_off
|
-- synthesis translate_off
|
debug: out cpu_debug_interface;
|
debug: out cpu_debug_interface;
|
-- synthesis translate_on
|
-- synthesis translate_on
|
|
|
Line 98... |
Line 98... |
io_din: in word;
|
io_din: in word;
|
io_dout: out word := (others => 'X');
|
io_dout: out word := (others => 'X');
|
io_daddr: out word := (others => 'X');
|
io_daddr: out word := (others => 'X');
|
|
|
-- Interrupts
|
-- Interrupts
|
cpu_irq: in std_ulogic;
|
|
cpu_irc: in std_ulogic_vector(number_of_interrupts - 1 downto 0);
|
cpu_irc: in std_ulogic_vector(number_of_interrupts - 1 downto 0);
|
cpu_irc_mask: in std_ulogic_vector(number_of_interrupts - 1 downto 0);
|
cpu_irc_mask: in std_ulogic_vector(number_of_interrupts - 1 downto 0);
|
cpu_irc_mask_we: in std_ulogic);
|
cpu_irc_mask_we: in std_ulogic);
|
end;
|
end;
|
|
|
architecture structural of core is
|
architecture structural of core is
|
constant interrupt_address_length: natural := n_bits(number_of_interrupts);
|
constant interrupt_address_length: natural := n_bits(number_of_interrupts);
|
constant file_name: string := "h2.hex";
|
constant file_name: string := "h2.hex";
|
constant file_type: file_format := FILE_HEX;
|
constant file_type: file_format := file_hex;
|
|
|
signal pc: address := (others => '0'); -- Program counter
|
signal pc: address := (others => '0'); -- Program counter
|
signal insn: word := (others => '0'); -- Instruction issued by program counter
|
signal insn: word := (others => '0'); -- Instruction issued by program counter
|
signal dwe: std_ulogic := '0'; -- Write enable
|
signal dwe: std_ulogic := '0'; -- Write enable
|
signal dre: std_ulogic := '0'; -- Read enable
|
signal dre: std_ulogic := '0'; -- Read enable
|
signal din: word := (others => '0');
|
signal din: word := (others => '0');
|
signal dout: word := (others => '0');
|
signal dout: word := (others => '0');
|
signal daddr: address := (others => '0');
|
signal daddr: address := (others => '0');
|
|
signal irc_edges: std_ulogic_vector(cpu_irc'range) := (others => '0');
|
|
signal irq_edges: std_ulogic := '0';
|
signal h2_irq: std_ulogic := '0';
|
signal h2_irq: std_ulogic := '0';
|
signal h2_irq_addr: std_ulogic_vector(interrupt_address_length - 1 downto 0) := (others=>'0');
|
signal h2_irq_addr: std_ulogic_vector(interrupt_address_length - 1 downto 0) := (others=>'0');
|
begin
|
begin
|
-- synthesis translate_off
|
-- synthesis translate_off
|
debug.pc <= pc;
|
debug.pc <= pc;
|
Line 130... |
Line 129... |
debug.din <= din;
|
debug.din <= din;
|
debug.dout <= dout;
|
debug.dout <= dout;
|
debug.daddr <= daddr;
|
debug.daddr <= daddr;
|
-- synthesis translate_on
|
-- synthesis translate_on
|
|
|
|
-- Ensure all interrupts occur are rising edge triggered
|
|
edges: work.util.rising_edge_detectors
|
|
generic map(g => g, N => cpu_irc'length)
|
|
port map(
|
|
clk => clk,
|
|
rst => rst,
|
|
di => cpu_irc,
|
|
do => irc_edges);
|
|
|
|
irq_edges <= or_reduce(irc_edges);
|
|
|
irqh_0: work.core_pkg.interrupt_request_handler
|
irqh_0: work.core_pkg.interrupt_request_handler
|
generic map(number_of_interrupts => number_of_interrupts)
|
generic map(g => g, number_of_interrupts => number_of_interrupts)
|
port map(
|
port map(
|
clk => clk,
|
clk => clk,
|
rst => rst,
|
rst => rst,
|
|
|
irq_i => cpu_irq,
|
irq_i => irq_edges,
|
irc_i => cpu_irc,
|
irc_i => irc_edges,
|
|
|
irq_o => h2_irq,
|
irq_o => h2_irq,
|
addr_o => h2_irq_addr,
|
addr_o => h2_irq_addr,
|
|
|
mask => cpu_irc_mask,
|
mask => cpu_irc_mask,
|
mask_we => cpu_irc_mask_we);
|
mask_we => cpu_irc_mask_we);
|
|
|
h2_0: work.h2_pkg.h2 -- The actual CPU instance (H2)
|
h2_0: work.h2_pkg.h2 -- The actual CPU instance (H2)
|
generic map(interrupt_address_length => interrupt_address_length)
|
generic map(asynchronous_reset => g.asynchronous_reset, delay => g.delay, interrupt_address_length => interrupt_address_length)
|
port map(
|
port map(
|
clk => clk,
|
clk => clk,
|
rst => rst,
|
rst => rst,
|
|
|
-- External interface with the 'outside world'
|
-- External interface with the 'outside world'
|
Line 174... |
Line 184... |
dout => dout,
|
dout => dout,
|
daddr => daddr);
|
daddr => daddr);
|
|
|
mem_h2_0: entity work.dual_port_block_ram
|
mem_h2_0: entity work.dual_port_block_ram
|
generic map(
|
generic map(
|
|
g => g,
|
addr_length => address'length,
|
addr_length => address'length,
|
data_length => word'length,
|
data_length => word'length,
|
file_name => file_name,
|
file_name => file_name,
|
file_type => file_type)
|
file_type => file_type)
|
port map(
|
port map(
|
Line 202... |
Line 213... |
--| @brief Interrupt request handler, while the CPU can handle interrupts
|
--| @brief Interrupt request handler, while the CPU can handle interrupts
|
--| it does not to a good job of it. This allows customization of
|
--| it does not to a good job of it. This allows customization of
|
--| priority.
|
--| priority.
|
--|
|
--|
|
--| @author Richard James Howe.
|
--| @author Richard James Howe.
|
--| @copyright Copyright 2017 Richard James Howe.
|
--| @copyright Copyright 2017, 2019 Richard James Howe.
|
--| @license MIT
|
--| @license MIT
|
--| @email howe.r.j.89@gmail.com
|
--| @email howe.r.j.89@gmail.com
|
--|
|
--|
|
--| This is a simple interrupt handler, interrupts are decoded in priority
|
--| This is a simple interrupt handler, interrupts are decoded in priority
|
--| order which can be set by a generic. If an interrupt occurs and then
|
--| order which can be set by a generic. If an interrupt occurs and then
|
--| another interrupt of the same type occurs before it has been processed
|
--| another interrupt of occurs before it has been processed the second
|
--| the second interrupt will be lost.
|
--| interrupt will be lost.
|
--|
|
--|
|
--------------------------------------------------------------------------------
|
--------------------------------------------------------------------------------
|
|
|
library ieee,work;
|
library ieee,work;
|
use ieee.std_logic_1164.all;
|
use ieee.std_logic_1164.all;
|
Line 221... |
Line 232... |
use ieee.math_real.all; -- only needed for calculations relating to generics
|
use ieee.math_real.all; -- only needed for calculations relating to generics
|
use work.util.reg;
|
use work.util.reg;
|
use work.util.n_bits;
|
use work.util.n_bits;
|
use work.util.select_bit;
|
use work.util.select_bit;
|
use work.util.priority;
|
use work.util.priority;
|
|
use work.util.common_generics;
|
|
|
entity interrupt_request_handler is
|
entity interrupt_request_handler is
|
generic(
|
generic(
|
|
g: common_generics;
|
number_of_interrupts: positive := 8;
|
number_of_interrupts: positive := 8;
|
lowest_interrupt_first: boolean := true);
|
lowest_interrupt_first: boolean := true);
|
port(
|
port(
|
clk: in std_ulogic;
|
clk: in std_ulogic;
|
rst: in std_ulogic;
|
rst: in std_ulogic;
|
Line 250... |
Line 263... |
signal addr: std_ulogic_vector(addr_length - 1 downto 0) := (others => '0');
|
signal addr: std_ulogic_vector(addr_length - 1 downto 0) := (others => '0');
|
signal irq: std_ulogic := '0';
|
signal irq: std_ulogic := '0';
|
|
|
signal mask_n: std_ulogic_vector(mask'range) := (others => '0');
|
signal mask_n: std_ulogic_vector(mask'range) := (others => '0');
|
begin
|
begin
|
|
|
irq_in: entity work.reg
|
irq_in: entity work.reg
|
generic map(
|
generic map(g => g, N => 1)
|
N => 1)
|
|
port map(
|
port map(
|
clk => clk,
|
clk => clk,
|
rst => rst,
|
rst => rst,
|
we => '1',
|
we => '1',
|
di(0) => irq_i,
|
di(0) => irq_i,
|
do(0) => irq_n);
|
do(0) => irq_n);
|
|
|
irc_in: entity work.reg
|
irc_in: entity work.reg
|
generic map(
|
generic map(g => g, N => number_of_interrupts)
|
N => number_of_interrupts)
|
|
port map(
|
port map(
|
clk => clk,
|
clk => clk,
|
rst => rst,
|
rst => rst,
|
we => '1',
|
we => '1',
|
di => irc_i,
|
di => irc_i,
|
do => irc_n);
|
do => irc_n);
|
|
|
irc_mask: entity work.reg generic map(
|
irc_mask: entity work.reg generic map(g => g, N => number_of_interrupts)
|
N => number_of_interrupts)
|
|
port map(
|
port map(
|
clk => clk,
|
clk => clk,
|
rst => rst,
|
rst => rst,
|
we => mask_we,
|
we => mask_we,
|
di => mask,
|
di => mask,
|
Line 284... |
Line 293... |
|
|
process(irc_n, irq_n, mask_n)
|
process(irc_n, irq_n, mask_n)
|
variable addr_n: std_ulogic_vector(addr'range) := (others => '0');
|
variable addr_n: std_ulogic_vector(addr'range) := (others => '0');
|
begin
|
begin
|
addr_n := priority(irc_n, not lowest_interrupt_first);
|
addr_n := priority(irc_n, not lowest_interrupt_first);
|
addr <= addr_n;
|
addr_o <= addr_n after g.delay;
|
if select_bit(mask_n, addr_n) = '1' then
|
if select_bit(mask_n, addr_n) = '1' then
|
irq <= irq_n;
|
irq_o <= irq_n after g.delay;
|
else
|
else
|
irq <= '0';
|
irq_o <= '0' after g.delay;
|
end if;
|
end if;
|
end process;
|
end process;
|
|
|
irq_out: entity work.reg
|
|
generic map(
|
|
N => 1)
|
|
port map(
|
|
clk => clk,
|
|
rst => rst,
|
|
we => '1',
|
|
di(0) => irq,
|
|
do(0) => irq_o);
|
|
|
|
addr_out: entity work.reg
|
|
generic map(
|
|
N => addr_length)
|
|
port map(
|
|
clk => clk,
|
|
rst => rst,
|
|
we => '1',
|
|
di => addr,
|
|
do => addr_o);
|
|
|
|
end architecture;
|
end architecture;
|
|
|
No newline at end of file
|
No newline at end of file
|