Reworked exception FSM:
- Pipeline is now flushed and finished and all dependencies are solved before entering exception handler - User mode writes on status register are now correctly finished before status is altered by exception - Processor stalls for 2 cycles after RFE to ensure that status register is correct in user mode - Added int-port Committed on the Free edition of March Hare Software CVSNT Server. Upgrade to CVS Suite for more features and support: http://march-hare.com/cvsnt/ git-svn-id: http://moon:8086/svn/vhdl/trunk@426 cc03376c-175c-47c8-b038-4cd826a8556b
This commit is contained in:
@@ -40,6 +40,7 @@ entity cop is
|
||||
(
|
||||
rst : in STD_LOGIC;
|
||||
clk : in STD_LOGIC;
|
||||
int : in unsigned(5 downto 0);
|
||||
ir_en : in STD_LOGIC;
|
||||
ir : in word_t;
|
||||
ctrl_in : in cop0_ctrl_in_t;
|
||||
@@ -54,6 +55,8 @@ architecture Behavioral of cop is
|
||||
signal epc : word_t;
|
||||
signal cause : word_t;
|
||||
signal status : word_t;
|
||||
signal imem_addr : word_t;
|
||||
signal imem_addr_we : STD_LOGIC;
|
||||
signal BadVAddr : word_t;
|
||||
signal exc_code : unsigned(4 downto 0);
|
||||
signal test_reg : word_t;
|
||||
@@ -68,8 +71,6 @@ architecture Behavioral of cop is
|
||||
signal im : unsigned(7 downto 0);
|
||||
signal status_save : STD_LOGIC;
|
||||
signal status_rest : STD_LOGIC;
|
||||
signal exception : STD_LOGIC;
|
||||
signal exception_end : STD_LOGIC;
|
||||
signal eflags : exc_flags_t;
|
||||
signal exc_enable : STD_LOGIC;
|
||||
signal icache_info : unsigned(7 downto 0);
|
||||
@@ -77,6 +78,7 @@ architecture Behavioral of cop is
|
||||
|
||||
type cop_pipe_t is record
|
||||
opc : opcode_t;
|
||||
RFE : std_logic;
|
||||
CO : std_logic;
|
||||
reg_ptr : reg_ptr_t;
|
||||
rs : reg_ptr_t;
|
||||
@@ -102,7 +104,7 @@ architecture Behavioral of cop is
|
||||
return result;
|
||||
end eval_int;
|
||||
|
||||
type exc_state_t is (exc_init, exc_idle, exc_commit_ID, exc_commit_EX, exc_commit_MEM);
|
||||
type exc_state_t is (exc_idle, exc_pipe_flush, exc_commit, exc_inject, exc_enter, exc_leave, exc_left);
|
||||
signal exc_state, exc_staten : exc_state_t;
|
||||
|
||||
--------------------------------------------------------------------------
|
||||
@@ -119,10 +121,10 @@ begin
|
||||
cop_pipe_ID.CO <= ir(25);
|
||||
cop_pipe_ID.re <= cop_pipe_ID.cs when (cop_pipe_ID.opc = "111000" or (cop_pipe_ID.opc = "010000" and cop_pipe_ID.rs = "00000")) else '0';
|
||||
cop_pipe_ID.we <= cop_pipe_ID.cs when (cop_pipe_ID.opc = "110000" or (cop_pipe_ID.opc = "010000" and cop_pipe_ID.rs = "00100")) else '0';
|
||||
|
||||
cop_pipe_ID.RFE <= cop_pipe_ID.cs when (cop_pipe_ID.CO = '1' and cop_pipe_ID.func = "010000") else '0';
|
||||
ctrl_out.RE <= status(25);
|
||||
ctrl_out.user_mode <= status(1);
|
||||
ctrl_out.int <= eflags.Int;
|
||||
ctrl_out.int <= eval_int(ip) and status(0);
|
||||
|
||||
cop_pipe_ID.reg_ptr <= cop_pipe_ID.rd when cop_pipe_ID.opc = "010000" else cop_pipe_ID.rt;
|
||||
|
||||
@@ -137,58 +139,71 @@ begin
|
||||
eflags.Sys <= ctrl_in.events.syscall;
|
||||
eflags.Bp <= ctrl_in.events.break;
|
||||
eflags.RI <= ctrl_in.events.illegal;
|
||||
eflags.Int <= eval_int(ip) and status(0);
|
||||
eflags.Int <= ctrl_in.events.int;
|
||||
|
||||
exception <= eflags.Ov or eflags.Sys or eflags.Bp or eflags.RI or eflags.IAdEL or eflags.IAdEK or eflags.DAdEL or eflags.DAdES or eflags.Int after 1 ns;
|
||||
|
||||
exception_state:
|
||||
process(exc_state, ctrl_in, exception)
|
||||
process(exc_state, ctrl_in, cop_pipe_ID)
|
||||
begin
|
||||
|
||||
exc_enable <= '0';
|
||||
ctrl_out.exc_inject <= '0';
|
||||
ctrl_out.exc_commit <= '0';
|
||||
ctrl_out.exc_pending <= '0';
|
||||
ctrl_out.exc_exit <= '0';
|
||||
epc_reg_we <= '0';
|
||||
code_reg_we <= '0';
|
||||
status_save <= '0';
|
||||
eflags_reg_we <= '0';
|
||||
status_rest <= '0';
|
||||
imem_addr_we <= '0';
|
||||
|
||||
exc_staten <= exc_state;
|
||||
|
||||
case exc_state is
|
||||
|
||||
when exc_init =>
|
||||
exc_staten <= exc_idle;
|
||||
|
||||
when exc_idle =>
|
||||
exc_enable <= '1';
|
||||
if exception = '1' then
|
||||
status_save <= '1';
|
||||
eflags_reg_we <= '1';
|
||||
code_reg_we <= '1';
|
||||
exc_staten <= exc_commit_ID;
|
||||
if cop_pipe_ID.RFE = '1' then
|
||||
exc_staten <= exc_leave;
|
||||
ctrl_out.exc_exit <= '1';
|
||||
ctrl_out.exc_commit <= '1';
|
||||
elsif ctrl_in.exc_req = '1' then
|
||||
exc_staten <= exc_pipe_flush;
|
||||
imem_addr_we <= '1';
|
||||
end if;
|
||||
|
||||
when exc_commit_ID =>
|
||||
when exc_pipe_flush =>
|
||||
ctrl_out.exc_pending <= '1';
|
||||
ctrl_out.exc_commit <= '1';
|
||||
if ctrl_in.exc_ack = '1' then
|
||||
exc_staten <= exc_commit;
|
||||
end if;
|
||||
|
||||
when exc_commit =>
|
||||
ctrl_out.exc_pending <= '1';
|
||||
ctrl_out.exc_commit <= '1';
|
||||
if ctrl_in.sdu.ID_stall = '0' then
|
||||
exc_staten <= exc_commit_EX;
|
||||
end if;
|
||||
|
||||
when exc_commit_EX =>
|
||||
ctrl_out.exc_pending <= '1';
|
||||
ctrl_out.exc_commit <= '1';
|
||||
if ctrl_in.sdu.stall_all = '0' then
|
||||
exc_staten <= exc_commit_MEM;
|
||||
exc_staten <= exc_inject;
|
||||
end if;
|
||||
|
||||
when exc_commit_MEM =>
|
||||
when exc_inject =>
|
||||
ctrl_out.exc_pending <= '1';
|
||||
if ctrl_in.sdu.stall_all = '0' then
|
||||
epc_reg_we <= '1';
|
||||
exc_staten <= exc_idle;
|
||||
end if;
|
||||
ctrl_out.exc_inject <= '1';
|
||||
ctrl_out.exc_commit <= '1';
|
||||
code_reg_we <= '1';
|
||||
status_save <= '1';
|
||||
epc_reg_we <= '1';
|
||||
exc_staten <= exc_enter;
|
||||
|
||||
when exc_enter =>
|
||||
ctrl_out.exc_pending <= '1';
|
||||
exc_staten <= exc_idle;
|
||||
|
||||
when exc_leave =>
|
||||
exc_staten <= exc_left;
|
||||
status_rest <= '1';
|
||||
ctrl_out.exc_exit <= '1';
|
||||
ctrl_out.exc_commit <= '1';
|
||||
|
||||
when exc_left =>
|
||||
exc_staten <= exc_idle;
|
||||
|
||||
when others =>
|
||||
exc_staten <= exc_idle;
|
||||
@@ -196,12 +211,22 @@ exception_state:
|
||||
end case;
|
||||
end process;
|
||||
|
||||
exception_last_imem_addr:
|
||||
process(clk)
|
||||
begin
|
||||
if rising_edge(clk) then
|
||||
if imem_addr_we = '1' then
|
||||
imem_addr <= ctrl_in.imem_addr;
|
||||
end if;
|
||||
end if;
|
||||
end process;
|
||||
|
||||
exception_state_next:
|
||||
process(clk)
|
||||
begin
|
||||
if rising_edge(clk) then
|
||||
if rst = '1' then
|
||||
exc_state <= exc_init;
|
||||
exc_state <= exc_idle;
|
||||
else
|
||||
exc_state <= exc_staten;
|
||||
end if;
|
||||
@@ -244,10 +269,10 @@ cop_exception_map:
|
||||
exc_code <= "01010";
|
||||
elsif eflags.IAdEL = '1' then
|
||||
exc_code <= "00100";
|
||||
BadVAddr <= ctrl_in.imem_addr;
|
||||
BadVAddr <= imem_addr;
|
||||
elsif eflags.IAdEK = '1' then
|
||||
exc_code <= "00100";
|
||||
BadVAddr <= ctrl_in.imem_addr;
|
||||
BadVAddr <= imem_addr;
|
||||
elsif eflags.DAdEL = '1' then
|
||||
exc_code <= "00100";
|
||||
BadVAddr <= ctrl_in.dmem_addr;
|
||||
@@ -261,9 +286,6 @@ cop_exception_map:
|
||||
end if;
|
||||
end process;
|
||||
|
||||
status_rest <= exception_end and ctrl_in.exc_left;
|
||||
|
||||
|
||||
ctrl_out.icache.inv_addr <= test_reg;
|
||||
ctrl_out.dcache.inv_addr <= test_reg;
|
||||
|
||||
@@ -292,25 +314,6 @@ cop_cache_op:
|
||||
end if;
|
||||
end process;
|
||||
|
||||
cop_status_restore:
|
||||
process(clk)
|
||||
begin
|
||||
if rising_edge(clk) then
|
||||
if rst = '1' then
|
||||
exception_end <= '0';
|
||||
ctrl_out.exc_exit <= '0';
|
||||
else
|
||||
if cop_pipe_ID.CO = '1' and cop_pipe_ID.func = "010000" and exception_end = '0' then -- RFE
|
||||
exception_end <= cop_pipe_ID.cs;
|
||||
ctrl_out.exc_exit <= cop_pipe_ID.cs;
|
||||
elsif exception_end = '1' and ctrl_in.exc_left = '1' then
|
||||
exception_end <= '0';
|
||||
ctrl_out.exc_exit <= '0';
|
||||
end if;
|
||||
end if;
|
||||
end if;
|
||||
end process;
|
||||
|
||||
cop_ip_reg_write:
|
||||
process(clk)
|
||||
begin
|
||||
@@ -322,7 +325,7 @@ cop_ip_reg_write:
|
||||
ip(1 downto 0) <= din(9 downto 8) and im(1 downto 0);
|
||||
end if;
|
||||
end if;
|
||||
ip(7 downto 2) <= ctrl_in.events.Int and im(7 downto 2);
|
||||
ip(7 downto 2) <= int and im(7 downto 2);
|
||||
end if;
|
||||
end process;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user