Line 120... |
Line 120... |
signal p1_ac : t_alu_control;
|
signal p1_ac : t_alu_control;
|
-- ALU flag outputs (comparison results)
|
-- ALU flag outputs (comparison results)
|
signal p1_alu_flags : t_alu_flags;
|
signal p1_alu_flags : t_alu_flags;
|
-- immediate data, sign- or zero-extended as required by IR
|
-- immediate data, sign- or zero-extended as required by IR
|
signal p1_data_imm : t_word;
|
signal p1_data_imm : t_word;
|
signal p1_muldiv_result : t_dword;
|
|
signal p1_branch_offset : t_pc;
|
signal p1_branch_offset : t_pc;
|
signal p1_branch_offset_sex:std_logic_vector(31 downto 18);
|
signal p1_branch_offset_sex:std_logic_vector(31 downto 18);
|
signal p1_rbank_rs_hazard : std_logic;
|
signal p1_rbank_rs_hazard : std_logic;
|
signal p1_rbank_rt_hazard : std_logic;
|
signal p1_rbank_rt_hazard : std_logic;
|
signal p1_jump_type_set0 : std_logic_vector(1 downto 0);
|
signal p1_jump_type_set0 : std_logic_vector(1 downto 0);
|
Line 157... |
Line 156... |
signal p1_link : std_logic;
|
signal p1_link : std_logic;
|
signal p1_jump_cond_sel : std_logic_vector(2 downto 0);
|
signal p1_jump_cond_sel : std_logic_vector(2 downto 0);
|
signal p1_data_addr : t_addr;
|
signal p1_data_addr : t_addr;
|
signal p1_data_offset : t_addr;
|
signal p1_data_offset : t_addr;
|
|
|
|
signal p1_muldiv_result : t_word;
|
|
signal p1_muldiv_func : t_mult_function;
|
|
signal p1_muldiv_running : std_logic;
|
|
signal p1_muldiv_started : std_logic;
|
|
signal p1_muldiv_stall : std_logic;
|
|
|
|
|
--------------------------------------------------------------------------------
|
--------------------------------------------------------------------------------
|
-- Pipeline stage 2
|
-- Pipeline stage 2
|
|
|
|
signal p2_muldiv_started : std_logic;
|
signal p2_exception : std_logic;
|
signal p2_exception : std_logic;
|
signal p2_rd_addr : std_logic_vector(1 downto 0);
|
signal p2_rd_addr : std_logic_vector(1 downto 0);
|
signal p2_rd_mux_control : std_logic_vector(3 downto 0);
|
signal p2_rd_mux_control : std_logic_vector(3 downto 0);
|
signal p2_load_target : t_regnum;
|
signal p2_load_target : t_regnum;
|
signal p2_do_load : std_logic;
|
signal p2_do_load : std_logic;
|
Line 182... |
Line 189... |
-- pipeline is stalled for any reason
|
-- pipeline is stalled for any reason
|
signal pipeline_stalled : std_logic;
|
signal pipeline_stalled : 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 pipeline_interlocked:std_logic;
|
|
|
|
|
--------------------------------------------------------------------------------
|
|
-- Multiplier interface registers
|
|
|
|
signal mdiv_hi_reg : t_word;
|
|
signal mdiv_lo_reg : t_word;
|
|
|
|
--------------------------------------------------------------------------------
|
--------------------------------------------------------------------------------
|
-- CP0 registers and signals
|
-- CP0 registers and signals
|
|
|
-- CP0[12]: status register
|
-- CP0[12]: status register
|
-- FIXME status flags unimplemented
|
-- FIXME status flags unimplemented
|
Line 325... |
Line 325... |
|
|
p1_alu_inp1 <= p1_rs;
|
p1_alu_inp1 <= p1_rs;
|
|
|
with p1_alu_op2_sel select p1_alu_inp2 <=
|
with p1_alu_op2_sel select p1_alu_inp2 <=
|
p1_data_imm when "11",
|
p1_data_imm when "11",
|
p1_muldiv_result(63 downto 32) when "01",
|
p1_muldiv_result when "01", -- FIXME mux input wasted!
|
p1_muldiv_result(31 downto 0) when "10",
|
p1_muldiv_result when "10",
|
p1_rt when others;
|
p1_rt when others;
|
|
|
alu_inst : entity work.mips_alu
|
alu_inst : entity work.mips_alu
|
port map (
|
port map (
|
clk => clk,
|
clk => clk,
|
Line 345... |
Line 345... |
|
|
|
|
--------------------------------------------------------------------------------
|
--------------------------------------------------------------------------------
|
-- Mul/Div block interface
|
-- Mul/Div block interface
|
|
|
-- FIXME when MUL*/DIV* are implemented, these registers and the load enable
|
-- Compute the mdiv block function word. If p1_muldiv_func has any value other
|
-- logic will change a little. It may be better to move them into the alu.
|
-- than MULT_NOTHING a new mdiv operation will start, truncating whatever other
|
mult_registers:
|
-- operation that may have been in course.
|
process(clk)
|
-- So we encode here the function to be performed and make sure the value stays
|
begin
|
-- there for only one cycle (the first ALU cycle of the mul/div instruction).
|
if clk'event and clk='1' then
|
|
-- MTHI, MTLO are never involved in stall cycles, no need to check
|
-- This will be '1' for all mul/div operations other than NOP...
|
if p1_load_hi='1' then
|
p1_muldiv_func(3) <= '1' when p1_op_special='1' and
|
mdiv_hi_reg <= p1_rs;
|
p1_ir_fn(5 downto 4)="01" and
|
end if;
|
-- ...but only if the mdiv is not already running
|
if p1_load_lo='1' then
|
p2_muldiv_started = '0' and
|
mdiv_lo_reg <= p1_rs;
|
p1_muldiv_running ='0'
|
end if;
|
else '0';
|
end if;
|
|
end process mult_registers;
|
-- When bit(3) is zero, the rest are zeroed too. Otherwise, they come from IR
|
|
p1_muldiv_func(2 downto 0) <=
|
|
p1_ir_fn(3) & p1_ir_fn(1 downto 0) when p1_muldiv_func(3)='1'
|
|
else "000";
|
|
|
p1_muldiv_result <= mdiv_hi_reg & mdiv_lo_reg; -- FIXME stub, mdiv missing
|
mult_div: entity work.mips_mult
|
|
port map (
|
|
a => p1_rs,
|
|
b => p1_rt,
|
|
c_mult => p1_muldiv_result,
|
|
pause_out => p1_muldiv_running,
|
|
mult_func => p1_muldiv_func,
|
|
clk => clk,
|
|
reset_in => reset
|
|
);
|
|
|
|
-- Active only for the 1st ALU cycle of any mul/div instruction
|
|
p1_muldiv_started <= '1' when p1_op_special='1' and
|
|
p1_ir_fn(5 downto 3)="011" and
|
|
--
|
|
p1_muldiv_running='0'
|
|
else '0';
|
|
|
|
-- Stall the pipeline to enable mdiv operation completion.
|
|
-- We need p2_muldiv_started to distinguish the cycle before p1_muldiv_running
|
|
-- is asserted and the cycle after it deasserts.
|
|
-- Otherwise we would reexecute the same muldiv endlessly instruction after
|
|
-- deassertion of p1_muldiv_running, since the IR was stalled and still contains
|
|
-- the mul opcode...
|
|
p1_muldiv_stall <= '1' when
|
|
-- Active for the cycle immediately before p1_muldiv_running asserts
|
|
-- and NOT for the cycle after it deasserts
|
|
(p1_muldiv_started='1' and p2_muldiv_started='0') or
|
|
-- Active until operation is complete
|
|
p1_muldiv_running = '1'
|
|
else '0';
|
|
|
|
|
--##############################################################################
|
--##############################################################################
|
-- PC register and branch logic
|
-- PC register and branch logic
|
|
|
Line 634... |
Line 667... |
p1_rbank_rt_hazard <= p0_rbank_rt_hazard;
|
p1_rbank_rt_hazard <= p0_rbank_rt_hazard;
|
end if;
|
end if;
|
end if;
|
end if;
|
end process pipeline_stage1_register;
|
end process pipeline_stage1_register;
|
|
|
|
pipeline_stage1_register2:
|
|
process(clk)
|
|
begin
|
|
if clk'event and clk='1' then
|
|
if reset='1' then
|
|
p2_muldiv_started <= '0';
|
|
else
|
|
p2_muldiv_started <= p1_muldiv_running;
|
|
end if;
|
|
end if;
|
|
end process pipeline_stage1_register2;
|
|
|
|
|
-- Stage 2 pipeline register. Split in two for convenience.
|
-- Stage 2 pipeline register. Split in two for convenience.
|
-- This register deals with two kinds of stalls:
|
-- This register deals with two kinds of stalls:
|
-- * When the pipeline stalls because of a load interlock, this register is
|
-- * When the pipeline stalls because of a load interlock, this register is
|
-- allowed to update so that the load operation can complete while the rest of
|
-- allowed to update so that the load operation can complete while the rest of
|
Line 719... |
Line 764... |
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
|
-- FIXME make sure this combinational will not have bad glitches
|
stall_pipeline <= mem_wait or load_interlock;
|
stall_pipeline <= mem_wait or load_interlock or p1_muldiv_stall;
|
|
|
|
|
-- FIXME load interlock should happen only if the instruction following
|
-- FIXME load interlock should happen only if the instruction following
|
-- the load actually uses the load target register. Something like this:
|
-- 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))
|
-- (p1_do_load='1' and (p1_rd_num=p0_rs_num or p1_rd_num=p0_rt_num))
|