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:
2009-04-11 08:34:50 +00:00
parent ae50048039
commit d3e486b6d5
+63 -60
View File
@@ -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;