OpenCores
URL https://opencores.org/ocsvn/forth-cpu/forth-cpu/trunk

Subversion Repositories forth-cpu

[/] [forth-cpu/] [trunk/] [core.vhd] - Rev 5

Compare with Previous | Blame | View Log

--------------------------------------------------------------------------------
--| @file core.vhd
--| @brief This contains the CPU, memory and interrupt handler instances
--|
--| @author     Richard James Howe.
--| @copyright  Copyright 2013,2017 Richard James Howe.
--| @license    MIT
--| @email      howe.r.j.89@gmail.com
--|
--------------------------------------------------------------------------------
 
library ieee, work;
use ieee.std_logic_1164.all;
use work.util.n_bits;
use work.util.common_generics;
use work.h2_pkg.all;
 
package core_pkg is
	type cpu_debug_interface is record
		pc:        address;
		insn:      word;
		dwe:       std_ulogic;
		dre:       std_ulogic;
		din:       word;
		dout:      word;
		daddr:     address;
	end record;
 
	component core is
	generic(g: common_generics; number_of_interrupts: positive := 8);
	port(
		-- synthesis translate_off
		debug:           out cpu_debug_interface;
		-- synthesis translate_on
 
		clk:             in   std_ulogic;
		rst:             in   std_ulogic;
 
		stop:            in   std_ulogic; -- Halts the CPU
 
		io_wr:           out  std_ulogic; -- I/O Write enable
		io_re:           out  std_ulogic; -- hardware *READS* can have side effects
		io_din:          in   word;
		io_dout:         out  word:= (others => 'X');
		io_daddr:        out  word:= (others => 'X');
 
		-- Interrupts
		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_we: in std_ulogic);
	end component;
 
	component interrupt_request_handler is
	generic(
		g: common_generics;
		number_of_interrupts:   positive := 8;
		lowest_interrupt_first: boolean  := true);
	port(
		clk:     in  std_ulogic;
		rst:     in  std_ulogic;
 
		irq_i:   in  std_ulogic;
		irc_i:   in  std_ulogic_vector(number_of_interrupts - 1 downto 0);
 
		mask:    in  std_ulogic_vector(number_of_interrupts - 1 downto 0);
		mask_we: in  std_ulogic;
 
		irq_o:   out std_ulogic;
		addr_o:  out std_ulogic_vector(n_bits(number_of_interrupts) - 1 downto 0));
	end component;
end package;
 
----- CPU ----------------------------------------------------------------------
library ieee,work;
use ieee.std_logic_1164.all;
use work.core_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_hex;
use work.util.or_reduce;
 
entity core is
	generic(g: common_generics; number_of_interrupts: positive := 8);
	port(
		-- synthesis translate_off
		debug:           out cpu_debug_interface;
		-- synthesis translate_on
 
		clk:             in   std_ulogic;
		rst:             in   std_ulogic;
 
		stop:            in   std_ulogic; -- Halts the CPU
 
		io_wr:           out  std_ulogic; -- I/O Write enable
		io_re:           out  std_ulogic; -- hardware *READS* can have side effects
		io_din:          in   word;
		io_dout:         out  word := (others => 'X');
		io_daddr:        out  word := (others => 'X');
 
		-- Interrupts
		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_we: in std_ulogic);
end;
 
architecture structural of core is
	constant interrupt_address_length: natural     := n_bits(number_of_interrupts);
	constant file_name:                string      := "h2.hex";
	constant file_type:                file_format := file_hex;
	signal pc:    address    := (others => '0'); -- Program counter
	signal insn:  word       := (others => '0'); -- Instruction issued by program counter
	signal dwe:   std_ulogic := '0'; -- Write enable
	signal dre:   std_ulogic := '0'; -- Read enable
	signal din:   word       := (others => '0');
	signal dout:  word       := (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_addr:  std_ulogic_vector(interrupt_address_length - 1 downto 0) := (others=>'0');
begin
	-- synthesis translate_off
	debug.pc    <= pc;
	debug.insn  <= insn;
	debug.dwe   <= dwe;
	debug.dre   <= dre;
	debug.din   <= din;
	debug.dout  <= dout;
	debug.daddr <= daddr;
	-- 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
	generic map(g => g, number_of_interrupts => number_of_interrupts)
	port map(
		clk    => clk,
		rst    => rst,
 
		irq_i  => irq_edges,
		irc_i  => irc_edges,
 
		irq_o  => h2_irq,
		addr_o => h2_irq_addr,
 
		mask    => cpu_irc_mask,
		mask_we => cpu_irc_mask_we);
 
	h2_0: work.h2_pkg.h2 -- The actual CPU instance (H2)
	generic map(asynchronous_reset => g.asynchronous_reset, delay => g.delay, interrupt_address_length => interrupt_address_length)
	port map(
		clk       =>    clk,
		rst       =>    rst,
 
		-- External interface with the 'outside world'
		stop      =>  stop,
		io_wr     =>  io_wr,
		io_re     =>  io_re,
		io_din    =>  io_din,
		io_dout   =>  io_dout,
		io_daddr  =>  io_daddr,
 
		irq       =>  h2_irq,
		irq_addr  =>  h2_irq_addr,
 
		-- Instruction and instruction address to CPU
		pc        =>  pc,
		insn      =>  insn,
		-- Fetch/Store
		dwe       =>  dwe,
		dre       =>  dre,
		din       =>  din,
		dout      =>  dout,
		daddr     =>  daddr);
 
	mem_h2_0: entity work.dual_port_block_ram
	generic map(
		g             => g,
		addr_length   => address'length,
		data_length   => word'length,
		file_name     => file_name,
		file_type     => file_type)
	port map(
		-- Port A, Read only, CPU instruction/address
		a_clk   =>    clk,
		a_dwe   =>    '0',
		a_dre   =>    '1',
		a_addr  =>    pc,
		a_din   =>    (others => '0'),
		a_dout  =>    insn,
		-- Port B, Read/Write controlled by CPU instructions
		b_clk   =>    clk,
		b_dwe   =>    dwe,
		b_dre   =>    dre,
		b_addr  =>    daddr,
		b_din   =>    dout,
		b_dout  =>    din);
 
end architecture;
 
--------------------------------------------------------------------------------
--| @brief Interrupt request handler, while the CPU can handle interrupts
--|        it does not to a good job of it. This allows customization of
--|        priority.
--|
--| @author     Richard James Howe.
--| @copyright  Copyright 2017, 2019 Richard James Howe.
--| @license    MIT
--| @email      howe.r.j.89@gmail.com
--|
--| 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
--| another interrupt of occurs before it has been processed the second
--| interrupt will be lost.
--|
--------------------------------------------------------------------------------
 
library ieee,work;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use ieee.math_real.all; -- only needed for calculations relating to generics
use work.util.reg;
use work.util.n_bits;
use work.util.select_bit;
use work.util.priority;
use work.util.common_generics;
 
entity interrupt_request_handler is
	generic(
		g: common_generics;
		number_of_interrupts:   positive := 8;
		lowest_interrupt_first: boolean  := true);
	port(
		clk:     in  std_ulogic;
		rst:     in  std_ulogic;
 
		irq_i:   in  std_ulogic;
		irc_i:   in  std_ulogic_vector(number_of_interrupts - 1 downto 0);
 
		mask:    in  std_ulogic_vector(number_of_interrupts - 1 downto 0);
		mask_we: in  std_ulogic;
 
		irq_o:   out std_ulogic;
		addr_o:  out std_ulogic_vector(n_bits(number_of_interrupts) - 1 downto 0));
end;
 
architecture rtl of interrupt_request_handler is
	constant addr_length: natural := n_bits(number_of_interrupts);
	signal irq_n: std_ulogic := '0';
	signal irc_n: std_ulogic_vector(irc_i'range) := (others => '0');
 
	signal addr:  std_ulogic_vector(addr_length - 1 downto 0) := (others => '0');
	signal irq:   std_ulogic := '0';
 
	signal mask_n: std_ulogic_vector(mask'range) := (others => '0');
begin
	irq_in: entity work.reg
		generic map(g => g, N  => 1)
		port map(
			clk    =>  clk,
			rst    =>  rst,
			we     =>  '1',
			di(0)  =>  irq_i,
			do(0)  =>  irq_n);
 
	irc_in: entity work.reg
		generic map(g => g, N  => number_of_interrupts)
		port map(
			clk  =>  clk,
			rst  =>  rst,
			we   =>  '1',
			di   =>  irc_i,
			do   =>  irc_n);
 
	irc_mask: entity work.reg generic map(g => g, N  => number_of_interrupts)
		port map(
			clk  =>  clk,
			rst  =>  rst,
			we   =>  mask_we,
			di   =>  mask,
			do   =>  mask_n);
 
	process(irc_n, irq_n, mask_n)
		variable addr_n: std_ulogic_vector(addr'range) := (others => '0');
	begin
		addr_n := priority(irc_n, not lowest_interrupt_first);
		addr_o <= addr_n after g.delay;
		if select_bit(mask_n, addr_n) = '1' then
			irq_o <= irq_n after g.delay;
		else
			irq_o <= '0' after g.delay;
		end if;
	end process;
 
end architecture;
 

Compare with Previous | Blame | View Log

powered by: WebSVN 2.1.0

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