mirror of
https://github.com/Gehstock/Mist_FPGA.git
synced 2026-04-25 03:54:57 +00:00
935 lines
43 KiB
VHDL
935 lines
43 KiB
VHDL
------------------------------------------------------------------------
|
|
---- ----
|
|
---- WF68K30L IP Core: this is the exception handler module. ----
|
|
---- ----
|
|
---- Description: ----
|
|
---- This is the exception handler which is responsible for the ----
|
|
---- interrupt management of the external interrupt and internal ----
|
|
---- exception processing. It manages auto-vectored interrupt ----
|
|
---- cycles, priority resolving and correct vector numbers. ----
|
|
---- For further information concerning the functionality of this ----
|
|
---- module refer to the MC68030 User's Manual and to the MC68K ----
|
|
---- family Programmer's Reference Manual. ----
|
|
------------------------------------------------------------------------
|
|
---- ----
|
|
---- Remarks: ----
|
|
---- The relationship between the STATUSn signal and the execution ----
|
|
---- of the next pending exception is handled by the BUSY signals. ----
|
|
---- If the pending interrupt is not signaled in time, when the ----
|
|
---- main controller signal STATUSn, the next instruction is ----
|
|
---- executed and afterwards the exception. When the pending ----
|
|
---- exception is asserted before the STATUSn of one of the main ----
|
|
---- controller, the exception is executed immediately. ----
|
|
---- ----
|
|
---- A bus error at an instruction boundary may occur, when the ----
|
|
---- operation word fetched from the instruction pipe is invalid. ----
|
|
---- Bus errors which occur at the time of the instruction boundary ----
|
|
---- but where released early or at the same time due to the pipe- ----
|
|
---- lined structure are treated as regular bus errors not related ----
|
|
---- with the instruction boundary. The signal IBOUND is used to ----
|
|
---- handle this situations correctly. ----
|
|
---- ----
|
|
---- This exception handler uses a simple logic for the handling ----
|
|
---- the RTE instruction. In comparision to the full featured 68K30 ----
|
|
---- it cannot complete from defective bus exception stack frames. ----
|
|
---- It is assumed, that a software handler has modified the images ----
|
|
---- in the exception stack frame for a bus handler so that the RTE ----
|
|
---- instruction restores from a correct stack frame. ----
|
|
---- ----
|
|
---- Author(s): ----
|
|
---- - Wolfgang Foerster, wf@experiment-s.de; wf@inventronik.de ----
|
|
---- ----
|
|
------------------------------------------------------------------------
|
|
---- ----
|
|
---- Copyright © 2014-2019 Wolfgang Foerster Inventronik GmbH. ----
|
|
---- ----
|
|
---- This documentation describes Open Hardware and is licensed ----
|
|
---- under the CERN OHL v. 1.2. You may redistribute and modify ----
|
|
---- this documentation under the terms of the CERN OHL v.1.2. ----
|
|
---- (http://ohwr.org/cernohl). This documentation is distributed ----
|
|
---- WITHOUT ANY EXPRESS OR IMPLIED WARRANTY, INCLUDING OF ----
|
|
---- MERCHANTABILITY, SATISFACTORY QUALITY AND FITNESS FOR A ----
|
|
---- PARTICULAR PURPOSE. Please see the CERN OHL v.1.2 for ----
|
|
---- applicable conditions ----
|
|
---- ----
|
|
------------------------------------------------------------------------
|
|
--
|
|
-- Revision History
|
|
--
|
|
-- Revision 2K14B 20141201 WF
|
|
-- Initial Release.
|
|
-- Revision 2K16A 20141201 WF
|
|
-- Fixed a bug in PC_LOAD.
|
|
-- Revision 2K18A 20180620 WF
|
|
-- Removed REST_BIW_0.
|
|
-- Removed PC_OFFSET.
|
|
-- Fixed PC restoring during exception processing.
|
|
-- Fixed the vector calculation of INT vectors.
|
|
-- Fixed faulty modeling in IRQ_FILTER.
|
|
-- Implemented the AVEC_FILTER to better meet bus timings.
|
|
-- The RTE exception has now highest priority (avoids mismatch).
|
|
-- TOP, CONTROL, Exception Handler Opcode Decoder: Rearranged PC_INC and ipipe flush logic.
|
|
-- Update the IRQ mask only for RESET and interrupts.
|
|
-- External interrupts are postponed if any system controllers are in initialize operation status.
|
|
-- RTE now loads the address offset correctly when entering the handler.
|
|
-- Rearranged address error handling.
|
|
-- Revision 2K19B 20191224 WF
|
|
-- Introduced signal synchronization in the P_D process to avoid malfunction by hazards.
|
|
-- The processor VERSION is now 32 bit wide.
|
|
--
|
|
|
|
library work;
|
|
use work.WF68K30L_PKG.all;
|
|
|
|
library ieee;
|
|
use ieee.std_logic_1164.all;
|
|
use ieee.std_logic_unsigned.all;
|
|
|
|
entity WF68K30L_EXCEPTION_HANDLER is
|
|
generic(VERSION : std_logic_vector(31 downto 0) := x"20191224");
|
|
port(
|
|
CLK : in std_logic;
|
|
RESET : in bit;
|
|
|
|
BUSY_MAIN : in bit;
|
|
BUSY_OPD : in bit;
|
|
|
|
EXH_REQ : out bit;
|
|
BUSY_EXH : out bit;
|
|
|
|
ADR_IN : in std_logic_vector(31 downto 0);
|
|
ADR_CPY : out std_logic_vector(31 downto 0);
|
|
ADR_OFFSET : out std_logic_vector(31 downto 0);
|
|
CPU_SPACE : out bit;
|
|
|
|
DATA_0 : in std_logic;
|
|
DATA_RD : out bit;
|
|
DATA_WR : out bit;
|
|
DATA_IN : in std_logic_vector(31 downto 0);
|
|
|
|
OP_SIZE : out OP_SIZETYPE; -- Operand size.
|
|
DATA_RDY : in bit;
|
|
DATA_VALID : in std_logic;
|
|
|
|
OPCODE_RDY : in bit; -- OPCODE is available.
|
|
OPD_ACK : in bit; -- Opword is available.
|
|
OW_VALID : in std_logic; -- Status from the opcode decoder.
|
|
|
|
STATUS_REG_IN : in std_logic_vector(15 downto 0);
|
|
SR_CPY : out std_logic_vector(15 downto 0);
|
|
SR_INIT : out bit;
|
|
SR_CLR_MBIT : out bit;
|
|
SR_WR : out bit;
|
|
|
|
ISP_DEC : out bit;
|
|
ISP_LOAD : out bit;
|
|
PC_INC : out bit;
|
|
PC_LOAD : out bit;
|
|
PC_RESTORE : out bit;
|
|
|
|
STACK_FORMAT : out std_logic_vector(3 downto 0);
|
|
STACK_POS : out integer range 0 to 46;
|
|
|
|
SP_ADD_DISPL : out bit;
|
|
DISPLACEMENT : out std_logic_vector(7 downto 0);
|
|
|
|
IPIPE_FILL : out bit;
|
|
IPIPE_FLUSH : out bit;
|
|
REFILLn : out std_logic;
|
|
RESTORE_ISP_PC : out bit;
|
|
|
|
HALT_OUTn : out std_logic;
|
|
STATUSn : out bit;
|
|
|
|
-- Interrupt controls:
|
|
INT_TRIG : in bit;
|
|
IRQ_IN : in std_logic_vector(2 downto 0);
|
|
IRQ_PEND : out std_logic_vector(2 downto 0);
|
|
AVECn : in std_logic;
|
|
IPENDn : out std_logic;
|
|
IVECT_OFFS : out std_logic_vector(9 downto 0); -- Interrupt vector offset.
|
|
|
|
|
|
-- Trap signals:
|
|
TRAP_AERR : in bit;
|
|
TRAP_BERR : in bit;
|
|
TRAP_CHK : in bit;
|
|
TRAP_DIVZERO : in bit;
|
|
TRAP_ILLEGAL : in bit;
|
|
TRAP_CODE_OPC : in TRAPTYPE_OPC; -- T_1010, T_1111, T_ILLEGAL, T_TRAP, T_PRIV.
|
|
TRAP_VECTOR : in std_logic_vector(3 downto 0);
|
|
TRAP_cc : in bit;
|
|
TRAP_V : in bit;
|
|
EX_TRACE_IN : in bit;
|
|
VBR_WR : in bit;
|
|
VBR : out std_logic_vector(31 downto 0)
|
|
);
|
|
end entity WF68K30L_EXCEPTION_HANDLER;
|
|
|
|
architecture BEHAVIOR of WF68K30L_EXCEPTION_HANDLER is
|
|
type EX_STATES is (IDLE, BUILD_STACK, BUILD_TSTACK, CALC_VECT_No, EXAMINE_VERSION, GET_VECTOR, HALTED, INIT, READ_BOTTOM,
|
|
READ_TOP, REFILL_PIPE, RESTORE_ISP, RESTORE_PC, RESTORE_STATUS, UPDATE_PC, SWITCH_STATE, VALIDATE_FRAME);
|
|
|
|
type EXCEPTIONS is (EX_NONE, EX_1010, EX_1111, EX_AERR, EX_BERR, EX_CHK, EX_DIVZERO, EX_FORMAT, EX_ILLEGAL,
|
|
EX_INT, EX_PRIV, EX_RESET, EX_RTE, EX_TRACE, EX_TRAP, EX_TRAPcc, EX_TRAPV);
|
|
|
|
signal ACCESS_ERR : bit;
|
|
signal AVEC : bit;
|
|
signal DATA_RD_I : bit;
|
|
signal DATA_WR_I : bit;
|
|
signal DOUBLE_BUSFLT : bit;
|
|
signal EXCEPTION : EXCEPTIONS; -- Currently executed exception.
|
|
signal EX_STATE : EX_STATES := IDLE;
|
|
signal NEXT_EX_STATE : EX_STATES;
|
|
signal EX_P_1010 : bit; -- ..._P are the pending exceptions.
|
|
signal EX_P_1111 : bit;
|
|
signal EX_P_AERR : bit;
|
|
signal EX_P_BERR : bit;
|
|
signal EX_P_CHK : bit;
|
|
signal EX_P_DIVZERO : bit;
|
|
signal EX_P_FORMAT : bit;
|
|
signal EX_P_ILLEGAL : bit;
|
|
signal EX_P_INT : bit;
|
|
signal EX_P_RESET : bit;
|
|
signal EX_P_RTE : bit;
|
|
signal EX_P_PRIV : bit;
|
|
signal EX_P_TRACE : bit;
|
|
signal EX_P_TRAP : bit;
|
|
signal EX_P_TRAPcc : bit;
|
|
signal EX_P_TRAPV : bit;
|
|
signal INT_VECT : std_logic_vector(31 downto 0); -- Interrupt vector.
|
|
signal IBOUND : boolean;
|
|
signal IRQ : std_logic_vector(2 downto 0);
|
|
signal IRQ_PEND_I : std_logic_vector(2 downto 0);
|
|
signal MBIT : std_logic;
|
|
signal PIPE_CNT : std_logic_vector(1 downto 0);
|
|
signal PIPE_FULL : boolean;
|
|
signal STACK_CNT : integer range 0 to 46;
|
|
signal STACK_FORMAT_I : std_logic_vector(3 downto 0);
|
|
signal SYS_INIT : bit;
|
|
begin
|
|
BUSY_EXH <= '1' when EX_STATE /= IDLE else '0';
|
|
|
|
IRQ_FILTER : process
|
|
-- This logic is intended to avoid spurious IRQs due
|
|
-- to setup / hold violations (IRQ_IN may operate in
|
|
-- a different clock domain).
|
|
variable IRQ_TMP_1 : std_logic_vector(2 downto 0) := "000";
|
|
variable IRQ_TMP_2 : std_logic_vector(2 downto 0) := "000";
|
|
begin
|
|
wait until CLK = '0' and CLK' event;
|
|
if IRQ_TMP_1 = IRQ_TMP_2 then
|
|
IRQ <= IRQ_TMP_2;
|
|
end if;
|
|
IRQ_TMP_2 := IRQ_TMP_1;
|
|
IRQ_TMP_1 := IRQ_IN;
|
|
end process IRQ_FILTER;
|
|
|
|
AVEC_FILTER : process
|
|
-- We need a flip flop for the incoming AVECn to meet
|
|
-- the timing requirements of the bus interface. AVECn
|
|
-- is asserted (low active) before DATA_RDY of the
|
|
-- bus interface. AVEC stays asserted until DATA_RDY.
|
|
begin
|
|
wait until CLK = '1' and CLK' event;
|
|
if AVECn = '0' then
|
|
AVEC <= '1';
|
|
elsif DATA_RDY = '1' or RESET = '1' then
|
|
AVEC <= '0';
|
|
end if;
|
|
end process AVEC_FILTER;
|
|
|
|
INSTRUCTION_BOUNDARY: process
|
|
-- This flip flop indicates a bus error exception,
|
|
-- when the micro sequencer is at an instruction
|
|
-- boundary.
|
|
begin
|
|
wait until CLK = '1' and CLK' event;
|
|
if RESET = '1' then
|
|
IBOUND <= false;
|
|
elsif OPD_ACK = '1' and OW_VALID = '0' then
|
|
IBOUND <= true;
|
|
elsif EX_STATE = BUILD_STACK then
|
|
IBOUND <= false;
|
|
end if;
|
|
end process INSTRUCTION_BOUNDARY;
|
|
|
|
PENDING: process
|
|
-- The exceptions which occurs are stored in this pending register until the
|
|
-- interrupt handler handled the respective exception.
|
|
-- The TRAP_PRIV, TRAP_1010, TRAP_1111, TRAP_ILLEGAL, TRAP_OP and TRAP_V may be a strobe
|
|
-- of 1 clock period. All others must be strobes of 1 clock period..
|
|
variable INT7_TRIG : boolean;
|
|
variable INT_VAR : std_logic_vector(2 downto 0);
|
|
variable SR_VAR : std_logic_vector(2 downto 0);
|
|
begin
|
|
wait until CLK = '1' and CLK' event;
|
|
if RESET = '1' then
|
|
EX_P_RESET <= '1';
|
|
elsif EX_STATE = RESTORE_PC and DATA_RDY = '1' and EXCEPTION = EX_RESET then
|
|
EX_P_RESET <= '0';
|
|
end if;
|
|
--
|
|
if TRAP_BERR = '1' then
|
|
EX_P_BERR <= '1';
|
|
elsif EX_STATE /= IDLE and DATA_RDY = '1' and DATA_VALID = '0' then
|
|
EX_P_BERR <= '1';
|
|
elsif EX_STATE = INIT and EXCEPTION = EX_BERR then
|
|
EX_P_BERR <= '0'; -- Reset in the beginning to enable retriggering.
|
|
elsif SYS_INIT = '1' then
|
|
EX_P_BERR <= '0';
|
|
end if;
|
|
--
|
|
if TRAP_AERR = '1' then
|
|
EX_P_AERR <= '1';
|
|
elsif EX_STATE = BUILD_STACK and EXCEPTION = EX_AERR then
|
|
EX_P_AERR <= '0';
|
|
elsif SYS_INIT = '1' then
|
|
EX_P_AERR <= '0';
|
|
end if;
|
|
--
|
|
if EX_TRACE_IN = '1' then
|
|
EX_P_TRACE <= '1';
|
|
elsif EX_STATE = BUILD_STACK and EXCEPTION = EX_TRACE then
|
|
EX_P_TRACE <= '0';
|
|
elsif SYS_INIT = '1' then
|
|
EX_P_TRACE <= '0';
|
|
end if;
|
|
--
|
|
if IRQ = "111" and SR_VAR = "111" and STATUS_REG_IN(10 downto 8) /= "111" then
|
|
INT7_TRIG := true; -- Trigger by lowering the mask from 7 to any value.
|
|
elsif IRQ = "111" and INT_VAR < "111" then
|
|
INT7_TRIG := true; -- Trigger when level 7 is entered.
|
|
else
|
|
INT7_TRIG := false;
|
|
end if;
|
|
--
|
|
SR_VAR := STATUS_REG_IN(10 downto 8); -- Update after use!
|
|
INT_VAR := IRQ; -- Update after use!
|
|
--
|
|
if SYS_INIT = '1' then -- Reset when disabling the interrupts.
|
|
EX_P_INT <= '0';
|
|
IRQ_PEND_I <= "111"; -- This is required for system startup.
|
|
elsif EX_STATE = GET_VECTOR and DATA_RDY = '1' then
|
|
EX_P_INT <= '0';
|
|
elsif INT7_TRIG = true then -- Level 7 is nonmaskable ...
|
|
EX_P_INT <= '1';
|
|
IRQ_PEND_I <= IRQ;
|
|
elsif INT_TRIG = '1' and STATUS_REG_IN(10 downto 8) < IRQ then
|
|
EX_P_INT <= '1';
|
|
IRQ_PEND_I <= IRQ;
|
|
end if;
|
|
--
|
|
-- The following nine traps never appear at the same time:
|
|
if TRAP_CHK = '1' then
|
|
EX_P_CHK <= '1';
|
|
elsif TRAP_DIVZERO = '1' then
|
|
EX_P_DIVZERO <= '1';
|
|
elsif TRAP_CODE_OPC = T_TRAP then
|
|
EX_P_TRAP <= '1';
|
|
elsif TRAP_cc = '1' then
|
|
EX_P_TRAPcc <= '1';
|
|
elsif TRAP_V = '1' then
|
|
EX_P_TRAPV <= '1';
|
|
elsif TRAP_CODE_OPC = T_PRIV then
|
|
EX_P_PRIV <= '1';
|
|
elsif TRAP_CODE_OPC = T_1010 then
|
|
EX_P_1010 <= '1';
|
|
elsif TRAP_CODE_OPC = T_1111 then
|
|
EX_P_1111 <= '1';
|
|
elsif TRAP_CODE_OPC = T_ILLEGAL then
|
|
EX_P_ILLEGAL <= '1';
|
|
elsif TRAP_ILLEGAL = '1' then -- Used for BKPT.
|
|
EX_P_ILLEGAL <= '1';
|
|
elsif EX_STATE = VALIDATE_FRAME and DATA_RDY = '1' and DATA_VALID = '1' and NEXT_EX_STATE = IDLE then
|
|
EX_P_FORMAT <= '1';
|
|
elsif EX_STATE = EXAMINE_VERSION and DATA_RDY = '1' and DATA_VALID = '1' and NEXT_EX_STATE = IDLE then
|
|
EX_P_FORMAT <= '1';
|
|
elsif TRAP_CODE_OPC = T_RTE then
|
|
EX_P_RTE <= '1';
|
|
elsif EX_STATE = REFILL_PIPE and NEXT_EX_STATE /= REFILL_PIPE then -- Clear after IPIPE_FLUSH.
|
|
case EXCEPTION is
|
|
when EX_1010 | EX_1111 | EX_CHK | EX_DIVZERO | EX_ILLEGAL | EX_TRAP | EX_TRAPcc | EX_TRAPV | EX_FORMAT | EX_PRIV | EX_RTE =>
|
|
EX_P_CHK <= '0';
|
|
EX_P_DIVZERO <= '0';
|
|
EX_P_PRIV <= '0';
|
|
EX_P_1010 <= '0';
|
|
EX_P_1111 <= '0';
|
|
EX_P_ILLEGAL <= '0';
|
|
EX_P_RTE <= '0';
|
|
EX_P_TRAP <= '0';
|
|
EX_P_TRAPcc <= '0';
|
|
EX_P_TRAPV <= '0';
|
|
EX_P_FORMAT <= '0';
|
|
when others =>
|
|
null;
|
|
end case;
|
|
-- Clear all possible traps during reset exception because the
|
|
-- signal EXCEPTION is not valid at this time:
|
|
elsif SYS_INIT = '1' then
|
|
EX_P_CHK <= '0';
|
|
EX_P_DIVZERO <= '0';
|
|
EX_P_PRIV <= '0';
|
|
EX_P_1010 <= '0';
|
|
EX_P_1111 <= '0';
|
|
EX_P_ILLEGAL <= '0';
|
|
EX_P_RTE <= '0';
|
|
EX_P_TRAP <= '0';
|
|
EX_P_TRAPV <= '0';
|
|
EX_P_FORMAT <= '0';
|
|
end if;
|
|
end process PENDING;
|
|
|
|
ACCESS_ERR <= '1' when EX_STATE = RESTORE_PC and DATA_RDY = '1' and DATA_0 = '1' else -- Odd PC value.
|
|
'1' when DATA_RDY = '1' and DATA_VALID = '0' else '0'; -- Bus error.
|
|
|
|
IRQ_PEND <= IRQ_PEND_I when EXCEPTION = EX_RESET or EXCEPTION = EX_INT else STATUS_REG_IN(10 downto 8);
|
|
IPENDn <= '0' when EX_P_INT = '1' or EX_P_RESET = '1' or EX_P_TRACE = '1' else '1';
|
|
|
|
-- This signal is asserted eraly to indicate the respective controller to stay in its idle state.
|
|
-- The exception is then inserted before a new operation has been loaded and processed.
|
|
EXH_REQ <= '0' when EX_STATE /= IDLE else
|
|
'1' when TRAP_CODE_OPC /= NONE else
|
|
'1' when (EX_P_RESET or EX_P_BERR or EX_P_AERR or EX_P_DIVZERO or EX_P_CHK) = '1' else
|
|
'1' when (EX_P_TRAPcc or EX_P_TRAPV or EX_P_TRACE or EX_P_FORMAT or EX_P_INT) = '1' else '0';
|
|
|
|
INT_VECTOR: process
|
|
-- This process provides the vector base register handling and
|
|
-- the interrupt vector number INT_VECT, which is determined
|
|
-- during interrupt processing.
|
|
variable VECT_No : std_logic_vector(9 downto 2) := "00000000";
|
|
variable VB_REG : std_logic_vector(31 downto 0) := x"00000000";
|
|
begin
|
|
wait until CLK = '1' and CLK' event;
|
|
if VBR_WR = '1' then
|
|
VB_REG := DATA_IN;
|
|
elsif SYS_INIT = '1' then
|
|
VB_REG := (others => '0');
|
|
end if;
|
|
--
|
|
if EX_STATE = CALC_VECT_No or EX_STATE = GET_VECTOR then
|
|
case EXCEPTION is
|
|
when EX_RESET => VECT_No := x"00";
|
|
when EX_BERR => VECT_No := x"02";
|
|
when EX_AERR => VECT_No := x"03";
|
|
when EX_ILLEGAL => VECT_No := x"04";
|
|
when EX_DIVZERO => VECT_No := x"05";
|
|
when EX_CHK => VECT_No := x"06";
|
|
when EX_TRAPcc => VECT_No := x"07";
|
|
when EX_TRAPV => VECT_No := x"07";
|
|
when EX_PRIV => VECT_No := x"08";
|
|
when EX_TRACE => VECT_No := x"09";
|
|
when EX_1010 => VECT_No := x"0A";
|
|
when EX_1111 => VECT_No := x"0B";
|
|
when EX_FORMAT => VECT_No := x"0E";
|
|
-- The uninitialized interrupt vector number x"0F"
|
|
-- is provided by the peripheral interrupt source
|
|
-- during the auto vector bus cycle.
|
|
when EX_INT =>
|
|
if DATA_RDY = '1' and AVEC = '1' then
|
|
VECT_No := x"18" + IRQ_PEND_I; -- Autovector.
|
|
elsif DATA_RDY = '1' and DATA_VALID = '0' then
|
|
VECT_No := x"18"; -- Spurious interrupt.
|
|
elsif DATA_RDY = '1' then
|
|
-- This is the vector number provided by the device.
|
|
-- If the returned VECT_No is x"0F" then it is the
|
|
-- uninitialized interrupt vector due to non initia-
|
|
-- lized vector register of the peripheral device.
|
|
VECT_No := DATA_IN(7 downto 0); -- Non autovector.
|
|
end if;
|
|
when EX_TRAP => VECT_No := x"2" & TRAP_VECTOR;
|
|
when others => VECT_No := (others => '-'); -- Don't care.
|
|
end case;
|
|
end if;
|
|
--
|
|
INT_VECT <= VB_REG + (VECT_No & "00");
|
|
VBR <= VB_REG;
|
|
IVECT_OFFS <= VECT_No & "00";
|
|
end process INT_VECTOR;
|
|
|
|
STORE_CURRENT_EXCEPTION: process
|
|
-- The exceptions which occurs are stored in the following flags until the
|
|
-- interrupt handler handled the respective exception.
|
|
-- This process also stores the current processed exception for further use.
|
|
-- The update takes place in the IDLE EX_STATE.
|
|
begin
|
|
wait until CLK = '1' and CLK' event;
|
|
-- Priority level 0:
|
|
if EX_STATE = IDLE and EX_P_RESET = '1' then
|
|
EXCEPTION <= EX_RESET;
|
|
-- Priority level 1:
|
|
elsif EX_STATE = IDLE and EX_P_AERR = '1' then
|
|
EXCEPTION <= EX_AERR;
|
|
elsif EX_STATE = IDLE and EX_P_BERR = '1' then
|
|
EXCEPTION <= EX_BERR;
|
|
-- Priority level 2:
|
|
-- BREAKPOINT is part of the main controller.
|
|
elsif EX_STATE = IDLE and EX_P_CHK = '1' then
|
|
EXCEPTION <= EX_CHK;
|
|
elsif EX_STATE = IDLE and EX_P_TRAPcc = '1' then
|
|
EXCEPTION <= EX_TRAPcc;
|
|
elsif EX_STATE = IDLE and EX_P_DIVZERO = '1' then
|
|
EXCEPTION <= EX_DIVZERO;
|
|
elsif EX_STATE = IDLE and EX_P_TRAP = '1' then
|
|
EXCEPTION <= EX_TRAP;
|
|
elsif EX_STATE = IDLE and EX_P_TRAPV = '1' then
|
|
EXCEPTION <= EX_TRAPV;
|
|
elsif EX_STATE = IDLE and EX_P_FORMAT = '1' then
|
|
EXCEPTION <= EX_FORMAT;
|
|
-- Priority level 3:
|
|
elsif EX_STATE = IDLE and EX_P_ILLEGAL = '1' then
|
|
EXCEPTION <= EX_ILLEGAL;
|
|
elsif EX_STATE = IDLE and EX_P_RTE = '1' then
|
|
EXCEPTION <= EX_RTE;
|
|
elsif EX_STATE = IDLE and EX_P_1010 = '1' then
|
|
EXCEPTION <= EX_1010;
|
|
elsif EX_STATE = IDLE and EX_P_1111 = '1' then
|
|
EXCEPTION <= EX_1111;
|
|
elsif EX_STATE = IDLE and EX_P_PRIV = '1' then
|
|
EXCEPTION <= EX_PRIV;
|
|
elsif EX_STATE = IDLE and EX_P_TRACE = '1' then
|
|
EXCEPTION <= EX_TRACE;
|
|
elsif EX_STATE = IDLE and EX_P_INT = '1' then
|
|
EXCEPTION <= EX_INT;
|
|
elsif NEXT_EX_STATE = IDLE then
|
|
EXCEPTION <= EX_NONE;
|
|
end if;
|
|
end process STORE_CURRENT_EXCEPTION;
|
|
|
|
CPU_SPACE <= '1' when NEXT_EX_STATE = GET_VECTOR else '0';
|
|
|
|
ADR_OFFSET <= x"000000" & "00000" & PIPE_CNT & '0' when EX_STATE = REFILL_PIPE else
|
|
x"00000004" when NEXT_EX_STATE = RESTORE_PC and EXCEPTION = EX_RESET else
|
|
x"00000002" when NEXT_EX_STATE = RESTORE_PC else
|
|
x"00000006" when NEXT_EX_STATE = VALIDATE_FRAME else
|
|
x"00000036" when NEXT_EX_STATE = EXAMINE_VERSION else
|
|
x"0000005C" when NEXT_EX_STATE = READ_BOTTOM else
|
|
INT_VECT when NEXT_EX_STATE = UPDATE_PC else x"00000000"; -- Default is top of the stack.
|
|
|
|
OP_SIZE <= LONG when EX_STATE = INIT else -- Decrement the stack by four (ISP_DEC).
|
|
LONG when NEXT_EX_STATE = RESTORE_ISP or NEXT_EX_STATE = RESTORE_PC else
|
|
LONG when NEXT_EX_STATE = BUILD_STACK or NEXT_EX_STATE = BUILD_TSTACK else -- Always long access.
|
|
LONG when NEXT_EX_STATE = UPDATE_PC or EX_STATE = UPDATE_PC else
|
|
LONG when EX_STATE = SWITCH_STATE else
|
|
LONG when NEXT_EX_STATE = EXAMINE_VERSION else
|
|
BYTE when NEXT_EX_STATE = GET_VECTOR else WORD;
|
|
|
|
with STACK_FORMAT_I select
|
|
DISPLACEMENT <= x"08" when x"0" | x"1",
|
|
x"0C" when x"2",
|
|
x"12" when x"9",
|
|
x"20" when x"A",
|
|
x"5C" when others; -- x"B".
|
|
|
|
SP_ADD_DISPL <= '1' when EX_STATE = RESTORE_STATUS and DATA_RDY = '1' and DATA_VALID = '1' else '0';
|
|
|
|
P_D: process(CLK, DATA_RDY)
|
|
-- These flip flops are necessary to delay
|
|
-- the read and writes during BUILD_STACK
|
|
-- and restoring the system because the
|
|
-- address calculation in the address
|
|
-- section requires one clock.
|
|
-- Important note: to avoid asynchronous reset by data hazards the
|
|
-- resetting signal is synchronized on the negative clock edge.
|
|
variable DATA_RDY_VAR : bit;
|
|
begin
|
|
if CLK = '0' and CLK' event then
|
|
DATA_RDY_VAR := DATA_RDY;
|
|
end if;
|
|
--
|
|
if DATA_RDY_VAR = '1' then
|
|
DATA_RD <= '0';
|
|
elsif CLK = '1' and CLK' event then
|
|
DATA_RD <= DATA_RD_I;
|
|
end if;
|
|
|
|
if DATA_RDY_VAR = '1' then
|
|
DATA_WR <= '0';
|
|
elsif CLK = '1' and CLK' event then
|
|
DATA_WR <= DATA_WR_I;
|
|
end if;
|
|
end process P_D;
|
|
|
|
DATA_RD_I <= '0' when DATA_RDY = '1' else
|
|
'1' when NEXT_EX_STATE = GET_VECTOR else
|
|
'1' when NEXT_EX_STATE = VALIDATE_FRAME else
|
|
'1' when NEXT_EX_STATE = EXAMINE_VERSION else
|
|
'1' when NEXT_EX_STATE = READ_TOP else
|
|
'1' when NEXT_EX_STATE = READ_BOTTOM else
|
|
'1' when NEXT_EX_STATE = RESTORE_ISP else
|
|
'1' when NEXT_EX_STATE = RESTORE_STATUS else
|
|
'1' when NEXT_EX_STATE = UPDATE_PC else
|
|
'1' when NEXT_EX_STATE = RESTORE_PC else '0';
|
|
|
|
DATA_WR_I <= '0' when DATA_RDY = '1' else
|
|
'1' when EX_STATE = BUILD_STACK else
|
|
'1' when EX_STATE = BUILD_TSTACK else '0';
|
|
|
|
ISP_LOAD <= '1' when EX_STATE = RESTORE_ISP and DATA_RDY = '1' and DATA_VALID = '1' else '0';
|
|
PC_RESTORE <= '1' when EX_STATE = RESTORE_PC and DATA_RDY = '1' and DATA_VALID = '1' else '0';
|
|
PC_LOAD <= '1' when EXCEPTION /= EX_RESET and EXCEPTION /= EX_RTE and EX_STATE /= REFILL_PIPE and NEXT_EX_STATE = REFILL_PIPE else '0';
|
|
|
|
IPIPE_FILL <= '1' when EX_STATE = REFILL_PIPE else '0';
|
|
|
|
-- This signal forces the PC logic in the address register section to calculate the address
|
|
-- of the next instruction. This address is written on the stack. For the following
|
|
-- instructions the old PC value is stacked: BERR, AERR, ILLEGAL, PRIV, TRACE, 1010, 1111, FORMAT.
|
|
PC_INC <= '1' when EXCEPTION = EX_CHK and EX_STATE /= BUILD_STACK and NEXT_EX_STATE = BUILD_STACK else
|
|
'1' when EXCEPTION = EX_DIVZERO and EX_STATE /= BUILD_STACK and NEXT_EX_STATE = BUILD_STACK else
|
|
'1' when EXCEPTION = EX_INT and EX_STATE /= BUILD_STACK and NEXT_EX_STATE = BUILD_STACK else
|
|
'1' when EXCEPTION = EX_TRAP and EX_STATE /= BUILD_STACK and NEXT_EX_STATE = BUILD_STACK else
|
|
'1' when EXCEPTION = EX_TRAPcc and EX_STATE /= BUILD_STACK and NEXT_EX_STATE = BUILD_STACK else
|
|
'1' when EXCEPTION = EX_TRAPV and EX_STATE /= BUILD_STACK and NEXT_EX_STATE = BUILD_STACK else '0';
|
|
|
|
ISP_DEC <= '1' when EX_STATE = INIT and EXCEPTION /= EX_RESET and EXCEPTION /= EX_RTE else -- Early due to one clock cycle address calculation.
|
|
'1' when EX_STATE = BUILD_STACK and DATA_RDY = '1' and NEXT_EX_STATE = BUILD_STACK else
|
|
'1' when EX_STATE = SWITCH_STATE else
|
|
'1' when EX_STATE = BUILD_TSTACK and DATA_RDY = '1' and NEXT_EX_STATE = BUILD_TSTACK else '0';
|
|
|
|
SR_INIT <= '1' when EX_STATE = INIT else '0';
|
|
SR_CLR_MBIT <= '1' when EX_STATE = BUILD_STACK and DATA_RDY = '1' and STACK_CNT = 2 and EXCEPTION = EX_INT and MBIT = '1' else '0';
|
|
SR_WR <= '1' when EX_STATE = RESTORE_STATUS and DATA_RDY = '1' and DATA_VALID = '1' else '0';
|
|
|
|
SYS_INIT <= '1' when EX_STATE = IDLE and EX_P_RESET = '1' else '0';
|
|
|
|
-- The processor gets halted, if a bus error occurs in the stacking or updating states during
|
|
-- the exception processing of a bus error, an address error or a reset.
|
|
HALT_OUTn <= '0' when EX_STATE = HALTED else '1';
|
|
|
|
RESTORE_ISP_PC <= '1' when EXCEPTION = EX_RESET and (NEXT_EX_STATE = RESTORE_ISP or EX_STATE = RESTORE_ISP) else
|
|
'1' when EXCEPTION = EX_RESET and (NEXT_EX_STATE = RESTORE_PC or EX_STATE = RESTORE_PC) else
|
|
'1' when NEXT_EX_STATE = UPDATE_PC else '0';
|
|
|
|
REFILLn <= '0' when EX_STATE = REFILL_PIPE else '1';
|
|
|
|
STACK_FORMAT <= STACK_FORMAT_I;
|
|
|
|
IPIPE_FLUSH <= '1' when EXCEPTION = EX_RESET and EX_STATE /= REFILL_PIPE else
|
|
'1' when EXCEPTION /= EX_NONE and EX_STATE /= REFILL_PIPE and NEXT_EX_STATE = REFILL_PIPE else '0';
|
|
|
|
DOUBLE_BUSFLT <= '1' when (EXCEPTION = EX_AERR or EXCEPTION = EX_RESET) and EX_STATE = RESTORE_PC and DATA_RDY = '1' and DATA_0 = '1' else -- Odd PC value.
|
|
'1' when EX_STATE /= IDLE and EXCEPTION = EX_AERR and DATA_RDY = '1' and DATA_VALID = '0' else
|
|
'1' when EX_STATE /= IDLE and EXCEPTION = EX_BERR and DATA_RDY = '1' and DATA_VALID = '0' else
|
|
'1' when EX_STATE /= IDLE and EXCEPTION = EX_RESET and DATA_RDY = '1' and DATA_VALID = '0' else '0';
|
|
|
|
P_TMP_CPY: process
|
|
-- These registers contain a copy of system relevant state information
|
|
-- which is necessary for restoring the exception. Copies are provided
|
|
-- for the status register, the program counter and the effective address.
|
|
begin
|
|
wait until CLK = '1' and CLK' event;
|
|
if EX_STATE = IDLE and NEXT_EX_STATE /= IDLE then
|
|
SR_CPY <= STATUS_REG_IN;
|
|
ADR_CPY <= ADR_IN;
|
|
MBIT <= STATUS_REG_IN(12);
|
|
elsif EX_STATE = BUILD_STACK and NEXT_EX_STATE = SWITCH_STATE then
|
|
SR_CPY(13) <= '1'; -- Set S bit.
|
|
end if;
|
|
end process P_TMP_CPY;
|
|
|
|
STACK_CTRL: process
|
|
-- This process controls the stacking of the data to the stack. Depending
|
|
-- on the stack frame format, the number of words written to the stack is
|
|
-- adjusted to long words. See the DATA_2_PORT multiplexer in the top level
|
|
-- file for more information.
|
|
variable STACK_POS_VAR : integer range 0 to 46 := 0;
|
|
begin
|
|
wait until CLK = '1' and CLK' event;
|
|
if EX_STATE /= BUILD_TSTACK and NEXT_EX_STATE = BUILD_TSTACK then
|
|
STACK_POS_VAR := 4;
|
|
STACK_FORMAT_I <= x"1";
|
|
elsif EX_STATE /= BUILD_STACK and NEXT_EX_STATE = BUILD_STACK then
|
|
case EXCEPTION is
|
|
when EX_INT | EX_ILLEGAL | EX_1010 | EX_1111 | EX_FORMAT | EX_PRIV | EX_TRAP =>
|
|
STACK_POS_VAR := 4; -- Format 0.
|
|
STACK_FORMAT_I <= x"0";
|
|
when EX_CHK | EX_TRAPcc | EX_TRAPV | EX_TRACE | EX_DIVZERO =>
|
|
STACK_POS_VAR := 6; -- Format 2.
|
|
STACK_FORMAT_I <= x"2";
|
|
when EX_AERR | EX_BERR =>
|
|
if IBOUND = true then
|
|
STACK_POS_VAR := 16; -- Format A.
|
|
STACK_FORMAT_I <= x"A";
|
|
else
|
|
STACK_POS_VAR := 46; -- Format B.
|
|
STACK_FORMAT_I <= x"B";
|
|
end if;
|
|
when others => null;
|
|
end case;
|
|
elsif EX_STATE = VALIDATE_FRAME and DATA_RDY = '1' and DATA_VALID = '1' then
|
|
STACK_FORMAT_I <= DATA_IN(15 downto 12);
|
|
elsif (EX_STATE = BUILD_STACK or EX_STATE = BUILD_TSTACK) and DATA_RDY = '1' then
|
|
STACK_POS_VAR := STACK_POS_VAR - 2; -- Always long words are written.
|
|
end if;
|
|
--
|
|
STACK_CNT <= STACK_POS_VAR;
|
|
STACK_POS <= STACK_POS_VAR;
|
|
end process STACK_CTRL;
|
|
|
|
P_STATUSn : process
|
|
-- This logic asserts the STATUSn permanently when the CPU is halted.
|
|
-- STATUSn is asserted for three clock cycles when the exception
|
|
-- processing starts for RESET, BERR, AERR, 1111, spurious inter-
|
|
-- rupt and autovectored interrupt. And for TRACE or external
|
|
-- interrupt exception it is asserted for two clock cycles.
|
|
variable CNT : std_logic_vector(1 downto 0);
|
|
begin
|
|
wait until CLK = '1' and CLK' event;
|
|
if EX_STATE = CALC_VECT_No then
|
|
case EXCEPTION is
|
|
when EX_RESET | EX_AERR | EX_BERR | EX_1111 =>
|
|
CNT := "11";
|
|
STATUSn <= '0';
|
|
when EX_INT | EX_TRACE =>
|
|
CNT := "10";
|
|
when others =>
|
|
CNT := "00";
|
|
end case;
|
|
end if;
|
|
|
|
if EX_STATE = HALTED then
|
|
STATUSn <= '0';
|
|
elsif CNT > "00" then
|
|
CNT := CNT - '1';
|
|
STATUSn <= '0';
|
|
else
|
|
STATUSn <= '1';
|
|
end if;
|
|
end process P_STATUSn;
|
|
|
|
PIPE_STATUS: process
|
|
-- This logic detects the status of the
|
|
-- instruction pipe prefetch in the
|
|
-- REFILL_PIPE state.
|
|
variable CNT : std_logic_vector(1 downto 0);
|
|
begin
|
|
wait until CLK = '1' and CLK' event;
|
|
if EX_STATE /= REFILL_PIPE then
|
|
PIPE_FULL <= false;
|
|
CNT := "00";
|
|
elsif EX_STATE = REFILL_PIPE and OPCODE_RDY = '1' and CNT < "10" then
|
|
CNT := CNT + '1';
|
|
elsif EX_STATE = REFILL_PIPE and OPCODE_RDY = '1' then
|
|
PIPE_FULL <= true;
|
|
end if;
|
|
PIPE_CNT <= CNT;
|
|
end process PIPE_STATUS;
|
|
|
|
EXCEPTION_HANDLER_REG: process
|
|
-- This is the register portion of the
|
|
-- exception control state machine.
|
|
begin
|
|
wait until CLK = '1' and CLK' event;
|
|
if RESET = '1' then
|
|
EX_STATE <= IDLE;
|
|
else
|
|
EX_STATE <= NEXT_EX_STATE;
|
|
end if;
|
|
end process EXCEPTION_HANDLER_REG;
|
|
|
|
EXCEPTION_HANDLER_DEC: process(ACCESS_ERR, BUSY_MAIN, BUSY_OPD, DATA_IN, DATA_VALID, DOUBLE_BUSFLT, EX_STATE, EX_P_RESET, EX_P_AERR, EX_P_BERR, EX_P_TRACE,
|
|
EX_P_INT, EX_P_ILLEGAL, EX_P_1010, EX_P_TRAPcc, EX_P_RTE, EX_P_1111, EX_P_FORMAT, EX_P_PRIV, EX_P_TRAP, EX_P_TRAPV,
|
|
EX_P_CHK, EX_P_DIVZERO, EXCEPTION, DATA_RDY, PIPE_FULL, MBIT, STACK_CNT, STACK_FORMAT_I)
|
|
begin
|
|
case EX_STATE is
|
|
when IDLE =>
|
|
-- The priority of the exception execution is given by the
|
|
-- following construct. Although type 3 commands do not require
|
|
-- a prioritization, there is no drawback using these conditions.
|
|
-- The spurious interrupt and uninitialized interrupt never appear
|
|
-- as basic interrupts and therefore are not an interrupt source.
|
|
-- During IDLE, when an interrupt occurs, the status register copy
|
|
-- control is asserted and the current interrupt controll is given
|
|
-- to the STORE_EXCEPTION process. During bus or address errors,
|
|
-- the status register must be copied immediately to recognize
|
|
-- the current status for RWn etc. (before the faulty bus cycle is
|
|
-- finished).
|
|
if (BUSY_MAIN = '1' or BUSY_OPD = '1') and EX_P_RESET = '0' then
|
|
NEXT_EX_STATE <= IDLE; -- Wait until the pipelined architecture is ready.
|
|
elsif EX_P_RESET = '1' or EX_P_AERR = '1' or EX_P_BERR = '1' then
|
|
NEXT_EX_STATE <= INIT;
|
|
elsif EX_P_TRAP = '1' or EX_P_TRAPcc = '1' or EX_P_TRAPV = '1' or EX_P_CHK = '1' or EX_P_DIVZERO = '1' then
|
|
NEXT_EX_STATE <= INIT;
|
|
elsif EX_P_FORMAT = '1' then
|
|
NEXT_EX_STATE <= INIT;
|
|
elsif EX_P_TRACE = '1' or EX_P_ILLEGAL = '1' or EX_P_1010 = '1' or EX_P_1111 = '1' or EX_P_PRIV = '1' then
|
|
NEXT_EX_STATE <= INIT;
|
|
elsif EX_P_RTE = '1' then
|
|
NEXT_EX_STATE <= INIT;
|
|
elsif EX_P_INT = '1' then
|
|
NEXT_EX_STATE <= INIT;
|
|
else -- No exception.
|
|
NEXT_EX_STATE <= IDLE;
|
|
end if;
|
|
when INIT =>
|
|
-- In this state, the supervisor mode is switched on (the S bit is set)
|
|
-- and the trace mode is switched off (the T bit is cleared).
|
|
-- Do not service, if halted. The current bus cycle is always finished
|
|
-- in this state. The worst case is a bus error which the finishes the
|
|
-- current bus cycle within the next clock cycle after BERR is asserted.
|
|
case EXCEPTION is
|
|
when EX_RTE =>
|
|
-- This state is foreseen to handle the address offset
|
|
-- correctly in the case the ADR_ATN is already set
|
|
-- by the main controller. So we have to wait one
|
|
-- clock cycle to ensure this data hazard.
|
|
NEXT_EX_STATE <= VALIDATE_FRAME; -- 68K10.
|
|
when EX_INT =>
|
|
NEXT_EX_STATE <= GET_VECTOR;
|
|
when others =>
|
|
NEXT_EX_STATE <= CALC_VECT_No;
|
|
end case;
|
|
when GET_VECTOR =>
|
|
-- This state is intended to determine the vector number for the current process.
|
|
-- See also the process EXC_VECTOR for the handling of the vector determination.
|
|
if DATA_RDY = '1' then
|
|
NEXT_EX_STATE <= BUILD_STACK;
|
|
else
|
|
NEXT_EX_STATE <= GET_VECTOR;
|
|
end if;
|
|
when CALC_VECT_No =>
|
|
-- This state is introduced to control the generation of the vector number
|
|
-- for all exceptions except the external interrupts.
|
|
case EXCEPTION is
|
|
when EX_RESET =>
|
|
NEXT_EX_STATE <= RESTORE_ISP; -- Do not stack anything but update the SSP and PC.
|
|
when others =>
|
|
NEXT_EX_STATE <= BUILD_STACK;
|
|
end case;
|
|
-- The following states provide writing to the stack pointer or reading
|
|
-- the exception vector address from memory. If there is a bus error
|
|
-- or an address error during the read or write cycles, the processor
|
|
-- proceeds in two different ways:
|
|
-- If the errors occur during a reset, bus error or address error
|
|
-- exception processing, a double bus fault has occured. In
|
|
-- consequence, the processor halts due to catastrophic system failure.
|
|
-- If the errors occur during other exception processings, the current
|
|
-- processing is aborted and this exception handler state machine will
|
|
-- immediately begin with the bus error exception handling.
|
|
when BUILD_STACK =>
|
|
if DOUBLE_BUSFLT = '1' then
|
|
NEXT_EX_STATE <= HALTED;
|
|
elsif ACCESS_ERR = '1' then
|
|
NEXT_EX_STATE <= IDLE;
|
|
elsif DATA_RDY = '1' and STACK_CNT = 2 and EXCEPTION = EX_INT and MBIT = '1' then
|
|
NEXT_EX_STATE <= SWITCH_STATE; -- Build throwaway stack frame.
|
|
elsif DATA_RDY = '1' and STACK_CNT = 2 then
|
|
NEXT_EX_STATE <= UPDATE_PC;
|
|
else
|
|
NEXT_EX_STATE <= BUILD_STACK;
|
|
end if;
|
|
when SWITCH_STATE => -- Required to decrement the correct stack pointer.
|
|
NEXT_EX_STATE <= BUILD_TSTACK;
|
|
when BUILD_TSTACK => -- Build throwaway stack frame.
|
|
if ACCESS_ERR = '1' then
|
|
NEXT_EX_STATE <= IDLE;
|
|
elsif DATA_RDY = '1' and STACK_CNT = 2 then
|
|
NEXT_EX_STATE <= UPDATE_PC;
|
|
else
|
|
NEXT_EX_STATE <= BUILD_TSTACK;
|
|
end if;
|
|
when UPDATE_PC =>
|
|
if DOUBLE_BUSFLT = '1' then
|
|
NEXT_EX_STATE <= HALTED;
|
|
elsif ACCESS_ERR = '1' then
|
|
NEXT_EX_STATE <= IDLE;
|
|
elsif DATA_RDY = '1' then
|
|
NEXT_EX_STATE <= REFILL_PIPE;
|
|
else
|
|
NEXT_EX_STATE <= UPDATE_PC;
|
|
end if;
|
|
when VALIDATE_FRAME =>
|
|
if ACCESS_ERR = '1' then
|
|
NEXT_EX_STATE <= IDLE;
|
|
elsif DATA_RDY = '1' then
|
|
case DATA_IN(15 downto 12) is
|
|
when x"0" | x"1" | x"2" | x"9" =>
|
|
NEXT_EX_STATE <= RESTORE_PC;
|
|
when x"A" | x"B" =>
|
|
NEXT_EX_STATE <= EXAMINE_VERSION;
|
|
when others =>
|
|
NEXT_EX_STATE <= IDLE; -- Format error.
|
|
end case;
|
|
else
|
|
NEXT_EX_STATE <= VALIDATE_FRAME;
|
|
end if;
|
|
when EXAMINE_VERSION =>
|
|
if ACCESS_ERR = '1' then
|
|
NEXT_EX_STATE <= IDLE;
|
|
elsif DATA_RDY = '1' then
|
|
if DATA_IN /= VERSION then
|
|
NEXT_EX_STATE <= IDLE; -- Format error.
|
|
else
|
|
NEXT_EX_STATE <= READ_TOP;
|
|
end if;
|
|
else
|
|
NEXT_EX_STATE <= EXAMINE_VERSION;
|
|
end if;
|
|
when READ_TOP =>
|
|
if ACCESS_ERR = '1' then
|
|
NEXT_EX_STATE <= IDLE;
|
|
elsif DATA_RDY = '1' then
|
|
NEXT_EX_STATE <= READ_BOTTOM;
|
|
else
|
|
NEXT_EX_STATE <= READ_TOP;
|
|
end if;
|
|
when READ_BOTTOM =>
|
|
if ACCESS_ERR = '1' then
|
|
NEXT_EX_STATE <= IDLE;
|
|
elsif DATA_RDY = '1' then
|
|
NEXT_EX_STATE <= RESTORE_PC;
|
|
else
|
|
NEXT_EX_STATE <= READ_BOTTOM;
|
|
end if;
|
|
when RESTORE_STATUS =>
|
|
if DOUBLE_BUSFLT = '1' then
|
|
NEXT_EX_STATE <= HALTED;
|
|
elsif ACCESS_ERR = '1' then
|
|
NEXT_EX_STATE <= IDLE;
|
|
elsif DATA_RDY = '1' and STACK_FORMAT_I = x"1" then
|
|
NEXT_EX_STATE <= VALIDATE_FRAME; -- Throwaway stack frame.
|
|
elsif DATA_RDY = '1' then
|
|
NEXT_EX_STATE <= REFILL_PIPE;
|
|
else
|
|
NEXT_EX_STATE <= RESTORE_STATUS;
|
|
end if;
|
|
when RESTORE_ISP =>
|
|
if DOUBLE_BUSFLT = '1' then
|
|
NEXT_EX_STATE <= HALTED;
|
|
elsif ACCESS_ERR = '1' then
|
|
NEXT_EX_STATE <= IDLE;
|
|
elsif DATA_RDY = '1' then
|
|
NEXT_EX_STATE <= RESTORE_PC;
|
|
else
|
|
NEXT_EX_STATE <= RESTORE_ISP;
|
|
end if;
|
|
when RESTORE_PC =>
|
|
if DOUBLE_BUSFLT = '1' then
|
|
NEXT_EX_STATE <= HALTED; -- Double bus fault.
|
|
elsif ACCESS_ERR = '1' then
|
|
NEXT_EX_STATE <= IDLE;
|
|
elsif EXCEPTION = EX_RESET and DATA_RDY = '1' then
|
|
NEXT_EX_STATE <= REFILL_PIPE;
|
|
elsif DATA_RDY = '1' then
|
|
NEXT_EX_STATE <= RESTORE_STATUS;
|
|
else
|
|
NEXT_EX_STATE <= RESTORE_PC;
|
|
end if;
|
|
when REFILL_PIPE =>
|
|
if DOUBLE_BUSFLT = '1' then
|
|
NEXT_EX_STATE <= HALTED;
|
|
elsif ACCESS_ERR = '1' then
|
|
NEXT_EX_STATE <= IDLE;
|
|
elsif PIPE_FULL = true then
|
|
NEXT_EX_STATE <= IDLE;
|
|
else
|
|
NEXT_EX_STATE <= REFILL_PIPE;
|
|
end if;
|
|
when HALTED =>
|
|
-- Processor halted, Double bus error!
|
|
NEXT_EX_STATE <= HALTED;
|
|
end case;
|
|
end process EXCEPTION_HANDLER_DEC;
|
|
end BEHAVIOR;
|
|
|