245 lines
7.8 KiB
VHDL
245 lines
7.8 KiB
VHDL
-- See the file "LICENSE" for the full license governing this code. --
|
|
|
|
library ieee;
|
|
use ieee.std_logic_1164.all;
|
|
use ieee.numeric_std.all;
|
|
use work.lt16x32_internal.all;
|
|
use work.lt16x32_global.all;
|
|
|
|
-- the core bundles all entities inside the core itself
|
|
entity core is
|
|
port(
|
|
-- clock signal
|
|
clk : in std_logic;
|
|
-- reset signal, active high, synchronous
|
|
rst : in std_logic;
|
|
-- external stall signal, active high, synchronous
|
|
stall : in std_logic;
|
|
|
|
-- signals from data memory
|
|
in_dmem : in dmem_core;
|
|
-- signals to data memory
|
|
out_dmem : out core_dmem;
|
|
|
|
-- signals from instruction memory
|
|
in_imem : in imem_core;
|
|
-- signals to instruction memory
|
|
out_imem : out core_imem;
|
|
|
|
-- signals from interrupt controller
|
|
in_irq : in irq_core;
|
|
-- signals to interrupt controller
|
|
out_irq : out core_irq;
|
|
|
|
-- hardfault signal, active high
|
|
hardfault : out std_logic
|
|
);
|
|
end entity core;
|
|
|
|
architecture RTL of core is
|
|
component datapath
|
|
port(clk : in std_logic;
|
|
rst : in std_logic;
|
|
stall : in std_logic;
|
|
out_dec : out dp_dec;
|
|
in_cp : in cp_dp;
|
|
out_cp : out dp_cp;
|
|
in_pc : in pc_dp;
|
|
out_pc : out dp_pc;
|
|
in_dmem : in dmem_dp;
|
|
out_dmem : out dp_dmem;
|
|
hardfault : out std_logic);
|
|
end component datapath;
|
|
component controlpath
|
|
port(clk : in std_logic;
|
|
rst : in std_logic;
|
|
stall : in std_logic;
|
|
in_dec : in dec_cp;
|
|
out_dec : out cp_dec;
|
|
out_dp : out cp_dp;
|
|
out_pc : out cp_pc;
|
|
out_dmem : out cp_dmem;
|
|
in_dp : in dp_cp;
|
|
hardfault : out std_logic);
|
|
end component controlpath;
|
|
component decoder
|
|
port(clk : in std_logic;
|
|
rst : in std_logic;
|
|
stall : in std_logic;
|
|
in_imem : in imem_dec;
|
|
in_dp : in dp_dec;
|
|
in_cp : in cp_dec;
|
|
out_cp : out dec_cp;
|
|
out_pc : out dec_pc;
|
|
out_imem : out dec_imem;
|
|
in_irq : in irq_dec;
|
|
out_irq : out dec_irq);
|
|
end component decoder;
|
|
component programcounter
|
|
port(clk : in std_logic;
|
|
rst : in std_logic;
|
|
stall : in std_logic;
|
|
in_cp : in cp_pc;
|
|
in_dp : in dp_pc;
|
|
in_dec : in dec_pc;
|
|
out_dp : out pc_dp;
|
|
out_imem : out pc_imem);
|
|
end component programcounter;
|
|
|
|
-- signals between instances
|
|
signal dp_cp_signal : dp_cp;
|
|
signal dp_dmem_signal : dp_dmem;
|
|
signal dmem_dp_signal : dmem_dp;
|
|
signal imem_dec_signal : imem_dec;
|
|
signal dec_cp_signal : dec_cp;
|
|
signal dec_imem_signal : dec_imem;
|
|
signal cp_dp_signal : cp_dp;
|
|
signal cp_dmem_signal : cp_dmem;
|
|
signal cp_dec_signal : cp_dec;
|
|
signal pc_dp_signal : pc_dp;
|
|
signal dp_pc_signal : dp_pc;
|
|
signal dec_pc_signal : dec_pc;
|
|
signal pc_imem_signal : pc_imem;
|
|
signal cp_pc_signal : cp_pc;
|
|
signal irq_dec_signal : irq_dec;
|
|
signal dec_irq_signal : dec_irq;
|
|
signal dp_dec_signal : dp_dec;
|
|
|
|
signal hardfault_dp : std_logic;
|
|
signal hardfault_cp : std_logic;
|
|
|
|
-- general halt signal
|
|
signal stall_internal : std_logic;
|
|
begin
|
|
-- configuration tests
|
|
|
|
-- irq_num_width must be smaller than or equal to 6 to fit into first byte of SR
|
|
assert (irq_prio_width <= 6) report "irq_prio_width must be <= 6." severity failure;
|
|
-- irq_num_width must fit into immediate
|
|
assert (irq_num_width < dec_cp_signal.s2.immediate'high) report "irq_num_width must be <= " & integer'image(dec_cp_signal.s2.immediate'high - 1) & "." severity failure;
|
|
-- reg_width must be 8, 16 or 32bit
|
|
assert ((reg_width = 8) or (reg_width = 16) or (reg_width = 32)) report "selected reg_width is not allowed. allowed values are 8, 16, 32, 64." severity failure;
|
|
-- pc must fit into register
|
|
assert (pc_width <= reg_width) report "pc_width must be smaller than or equal to reg_width." severity failure;
|
|
|
|
-- component instantiation
|
|
datapath_inst : component datapath
|
|
port map(clk => clk,
|
|
rst => rst,
|
|
stall => stall_internal,
|
|
out_dec => dp_dec_signal,
|
|
in_cp => cp_dp_signal,
|
|
out_cp => dp_cp_signal,
|
|
in_pc => pc_dp_signal,
|
|
out_pc => dp_pc_signal,
|
|
in_dmem => dmem_dp_signal,
|
|
out_dmem => dp_dmem_signal,
|
|
hardfault => hardfault_dp);
|
|
|
|
controlpath_inst : component controlpath
|
|
port map(clk => clk,
|
|
rst => rst,
|
|
stall => stall_internal,
|
|
in_dec => dec_cp_signal,
|
|
out_dec => cp_dec_signal,
|
|
out_dp => cp_dp_signal,
|
|
out_pc => cp_pc_signal,
|
|
out_dmem => cp_dmem_signal,
|
|
in_dp => dp_cp_signal,
|
|
hardfault => hardfault_cp);
|
|
|
|
decoder_inst : component decoder
|
|
port map(clk => clk,
|
|
rst => rst,
|
|
stall => stall_internal,
|
|
in_imem => imem_dec_signal,
|
|
in_dp => dp_dec_signal,
|
|
in_cp => cp_dec_signal,
|
|
out_cp => dec_cp_signal,
|
|
out_pc => dec_pc_signal,
|
|
out_imem => dec_imem_signal,
|
|
in_irq => irq_dec_signal,
|
|
out_irq => dec_irq_signal);
|
|
|
|
programcounter_inst : component programcounter
|
|
port map(clk => clk,
|
|
rst => rst,
|
|
stall => stall_internal,
|
|
in_cp => cp_pc_signal,
|
|
in_dp => dp_pc_signal,
|
|
in_dec => dec_pc_signal,
|
|
out_dp => pc_dp_signal,
|
|
out_imem => pc_imem_signal);
|
|
|
|
-- signals from data memory
|
|
dmem_dp_signal.read_data <= in_dmem.read_data;
|
|
|
|
-- signals to data memory
|
|
out_dmem.read_addr <= dp_dmem_signal.read_addr;
|
|
out_dmem.read_size <= to_stdlogicvector(cp_dmem_signal.read_size);
|
|
out_dmem.write_addr <= dp_dmem_signal.write_addr;
|
|
out_dmem.write_data <= dp_dmem_signal.write_data;
|
|
out_dmem.write_size <= to_stdlogicvector(cp_dmem_signal.write_size);
|
|
|
|
-- dmem read enable is overwritten if stall is active
|
|
dmem_read_en : with stall select out_dmem.read_en <=
|
|
'0' when '1',
|
|
cp_dmem_signal.read_en when others;
|
|
-- dmem write enable is overwritten if stall is active
|
|
dmem_write_en : with stall select out_dmem.write_en <=
|
|
'0' when '1',
|
|
cp_dmem_signal.write_en when others;
|
|
|
|
-- signals from instruction memory
|
|
imem_dec_signal.read_data <= in_imem.read_data;
|
|
imem_dec_signal.ready <= in_imem.ready;
|
|
|
|
-- signals to instruction memory
|
|
|
|
-- fill imem address, if pc width is smaller than memory width
|
|
-- all warnings of the type "Null range" can be safely ignored for pc_width = mem_width
|
|
imem_addr_fill : if (pc_width < mem_width) generate
|
|
out_imem.read_addr(mem_width - 1 downto pc_width) <= (others => '0');
|
|
end generate imem_addr_fill;
|
|
|
|
out_imem.read_addr(pc_width - 1 downto 0) <= std_logic_vector(pc_imem_signal.value);
|
|
-- imem read enable is overwritten if stall is active
|
|
imem_read_en : with stall_internal select out_imem.read_en <=
|
|
'0' when '1',
|
|
dec_imem_signal.en when others;
|
|
|
|
-- the halfword flag needs a delay as it refers to last clock cycles imem address
|
|
-- (the corresponding data is read in this clock cycle)
|
|
halfword_delay : process(clk) is
|
|
begin
|
|
if (rising_edge(clk)) then
|
|
if (rst = '1') then
|
|
-- reset to zero
|
|
imem_dec_signal.instruction_halfword_select <= '0';
|
|
elsif (stall_internal = '0') then
|
|
-- set to pc_value(1)
|
|
imem_dec_signal.instruction_halfword_select <= pc_imem_signal.value(1);
|
|
--! else? --TF
|
|
end if;
|
|
end if;
|
|
end process halfword_delay;
|
|
|
|
-- signals from interrupt controller
|
|
irq_dec_signal.num <= in_irq.num;
|
|
irq_dec_signal.priority <= in_irq.priority;
|
|
irq_dec_signal.req <= in_irq.req;
|
|
irq_dec_signal.nmi <= in_irq.nmi;
|
|
|
|
-- signals to interrupt controller
|
|
out_irq.ack <= dec_irq_signal.ack;
|
|
out_irq.trap_num <= dec_irq_signal.trap_num;
|
|
out_irq.trap_req <= dec_irq_signal.trap_req;
|
|
|
|
-- stall if dmem not ready, imem not ready is handled in decoder_fsm
|
|
stall_internal <= (not in_dmem.ready) or stall;
|
|
|
|
-- hardfault logic
|
|
hardfault <= hardfault_cp or hardfault_dp;
|
|
|
|
end architecture RTL;
|