1
0
mirror of https://github.com/Gehstock/Mist_FPGA.git synced 2026-04-27 12:49:15 +00:00
Files
Gehstock.Mist_FPGA/common/CPU/68K10/wf68k10_control.vhd
2020-09-06 18:16:38 +02:00

2045 lines
127 KiB
VHDL

------------------------------------------------------------------------
---- ----
---- WF68K10 IP Core: this is the main controller to handle all ----
---- integer instructions. ----
---- ----
---- Description: ----
---- This controller handles all integer instructions and provides ----
---- all required system control signals. The instructions are ----
---- requested from the instruction prefetch unit in the opcode ----
---- decoder unit. The data is mostly written to the ALU and after- ----
---- wards from the ALU to the writeback logic. This pipelined ----
---- structure requires a correct management of data in use. Any ----
---- address or data registers or memory addresses which are in use ----
---- are marked by a flag not to be used befor written back. Any ----
---- time data or address reegisters or the effective address are ----
---- in the writeback pipe, the respective use flag is evaluated. ----
---- Instructions like MOVE read unused source and the destination ----
---- is written, when the ALU and writeback controller 'free'. ----
---- Instructions like ADD, SUB etc. read unused source and desti- ----
---- nations and write back the destination, when the operands are ----
---- not used any more and the ALU and writeback controller are not ----
---- in use by another operation. ----
---- The main controller is the second pipeline stage of the CPU. ----
---- The pipelining structure also requires some special treatment ----
---- for the system control instructions as described as follows: ----
------------------------------------------------------------------------
---- System Control Instructions: ----
---- There are several instructions which require the instruction ----
---- pipe to be flushed as described in the following. For further ----
---- information refer to the 68Kxx data sheets. ----
---- ----
---- 1. TRAP generating: ----
---- The following instructions result in a pipe flush when the ----
---- exception handler takes control over the system: ----
---- BKPT, CHK, ILLEGAL, TRAP, TRAPV ----
---- There are some other indirect conditions flushing the pipe ----
---- such as the STOP which is invoked by an external interrupt.----
---- ----
---- 2. Privilege violations: ----
---- Some instructions may result in a privilege violation ----
---- when executed in user space. The result will be a ----
---- privilege violation trap and the ipipe is flushed when ----
---- the exception handler takes over. The instructions are: ----
---- ANDI_TO_SR, EORI_TO_SR, ORI_TO_SR, MOVEC, MOVES, MOVE_USP, ----
---- MOVE_FROM_SR (68K10), MOVE_TO_SR, RESET, RTE and STOP. ----
---- ----
---- 3. Branches and Jumps: ----
---- In case of branches and jumps and the respective return ----
---- operations it is required to flush the instruction pipe. ----
---- If PC value changes due to any branch or jump, it is neces- ----
---- sary to flush the instruction pipe to invalidate already ----
---- loaded 'old' instructions. This affects: ----
---- BRA, BSR, Bcc, DBcc, JMP, JSR and the returns: ----
---- RTD, RTR, RTS, RTE and also STOP. ----
---- ----
------------------------------------------------------------------------
---- Data hazards: ----
---- To avoid malfunction by using old data several things have ----
---- to be taken into account: ----
---- 1. Operations manipulating the system registers must wait ----
---- in the end of the operation until the ALU has updated ----
---- the condition codes. These operations are ANDI_TO_SR, ----
---- EORI_TO_SR, ORI_TO_SR, MOVE_TO_SR and MOVEC. ----
---- 2. Operations using the staus register must not start until ----
---- the ALU has updated the condition codes. These operations ----
---- are MOVE_FROM_CCR, MOVE_FROM_SR and MOVEC. ----
---- 3. Operations using the stack pointer must not start until ----
---- the stack pointer is updated by the previous operation. ----
---- Operations using the stack pointer are RTD, RTR, RTS, ----
---- MOVEC, MOVE_USP and UNLK. ----
---- 4. Operations manipulating the stack pointer without using ----
---- the ALU must not start until the stack is written by the ----
---- previous operation. Stack pointer manipulating operations ----
---- are BSR, JSR, LINK and PEA. ----
------------------------------------------------------------------------
---- ----
---- Remarks: ----
---- ----
---- 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 20160620 WF
-- Fixed a bug in the MOVEM operation.
-- Break the DBcc_LOOP when the exception handler is busy.
-- Revision 2K18A (unreleased) WF
-- Fixed a bug in MOVE An,-(Ay). Thanks to Gary Bingham for the support.
-- Removed RERUN_RMC.
-- Fixed wrong PEA behaviour.
-- Fixed the displacement for LINK.
-- Fixed AR_MARK_USED in LINK.
-- Fixed the operation size for MOVEQ.
-- ADDQ, SUBQ Fix: address registers are always written long.
-- ADDI, ANDI, EORI, ORI, SUBI: address is not marked used if destination is Dn.
-- ADDI, ANDI, EORI, ORI, SUBI: data register is marked used if destination is Dn.
-- EXG: rearranged logic to meet the new top level multiplexers.
-- LINK, UNLK: wait in START_OP until the ALU is ready (avoids possible data hazards).
-- LINK, UNLK: fixed the write back operation size.
-- MOVEM: Fixed predecrement mode for consecutive MOVEM -(An).
-- MOVEP: MOVEP_PNTR is now correct for consecutive MOVEP.
-- MOVEP: avoid structural hazard in SWITCH_STATE by waiting for ALU.
-- EOR: fixed a bug in the writeback mechanism.
-- BSR, JSR: EXEC_WB state machine waits now for ALU_INIT. Avoid structural / data hazard.
-- The instruction pipe is not flushed for ANDI_TO_CCR, EORI_TO_CCR, ORI_TO_CCR.
-- The instruction pipe is not flushed for MOVE_FROM_CCR, MOVE_TO_CCR, MOVE_FROM_SR, MOVE_USP, MOVEC.
-- Modifications in the FETCH state machine to avoid several data hazards for MOVEM, MOVE_FROM_CCR, MOVE_FROM_SR.
-- Modifications in the FETCH state machine to avoid several data hazards for ANDI_TO_CCR, ANDI_TO_SR, EORI_TO_CCR, EORI_TO_SR, ORI_TO_CCR, ORI_TO_SR.
-- Bugfix: the condition codes were not updated if there was a pending interrupt.
-- We have to stop a pending operation in case of a pending interrupt. This is done by rejecting OW_RDY.
-- Write the undecremented Register for MOVE Ax, -(Ax).
-- LINK A7 and PEA(A7) stacks the undecremented A7.
-- UNMARK is now asserted in the end of the write cycle. This avoids data hazards.
-- Fixed a MOVEC writeback issue (use BIW_WB... instead of BIW_...).
-- Fixed a USP writeback issue (use BIW_WB... instead of BIW_...).
-- Introduced a switch NO_PIPELINE.
-- MOVEM-Fix: the effective address in memory to register is stored (STORE_AEFF) not to be overwritten in case the addressing register is also loaded.
-- DBcc: fixed a data hazard for DBcc_COND evaluation by waiting on the ALU result.
-- Fixed DR_WR_1 locking against AR_WR_2.
-- IPIPE is flushed, when there is a memory space change in the end of xx_TO_SR operations.
-- To handle correct addressing, ADR_OFFSET is now cleared right in the end of the respective operation.
-- Fixed a bug in EOR writing back in register direct mode.
-- ADDQ and SUBQ: fixed (An)+ mode. An increments now.
-- Fixed DIVS, DIVU in memory address modes (wrong control flow).
-- ADDQ and SUBQ: fixed condition code control UPDT_CC.
-- Fixed a data hazard bug using addressing modes with index register.
-- Rewritten DBcc loop for split loops (see LOOP_SPLIT).
-- BTST: fixed (d16,Ax) addressing mode.
-- Fixed several pipelinig issues (hazards).
-- Revision 2K19A 20190419 WF
-- Introdeced a new state CALC_AEFF which results in no need of ADR_ATN and a twice highre fmax.
-- Revision 2K19B 20191224 WF
-- NOP explicitely synchronizes the instruction pipe now.
-- Control: BUSY is now asserted when an opword is loaded and we have to wait in START_OP (avoids other controllers to reload the opword, see OW_REQ).
-- Removed a data hazard condition (A7) for JSR, PEA, LINK and UNLK in the beginning of the operation.
--
use work.WF68K10_PKG.all;
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;
use ieee.numeric_std.all;
entity WF68K10_CONTROL is
generic(NO_PIPELINE : boolean); -- If true the controller work in scalar mode.
port (
CLK : in std_logic; -- System clock.
RESET_CPU : in bit; -- CPU reset.
BUSY : out bit; -- Main controller finished an execution.
BUSY_EXH : in bit;
EXH_REQ : in bit;
INT_TRIG : out bit;
OW_REQ : out bit; -- Operation words request.
OW_VALID : in std_logic; -- Operation words is valid.
EW_REQ : out bit; -- Extension word request.
EW_ACK : in bit; -- Extension word available.
OPD_ACK : in bit; -- Opcode has new data.
ADR_MARK_USED : out bit;
ADR_IN_USE : in bit;
ADR_OFFSET : out std_logic_vector(5 downto 0);
DATA_RD : out bit;
DATA_WR : out bit;
DATA_RDY : in bit;
DATA_VALID : in std_logic;
RMC : out bit;
LOAD_OP1 : out bit;
LOAD_OP2 : out bit;
LOAD_OP3 : out bit;
STORE_ADR_FORMAT : out bit;
STORE_D16 : out bit;
STORE_DISPL : out bit;
STORE_ABS_HI : out bit;
STORE_ABS_LO : out bit;
STORE_AEFF : out bit;
STORE_IDATA_B2 : out bit;
STORE_IDATA_B1 : out bit;
-- System control signals:
OP : in OP_68K;
OP_SIZE : out OP_SIZETYPE;
BIW_0 : in std_logic_vector(13 downto 0);
BIW_1 : in std_logic_vector(15 downto 0);
EXT_WORD : in std_logic_vector(15 downto 0);
ADR_MODE : out std_logic_vector(2 downto 0);
AMODE_SEL : out std_logic_vector(2 downto 0);
OP_WB : out OP_68K;
OP_SIZE_WB : out OP_SIZETYPE;
BIW_0_WB_73 : out std_logic_vector(7 downto 3); -- Used for EXG.
AR_MARK_USED : out bit;
USE_APAIR : out boolean;
AR_IN_USE : in bit;
AR_SEL_RD_1 : out std_logic_vector(2 downto 0);
AR_SEL_RD_2 : out std_logic_vector(2 downto 0);
AR_SEL_WR_1 : out std_logic_vector(2 downto 0);
AR_SEL_WR_2 : out std_logic_vector(2 downto 0);
AR_INC : out bit;
AR_DEC : out bit;
AR_WR_1 : out bit;
AR_WR_2 : out bit;
DR_MARK_USED : out bit;
USE_DPAIR : out boolean;
DR_IN_USE : in bit;
DR_SEL_WR_1 : out std_logic_vector(2 downto 0);
DR_SEL_WR_2 : out std_logic_vector(2 downto 0);
DR_SEL_RD_1 : out std_logic_vector(2 downto 0);
DR_SEL_RD_2 : out std_logic_vector(2 downto 0);
DR_WR_1 : out bit;
DR_WR_2 : out bit;
UNMARK : out bit;
DISPLACEMENT : out std_logic_vector(31 downto 0);
PC_ADD_DISPL : out bit;
PC_LOAD : out bit;
PC_INC_EXH : in bit;
SP_ADD_DISPL : out bit;
DFC_WR : out bit;
DFC_RD : out bit;
SFC_WR : out bit;
SFC_RD : out bit;
VBR_WR : out bit;
VBR_RD : out bit;
USP_RD : out bit;
USP_WR : out bit;
IPIPE_FLUSH : out bit; -- Abandon the instruction pipeline.
ALU_INIT : out bit;
ALU_BSY : in bit;
ALU_REQ : in bit;
ALU_ACK : out bit;
BKPT_CYCLE : out bit;
BKPT_INSERT : out bit;
LOOP_BSY : in bit;
LOOP_SPLIT : out boolean;
LOOP_EXIT : out bit;
SR_WR : out bit;
MOVEM_ADn : out bit;
MOVEP_PNTR : out integer range 0 to 3;
CC_UPDT : out bit;
TRACE_EN : in std_logic;
ALU_COND : in boolean;
DBcc_COND : in boolean;
BRANCH_ATN : in bit;
RESET_STRB : out bit;
BERR : out bit;
EX_TRACE : out bit;
TRAP_ILLEGAL : out bit; -- Used for BKPT.
TRAP_V : out bit
);
end entity WF68K10_CONTROL;
architecture BEHAVIOUR of WF68K10_CONTROL is
type FETCH_STATES is (START_OP, CALC_AEFF, FETCH_DISPL, FETCH_EXWORD_1, FETCH_ABS_HI, FETCH_ABS_LO,
FETCH_IDATA_B2, FETCH_IDATA_B1, FETCH_OPERAND, INIT_EXEC_WB, SLEEP, SWITCH_STATE);
type EXEC_WB_STATES is (IDLE, EXECUTE, WRITEBACK, WRITE_DEST);
signal FETCH_STATE : FETCH_STATES;
signal NEXT_FETCH_STATE : FETCH_STATES;
signal EXEC_WB_STATE : EXEC_WB_STATES;
signal NEXT_EXEC_WB_STATE : EXEC_WB_STATES;
signal ADR_MODE_I : std_logic_vector(2 downto 0);
signal ALU_INIT_I : bit;
signal ALU_TRIG : bit;
signal AR_DEC_I : bit;
signal AR_WR_I : bit;
signal AR_WR_II : bit;
signal BIW_0_WB : std_logic_vector(11 downto 0);
signal BIW_1_WB : std_logic_vector(15 downto 0);
signal DATA_RD_I : bit;
signal DATA_WR_I : bit;
signal EW_RDY : bit;
signal INIT_ENTRY : bit;
signal IPIPE_FLUSH_I : bit;
signal LOOP_EXIT_I : bit;
signal MOVEM_ADn_I : bit;
signal MOVEM_ADn_WB : bit;
signal MOVEM_COND : boolean;
signal MOVEM_FIRST_RD : boolean;
signal MOVEM_INH_WR : boolean;
signal MOVEM_LAST_WR : boolean;
signal MOVEM_PNTR : std_logic_vector(3 downto 0);
signal MOVEP_PNTR_I : integer range 0 to 3;
signal OP_SIZE_I : OP_SIZETYPE;
signal OP_WB_I : OP_68K := UNIMPLEMENTED;
signal OW_RDY : bit;
signal PC_LOAD_I : bit;
signal PHASE2 : boolean;
signal RD_RDY : bit;
signal READ_CYCLE : bit;
signal UPDT_CC : bit;
signal WR_RDY : bit;
signal WRITE_CYCLE : bit;
-- Debugging:
signal OP_TEST : bit;
begin
BUSY <= '1' when OPD_ACK = '1' else -- Early indication.
'1' when OW_RDY = '1' and OP /= ILLEGAL and OP /= RTE and OP /= TRAP and OP /= UNIMPLEMENTED else -- In progress MAIN is now busy.
'1' when LOOP_BSY = '1' else -- Finish the DBcc loop.
'1' when ALU_BSY = '1' else -- Busy, wait.
'1' when FETCH_STATE /= START_OP else '0'; -- Main controller is busy.
-- The interrupt must not be activated when the controller is in its START_OP
-- state and fetches new OPWORDS. so we define the trigger for the interrupt
-- in the end of the FETCH phase. The SLEEP state is important for STOP.
INT_TRIG <= '1' when FETCH_STATE = INIT_EXEC_WB or FETCH_STATE = SLEEP else '0';
OW_REQ <= '0' when BUSY_EXH = '1' else
'0' when EXH_REQ = '1' and LOOP_BSY = '0' else -- Non interrupt exception requests, loop has priority.
'0' when OPD_ACK = '1' or OW_RDY = '1' else
'1' when NO_PIPELINE = true and FETCH_STATE = START_OP and ALU_BSY = '0' else
'1' when NO_PIPELINE = false and FETCH_STATE = START_OP else '0';
DATA_AVAILABLE: process
-- These flip flops store the information whether the data required in the different
-- states is available or not. This is necessary in case of delayed cycles for
-- example if the required address register is not ready to be read.
begin
wait until CLK = '1' and CLK' event;
if RESET_CPU = '1' then
OW_RDY <= '0';
elsif FETCH_STATE = START_OP and NEXT_FETCH_STATE /= START_OP then
OW_RDY <= '0'; -- Reset.
elsif FETCH_STATE = START_OP and (OP = ILLEGAL or OP = RTE or OP = TRAP or OP = UNIMPLEMENTED) and BUSY_EXH = '1' then
OW_RDY <= '0'; -- Done.
elsif OPD_ACK = '1' then
OW_RDY <= '1'; -- Set.
end if;
if FETCH_STATE = START_OP then
EW_RDY <= '0';
elsif FETCH_STATE = FETCH_DISPL and NEXT_FETCH_STATE /= FETCH_DISPL then
EW_RDY <= '0';
elsif FETCH_STATE = FETCH_EXWORD_1 and NEXT_FETCH_STATE /= FETCH_EXWORD_1 then
EW_RDY <= '0';
elsif FETCH_STATE = FETCH_IDATA_B1 and NEXT_FETCH_STATE /= FETCH_IDATA_B1 then
EW_RDY <= '0';
elsif (FETCH_STATE = FETCH_DISPL or FETCH_STATE = FETCH_EXWORD_1 or FETCH_STATE = FETCH_IDATA_B1) and EW_ACK = '1' then
EW_RDY <= '1';
end if;
end process DATA_AVAILABLE;
EW_REQ <= '0' when EW_ACK = '1' or EW_RDY = '1' else
'1' when FETCH_STATE = FETCH_DISPL or FETCH_STATE = FETCH_EXWORD_1 else
'1' when FETCH_STATE = FETCH_ABS_HI or FETCH_STATE = FETCH_ABS_LO else
'1' when FETCH_STATE = FETCH_IDATA_B2 or FETCH_STATE = FETCH_IDATA_B1 else
'1' when FETCH_STATE /= FETCH_DISPL and NEXT_FETCH_STATE = FETCH_DISPL else
'1' when FETCH_STATE /= FETCH_EXWORD_1 and NEXT_FETCH_STATE = FETCH_EXWORD_1 else
'1' when FETCH_STATE /= FETCH_ABS_HI and NEXT_FETCH_STATE = FETCH_ABS_HI else
'1' when FETCH_STATE /= FETCH_ABS_LO and NEXT_FETCH_STATE = FETCH_ABS_LO else
'1' when FETCH_STATE /= FETCH_IDATA_B2 and NEXT_FETCH_STATE = FETCH_IDATA_B2 else
'1' when FETCH_STATE /= FETCH_IDATA_B1 and NEXT_FETCH_STATE = FETCH_IDATA_B1 else '0';
CYCLECONTROL: process
-- This process contros the read and write signals, if
-- asserted simultaneously. In this way, a read cycle is
-- not interrupted by a write cycle and vice versa.
begin
wait until CLK = '1' and CLK' event;
if DATA_RDY = '1' then
WRITE_CYCLE <= '0';
READ_CYCLE <= '0';
elsif DATA_WR_I = '1' then
WRITE_CYCLE <= '1';
READ_CYCLE <= '0';
elsif DATA_RD_I = '1' then
READ_CYCLE <= '1';
WRITE_CYCLE <= '0';
end if;
end process CYCLECONTROL;
RD_RDY <= DATA_RDY when READ_CYCLE = '1' else '0';
WR_RDY <= DATA_RDY when WRITE_CYCLE = '1' else '0';
INIT_ENTRY <= '1' when FETCH_STATE /= INIT_EXEC_WB and NEXT_FETCH_STATE = INIT_EXEC_WB else '0';
DATA_RD <= DATA_RD_I;
DATA_RD_I <= '0' when DATA_WR_I = '1' and READ_CYCLE = '0' and WRITE_CYCLE = '0' else -- Write is prioritized.
'0' when WRITE_CYCLE = '1' else -- Do not read during a write cycle.
'0' when ADR_IN_USE = '1' else -- Avoid data hazards.
'0' when DATA_RDY = '1' else
'1' when FETCH_STATE = FETCH_OPERAND else '0';
DATA_WR <= DATA_WR_I;
DATA_WR_I <= '0' when READ_CYCLE = '1' else -- Do not write during a read cycle.
'0' when DATA_RDY = '1' else
'1' when EXEC_WB_STATE = WRITE_DEST else '0';
RMC <= '1' when OP = TAS and FETCH_STATE /= START_OP else '0';
ALU_ACK <= '1' when EXEC_WB_STATE = EXECUTE and NEXT_EXEC_WB_STATE = IDLE else
'1' when EXEC_WB_STATE = WRITEBACK else
'1' when EXEC_WB_STATE = WRITE_DEST and WR_RDY = '1' else '0';
-- Store the extension word right in the end due to used data and/or address registers.
STORE_ADR_FORMAT <= '1' when FETCH_STATE = FETCH_EXWORD_1 and NEXT_FETCH_STATE /= FETCH_EXWORD_1 else '0';
STORE_D16 <= '1' when FETCH_STATE = FETCH_DISPL and EW_ACK = '1' else '0';
STORE_DISPL <= '1' when OP = MOVEP and FETCH_STATE = START_OP and NEXT_FETCH_STATE /= START_OP and BIW_0(7 downto 6) < "10" else -- Memory to register.
'1' when OP = MOVEP and FETCH_STATE = SWITCH_STATE else '0'; -- Register to memory.
STORE_ABS_HI <= '1' when FETCH_STATE = FETCH_ABS_HI and EW_ACK = '1' else '0';
STORE_ABS_LO <= '1' when FETCH_STATE = FETCH_ABS_LO and EW_ACK = '1' else '0';
STORE_IDATA_B2 <= '1' when FETCH_STATE = FETCH_IDATA_B2 and EW_ACK = '1' else '0';
STORE_IDATA_B1 <= '1' when FETCH_STATE = FETCH_IDATA_B1 and EW_ACK = '1' else '0';
LOAD_OP1 <= '1' when OP = CMPM and FETCH_STATE = FETCH_OPERAND and RD_RDY = '1' and DATA_VALID = '1' and PHASE2 = true else
'1' when OP = MOVE and BIW_0(8 downto 6) = "100" and BIW_0(5 downto 3) = "001" and BIW_0(11 downto 9) = BIW_0(2 downto 0) and INIT_ENTRY = '1' else -- Load early to write the undecremented Register for Ax, -(Ax).
'1' when OP = MOVES and FETCH_STATE = START_OP and NEXT_FETCH_STATE /= START_OP and ADR_MODE_I = "100" and BIW_1(15) = '1' and BIW_1(11) = '1' and BIW_1(14 downto 12) = BIW_0(2 downto 0) else -- Load the adressing register before decrementing.
'1' when OP = PEA and FETCH_STATE = SWITCH_STATE and PHASE2 = true else -- Load early not to stack the decremented value.
'0' when OP = CMPM or OP = PEA else
'0' when OP = MOVE and BIW_0(8 downto 6) = "100" and BIW_0(5 downto 3) = "001" and BIW_0(11 downto 9) = BIW_0(2 downto 0) else
'0' when OP = MOVES and ADR_MODE_I = "100" and BIW_1(15) = '1' and BIW_1(11) = '1' and BIW_1(14 downto 12) = BIW_0(2 downto 0) else -- Do not load the decremented addressing register.
'1' when ALU_INIT_I = '1' else '0';
LOAD_OP2 <= '1' when (OP = ABCD or OP = SBCD) and FETCH_STATE = FETCH_OPERAND and RD_RDY = '1' and DATA_VALID = '1' and PHASE2 = false else
'1' when (OP = ADDX or OP = SUBX) and FETCH_STATE = FETCH_OPERAND and RD_RDY = '1' and DATA_VALID = '1' and PHASE2 = false else
'1' when (OP = ABCD or OP = SBCD) and FETCH_STATE = INIT_EXEC_WB and BIW_0(3) = '0' else -- Register direct.
'1' when (OP = ADDX or OP = SUBX) and FETCH_STATE = INIT_EXEC_WB and BIW_0(3) = '0' else -- Register direct.
'1' when OP = CMPM and FETCH_STATE = FETCH_OPERAND and RD_RDY = '1' and DATA_VALID = '1' and PHASE2 = false else
'0' when OP = ABCD or OP = SBCD or OP = ADDX or OP = SUBX or OP = CMPM else
'1' when OP = LINK and BIW_0(2 downto 0) = "111" and FETCH_STATE = START_OP and NEXT_FETCH_STATE /= START_OP else -- Load early not to stack the decremented address register.
'0' when OP = LINK and BIW_0(2 downto 0) = "111" else
'1' when INIT_ENTRY = '1' else '0';
LOAD_OP3 <= '1' when (OP = DIVS or OP = DIVU) and OP_SIZE_I = LONG and BIW_1(10) = '1' and INIT_ENTRY = '1' else '0'; -- 64 bit operand.
SR_WR <= '1' when (OP_WB_I = ANDI_TO_SR or OP_WB_I = EORI_TO_SR or OP_WB_I = ORI_TO_SR) and EXEC_WB_STATE = WRITEBACK else
'1' when (OP_WB_I = MOVE_TO_CCR or OP_WB_I = MOVE_TO_SR) and EXEC_WB_STATE = WRITEBACK else
'1' when OP_WB_I = STOP and EXEC_WB_STATE = WRITEBACK else '0';
-- Addressing mode:
ADR_MODE <= ADR_MODE_I;
ADR_MODE_I <= "010" when OP = BSR or OP = LINK or OP = UNLK else -- (An), (Dn).
"010" when OP = RTD or OP = RTR or OP = RTS else -- (An).
"011" when OP = CMPM else -- (An)+
"100" when OP = ABCD or OP = SBCD else -- -(An).
"100" when OP = ADDX or OP = SUBX else -- -(An).
"101" when OP = MOVEP else -- (d16, An).
-- The following two conditions change the address mode right in the end of the fetch phase.
"010" when (OP = JSR or OP = PEA) and FETCH_STATE = INIT_EXEC_WB and ALU_BSY = '0' else -- (A7).
BIW_0(8 downto 6) when OP = MOVE and FETCH_STATE = INIT_EXEC_WB and ALU_BSY = '0' else
BIW_0(8 downto 6) when OP = MOVE and PHASE2 = true else
BIW_0(5 downto 3);
-- This is the selector for the address mode "111".
AMODE_SEL <= BIW_0(11 downto 9) when OP = MOVE and (NEXT_FETCH_STATE = INIT_EXEC_WB or FETCH_STATE = INIT_EXEC_WB) else
BIW_0(11 downto 9) when OP = MOVE and PHASE2 = true else BIW_0(2 downto 0);
-- Used for the addressing modes and as source selector.
-- In case of the addressing modes, the selector mus be valid one clock cycle before the bus cycle
-- starts due to the pipeline stage for ADR_REG in the address register section.
AR_SEL_RD_1 <= BIW_0(11 downto 9) when (OP = ABCD or OP = SBCD) and FETCH_STATE = START_OP else
BIW_0(11 downto 9) when (OP = ABCD or OP = SBCD) and FETCH_STATE = CALC_AEFF and PHASE2 = false else
BIW_0(11 downto 9) when (OP = ABCD or OP = SBCD) and FETCH_STATE = FETCH_OPERAND and PHASE2 = false and RD_RDY = '0' else -- Destination first.
BIW_0(11 downto 9) when (OP = ABCD or OP = SBCD) and FETCH_STATE = INIT_EXEC_WB else
BIW_0(11 downto 9) when (OP = ADDX or OP = SUBX) and FETCH_STATE = START_OP else
BIW_0(11 downto 9) when (OP = ADDX or OP = SUBX) and FETCH_STATE = CALC_AEFF and PHASE2 = false else
BIW_0(11 downto 9) when (OP = ADDX or OP = SUBX) and FETCH_STATE = FETCH_OPERAND and PHASE2 = false and RD_RDY = '0' else -- Destination first.
BIW_0(11 downto 9) when (OP = ADDX or OP = SUBX) and FETCH_STATE = INIT_EXEC_WB else
BIW_0(11 downto 9) when OP = CMPM and FETCH_STATE = FETCH_OPERAND and PHASE2 = false else -- Fetch destination.
BIW_0(11 downto 9) when OP = MOVE and FETCH_STATE = START_OP and BIW_0(5 downto 3) < "010" and BIW_0(8 downto 6) /= "000" else -- Source is Dn, An.
BIW_0(11 downto 9) when OP = MOVE and FETCH_STATE = CALC_AEFF and PHASE2 = true else
BIW_0(11 downto 9) when OP = MOVE and FETCH_STATE = FETCH_OPERAND and RD_RDY = '1' and BIW_0(8 downto 6) = "100" and BIW_0(5 downto 3) /= "011" else -- All except (An)+,-(An).
BIW_0(11 downto 9) when OP = MOVE and FETCH_STATE = FETCH_IDATA_B1 and BIW_0(8 downto 6) /= "000" else
BIW_0(11 downto 9) when OP = MOVE and FETCH_STATE = FETCH_ABS_LO and BIW_0(8 downto 6) /= "000" and PHASE2 = false else
BIW_0(11 downto 9) when OP = MOVE and FETCH_STATE = SWITCH_STATE and BIW_0(8 downto 6) /= "000" else
BIW_0(11 downto 9) when OP = MOVE and FETCH_STATE = INIT_EXEC_WB and BIW_0(8 downto 6) /= "000" else
BIW_1(14 downto 12) when OP = MOVEC and BIW_0(0) = '1' else -- MOVEC: general register to control register.
"111" when OP = BSR or OP = MOVEC else -- Stack pointers.
"111" when (OP = JSR or OP = LINK) and FETCH_STATE = START_OP else -- Select the SP to decrement.
"111" when OP = PEA and FETCH_STATE = SWITCH_STATE and PHASE2 = true else -- Select the SP to decrement.
"111" when (OP = JSR or OP = LINK or OP = PEA) and FETCH_STATE = INIT_EXEC_WB else -- Writeback address is the SP.
"111" when OP = RTD or OP = RTR or OP = RTS else -- Stack pointer.
"111" when OP = UNLK and (FETCH_STATE = START_OP or FETCH_STATE = CALC_AEFF or FETCH_STATE = FETCH_OPERAND) else -- Check in START_OP to avoid dataz hazards!
BIW_0(2 downto 0) when OP = ABCD or OP = ADD or OP = ADDA or OP = ADDI or OP = ADDQ or OP = ADDX or OP = AND_B or OP = ANDI else
BIW_0(2 downto 0) when OP = ASL or OP = ASR or OP = BCHG or OP = BCLR or OP = BSET or OP = BTST else
BIW_0(2 downto 0) when OP = CHK or OP = CLR or OP = CMP or OP = CMPA or OP = CMPI or OP = CMPM else
BIW_0(2 downto 0) when OP = DIVS or OP = DIVU or OP = EOR or OP = EORI or OP = EXG or OP = JMP or OP = JSR or OP = LEA or OP = LINK or OP = LSL or OP = LSR else
BIW_0(2 downto 0) when OP = MOVE or OP = MOVEA or OP = MOVE_FROM_CCR or OP = MOVE_FROM_SR or OP = MOVE_TO_CCR or OP = MOVE_TO_SR else
BIW_0(2 downto 0) when OP = MOVE_USP or OP = MOVEM or OP = MOVEP or OP = MOVES or OP = MULS or OP = MULU else
BIW_0(2 downto 0) when OP = NBCD or OP = NEG or OP = NEGX or OP = NOT_B or OP = OR_B or OP = ORI or OP = PEA else
BIW_0(2 downto 0) when OP = ROTL or OP = ROTR or OP = ROXL or OP = ROXR or OP = SBCD or OP = Scc or OP = SUB or OP = SUBA else
BIW_0(2 downto 0) when OP = SUBI or OP = SUBQ or OP = SUBX or OP = TAS or OP = TST or OP = UNLK else "000";
-- Always the destination.
AR_SEL_WR_1 <= BIW_0(2 downto 0) when OP = ADDQ or OP = SUBQ else
BIW_0(2 downto 0) when OP = EXG and BIW_0(7 downto 3) = "10001" else -- Data and Address register.
BIW_1(14 downto 12) when OP = MOVEC or OP = MOVES else
"111" when OP = UNLK and FETCH_STATE = START_OP else
BIW_0(2 downto 0) when OP = LINK else
MOVEM_PNTR(2 downto 0) when OP = MOVEM else
BIW_0(2 downto 0) when OP = MOVE_USP else
BIW_0(11 downto 9); -- ADDA, EXG, LEA, MOVE, MOVEA, SUBA.
AR_WR_1 <= AR_WR_I;
AR_WR_I <= '1' when OP = LINK and FETCH_STATE = INIT_EXEC_WB and ALU_BSY = '0' else -- Write SP to An.
'1' when OP = UNLK and FETCH_STATE = SWITCH_STATE and NEXT_FETCH_STATE /= SWITCH_STATE else -- Write An to SP.
'0' when EXEC_WB_STATE /= WRITEBACK else
'1' when OP_WB_I = ADDA or OP_WB_I = SUBA else
'1' when (OP_WB_I = ADDQ or OP_WB_I = SUBQ) and BIW_0_WB(5 downto 3) = "001" else
'1' when OP_WB_I = EXG and BIW_0_WB(7 downto 3) = "01001" else -- Two address registers.
'1' when OP_WB_I = EXG and BIW_0_WB(7 downto 3) = "10001" else -- Data and Address register.
'1' when OP_WB_I = LEA else
'1' when OP_WB_I = MOVE_USP and BIW_0_WB(3) = '1' else
'1' when OP_WB_I = MOVEA else
'1' when OP_WB_I = MOVEC and BIW_1_WB(15) = '1' and BIW_0_WB(0) = '0' else
'1' when OP_WB_I = MOVES and BIW_1_WB(15) = '1' else
'1' when OP_WB_I = MOVEM and MOVEM_ADn_WB = '1' else '0';
AR_SEL_RD_2 <= MOVEM_PNTR(2 downto 0) when OP = MOVEM else -- This is the non addressing output.
BIW_1(14 downto 12) when OP = MOVES else
BIW_0(2 downto 0) when OP = ADDQ or OP = MOVE or OP = SUBQ or OP = TST else
BIW_0(2 downto 0) when OP = EXG and BIW_0(7 downto 3) = "10001" else -- Data and address register.
BIW_0(11 downto 9) when OP = ADDA or OP = CMPA or OP = EXG or OP = SUBA else "000";
AR_SEL_WR_2 <= BIW_0(2 downto 0); -- Used for EXG, UNLK.
AR_WR_2 <= AR_WR_II;
AR_WR_II <= '1' when OP_WB_I = UNLK and EXEC_WB_STATE = WRITEBACK else -- Write (SP) to An.
'1' when OP_WB_I = EXG and EXEC_WB_STATE = WRITEBACK and BIW_0_WB(7 downto 3) = "01001" else '0'; -- Two address registers.
AR_INC <= '1' when (OP = ADD or OP = CMP or OP = SUB) and ADR_MODE_I = "011" and ALU_INIT_I = '1' else
'1' when (OP = ADDA or OP = CMPA or OP = SUBA) and ADR_MODE_I = "011" and FETCH_STATE = FETCH_OPERAND and DATA_RDY = '1' else
'1' when (OP = ADDI or OP = CMPI or OP = SUBI) and ADR_MODE_I = "011" and ALU_INIT_I = '1' else
'1' when (OP = ADDQ or OP = SUBQ) and ADR_MODE_I = "011" and ALU_INIT_I = '1' else
'1' when (OP = AND_B or OP = EOR or OP = OR_B) and ADR_MODE_I = "011" and ALU_INIT_I = '1' else
'1' when (OP = ANDI or OP = EORI or OP = ORI) and ADR_MODE_I = "011" and ALU_INIT_I = '1' else
'1' when (OP = ASL or OP = ASR or OP = LSL or OP = LSR) and BIW_0(7 downto 3) = "11011" and ALU_INIT_I = '1' else
'1' when (OP = ROTL or OP = ROTR or OP = ROXL or OP = ROXR) and BIW_0(7 downto 3) = "11011" and ALU_INIT_I = '1' else
'1' when (OP = BCHG or OP = BCLR or OP = BSET or OP = BTST) and ADR_MODE_I = "011" and ALU_INIT_I = '1' else
'1' when OP = TAS and ADR_MODE_I = "011" and FETCH_STATE = INIT_EXEC_WB and NEXT_FETCH_STATE /= INIT_EXEC_WB else
'1' when (OP = CHK or OP = CLR or OP = TST or OP = Scc) and ADR_MODE_I = "011" and ALU_INIT_I = '1' else
'1' when (OP = NBCD or OP = NEG or OP = NEGX or OP = NOT_B) and ADR_MODE_I = "011" and ALU_INIT_I = '1' else
'1' when OP = CMPM and FETCH_STATE = FETCH_OPERAND and RD_RDY = '1' and DATA_VALID = '1' else
'1' when (OP = MULS or OP = MULU or OP = DIVS or OP = DIVU) and ADR_MODE_I = "011" and ALU_INIT_I = '1' else
'1' when (OP = MOVE_FROM_CCR or OP = MOVE_FROM_SR) and ADR_MODE_I = "011" and FETCH_STATE = INIT_EXEC_WB and NEXT_FETCH_STATE /= INIT_EXEC_WB else
'1' when (OP = MOVE_TO_CCR or OP = MOVE_TO_SR) and ADR_MODE_I = "011" and FETCH_STATE = INIT_EXEC_WB and NEXT_FETCH_STATE /= INIT_EXEC_WB else
'1' when OP = MOVE and ADR_MODE_I = "011" and FETCH_STATE = FETCH_OPERAND and NEXT_FETCH_STATE /= FETCH_OPERAND else
'1' when OP = MOVE and BIW_0(8 downto 6) = "011" and FETCH_STATE = INIT_EXEC_WB and NEXT_FETCH_STATE /= INIT_EXEC_WB else
'1' when OP = MOVEA and ADR_MODE_I = "011" and FETCH_STATE = INIT_EXEC_WB and NEXT_FETCH_STATE /= INIT_EXEC_WB else
'1' when OP = MOVEM and ADR_MODE_I = "011" and ALU_INIT_I = '1' else
'1' when OP = MOVES and ADR_MODE_I = "011" and ALU_INIT_I = '1' else
'1' when (OP = UNLK or OP = RTD or OP = RTR or OP = RTS) and FETCH_STATE = FETCH_OPERAND and RD_RDY = '1' and DATA_VALID = '1' else '0';
with OP select
AR_DEC_I <= '1' when ABCD | ADD | ADDA | ADDI | ADDQ | ADDX | AND_B | ANDI | ASL | ASR | BCHG | BCLR | BSET | BTST | CHK | CMP | CMPA | CMPI |
DIVS | DIVU | EOR | EORI | LSL | LSR | MOVE | MOVEA | MOVE_TO_CCR | MOVE_TO_SR | MOVES | MULS | MULU | NBCD | NEG | NEGX |
NOT_B | OR_B | ORI | ROTL | ROTR | ROXL | ROXR | SBCD | SUB | SUBA | SUBI | SUBQ | SUBX | TAS | TST, '0' when others;
AR_DEC <= AR_DEC_I when ADR_MODE_I = "100" and FETCH_STATE /= CALC_AEFF and NEXT_FETCH_STATE = CALC_AEFF else
'1' when (OP = BSR or OP = JSR or OP = LINK) and FETCH_STATE = START_OP and NEXT_FETCH_STATE /= START_OP else
'1' when (OP = CLR or OP = Scc) and ADR_MODE_I = "100" and INIT_ENTRY = '1' else
'1' when OP = MOVE and BIW_0(8 downto 6) = "100" and BIW_0(5 downto 3) /= "011" and INIT_ENTRY = '1' else -- Not (An)+,-(An).
'1' when OP = MOVE and BIW_0(8 downto 6) = "100" and FETCH_STATE = SWITCH_STATE else -- Needed for source (An)+ mode.
'1' when OP = MOVEM and ADR_MODE_I = "100" and INIT_ENTRY = '1' else -- Decrement before the first bus access.
'1' when OP = MOVEM and ADR_MODE_I = "100" and ALU_INIT_I = '1' and MOVEM_LAST_WR = false else -- After the last bus access the address register is not decremented.
'1' when (OP = MOVE_FROM_CCR or OP = MOVE_FROM_SR) and ADR_MODE_I = "100" and INIT_ENTRY = '1' else
'1' when OP = MOVES and ADR_MODE_I = "100" and BIW_1(11) = '1' and INIT_ENTRY = '1' else
-- PEA: decrement late in SWITCH_STATE not to decremented address register for PEA (xx,A7,yy) address modi.
'1' when OP = PEA and FETCH_STATE = SWITCH_STATE and PHASE2 = true else '0';
DR_SEL_RD_1 <= EXT_WORD(14 downto 12) when FETCH_STATE = FETCH_EXWORD_1 else -- Index register
BIW_0(11 downto 9) when (OP = ADD or OP = SUB) and BIW_0(8) = '1' else
BIW_0(11 downto 9) when (OP = AND_B or OP = EOR or OP = OR_B) and BIW_0(8) = '1' else
BIW_0(11 downto 9) when OP = BCHG or OP = BCLR or OP = BSET or OP = BTST else
BIW_0(11 downto 9) when OP = ASL or OP = ASR or OP = LSL or OP = LSR else
BIW_0(11 downto 9) when OP = ROTL or OP = ROTR or OP = ROXL or OP = ROXR else
BIW_1(2 downto 0) when (OP = DIVS or OP = DIVU) and FETCH_STATE /= INIT_EXEC_WB and BIW_0(8 downto 6) = "001" else -- LONG 64.
MOVEM_PNTR(2 downto 0) when OP = MOVEM else
BIW_0(11 downto 9) when OP = MOVEP else
BIW_1(14 downto 12) when OP = MOVEC or OP = MOVES else
BIW_0(2 downto 0) when OP = ADD or OP = AND_B or OP = OR_B or OP = SUB else
BIW_0(2 downto 0) when OP = ABCD or OP = ADDA or OP = ADDX or OP = CHK or OP = CMP or OP = CMPA else
BIW_0(11 downto 9) when OP = EXG and BIW_0(7 downto 3) = "10001" else -- Data and address register.
BIW_0(2 downto 0) when OP = DIVS or OP = DIVU or OP = EXG else
BIW_0(2 downto 0) when OP = MOVE or OP = MOVEA or OP = MOVE_TO_CCR or OP = MOVE_TO_SR or OP = MULS or OP = MULU else
BIW_0(2 downto 0) when OP = SBCD or OP = SUBA or OP = SUBX else "000";
DR_SEL_WR_1 <= BIW_1(14 downto 12) when OP = MOVEC or OP = MOVES else
BIW_0(11 downto 9) when OP = ABCD or OP = SBCD else
BIW_0(11 downto 9) when OP = ADDX or OP = SUBX else
BIW_0(11 downto 9) when OP = ADD or OP = SUB else
BIW_0(11 downto 9) when OP = AND_B or OP = OR_B else
BIW_0(11 downto 9) when (OP = DIVS or OP = DIVU) and OP_SIZE_I = WORD else
BIW_1(14 downto 12) when OP = DIVS or OP = DIVU else
BIW_0(11 downto 9) when (OP = MULS or OP = MULU) and OP_SIZE_I = WORD else
BIW_1(14 downto 12) when OP = MULS or OP = MULU else -- Low order result and operand.
BIW_0(11 downto 9) when OP = EXG else
BIW_0(11 downto 9) when OP = MOVE or OP = MOVEP or OP = MOVEQ else
MOVEM_PNTR(2 downto 0) when OP = MOVEM else
BIW_0(2 downto 0);
DR_WR_1 <= '1' when OP_WB_I = EXG and EXEC_WB_STATE = WRITEBACK and BIW_0_WB(7 downto 3) = "10001" else -- Address- and data register.
'0' when AR_WR_I = '1' else -- This is the locking AR against DR.
'0' when AR_WR_II = '1' else -- This is the locking AR against DR.
'0' when OP_WB_I = ANDI_TO_SR or OP_WB_I = EORI_TO_SR or OP_WB_I = ORI_TO_SR else
'0' when OP_WB_I = MOVE_TO_CCR or OP_WB_I = MOVE_TO_SR else
'0' when OP_WB_I = MOVE_USP else -- USP is written.
'0' when OP_WB_I = MOVEC and BIW_0_WB(0) = '1' else -- To control register.
'0' when OP_WB_I = STOP else -- SR is written but not DR.
'1' when EXEC_WB_STATE = WRITEBACK else '0';
DR_SEL_RD_2 <= BIW_0(11 downto 9) when OP = ABCD or OP = SBCD or OP = ADDX or OP = SUBX else
BIW_0(2 downto 0) when (OP = ADD or OP = AND_B or OP = OR_B or OP = SUB) and BIW_0(8) = '1' else
BIW_0(11 downto 9) when OP = ADD or OP = CMP or OP = SUB or OP = AND_B or OP = OR_B else
BIW_0(11 downto 9) when OP = CHK or OP = EXG else
BIW_0(11 downto 9) when (OP = DIVS or OP = DIVU) and BIW_0(7) = '1' else -- WORD size.
BIW_1(14 downto 12) when (OP = DIVS or OP = DIVU) else -- Quotient low portion.
BIW_0(11 downto 9) when (OP = MULS or OP = MULU) and BIW_0(7) = '1' else -- WORD size.
BIW_1(14 downto 12) when (OP = MULS or OP = MULU) else
BIW_0(2 downto 0) when OP = BCHG or OP = BCLR or OP = BSET or OP = BTST else
BIW_0(2 downto 0) when OP = ADDI or OP = ADDQ or OP = ANDI or OP = BCHG or OP = BCLR or OP = BSET or OP = BTST or OP = CMPI else
BIW_0(2 downto 0) when OP = DBcc or OP = EOR or OP = EORI or OP = EXT or OP = NBCD or OP = NEG or OP = NEGX else
BIW_0(2 downto 0) when OP = NOT_B or OP = ORI or OP = SUBI or OP = SUBQ or OP = SWAP or OP = TAS or OP = TST else
BIW_0(2 downto 0) when OP = ASL or OP = ASR or OP = LSL or OP = LSR else
BIW_0(2 downto 0) when OP = ROTL or OP = ROTR or OP = ROXL or OP = ROXR else "000";
DR_SEL_WR_2 <= BIW_0(2 downto 0) when OP = EXG else BIW_1(2 downto 0); -- Default is for DIVS and DIVU, MULS, MULU.
-- Normally source register. Writte in a few exceptions.
DR_WR_2 <= '1' when OP_WB_I = EXG and EXEC_WB_STATE = WRITEBACK and BIW_0_WB(7 downto 3) = "01000" else -- Two data registers.
'1' when OP_WB_I = DIVS and EXEC_WB_STATE = WRITEBACK and BIW_0_WB(8 downto 6) = "001" and BIW_1_WB(14 downto 12) /= BIW_1_WB(2 downto 0) else
'1' when OP_WB_I = DIVU and EXEC_WB_STATE = WRITEBACK and BIW_0_WB(8 downto 6) = "001" and BIW_1_WB(14 downto 12) /= BIW_1_WB(2 downto 0) else
'1' when OP_WB_I = MULS and EXEC_WB_STATE = WRITEBACK and BIW_0_WB(8 downto 6) = "000" and BIW_1_WB(10) = '1' and BIW_1_WB(14 downto 12) /= BIW_1_WB(2 downto 0) else
'1' when OP_WB_I = MULU and EXEC_WB_STATE = WRITEBACK and BIW_0_WB(8 downto 6) = "000" and BIW_1_WB(10) = '1' and BIW_1_WB(14 downto 12) /= BIW_1_WB(2 downto 0) else '0';
WB_BUFFER: process
-- This process stores the data for the
-- WRITEBACK or the WRITE_DEST procedure.
-- The MOVEM condition is foreseen to bring
-- the ADn_WB and the PNTR_WB right in time
-- befor the address or data registers are
-- marked used.
begin
wait until CLK = '1' and CLK' event;
if OP = LINK and FETCH_STATE = START_OP and NEXT_FETCH_STATE = SWITCH_STATE then
OP_SIZE_WB <= OP_SIZE_I; -- Bring this information early because the registers are written early.
elsif ALU_INIT_I = '1' then
if OP = DIVS or OP = DIVU or OP = MULS or OP = MULU then
OP_SIZE_WB <= LONG;
elsif OP = MOVEM and BIW_0(10) = '1' then -- Memory to register.
OP_SIZE_WB <= LONG; -- Registers are always written long.
else
OP_SIZE_WB <= OP_SIZE_I; -- Store right in the end before data processing starts.
end if;
MOVEM_ADn_WB <= MOVEM_ADn_I;
OP_WB_I <= OP;
BIW_0_WB <= BIW_0(11 downto 0);
BIW_1_WB <= BIW_1;
end if;
end process WB_BUFFER;
OP_WB <= OP_WB_I;
BIW_0_WB_73 <= BIW_0_WB(7 downto 3);
OP_SIZE <= OP_SIZE_I;
OP_SIZE_I <= LONG when (OP = ADDA or OP = CMPA or OP = SUBA) and BIW_0(8 downto 7) = "11" else
LONG when (OP = BCHG or OP = BCLR or OP = BTST or OP = BSET) and BIW_0(5 downto 3) = "000" else
LONG when OP = EXT and BIW_0(8 downto 6) = "011" else
LONG when OP = BSR or OP = EXG or OP = JSR or OP = LEA or OP = LINK or OP = PEA or OP = SWAP or OP = UNLK else
LONG when OP = CHK and BIW_0(8 downto 7) = "10" else
LONG when (OP = MOVE or OP = MOVEA) and BIW_0(13 downto 12) = "10" else
LONG when OP = MOVEC or OP = MOVEQ or OP = MOVE_USP or OP = RTD or OP = RTS else
LONG when OP = MOVEM and BIW_0(6) = '1' else
LONG when OP = MOVEP and FETCH_STATE = INIT_EXEC_WB and BIW_0(7 downto 6) < "10" else -- Writeback to registers is long (see top level multiplexer).
LONG when (OP = DIVS or OP = DIVU or OP = MULS or OP = MULU) and BIW_0(7) = '0' else
LONG when OP = RTR and PHASE2 = true else -- Read PC.
WORD when (OP = ADDA or OP = CMPA or OP = SUBA) and BIW_0(8 downto 7) = "01" else
WORD when (OP = ASL or OP = ASR) and BIW_0(7 downto 6) = "11" else -- Memory shifts.
WORD when OP = ANDI_TO_SR or OP = EORI_TO_SR or OP = ORI_TO_SR else
WORD when OP = BKPT and FETCH_STATE = FETCH_OPERAND and DATA_RD_I = '1' else
WORD when OP = CHK and BIW_0(8 downto 7) = "11" else
WORD when OP = DBcc or OP = EXT else
WORD when (OP = LSL or OP = LSR) and BIW_0(7 downto 6) = "11" else -- Memory shifts.
WORD when (OP = MOVE or OP = MOVEA) and BIW_0(13 downto 12) = "11" else
WORD when OP = MOVE_FROM_CCR or OP = MOVE_TO_CCR else
WORD when OP = MOVE_FROM_SR or OP = MOVE_TO_SR else
WORD when OP = MOVEM or OP = RTR else
WORD when OP = DIVS or OP = DIVU or OP = MULS or OP = MULU else
WORD when (OP = ROTL or OP = ROTR) and BIW_0(7 downto 6) = "11" else -- Memory shifts.
WORD when (OP = ROXL or OP = ROXR) and BIW_0(7 downto 6) = "11" else -- Memory shifts.
BYTE when OP = ABCD or OP = NBCD or OP = SBCD else
BYTE when OP = ANDI_TO_CCR or OP = EORI_TO_CCR or OP = ORI_TO_CCR else
BYTE when OP = BCHG or OP = BCLR or OP = BTST or OP = BSET else
BYTE when OP = MOVE or OP = MOVEP else
BYTE when OP = Scc or OP = TAS else
-- The following are default settings for all other OP_SIZE relevant operations.
BYTE when BIW_0(7 downto 6) = "00" else
WORD when BIW_0(7 downto 6) = "01" else LONG;
BKPT_CYCLE <= '1' when OP = BKPT and FETCH_STATE = FETCH_OPERAND and DATA_RD_I = '1' else '0';
BKPT_INSERT <= '1' when OP = BKPT and FETCH_STATE = FETCH_OPERAND and RD_RDY = '1' and DATA_VALID = '1' else '0';
-- All traps must be modeled as strobes.
TRAP_ILLEGAL <= '1' when OP = BKPT and FETCH_STATE = FETCH_OPERAND and RD_RDY = '1' and DATA_VALID = '0' else '0';
TRAP_V <= '1' when OP = TRAPV and ALU_COND = true and FETCH_STATE = SLEEP and NEXT_FETCH_STATE = START_OP else '0';
BERR <= '0' when FETCH_STATE = START_OP and EXEC_WB_STATE = IDLE else -- Disable when controller is not active.
'0' when OP = BKPT else -- No bus error during breakpoint cycle.
'1' when DATA_RDY = '1' and DATA_VALID = '0' else
'1' when OPD_ACK = '1' and OW_VALID = '0' else
'1' when EW_ACK = '1' and OW_VALID = '0' else '0';
SFC_RD <= '1' when OP = MOVEC and BIW_0(0) = '0' and BIW_1(11 downto 0) = x"000" else '0';
SFC_WR <= '1' when OP_WB_I = MOVEC and BIW_0_WB(0) = '1' and BIW_1_WB(11 downto 0) = x"000" and EXEC_WB_STATE = WRITEBACK else '0';
DFC_RD <= '1' when OP = MOVEC and BIW_0(0) = '0' and BIW_1(11 downto 0) = x"001" else '0';
DFC_WR <= '1' when OP_WB_I = MOVEC and BIW_0_WB(0) = '1' and BIW_1_WB(11 downto 0) = x"001" and EXEC_WB_STATE = WRITEBACK else '0';
VBR_RD <= '1' when OP = MOVEC and BIW_0(0) = '0' and BIW_1(11 downto 0) = x"801" else '0';
VBR_WR <= '1' when OP_WB_I = MOVEC and BIW_0_WB(0) = '1' and BIW_1_WB(11 downto 0) = x"801" and EXEC_WB_STATE = WRITEBACK else '0';
USP_RD <= '1' when OP = MOVE_USP and BIW_0(3) = '1' else
'1' when OP = MOVEC and BIW_0(0) = '0' and BIW_1(11 downto 0) = x"800" else '0';
USP_WR <= '1' when OP_WB_I = MOVE_USP and EXEC_WB_STATE = WRITEBACK and BIW_0_WB(3) = '0' else
'1' when OP_WB_I = MOVEC and BIW_0_WB(0) = '1' and BIW_1_WB(11 downto 0) = x"800" and EXEC_WB_STATE = WRITEBACK else '0';
P_DISPLACEMENT: process
variable DISPL_VAR : std_logic_vector(31 downto 0);
-- The displacement is is always word sized and sign
-- extended for the K00/K10.
begin
wait until CLK = '1' and CLK' event;
case OP is
when Bcc | BRA | BSR =>
case BIW_0(7 downto 0) is
when x"00" =>
for i in 16 to 31 loop
DISPL_VAR(i) := BIW_1(15);
end loop;
DISPL_VAR(15 downto 0) := BIW_1;
when others =>
for i in 8 to 31 loop
DISPL_VAR(i) := BIW_0(7);
end loop;
DISPL_VAR(7 downto 0) := BIW_0(7 downto 0);
end case;
when DBcc | MOVEP | RTD =>
for i in 16 to 31 loop
DISPL_VAR(i) := BIW_1(15);
end loop;
DISPL_VAR(15 downto 0) := BIW_1;
when others => -- Used for LINK.
for i in 16 to 31 loop
DISPL_VAR(i) := BIW_1(15);
end loop;
DISPL_VAR(15 downto 0) := BIW_1;
end case;
--
case OP is
when LINK | MOVEP => DISPLACEMENT <= DISPL_VAR;
when others => DISPLACEMENT <= DISPL_VAR + "10";
end case;
end process P_DISPLACEMENT;
PC_ADD_DISPL <= '1' when OP = Bcc and FETCH_STATE /= START_OP and NEXT_FETCH_STATE = START_OP and ALU_COND = true else
'1' when (OP = BRA or OP = BSR) and FETCH_STATE /= START_OP and NEXT_FETCH_STATE = START_OP else
'1' when OP = DBcc and FETCH_STATE /= START_OP and NEXT_FETCH_STATE = START_OP and ALU_COND = false and DBcc_COND = false else '0';
PC_LOAD <= PC_LOAD_I;
PC_LOAD_I <= '1' when (OP = JMP or OP = JSR) and FETCH_STATE /= START_OP and NEXT_FETCH_STATE = START_OP else
'1' when (OP = RTD or OP = RTR or OP = RTS) and FETCH_STATE /= START_OP and NEXT_FETCH_STATE = START_OP else '0';
-- The pipe is flushed for the system control instructions. Be aware, that the operations resulting in an exception
-- like the CHK or TRAP operations flush the pipe via the exception handler.
-- Context switch may occur from:
-- changing the PC value (branches etc.)
-- changing the RAM space (status register MSBs).
-- changing Function codes or the active stack pointer.
IPIPE_FLUSH <= IPIPE_FLUSH_I;
IPIPE_FLUSH_I <= '1' when (OP = BRA or OP = BSR) and FETCH_STATE /= START_OP and NEXT_FETCH_STATE = START_OP else
'1' when OP = Bcc and FETCH_STATE /= START_OP and NEXT_FETCH_STATE = START_OP and ALU_COND = true else
'1' when OP = DBcc and LOOP_BSY = '0' and FETCH_STATE /= START_OP and NEXT_FETCH_STATE = START_OP and ALU_COND = false and DBcc_COND = false else
'1' when OP = DBcc and LOOP_EXIT_I = '1' and (ALU_COND = true or DBcc_COND = true) else -- Flush the pipe after a finished loop.
'1' when (OP = ANDI_TO_SR or OP = EORI_TO_SR or OP = MOVE_TO_SR or OP = ORI_TO_SR) and FETCH_STATE = SLEEP and NEXT_FETCH_STATE = START_OP else
'1' when (OP = JMP or OP = JSR) and FETCH_STATE /= START_OP and NEXT_FETCH_STATE = START_OP else
'1' when OP = MOVEC and BIW_0(0) = '1' and FETCH_STATE /= START_OP and NEXT_FETCH_STATE = START_OP else -- Writing control registers.
'1' when (OP = RTD or OP = RTR or OP = RTS) and FETCH_STATE /= START_OP and NEXT_FETCH_STATE = START_OP else '0';
SP_ADD_DISPL <= '1' when OP = LINK and FETCH_STATE = INIT_EXEC_WB and ALU_BSY = '0' else
'1' when OP = RTD and FETCH_STATE = FETCH_OPERAND and RD_RDY = '1' and DATA_VALID = '1' else '0';
ALU_TRIG <= '0' when ALU_BSY = '1' or FETCH_STATE /= INIT_EXEC_WB else
'0' when OP = CMPM and PHASE2 = false else
'0' when OP = MOVE and PHASE2 = true else -- No ALU required after second portion of address calculation.
'0' when OP = MOVEM and MOVEM_COND = false else
'0' when OP = MOVEM and BIW_0(10) = '1' and MOVEM_FIRST_RD = false else -- Do not load before the first read access.
'0' when OP = RTR and PHASE2 = true else '1'; -- RTR: not when PC is loaded.
-- This is the signal loading the operands into the ALU registers:
ALU_INIT <= ALU_INIT_I;
with OP select
ALU_INIT_I <= ALU_TRIG when ABCD | ADD | ADDA | ADDI | ADDQ | ADDX | AND_B | ANDI | ANDI_TO_CCR | ANDI_TO_SR | ASL | ASR | Bcc | BCHG |
BCLR | BSET | BSR | BTST | CHK | CLR | CMP | CMPA | CMPI | CMPM | DBcc | DIVS | DIVU | EOR | EORI |
EORI_TO_CCR | EORI_TO_SR | EXG | EXT | JSR | LEA | LINK | LSL | LSR | MOVE | MOVEA | MOVE_FROM_CCR |
MOVE_TO_CCR | MOVE_FROM_SR | MOVE_TO_SR | MOVE_USP | MOVEC | MOVEM | MOVEQ | MOVEP | MOVES | MULS |
MULU | NBCD | NEG | NEGX | NOT_B | OR_B | ORI | ORI_TO_CCR | ORI_TO_SR | PEA | ROTL | ROTR | ROXL |
ROXR | RTR | SBCD | Scc | SUB | SUBA | SUBI | SUBQ | SUBX | SWAP | STOP | TAS | TRAPV | TST | UNLK, '0' when others;
UPDT_CC <= '0' when (OP_WB_I = ADDQ or OP_WB_I = SUBQ) and BIW_0_WB(5 downto 3) = "001" else ALU_REQ; -- No update for ADDQ and SUBQ when destination is an address register.
with OP_WB_I select
CC_UPDT <= UPDT_CC when ABCD | ADD | ADDI | ADDQ | ADDX | AND_B | ANDI | ANDI_TO_CCR | ASL | ASR | BCHG | BCLR |
BSET | BTST | CHK | CLR | CMP | CMPA | CMPI | CMPM | DIVS | DIVU |
EOR | EORI | EORI_TO_CCR | EXT | LSL | LSR | MOVE | MOVEQ | MULS | MULU | NBCD |
NEG | NEGX | NOT_B | OR_B | ORI | ORI_TO_CCR | ROTL | ROTR | ROXL | ROXR | RTR | SBCD |
SUB | SUBI | SUBQ | SUBX | SWAP | TAS | TST, '0' when others;
ADR_MARK_USED <= '1' when OP = MOVE and FETCH_STATE = INIT_EXEC_WB and PHASE2 = true else -- Destination address calculation done.
'0' when FETCH_STATE /= INIT_EXEC_WB or ALU_BSY = '1' else -- Deactivate except in the end of INIT_EXEC_WB.
'1' when OP = BSR or OP = JSR or OP = LINK or OP = PEA else
'1' when (OP = ADDI or OP = ANDI or OP = EOR or OP = EORI or OP = ORI or OP = SUBI) and BIW_0(5 downto 3) /= "000" else
'1' when (OP = ABCD or OP = SBCD or OP = ADDX or OP = SUBX) and BIW_0(3) = '1' else
'1' when (OP = ADD or OP = AND_B or OP = OR_B or OP = SUB) and BIW_0(8) = '1' else -- Destination is memory.
'1' when (OP = ADDQ or OP = BCHG or OP = BCLR or OP = BSET or OP = CLR or OP = MOVE_FROM_CCR or OP = MOVE_FROM_SR) and BIW_0(5 downto 3) > "001" else
'1' when (OP = NBCD or OP = NEG or OP = NEGX or OP = NOT_B or OP = Scc or OP = SUBQ or OP = TAS) and BIW_0(5 downto 3) > "001" else
'1' when (OP = ASL or OP = ASR or OP = LSL or OP = LSR) and BIW_0(7 downto 6) = "11" else -- Memory shifts.
'1' when (OP = ROTL or OP = ROTR or OP = ROXL or OP = ROXR) and BIW_0(7 downto 6) = "11" else -- Memory shifts.
'1' when OP = MOVE and PHASE2 = false and BIW_0(8 downto 6) /= "000" and BIW_0(8 downto 6) < "101" else -- We do not need destination address calculation access.
'1' when OP = MOVEM and BIW_0(10) = '0' and MOVEM_COND = true else -- Register to memory.
'1' when OP = MOVEP and BIW_0(7 downto 6) > "01" else -- Register to Memory.
'1' when OP = MOVES and BIW_1(11) = '1' else '0'; -- Register to memory.
AR_MARK_USED <= '1' when OP = UNLK and FETCH_STATE /= SWITCH_STATE and NEXT_FETCH_STATE = SWITCH_STATE else -- This is for An to SP.
'1' when OP = LINK and FETCH_STATE = SWITCH_STATE and NEXT_FETCH_STATE /= SWITCH_STATE else -- This is for SP to An.
'0' when FETCH_STATE /= INIT_EXEC_WB or NEXT_FETCH_STATE = INIT_EXEC_WB else -- Deactivate except in the end of INIT_EXEC_WB.
'1' when OP = ADDA or OP = SUBA else
'1' when (OP = ADDQ or OP = SUBQ) and BIW_0(5 downto 3) = "001" else
'1' when OP = EXG and BIW_0(7 downto 3) /= "01000" else
'1' when OP = LEA else
'1' when OP = MOVE_USP else
'1' when OP = MOVEM and BIW_0(10) = '1' and MOVEM_ADn_I = '1' and MOVEM_COND = true else -- Memory to register.
'1' when OP = MOVEA else
'1' when OP = MOVEC and BIW_0(0) = '0' and BIW_1(15) = '1' else -- Destination is Ax.
'1' when OP = MOVES and BIW_1(15) = '1' and BIW_1(11) = '0' else
'1' when OP = UNLK else '0';
DR_MARK_USED <= '0' when FETCH_STATE /= INIT_EXEC_WB or NEXT_FETCH_STATE = INIT_EXEC_WB else -- Deactivate except in the end of INIT_EXEC_WB.
'1' when (OP = ABCD or OP = SBCD) and BIW_0(3) = '0' else
'1' when (OP = ADDX or OP = SUBX) and BIW_0(3) = '0' else
'1' when (OP = ADDQ or OP = SUBQ) and BIW_0(5 downto 3) = "000" else
'1' when (OP = ADD or OP = SUB) and BIW_0(8) = '0' else -- Destination is a register.
'1' when (OP = ADDI or OP = ANDI or OP = EOR or OP = EORI or OP = ORI or OP = SUBI) and BIW_0(5 downto 3) = "000" else
'1' when (OP = AND_B or OP = OR_B) and BIW_0(8) = '0' else -- Destination is a register.
'1' when (OP = ASL or OP = ASR) and BIW_0(7 downto 6) /= "11" else
'1' when (OP = LSL or OP = LSR) and BIW_0(7 downto 6) /= "11" else
'1' when (OP = ROTL or OP = ROTR) and BIW_0(7 downto 6) /= "11" else
'1' when (OP = ROXL or OP = ROXR) and BIW_0(7 downto 6) /= "11" else
'1' when (OP = BCHG or OP = BCLR or OP = BSET) and BIW_0(5 downto 3) = "000" else
'1' when (OP = CLR or OP = TAS or OP = Scc) and BIW_0(5 downto 3) = "000" else
'1' when OP = DBcc or OP = DIVS or OP = DIVU or OP = MULS or OP = MULU else
'1' when OP = EXG and BIW_0(7 downto 3) /= "01001" else
'1' when OP = EXT or OP = SWAP else
'1' when OP = MOVE and BIW_0(8 downto 6) = "000" else
'1' when (OP = MOVE_FROM_CCR or OP = MOVE_FROM_SR) and BIW_0(5 downto 3) = "000" else
'1' when OP = MOVEM and BIW_0(10) = '1' and MOVEM_ADn_I = '0' and MOVEM_COND = true else -- Memory to register.
'1' when OP = MOVEP and BIW_0(7 downto 6) < "10" else -- Memory to register.
'1' when OP = MOVEC and BIW_0(0) = '0' and BIW_1(15) = '0' else -- Destination is Dx.
'1' when OP = MOVEQ else
'1' when OP = MOVES and BIW_1(15) = '0' and BIW_1(11) = '0' else
'1' when (OP = NBCD or OP = NEG or OP = NEGX or OP = NOT_B) and BIW_0(5 downto 3) = "000" else '0';
UNMARK <= '1' when EXEC_WB_STATE /= IDLE and NEXT_EXEC_WB_STATE = IDLE else '0'; -- Release a pending write cycle when done.
-- These signals indicates, that two registers are prepared to be written. In this case, the values
-- in both of these registers are invalidated before the writeback.
USE_APAIR <= true when OP = EXG and BIW_0(7 downto 3) = "01001" else false;
USE_DPAIR <= true when OP = EXG and BIW_0(7 downto 3) = "01000" else
true when (OP = DIVS or OP = DIVU) and OP_SIZE_I = LONG and BIW_1(14 downto 12) /= BIW_1(2 downto 0) else
true when (OP = MULS or OP = MULU) and OP_SIZE_I = LONG and BIW_1(10) = '1' and BIW_1(14 downto 12) /= BIW_1(2 downto 0) else false;
LOOP_EXIT <= LOOP_EXIT_I;
LOOP_EXIT_I <= '1' when OP /= DBcc and LOOP_BSY = '1' and FETCH_STATE /= START_OP and NEXT_FETCH_STATE = START_OP and EXH_REQ = '1' else -- Exception! break the loop.
'1' when OP = DBcc and LOOP_BSY = '1' and FETCH_STATE = SLEEP and NEXT_FETCH_STATE = START_OP and (ALU_COND = true or DBcc_COND = true) else '0'; -- 68010 loop mechanism.
LOOP_CTRL: process
-- This flip flop indicates, if a DBcc loop operation has finished if the exception handler indicates an interrupt.
-- If so, no action is required. If the loop is split (when not finished) the exception handler may not increment
-- the PC to hold the value of the loop operation.
-- Split the loop between the loop op and DBcc to handle the PC value at interrupts correctly.
begin
wait until CLK = '1' and CLK' event;
if FETCH_STATE = START_OP and NEXT_FETCH_STATE /= START_OP then
LOOP_SPLIT <= false;
elsif PC_INC_EXH = '1' then
LOOP_SPLIT <= false;
elsif OP /= DBcc and EXH_REQ = '1' and LOOP_BSY = '1' and FETCH_STATE = SLEEP and NEXT_FETCH_STATE = START_OP then
LOOP_SPLIT <= true;
end if;
end process LOOP_CTRL;
RESET_STRB <= '1' when OP = RESET and INIT_ENTRY = '1' else '0';
EX_TRACE <= '0' when OP = ILLEGAL or OP = UNIMPLEMENTED else
'1' when TRACE_EN = '1' and OPD_ACK = '1' and FETCH_STATE = START_OP and OP = TRAP else
'1' when TRACE_EN = '1' and FETCH_STATE /= START_OP and NEXT_FETCH_STATE = START_OP else '0';
ADDRESS_OFFSET: process
variable ADR_OFFS_VAR: std_logic_vector(5 downto 0) := "000000";
begin
wait until CLK = '1' and CLK' event;
if FETCH_STATE = START_OP then
ADR_OFFS_VAR := "000000";
else
case OP is
when MOVEM =>
if ADR_MODE_I = "011" or ADR_MODE_I = "100" then -- (An)+, -(An).
null; -- Offset comes from addressing register in register to memory mode.
elsif BIW_0(10) = '1' and MOVEM_FIRST_RD = false then
null; -- Do not increment before the first bus access.
elsif MOVEM_COND = true and FETCH_STATE = INIT_EXEC_WB and ALU_BSY = '0' and OP_SIZE_I = LONG then
ADR_OFFS_VAR := ADR_OFFS_VAR + "100"; -- Register to memory.
elsif MOVEM_COND = true and FETCH_STATE = INIT_EXEC_WB and ALU_BSY = '0' then
ADR_OFFS_VAR := ADR_OFFS_VAR + "10"; -- Register to memory.
end if;
when MOVEP =>
if FETCH_STATE = INIT_EXEC_WB and ALU_BSY = '0' then
ADR_OFFS_VAR := ADR_OFFS_VAR + "10";
end if;
when others => null;
end case;
end if;
ADR_OFFSET <= ADR_OFFS_VAR;
end process ADDRESS_OFFSET;
MOVEM_CONTROL: process(ADR_MODE_I, CLK, BIW_0, BIW_1, OP, RESET_CPU, FETCH_STATE, NEXT_FETCH_STATE, ALU_BSY, MOVEM_PNTR)
variable INDEX : integer range 0 to 15 := 0;
variable MOVEM_PVAR : std_logic_vector(3 downto 0) := x"0";
variable BITS : std_logic_vector(4 downto 0);
begin
if CLK = '1' and CLK' event then
if FETCH_STATE = START_OP then
MOVEM_PVAR := x"0";
elsif FETCH_STATE = INIT_EXEC_WB and MOVEM_COND = false and MOVEM_PVAR < x"F" and ALU_BSY = '0' then
MOVEM_PVAR := MOVEM_PVAR + '1'; -- No data to write.
elsif BIW_0(10) = '1' and MOVEM_FIRST_RD = true and FETCH_STATE = INIT_EXEC_WB and MOVEM_PVAR < x"F" and ALU_BSY = '0' then
MOVEM_PVAR := MOVEM_PVAR + '1'; -- Data has not been read.
elsif BIW_0(10) = '0' and FETCH_STATE = INIT_EXEC_WB and MOVEM_PVAR < x"F" and ALU_BSY = '0' then
MOVEM_PVAR := MOVEM_PVAR + '1'; -- Data has been written.
end if;
if OP = MOVEM and ALU_INIT_I = '1' and ADR_MODE_I = "011" and MOVEM_ADn_I = '1' and MOVEM_PNTR(2 downto 0) = BIW_0(2 downto 0) then
MOVEM_INH_WR <= true; -- Do not write the addressing register.
elsif ALU_INIT_I = '1' then
MOVEM_INH_WR <= false;
end if;
if FETCH_STATE = START_OP then
MOVEM_FIRST_RD <= false;
elsif OP = MOVEM and FETCH_STATE = FETCH_OPERAND and RD_RDY = '1' then
MOVEM_FIRST_RD <= true;
end if;
if RESET_CPU = '1' or (FETCH_STATE /= START_OP and NEXT_FETCH_STATE = START_OP) then
BITS := "00000";
MOVEM_LAST_WR <= false;
elsif OP = MOVEM and FETCH_STATE = START_OP and NEXT_FETCH_STATE /= START_OP and ADR_MODE_I = "100" then -- -(An).
for i in 0 to 15 loop
BITS := BITS + BIW_1(i); -- Count number of '1's.
end loop;
MOVEM_LAST_WR <= false;
elsif OP = MOVEM and ALU_INIT_I = '1' and BITS > "00001" then
BITS := BITS - '1';
elsif OP = MOVEM and BITS = "00001" then
MOVEM_LAST_WR <= true;
end if;
-- During the MOVEM instruction in memory to register operation and addressing modes "010", "101","110" the effective address might be
-- affected, if the addressing register is active in the register list mask. To deal with it, the effective address is stored until the
-- MOVEM has read all registers from memory addressed by the initial addressing register (old value).
-- This logic is modeled synchronously (one clock latency) due to the one clock delay of the address calculation.
if OP /= MOVEM or BIW_0(10) /= '1' or (ADR_MODE_I /= "010" and ADR_MODE_I /= "101" and ADR_MODE_I /= "110") then
STORE_AEFF <= '0';
elsif FETCH_STATE /= START_OP and NEXT_FETCH_STATE = START_OP then
STORE_AEFF <= '0'; -- Operation completed.
elsif FETCH_STATE = SWITCH_STATE or FETCH_STATE = CALC_AEFF or FETCH_STATE = FETCH_OPERAND or FETCH_STATE = INIT_EXEC_WB then
STORE_AEFF <= '1';
end if;
end if;
-- This signal determines whether to handle address or data registers.
if ADR_MODE_I = "100" then -- -(An).
MOVEM_ADn_I <= not To_Bit(MOVEM_PVAR(3));
MOVEM_ADn <= not To_Bit(MOVEM_PVAR(3));
else
MOVEM_ADn_I <= To_Bit(MOVEM_PVAR(3));
MOVEM_ADn <= To_Bit(MOVEM_PVAR(3));
end if;
INDEX := To_Integer(unsigned(MOVEM_PVAR));
-- The following signal determines if a register is affected or not, depending
-- on the status of the register list bit.
if OP = MOVEM and BIW_1(INDEX) = '1' then
MOVEM_COND <= true;
else
MOVEM_COND <= false;
end if;
-- This signal determines whether to handle address or data registers.
if ADR_MODE_I = "100" then -- -(An).
MOVEM_PNTR <= not MOVEM_PVAR; -- Count down.
else
MOVEM_PNTR <= MOVEM_PVAR;
end if;
end process MOVEM_CONTROL;
MOVEP_CONTROL: process(CLK, MOVEP_PNTR_I)
-- This logic handles the bytes to be written or read during the MOVEP
-- operation. In LONG mode 4 bytes are affected and in WORD mode two bytes.
begin
if CLK = '1' and CLK' event then
if RESET_CPU = '1' or (FETCH_STATE /= START_OP and NEXT_FETCH_STATE = START_OP) then
MOVEP_PNTR_I <= 0;
elsif FETCH_STATE = START_OP and (BIW_0(8 downto 6) = "101" or BIW_0(8 downto 6) = "111") then
MOVEP_PNTR_I <= 3; -- LONG.
elsif FETCH_STATE = START_OP then
MOVEP_PNTR_I <= 1; -- WORD.
elsif FETCH_STATE = INIT_EXEC_WB and ALU_BSY = '0' and MOVEP_PNTR_I /= 0 then
MOVEP_PNTR_I <= MOVEP_PNTR_I - 1; -- Register to memory
end if;
end if;
MOVEP_PNTR <= MOVEP_PNTR_I;
end process MOVEP_CONTROL;
PHASE2_CONTROL: process
-- This is used for some operations which require
-- two control sequences.
begin
wait until CLK = '1' and CLK' event;
if NEXT_FETCH_STATE = START_OP then
PHASE2 <= false;
elsif (OP = ABCD or OP = SBCD) and FETCH_STATE = FETCH_OPERAND and RD_RDY = '1' then
PHASE2 <= true; -- One clock cycle delay for destination address calculation.
elsif (OP = ADDX or OP = SUBX) and FETCH_STATE = FETCH_OPERAND and RD_RDY = '1' then
PHASE2 <= true; -- One clock cycle delay for destination address calculation.
elsif OP = CMPM and FETCH_STATE = INIT_EXEC_WB and ALU_BSY = '0' then
PHASE2 <= true; -- Used as a control flow switch.
elsif OP = JSR and FETCH_STATE = SLEEP then
PHASE2 <= true; -- One clock cycle delay for address calculation.
elsif OP = PEA and FETCH_STATE = SWITCH_STATE then
PHASE2 <= true; -- One clock cycle delay for address calculation.
elsif OP = RTR and FETCH_STATE = INIT_EXEC_WB and NEXT_FETCH_STATE = CALC_AEFF then
PHASE2 <= true; -- Used as a control flow switch.
elsif OP = MOVE and FETCH_STATE = INIT_EXEC_WB and ALU_BSY = '0' and BIW_0(8 downto 6) > "100" then
PHASE2 <= true; -- Indicate destination address calculation is in progress.
end if;
end process PHASE2_CONTROL;
STATE_REGs: process
begin
wait until CLK = '1' and CLK' event;
if RESET_CPU = '1' then
FETCH_STATE <= START_OP;
EXEC_WB_STATE <= IDLE;
elsif EW_ACK = '1' and OW_VALID = '0' then
FETCH_STATE <= START_OP; -- Bus error.
EXEC_WB_STATE <= IDLE;
elsif OPD_ACK = '1' and OW_VALID = '0' then
FETCH_STATE <= START_OP; -- Bus error.
EXEC_WB_STATE <= IDLE;
elsif DATA_RD_I = '1' and RD_RDY = '1' and DATA_VALID = '0' then
FETCH_STATE <= START_OP; -- Bus error.
EXEC_WB_STATE <= IDLE;
elsif DATA_WR_I = '1' and RD_RDY = '1' and DATA_VALID = '0' then
FETCH_STATE <= START_OP; -- Bus error.
EXEC_WB_STATE <= IDLE;
else
FETCH_STATE <= NEXT_FETCH_STATE;
EXEC_WB_STATE <= NEXT_EXEC_WB_STATE;
end if;
end process STATE_REGs;
-- Debugging:
-- Use this signal to detect instructions in use in the writeback path (OP_WB_I) or in the fetch path (OP).
-- for these instructions you can halt the pipeline in the START_OP state to detect any problems.
-- with OP select
-- with OP_WB_I select
-- OP_TEST <= '1' when ADDA | ADDQ | EXG | LEA | LINK | MOVEA | MOVE_USP | MOVEC | MOVEM | MOVES | SUBA | SUBQ | UNLK | -- Address register manipulations.
-- ASL | ASR | LSL | LSR | ROTL | ROTR | ROXL | ROXR | DIVS | DIVU | -- Long ALU operations. (68K10, 68K30L have no barrel shifter).
-- ADD | AND_B | CLR | EOR | SUB | OR_B | CMP | CMPA | CMPM | NOT_B | NBCD | NEG | NEGX | SWAP | TAS | TST |
-- ANDI_TO_CCR | ANDI_TO_SR | EORI_TO_CCR | EORI_TO_SR | ORI_TO_CCR | ORI_TO_SR | MOVE_FROM_CCR |
-- MOVE_TO_CCR | MOVE_FROM_SR | MOVE_TO_SR | MOVE | MOVEQ | MOVEP | PEA |
-- ABCD | ADDX | SBCD | SUBX | BCHG | BCLR | BSET | BTST | EXT |
-- Bcc | BSR | CHK | DBcc | JSR | TRAPV | RTR | Scc | STOP |
-- ADDI | ANDI | SUBI | CMPI | EORI | ORI | MULS | MULU, '0' when others;
FETCH_DEC: process(ADR_MODE_I, ALU_BSY, ALU_COND, AR_IN_USE, BIW_0, BIW_1, BRANCH_ATN, DR_IN_USE, EW_ACK,
EW_RDY, EXEC_WB_STATE, EXH_REQ, EXT_WORD, FETCH_STATE, MOVEM_COND, MOVEM_PNTR, MOVEP_PNTR_I,
NEXT_EXEC_WB_STATE, OP, OP_SIZE_I, OP_WB_I, OPD_ACK, OW_RDY, PHASE2, RD_RDY, TRACE_EN, WR_RDY)
-- ADH: avoid data hazard.
-- ASH: avoid structural hazard.
-- ACH: avoid control hazard.
begin
case FETCH_STATE is
when START_OP =>
if OPD_ACK = '0' and OW_RDY = '0' then
NEXT_FETCH_STATE <= START_OP;
-- Debugging:
--elsif OP_TEST = '1' and ALU_BSY = '1' then
-- NEXT_FETCH_STATE <= START_OP;
else
case OP is
when ILLEGAL | RTE | TRAP | UNIMPLEMENTED =>
NEXT_FETCH_STATE <= START_OP;
when DBcc | EXT | MOVEQ | SWAP =>
if DR_IN_USE = '1' then
NEXT_FETCH_STATE <= START_OP; -- Wait, ADH.
else
NEXT_FETCH_STATE <= INIT_EXEC_WB; -- Proceed.
end if;
when ABCD | SBCD | ADDX | SUBX =>
if BIW_0(3) = '0' and DR_IN_USE = '0' then -- ADH.
NEXT_FETCH_STATE <= INIT_EXEC_WB; -- Register to register.
elsif BIW_0(3) = '1' and AR_IN_USE = '0' then -- Check for destination addressing register. ADH.
NEXT_FETCH_STATE <= CALC_AEFF; -- Memory to memory.
else
NEXT_FETCH_STATE <= START_OP; -- Wait, ADH.
end if;
when ADD | ADDI | ADDQ | AND_B | ANDI | CMP | CMPI | EOR | EORI |
NBCD | NEG | NEGX | NOT_B | OR_B | ORI | SUB | SUBI | SUBQ | TST | TAS =>
-- These instructions have to take the destination into aspect
-- because the destination is an ALU operand and may cause data hazards.
case BIW_0(5 downto 3) is
when "000" => -- Dn.
if DR_IN_USE = '0' then
NEXT_FETCH_STATE <= INIT_EXEC_WB;
else
NEXT_FETCH_STATE <= START_OP;
end if;
when "001" => -- An.
if (OP = ADD or OP = SUB or OP = AND_B or OP = EOR or OP = OR_B or OP = CMP) and (AR_IN_USE = '1' or DR_IN_USE = '1')then -- ADH.
NEXT_FETCH_STATE <= START_OP;
elsif AR_IN_USE = '0' then
NEXT_FETCH_STATE <= INIT_EXEC_WB;
else
NEXT_FETCH_STATE <= START_OP;
end if;
when "010" | "011" => -- (An), (An)+.
if AR_IN_USE = '1' then -- ADH.
NEXT_FETCH_STATE <= START_OP; -- Wait, ADH.
else
NEXT_FETCH_STATE <= FETCH_OPERAND;
end if;
when "100" => -- -(An).
if AR_IN_USE = '1' then -- ADH.
NEXT_FETCH_STATE <= START_OP; -- Wait, ADH.
else
NEXT_FETCH_STATE <= CALC_AEFF;
end if;
when "101" =>
NEXT_FETCH_STATE <= FETCH_DISPL;
when "110" =>
NEXT_FETCH_STATE <= FETCH_EXWORD_1;
when others => -- "111"
if BIW_0(2 downto 0) = "000" then
NEXT_FETCH_STATE <= FETCH_ABS_LO;
elsif BIW_0(2 downto 0) = "001" then
NEXT_FETCH_STATE <= FETCH_ABS_HI;
elsif BIW_0(2 downto 0) = "100" and OP_SIZE_I = LONG then
NEXT_FETCH_STATE <= FETCH_IDATA_B2;
elsif BIW_0(2 downto 0) = "100" then -- Word or byte.
NEXT_FETCH_STATE <= FETCH_IDATA_B1;
elsif BIW_0(2 downto 0) = "010" then
NEXT_FETCH_STATE <= FETCH_DISPL;
else
NEXT_FETCH_STATE <= FETCH_EXWORD_1;
end if;
end case;
when ADDA | BCHG | BCLR | BSET | BTST | CHK | CMPA |
DIVS | DIVU | MULS | MULU | MOVEA | MOVE_TO_CCR | MOVE_TO_SR | SUBA =>
case BIW_0(5 downto 3) is
when "000" => -- Source is Dn.
if (OP = ADDA or OP = SUBA or OP = CMPA or OP = MOVEA) and (AR_IN_USE = '1' or DR_IN_USE = '1') then -- ADH.
NEXT_FETCH_STATE <= START_OP;
elsif DR_IN_USE = '0' then
NEXT_FETCH_STATE <= INIT_EXEC_WB;
else
NEXT_FETCH_STATE <= START_OP;
end if;
when "001" => -- Valid for ADDA, CMPA, MOVEA, SUBA; source is An.
if AR_IN_USE = '0' then
NEXT_FETCH_STATE <= INIT_EXEC_WB; -- ADH.
else
NEXT_FETCH_STATE <= START_OP;
end if;
when "010" | "011" => -- (An), (An)+.
if AR_IN_USE = '1' then -- ADH.
NEXT_FETCH_STATE <= START_OP; -- Wait, ADH!
else
NEXT_FETCH_STATE <= FETCH_OPERAND;
end if;
when "100" => -- -(An).
if AR_IN_USE = '1' then -- ADH.
NEXT_FETCH_STATE <= START_OP; -- Wait, ADH!
else
NEXT_FETCH_STATE <= CALC_AEFF;
end if;
when "101" =>
NEXT_FETCH_STATE <= FETCH_DISPL;
when "110" =>
NEXT_FETCH_STATE <= FETCH_EXWORD_1;
when others => -- "111"
if BIW_0(2 downto 0) = "000" then
NEXT_FETCH_STATE <= FETCH_ABS_LO;
elsif BIW_0(2 downto 0) = "001" then
NEXT_FETCH_STATE <= FETCH_ABS_HI;
elsif BIW_0(2 downto 0) = "100" and OP_SIZE_I = LONG then
NEXT_FETCH_STATE <= FETCH_IDATA_B2;
elsif BIW_0(2 downto 0) = "100" then -- Word or Byte.
NEXT_FETCH_STATE <= FETCH_IDATA_B1;
elsif BIW_0(2 downto 0) = "010" then
NEXT_FETCH_STATE <= FETCH_DISPL;
else
NEXT_FETCH_STATE <= FETCH_EXWORD_1;
end if;
end case;
when EXG =>
if BIW_0(7 downto 3) = "10001" and (DR_IN_USE = '1' or AR_IN_USE = '1') then
NEXT_FETCH_STATE <= START_OP; -- Wait, ADH.
elsif BIW_0(7 downto 3) = "01000" and DR_IN_USE = '1' then
NEXT_FETCH_STATE <= START_OP; -- Wait, ADH.
elsif BIW_0(7 downto 3) = "01001" and AR_IN_USE = '1' then
NEXT_FETCH_STATE <= START_OP; -- Wait, ADH.
else
NEXT_FETCH_STATE <= INIT_EXEC_WB;
end if;
when NOP => -- Synchronize the instruction pipeline.
if ALU_BSY = '0' and EXEC_WB_STATE = IDLE then
NEXT_FETCH_STATE <= INIT_EXEC_WB;
else
NEXT_FETCH_STATE <= START_OP;
end if;
when MOVE_FROM_CCR | MOVE_FROM_SR =>
if ALU_BSY = '0' then
case BIW_0(5 downto 3) is
when "000" => -- Destination is Dn.
if DR_IN_USE = '0' then
NEXT_FETCH_STATE <= INIT_EXEC_WB;
else
NEXT_FETCH_STATE <= START_OP;
end if;
when "010" | "011" | "100" => -- (An), (An)+, -(An).
if AR_IN_USE = '0' then
NEXT_FETCH_STATE <= INIT_EXEC_WB;
else
NEXT_FETCH_STATE <= START_OP; -- Wait, ADH.
end if;
when "101" =>
NEXT_FETCH_STATE <= FETCH_DISPL;
when "110" =>
NEXT_FETCH_STATE <= FETCH_EXWORD_1;
when others => -- "111"
if BIW_0(2 downto 0) = "000" then
NEXT_FETCH_STATE <= FETCH_ABS_LO;
else
NEXT_FETCH_STATE <= FETCH_ABS_HI;
end if;
end case;
else
NEXT_FETCH_STATE <= START_OP;
end if;
when ASL | ASR | LSL | LSR | ROTL | ROTR | ROXL | ROXR =>
if BIW_0(7 downto 6) /= "11" then -- Register shifts.
if DR_IN_USE = '0' then
NEXT_FETCH_STATE <= INIT_EXEC_WB; -- ADH.
else
NEXT_FETCH_STATE <= START_OP;
end if;
else -- Memory shifts.
case BIW_0(5 downto 3) is
when "010" | "011" => -- (An), (An)+.
if AR_IN_USE = '0' then -- ADH.
NEXT_FETCH_STATE <= FETCH_OPERAND;
else
NEXT_FETCH_STATE <= START_OP;
end if;
when "100" => -- -(An).
if AR_IN_USE = '0' then -- ADH.
NEXT_FETCH_STATE <= CALC_AEFF;
else
NEXT_FETCH_STATE <= START_OP;
end if;
when "101" =>
NEXT_FETCH_STATE <= FETCH_DISPL;
when "110" =>
NEXT_FETCH_STATE <= FETCH_EXWORD_1;
when others => -- "111".
if BIW_0(2 downto 0) = "000" then
NEXT_FETCH_STATE <= FETCH_ABS_LO;
else
NEXT_FETCH_STATE <= FETCH_ABS_HI;
end if;
end case;
end if;
when BKPT =>
-- Wait until the bus controller is free to avoid a structural
-- hazard due to the top level function code multiplexer which
-- switches the CPU_SPACE selector.
if ALU_BSY = '0' then
NEXT_FETCH_STATE <= FETCH_OPERAND;
else
NEXT_FETCH_STATE <= START_OP;
end if;
when CMPM | RTD | RTR | RTS =>
if AR_IN_USE = '0' then -- ADH.
NEXT_FETCH_STATE <= FETCH_OPERAND;
else
NEXT_FETCH_STATE <= START_OP;
end if;
when CLR | JMP | JSR | LEA | PEA | Scc => -- No read access required.
case BIW_0(5 downto 3) is
when "000" => -- CLR, Scc.
if DR_IN_USE = '0' then
NEXT_FETCH_STATE <= INIT_EXEC_WB;
else
NEXT_FETCH_STATE <= START_OP;
end if;
when "001" | "010" | "011" | "100" =>
if AR_IN_USE = '1' then
NEXT_FETCH_STATE <= START_OP; -- Wait, ADH.
elsif OP = LEA or OP = PEA then
NEXT_FETCH_STATE <= SWITCH_STATE;
else
NEXT_FETCH_STATE <= INIT_EXEC_WB;
end if;
when "101" =>
NEXT_FETCH_STATE <= FETCH_DISPL;
when "110" =>
NEXT_FETCH_STATE <= FETCH_EXWORD_1;
when others => -- "111"
if BIW_0(2 downto 0) = "000" then
NEXT_FETCH_STATE <= FETCH_ABS_LO;
elsif BIW_0(2 downto 0) = "001" then
NEXT_FETCH_STATE <= FETCH_ABS_HI;
elsif BIW_0(2 downto 0) = "010" then
NEXT_FETCH_STATE <= FETCH_DISPL;
else
NEXT_FETCH_STATE <= FETCH_EXWORD_1;
end if;
end case;
--
-- The following condition is a special case for the
-- stack manipulating operations JSR and PEA. If A7
-- is in use, we have to wait in all addressing modes.
if (OP = JSR or OP = PEA) and AR_IN_USE = '1' then
NEXT_FETCH_STATE <= START_OP; -- Wait, ADH.
end if;
when LINK | UNLK =>
-- We have to wait for the ALU because the registers are written without pipelining
-- through the ALU and the stack is decremented early. For PEA we have to wait in
-- all addressing modes, if A7 is in use.
if OP = LINK and (ALU_BSY = '1' or AR_IN_USE = '1') then
NEXT_FETCH_STATE <= START_OP; -- Wait, ADH, ASH (two address registers are affected).
elsif OP = UNLK and ALU_BSY = '1' then
NEXT_FETCH_STATE <= START_OP; -- Wait, ADH, ASH (two address registers are affected).
else
NEXT_FETCH_STATE <= SWITCH_STATE; -- Stack pointer is decremented in this state.
end if;
when MOVE =>
case BIW_0(5 downto 3) is -- Source operand.
when "000" => -- Dn.
-- Destination is -(An) and will be decremented here, wait.
if BIW_0(8 downto 6) = "100" and (AR_IN_USE = '1' or DR_IN_USE = '1') then
NEXT_FETCH_STATE <= START_OP;
elsif DR_IN_USE = '1' then
NEXT_FETCH_STATE <= START_OP;
else
NEXT_FETCH_STATE <= INIT_EXEC_WB;
end if;
when "001" => -- An.
if AR_IN_USE = '1' then
NEXT_FETCH_STATE <= START_OP;
else
NEXT_FETCH_STATE <= INIT_EXEC_WB;
end if;
when "010" | "011" => -- (An), (An)+.
if AR_IN_USE = '0' then
NEXT_FETCH_STATE <= FETCH_OPERAND;
else
NEXT_FETCH_STATE <= START_OP;
end if;
when "100" => -- -(An).
if AR_IN_USE = '0' then
NEXT_FETCH_STATE <= CALC_AEFF;
else
NEXT_FETCH_STATE <= START_OP;
end if;
when "101" =>
NEXT_FETCH_STATE <= FETCH_DISPL;
when "110" =>
NEXT_FETCH_STATE <= FETCH_EXWORD_1;
when others =>
if BIW_0(2 downto 0) = "000" then
NEXT_FETCH_STATE <= FETCH_ABS_LO;
elsif BIW_0(2 downto 0) = "001" then
NEXT_FETCH_STATE <= FETCH_ABS_HI;
elsif BIW_0(2 downto 0) = "100" and BIW_0(13 downto 12) = "10" then -- Long.
NEXT_FETCH_STATE <= FETCH_IDATA_B2;
elsif BIW_0(2 downto 0) = "100" then -- Word or Byte.
NEXT_FETCH_STATE <= FETCH_IDATA_B1;
elsif BIW_0(2 downto 0) = "010" then
NEXT_FETCH_STATE <= FETCH_DISPL;
else
NEXT_FETCH_STATE <= FETCH_EXWORD_1;
end if;
end case;
when MOVEM =>
case BIW_0(5 downto 3) is
when "010" | "011" | "100" => -- (An), (An)+, -(An).
if AR_IN_USE = '1' then -- ADH.
NEXT_FETCH_STATE <= START_OP;
else
NEXT_FETCH_STATE <= INIT_EXEC_WB;
end if;
when "101" =>
NEXT_FETCH_STATE <= FETCH_DISPL;
when "110" =>
NEXT_FETCH_STATE <= FETCH_EXWORD_1;
when others =>
if BIW_0(2 downto 0) = "000" then
NEXT_FETCH_STATE <= FETCH_ABS_LO;
elsif BIW_0(2 downto 0) = "001" then
NEXT_FETCH_STATE <= FETCH_ABS_HI;
elsif BIW_0(2 downto 0) = "010" then
NEXT_FETCH_STATE <= FETCH_DISPL;
else
NEXT_FETCH_STATE <= FETCH_EXWORD_1;
end if;
end case;
when MOVEP =>
if AR_IN_USE = '0' and BIW_0(7 downto 6) < "10" then
NEXT_FETCH_STATE <= SWITCH_STATE; -- Memory to register.
elsif AR_IN_USE = '0' and DR_IN_USE = '0' then -- ADH.
NEXT_FETCH_STATE <= SWITCH_STATE; -- Register to memory.
else
NEXT_FETCH_STATE <= START_OP;
end if;
when BSR | MOVE_USP =>
-- MOVE_USP: wait until A7 has been updated to load the correct data to the ALU.
-- BSR: wait until A7 has been updated before decrementing.
if AR_IN_USE = '0' then -- ADH.
NEXT_FETCH_STATE <= INIT_EXEC_WB;
else
NEXT_FETCH_STATE <= START_OP;
end if;
when MOVEC =>
if BIW_0(0) = '1' and BIW_1(15) = '1' and AR_IN_USE = '1' then -- Address register is source.
NEXT_FETCH_STATE <= START_OP; -- Wait, ADH.
elsif BIW_0(0) = '1' and BIW_1(15) = '0' and DR_IN_USE = '1' then -- Data register is source.
NEXT_FETCH_STATE <= START_OP; -- Wait, ADH.
else
NEXT_FETCH_STATE <= INIT_EXEC_WB; -- AR, DR are destination.
end if;
when MOVES =>
case BIW_0(5 downto 3) is
when "010" | "011" => -- (An), (An)+.
if BIW_1(11) = '0' and AR_IN_USE = '0' then -- ADH.
NEXT_FETCH_STATE <= FETCH_OPERAND; -- Memory to register.
elsif BIW_1(11) = '1' and AR_IN_USE = '0' then -- ADH.
NEXT_FETCH_STATE <= INIT_EXEC_WB; -- Register to memory.
else
NEXT_FETCH_STATE <= START_OP; -- Wait, ADH.
end if;
when "100" => -- -(An).
if BIW_1(11) = '0' and AR_IN_USE = '0' then -- ADH.
NEXT_FETCH_STATE <= CALC_AEFF; -- Memory to register.
elsif BIW_1(11) = '1' and AR_IN_USE = '0' then -- ADH.
NEXT_FETCH_STATE <= INIT_EXEC_WB; -- Register to memory.
else
NEXT_FETCH_STATE <= START_OP; -- Wait, ADH.
end if;
when "101" =>
NEXT_FETCH_STATE <= FETCH_DISPL;
when "110" =>
NEXT_FETCH_STATE <= FETCH_EXWORD_1;
when others => -- "111"
if BIW_0(2 downto 0) = "000" then
NEXT_FETCH_STATE <= FETCH_ABS_LO;
else
NEXT_FETCH_STATE <= FETCH_ABS_HI;
end if;
end case;
-- Register to memory:
if BIW_1(11) = '1' and BIW_1(15) = '1' and AR_IN_USE = '1' then -- ADH.
NEXT_FETCH_STATE <= START_OP;
elsif BIW_1(11) = '1' and BIW_1(15) = '0' and DR_IN_USE = '1' then -- ADH.
NEXT_FETCH_STATE <= START_OP;
end if;
when ANDI_TO_CCR | ANDI_TO_SR | EORI_TO_CCR | EORI_TO_SR | ORI_TO_CCR | ORI_TO_SR | RESET =>
-- Wait until the status register / condition codes have been updated. Otherwise we
-- possibly have a data hazard using the wrong condition codes for the operation.
-- Be aware: for the ANDI_TO_SR, EORI_TO_SR, MOVE_TO_SR and ORI_TOI_SR operations
-- the pipe flush results in automatically aligned condition codes. Nevertheless
-- we need this logic for the respective operations, if the pipe is not flushed,
-- in the case of non changing RAM space.
-- For the RESET: we should not reset in running writeback cycles.
if ALU_BSY = '1' then
NEXT_FETCH_STATE <= START_OP;
else
NEXT_FETCH_STATE <= INIT_EXEC_WB;
end if;
when others => -- Bcc, BRA, STOP, TRAPV.
NEXT_FETCH_STATE <= INIT_EXEC_WB;
end case;
end if;
when FETCH_DISPL =>
case OP is
when ADD | CMP | SUB | AND_B | EOR | OR_B =>
if (EW_ACK = '1' or EW_RDY = '1') and AR_IN_USE = '0' then -- ADH.
NEXT_FETCH_STATE <= CALC_AEFF;
else
NEXT_FETCH_STATE <= FETCH_DISPL;
end if;
when ADDA | BCHG | BCLR | BSET | BTST | CHK | CMPA | DIVS | DIVU | MULS | MULU | MOVE | MOVEA | MOVE_TO_CCR | MOVE_TO_SR | SUBA =>
if (EW_ACK = '1' or EW_RDY = '1') and OP = MOVE and PHASE2 = true and AR_IN_USE = '0' then -- ADH.
NEXT_FETCH_STATE <= INIT_EXEC_WB;
elsif (EW_ACK = '1' or EW_RDY = '1') and AR_IN_USE = '0' then -- ADH.
NEXT_FETCH_STATE <= CALC_AEFF;
else
NEXT_FETCH_STATE <= FETCH_DISPL;
end if;
when ADDI | ADDQ | ANDI | CMPI | EORI | NBCD | NEG | NEGX | NOT_B | ORI | SUBI | SUBQ | TST | TAS | ASL | ASR | LSL | LSR | ROTL | ROTR | ROXL | ROXR =>
if (EW_ACK = '1' or EW_RDY = '1') and AR_IN_USE = '0' then -- ADH.
NEXT_FETCH_STATE <= CALC_AEFF;
else
NEXT_FETCH_STATE <= FETCH_DISPL;
end if;
when MOVES =>
if (EW_ACK = '1' or EW_RDY = '1') and AR_IN_USE = '0' and BIW_1(11) = '0' then
NEXT_FETCH_STATE <= CALC_AEFF;
elsif (EW_ACK = '1' or EW_RDY = '1') and AR_IN_USE = '0' then
NEXT_FETCH_STATE <= INIT_EXEC_WB;
else
NEXT_FETCH_STATE <= FETCH_DISPL;
end if;
when LEA | PEA =>
if (EW_ACK = '1' or EW_RDY = '1') and AR_IN_USE = '0' then -- ADH.
NEXT_FETCH_STATE <= SWITCH_STATE;
else
NEXT_FETCH_STATE <= FETCH_DISPL;
end if;
when others => -- CLR, JMP, JSR, MOVE_FROM_CCR, MOVE_FROM_SR, MOVEM, Scc.
if (EW_ACK = '1' or EW_RDY = '1') and AR_IN_USE = '0' then -- ADH.
NEXT_FETCH_STATE <= INIT_EXEC_WB;
else
NEXT_FETCH_STATE <= FETCH_DISPL;
end if;
end case;
when FETCH_EXWORD_1 =>
-- Be aware that the An registers which will be addressed by EXWORD_1 and are used for several addressing modes
-- are valid right after this state (because every address register manipulation requires no more than two clock cycles).
if EW_ACK = '1' or EW_RDY = '1' then -- Null displacement.
case OP is
when ADD | CMP | SUB | AND_B | EOR | OR_B =>
if (BIW_1(15) = '0' and AR_IN_USE = '0' and DR_IN_USE = '0') or (BIW_1(15) = '1' and AR_IN_USE = '0') then -- ADH.
NEXT_FETCH_STATE <= CALC_AEFF;
else
NEXT_FETCH_STATE <= FETCH_EXWORD_1;
end if;
when ADDA | BCHG | BCLR | BSET | BTST | CHK | CMPA | DIVS | DIVU | MULS | MULU | MOVE | MOVEA | MOVE_TO_CCR | MOVE_TO_SR | SUBA =>
if OP = MOVE and PHASE2 = true and BIW_1(15) = '0' and AR_IN_USE = '0' and DR_IN_USE = '0' then -- ADH.
NEXT_FETCH_STATE <= INIT_EXEC_WB;
elsif OP = MOVE and PHASE2 = true and BIW_1(15) = '1' and AR_IN_USE = '0' then -- ADH.
NEXT_FETCH_STATE <= INIT_EXEC_WB;
elsif (BIW_1(15) = '0' and AR_IN_USE = '0' and DR_IN_USE = '0') or (BIW_1(15) = '1' and AR_IN_USE = '0') then -- ADH.
NEXT_FETCH_STATE <= CALC_AEFF;
else
NEXT_FETCH_STATE <= FETCH_EXWORD_1;
end if;
when MOVES =>
if (BIW_1(15) = '0' and AR_IN_USE = '0' and DR_IN_USE = '0') or (BIW_1(15) = '1' and AR_IN_USE = '0') then -- ADH.
if BIW_1(11) = '0' then
NEXT_FETCH_STATE <= CALC_AEFF;
else
NEXT_FETCH_STATE <= INIT_EXEC_WB;
end if;
else
NEXT_FETCH_STATE <= FETCH_EXWORD_1;
end if;
when ADDI | ADDQ | ANDI | CMPI | EORI | NBCD | NEG | NEGX | NOT_B | ORI | SUBI | SUBQ | TST | TAS | ASL | ASR | LSL | LSR | ROTL | ROTR | ROXL | ROXR =>
if (BIW_1(15) = '0' and AR_IN_USE = '0' and DR_IN_USE = '0') or (BIW_1(15) = '1' and AR_IN_USE = '0') then -- ADH.
NEXT_FETCH_STATE <= CALC_AEFF;
else
NEXT_FETCH_STATE <= FETCH_EXWORD_1;
end if;
when LEA | PEA =>
if (BIW_1(15) = '0' and AR_IN_USE = '0' and DR_IN_USE = '0') or (BIW_1(15) = '1' and AR_IN_USE = '0') then -- ADH.
NEXT_FETCH_STATE <= SWITCH_STATE;
else
NEXT_FETCH_STATE <= FETCH_EXWORD_1;
end if;
when others => -- CLR, JMP, JSR, MOVE_FROM_CCR, MOVE_FROM_SR, MOVEM, Scc.
if (BIW_1(15) = '0' and AR_IN_USE = '0' and DR_IN_USE = '0') or (BIW_1(15) = '1' and AR_IN_USE = '0') then -- ADH.
NEXT_FETCH_STATE <= INIT_EXEC_WB;
else
NEXT_FETCH_STATE <= FETCH_EXWORD_1;
end if;
end case;
else
NEXT_FETCH_STATE <= FETCH_EXWORD_1;
end if;
when FETCH_ABS_HI =>
if EW_ACK = '1' then
NEXT_FETCH_STATE <= FETCH_ABS_LO;
else
NEXT_FETCH_STATE <= FETCH_ABS_HI;
end if;
when FETCH_ABS_LO =>
if EW_ACK = '1' then
case OP is
when CLR | JMP | JSR | MOVE_FROM_CCR | MOVE_FROM_SR | MOVEM | Scc =>
NEXT_FETCH_STATE <= INIT_EXEC_WB;
when LEA | PEA =>
NEXT_FETCH_STATE <= SWITCH_STATE;
when MOVE =>
if PHASE2 = false then
NEXT_FETCH_STATE <= CALC_AEFF;
else
NEXT_FETCH_STATE <= INIT_EXEC_WB;
end if;
when MOVES =>
if BIW_1(11) = '0' then
NEXT_FETCH_STATE <= CALC_AEFF;
else
NEXT_FETCH_STATE <= INIT_EXEC_WB;
end if;
when others =>
NEXT_FETCH_STATE <= CALC_AEFF;
end case;
else
NEXT_FETCH_STATE <= FETCH_ABS_LO;
end if;
when FETCH_IDATA_B2 =>
if EW_ACK = '1' then
NEXT_FETCH_STATE <= FETCH_IDATA_B1;
else
NEXT_FETCH_STATE <= FETCH_IDATA_B2;
end if;
when FETCH_IDATA_B1 =>
if EW_ACK = '1' or EW_RDY = '1' then
case OP is -- ADH.
when ADD | SUB | AND_B | OR_B | BTST | DIVS | DIVU | MULS | MULU | CHK | MOVE =>
NEXT_FETCH_STATE <= SWITCH_STATE;
when ADDA | CMPA | SUBA | MOVEA =>
NEXT_FETCH_STATE <= SWITCH_STATE;
when others =>
if DR_IN_USE = '1' then -- ADH.
NEXT_FETCH_STATE <= FETCH_IDATA_B1;
else
NEXT_FETCH_STATE <= INIT_EXEC_WB;
end if;
end case;
else
NEXT_FETCH_STATE <= FETCH_IDATA_B1;
end if;
when CALC_AEFF =>
NEXT_FETCH_STATE <= FETCH_OPERAND; -- One CLK calculation delay.
when FETCH_OPERAND =>
if RD_RDY = '1' then
case OP is
when ABCD | ADDX | SBCD | SUBX =>
if PHASE2 = false then
NEXT_FETCH_STATE <= CALC_AEFF;
else
NEXT_FETCH_STATE <= INIT_EXEC_WB;
end if;
when ADD | CMP | CHK | SUB | AND_B | EOR | OR_B | BCHG | BCLR | BSET | BTST | DIVS | DIVU | MULS | MULU =>
if DR_IN_USE = '1' then
NEXT_FETCH_STATE <= SWITCH_STATE;
else
NEXT_FETCH_STATE <= INIT_EXEC_WB;
end if;
when ADDA | CMPA | SUBA =>
if BIW_0(11 downto 9) = BIW_0(2 downto 0) and ADR_MODE_I = "011" then
NEXT_FETCH_STATE <= SWITCH_STATE; -- Postincrement (Ax)+, AX; wait before loading the ALU.
else
NEXT_FETCH_STATE <= INIT_EXEC_WB;
end if;
when MOVE =>
if BIW_0(8 downto 6) = "100" and ADR_MODE_I = "011" then -- (An)+,-(An).
NEXT_FETCH_STATE <= SWITCH_STATE;
else
NEXT_FETCH_STATE <= INIT_EXEC_WB;
end if;
when others =>
NEXT_FETCH_STATE <= INIT_EXEC_WB;
end case;
else
NEXT_FETCH_STATE <= FETCH_OPERAND;
end if;
when SWITCH_STATE => -- This state is used individually by several operations.
case OP is
when ADDA | CMPA | SUBA | MOVEA => -- Address register operations.
if AR_IN_USE = '0' then
NEXT_FETCH_STATE <= INIT_EXEC_WB;
else
NEXT_FETCH_STATE <= SWITCH_STATE;
end if;
when LEA | LINK | MOVE =>
-- LEA: calculate effective address (1 clock cycle) load it in INIT_EXEC_WB.
-- LINK: used to load the decremented stack pointer.
-- MOVE: Used for (An)+,-(An). address mode.
NEXT_FETCH_STATE <= INIT_EXEC_WB;
when UNLK => -- SP is updated here.
NEXT_FETCH_STATE <= CALC_AEFF;
when MOVEM => -- MOVEM requires 1 CLK cycle for address calculation.
if MOVEM_COND = false then
NEXT_FETCH_STATE <= INIT_EXEC_WB; -- Cancel bus access.
else
NEXT_FETCH_STATE <= CALC_AEFF;
end if;
when MOVEP => -- Register select and displacement update.
if DR_IN_USE = '0' and BIW_0(7 downto 6) < "10" then
NEXT_FETCH_STATE <= CALC_AEFF;
elsif DR_IN_USE = '0' and ALU_BSY = '0' then -- ASH.
NEXT_FETCH_STATE <= INIT_EXEC_WB; -- Register to memory.
else
NEXT_FETCH_STATE <= SWITCH_STATE;
end if;
when PEA =>
-- PEA requires two clock cycles here for effective adress calculation because it
-- is loaded early. The first clock cycle the address becomes valid and after the
-- second the address is loaded to the ALU for writing on the stack.
if PHASE2 = false then
NEXT_FETCH_STATE <= SWITCH_STATE;
else
NEXT_FETCH_STATE <= INIT_EXEC_WB;
end if;
when others => -- Data register operations.
if DR_IN_USE = '0' then
NEXT_FETCH_STATE <= INIT_EXEC_WB;
else
NEXT_FETCH_STATE <= SWITCH_STATE;
end if;
end case;
when INIT_EXEC_WB =>
case OP is
when ANDI_TO_SR | EORI_TO_SR | MOVE_TO_SR | ORI_TO_SR =>
if ALU_BSY = '0' and BRANCH_ATN = '1' then
NEXT_FETCH_STATE <= SLEEP; -- Wait for new processor context.
elsif ALU_BSY = '0' then
NEXT_FETCH_STATE <= START_OP; -- Proceed normally.
else
NEXT_FETCH_STATE <= INIT_EXEC_WB;
end if;
when Bcc | CHK | DBcc | JMP | TRAPV =>
if ALU_BSY = '0' then
NEXT_FETCH_STATE <= SLEEP;
else
NEXT_FETCH_STATE <= INIT_EXEC_WB;
end if;
when JSR | MOVEC | TAS =>
-- TAS provides a RMC operation so have to sleep a little bit ;-)
if ALU_BSY = '0' then
NEXT_FETCH_STATE <= SLEEP;
else
NEXT_FETCH_STATE <= INIT_EXEC_WB;
end if;
when BRA | BSR | RTD | RTS =>
if ALU_BSY = '0' then
NEXT_FETCH_STATE <= START_OP;
else
NEXT_FETCH_STATE <= INIT_EXEC_WB;
end if;
when CMPM =>
if ALU_BSY = '0' and PHASE2 = false then
NEXT_FETCH_STATE <= FETCH_OPERAND; -- Second compare required?
elsif ALU_BSY = '0' then -- ASH.
NEXT_FETCH_STATE <= START_OP;
else
NEXT_FETCH_STATE <= INIT_EXEC_WB;
end if;
when MOVE_USP =>
if ALU_BSY = '0' and BIW_0(3) = '0' then -- An to USP.
NEXT_FETCH_STATE <= SLEEP;
elsif ALU_BSY = '0' then
NEXT_FETCH_STATE <= START_OP; -- USP to An.
else
NEXT_FETCH_STATE <= INIT_EXEC_WB;
end if;
when MOVE =>
if ALU_BSY = '0' and PHASE2 = false then -- Load the Operand into the ALU here.
case BIW_0(8 downto 6) is -- Destination operand.
when "101" =>
NEXT_FETCH_STATE <= FETCH_DISPL;
when "110" =>
NEXT_FETCH_STATE <= FETCH_EXWORD_1;
when "111" =>
if BIW_0(11 downto 9) = "000" then
NEXT_FETCH_STATE <= FETCH_ABS_LO;
else
NEXT_FETCH_STATE <= FETCH_ABS_HI;
end if;
when others => -- No destination address calculation required.
NEXT_FETCH_STATE <= START_OP;
end case;
elsif PHASE2 = true then -- ALU is not required at this point.
NEXT_FETCH_STATE <= START_OP;
else
NEXT_FETCH_STATE <= INIT_EXEC_WB;
end if;
when MOVEM =>
if ALU_BSY = '0' and BIW_0(10) = '0' and ADR_MODE_I = "100" and MOVEM_PNTR = x"0" then -- -(An), register to memory.
NEXT_FETCH_STATE <= SLEEP; -- Data completely transfered to the ALU.
elsif ALU_BSY = '0' and BIW_0(10) = '0' and ADR_MODE_I /= "100" and MOVEM_PNTR = x"F" then -- Register to memory
NEXT_FETCH_STATE <= SLEEP; -- Data completely transfered to the ALU.
elsif ALU_BSY = '0' and BIW_0(10) = '1' and MOVEM_PNTR = x"F" then -- Memory to register.
NEXT_FETCH_STATE <= SLEEP; -- Data completely transfered to the ALU.
elsif ALU_BSY = '0' and BIW_0(10) = '1' then -- Memory to register.
NEXT_FETCH_STATE <= SWITCH_STATE;
else
NEXT_FETCH_STATE <= INIT_EXEC_WB; -- Register to memory.
end if;
when MOVEP =>
if ALU_BSY = '0' and MOVEP_PNTR_I = 0 then
NEXT_FETCH_STATE <= START_OP; -- Ready.
elsif ALU_BSY = '0' and BIW_0(7 downto 6) < "10" then
NEXT_FETCH_STATE <= CALC_AEFF; -- Memory to register.
else
NEXT_FETCH_STATE <= INIT_EXEC_WB; -- Register to memory.
end if;
when NOP =>
if ALU_BSY = '1' then -- ASH.
NEXT_FETCH_STATE <= INIT_EXEC_WB; -- Wait for all pending bus cycles to be completed.
else
NEXT_FETCH_STATE <= START_OP;
end if;
when RTR =>
if ALU_BSY = '0' and PHASE2 = false then
NEXT_FETCH_STATE <= CALC_AEFF;
elsif ALU_BSY = '0' and PHASE2 = true then
NEXT_FETCH_STATE <= START_OP;
else
NEXT_FETCH_STATE <= INIT_EXEC_WB;
end if;
when STOP =>
if ALU_BSY = '0' then -- ASH.
NEXT_FETCH_STATE <= SLEEP;
else
NEXT_FETCH_STATE <= INIT_EXEC_WB;
end if;
when UNLK =>
if ALU_BSY = '0' and AR_IN_USE = '0' then -- ADH, ASH.
NEXT_FETCH_STATE <= START_OP;
else
NEXT_FETCH_STATE <= INIT_EXEC_WB;
end if;
when others =>
if ALU_BSY = '0' then -- ASH.
NEXT_FETCH_STATE <= START_OP;
else
NEXT_FETCH_STATE <= INIT_EXEC_WB; -- ASH.
end if;
end case;
when SLEEP =>
case OP is
when ANDI_TO_SR | EORI_TO_SR | MOVE_TO_SR | MOVEM | ORI_TO_SR | TAS =>
-- MOVEM: wait until last register is written to avoid data hazards
-- because the ADR_IN_USE, AR_IN__USE and DR_IN_USE does not
-- work for MOVEM (several registers in use).
-- TAS is a read modify write instruction.
-- _TO_SR instructions wait for the change of the SBIT
-- and so for a new processor context.
if NEXT_EXEC_WB_STATE = IDLE then
NEXT_FETCH_STATE <= START_OP;
else
NEXT_FETCH_STATE <= SLEEP;
end if;
when JSR =>
if PHASE2 = false then
NEXT_FETCH_STATE <= SLEEP; -- Wait for address calculation.
else
NEXT_FETCH_STATE <= START_OP;
end if;
when MOVE_USP | MOVEC =>
-- MOVE_USP: wait for writeback not to conflict with AR_DEC in START_OP.
if NEXT_EXEC_WB_STATE = IDLE then
NEXT_FETCH_STATE <= START_OP;
else
NEXT_FETCH_STATE <= SLEEP; -- Wait for new processor context.
end if;
when DBcc =>
-- DBcc: evaluate conditions.
if NEXT_EXEC_WB_STATE = IDLE then
NEXT_FETCH_STATE <= START_OP;
else
NEXT_FETCH_STATE <= SLEEP;
end if;
when STOP =>
if TRACE_EN = '1' then
NEXT_FETCH_STATE <= START_OP; -- Do not perform a stop while tracing.
elsif EXH_REQ = '1' then
NEXT_FETCH_STATE <= START_OP; -- Wait on interrupt.
else
NEXT_FETCH_STATE <= SLEEP;
end if;
when others => -- Bcc, CHK, JMP, TRAPV.
-- Bcc: evaluate conditions.
-- CHK: use SWITCH_STATE for TRAP evaluation.
-- JMP: wait for address calculation.
-- TRAPV: check conditions.
NEXT_FETCH_STATE <= START_OP;
end case;
end case;
end process FETCH_DEC;
EXEC_WB_DEC: process(ALU_COND, ALU_INIT_I, ALU_REQ, BIW_0_WB, BIW_1_WB, EXEC_WB_STATE, MOVEM_INH_WR, OP_WB_I, PHASE2, WR_RDY)
begin
case EXEC_WB_STATE is
when IDLE => -- OP is still valid here; OP_WB_I one clock later.
if ALU_INIT_I = '1' then
NEXT_EXEC_WB_STATE <= EXECUTE;
else
NEXT_EXEC_WB_STATE <= IDLE;
end if;
when EXECUTE =>
if ALU_REQ = '1' then
case OP_WB_I is
when ABCD | SBCD | ADDX | SUBX =>
if BIW_0_WB(3) = '0' then -- Register to register.
NEXT_EXEC_WB_STATE <= WRITEBACK;
else -- Memory to memory.
NEXT_EXEC_WB_STATE <= WRITE_DEST;
end if;
when ADD | SUB | AND_B | OR_B =>
if BIW_0_WB(8) = '0' then
NEXT_EXEC_WB_STATE <= WRITEBACK; -- Destination is register.
else
NEXT_EXEC_WB_STATE <= WRITE_DEST; -- Destination is in memory.
end if;
when ADDA | SUBA | ANDI_TO_SR | DIVS | DIVU | EORI_TO_SR | EXG | EXT | LEA | MOVE_TO_CCR |
MOVE_TO_SR | MOVE_USP | MOVEA | MOVEC | MOVEQ | MULS | MULU | ORI_TO_SR | STOP | SWAP | UNLK =>
NEXT_EXEC_WB_STATE <= WRITEBACK;
when ADDI | ADDQ | ANDI | BCHG | BCLR | BSET | CLR | EOR | EORI |
MOVE_FROM_CCR | MOVE_FROM_SR | NBCD | NEG | NEGX | NOT_B | ORI | Scc | SUBI | SUBQ | TAS =>
if BIW_0_WB(5 downto 3) = "000" then
NEXT_EXEC_WB_STATE <= WRITEBACK; -- Destination is a data register.
elsif BIW_0_WB(5 downto 3) = "001" then -- Valid for ADDQ and SUBQ.
NEXT_EXEC_WB_STATE <= WRITEBACK; -- Destination is an address register.
else
NEXT_EXEC_WB_STATE <= WRITE_DEST; -- Destination is in memory.
end if;
when ASL | ASR | LSL | LSR | ROTL | ROTR | ROXL | ROXR =>
if BIW_0_WB(7 downto 6) /= "11" then
NEXT_EXEC_WB_STATE <= WRITEBACK; -- Register shifts.
else
NEXT_EXEC_WB_STATE <= WRITE_DEST; -- Memory shifts.
end if;
when DBcc =>
if ALU_COND = true then
NEXT_EXEC_WB_STATE <= IDLE;
else
NEXT_EXEC_WB_STATE <= WRITEBACK;
end if;
when MOVE =>
if BIW_0_WB(8 downto 6) = "000" then
NEXT_EXEC_WB_STATE <= WRITEBACK; -- Destination is register.
elsif PHASE2 = false then
NEXT_EXEC_WB_STATE <= WRITE_DEST; -- Destination is in memory.
else
NEXT_EXEC_WB_STATE <= EXECUTE; -- Wait for PHASE2 address calculation.
end if;
when BSR | JSR | LINK | PEA =>
NEXT_EXEC_WB_STATE <= WRITE_DEST;
when MOVEM =>
if OP_WB_I = MOVEM and MOVEM_INH_WR = true then
NEXT_EXEC_WB_STATE <= IDLE; -- Discard the write cycle.
elsif BIW_0_WB(10) = '1' then
NEXT_EXEC_WB_STATE <= WRITEBACK; -- Destination is register.
else
NEXT_EXEC_WB_STATE <= WRITE_DEST; -- Destination is in memory.
end if;
when MOVEP =>
if BIW_0_WB(7 downto 6) < "10" then
NEXT_EXEC_WB_STATE <= WRITEBACK; -- Memory to register.
else
NEXT_EXEC_WB_STATE <= WRITE_DEST; -- Register to memory.
end if;
when MOVES =>
if BIW_1_WB(11) = '0' then
NEXT_EXEC_WB_STATE <= WRITEBACK; -- Destination is register.
else
NEXT_EXEC_WB_STATE <= WRITE_DEST; -- Destination is in memory.
end if;
-- Default is for:
-- ANDI_TO_CCR, Bcc, CHK, CMP, CMPA, CMPI, CMPM
-- EORI_TO_CCR, ORI_TO_CCR, RTR, TRAPV, TST.
when others =>
NEXT_EXEC_WB_STATE <= IDLE;
end case;
else
NEXT_EXEC_WB_STATE <= EXECUTE;
end if;
when WRITEBACK =>
NEXT_EXEC_WB_STATE <= IDLE;
when WRITE_DEST =>
if WR_RDY = '1' then
NEXT_EXEC_WB_STATE <= IDLE;
else
NEXT_EXEC_WB_STATE <= WRITE_DEST;
end if;
end case;
end process EXEC_WB_DEC;
end BEHAVIOUR;