--------------------------------------------------------------------------------
|
--------------------------------------------------------------------------------
|
-- ion_cpu.vhdl -- MIPS-I(tm) compatible CPU core
|
-- ion_cpu.vhdl -- MIPS-I(tm) compatible CPU core
|
--------------------------------------------------------------------------------
|
--------------------------------------------------------------------------------
|
-- project: ION (http://www.opencores.org/project,ion_cpu)
|
-- project: ION (http://www.opencores.org/project,ion_cpu)
|
-- author: Jose A. Ruiz (ja_rd@hotmail.com)
|
-- author: Jose A. Ruiz (ja_rd@hotmail.com)
|
-- created: Jan/11/2011
|
-- created: Jan/11/2011
|
-- last modified: Jun/05/2011 (ja_rd@hotmail.com)
|
-- last modified: Jul/31/2011 (ja_rd@hotmail.com)
|
--------------------------------------------------------------------------------
|
--------------------------------------------------------------------------------
|
-- Please read file /doc/ion_project.txt for usage instructions.
|
-- Please read file /doc/ion_project.txt for usage instructions.
|
--------------------------------------------------------------------------------
|
--------------------------------------------------------------------------------
|
--### MIPS-I things not implemented
|
--### MIPS-I things not implemented
|
--
|
--
|
-- 1.- Most of the R3000 CP0 registers and of course all of the CP1.
|
-- 1.- Most of the R3000 CP0 registers and of course all of the CP1.
|
-- 2.- External interrupts missing, with CP0.SR IR, NMI and IM7..0 flags.
|
-- 2.- External interrupts missing, with CP0.SR IR, NMI and IM7..0 flags.
|
--
|
--
|
--### 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
|
-- every load takes two cycles.
|
-- every load takes two cycles.
|
-- The interlock logic should check register indices (@note2)
|
-- The interlock logic should check register indices (@note2)
|
-- 2.- CP0 SR (status register) bits KUo/IEo & KUP/IEp are missing.
|
-- 2.- Invalid instruction side effects:
|
-- This means that EXCEPTIONS CAN'T BE NESTED in this version of the CPU.
|
|
-- 3.- Invalid instruction side effects:
|
|
-- Invalid opcodes do trap but the logic that prevents bad opcodes from
|
-- Invalid opcodes do trap but the logic that prevents bad opcodes from
|
-- having side affects has not been tested yet.
|
-- having side affects has not been tested yet.
|
-- 4.- Kernel/user status.
|
-- 3.- Kernel/user status.
|
-- When in user mode, COP* instructions will trigger a 'CpU' exception.
|
-- When in user mode, COP* instructions will trigger a 'CpU' exception.
|
-- BUT there's no address checking and user code can still access kernel
|
-- BUT there's no address checking and user code can still access kernel
|
-- space in this version.
|
-- space in this version.
|
-- Besides, see point 2 above about the missing SR bits.
|
|
--
|
--
|
--------------------------------------------------------------------------------
|
--------------------------------------------------------------------------------
|
-- KNOWN BUGS:
|
-- KNOWN BUGS:
|
--
|
--
|
-- 1.- The instruction executed right after entering user mode (i.e. the
|
-- 1.- The instruction executed right after entering user mode (i.e. the
|
-- instruction after the MTC0 or RFE that clears the KU flag) is executed
|
-- instruction after the MTC0 or RFE that clears the KU flag) is executed
|
-- in kernel mode (instead of user mode). This is a gapping security hole,
|
-- in kernel mode (instead of user mode). This is a gaping security hole,
|
-- in case it makes any sense to speak of security in this project at this
|
-- in case it makes any sense to speak of security in this project at this
|
-- stage.
|
-- stage.
|
-- This can be easily fixed but is not very urgent.
|
-- This can be easily fixed but is not very urgent.
|
--------------------------------------------------------------------------------
|
--------------------------------------------------------------------------------
|
-- Copyright (C) 2011 Jose A. Ruiz
|
-- Copyright (C) 2011 Jose A. Ruiz
|
--
|
--
|
-- This source file may be used and distributed without
|
-- This source file may be used and distributed without
|
-- restriction provided that this copyright statement is not
|
-- restriction provided that this copyright statement is not
|
-- removed from the file and that any derivative work contains
|
-- removed from the file and that any derivative work contains
|
-- the original copyright notice and the associated disclaimer.
|
-- the original copyright notice and the associated disclaimer.
|
--
|
--
|
-- This source file is free software; you can redistribute it
|
-- This source file is free software; you can redistribute it
|
-- and/or modify it under the terms of the GNU Lesser General
|
-- and/or modify it under the terms of the GNU Lesser General
|
-- Public License as published by the Free Software Foundation;
|
-- Public License as published by the Free Software Foundation;
|
-- either version 2.1 of the License, or (at your option) any
|
-- either version 2.1 of the License, or (at your option) any
|
-- later version.
|
-- later version.
|
--
|
--
|
-- This source is distributed in the hope that it will be
|
-- This source is distributed in the hope that it will be
|
-- useful, but WITHOUT ANY WARRANTY; without even the implied
|
-- useful, but WITHOUT ANY WARRANTY; without even the implied
|
-- warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
-- warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
-- PURPOSE. See the GNU Lesser General Public License for more
|
-- PURPOSE. See the GNU Lesser General Public License for more
|
-- details.
|
-- details.
|
--
|
--
|
-- You should have received a copy of the GNU Lesser General
|
-- You should have received a copy of the GNU Lesser General
|
-- Public License along with this source; if not, download it
|
-- Public License along with this source; if not, download it
|
-- from http://www.opencores.org/lgpl.shtml
|
-- from http://www.opencores.org/lgpl.shtml
|
--------------------------------------------------------------------------------
|
--------------------------------------------------------------------------------
|
|
|
library ieee;
|
library ieee;
|
use ieee.std_logic_1164.all;
|
use ieee.std_logic_1164.all;
|
use ieee.std_logic_arith.all;
|
use ieee.std_logic_arith.all;
|
use ieee.std_logic_unsigned.all;
|
use ieee.std_logic_unsigned.all;
|
use work.mips_pkg.all;
|
use work.mips_pkg.all;
|
|
|
entity mips_cpu is
|
entity mips_cpu is
|
generic(
|
generic(
|
-- Reset vector address minus 4
|
-- Reset vector address minus 4
|
RESET_VECTOR_M4 : t_word := RESET_VECTOR_M4;
|
RESET_VECTOR_M4 : t_word := RESET_VECTOR_M4;
|
-- Trap vector address
|
-- Trap vector address
|
TRAP_VECTOR : t_word := TRAP_VECTOR;
|
TRAP_VECTOR : t_word := TRAP_VECTOR;
|
-- Type of memory to be used for register bank in xilinx HW
|
-- Type of memory to be used for register bank in xilinx HW
|
XILINX_REGBANK : string := "distributed" -- {distributed|block}
|
XILINX_REGBANK : string := "distributed" -- {distributed|block}
|
);
|
);
|
port(
|
port(
|
clk : in std_logic;
|
clk : in std_logic;
|
reset : in std_logic;
|
reset : in std_logic;
|
interrupt : in std_logic;
|
interrupt : in std_logic_vector(7 downto 0);
|
|
|
data_addr : out std_logic_vector(31 downto 0);
|
data_addr : out std_logic_vector(31 downto 0);
|
|
|
data_rd : in std_logic_vector(31 downto 0);
|
data_rd : in std_logic_vector(31 downto 0);
|
data_rd_vma : out std_logic;
|
data_rd_vma : out std_logic;
|
|
|
byte_we : out std_logic_vector(3 downto 0);
|
byte_we : out std_logic_vector(3 downto 0);
|
data_wr : out std_logic_vector(31 downto 0);
|
data_wr : out std_logic_vector(31 downto 0);
|
|
|
code_rd_addr : out std_logic_vector(31 downto 2);
|
code_rd_addr : out std_logic_vector(31 downto 2);
|
code_rd : in std_logic_vector(31 downto 0);
|
code_rd : in std_logic_vector(31 downto 0);
|
code_rd_vma : out std_logic;
|
code_rd_vma : out std_logic;
|
|
|
cache_enable : out std_logic;
|
cache_enable : out std_logic;
|
ic_invalidate : out std_logic;
|
ic_invalidate : out std_logic;
|
|
|
mem_wait : in std_logic
|
mem_wait : in std_logic
|
);
|
);
|
end; --entity mips_cpu
|
end; --entity mips_cpu
|
|
|
architecture rtl of mips_cpu is
|
architecture rtl of mips_cpu is
|
|
|
--------------------------------------------------------------------------------
|
--------------------------------------------------------------------------------
|
-- Pipeline stage 0
|
-- Pipeline stage 0
|
|
|
signal p0_pc_reg : t_pc;
|
signal p0_pc_reg : t_pc;
|
signal p0_pc_restart : t_pc;
|
signal p0_pc_restart : t_pc;
|
signal p0_pc_incremented : t_pc;
|
signal p0_pc_incremented : t_pc;
|
signal p0_pc_jump : t_pc;
|
signal p0_pc_jump : t_pc;
|
signal p0_pc_branch : t_pc;
|
signal p0_pc_branch : t_pc;
|
signal p0_pc_target : t_pc;
|
signal p0_pc_target : t_pc;
|
signal p0_pc_next : t_pc;
|
signal p0_pc_next : t_pc;
|
signal p0_rs_num : t_regnum;
|
signal p0_rs_num : t_regnum;
|
signal p0_rt_num : t_regnum;
|
signal p0_rt_num : t_regnum;
|
signal p0_jump_cond_value : std_logic;
|
signal p0_jump_cond_value : std_logic;
|
signal p0_rbank_rs_hazard : std_logic;
|
signal p0_rbank_rs_hazard : std_logic;
|
signal p0_rbank_rt_hazard : std_logic;
|
signal p0_rbank_rt_hazard : std_logic;
|
signal p0_uses_rs1 : std_logic;
|
signal p0_uses_rs1 : std_logic;
|
signal p0_uses_rs2 : std_logic;
|
signal p0_uses_rs2 : std_logic;
|
|
|
signal p1_rs1_hazard : std_logic;
|
signal p1_rs1_hazard : std_logic;
|
signal p1_rs2_hazard : std_logic;
|
signal p1_rs2_hazard : std_logic;
|
|
|
--------------------------------------------------------------------------------
|
--------------------------------------------------------------------------------
|
-- Pipeline stage 1
|
-- Pipeline stage 1
|
|
|
|
|
signal p1_rbank : t_rbank := (others => X"00000000");
|
signal p1_rbank : t_rbank := (others => X"00000000");
|
|
|
-- IMPORTANT: This attribute is used by Xilinx tools to select how to implement
|
-- IMPORTANT: This attribute is used by Xilinx tools to select how to implement
|
-- the register bank. If we don't use it, by default XST would infer 2 BRAMs for
|
-- the register bank. If we don't use it, by default XST would infer 2 BRAMs for
|
-- the 1024-bit 3-port reg bank, which you probably don't want.
|
-- the 1024-bit 3-port reg bank, which you probably don't want.
|
-- This can take the values {distributed|block}.
|
-- This can take the values {distributed|block}.
|
attribute ram_style : string;
|
attribute ram_style : string;
|
attribute ram_style of p1_rbank : signal is XILINX_REGBANK;
|
attribute ram_style of p1_rbank : signal is XILINX_REGBANK;
|
|
|
signal p1_rs, p1_rt : t_word;
|
signal p1_rs, p1_rt : t_word;
|
signal p1_rs_rbank : t_word;
|
signal p1_rs_rbank : t_word;
|
signal p1_rt_rbank : t_word;
|
signal p1_rt_rbank : t_word;
|
signal p1_rbank_forward : t_word;
|
signal p1_rbank_forward : t_word;
|
signal p1_rd_num : t_regnum;
|
signal p1_rd_num : t_regnum;
|
signal p1_c0_rs_num : t_regnum;
|
signal p1_c0_rs_num : t_regnum;
|
signal p1_rbank_wr_addr : t_regnum;
|
signal p1_rbank_wr_addr : t_regnum;
|
signal p1_rbank_we : std_logic;
|
signal p1_rbank_we : std_logic;
|
signal p1_rbank_wr_data : t_word;
|
signal p1_rbank_wr_data : t_word;
|
signal p1_alu_inp1 : t_word;
|
signal p1_alu_inp1 : t_word;
|
signal p1_alu_inp2 : t_word;
|
signal p1_alu_inp2 : t_word;
|
signal p1_alu_outp : t_word;
|
signal p1_alu_outp : t_word;
|
-- ALU control inputs (shortened name for brevity in expressions)
|
-- ALU control inputs (shortened name for brevity in expressions)
|
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_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);
|
signal p1_jump_type_set1 : std_logic_vector(1 downto 0);
|
signal p1_jump_type_set1 : std_logic_vector(1 downto 0);
|
signal p1_ir_reg : std_logic_vector(31 downto 0);
|
signal p1_ir_reg : std_logic_vector(31 downto 0);
|
signal p1_ir_op : std_logic_vector(31 downto 26);
|
signal p1_ir_op : std_logic_vector(31 downto 26);
|
signal p1_ir_fn : std_logic_vector(5 downto 0);
|
signal p1_ir_fn : std_logic_vector(5 downto 0);
|
signal p1_op_special : std_logic;
|
signal p1_op_special : std_logic;
|
signal p1_exception : std_logic;
|
signal p1_exception : std_logic;
|
signal p1_do_reg_jump : std_logic;
|
signal p1_do_reg_jump : std_logic;
|
signal p1_do_zero_ext_imm : std_logic;
|
signal p1_do_zero_ext_imm : std_logic;
|
signal p1_set_cp : std_logic;
|
signal p1_set_cp : std_logic;
|
signal p1_get_cp : std_logic;
|
signal p1_get_cp : std_logic;
|
signal p1_set_cp0 : std_logic;
|
signal p1_set_cp0 : std_logic;
|
signal p1_get_cp0 : std_logic;
|
signal p1_get_cp0 : std_logic;
|
signal p1_rfe : std_logic;
|
signal p1_rfe : std_logic;
|
signal p1_alu_op2_sel : std_logic_vector(1 downto 0);
|
signal p1_alu_op2_sel : std_logic_vector(1 downto 0);
|
signal p1_alu_op2_sel_set0: std_logic_vector(1 downto 0);
|
signal p1_alu_op2_sel_set0: std_logic_vector(1 downto 0);
|
signal p1_alu_op2_sel_set1: std_logic_vector(1 downto 0);
|
signal p1_alu_op2_sel_set1: std_logic_vector(1 downto 0);
|
signal p1_do_load : std_logic;
|
signal p1_do_load : std_logic;
|
signal p1_do_store : std_logic;
|
signal p1_do_store : std_logic;
|
signal p1_store_size : std_logic_vector(1 downto 0);
|
signal p1_store_size : std_logic_vector(1 downto 0);
|
signal p1_we_control : std_logic_vector(5 downto 0);
|
signal p1_we_control : std_logic_vector(5 downto 0);
|
signal p1_load_alu : std_logic;
|
signal p1_load_alu : std_logic;
|
signal p1_load_alu_set0 : std_logic;
|
signal p1_load_alu_set0 : std_logic;
|
signal p1_load_alu_set1 : std_logic;
|
signal p1_load_alu_set1 : std_logic;
|
signal p1_ld_upper_hword : std_logic;
|
signal p1_ld_upper_hword : std_logic;
|
signal p1_ld_upper_byte : std_logic;
|
signal p1_ld_upper_byte : std_logic;
|
signal p1_ld_unsigned : std_logic;
|
signal p1_ld_unsigned : std_logic;
|
signal p1_jump_type : std_logic_vector(1 downto 0);
|
signal p1_jump_type : std_logic_vector(1 downto 0);
|
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_result : t_word;
|
signal p1_muldiv_func : t_mult_function;
|
signal p1_muldiv_func : t_mult_function;
|
signal p1_muldiv_running : std_logic;
|
signal p1_muldiv_running : std_logic;
|
signal p1_muldiv_started : std_logic;
|
signal p1_muldiv_started : std_logic;
|
signal p1_muldiv_stall : std_logic;
|
signal p1_muldiv_stall : std_logic;
|
|
|
signal p1_unknown_opcode : std_logic;
|
signal p1_unknown_opcode : std_logic;
|
signal p1_cp_unavailable : std_logic;
|
signal p1_cp_unavailable : std_logic;
|
|
|
--------------------------------------------------------------------------------
|
--------------------------------------------------------------------------------
|
-- Pipeline stage 2
|
-- Pipeline stage 2
|
|
|
signal p2_muldiv_started : std_logic;
|
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;
|
signal p2_do_store : std_logic;
|
signal p2_do_store : std_logic;
|
signal p2_ld_upper_hword : std_logic;
|
signal p2_ld_upper_hword : std_logic;
|
signal p2_ld_upper_byte : std_logic;
|
signal p2_ld_upper_byte : std_logic;
|
signal p2_ld_unsigned : std_logic;
|
signal p2_ld_unsigned : std_logic;
|
signal p2_wback_mux_sel : std_logic_vector(1 downto 0);
|
signal p2_wback_mux_sel : std_logic_vector(1 downto 0);
|
signal p2_data_word_rd : t_word;
|
signal p2_data_word_rd : t_word;
|
signal p2_data_word_ext : std_logic;
|
signal p2_data_word_ext : std_logic;
|
|
|
--------------------------------------------------------------------------------
|
--------------------------------------------------------------------------------
|
-- Global control signals
|
-- Global control signals
|
|
|
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_memwait : std_logic;
|
signal stalled_muldiv : 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 stalled_interlock : std_logic;
|
signal stalled_interlock : std_logic;
|
|
|
signal reset_done : std_logic;
|
signal reset_done : std_logic;
|
|
|
--------------------------------------------------------------------------------
|
--------------------------------------------------------------------------------
|
-- CP0 registers and signals
|
-- CP0 registers and signals
|
|
|
-- CP0[12]: status register, KUo/IEo & KUP/IEp & KU/IE bits
|
-- CP0[12]: status register, KUo/IEo & KUP/IEp & KU/IE bits
|
signal cp0_status : std_logic_vector(5 downto 0);
|
signal cp0_status : std_logic_vector(5 downto 0);
|
signal cp0_sr_ku_reg : std_logic;
|
signal cp0_sr_ku_reg : std_logic;
|
-- CP0[12]: status register, cache control
|
-- CP0[12]: status register, cache control
|
signal cp0_cache_control : std_logic_vector(17 downto 16);
|
signal cp0_cache_control : std_logic_vector(17 downto 16);
|
-- Output of CP0 register bank (only a few regs are implemented)
|
-- Output of CP0 register bank (only a few regs are implemented)
|
signal cp0_reg_read : t_word;
|
signal cp0_reg_read : t_word;
|
-- CP0[14]: EPC register (PC value saved at exceptions)
|
-- CP0[14]: EPC register (PC value saved at exceptions)
|
signal cp0_epc : t_pc;
|
signal cp0_epc : t_pc;
|
-- CP0[13]: 'Cause' register (cause and attributes of exception)
|
-- CP0[13]: 'Cause' register (cause and attributes of exception)
|
signal cp0_cause : t_word;
|
signal cp0_cause : t_word;
|
signal cp0_in_delay_slot : std_logic;
|
signal cp0_in_delay_slot : std_logic;
|
signal cp0_cause_bd : std_logic;
|
signal cp0_cause_bd : std_logic;
|
signal cp0_cause_ce : std_logic_vector(1 downto 0);
|
signal cp0_cause_ce : std_logic_vector(1 downto 0);
|
signal cp0_cause_exc_code : std_logic_vector(4 downto 0);
|
signal cp0_cause_exc_code : std_logic_vector(4 downto 0);
|
|
|
begin
|
begin
|
|
|
--##############################################################################
|
--##############################################################################
|
-- Register bank & datapath
|
-- Register bank & datapath
|
|
|
-- Register indices are 'decoded' out of the instruction word BEFORE loading IR
|
-- Register indices are 'decoded' out of the instruction word BEFORE loading IR
|
p0_rs_num <= std_logic_vector(code_rd(25 downto 21));
|
p0_rs_num <= std_logic_vector(code_rd(25 downto 21));
|
with p1_ir_reg(31 downto 26) select p1_rd_num <=
|
with p1_ir_reg(31 downto 26) select p1_rd_num <=
|
p1_ir_reg(15 downto 11) when "000000",
|
p1_ir_reg(15 downto 11) when "000000",
|
p1_ir_reg(20 downto 16) when others;
|
p1_ir_reg(20 downto 16) when others;
|
|
|
p0_rt_num <= std_logic_vector(code_rd(20 downto 16)); -- also called rs2 in the docs
|
p0_rt_num <= std_logic_vector(code_rd(20 downto 16)); -- also called rs2 in the docs
|
|
|
--------------------------------------------------------------------------------
|
--------------------------------------------------------------------------------
|
-- Data input shifter & masker (LB,LBU,LH,LHU,LW)
|
-- Data input shifter & masker (LB,LBU,LH,LHU,LW)
|
|
|
p2_rd_mux_control <= p2_ld_upper_hword & p2_ld_upper_byte & p2_rd_addr;
|
p2_rd_mux_control <= p2_ld_upper_hword & p2_ld_upper_byte & p2_rd_addr;
|
|
|
-- Extension for unused bits will be zero or the sign (bit 7 or bit 15)
|
-- Extension for unused bits will be zero or the sign (bit 7 or bit 15)
|
p2_data_word_ext <= '0' when p2_ld_unsigned='1' else
|
p2_data_word_ext <= '0' when p2_ld_unsigned='1' else
|
-- LH
|
-- LH
|
data_rd(31) when p2_ld_upper_byte='1' and p2_rd_addr="00" else
|
data_rd(31) when p2_ld_upper_byte='1' and p2_rd_addr="00" else
|
data_rd(15) when p2_ld_upper_byte='1' and p2_rd_addr="10" else
|
data_rd(15) when p2_ld_upper_byte='1' and p2_rd_addr="10" else
|
-- LB
|
-- LB
|
data_rd(7) when p2_rd_addr="11" else
|
data_rd(7) when p2_rd_addr="11" else
|
data_rd(15) when p2_rd_addr="10" else
|
data_rd(15) when p2_rd_addr="10" else
|
data_rd(23) when p2_rd_addr="01" else
|
data_rd(23) when p2_rd_addr="01" else
|
data_rd(31);
|
data_rd(31);
|
|
|
-- byte 0 may come from any of the 4 bytes of the input word
|
-- byte 0 may come from any of the 4 bytes of the input word
|
with p2_rd_mux_control select p2_data_word_rd(7 downto 0) <=
|
with p2_rd_mux_control select p2_data_word_rd(7 downto 0) <=
|
data_rd(31 downto 24) when "0000",
|
data_rd(31 downto 24) when "0000",
|
data_rd(23 downto 16) when "0001",
|
data_rd(23 downto 16) when "0001",
|
data_rd(23 downto 16) when "0100",
|
data_rd(23 downto 16) when "0100",
|
data_rd(15 downto 8) when "0010",
|
data_rd(15 downto 8) when "0010",
|
data_rd( 7 downto 0) when others;
|
data_rd( 7 downto 0) when others;
|
|
|
-- byte 1 may come from input bytes 1 or 3 or may be extended for LB, LBU
|
-- byte 1 may come from input bytes 1 or 3 or may be extended for LB, LBU
|
with p2_rd_mux_control select p2_data_word_rd(15 downto 8) <=
|
with p2_rd_mux_control select p2_data_word_rd(15 downto 8) <=
|
data_rd(31 downto 24) when "0100",
|
data_rd(31 downto 24) when "0100",
|
data_rd(15 downto 8) when "0110",
|
data_rd(15 downto 8) when "0110",
|
data_rd(15 downto 8) when "1100",
|
data_rd(15 downto 8) when "1100",
|
data_rd(15 downto 8) when "1101",
|
data_rd(15 downto 8) when "1101",
|
data_rd(15 downto 8) when "1110",
|
data_rd(15 downto 8) when "1110",
|
data_rd(15 downto 8) when "1111",
|
data_rd(15 downto 8) when "1111",
|
(others => p2_data_word_ext) when others;
|
(others => p2_data_word_ext) when others;
|
|
|
-- bytes 2,3 come straight from input or are extended for LH,LHU
|
-- bytes 2,3 come straight from input or are extended for LH,LHU
|
with p2_ld_upper_hword select p2_data_word_rd(31 downto 16) <=
|
with p2_ld_upper_hword select p2_data_word_rd(31 downto 16) <=
|
(others => p2_data_word_ext) when '0',
|
(others => p2_data_word_ext) when '0',
|
data_rd(31 downto 16) when others;
|
data_rd(31 downto 16) when others;
|
|
|
--------------------------------------------------------------------------------
|
--------------------------------------------------------------------------------
|
-- Reg bank input multiplexor
|
-- Reg bank input multiplexor
|
|
|
-- Select which data is to be written back to the reg bank and where
|
-- Select which data is to be written back to the reg bank and where
|
p1_rbank_wr_addr <= p1_rd_num when p2_do_load='0' and p1_link='0' else
|
p1_rbank_wr_addr <= p1_rd_num when p2_do_load='0' and p1_link='0' else
|
"11111" when p2_do_load='0' and p1_link='1' else
|
"11111" when p2_do_load='0' and p1_link='1' else
|
p2_load_target;
|
p2_load_target;
|
|
|
p2_wback_mux_sel <=
|
p2_wback_mux_sel <=
|
"00" when p2_do_load='0' and p1_get_cp0='0' and p1_link='0' else
|
"00" when p2_do_load='0' and p1_get_cp0='0' and p1_link='0' else
|
"01" when p2_do_load='1' and p1_get_cp0='0' and p1_link='0' else
|
"01" when p2_do_load='1' and p1_get_cp0='0' and p1_link='0' else
|
"10" when p2_do_load='0' and p1_get_cp0='1' and p1_link='0' else
|
"10" when p2_do_load='0' and p1_get_cp0='1' and p1_link='0' else
|
"11";
|
"11";
|
|
|
with (p2_wback_mux_sel) select p1_rbank_wr_data <=
|
with (p2_wback_mux_sel) select p1_rbank_wr_data <=
|
p1_alu_outp when "00",
|
p1_alu_outp when "00",
|
p2_data_word_rd when "01",
|
p2_data_word_rd when "01",
|
p0_pc_incremented & "00" when "11",
|
p0_pc_incremented & "00" when "11",
|
cp0_reg_read when others;
|
cp0_reg_read when others;
|
|
|
--------------------------------------------------------------------------------
|
--------------------------------------------------------------------------------
|
-- Register bank RAM & Rbank WE logic
|
-- Register bank RAM & Rbank WE logic
|
|
|
p1_rbank_we <= '1' when (p2_do_load='1' or p1_load_alu='1' or p1_link='1' or
|
p1_rbank_we <= '1' when (p2_do_load='1' or p1_load_alu='1' or p1_link='1' or
|
-- if mfc0 triggers privilege trap, don't load reg
|
-- if mfc0 triggers privilege trap, don't load reg
|
(p1_get_cp0='1' and p1_cp_unavailable='0')) and
|
(p1_get_cp0='1' and p1_cp_unavailable='0')) and
|
-- 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
|
-- if stalled because of muldiv, block writeback
|
stalled_muldiv='0' and --@note1
|
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';
|
|
|
-- Register bank as triple-port RAM. Should synth to 2 BRAMs unless you use
|
-- Register bank as triple-port RAM. Should synth to 2 BRAMs unless you use
|
-- synth attributes to prevent it (see 'ram_style' attribute above) or your
|
-- synth attributes to prevent it (see 'ram_style' attribute above) or your
|
-- 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' then
|
if p1_rbank_we='1' then
|
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
|
-- the rbank read port loads in the same conditions as the IR: don't
|
-- update Rs or Rt if the pipeline is frozen
|
-- update Rs or Rt if the pipeline is frozen
|
if stall_pipeline='0' then
|
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 if;
|
end process synchronous_reg_bank;
|
end process synchronous_reg_bank;
|
|
|
--------------------------------------------------------------------------------
|
--------------------------------------------------------------------------------
|
-- Reg bank 'writeback' data forwarding
|
-- Reg bank 'writeback' data forwarding
|
|
|
-- Register writeback data in a DFF in case it needs to be forwarded.
|
-- Register writeback data in a DFF in case it needs to be forwarded.
|
data_forward_register:
|
data_forward_register:
|
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' then -- no need to check for stall cycles
|
if p1_rbank_we='1' then -- no need to check for stall cycles
|
p1_rbank_forward <= p1_rbank_wr_data;
|
p1_rbank_forward <= p1_rbank_wr_data;
|
end if;
|
end if;
|
end if;
|
end if;
|
end process data_forward_register;
|
end process data_forward_register;
|
|
|
-- Bypass sync RAM if we're reading and writing to the same address. This saves
|
-- Bypass sync RAM if we're reading and writing to the same address. This saves
|
-- 1 stall cycle and fixes the data hazard.
|
-- 1 stall cycle and fixes the data hazard.
|
p0_rbank_rs_hazard <= '1' when p1_rbank_wr_addr=p0_rs_num and p1_rbank_we='1'
|
p0_rbank_rs_hazard <= '1' when p1_rbank_wr_addr=p0_rs_num and p1_rbank_we='1'
|
else '0';
|
else '0';
|
p0_rbank_rt_hazard <= '1' when p1_rbank_wr_addr=p0_rt_num and p1_rbank_we='1'
|
p0_rbank_rt_hazard <= '1' when p1_rbank_wr_addr=p0_rt_num and p1_rbank_we='1'
|
else '0';
|
else '0';
|
|
|
p1_rs <= p1_rs_rbank when p1_rbank_rs_hazard='0' else p1_rbank_forward;
|
p1_rs <= p1_rs_rbank when p1_rbank_rs_hazard='0' else p1_rbank_forward;
|
p1_rt <= p1_rt_rbank when p1_rbank_rt_hazard='0' else p1_rbank_forward;
|
p1_rt <= p1_rt_rbank when p1_rbank_rt_hazard='0' else p1_rbank_forward;
|
|
|
|
|
--------------------------------------------------------------------------------
|
--------------------------------------------------------------------------------
|
-- ALU & ALU input multiplexors
|
-- ALU & ALU input multiplexors
|
|
|
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 when "01",
|
p1_muldiv_result when "01",
|
--p1_muldiv_result when "10", -- FIXME mux input wasted!
|
--p1_muldiv_result when "10", -- FIXME mux input wasted!
|
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,
|
reset => reset,
|
reset => reset,
|
ac => p1_ac,
|
ac => p1_ac,
|
flags => p1_alu_flags,
|
flags => p1_alu_flags,
|
|
|
inp1 => p1_alu_inp1,
|
inp1 => p1_alu_inp1,
|
inp2 => p1_alu_inp2,
|
inp2 => p1_alu_inp2,
|
outp => p1_alu_outp
|
outp => p1_alu_outp
|
);
|
);
|
|
|
|
|
--------------------------------------------------------------------------------
|
--------------------------------------------------------------------------------
|
-- Mul/Div block interface
|
-- Mul/Div block interface
|
|
|
-- Compute the mdiv block function word. If p1_muldiv_func has any value other
|
-- Compute the mdiv block function word. If p1_muldiv_func has any value other
|
-- than MULT_NOTHING a new mdiv operation will start, truncating whatever other
|
-- than MULT_NOTHING a new mdiv operation will start, truncating whatever other
|
-- operation that may have been in course.
|
-- operation that may have been in course.
|
-- So we encode here the function to be performed and make sure the value stays
|
-- So we encode here the function to be performed and make sure the value stays
|
-- there for only one cycle (the first ALU cycle of the mul/div instruction).
|
-- there for only one cycle (the first ALU cycle of the mul/div instruction).
|
|
|
-- This will be '1' for all mul/div operations other than NOP...
|
-- This will be '1' for all mul/div operations other than NOP...
|
p1_muldiv_func(3) <= '1' when p1_op_special='1' and
|
p1_muldiv_func(3) <= '1' when p1_op_special='1' and
|
p1_ir_fn(5 downto 4)="01" and
|
p1_ir_fn(5 downto 4)="01" and
|
-- ...but only if the mdiv is not already running
|
-- ...but only if the mdiv is not already running
|
p2_muldiv_started = '0' and
|
p2_muldiv_started = '0' and
|
p1_muldiv_running ='0'
|
p1_muldiv_running ='0'
|
else '0';
|
else '0';
|
|
|
-- When bit(3) is zero, the rest are zeroed too. Otherwise, they come from IR
|
-- When bit(3) is zero, the rest are zeroed too. Otherwise, they come from IR
|
p1_muldiv_func(2 downto 0) <=
|
p1_muldiv_func(2 downto 0) <=
|
p1_ir_fn(3) & p1_ir_fn(1 downto 0) when p1_muldiv_func(3)='1'
|
p1_ir_fn(3) & p1_ir_fn(1 downto 0) when p1_muldiv_func(3)='1'
|
else "000";
|
else "000";
|
|
|
mult_div: entity work.mips_mult
|
mult_div: entity work.mips_mult
|
port map (
|
port map (
|
a => p1_rs,
|
a => p1_rs,
|
b => p1_rt,
|
b => p1_rt,
|
c_mult => p1_muldiv_result,
|
c_mult => p1_muldiv_result,
|
pause_out => p1_muldiv_running,
|
pause_out => p1_muldiv_running,
|
mult_func => p1_muldiv_func,
|
mult_func => p1_muldiv_func,
|
clk => clk,
|
clk => clk,
|
reset_in => reset
|
reset_in => reset
|
);
|
);
|
|
|
-- Active only for the 1st ALU cycle of any mul/div instruction
|
-- Active only for the 1st ALU cycle of any mul/div instruction
|
p1_muldiv_started <= '1' when p1_op_special='1' and
|
p1_muldiv_started <= '1' when p1_op_special='1' and
|
p1_ir_fn(5 downto 3)="011" and
|
p1_ir_fn(5 downto 3)="011" and
|
--
|
--
|
p1_muldiv_running='0'
|
p1_muldiv_running='0'
|
else '0';
|
else '0';
|
|
|
-- Stall the pipeline to enable mdiv operation completion.
|
-- Stall the pipeline to enable mdiv operation completion.
|
-- We need p2_muldiv_started to distinguish the cycle before p1_muldiv_running
|
-- We need p2_muldiv_started to distinguish the cycle before p1_muldiv_running
|
-- is asserted and the cycle after it deasserts.
|
-- is asserted and the cycle after it deasserts.
|
-- Otherwise we would reexecute the same muldiv endlessly instruction after
|
-- Otherwise we would reexecute the same muldiv endlessly instruction after
|
-- deassertion of p1_muldiv_running, since the IR was stalled and still contains
|
-- deassertion of p1_muldiv_running, since the IR was stalled and still contains
|
-- the mul opcode...
|
-- the mul opcode...
|
p1_muldiv_stall <= '1' when
|
p1_muldiv_stall <= '1' when
|
-- Active for the cycle immediately before p1_muldiv_running asserts
|
-- Active for the cycle immediately before p1_muldiv_running asserts
|
-- and NOT for the cycle after it deasserts
|
-- and NOT for the cycle after it deasserts
|
(p1_muldiv_started='1' and p2_muldiv_started='0') or
|
(p1_muldiv_started='1' and p2_muldiv_started='0') or
|
-- Active until operation is complete
|
-- Active until operation is complete
|
p1_muldiv_running = '1'
|
p1_muldiv_running = '1'
|
else '0';
|
else '0';
|
|
|
|
|
--##############################################################################
|
--##############################################################################
|
-- PC register and branch logic
|
-- PC register and branch logic
|
|
|
-- p0_pc_reg will not be incremented on stall cycles
|
-- p0_pc_reg will not be incremented on stall cycles
|
p0_pc_incremented <= p0_pc_reg + (not stall_pipeline);
|
p0_pc_incremented <= p0_pc_reg + (not stall_pipeline);
|
|
|
-- main pc mux: jump or continue
|
-- main pc mux: jump or continue
|
p0_pc_next <=
|
p0_pc_next <=
|
p0_pc_target when
|
p0_pc_target when
|
-- We jump on jump instructions whose condition is met...
|
-- We jump on jump instructions whose condition is met...
|
((p1_jump_type(1)='1' and p0_jump_cond_value='1' and
|
((p1_jump_type(1)='1' and p0_jump_cond_value='1' and
|
-- ...except we abort any jump that follows the victim of an exception
|
-- ...except we abort any jump that follows the victim of an exception
|
p2_exception='0') or
|
p2_exception='0') or
|
-- We jump on exceptions too...
|
-- We jump on exceptions too...
|
p1_exception='1')
|
p1_exception='1')
|
-- ... but we only jump at all if the pipeline is not stalled
|
-- ... but we only jump at all if the pipeline is not stalled
|
and stall_pipeline='0'
|
and stall_pipeline='0'
|
else p0_pc_incremented;
|
else p0_pc_incremented;
|
|
|
pc_register:
|
pc_register:
|
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 <vector>-4 so that 1st fetch addr is <vector>
|
-- reset to <vector>-4 so that 1st fetch addr is <vector>
|
p0_pc_reg <= RESET_VECTOR_M4(31 downto 2);
|
p0_pc_reg <= RESET_VECTOR_M4(31 downto 2);
|
else
|
else
|
if reset_done='1' then
|
if reset_done='1' then
|
-- 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)
|
-- It's the addr of the instruction triggering the exception,
|
-- It's the addr of the instruction triggering the exception,
|
-- except when the triggering instruction is in a delay slot. In
|
-- except when the triggering instruction is in a delay slot. In
|
-- that case, this is the previous jump instruction address.
|
-- that case, this is the previous jump instruction address.
|
-- I.e. all as per the mips-1 specs.
|
-- I.e. all as per the mips-1 specs.
|
if (p1_jump_type="00" or p0_jump_cond_value='0') then
|
if (p1_jump_type="00" or p0_jump_cond_value='0') then
|
p0_pc_restart <= p0_pc_reg;
|
p0_pc_restart <= p0_pc_reg;
|
-- remember if we are in a delay slot, in case there's a trap
|
-- remember if we are in a delay slot, in case there's a trap
|
cp0_in_delay_slot <= '0'; -- NOT in a delay slot
|
cp0_in_delay_slot <= '0'; -- NOT in a delay slot
|
else
|
else
|
cp0_in_delay_slot <= '1'; -- in a delay slot
|
cp0_in_delay_slot <= '1'; -- in a delay slot
|
end if;
|
end if;
|
end if;
|
end if;
|
end if;
|
end if;
|
end if;
|
end if;
|
end process pc_register;
|
end process pc_register;
|
|
|
-- Common rd/wr address; lowest 2 bits are output as debugging aid only
|
-- Common rd/wr address; lowest 2 bits are output as debugging aid only
|
data_addr <= p1_data_addr(31 downto 0);
|
data_addr <= p1_data_addr(31 downto 0);
|
|
|
-- 'Memory enable' signals for both memory interfaces
|
-- 'Memory enable' signals for both memory interfaces
|
data_rd_vma <= p1_do_load and not pipeline_stalled;
|
data_rd_vma <= p1_do_load and not pipeline_stalled;
|
code_rd_vma <= (not stall_pipeline) and reset_done;
|
code_rd_vma <= (not stall_pipeline) and reset_done;
|
|
|
-- reset_done will be asserted after the reset process is finished, when the
|
-- reset_done will be asserted after the reset process is finished, when the
|
-- CPU can start operating normally.
|
-- CPU can start operating normally.
|
-- We only use it to make sure code_rd_vma is not asserted prematurely.
|
-- We only use it to make sure code_rd_vma is not asserted prematurely.
|
wait_for_end_of_reset:
|
wait_for_end_of_reset:
|
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_done <= '0';
|
reset_done <= '0';
|
else
|
else
|
reset_done <= '1';
|
reset_done <= '1';
|
end if;
|
end if;
|
end if;
|
end if;
|
end process wait_for_end_of_reset;
|
end process wait_for_end_of_reset;
|
|
|
-- The final value used to access code memory
|
-- The final value used to access code memory
|
code_rd_addr <= p0_pc_next;
|
code_rd_addr <= p0_pc_next;
|
|
|
-- compute target of J/JR instructions
|
-- compute target of J/JR instructions
|
p0_pc_jump <= p1_rs(31 downto 2) when p1_do_reg_jump='1' else
|
p0_pc_jump <= p1_rs(31 downto 2) when p1_do_reg_jump='1' else
|
p0_pc_reg(31 downto 28) & p1_ir_reg(25 downto 0);
|
p0_pc_reg(31 downto 28) & p1_ir_reg(25 downto 0);
|
|
|
-- compute target of relative branch instructions
|
-- compute target of relative branch instructions
|
p1_branch_offset_sex <= (others => p1_ir_reg(15));
|
p1_branch_offset_sex <= (others => p1_ir_reg(15));
|
p1_branch_offset <= p1_branch_offset_sex & p1_ir_reg(15 downto 0);
|
p1_branch_offset <= p1_branch_offset_sex & p1_ir_reg(15 downto 0);
|
-- p0_pc_reg is the addr of the instruction in delay slot
|
-- p0_pc_reg is the addr of the instruction in delay slot
|
p0_pc_branch <= p0_pc_reg + p1_branch_offset;
|
p0_pc_branch <= p0_pc_reg + p1_branch_offset;
|
|
|
-- decide which jump target is to be used
|
-- decide which jump target is to be used
|
p0_pc_target <=
|
p0_pc_target <=
|
TRAP_VECTOR(31 downto 2) when p1_exception='1' else
|
TRAP_VECTOR(31 downto 2) when p1_exception='1' else
|
p0_pc_jump when p1_jump_type(0)='1' else
|
p0_pc_jump when p1_jump_type(0)='1' else
|
p0_pc_branch;
|
p0_pc_branch;
|
|
|
|
|
--##############################################################################
|
--##############################################################################
|
-- Instruction decoding and IR
|
-- Instruction decoding and IR
|
|
|
instruction_register:
|
instruction_register:
|
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
|
p1_ir_reg <= (others => '0');
|
p1_ir_reg <= (others => '0');
|
elsif stall_pipeline='0' then
|
elsif stall_pipeline='0' then
|
p1_ir_reg <= code_rd;
|
p1_ir_reg <= code_rd;
|
end if;
|
end if;
|
end if;
|
end if;
|
end process instruction_register;
|
end process instruction_register;
|
|
|
-- Zero extension/Sign extension of instruction immediate data
|
-- Zero extension/Sign extension of instruction immediate data
|
p1_data_imm(15 downto 0) <= p1_ir_reg(15 downto 0);
|
p1_data_imm(15 downto 0) <= p1_ir_reg(15 downto 0);
|
|
|
with p1_do_zero_ext_imm select p1_data_imm(31 downto 16) <=
|
with p1_do_zero_ext_imm select p1_data_imm(31 downto 16) <=
|
(others => '0') when '1',
|
(others => '0') when '1',
|
(others => p1_ir_reg(15)) when others;
|
(others => p1_ir_reg(15)) when others;
|
|
|
|
|
-- 'Extract' main fields from IR, for convenience
|
-- 'Extract' main fields from IR, for convenience
|
p1_ir_op <= p1_ir_reg(31 downto 26);
|
p1_ir_op <= p1_ir_reg(31 downto 26);
|
p1_ir_fn <= p1_ir_reg(5 downto 0);
|
p1_ir_fn <= p1_ir_reg(5 downto 0);
|
|
|
-- Decode jump type, if any, for instructions with op/=0
|
-- Decode jump type, if any, for instructions with op/=0
|
with p1_ir_op select p1_jump_type_set0 <=
|
with p1_ir_op select p1_jump_type_set0 <=
|
-- FIXME verify that we actually weed out ALL invalid instructions
|
-- FIXME verify that we actually weed out ALL invalid instructions
|
"10" when "000001", -- BLTZ, BGEZ, BLTZAL, BGTZAL
|
"10" when "000001", -- BLTZ, BGEZ, BLTZAL, BGTZAL
|
"11" when "000010", -- J
|
"11" when "000010", -- J
|
"11" when "000011", -- JAL
|
"11" when "000011", -- JAL
|
"10" when "000100", -- BEQ
|
"10" when "000100", -- BEQ
|
"10" when "000101", -- BNE
|
"10" when "000101", -- BNE
|
"10" when "000110", -- BLEZ
|
"10" when "000110", -- BLEZ
|
"10" when "000111", -- BGTZ
|
"10" when "000111", -- BGTZ
|
"00" when others; -- no jump
|
"00" when others; -- no jump
|
|
|
-- Decode jump type, if any, for instructions with op=0
|
-- Decode jump type, if any, for instructions with op=0
|
p1_jump_type_set1 <= "11" when p1_op_special='1' and
|
p1_jump_type_set1 <= "11" when p1_op_special='1' and
|
p1_ir_reg(5 downto 1)="00100"
|
p1_ir_reg(5 downto 1)="00100"
|
else "00";
|
else "00";
|
|
|
-- Decode jump type for the instruction in IR (composite of two formats)
|
-- Decode jump type for the instruction in IR (composite of two formats)
|
p1_jump_type <= p1_jump_type_set0 or p1_jump_type_set1;
|
p1_jump_type <= p1_jump_type_set0 or p1_jump_type_set1;
|
|
|
p1_link <= '1' when (p1_ir_op="000000" and p1_ir_reg(5 downto 0)="001001") or
|
p1_link <= '1' when (p1_ir_op="000000" and p1_ir_reg(5 downto 0)="001001") or
|
(p1_ir_op="000001" and p1_ir_reg(20)='1') or
|
(p1_ir_op="000001" and p1_ir_reg(20)='1') or
|
(p1_ir_op="000011")
|
(p1_ir_op="000011")
|
else '0';
|
else '0';
|
|
|
-- Decode jump condition: encode a mux control signal from IR...
|
-- Decode jump condition: encode a mux control signal from IR...
|
p1_jump_cond_sel <=
|
p1_jump_cond_sel <=
|
"001" when p1_ir_op="000001" and p1_ir_reg(16)='0' else -- op1 < 0 BLTZ*
|
"001" when p1_ir_op="000001" and p1_ir_reg(16)='0' else -- op1 < 0 BLTZ*
|
"101" when p1_ir_op="000001" and p1_ir_reg(16)='1' else -- !(op1 < 0) BNLTZ*
|
"101" when p1_ir_op="000001" and p1_ir_reg(16)='1' else -- !(op1 < 0) BNLTZ*
|
"010" when p1_ir_op="000100" else -- op1 == op2 BEQ
|
"010" when p1_ir_op="000100" else -- op1 == op2 BEQ
|
"110" when p1_ir_op="000101" else -- !(op1 == op2) BNE
|
"110" when p1_ir_op="000101" else -- !(op1 == op2) BNE
|
"011" when p1_ir_op="000110" else -- op1 <= 0 BLEZ
|
"011" when p1_ir_op="000110" else -- op1 <= 0 BLEZ
|
"111" when p1_ir_op="000111" else -- !(op1 <= 0) BGTZ
|
"111" when p1_ir_op="000111" else -- !(op1 <= 0) BGTZ
|
"000"; -- always
|
"000"; -- always
|
|
|
-- ... and use mux control signal to select the condition value
|
-- ... and use mux control signal to select the condition value
|
with p1_jump_cond_sel select p0_jump_cond_value <=
|
with p1_jump_cond_sel select p0_jump_cond_value <=
|
p1_alu_flags.inp1_lt_zero when "001",
|
p1_alu_flags.inp1_lt_zero when "001",
|
not p1_alu_flags.inp1_lt_zero when "101",
|
not p1_alu_flags.inp1_lt_zero when "101",
|
p1_alu_flags.inp1_eq_inp2 when "010",
|
p1_alu_flags.inp1_eq_inp2 when "010",
|
not p1_alu_flags.inp1_eq_inp2 when "110",
|
not p1_alu_flags.inp1_eq_inp2 when "110",
|
(p1_alu_flags.inp1_lt_inp2 or
|
(p1_alu_flags.inp1_lt_inp2 or
|
p1_alu_flags.inp1_eq_inp2) when "011",
|
p1_alu_flags.inp1_eq_inp2) when "011",
|
not (p1_alu_flags.inp1_lt_inp2 or
|
not (p1_alu_flags.inp1_lt_inp2 or
|
p1_alu_flags.inp1_eq_inp2) when "111",
|
p1_alu_flags.inp1_eq_inp2) when "111",
|
'1' when others;
|
'1' when others;
|
|
|
-- Decode instructions that launch exceptions
|
-- Decode instructions that launch exceptions
|
p1_exception <= '1' when
|
p1_exception <= '1' when
|
(p1_op_special='1' and p1_ir_reg(5 downto 1)="00110") or -- syscall/break
|
(p1_op_special='1' and p1_ir_reg(5 downto 1)="00110") or -- syscall/break
|
p1_unknown_opcode='1' or
|
p1_unknown_opcode='1' or
|
p1_cp_unavailable='1'
|
p1_cp_unavailable='1'
|
else '0';
|
else '0';
|
|
|
-- Decode MTC0/MFC0 instructions (see @note3)
|
-- Decode MTC0/MFC0 instructions (see @note3)
|
p1_set_cp <= '1' when p1_ir_reg(31 downto 28)="0100" and
|
p1_set_cp <= '1' when p1_ir_reg(31 downto 28)="0100" and
|
p1_ir_reg(25 downto 21)="00100" else '0';
|
p1_ir_reg(25 downto 21)="00100" else '0';
|
p1_get_cp <= '1' when p1_ir_reg(31 downto 28)="0100" and
|
p1_get_cp <= '1' when p1_ir_reg(31 downto 28)="0100" and
|
p1_ir_reg(25 downto 21)="00000" else '0';
|
p1_ir_reg(25 downto 21)="00000" else '0';
|
|
|
p1_set_cp0 <= '1' when p1_ir_reg(27 downto 26)="00" and p1_set_cp='1' else '0';
|
p1_set_cp0 <= '1' when p1_ir_reg(27 downto 26)="00" and p1_set_cp='1' else '0';
|
p1_get_cp0 <= '1' when p1_ir_reg(27 downto 26)="00" and p1_get_cp='1' else '0';
|
p1_get_cp0 <= '1' when p1_ir_reg(27 downto 26)="00" and p1_get_cp='1' else '0';
|
|
|
-- Decode RFE instruction (see @note3)
|
-- Decode RFE instruction (see @note3)
|
p1_rfe <= '1' when p1_ir_reg(31 downto 21)="01000010000" and
|
p1_rfe <= '1' when p1_ir_reg(31 downto 21)="01000010000" and
|
p1_ir_reg(5 downto 0)="010000"
|
p1_ir_reg(5 downto 0)="010000"
|
else '0';
|
else '0';
|
|
|
-- Raise some signals for some particular group of opcodes
|
-- Raise some signals for some particular group of opcodes
|
p1_op_special <= '1' when p1_ir_op="000000" else '0'; -- group '0' opcodes
|
p1_op_special <= '1' when p1_ir_op="000000" else '0'; -- group '0' opcodes
|
p1_do_reg_jump <= '1' when p1_op_special='1' and p1_ir_fn(5 downto 1)="00100" else '0';
|
p1_do_reg_jump <= '1' when p1_op_special='1' and p1_ir_fn(5 downto 1)="00100" else '0';
|
p1_do_zero_ext_imm <= '1' when (p1_ir_op(31 downto 28)="0011") else '0';
|
p1_do_zero_ext_imm <= '1' when (p1_ir_op(31 downto 28)="0011") else '0';
|
|
|
-- Decode input data mux control (LW, LH, LB, LBU, LHU) and load enable
|
-- Decode input data mux control (LW, LH, LB, LBU, LHU) and load enable
|
p1_do_load <= '1' when
|
p1_do_load <= '1' when
|
p1_ir_op(31 downto 29)="100" and
|
p1_ir_op(31 downto 29)="100" and
|
p1_ir_op(28 downto 26)/="010" and -- LWL
|
p1_ir_op(28 downto 26)/="010" and -- LWL
|
p1_ir_op(28 downto 26)/="110" and -- LWR
|
p1_ir_op(28 downto 26)/="110" and -- LWR
|
p1_ir_op(28 downto 26)/="111" and -- LWR
|
p1_ir_op(28 downto 26)/="111" and -- LWR
|
p2_exception='0' -- abort load if previous instruction triggered trap
|
p2_exception='0' -- abort load if previous instruction triggered trap
|
else '0';
|
else '0';
|
|
|
p1_load_alu_set0 <= '1'
|
p1_load_alu_set0 <= '1'
|
when p1_op_special='1' and
|
when p1_op_special='1' and
|
((p1_ir_op(31 downto 29)="000" and p1_ir_op(27 downto 26)="00") or
|
((p1_ir_op(31 downto 29)="000" and p1_ir_op(27 downto 26)="00") or
|
(p1_ir_op(31 downto 29)="000" and p1_ir_op(27 downto 26)="10") or
|
(p1_ir_op(31 downto 29)="000" and p1_ir_op(27 downto 26)="10") or
|
(p1_ir_op(31 downto 29)="000" and p1_ir_op(27 downto 26)="11") or
|
(p1_ir_op(31 downto 29)="000" and p1_ir_op(27 downto 26)="11") or
|
(p1_ir_op(31 downto 29)="000" and p1_ir_op(27 downto 26)="00") or
|
(p1_ir_op(31 downto 29)="000" and p1_ir_op(27 downto 26)="00") or
|
(p1_ir_op(31 downto 28)="0100" and p1_ir_op(27 downto 26)="00") or
|
(p1_ir_op(31 downto 28)="0100" and p1_ir_op(27 downto 26)="00") or
|
(p1_ir_op(31 downto 28)="0100" and p1_ir_op(27 downto 26)="10") or
|
(p1_ir_op(31 downto 28)="0100" and p1_ir_op(27 downto 26)="10") or
|
(p1_ir_op(31 downto 28)="1000") or
|
(p1_ir_op(31 downto 28)="1000") or
|
(p1_ir_op(31 downto 28)="1001") or
|
(p1_ir_op(31 downto 28)="1001") or
|
(p1_ir_op(31 downto 28)="1010" and p1_ir_op(27 downto 26)="10") or
|
(p1_ir_op(31 downto 28)="1010" and p1_ir_op(27 downto 26)="10") or
|
(p1_ir_op(31 downto 28)="1010" and p1_ir_op(27 downto 26)="11") or
|
(p1_ir_op(31 downto 28)="1010" and p1_ir_op(27 downto 26)="11") or
|
(p1_ir_op(31 downto 28)="0010" and p1_ir_op(27 downto 26)="01"))
|
(p1_ir_op(31 downto 28)="0010" and p1_ir_op(27 downto 26)="01"))
|
else '0';
|
else '0';
|
|
|
with p1_ir_op select p1_load_alu_set1 <=
|
with p1_ir_op select p1_load_alu_set1 <=
|
'1' when "001000", -- addi
|
'1' when "001000", -- addi
|
'1' when "001001", -- addiu
|
'1' when "001001", -- addiu
|
'1' when "001010", -- slti
|
'1' when "001010", -- slti
|
'1' when "001011", -- sltiu
|
'1' when "001011", -- sltiu
|
'1' when "001100", -- andi
|
'1' when "001100", -- andi
|
'1' when "001101", -- ori
|
'1' when "001101", -- ori
|
'1' when "001110", -- xori
|
'1' when "001110", -- xori
|
'1' when "001111", -- lui
|
'1' when "001111", -- lui
|
'0' when others;
|
'0' when others;
|
p1_load_alu <= (p1_load_alu_set0 or p1_load_alu_set1) and
|
p1_load_alu <= (p1_load_alu_set0 or p1_load_alu_set1) and
|
not p1_unknown_opcode;
|
not p1_unknown_opcode;
|
|
|
p1_ld_upper_hword <= p1_ir_op(27); -- use input upper hword vs. sign extend/zero
|
p1_ld_upper_hword <= p1_ir_op(27); -- use input upper hword vs. sign extend/zero
|
p1_ld_upper_byte <= p1_ir_op(26); -- use input upper byte vs. sign extend/zero
|
p1_ld_upper_byte <= p1_ir_op(26); -- use input upper byte vs. sign extend/zero
|
p1_ld_unsigned <= p1_ir_op(28); -- sign extend vs. zero extend
|
p1_ld_unsigned <= p1_ir_op(28); -- sign extend vs. zero extend
|
|
|
-- ALU input-2 selection: use external data for 2x opcodes (loads)
|
-- ALU input-2 selection: use external data for 2x opcodes (loads)
|
p1_alu_op2_sel_set0 <=
|
p1_alu_op2_sel_set0 <=
|
"11" when p1_ir_op(31 downto 30)="10" or p1_ir_op(29)='1' else
|
"11" when p1_ir_op(31 downto 30)="10" or p1_ir_op(29)='1' else
|
"00";
|
"00";
|
|
|
-- ALU input-2 selection: use registers Hi and Lo for MFHI, MFLO
|
-- ALU input-2 selection: use registers Hi and Lo for MFHI, MFLO
|
p1_alu_op2_sel_set1 <=
|
p1_alu_op2_sel_set1 <=
|
"01" when p1_op_special='1' and (p1_ir_fn="010000" or p1_ir_fn="010010")
|
"01" when p1_op_special='1' and (p1_ir_fn="010000" or p1_ir_fn="010010")
|
else "00";
|
else "00";
|
|
|
-- ALU input-2 final selection
|
-- ALU input-2 final selection
|
p1_alu_op2_sel <= p1_alu_op2_sel_set0 or p1_alu_op2_sel_set1;
|
p1_alu_op2_sel <= p1_alu_op2_sel_set0 or p1_alu_op2_sel_set1;
|
|
|
-- Decode store operations
|
-- Decode store operations
|
p1_do_store <= '1' when
|
p1_do_store <= '1' when
|
p1_ir_op(31 downto 29)="101" and
|
p1_ir_op(31 downto 29)="101" and
|
(p1_ir_op(28 downto 26)="000" or -- SB
|
(p1_ir_op(28 downto 26)="000" or -- SB
|
p1_ir_op(28 downto 26)="001" or -- SH
|
p1_ir_op(28 downto 26)="001" or -- SH
|
p1_ir_op(28 downto 26)="011") and -- SWH
|
p1_ir_op(28 downto 26)="011") and -- SWH
|
p2_exception='0' -- abort when previous instruction triggered exception
|
p2_exception='0' -- abort when previous instruction triggered exception
|
else '0';
|
else '0';
|
p1_store_size <= p1_ir_op(27 downto 26);
|
p1_store_size <= p1_ir_op(27 downto 26);
|
|
|
|
|
-- Extract source and destination C0 register indices
|
-- Extract source and destination C0 register indices
|
p1_c0_rs_num <= p1_ir_reg(15 downto 11);
|
p1_c0_rs_num <= p1_ir_reg(15 downto 11);
|
|
|
-- Decode ALU control signals
|
-- Decode ALU control signals
|
|
|
p1_ac.use_slt <= '1' when (p1_ir_op="000001" and p1_ir_reg(20 downto 17)="01000") or
|
p1_ac.use_slt <= '1' when (p1_ir_op="000001" and p1_ir_reg(20 downto 17)="01000") or
|
(p1_ir_op="000000" and p1_ir_reg(5 downto 1)="10101") or
|
(p1_ir_op="000000" and p1_ir_reg(5 downto 1)="10101") or
|
p1_ir_op="001010" or p1_ir_op="001011"
|
p1_ir_op="001010" or p1_ir_op="001011"
|
else '0';
|
else '0';
|
p1_ac.arith_unsigned <= p1_ac.use_slt and (p1_ir_reg(0) or p1_ir_op(26));
|
p1_ac.arith_unsigned <= p1_ac.use_slt and (p1_ir_reg(0) or p1_ir_op(26));
|
|
|
p1_ac.use_logic(0) <= '1' when (p1_op_special='1' and p1_ir_fn(5 downto 3)/="000") or
|
p1_ac.use_logic(0) <= '1' when (p1_op_special='1' and p1_ir_fn(5 downto 3)/="000") or
|
-- all immediate arith and logic
|
-- all immediate arith and logic
|
p1_ir_op(31 downto 29)="001"
|
p1_ir_op(31 downto 29)="001"
|
else '0';
|
else '0';
|
p1_ac.use_logic(1) <= '1' when (p1_op_special='1' and p1_ir_fn="100111") else '0';
|
p1_ac.use_logic(1) <= '1' when (p1_op_special='1' and p1_ir_fn="100111") else '0';
|
|
|
p1_ac.use_arith <= '1' when p1_ir_op(31 downto 28)="0010" or
|
p1_ac.use_arith <= '1' when p1_ir_op(31 downto 28)="0010" or
|
(p1_op_special='1' and
|
(p1_op_special='1' and
|
(p1_ir_fn(5 downto 2)="1000" or
|
(p1_ir_fn(5 downto 2)="1000" or
|
p1_ir_fn(5 downto 2)="1010"))
|
p1_ir_fn(5 downto 2)="1010"))
|
else '0';
|
else '0';
|
|
|
-- selection of 2nd internal alu operand: {i2, /i2, i2<<16, 0x0}
|
-- selection of 2nd internal alu operand: {i2, /i2, i2<<16, 0x0}
|
p1_ac.neg_sel(1)<= '1' when p1_ir_op(29 downto 26) = "1111" else '0';
|
p1_ac.neg_sel(1)<= '1' when p1_ir_op(29 downto 26) = "1111" else '0';
|
p1_ac.neg_sel(0)<= '1' when p1_ir_op="001010" or
|
p1_ac.neg_sel(0)<= '1' when p1_ir_op="001010" or
|
p1_ir_op="001011" or
|
p1_ir_op="001011" or
|
p1_ir_op(31 downto 28)="0001" or
|
p1_ir_op(31 downto 28)="0001" or
|
(p1_op_special='1' and
|
(p1_op_special='1' and
|
(p1_ir_fn="100010" or
|
(p1_ir_fn="100010" or
|
p1_ir_fn="100011" or
|
p1_ir_fn="100011" or
|
p1_ir_fn(5 downto 2)="1010"))
|
p1_ir_fn(5 downto 2)="1010"))
|
else '0';
|
else '0';
|
p1_ac.cy_in <= p1_ac.neg_sel(0);
|
p1_ac.cy_in <= p1_ac.neg_sel(0);
|
|
|
p1_ac.shift_sel <= p1_ir_fn(1 downto 0);
|
p1_ac.shift_sel <= p1_ir_fn(1 downto 0);
|
|
|
p1_ac.logic_sel <= "00" when (p1_op_special='1' and p1_ir_fn="100100") else
|
p1_ac.logic_sel <= "00" when (p1_op_special='1' and p1_ir_fn="100100") else
|
"01" when (p1_op_special='1' and p1_ir_fn="100101") else
|
"01" when (p1_op_special='1' and p1_ir_fn="100101") else
|
"10" when (p1_op_special='1' and p1_ir_fn="100110") else
|
"10" when (p1_op_special='1' and p1_ir_fn="100110") else
|
"01" when (p1_op_special='1' and p1_ir_fn="100111") else
|
"01" when (p1_op_special='1' and p1_ir_fn="100111") else
|
"00" when (p1_ir_op="001100") else
|
"00" when (p1_ir_op="001100") else
|
"01" when (p1_ir_op="001101") else
|
"01" when (p1_ir_op="001101") else
|
"10" when (p1_ir_op="001110") else
|
"10" when (p1_ir_op="001110") else
|
"11";
|
"11";
|
|
|
p1_ac.shift_amount <= p1_ir_reg(10 downto 6) when p1_ir_fn(2)='0' else p1_rs(4 downto 0);
|
p1_ac.shift_amount <= p1_ir_reg(10 downto 6) when p1_ir_fn(2)='0' else p1_rs(4 downto 0);
|
|
|
|
|
--------------------------------------------------------------------------------
|
--------------------------------------------------------------------------------
|
-- Decoding of unimplemented and privileged instructions
|
-- Decoding of unimplemented and privileged instructions
|
|
|
-- Unimplemented instructions include:
|
-- Unimplemented instructions include:
|
-- 1.- All instructions above architecture MIPS-I except:
|
-- 1.- All instructions above architecture MIPS-I except:
|
-- 1.1.- eret
|
-- 1.1.- eret
|
-- 2.- Unaligned stores and loads (LWL,LWR,SWL,SWR)
|
-- 2.- Unaligned stores and loads (LWL,LWR,SWL,SWR)
|
-- 3.- All CP0 instructions other than mfc0 and mtc0
|
-- 3.- All CP0 instructions other than mfc0 and mtc0
|
-- 4.- All CPi instructions
|
-- 4.- All CPi instructions
|
-- 5.- All cache instructions
|
-- 5.- All cache instructions
|
-- For the time being, we'll decode them all together.
|
-- For the time being, we'll decode them all together.
|
|
|
-- FIXME: some of these should trap but others should just NOP (e.g. EHB)
|
-- FIXME: some of these should trap but others should just NOP (e.g. EHB)
|
|
|
p1_unknown_opcode <= '1' when
|
p1_unknown_opcode <= '1' when
|
-- decode by 'opcode' field
|
-- decode by 'opcode' field
|
p1_ir_op(31 downto 29)="011" or
|
p1_ir_op(31 downto 29)="011" or
|
p1_ir_op(31 downto 29)="110" or
|
p1_ir_op(31 downto 29)="110" or
|
p1_ir_op(31 downto 29)="111" or
|
p1_ir_op(31 downto 29)="111" or
|
(p1_ir_op(31 downto 29)="010" and p1_ir_op(28 downto 26)/="000") or
|
(p1_ir_op(31 downto 29)="010" and p1_ir_op(28 downto 26)/="000") or
|
p1_ir_op="101111" or -- CACHE
|
p1_ir_op="101111" or -- CACHE
|
p1_ir_op="100010" or -- LWL
|
p1_ir_op="100010" or -- LWL
|
p1_ir_op="100110" or -- LWR
|
p1_ir_op="100110" or -- LWR
|
p1_ir_op="101010" or -- SWL
|
p1_ir_op="101010" or -- SWL
|
p1_ir_op="101110" or -- SWR
|
p1_ir_op="101110" or -- SWR
|
p1_ir_op="100111" or
|
p1_ir_op="100111" or
|
p1_ir_op="101100" or
|
p1_ir_op="101100" or
|
p1_ir_op="101101" or
|
p1_ir_op="101101" or
|
-- decode instructions in the 'special' opcode group
|
-- decode instructions in the 'special' opcode group
|
(p1_ir_op="000000" and
|
(p1_ir_op="000000" and
|
(p1_ir_fn(5 downto 4)="11" or
|
(p1_ir_fn(5 downto 4)="11" or
|
p1_ir_fn="000001" or
|
p1_ir_fn="000001" or
|
p1_ir_fn="000101" or
|
p1_ir_fn="000101" or
|
p1_ir_fn="001010" or
|
p1_ir_fn="001010" or
|
p1_ir_fn="001011" or
|
p1_ir_fn="001011" or
|
p1_ir_fn="001110" or
|
p1_ir_fn="001110" or
|
p1_ir_fn(5 downto 2)="0101" or
|
p1_ir_fn(5 downto 2)="0101" or
|
p1_ir_fn(5 downto 2)="0111" or
|
p1_ir_fn(5 downto 2)="0111" or
|
p1_ir_fn(5 downto 2)="1011")) or
|
p1_ir_fn(5 downto 2)="1011")) or
|
-- decode instructions in the 'regimm' opcode group
|
-- decode instructions in the 'regimm' opcode group
|
(p1_ir_op="000001" and
|
(p1_ir_op="000001" and
|
(p1_ir_reg(20 downto 16)/="00000" and -- BLTZ is valid
|
(p1_ir_reg(20 downto 16)/="00000" and -- BLTZ is valid
|
p1_ir_reg(20 downto 16)/="00001" and -- BGEZ is valid
|
p1_ir_reg(20 downto 16)/="00001" and -- BGEZ is valid
|
p1_ir_reg(20 downto 16)/="10000" and -- BLTZAL is valid
|
p1_ir_reg(20 downto 16)/="10000" and -- BLTZAL is valid
|
p1_ir_reg(20 downto 16)/="10001")) -- BGEZAL is valid
|
p1_ir_reg(20 downto 16)/="10001")) -- BGEZAL is valid
|
|
|
else '0';
|
else '0';
|
|
|
p1_cp_unavailable <= '1' when
|
p1_cp_unavailable <= '1' when
|
(p1_set_cp='1' and p1_set_cp0='0') or -- mtc1..3
|
(p1_set_cp='1' and p1_set_cp0='0') or -- mtc1..3
|
(p1_get_cp='1' and p1_get_cp0='0') or -- mfc1..3
|
(p1_get_cp='1' and p1_get_cp0='0') or -- mfc1..3
|
((p1_get_cp0='1' or p1_set_cp0='1' or p1_rfe='1')
|
((p1_get_cp0='1' or p1_set_cp0='1' or p1_rfe='1')
|
and cp0_sr_ku_reg='0')
|
and cp0_sr_ku_reg='0')
|
--and cp0_status(1)='0') -- COP0 user mode
|
--and cp0_status(1)='0') -- COP0 user mode
|
-- FIXME CP1..3 logic missing
|
-- FIXME CP1..3 logic missing
|
else '0';
|
else '0';
|
|
|
--##############################################################################
|
--##############################################################################
|
-- Pipeline registers & pipeline control logic
|
-- Pipeline registers & pipeline control logic
|
|
|
-- Stage 1 pipeline register. Involved in ALU control.
|
-- Stage 1 pipeline register. Involved in ALU control.
|
pipeline_stage1_register:
|
pipeline_stage1_register:
|
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
|
p1_rbank_rs_hazard <= '0';
|
p1_rbank_rs_hazard <= '0';
|
p1_rbank_rt_hazard <= '0';
|
p1_rbank_rt_hazard <= '0';
|
elsif stall_pipeline='0' then
|
elsif stall_pipeline='0' then
|
p1_rbank_rs_hazard <= p0_rbank_rs_hazard;
|
p1_rbank_rs_hazard <= p0_rbank_rs_hazard;
|
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:
|
pipeline_stage1_register2:
|
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
|
p2_muldiv_started <= '0';
|
p2_muldiv_started <= '0';
|
else
|
else
|
p2_muldiv_started <= p1_muldiv_running;
|
p2_muldiv_started <= p1_muldiv_running;
|
end if;
|
end if;
|
end if;
|
end if;
|
end process pipeline_stage1_register2;
|
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
|
-- the pipeline is frozen.
|
-- the pipeline is frozen.
|
-- * When the stall is caused by any other reason, this register freezes with
|
-- * When the stall is caused by any other reason, this register freezes with
|
-- the rest of the machine.
|
-- the rest of the machine.
|
|
|
-- Part of stage 2 register that controls load operation
|
-- Part of stage 2 register that controls load operation
|
pipeline_stage2_register_load_control:
|
pipeline_stage2_register_load_control:
|
process(clk)
|
process(clk)
|
begin
|
begin
|
if clk'event and clk='1' then
|
if clk'event and clk='1' then
|
-- Clear load control, effectively preventing load, at reset or if
|
-- Clear load control, effectively preventing load, at reset or if
|
-- the previous instruction raised an exception.
|
-- the previous instruction raised an exception.
|
if reset='1' or p2_exception='1' then
|
if reset='1' or p2_exception='1' then
|
p2_do_store <= '0';
|
p2_do_store <= '0';
|
p2_do_load <= '0';
|
p2_do_load <= '0';
|
p2_ld_upper_hword <= '0';
|
p2_ld_upper_hword <= '0';
|
p2_ld_upper_byte <= '0';
|
p2_ld_upper_byte <= '0';
|
p2_ld_unsigned <= '0';
|
p2_ld_unsigned <= '0';
|
p2_load_target <= "00000";
|
p2_load_target <= "00000";
|
|
|
-- Load signals from previous stage only if there is no pipeline stall
|
-- Load signals from previous stage only if there is no pipeline stall
|
-- unless the stall is caused by interlock (@note1).
|
-- unless the stall is caused by interlock (@note1).
|
elsif (stall_pipeline='0' or load_interlock='1') then
|
elsif (stall_pipeline='0' or load_interlock='1') then
|
-- Disable reg bank writeback if pipeline is stalled; this prevents
|
-- Disable reg bank writeback if pipeline is stalled; this prevents
|
-- duplicate writes in case the stall is a mem_wait.
|
-- duplicate writes in case the stall is a mem_wait.
|
if pipeline_stalled='0' then
|
if pipeline_stalled='0' then
|
p2_do_load <= p1_do_load;
|
p2_do_load <= p1_do_load;
|
else
|
else
|
p2_do_load <= '0';
|
p2_do_load <= '0';
|
end if;
|
end if;
|
p2_do_store <= p1_do_store;
|
p2_do_store <= p1_do_store;
|
p2_load_target <= p1_rd_num;
|
p2_load_target <= p1_rd_num;
|
p2_ld_upper_hword <= p1_ld_upper_hword;
|
p2_ld_upper_hword <= p1_ld_upper_hword;
|
p2_ld_upper_byte <= p1_ld_upper_byte;
|
p2_ld_upper_byte <= p1_ld_upper_byte;
|
p2_ld_unsigned <= p1_ld_unsigned;
|
p2_ld_unsigned <= p1_ld_unsigned;
|
end if;
|
end if;
|
end if;
|
end if;
|
end process pipeline_stage2_register_load_control;
|
end process pipeline_stage2_register_load_control;
|
|
|
-- All the rest of the stage 2 register
|
-- All the rest of the stage 2 register
|
pipeline_stage2_register_others:
|
pipeline_stage2_register_others:
|
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
|
p2_exception <= '0';
|
p2_exception <= '0';
|
|
|
-- Load signals from previous stage only if there is no pipeline stall
|
-- Load signals from previous stage only if there is no pipeline stall
|
-- unless the stall is caused by interlock (@note1).
|
-- unless the stall is caused by interlock (@note1).
|
elsif (stall_pipeline='0' or load_interlock='1') then
|
elsif (stall_pipeline='0' or load_interlock='1') then
|
p2_rd_addr <= p1_data_addr(1 downto 0);
|
p2_rd_addr <= p1_data_addr(1 downto 0);
|
p2_exception <= p1_exception;
|
p2_exception <= p1_exception;
|
end if;
|
end if;
|
end if;
|
end if;
|
end process pipeline_stage2_register_others;
|
end process pipeline_stage2_register_others;
|
|
|
--------------------------------------------------------------------------------
|
--------------------------------------------------------------------------------
|
-- Pipeline control logic (stall control)
|
-- Pipeline control logic (stall control)
|
|
|
-- FIXME demonstrate that this combinational will not have bad glitches
|
-- FIXME demonstrate that this combinational will not have bad glitches
|
stall_pipeline <= mem_wait or load_interlock or p1_muldiv_stall;
|
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))
|
load_interlock <= '1' when
|
load_interlock <= '1' when
|
p1_do_load='1' and -- this is a load instruction
|
p1_do_load='1' and -- this is a load instruction
|
pipeline_stalled='0' and -- not already stalled (i.e. assert for 1 cycle)
|
pipeline_stalled='0' and -- not already stalled (i.e. assert for 1 cycle)
|
(p1_rs1_hazard='1' or p1_rs2_hazard='1')
|
(p1_rs1_hazard='1' or p1_rs2_hazard='1')
|
else '0';
|
else '0';
|
|
|
|
|
pipeline_stalled <= stalled_interlock or stalled_memwait or stalled_muldiv;
|
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
|
stalled_interlock <= '0';
|
stalled_interlock <= '0';
|
stalled_memwait <= '0';
|
stalled_memwait <= '0';
|
stalled_muldiv <= '0';
|
stalled_muldiv <= '0';
|
else
|
else
|
if mem_wait='1' then
|
if mem_wait='1' then
|
stalled_memwait <= '1';
|
stalled_memwait <= '1';
|
else
|
else
|
stalled_memwait <= '0';
|
stalled_memwait <= '0';
|
end if;
|
end if;
|
|
|
if p1_muldiv_stall='1' then
|
if p1_muldiv_stall='1' then
|
stalled_muldiv <= '1';
|
stalled_muldiv <= '1';
|
else
|
else
|
stalled_muldiv <= '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
|
stalled_interlock <= '1';
|
stalled_interlock <= '1';
|
else
|
else
|
stalled_interlock <= '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;
|
|
|
-- Here's where we stall the pipeline upon load reg bank hazards
|
-- Here's where we stall the pipeline upon load reg bank hazards
|
-- FIXME (@note2) for the time being we stall the pipeline for ALL loads
|
-- FIXME (@note2) for the time being we stall the pipeline for ALL loads
|
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",
|
'0' when "000011",
|
'0' when "000011",
|
'0' when "001111",
|
'0' when "001111",
|
'0' when "001000",
|
'0' when "001000",
|
'1' when others;
|
'1' when others;
|
|
|
with p1_ir_op select p0_uses_rs2 <=
|
with p1_ir_op select p0_uses_rs2 <=
|
'1' when "000000",
|
'1' when "000000",
|
'1' when "000100",
|
'1' when "000100",
|
'1' when "000101",
|
'1' when "000101",
|
'1' when "000110",
|
'1' when "000110",
|
'1' when "000111",
|
'1' when "000111",
|
'1' when "010000",
|
'1' when "010000",
|
'1' when "101000",
|
'1' when "101000",
|
'1' when "101001",
|
'1' when "101001",
|
'1' when "101010",
|
'1' when "101010",
|
'1' when "101011",
|
'1' when "101011",
|
'1' when "101110",
|
'1' when "101110",
|
'0' when others;
|
'0' when others;
|
|
|
|
|
--##############################################################################
|
--##############################################################################
|
-- Data memory interface
|
-- Data memory interface
|
|
|
--------------------------------------------------------------------------------
|
--------------------------------------------------------------------------------
|
-- Memory addressing adder (data address generation)
|
-- Memory addressing adder (data address generation)
|
|
|
p1_data_offset(31 downto 16) <= (others => p1_data_imm(15));
|
p1_data_offset(31 downto 16) <= (others => p1_data_imm(15));
|
p1_data_offset(15 downto 0) <= p1_data_imm(15 downto 0);
|
p1_data_offset(15 downto 0) <= p1_data_imm(15 downto 0);
|
|
|
p1_data_addr <= p1_rs + p1_data_offset;
|
p1_data_addr <= p1_rs + p1_data_offset;
|
|
|
--------------------------------------------------------------------------------
|
--------------------------------------------------------------------------------
|
-- Write enable vector
|
-- Write enable vector
|
|
|
-- byte_we is a function of the write size and alignment
|
-- byte_we is a function of the write size and alignment
|
-- size = {00=1,01=2,11=4}; we 3 is MSB, 0 is LSB; big endian => 00 is msb
|
-- size = {00=1,01=2,11=4}; we 3 is MSB, 0 is LSB; big endian => 00 is msb
|
|
|
p1_we_control <= (mem_wait) & p1_do_store & p1_store_size & p1_data_addr(1 downto 0);
|
p1_we_control <= (mem_wait) & p1_do_store & p1_store_size & p1_data_addr(1 downto 0);
|
--p1_we_control <= (pipeline_stalled) & p1_do_store & p1_store_size & p1_data_addr(1 downto 0);
|
--p1_we_control <= (pipeline_stalled) & p1_do_store & p1_store_size & p1_data_addr(1 downto 0);
|
|
|
-- Bug: For two SW instructions in a row, the 2nd one will be stalled and lost:
|
-- Bug: For two SW instructions in a row, the 2nd one will be stalled and lost:
|
-- the write will never be executed by the cache.
|
-- the write will never be executed by the cache.
|
-- Fixed by stalling immediately after asserting byte_we.
|
-- Fixed by stalling immediately after asserting byte_we.
|
-- FIXME the above fix has been tested but is still under trial (provisional)
|
-- FIXME the above fix has been tested but is still under trial (provisional)
|
|
|
-- The present code will not work in cache-less systems (such as the tb0) if
|
-- The present code will not work in cache-less systems (such as the tb0) if
|
-- it stalls the CPU. Solution: don't allow stalls in cache-less systems.
|
-- it stalls the CPU. Solution: don't allow stalls in cache-less systems.
|
-- FIXME this little mess has to be documented.
|
-- FIXME this little mess has to be documented.
|
|
|
|
|
with p1_we_control select byte_we <=
|
with p1_we_control select byte_we <=
|
"1000" when "010000", -- SB %0
|
"1000" when "010000", -- SB %0
|
"0100" when "010001", -- SB %1
|
"0100" when "010001", -- SB %1
|
"0010" when "010010", -- SB %2
|
"0010" when "010010", -- SB %2
|
"0001" when "010011", -- SB %3
|
"0001" when "010011", -- SB %3
|
"1100" when "010100", -- SH %0
|
"1100" when "010100", -- SH %0
|
"0011" when "010110", -- SH %2
|
"0011" when "010110", -- SH %2
|
"1111" when "011100", -- SW %4
|
"1111" when "011100", -- SW %4
|
"0000" when others; -- all other combinations are spurious so don't write
|
"0000" when others; -- all other combinations are spurious so don't write
|
|
|
-- Data to be stored always comes straight from the reg bank, but it needs to
|
-- Data to be stored always comes straight from the reg bank, but it needs to
|
-- be shifted so that the LSB is aligned to the write address:
|
-- be shifted so that the LSB is aligned to the write address:
|
|
|
data_wr(7 downto 0) <= p1_rt(7 downto 0);
|
data_wr(7 downto 0) <= p1_rt(7 downto 0);
|
|
|
with p1_we_control select data_wr(15 downto 8) <=
|
with p1_we_control select data_wr(15 downto 8) <=
|
p1_rt( 7 downto 0) when "010010", -- SB %2
|
p1_rt( 7 downto 0) when "010010", -- SB %2
|
p1_rt(15 downto 8) when others;
|
p1_rt(15 downto 8) when others;
|
|
|
with p1_we_control select data_wr(23 downto 16) <=
|
with p1_we_control select data_wr(23 downto 16) <=
|
p1_rt( 7 downto 0) when "010001", -- SB %1
|
p1_rt( 7 downto 0) when "010001", -- SB %1
|
p1_rt( 7 downto 0) when "010100", -- SH %0
|
p1_rt( 7 downto 0) when "010100", -- SH %0
|
p1_rt(23 downto 16) when others;
|
p1_rt(23 downto 16) when others;
|
|
|
with p1_we_control select data_wr(31 downto 24) <=
|
with p1_we_control select data_wr(31 downto 24) <=
|
p1_rt( 7 downto 0) when "010000", -- SB %0
|
p1_rt( 7 downto 0) when "010000", -- SB %0
|
p1_rt(15 downto 8) when "010100", -- SH %0
|
p1_rt(15 downto 8) when "010100", -- SH %0
|
p1_rt(31 downto 24) when others;
|
p1_rt(31 downto 24) when others;
|
|
|
|
|
--##############################################################################
|
--##############################################################################
|
-- CP0 and exception processing
|
-- CP0 and exception processing
|
|
|
cp0_registers:
|
cp0_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
|
-- KU/IE="10" ==> mode=kernel; ints=disabled
|
-- KU/IE="10" ==> mode=kernel; ints=disabled
|
cp0_status <= "000010"; -- bits (KUo/IEo & KUp/IEp) reset to zero
|
cp0_status <= "000010"; -- bits (KUo/IEo & KUp/IEp) reset to zero
|
cp0_sr_ku_reg <= '1'; -- delayed KU flag
|
cp0_sr_ku_reg <= '1'; -- delayed KU flag
|
cp0_cache_control <= "00";
|
cp0_cache_control <= "00";
|
cp0_cause_exc_code <= "00000";
|
cp0_cause_exc_code <= "00000";
|
cp0_cause_bd <= '0';
|
cp0_cause_bd <= '0';
|
else
|
else
|
if pipeline_stalled='0' then
|
if pipeline_stalled='0' then
|
if p1_exception='1' then
|
if p1_exception='1' then
|
-- Exception: do all that needs to be done right here
|
-- Exception: do all that needs to be done right here
|
|
|
-- Save PC in EPC register...
|
-- Save PC in EPC register...
|
cp0_epc <= p0_pc_restart;
|
cp0_epc <= p0_pc_restart;
|
-- ... set KU flag to Kernel mode ...
|
-- ... set KU flag to Kernel mode ...
|
cp0_status(1) <= '1';
|
cp0_status(1) <= '1';
|
-- ... and 'push' old KU/IE flag values
|
-- ... and 'push' old KU/IE flag values
|
cp0_status(5 downto 4) <= cp0_status(3 downto 2);
|
cp0_status(5 downto 4) <= cp0_status(3 downto 2);
|
cp0_status(3 downto 2) <= cp0_status(1 downto 0);
|
cp0_status(3 downto 2) <= cp0_status(1 downto 0);
|
|
|
-- Set the 'exception cause' code...
|
-- Set the 'exception cause' code...
|
if p1_unknown_opcode='1' then
|
if p1_unknown_opcode='1' then
|
cp0_cause_exc_code <= "01010"; -- bad opcode ('reserved')
|
cp0_cause_exc_code <= "01010"; -- bad opcode ('reserved')
|
elsif p1_cp_unavailable='1' then
|
elsif p1_cp_unavailable='1' then
|
-- this triggers for mtc0/mfc0 in user mode too
|
-- this triggers for mtc0/mfc0 in user mode too
|
cp0_cause_exc_code <= "01011"; -- CP* unavailable
|
cp0_cause_exc_code <= "01011"; -- CP* unavailable
|
else
|
else
|
if p1_ir_fn(0)='0' then
|
if p1_ir_fn(0)='0' then
|
cp0_cause_exc_code <= "01000"; -- syscall
|
cp0_cause_exc_code <= "01000"; -- syscall
|
else
|
else
|
cp0_cause_exc_code <= "01001"; -- break
|
cp0_cause_exc_code <= "01001"; -- break
|
end if;
|
end if;
|
end if;
|
end if;
|
-- ... and the BD flag for exceptions in delay slots
|
-- ... and the BD flag for exceptions in delay slots
|
cp0_cause_bd <= cp0_in_delay_slot;
|
cp0_cause_bd <= cp0_in_delay_slot;
|
|
|
elsif p1_rfe='1' and cp0_status(1)='1' then
|
elsif p1_rfe='1' and cp0_status(1)='1' then
|
-- RFE: restore ('pop') the KU/IE flag values
|
-- RFE: restore ('pop') the KU/IE flag values
|
|
|
cp0_status(3 downto 2) <= cp0_status(5 downto 4);
|
cp0_status(3 downto 2) <= cp0_status(5 downto 4);
|
cp0_status(1 downto 0) <= cp0_status(3 downto 2);
|
cp0_status(1 downto 0) <= cp0_status(3 downto 2);
|
|
|
elsif p1_set_cp0='1' and cp0_status(1)='1' then
|
elsif p1_set_cp0='1' and cp0_status(1)='1' then
|
-- MTC0: load CP0[xx] with Rt
|
-- MTC0: load CP0[xx] with Rt
|
|
|
-- NOTE: in MTCx, the source register is Rt
|
-- NOTE: in MTCx, the source register is Rt
|
-- FIXME this works because only SR is writeable; when
|
-- FIXME this works because only SR is writeable; when
|
-- CP0[13].IP1-0 are implemented, check for CP0 reg index.
|
-- CP0[13].IP1-0 are implemented, check for CP0 reg index.
|
cp0_status <= p1_rt(cp0_status'high downto 0);
|
cp0_status <= p1_rt(cp0_status'high downto 0);
|
cp0_cache_control <= p1_rt(17 downto 16);
|
cp0_cache_control <= p1_rt(17 downto 16);
|
end if;
|
end if;
|
end if;
|
end if;
|
if stall_pipeline='0' then
|
if stall_pipeline='0' then
|
cp0_sr_ku_reg <= cp0_status(1);
|
cp0_sr_ku_reg <= cp0_status(1);
|
end if;
|
end if;
|
end if;
|
end if;
|
end if;
|
end if;
|
end process cp0_registers;
|
end process cp0_registers;
|
|
|
cache_enable <= cp0_cache_control(17);
|
cache_enable <= cp0_cache_control(17);
|
ic_invalidate <= cp0_cache_control(16);
|
ic_invalidate <= cp0_cache_control(16);
|
|
|
cp0_cause_ce <= "00"; -- FIXME CP* traps merged with unimplemented opcode traps
|
cp0_cause_ce <= "00"; -- FIXME CP* traps merged with unimplemented opcode traps
|
cp0_cause <= cp0_cause_bd & '0' & cp0_cause_ce &
|
cp0_cause <= cp0_cause_bd & '0' & cp0_cause_ce &
|
X"00000" & '0' & cp0_cause_exc_code & "00";
|
X"00000" & '0' & cp0_cause_exc_code & "00";
|
|
|
-- FIXME the mux should mask to zero for any unused reg index
|
-- FIXME the mux should mask to zero for any unused reg index
|
with p1_c0_rs_num select cp0_reg_read <=
|
with p1_c0_rs_num select cp0_reg_read <=
|
X"000000" & "00" & cp0_status when "01100",
|
X"000000" & "00" & cp0_status when "01100",
|
cp0_cause when "01101",
|
cp0_cause when "01101",
|
cp0_epc & "00" when others;
|
cp0_epc & "00" when others;
|
|
|
|
|
end architecture rtl;
|
end architecture rtl;
|
|
|
--------------------------------------------------------------------------------
|
--------------------------------------------------------------------------------
|
-- Implementation notes
|
-- Implementation notes
|
--------------------------------------------------------------------------------
|
--------------------------------------------------------------------------------
|
-- @note1 :
|
-- @note1 :
|
-- This is the meaning of these two signals:
|
-- This is the meaning of these two signals:
|
-- pipeline_stalled & stalled_interlock =>
|
-- 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
|
--
|
--
|
-- Just to clarify, 'stage X stalled' here means that the registers named
|
-- Just to clarify, 'stage X stalled' here means that the registers named
|
-- pX_* don't load.
|
-- pX_* don't load.
|
--
|
--
|
-- The register bank WE is enabled when the pipeline is not stalled and when
|
-- The register bank WE is enabled when the pipeline is not stalled and when
|
-- it is stalled because of a load interlock; so that in case of interlock the
|
-- it is stalled because of a load interlock; so that in case of interlock the
|
-- load operation can complete while the rest of the pipeline is frozen.
|
-- load operation can complete while the rest of the pipeline is frozen.
|
--
|
--
|
-- @note2:
|
-- @note2:
|
-- The logic that checks register indices for data hazards is 'commented out'
|
-- The logic that checks register indices for data hazards is 'commented out'
|
-- because it has not been tested yet.
|
-- because it has not been tested yet.
|
--
|
--
|
-- @note3:
|
-- @note3:
|
-- CP0 instructions (mtc0, mfc0 and rfe) are only partially decoded.
|
-- CP0 instructions (mtc0, mfc0 and rfe) are only partially decoded.
|
-- This is possible because no other VALID MIPS* opcode shares the decoded
|
-- This is possible because no other VALID MIPS* opcode shares the decoded
|
-- part; that is, we're not going to misdecode a MIPS32 opcode, but we MIGHT
|
-- part; that is, we're not going to misdecode a MIPS32 opcode, but we MIGHT
|
-- mistake a bad opcode for a COP0; we'll live with that for the time being.
|
-- mistake a bad opcode for a COP0; we'll live with that for the time being.
|
--
|
--
|
--------------------------------------------------------------------------------
|
--------------------------------------------------------------------------------
|
|
|