Line 19... |
Line 19... |
-- # RTE instruction (or ERET)
|
-- # RTE instruction (or ERET)
|
-- # Most of the CP0 registers and of course all of the CP1
|
-- # Most of the CP0 registers and of course all of the CP1
|
-- # External interrupts
|
-- # External interrupts
|
--
|
--
|
--### Things implemented but not tested
|
--### Things implemented but not tested
|
-- # Memory pause input
|
-- # Memory pause input -- not tested with a real cache
|
--
|
--
|
--### Things with provisional implementation
|
--### Things with provisional implementation
|
--
|
--
|
-- 1.- Load interlocks: the pipeline is stalled for every load instruction, even
|
-- 1.- Load interlocks: the pipeline is stalled for every load instruction, even
|
-- if the target register is not used in the following instruction. So that
|
-- if the target register is not used in the following instruction. So that
|
Line 180... |
Line 180... |
|
|
signal load_interlock : std_logic;
|
signal load_interlock : std_logic;
|
signal stall_pipeline : std_logic;
|
signal stall_pipeline : std_logic;
|
-- pipeline is stalled for any reason
|
-- pipeline is stalled for any reason
|
signal pipeline_stalled : std_logic;
|
signal pipeline_stalled : std_logic;
|
|
|
|
signal stalled_memwait : std_logic;
|
|
signal stalled_muldiv : std_logic;
|
-- pipeline is stalled because of a load instruction interlock
|
-- pipeline is stalled because of a load instruction interlock
|
signal pipeline_interlocked:std_logic;
|
signal stalled_interlock : std_logic;
|
|
|
|
|
--------------------------------------------------------------------------------
|
--------------------------------------------------------------------------------
|
-- CP0 registers and signals
|
-- CP0 registers and signals
|
|
|
-- CP0[12]: status register
|
-- CP0[12]: status register
|
Line 271... |
Line 275... |
-- If target register is $zero, ignore write
|
-- If target register is $zero, ignore write
|
p1_rbank_wr_addr/="00000" and
|
p1_rbank_wr_addr/="00000" and
|
-- if the cache controller keeps the cpu stopped, do
|
-- if the cache controller keeps the cpu stopped, do
|
-- not writeback
|
-- not writeback
|
mem_wait='0' and
|
mem_wait='0' and
|
|
-- if stalled because of muldiv, block writeback
|
|
stalled_muldiv='0' and --@note1
|
-- on exception, abort next instruction (by preventing
|
-- on exception, abort next instruction (by preventing
|
-- regbank writeback).
|
-- regbank writeback).
|
p2_exception='0'
|
p2_exception='0'
|
else '0';
|
else '0';
|
|
|
Line 283... |
Line 289... |
-- FPGA has 3-port BRAMS, or has none.
|
-- FPGA has 3-port BRAMS, or has none.
|
synchronous_reg_bank:
|
synchronous_reg_bank:
|
process(clk)
|
process(clk)
|
begin
|
begin
|
if clk'event and clk='1' then
|
if clk'event and clk='1' then
|
if p1_rbank_we='1' and
|
if p1_rbank_we='1' then
|
(pipeline_stalled='0' or pipeline_interlocked='1') then -- @note1
|
|
p1_rbank(conv_integer(p1_rbank_wr_addr)) <= p1_rbank_wr_data;
|
p1_rbank(conv_integer(p1_rbank_wr_addr)) <= p1_rbank_wr_data;
|
end if;
|
end if;
|
|
-- the rbank read port loads in the same conditions as the IR: don't
|
|
-- update Rs or Rt if the pipeline is frozen
|
|
if stall_pipeline='0' then
|
p1_rt_rbank <= p1_rbank(conv_integer(p0_rt_num));
|
p1_rt_rbank <= p1_rbank(conv_integer(p0_rt_num));
|
p1_rs_rbank <= p1_rbank(conv_integer(p0_rs_num));
|
p1_rs_rbank <= p1_rbank(conv_integer(p0_rs_num));
|
end if;
|
end if;
|
|
end if;
|
end process synchronous_reg_bank;
|
end process synchronous_reg_bank;
|
|
|
-- Register writeback data in case it needs to be forwarded.
|
-- Register writeback data in case it needs to be forwarded.
|
data_forward_register:
|
data_forward_register:
|
process(clk)
|
process(clk)
|
Line 425... |
Line 434... |
process(clk)
|
process(clk)
|
begin
|
begin
|
if clk'event and clk='1' then
|
if clk'event and clk='1' then
|
if reset='1' then
|
if reset='1' then
|
-- reset to 0xffffffff so that 1st fetch addr is 0x00000000
|
-- reset to 0xffffffff so that 1st fetch addr is 0x00000000
|
|
-- FIXME reset vector is hardcoded
|
p0_pc_reg <= (others => '1');
|
p0_pc_reg <= (others => '1');
|
else
|
else
|
-- p0_pc_reg holds the same value as external sync ram addr register
|
-- p0_pc_reg holds the same value as external sync ram addr register
|
p0_pc_reg <= p0_pc_next;
|
p0_pc_reg <= p0_pc_next;
|
-- p0_pc_restart = addr saved to EPC on interrupts (@note2)
|
-- p0_pc_restart = addr saved to EPC on interrupts (@note2)
|
Line 808... |
Line 818... |
|
|
--------------------------------------------------------------------------------
|
--------------------------------------------------------------------------------
|
|
|
-- FIXME stall when needed: mem pause, mdiv pause and load interlock
|
-- FIXME stall when needed: mem pause, mdiv pause and load interlock
|
|
|
|
|
|
-- FIXME make sure this combinational will not have bad glitches
|
|
stall_pipeline <= mem_wait or load_interlock or p1_muldiv_stall;
|
|
|
|
|
|
-- FIXME load interlock should happen only if the instruction following
|
|
-- the load actually uses the load target register. Something like this:
|
|
-- (p1_do_load='1' and (p1_rd_num=p0_rs_num or p1_rd_num=p0_rt_num))
|
|
load_interlock <= '1' when
|
|
p1_do_load='1' and -- this is a load instruction
|
|
pipeline_stalled='0' and -- not already stalled (i.e. assert for 1 cycle)
|
|
(p1_rs1_hazard='1' or p1_rs2_hazard='1')
|
|
else '0';
|
|
|
|
|
|
|
|
|
|
pipeline_stalled <= stalled_interlock or stalled_memwait or stalled_muldiv;
|
|
|
pipeline_stall_registers:
|
pipeline_stall_registers:
|
process(clk)
|
process(clk)
|
begin
|
begin
|
if clk'event and clk='1' then
|
if clk'event and clk='1' then
|
if reset='1' then
|
if reset='1' then
|
pipeline_stalled <= '0';
|
stalled_interlock <= '0';
|
pipeline_interlocked <= '0';
|
stalled_memwait <= '0';
|
|
stalled_muldiv <= '0';
|
|
else
|
|
if mem_wait='1' then
|
|
stalled_memwait <= '1';
|
else
|
else
|
if stall_pipeline='1' then
|
stalled_memwait <= '0';
|
pipeline_stalled <= '1';
|
end if;
|
|
|
|
if p1_muldiv_stall='1' then
|
|
stalled_muldiv <= '1';
|
else
|
else
|
pipeline_stalled <= '0';
|
stalled_muldiv <= '0';
|
end if;
|
end if;
|
|
|
-- stalls caused by mem_wait and load_interlock are independent and
|
-- stalls caused by mem_wait and load_interlock are independent and
|
-- must not overlap; so when mem_wait='1' the cache stall takes
|
-- must not overlap; so when mem_wait='1' the cache stall takes
|
-- precedence and the loa interlock must wait.
|
-- precedence and the loa interlock must wait.
|
if mem_wait='0' then
|
if mem_wait='0' then
|
if load_interlock='1' then
|
if load_interlock='1' then
|
pipeline_interlocked <= '1';
|
stalled_interlock <= '1';
|
else
|
else
|
pipeline_interlocked <= '0';
|
stalled_interlock <= '0';
|
end if;
|
end if;
|
end if;
|
end if;
|
end if;
|
end if;
|
end if;
|
end if;
|
end process pipeline_stall_registers;
|
end process pipeline_stall_registers;
|
|
|
-- FIXME make sure this combinational will not have bad glitches
|
|
stall_pipeline <= mem_wait or load_interlock or p1_muldiv_stall;
|
|
|
|
|
|
-- FIXME load interlock should happen only if the instruction following
|
|
-- the load actually uses the load target register. Something like this:
|
|
-- (p1_do_load='1' and (p1_rd_num=p0_rs_num or p1_rd_num=p0_rt_num))
|
|
load_interlock <= '1' when
|
|
p1_do_load='1' and -- this is a load instruction
|
|
pipeline_stalled='0' and -- not already stalled (i.e. assert for 1 cycle)
|
|
(p1_rs1_hazard='1' or p1_rs2_hazard='1')
|
|
|
|
else '0';
|
|
|
|
p1_rs1_hazard <= '1'; --'1' when p0_uses_rs1='1' and p1_rd_num=p0_rs_num else '0';
|
p1_rs1_hazard <= '1'; --'1' when p0_uses_rs1='1' and p1_rd_num=p0_rs_num else '0';
|
p1_rs2_hazard <= '1'; --'1' when p0_uses_rs2='1' and p1_rd_num=p0_rt_num else '0';
|
p1_rs2_hazard <= '1'; --'1' when p0_uses_rs2='1' and p1_rd_num=p0_rt_num else '0';
|
|
|
with p1_ir_op select p0_uses_rs1 <=
|
with p1_ir_op select p0_uses_rs1 <=
|
'0' when "000010",
|
'0' when "000010",
|
Line 974... |
Line 996... |
-- Implementation notes
|
-- Implementation notes
|
--------------------------------------------------------------------------------
|
--------------------------------------------------------------------------------
|
-- @note1 :
|
-- @note1 :
|
--
|
--
|
-- This is the meaning of these two signals:
|
-- This is the meaning of these two signals:
|
-- pipeline_stalled & pipeline_interlocked =>
|
-- pipeline_stalled & stalled_interlock =>
|
-- "00" => normal state
|
-- "00" => normal state
|
-- "01" => normal state (makes for easier decoding)
|
-- "01" => normal state (makes for easier decoding)
|
-- "10" => all stages of pipeline stalled, including rbank
|
-- "10" => all stages of pipeline stalled, including rbank
|
-- "11" => all stages of pipeline stalled, except reg bank write port
|
-- "11" => all stages of pipeline stalled, except reg bank write port
|
--
|
--
|