1
0
mirror of https://github.com/Gehstock/Mist_FPGA.git synced 2026-01-21 10:02:30 +00:00
Gehstock.Mist_FPGA/common/CPU/68K10/wf68k10_opcode_decoder.vhd
2020-09-06 18:16:38 +02:00

1229 lines
66 KiB
VHDL

------------------------------------------------------------------------
---- ----
---- WF68K10 IP Core: this is the bus controller module. ----
---- ----
---- Description: ----
---- This module is a 68010 compatible instruction word decoder. ----
---- It is primarily controlled by the following signals: ----
---- OW_REQ, OPD_ACK, EW_REQ and EW_ACK. The handshaking is as ----
---- follows: if a new instruction is required, assert the signal ----
---- OW_REQ and wait until ACK is asserted by the decoder logic. ----
---- Deassert OW_REQ right after ACK (in the same clock cycle). ----
---- At this point, the required instruction has already been copied----
---- from the pipe to the register BIW_0. The respective additional ----
---- instruction words are located in BIW_1, BIW_2. For more infor- ----
---- mation see the 68010 "Programmers Reference Manual" and the ----
---- signal INSTR_LVL in this module. ----
---- The extension request works in the same manner by asserting ----
---- EW_REQ. At the time of EXT_ACK one extension word has been ----
---- copied to EXT_WORD. ----
---- Be aware that it is in the scope of the logic driving ----
---- OW_REQ and EW_REQ to hold the instruction pipe aligned. ----
---- This means in detail, that the correct number or instruction ----
---- and extension words must be requested. Otherwise unpredictable ----
---- processor behaviour will occur. Furthermore OW_REQ and EW_REQ ----
---- must not be asserted the same time. ----
---- This operation code decoder with the handshake logic as des- ----
---- cribed above is the first pipeline stage of the CPU architec- ----
---- ture. ----
---- ----
---- ----
---- 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 20161224 WF
-- Break the DBcc_LOOP when the exception handler is busy (see process P_LOOP).
-- Revision 2K18A 20180620 WF
-- Several minor improvements to meet better 68000 compatibility.
-- Removed illegal MOVEC control register patterns.
-- Removed REST_BIW_0.
-- Fixed the PW_EW_OFFSET calculation for JSR.
-- Rewritten DBcc loop.
-- Fix for unimplemented or illegal operations: PC is increased before stacked.
-- Removed CAHR, we have no cache.
-- Rearranged address error handling.
-- Revision 2K19B 20191224 WF
-- Introduced signal synchronization in the P_BSY process to avoid malfunction by hazards.
--
library work;
use work.WF68K10_PKG.all;
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;
entity WF68K10_OPCODE_DECODER is
generic(NO_LOOP : boolean); -- If true the DBcc loop mechanism is disabled.
port (
CLK : in std_logic;
K6800n : in std_logic; -- '0' for MC68000 compatibility.
OW_REQ_MAIN : in bit; -- Request from the execution unit.
EW_REQ_MAIN : in bit; -- Extension words request.
EXH_REQ : in bit; -- Exception request.
BUSY_EXH : in bit; -- Exception handler is busy.
BUSY_MAIN : in bit; -- Main controller busy.
BUSY_OPD : out bit; -- This unit is busy.
BKPT_INSERT : in bit;
BKPT_DATA : in std_logic_vector(15 downto 0);
LOOP_EXIT : in bit;
LOOP_BSY : out bit;
OPD_ACK_MAIN : out bit; -- Operation controller acknowledge.
EW_ACK : buffer bit; -- Extension word available.
PC_INC : out bit;
PC_INC_EXH : in bit;
PC_ADR_OFFSET : out std_logic_vector(7 downto 0);
PC_EW_OFFSET : buffer std_logic_vector(3 downto 0);
PC_OFFSET : out std_logic_vector(7 downto 0);
OPCODE_RD : out bit;
OPCODE_RDY : in bit;
OPCODE_VALID : in std_logic;
OPCODE_DATA : in std_logic_vector(15 downto 0);
IPIPE_FILL : in bit;
IPIPE_FLUSH : in bit; -- Abandon the instruction pipe.
-- Fault logic:
OW_VALID : out std_logic; -- Operation words valid.
-- Trap logic:
SBIT : in std_logic;
TRAP_CODE : out TRAPTYPE_OPC;
-- System control signals:
OP : buffer OP_68K;
BIW_0 : buffer std_logic_vector(15 downto 0);
BIW_1 : out std_logic_vector(15 downto 0);
BIW_2 : out std_logic_vector(15 downto 0);
EXT_WORD : out std_logic_vector(15 downto 0)
);
end entity WF68K10_OPCODE_DECODER;
architecture BEHAVIOR of WF68K10_OPCODE_DECODER is
type INSTR_LVL_TYPE is(D, C, B);
type IPIPE_TYPE is
record
D : std_logic_vector(15 downto 0);
C : std_logic_vector(15 downto 0);
B : std_logic_vector(15 downto 0);
end record;
signal REQ : bit;
signal EW_REQ : bit;
signal IPIPE : IPIPE_TYPE;
signal FIFO_RD : bit;
signal IPIPE_B_FAULT : std_logic;
signal IPIPE_C_FAULT : std_logic;
signal IPIPE_D_FAULT : std_logic;
signal IPIPE_PNTR : natural range 0 to 3;
signal INSTR_LVL : INSTR_LVL_TYPE;
signal LOOP_ATN : boolean;
signal LOOP_BSY_I : boolean;
signal LOOP_OP : boolean;
signal BKPT_REQ : bit;
signal OP_I : OP_68K;
signal OPCODE_FLUSH : bit;
signal OPCODE_RD_I : bit;
signal OPCODE_RDY_I : bit;
signal OW_REQ : bit;
signal TRAP_CODE_I : TRAPTYPE_OPC;
signal FLUSHED : boolean;
signal PC_INC_I : bit;
signal PIPE_RDY : bit;
begin
P_BSY: process(CLK)
-- This logic requires asynchronous reset. This flip flop is intended
-- to break combinatorial loops. If an opcode cycle in the bus controller
-- unit is currently running, the actual PC address is stored during this
-- cycle. Therefore it is not possible to flush the pipe and manipulate
-- the PC during a running cycle. For the exception handler reading the
-- opcode is inhibited during a pipe flush. For the main controller unit
-- the pipe is flushed after a running opcode cycle.
-- Important note: to avoid asynchronous reset by data hazards the
-- resetting signals are synchronized on the negative clock edge.
variable OPCODE_RDY_VAR : bit;
variable BUSY_EXH_VAR : bit;
variable IPIPE_FILL_VAR : bit;
begin
if CLK = '0' and CLK' event then
OPCODE_RDY_VAR := OPCODE_RDY;
BUSY_EXH_VAR := BUSY_EXH;
IPIPE_FILL_VAR := IPIPE_FILL;
end if;
--
if OPCODE_RDY_VAR = '1' then
OPCODE_RD_I <= '0';
elsif BUSY_EXH_VAR = '1' and IPIPE_FILL_VAR = '0' then
OPCODE_RD_I <= '0';
elsif CLK = '1' and CLK' event then
if IPIPE_FLUSH = '1' then
OPCODE_RD_I <= '1';
elsif (LOOP_ATN = true and OPCODE_RD_I = '0') or LOOP_BSY_I = true then
OPCODE_RD_I <= '0';
elsif IPIPE_PNTR < 3 then
OPCODE_RD_I <= '1';
end if;
end if;
end process P_BSY;
P_OPCODE_FLUSH: process
-- If there is a pending opcode cycle during a pipe flush,
-- an opcode mismatch will destroy scalar opcode processing.
-- To avoid this, we have to dismiss the upcoming opcode.
begin
wait until CLK = '1' and CLK' event;
if IPIPE_FLUSH = '1' and OPCODE_RD_I = '1' and OPCODE_RDY = '0' then
OPCODE_FLUSH <= '1';
elsif OPCODE_RDY = '1' or BUSY_EXH = '1' then
OPCODE_FLUSH <= '0';
end if;
end process P_OPCODE_FLUSH;
OPCODE_RD <= OPCODE_RD_I;
OPCODE_RDY_I <= '0' when OPCODE_FLUSH = '1' else OPCODE_RDY; -- Dismiss the current read cycle.
BUSY_OPD <= '0' when EXH_REQ = '1' and BUSY_MAIN = '0' and IPIPE_PNTR > 0 and OPCODE_RD_I = '0' else -- Fill one opcode is sufficient here.
'1' when IPIPE_PNTR < 3 or OPCODE_RD_I = '1' else '0';
INSTRUCTION_PIPE: process
-- These are the instruction pipe FIFO registers. The opcodes are stored in IPIPE.B, IPIPE.C
-- and IPIPE.D which is copied to the instruction register or to the respective extension when
-- read. Be aware, that the pipe is always completely refilled to determine the correct INSTR_LVL
-- before it is copied to the execution unit.
variable IPIPE_D_VAR : std_logic_vector(15 downto 0);
begin
wait until CLK = '1' and CLK' event;
if IPIPE_FLUSH = '1' then
IPIPE.D <= (others => '0');
IPIPE.C <= (others => '0');
IPIPE.B <= (others => '0');
IPIPE_PNTR <= 0;
elsif BKPT_INSERT = '1' then
IPIPE_D_VAR := IPIPE.D;
IPIPE.D <= BKPT_DATA; -- Insert the breakpoint data.
BKPT_REQ <= '1';
elsif OW_REQ = '1' and BKPT_REQ = '1' then
IPIPE.D <= IPIPE_D_VAR; -- Restore from breakpoint.
BKPT_REQ <= '0';
elsif LOOP_ATN = true and OPCODE_RD_I = '1' then
null; -- Wait for pending opcodes.
elsif OW_REQ = '1' and PIPE_RDY = '1' and OP_I = DBcc and LOOP_OP = true and IPIPE.C = x"FFFC" then -- Initialize the loop.
IPIPE.D <= BIW_0; -- This is the LEVEL D operation for the loop.
elsif OW_REQ = '1' and LOOP_BSY_I = true then
IPIPE.D <= BIW_0; -- Recycle the loop operations.
elsif LOOP_BSY_I = true then
null; -- Do not change the pipe during the loop.
elsif OW_REQ = '1' and INSTR_LVL = D and PIPE_RDY = '1' and IPIPE_PNTR = 2 then
if OPCODE_RDY_I = '1' then
IPIPE.D <= IPIPE.C;
IPIPE.C <= OPCODE_DATA;
IPIPE_D_FAULT <= IPIPE_C_FAULT;
IPIPE_C_FAULT <= not OPCODE_VALID;
else
IPIPE.D <= IPIPE.C;
IPIPE_D_FAULT <= IPIPE_C_FAULT;
IPIPE_PNTR <= IPIPE_PNTR - 1;
end if;
elsif OW_REQ = '1' and INSTR_LVL = D and PIPE_RDY = '1' and IPIPE_PNTR = 3 then
if OPCODE_RDY_I = '1' then
IPIPE.D <= IPIPE.C;
IPIPE.C <= IPIPE.B;
IPIPE.B <= OPCODE_DATA;
IPIPE_D_FAULT <= IPIPE_C_FAULT;
IPIPE_C_FAULT <= IPIPE_B_FAULT;
IPIPE_B_FAULT <= not OPCODE_VALID;
else
IPIPE.D <= IPIPE.C;
IPIPE.C <= IPIPE.B;
IPIPE_D_FAULT <= IPIPE_C_FAULT;
IPIPE_C_FAULT <= IPIPE_B_FAULT;
IPIPE_PNTR <= IPIPE_PNTR - 1;
end if;
elsif OW_REQ = '1' and INSTR_LVL = C and PIPE_RDY = '1' and IPIPE_PNTR = 2 then
if OPCODE_RDY_I = '1' then
IPIPE.D <= OPCODE_DATA;
IPIPE_D_FAULT <= not OPCODE_VALID;
IPIPE_PNTR <= IPIPE_PNTR - 1;
else
IPIPE_PNTR <= 0;
end if;
elsif OW_REQ = '1' and INSTR_LVL = C and PIPE_RDY = '1' and IPIPE_PNTR = 3 then
if OPCODE_RDY_I = '1' then
IPIPE.D <= IPIPE.B;
IPIPE.C <= OPCODE_DATA;
IPIPE_D_FAULT <= IPIPE_B_FAULT;
IPIPE_C_FAULT <= not OPCODE_VALID;
IPIPE_PNTR <= IPIPE_PNTR - 1;
else
IPIPE.D <= IPIPE.B;
IPIPE_D_FAULT <= IPIPE_B_FAULT;
IPIPE_PNTR <= IPIPE_PNTR - 2;
end if;
elsif OW_REQ = '1' and INSTR_LVL = B and PIPE_RDY = '1' then -- IPIPE_PNTR = 3.
if OPCODE_RDY_I = '1' then
IPIPE.D <= OPCODE_DATA;
IPIPE_D_FAULT <= not OPCODE_VALID;
IPIPE_PNTR <= IPIPE_PNTR - 2;
else
IPIPE_PNTR <= 0;
end if;
elsif EW_REQ = '1' and IPIPE_PNTR >= 1 then
case IPIPE_PNTR is
when 3 =>
if OPCODE_RDY_I = '1' then
IPIPE.D <= IPIPE.C;
IPIPE.C <= IPIPE.B;
IPIPE.B <= OPCODE_DATA;
IPIPE_D_FAULT <= IPIPE_C_FAULT;
IPIPE_C_FAULT <= IPIPE_B_FAULT;
IPIPE_B_FAULT <= not OPCODE_VALID;
else
IPIPE.D <= IPIPE.C;
IPIPE.C <= IPIPE.B;
IPIPE_D_FAULT <= IPIPE_C_FAULT;
IPIPE_C_FAULT <= IPIPE_B_FAULT;
IPIPE_PNTR <= IPIPE_PNTR - 1;
end if;
when 2 =>
if OPCODE_RDY_I = '1' then
IPIPE.D <= IPIPE.C;
IPIPE.C <= OPCODE_DATA;
IPIPE_D_FAULT <= IPIPE_C_FAULT;
IPIPE_C_FAULT <= not OPCODE_VALID;
else
IPIPE.D <= IPIPE.C;
IPIPE_D_FAULT <= IPIPE_C_FAULT;
IPIPE_PNTR <= IPIPE_PNTR - 1;
end if;
when 1 =>
if OPCODE_RDY_I = '1' then
IPIPE.D <= OPCODE_DATA;
IPIPE_D_FAULT <= not OPCODE_VALID;
else
IPIPE_PNTR <= 0;
end if;
when others => null;
end case;
elsif OPCODE_RDY_I = '1' then
case IPIPE_PNTR is
when 2 =>
IPIPE.B <= OPCODE_DATA;
IPIPE_B_FAULT <= not OPCODE_VALID;
IPIPE_PNTR <= 3;
when 1 =>
IPIPE.C <= OPCODE_DATA;
IPIPE_C_FAULT <= not OPCODE_VALID;
IPIPE_PNTR <= 2;
when 0 =>
IPIPE.D <= OPCODE_DATA;
IPIPE_D_FAULT <= not OPCODE_VALID;
IPIPE_PNTR <= 1;
when others => null;
end case;
end if;
end process INSTRUCTION_PIPE;
P_FAULT: process
-- This are the fault flags for pipe B and C.
-- These flags are set, when an instruction
-- request uses either of the respective pipes.
begin
wait until CLK = '1' and CLK' event;
if IPIPE_FLUSH = '1' then
OW_VALID <= '0';
elsif OW_REQ = '1' and LOOP_BSY_I = true then
OW_VALID <= '1';
elsif OW_REQ = '1' and PIPE_RDY = '1' and INSTR_LVL = D then
OW_VALID <= not IPIPE_D_FAULT;
elsif OW_REQ = '1' and PIPE_RDY = '1' and INSTR_LVL = C then
OW_VALID <= not(IPIPE_D_FAULT or IPIPE_C_FAULT);
elsif OW_REQ = '1' and PIPE_RDY = '1' and INSTR_LVL = B then
OW_VALID <= not (IPIPE_D_FAULT or IPIPE_C_FAULT or IPIPE_B_FAULT);
elsif EW_REQ = '1' and PIPE_RDY = '1' then
OW_VALID <= not IPIPE_D_FAULT;
end if;
end process P_FAULT;
OUTBUFFERS: process
variable OP_STOP : boolean;
begin
wait until CLK = '1' and CLK' event;
if OP_STOP = true and IPIPE_FLUSH = '1' then
TRAP_CODE <= NONE;
OP_STOP := false;
elsif IPIPE_FLUSH = '1' then
TRAP_CODE <= NONE;
elsif OP_STOP = true then
null; -- Do not update after PC is incremented.
elsif LOOP_ATN = true and OPCODE_RD_I = '1' then
null; -- Wait for pending opcodes.
elsif OW_REQ = '1' and LOOP_BSY_I = true then
OP <= OP_I;
BIW_0 <= IPIPE.D;
TRAP_CODE <= TRAP_CODE_I;
elsif OW_REQ = '1' and (PIPE_RDY = '1' or BKPT_REQ = '1') then
-- Be aware: all BIW are written unaffected
-- if they are all used.
OP <= OP_I;
BIW_0 <= IPIPE.D;
BIW_1 <= IPIPE.C;
BIW_2 <= IPIPE.B;
TRAP_CODE <= TRAP_CODE_I;
--
if OP_I = STOP then
OP_STOP := true;
end if;
elsif EW_REQ = '1' and IPIPE_PNTR /= 0 then
EXT_WORD <= IPIPE.D;
end if;
end process OUTBUFFERS;
LOOP_OP <= false when NO_LOOP = true else
true when OP = MOVE and BIW_0(8 downto 3) = "010010" else -- (Ay) to (Ax).
true when OP = MOVE and BIW_0(8 downto 3) = "011010" else -- (Ay) to (Ax)+.
true when OP = MOVE and BIW_0(8 downto 3) = "100010" else -- (Ay) to -(Ax).
true when OP = MOVE and BIW_0(8 downto 3) = "010011" else -- (Ay)+ to (Ax).
true when OP = MOVE and BIW_0(8 downto 3) = "011011" else -- (Ay)+ to (Ax)+.
true when OP = MOVE and BIW_0(8 downto 3) = "100011" else -- (Ay)+ to -(Ax).
true when OP = MOVE and BIW_0(8 downto 3) = "010100" else -- -(Ay) to (Ax).
true when OP = MOVE and BIW_0(8 downto 3) = "011100" else -- -(Ay) to (Ax)+.
true when OP = MOVE and BIW_0(8 downto 3) = "100100" else -- -(Ay) to -(Ax).
true when OP = MOVE and BIW_0(8 downto 3) = "100100" else -- -(Ay) to -(Ax).
true when OP = MOVE and BIW_0(8 downto 3) = "010000" else -- Dy to (Ax).
true when OP = MOVE and BIW_0(8 downto 3) = "011000" else -- Dy to (Ax)+.
true when OP = MOVE and BIW_0(8 downto 3) = "010001" else -- Ay to (Ax).
true when OP = MOVE and BIW_0(8 downto 3) = "011001" else -- Ay to (Ax)+.
true when (OP = ADD or OP = AND_B or OP = CMP or OP = EOR or OP = OR_B or OP = SUB) and BIW_0(5 downto 3) = "010" else -- (Ay) to Dx, Dx to (Ay).
true when (OP = ADD or OP = AND_B or OP = CMP or OP = EOR or OP = OR_B or OP = SUB) and BIW_0(5 downto 3) = "011" else -- (Ay)+ to Dx, Dx to (Ay)+.
true when (OP = ADD or OP = AND_B or OP = CMP or OP = EOR or OP = OR_B or OP = SUB) and BIW_0(5 downto 3) = "100" else -- -(Ay) to Dx, Dx to -(Ay).
true when (OP = ADDA or OP = CMPA or OP = SUBA) and BIW_0(5 downto 3) = "010" else -- (Ay) to Ax.
true when (OP = ADDA or OP = CMPA or OP = SUBA) and BIW_0(5 downto 3) = "011" else -- (Ay)+ to Ax.
true when (OP = ADDA or OP = CMPA or OP = SUBA) and BIW_0(5 downto 3) = "100" else -- -(Ay) to Ax.
true when OP = ABCD or OP = SBCD or OP = ADDX or OP = SUBX or OP = CMPM else -- -(Ay) to -(Ay), (Ay)+ to (Ay)+ for CMPM.
true when (OP = CLR or OP = NEG or OP = NEGX or OP = NOT_B or OP = TST or OP = NBCD) and BIW_0(5 downto 3) = "010" else -- (Ay).
true when (OP = CLR or OP = NEG or OP = NEGX or OP = NOT_B or OP = TST or OP = NBCD) and BIW_0(5 downto 3) = "011" else -- (Ay)+.
true when (OP = CLR or OP = NEG or OP = NEGX or OP = NOT_B or OP = TST or OP = NBCD) and BIW_0(5 downto 3) = "100" else -- -(Ay).
true when (OP = ASL or OP = ASR or OP = LSL or OP = LSR) and BIW_0(7 downto 3) = "11010" else -- (Ay) by #1.
true when (OP = ASL or OP = ASR or OP = LSL or OP = LSR) and BIW_0(7 downto 3) = "11011" else -- (Ay)+ by #1.
true when (OP = ASL or OP = ASR or OP = LSL or OP = LSR) and BIW_0(7 downto 3) = "11100" else -- -(Ay) by #1.
true when (OP = ROTL or OP = ROTR or OP = ROXL or OP = ROXR) and BIW_0(7 downto 3) = "11010" else -- (Ay) by #1.
true when (OP = ROTL or OP = ROTR or OP = ROXL or OP = ROXR) and BIW_0(7 downto 3) = "11011" else -- (Ay)+ by #1.
true when (OP = ROTL or OP = ROTR or OP = ROXL or OP = ROXR) and BIW_0(7 downto 3) = "11100" else false; -- -(Ay) by #1.
-- This is the loop attention signal. There are several conditions to start a loop operation.
-- 1. A loop capable operation is in progress indicated by LOOP_OP.
-- 2. A DBcc operation is coming up (IPIPE.D).
-- 3. The displacement is minus four (IPIPE.C).
-- 4. The exception handler may not indicate a request. Otherwise the system may hang in a self
-- blocking mechanism concerning OW_REQ, LOOP_ATN, ALU_BSY.
LOOP_ATN <= false when EXH_REQ = '1' else
true when LOOP_BSY_I = false and LOOP_OP = true and OP_I = DBcc and IPIPE.C = x"FFFC" else false; -- IPIPE.C value must be minus four.
P_LOOP: process
-- This flip flop controls the loop mode of the
-- processor. Refer to the MC68000 user manual
-- Appendix A for more information.
begin
wait until CLK = '1' and CLK' event;
if LOOP_ATN = true and OW_REQ = '1' and OPCODE_RD_I = '0' then
LOOP_BSY <= '1';
LOOP_BSY_I <= true;
elsif LOOP_EXIT = '1' or BUSY_EXH = '1' then
LOOP_BSY <= '0';
LOOP_BSY_I <= false;
end if;
end process P_LOOP;
OW_REQ <= '0' when BUSY_EXH = '1' else OW_REQ_MAIN;
EW_REQ <= EW_REQ_MAIN;
PIPE_RDY <= '1' when OW_REQ = '1' and IPIPE_PNTR = 3 and INSTR_LVL = B else
'1' when OW_REQ = '1' and IPIPE_PNTR > 1 and INSTR_LVL = C else
'1' when OW_REQ = '1' and IPIPE_PNTR > 1 and INSTR_LVL = D else -- We need always pipe C and D to determine the INSTR_LVL.
'1' when EW_REQ = '1' and IPIPE_PNTR > 0 else '0';
HANDSHAKING: process
-- Wee need these flip flops to ensure, that the OUTBUFFERS are
-- written when the respecktive _ACK signal is asserted.
-- The breakpoint cycles are valid for one word operations and
-- therefore does never start FPU operations.
begin
wait until CLK = '1' and CLK' event;
if EW_REQ = '1' and IPIPE_PNTR /= 0 then
EW_ACK <= '1';
else
EW_ACK <= '0';
end if;
if IPIPE_FLUSH = '1' then
OPD_ACK_MAIN <= '0';
elsif TRAP_CODE_I = T_PRIV then -- No action when priviledged.
OPD_ACK_MAIN <= '0';
elsif OW_REQ = '1' and LOOP_BSY_I = true then
OPD_ACK_MAIN <= '1';
elsif OW_REQ = '1' and (PIPE_RDY = '1' or BKPT_REQ = '1') then
OPD_ACK_MAIN <= '1';
else
OPD_ACK_MAIN <= '0';
end if;
end process HANDSHAKING;
P_PC_OFFSET: process(CLK, BUSY_EXH, LOOP_BSY_I, LOOP_EXIT, OP, PC_INC_I)
-- Be Aware: the ADR_OFFSET requires the 'old' PC_VAR.
-- To arrange this, the ADR_OFFSET logic is located
-- above the PC_VAR logic. Do not change this!
-- The PC_VAR is modeled in a way, that the PC points
-- always to the BIW_0.
-- The PC_EW_OFFSET is also used for the calculation
-- of the correct PC value written to the stack pointer
-- during BSR, JSR and exceptions.
variable ADR_OFFSET : std_logic_vector(6 downto 0);
variable PC_VAR : std_logic_vector(6 downto 0);
variable PC_VAR_MEM : std_logic_vector(6 downto 0);
begin
if CLK = '1' and CLK' event then
if IPIPE_FLUSH = '1' then
ADR_OFFSET := "0000000";
elsif PC_INC_I = '1' and OPCODE_RDY_I = '1' then
ADR_OFFSET := ADR_OFFSET + '1' - PC_VAR;
elsif OPCODE_RDY_I = '1' then
ADR_OFFSET := ADR_OFFSET + '1';
elsif PC_INC_I = '1' then
ADR_OFFSET := ADR_OFFSET - PC_VAR;
end if;
--
if BUSY_EXH = '0' then
PC_VAR_MEM := PC_VAR; -- Store the old offset to write back on the stack.
end if;
if BUSY_EXH = '1' then
-- New PC is loaded by the exception handler.
-- So PC_VAR must be initialized.
PC_VAR := "0000000";
elsif PC_INC_I = '1' or FLUSHED = true then
case INSTR_LVL is
when D => PC_VAR := "0000001";
when C => PC_VAR := "0000010";
when B => PC_VAR := "0000011";
end case;
elsif EW_REQ = '1' and IPIPE_PNTR /= 0 then
PC_VAR := PC_VAR + '1';
end if;
--
if OW_REQ = '1' and BKPT_REQ = '1' then
PC_EW_OFFSET <= "0010"; -- Always level D operations.
elsif OW_REQ = '1' and PIPE_RDY = '1' and OP_I = JSR then -- Initialize.
PC_EW_OFFSET <= x"0";
elsif OW_REQ = '1' and PIPE_RDY = '1' then -- BSR.
case INSTR_LVL is
when D => PC_EW_OFFSET <= "0010";
when C => PC_EW_OFFSET <= "0100";
when others => PC_EW_OFFSET <= "0110"; -- LONG displacement.
end case;
elsif EW_ACK = '1' and OP = JSR then -- Calculate the required extension words.
PC_EW_OFFSET <= PC_EW_OFFSET + "010";
end if;
end if;
--
if BUSY_EXH = '1' and PC_INC_I = '1' then
PC_OFFSET <= PC_VAR_MEM & '0';
elsif OP = DBcc and LOOP_BSY_I = true and LOOP_EXIT = '0' then
-- Suppress to increment after DBcc operation during the loop to
-- handle a correct PC with displacement when looping around.
-- In non looping mode, the PC_ING is superseeded by
-- IPIPE_FLUSH in the PC logic. In loop mode we have no flush.
PC_OFFSET <= x"00";
else
PC_OFFSET <= PC_VAR & '0';
end if;
PC_ADR_OFFSET <= ADR_OFFSET & '0';
end process P_PC_OFFSET;
P_FLUSH: process
-- This flip flop is intended to control the incrementation
-- of the PC: normally the PC is updated in the end of an
-- operation (if a new opword is available) or otherwise in
-- the START_OP phase. When the instruction pipe is flushed,
-- it is required to increment the PC immediately to provide
-- the correct address for the pipe refilling. In this case
-- the PC update after the pipe refill is suppressed.
begin
wait until CLK = '1' and CLK' event;
if IPIPE_FLUSH = '1' then
FLUSHED <= true;
elsif OW_REQ = '1' and PIPE_RDY = '1' then
FLUSHED <= false;
end if;
end process P_FLUSH;
PC_INC <= PC_INC_I;
PC_INC_I <= '0' when FLUSHED = true else -- Avoid double increment after a flushed pipe.
'1' when IPIPE_FLUSH = '1' and BUSY_MAIN = '1' else -- If the pipe is flushed, we need the new PC value for refilling.
'0' when BKPT_REQ = '1' else -- Do not update!
'1' when OW_REQ = '1' and PIPE_RDY = '1' else PC_INC_EXH;
-- This signal indicates how many pipe stages are used at a time.
-- Be aware: all coprocessor commands are level D to meet the require-
-- ments of the scanPC.
INSTR_LVL <= D when TRAP_CODE_I = T_PRIV else -- Points to the first word. Required for stacking.
B when OP_I = ADDI and IPIPE.D(7 downto 6) = "10" else
B when OP_I = ANDI and IPIPE.D(7 downto 6) = "10" else
-- B when (OP_I = Bcc or OP_I = BRA or OP_I = BSR) and IPIPE.D(7 downto 0) = x"FF" else -- LONG for 68K10+.
B when OP_I = CMPI and IPIPE.D(7 downto 6) = "10" else
B when OP_I = EORI and IPIPE.D(7 downto 6) = "10" else
B when OP_I = ORI and IPIPE.D(7 downto 6) = "10" else
B when OP_I = SUBI and IPIPE.D(7 downto 6) = "10" else
C when OP_I = ADDI or OP_I = ANDI or OP_I = ANDI_TO_SR or OP_I = ANDI_TO_CCR else
C when (OP_I = BCHG or OP_I = BCLR or OP_I = BSET or OP_I = BTST) and IPIPE.D(8) = '0' else
C when (OP_I = Bcc or OP_I = BRA or OP_I = BSR) and IPIPE.D(7 downto 0) = x"00" else
C when OP_I = CMPI or OP_I = DBcc else
C when (OP_I = DIVS or OP_I = DIVU) and IPIPE.D(8 downto 6) = "001" else
C when OP_I = EORI or OP_I = EORI_TO_CCR or OP_I = EORI_TO_SR else
C when OP_I = LINK or OP_I = MOVEC else -- 68K00 and 68K10 have no long LINK.
C when OP_I = MOVEM or OP_I = MOVEP or OP_I = MOVES else
C when (OP_I = MULS or OP_I = MULU) and IPIPE.D(8 downto 6) = "000" else
C when OP_I = ORI_TO_CCR or OP_I = ORI_TO_SR or OP_I = ORI else
C when OP_I = RTD or OP_I = SUBI or OP_I = STOP else D;
TRAP_CODE_I <= T_1010 when OP_I = UNIMPLEMENTED and IPIPE.D(15 downto 12) = x"A" else
T_1111 when OP_I = UNIMPLEMENTED and IPIPE.D(15 downto 12) = x"F" else
T_ILLEGAL when OP_I = ILLEGAL else
T_RTE when OP_I = RTE and SBIT = '1' else -- Handled like a trap simplifies the code.
T_TRAP when OP_I = TRAP else
T_PRIV when OP_I = ANDI_TO_SR and SBIT = '0' else
T_PRIV when OP_I = EORI_TO_SR and SBIT = '0' else
T_PRIV when OP_I = MOVE_TO_SR and SBIT = '0' else
T_PRIV when OP_I = MOVE_FROM_SR and SBIT = '0' and K6800n = '1' else -- This is for backward compatibility.
T_PRIV when (OP_I = MOVE_USP or OP_I = MOVEC or OP_I = MOVES) and SBIT = '0' else
T_PRIV when OP_I = ORI_TO_SR and SBIT = '0' else
T_PRIV when (OP_I = RESET or OP_I = RTE) and SBIT = '0' else
T_PRIV when OP_I = STOP and SBIT = '0' else NONE;
OP_DECODE: process(IPIPE, K6800n)
begin
-- The default OPCODE is the ILLEGAL operation, if no of the following conditions are met.
-- If any not used bit pattern occurs, the CPU will result in an ILLEGAL trap. An exception of
-- this behavior is the OPCODE with the 1010 or the 1111 pattern in the four MSBs.
-- These lead to the respective traps.
OP_I <= ILLEGAL;
case IPIPE.D(15 downto 12) is -- Operation code map.
when x"0" => -- Bit manipulation / MOVEP / Immediate.
if IPIPE.D(11 downto 0) = x"03C" then
OP_I <= ORI_TO_CCR;
elsif IPIPE.D(11 downto 0) = x"07C" then
OP_I <= ORI_TO_SR;
elsif IPIPE.D(11 downto 0) = x"23C" then
OP_I <= ANDI_TO_CCR;
elsif IPIPE.D(11 downto 0) = x"27C" then
OP_I <= ANDI_TO_SR;
elsif IPIPE.D(11 downto 0) = x"A3C" then
OP_I <= EORI_TO_CCR;
elsif IPIPE.D(11 downto 0) = x"A7C" then
OP_I <= EORI_TO_SR;
elsif IPIPE.D(11 downto 8) = "1110" and IPIPE.D(7 downto 6) < "11" and IPIPE.D(5 downto 3) >= "010" and IPIPE.D(5 downto 3) < "111" and K6800n = '1' then
OP_I <= MOVES;
elsif IPIPE.D(11 downto 8) = "1110" and IPIPE.D(7 downto 6) < "11" and IPIPE.D(5 downto 3) = "111" and IPIPE.D(2 downto 0) < "010" and K6800n = '1' then
OP_I <= MOVES;
elsif IPIPE.D(8 downto 6) > "011" and IPIPE.D(5 downto 3) = "001" then
OP_I <= MOVEP;
else
case IPIPE.D(5 downto 3) is -- Addressing mode.
when "000" | "010" | "011" | "100" | "101" | "110" =>
-- Bit operations with static bit number:
if IPIPE.D(11 downto 6) = "100000" then
OP_I <= BTST;
elsif IPIPE.D(11 downto 6) = "100001" then
OP_I <= BCHG;
elsif IPIPE.D(11 downto 6) = "100010" then
OP_I <= BCLR;
elsif IPIPE.D(11 downto 6) = "100011" then
OP_I <= BSET;
-- Logic operations:
elsif IPIPE.D(11 downto 8) = x"0" and IPIPE.D(7 downto 6) < "11" then
OP_I <= ORI;
elsif IPIPE.D(11 downto 8) = x"2" and IPIPE.D(7 downto 6) < "11" then
OP_I <= ANDI;
elsif IPIPE.D(11 downto 8) = x"4" and IPIPE.D(7 downto 6) < "11" then
OP_I <= SUBI;
elsif IPIPE.D(11 downto 8) = x"6" and IPIPE.D(7 downto 6) < "11" then
OP_I <= ADDI;
elsif IPIPE.D(11 downto 8) = x"A" and IPIPE.D(7 downto 6) < "11" then
OP_I <= EORI;
elsif IPIPE.D(11 downto 8) = x"C" and IPIPE.D(7 downto 6) < "11" then
OP_I <= CMPI;
-- Bit operations with dynamic bit number:
elsif IPIPE.D(8 downto 6) = "100" then
OP_I <= BTST;
elsif IPIPE.D(8 downto 6) = "101" then
OP_I <= BCHG;
elsif IPIPE.D(8 downto 6) = "110" then
OP_I <= BCLR;
elsif IPIPE.D(8 downto 6) = "111" then
OP_I <= BSET;
end if;
when "111" =>
-- In the addressing mode "111" not all register selections are valid.
-- Bit operations with static bit number:
if IPIPE.D(11 downto 6) = "100000" and IPIPE.D(2 downto 0) < "100" then
OP_I <= BTST;
elsif IPIPE.D(11 downto 6) = "100001" and IPIPE.D(2 downto 0) < "010" then
OP_I <= BCHG;
elsif IPIPE.D(11 downto 6) = "100010" and IPIPE.D(2 downto 0) < "010" then
OP_I <= BCLR;
elsif IPIPE.D(11 downto 6) = "100011" and IPIPE.D(2 downto 0) < "010" then
OP_I <= BSET;
-- Logic operations:
elsif IPIPE.D(11 downto 8) = x"0" and IPIPE.D(7 downto 6) < "11" and IPIPE.D(2 downto 0) < "010" then
OP_I <= ORI;
elsif IPIPE.D(11 downto 8) = x"2" and IPIPE.D(7 downto 6) < "11" and IPIPE.D(2 downto 0) < "010" then
OP_I <= ANDI;
elsif IPIPE.D(11 downto 8) = x"4" and IPIPE.D(7 downto 6) < "11" and IPIPE.D(2 downto 0) < "010" then
OP_I <= SUBI;
elsif IPIPE.D(11 downto 8) = x"6" and IPIPE.D(7 downto 6) < "11" and IPIPE.D(2 downto 0) < "010" then
OP_I <= ADDI;
elsif IPIPE.D(11 downto 8) = x"A" and IPIPE.D(7 downto 6) < "11" and IPIPE.D(2 downto 0) < "010" then
OP_I <= EORI;
elsif IPIPE.D(11 downto 8) = x"C" and IPIPE.D(7 downto 6) < "11" and IPIPE.D(2 downto 0) < "100" then
OP_I <= CMPI;
-- Bit operations with dynamic bit number:
elsif IPIPE.D(8 downto 6) = "100" and IPIPE.D(2 downto 0) < "101" then
OP_I <= BTST;
elsif IPIPE.D(8 downto 6) = "101" and IPIPE.D(2 downto 0) < "010" then
OP_I <= BCHG;
elsif IPIPE.D(8 downto 6) = "110" and IPIPE.D(2 downto 0) < "010" then
OP_I <= BCLR;
elsif IPIPE.D(8 downto 6) = "111" and IPIPE.D(2 downto 0) < "010" then
OP_I <= BSET;
end if;
when others =>
null;
end case;
end if;
when x"1" => -- Move BYTE.
if IPIPE.D(8 downto 6) = "111" and IPIPE.D(11 downto 9) < "010"
and IPIPE.D(5 downto 3) = "111" and IPIPE.D(2 downto 0) < "101" then
OP_I <= MOVE;
elsif IPIPE.D(8 downto 6) = "111" and IPIPE.D(11 downto 9) < "010" and IPIPE.D(5 downto 3) /= "001" and IPIPE.D(5 downto 3) /= "111" then
OP_I <= MOVE;
elsif IPIPE.D(8 downto 6) /= "001" and IPIPE.D(8 downto 6) /= "111"
and IPIPE.D(5 downto 3) = "111" and IPIPE.D(2 downto 0) < "101" then
OP_I <= MOVE;
elsif IPIPE.D(8 downto 6) /= "001" and IPIPE.D(8 downto 6) /= "111" and IPIPE.D(5 downto 3) /= "001" and IPIPE.D(5 downto 3) /= "111" then
OP_I <= MOVE;
end if;
when x"2" | x"3" => -- Move WORD or LONG.
if IPIPE.D(8 downto 6) = "111" and IPIPE.D(11 downto 9) < "010"
and IPIPE.D(5 downto 3) = "111" and IPIPE.D(2 downto 0) < "101" then
OP_I <= MOVE;
elsif IPIPE.D(8 downto 6) = "111" and IPIPE.D(11 downto 9) < "010" and IPIPE.D(5 downto 3) /= "111" then
OP_I <= MOVE;
elsif IPIPE.D(8 downto 6) = "001" and IPIPE.D(5 downto 3) = "111" and IPIPE.D(2 downto 0) < "101" then
OP_I <= MOVEA;
elsif IPIPE.D(8 downto 6) = "001" and IPIPE.D(5 downto 3) /= "111" then
OP_I <= MOVEA;
elsif IPIPE.D(8 downto 6) /= "001" and IPIPE.D(8 downto 6) /= "111" and IPIPE.D(5 downto 3) = "111" and IPIPE.D(2 downto 0) < "101" then
OP_I <= MOVE;
elsif IPIPE.D(8 downto 6) /= "001" and IPIPE.D(8 downto 6) /= "111" and IPIPE.D(5 downto 3) /= "111" then
OP_I <= MOVE;
end if;
when x"4" => -- Miscellaneous.
if IPIPE.D(11 downto 0) = x"E70" then
OP_I <= RESET;
elsif IPIPE.D(11 downto 0) = x"E71" then
OP_I <= NOP;
elsif IPIPE.D(11 downto 0) = x"E72" then
OP_I <= STOP;
elsif IPIPE.D(11 downto 0) = x"E73" then
OP_I <= RTE;
elsif IPIPE.D(11 downto 0) = x"E74" and K6800n = '1' then
OP_I <= RTD;
elsif IPIPE.D(11 downto 0) = x"E75" then
OP_I <= RTS;
elsif IPIPE.D(11 downto 0) = x"E76" then
OP_I <= TRAPV;
elsif IPIPE.D(11 downto 0) = x"E77" then
OP_I <= RTR;
elsif IPIPE.D(11 downto 0) = x"AFC" then
OP_I <= ILLEGAL;
elsif IPIPE.D(11 downto 1) = "11100111101" and IPIPE.C(11 downto 0) = x"000" and K6800n = '1' then
OP_I <= MOVEC;
elsif IPIPE.D(11 downto 1) = "11100111101" and IPIPE.C(11 downto 0) = x"001" and K6800n = '1' then
OP_I <= MOVEC;
elsif IPIPE.D(11 downto 1) = "11100111101" and IPIPE.C(11 downto 0) = x"800" and K6800n = '1' then
OP_I <= MOVEC;
elsif IPIPE.D(11 downto 1) = "11100111101" and IPIPE.C(11 downto 0) = x"801" and K6800n = '1' then
OP_I <= MOVEC;
elsif IPIPE.D(11 downto 1) = "11100111101" then
OP_I <= ILLEGAL; -- Not valid MOVEC patterns.
elsif IPIPE.D(11 downto 3) = "100001001" and K6800n = '1' then -- 68K10.
OP_I <= BKPT;
elsif IPIPE.D(11 downto 3) = "111001010" then
OP_I <= LINK; -- WORD.
elsif IPIPE.D(11 downto 3) = "111001011" then
OP_I <= UNLK;
elsif IPIPE.D(11 downto 3) = "100001000" then
OP_I <= SWAP;
elsif IPIPE.D(11 downto 4) = x"E4" then
OP_I <= TRAP;
elsif IPIPE.D(11 downto 4) = x"E6" then
OP_I <= MOVE_USP;
else
case IPIPE.D(5 downto 3) is -- Addressing mode.
when "000" | "010" | "011" | "100" | "101" | "110" =>
if IPIPE.D(11 downto 6) = "110001" then
if IPIPE.C(11) = '1' then
OP_I <= DIVS; -- Long.
else
OP_I <= DIVU; -- Long.
end if;
elsif IPIPE.D(11 downto 6) = "001011" and K6800n = '1' then
OP_I <= MOVE_FROM_CCR;
elsif IPIPE.D(11 downto 6) = "000011" then
OP_I <= MOVE_FROM_SR;
elsif IPIPE.D(11 downto 6) = "010011" then
OP_I <= MOVE_TO_CCR;
elsif IPIPE.D(11 downto 6) = "011011" then
OP_I <= MOVE_TO_SR;
elsif IPIPE.D(11 downto 6) = "110000" then
if IPIPE.C(11) = '1' then
OP_I <= MULS; -- Long.
else
OP_I <= MULU; -- Long.
end if;
elsif IPIPE.D(11 downto 6) = "100000" then
OP_I <= NBCD;
elsif IPIPE.D(11 downto 6) = "101011" then
OP_I <= TAS;
end if;
when "111" => -- Not all registers are valid for this mode.
if IPIPE.D(11 downto 6) = "110001" and IPIPE.D(2 downto 0) < "101" then
if IPIPE.C(11) = '1' then
OP_I <= DIVS; -- Long.
else
OP_I <= DIVU; -- Long.
end if;
elsif IPIPE.D(11 downto 6) = "001011" and IPIPE.D(2 downto 0) < "010" and K6800n = '1' then
OP_I <= MOVE_FROM_CCR;
elsif IPIPE.D(11 downto 6) = "000011" and IPIPE.D(2 downto 0) < "010" then
OP_I <= MOVE_FROM_SR;
elsif IPIPE.D(11 downto 6) = "010011" and IPIPE.D(2 downto 0) < "101" then
OP_I <= MOVE_TO_CCR;
elsif IPIPE.D(11 downto 6) = "011011" and IPIPE.D(2 downto 0) < "101" then
OP_I <= MOVE_TO_SR;
elsif IPIPE.D(11 downto 6) = "110000" and IPIPE.D(2 downto 0) < "101" then
if IPIPE.C(11) = '1' then
OP_I <= MULS; -- Long.
else
OP_I <= MULU; -- Long.
end if;
elsif IPIPE.D(11 downto 6) = "100000" and IPIPE.D(2 downto 0) < "010" then
OP_I <= NBCD;
elsif IPIPE.D(11 downto 6) = "101011" and IPIPE.D(2 downto 0) < "010" then
OP_I <= TAS;
end if;
when others =>
null;
end case;
case IPIPE.D(5 downto 3) is -- Addressing mode.
when "010" | "101" | "110" =>
if IPIPE.D(11 downto 6) = "100001" then
OP_I <= PEA;
elsif IPIPE.D(11 downto 6) = "111010" then
OP_I <= JSR;
elsif IPIPE.D(11 downto 6) = "111011" then
OP_I <= JMP;
end if;
when "111" => -- Not all registers are valid for this mode.
if IPIPE.D(11 downto 6) = "100001" and IPIPE.D(2 downto 0) < "100" then
OP_I <= PEA;
elsif IPIPE.D(11 downto 6) = "111010" and IPIPE.D(2 downto 0) < "100" then
OP_I <= JSR;
elsif IPIPE.D(11 downto 6) = "111011" and IPIPE.D(2 downto 0) < "100" then
OP_I <= JMP;
end if;
when others =>
null;
end case;
-- For the following operation codes a SIZE (IPIPE.D(7 downto 6)) is not valid.
-- For the following operation codes an addressing mode x"001" is not valid.
if IPIPE.D(7 downto 6) < "11" and IPIPE.D(5 downto 3) /= "001" and IPIPE.D(5 downto 3) /= "111" then
case IPIPE.D(11 downto 8) is
when x"0" => OP_I <= NEGX;
when x"2" => OP_I <= CLR;
when x"4" => OP_I <= NEG;
when x"6" => OP_I <= NOT_B;
when others => null;
end case;
-- Not all registers are valid for the addressing mode "111":
elsif IPIPE.D(7 downto 6) < "11" and IPIPE.D(5 downto 3) = "111" and IPIPE.D(2 downto 0) < "010" then
case IPIPE.D(11 downto 8) is
when x"0" => OP_I <= NEGX;
when x"2" => OP_I <= CLR;
when x"4" => OP_I <= NEG;
when x"6" => OP_I <= NOT_B;
when others => null;
end case;
end if;
if IPIPE.D(11 downto 8) = x"A" and IPIPE.D(7 downto 6) < "11" and IPIPE.D(5 downto 3) = "111" and (IPIPE.D(2 downto 0) < "010" or IPIPE.D(2 downto 0) = "100") then -- 68K
-- if IPIPE.D(11 downto 8) = x"A" and IPIPE.D(7 downto 6) < "11" and IPIPE.D(5 downto 3) = "111" and IPIPE.D(2 downto 0) < "101" then -- 68K20 and up.
OP_I <= TST; -- For the 68K00 the byte addressing mode on address register direst is allowed.
elsif IPIPE.D(11 downto 8) = x"A" and IPIPE.D(7 downto 6) < "11" and IPIPE.D(5 downto 3) /= "111" then
case IPIPE.D(7 downto 6) is
when "01" | "10" => OP_I <= TST; -- Long or word, all addressing modes.
when others => -- Byte: Address register direct not allowed.
if IPIPE.D(5 downto 3) /= "001" then
OP_I <= TST;
end if;
end case;
end if;
if IPIPE.D(11 downto 9) = "100" and IPIPE.D(5 downto 3) = "000" then
case IPIPE.D(8 downto 6) is -- Valid OPMODES for this operation code.
when "010" | "011" => OP_I <= EXT;
when others => null;
end case;
end if;
if IPIPE.D(8 downto 6) = "111" then
case IPIPE.D(5 downto 3) is -- OPMODES.
when "010" | "101" | "110" =>
OP_I <= LEA;
when "111" =>
if IPIPE.D(2 downto 0) < "100" then -- Not all registers are valid for this OPMODE.
OP_I <= LEA;
end if;
when others => null;
end case;
end if;
if IPIPE.D(11) = '1' and IPIPE.D(9 downto 7) = "001" then
if IPIPE.D(10) = '0' then -- Register to memory transfer.
case IPIPE.D(5 downto 3) is -- OPMODES, no postincrement addressing.
when "010" | "100" | "101" | "110" =>
OP_I <= MOVEM;
when "111" =>
if IPIPE.D(2 downto 0) = "000" or IPIPE.D(2 downto 0) = "001" then
OP_I <= MOVEM;
end if;
when others => null;
end case;
else -- Memory to register transfer, no predecrement addressing.
case IPIPE.D(5 downto 3) is -- OPMODES.
when "010" | "011" | "101" | "110" =>
OP_I <= MOVEM;
when "111" =>
if IPIPE.D(2 downto 0) < "100" then
OP_I <= MOVEM;
end if;
when others => null;
end case;
end if;
end if;
-- The size must be "11" and the OPMODE may not be "001".
if IPIPE.D(8 downto 7) = "11" and IPIPE.D(6 downto 3) = x"7" and IPIPE.D(2 downto 0) < "101" then
OP_I <= CHK; -- CHK is WORD wide for the 68K10 and 68K00.
elsif IPIPE.D(8 downto 7) = "11" and IPIPE.D(6 downto 3) /= x"1" and IPIPE.D(6 downto 3) < x"7" then
OP_I <= CHK; -- CHK is WORD wide for the 68K10 and 68K00.
end if;
end if;
when x"5" => -- ADDQ / SUBQ / Scc / DBcc.
if IPIPE.D(7 downto 3) = "11001" then
OP_I <= DBcc;
elsif IPIPE.D(7 downto 6) = "11" and IPIPE.D(5 downto 3) = "111" and IPIPE.D(2 downto 0) < "010" then
OP_I <= Scc;
elsif IPIPE.D(7 downto 6) = "11" and IPIPE.D(5 downto 3) /= "001" and IPIPE.D(5 downto 3) /= "111" then
OP_I <= Scc;
--
elsif IPIPE.D(8) = '0' and IPIPE.D(7 downto 6) < "11" and IPIPE.D(5 downto 3) = "111" and IPIPE.D(2 downto 0) < "010" then
OP_I <= ADDQ;
elsif IPIPE.D(8) = '0' and (IPIPE.D(7 downto 6) = "01" or IPIPE.D(7 downto 6) = "10") and IPIPE.D(5 downto 3) /= "111" then
OP_I <= ADDQ;
elsif IPIPE.D(8) = '0' and IPIPE.D(7 downto 6) = "00" and IPIPE.D(5 downto 3) /= "001" and IPIPE.D(5 downto 3) /= "111" then
OP_I <= ADDQ;
--
elsif IPIPE.D(8) = '1' and IPIPE.D(7 downto 6) < "11" and IPIPE.D(5 downto 3) = "111" and IPIPE.D(2 downto 0) < "010" then
OP_I <= SUBQ;
elsif IPIPE.D(8) = '1' and (IPIPE.D(7 downto 6) = "01" or IPIPE.D(7 downto 6) = "10") and IPIPE.D(5 downto 3) /= "111" then
OP_I <= SUBQ;
elsif IPIPE.D(8) = '1' and IPIPE.D(7 downto 6) = "00" and IPIPE.D(5 downto 3) /= "001" and IPIPE.D(5 downto 3) /= "111" then
OP_I <= SUBQ;
end if;
when x"6" => -- Bcc / BSR / BRA.
if IPIPE.D(11 downto 8) = x"0" then
OP_I <= BRA;
elsif IPIPE.D(11 downto 8) = x"1" then
OP_I <= BSR;
else
OP_I <= Bcc;
end if;
when x"7" => -- MOVEQ.
if IPIPE.D(8) = '0' then
OP_I <= MOVEQ;
end if;
when x"8" => -- OR / DIV / SBCD.
if IPIPE.D(8 downto 6) = "011" and IPIPE.D(5 downto 3) = "111" and IPIPE.D(2 downto 0) < "101" then
OP_I <= DIVU; -- WORD.
elsif IPIPE.D(8 downto 6) = "011" and IPIPE.D(5 downto 3) /= "001" and IPIPE.D(5 downto 3) /= "111" then
OP_I <= DIVU; -- WORD.
elsif IPIPE.D(8 downto 6) = "111" and IPIPE.D(5 downto 3) = "111" and IPIPE.D(2 downto 0) < "101" then
OP_I <= DIVS; -- WORD.
elsif IPIPE.D(8 downto 6) = "111" and IPIPE.D(5 downto 3) /= "001" and IPIPE.D(5 downto 3) /= "111" then
OP_I <= DIVS; -- WORD.
elsif IPIPE.D(8 downto 4) = "10000" then
OP_I <= SBCD;
end if;
--
case IPIPE.D(8 downto 6) is
when "000" | "001" | "010" =>
if IPIPE.D(5 downto 3) = "111" and IPIPE.D(2 downto 0) < "101" then
OP_I <= OR_B;
elsif IPIPE.D(5 downto 3) /= "001" and IPIPE.D(5 downto 3) /= "111" then
OP_I <= OR_B;
end if;
when "100" | "101" | "110" =>
if IPIPE.D(5 downto 3) = "111" and IPIPE.D(2 downto 0) < "010" then
OP_I <= OR_B;
elsif IPIPE.D(5 downto 3) > "001" and IPIPE.D(5 downto 3) /= "111" then
OP_I <= OR_B;
end if;
when others =>
null;
end case;
when x"9" => -- SUB / SUBX.
case IPIPE.D(8 downto 6) is
when "000" => -- Byte size.
if IPIPE.D(5 downto 3) = "111" and IPIPE.D(2 downto 0) < "101" then
OP_I <= SUB;
elsif IPIPE.D(5 downto 3) /= "111" and IPIPE.D(5 downto 3) /= "001" then
OP_I <= SUB;
end if;
when "001" | "010" => -- Word and long.
if IPIPE.D(5 downto 3) = "111" and IPIPE.D(2 downto 0) < "101" then
OP_I <= SUB;
elsif IPIPE.D(5 downto 3) /= "111" then
OP_I <= SUB;
end if;
when "100" =>
if IPIPE.D(5 downto 3) = "000" or IPIPE.D(5 downto 3) = "001" then
OP_I <= SUBX;
elsif IPIPE.D(5 downto 3) = "111" and IPIPE.D(2 downto 0) < "010" then
OP_I <= SUB;
elsif IPIPE.D(5 downto 3) /= "111" and IPIPE.D(5 downto 3) /= "001" then -- Byte size.
OP_I <= SUB;
end if;
when "101" | "110" =>
if IPIPE.D(5 downto 3) = "000" or IPIPE.D(5 downto 3) = "001" then
OP_I <= SUBX;
elsif IPIPE.D(5 downto 3) = "111" and IPIPE.D(2 downto 0) < "010" then
OP_I <= SUB;
elsif IPIPE.D(5 downto 3) /= "111" then -- Word and long.
OP_I <= SUB;
end if;
when "011" | "111" =>
if IPIPE.D(5 downto 3) = "111" and IPIPE.D(2 downto 0) < "101" then
OP_I <= SUBA;
elsif IPIPE.D(5 downto 3) /= "111" then
OP_I <= SUBA;
end if;
when others => -- U, X, Z, W, H, L, -.
null;
end case;
when x"A" => -- (1010, Unassigned, Reserved).
OP_I <= UNIMPLEMENTED;
when x"B" => -- CMP / EOR.
if IPIPE.D(8) = '1' and IPIPE.D(7 downto 6) < "11" and IPIPE.D(5 downto 3) = "001" then
OP_I <= CMPM;
else
case IPIPE.D(8 downto 6) is -- OPMODE field.
when "000" =>
if IPIPE.D(5 downto 3) = "111" and IPIPE.D(2 downto 0) < "101" then
OP_I <= CMP;
elsif IPIPE.D(5 downto 3) /= "001" and IPIPE.D(5 downto 3) /= "111" then
OP_I <= CMP;
end if;
when "001" | "010" =>
if IPIPE.D(5 downto 3) = "111" and IPIPE.D(2 downto 0) < "101" then
OP_I <= CMP;
elsif IPIPE.D(5 downto 3) /= "111" then
OP_I <= CMP;
end if;
when "011" | "111" =>
if IPIPE.D(5 downto 3) = "111" and IPIPE.D(2 downto 0) < "101" then
OP_I <= CMPA;
elsif IPIPE.D(5 downto 3) /= "111" then
OP_I <= CMPA;
end if;
when "100" | "101" | "110" =>
if IPIPE.D(5 downto 3) = "111" and IPIPE.D(2 downto 0) < "101" then
OP_I <= EOR;
elsif IPIPE.D(5 downto 3) /= "001" and IPIPE.D(5 downto 3) /= "111" then
OP_I <= EOR;
end if;
when others => -- U, X, Z, W, H, L, -.
null;
end case;
end if;
when x"C" => -- AND / MUL / ABCD / EXG.
if IPIPE.D(8 downto 4) = "10000" then
OP_I <= ABCD;
elsif IPIPE.D(8 downto 6) = "011" and IPIPE.D(5 downto 3) = "111" and IPIPE.D(2 downto 0) < "101" then
OP_I <= MULU; -- WORD.
elsif IPIPE.D(8 downto 6) = "011" and IPIPE.D(5 downto 3) /= "001" and IPIPE.D(5 downto 3) /= "111" then
OP_I <= MULU; -- WORD.
elsif IPIPE.D(8 downto 6) = "111" and IPIPE.D(5 downto 3) = "111" and IPIPE.D(2 downto 0) < "101" then
OP_I <= MULS; -- WORD.
elsif IPIPE.D(8 downto 6) = "111" and IPIPE.D(5 downto 3) /= "001" and IPIPE.D(5 downto 3) /= "111" then
OP_I <= MULS; -- WORD.
elsif IPIPE.D(8 downto 3) = "101000" or IPIPE.D(8 downto 3) = "101001" or IPIPE.D(8 downto 3) = "110001" then
OP_I <= EXG;
else
case IPIPE.D(8 downto 6) is -- OPMODE
when "000" | "001" | "010" =>
if IPIPE.D(5 downto 3) = "111" and IPIPE.D(2 downto 0) < "101" then
OP_I <= AND_B;
elsif IPIPE.D(5 downto 3) /= "001" and IPIPE.D(5 downto 3) /= "111" then
OP_I <= AND_B;
end if;
when "100" | "101" | "110" =>
if IPIPE.D(5 downto 3) = "111" and IPIPE.D(2 downto 0) < "010" then
OP_I <= AND_B;
elsif IPIPE.D(5 downto 3) > "001" and IPIPE.D(5 downto 3) /= "111" then
OP_I <= AND_B;
end if;
when others =>
null;
end case;
end if;
when x"D" => -- ADD / ADDX.
case IPIPE.D(8 downto 6) is
when "000" =>
if IPIPE.D(5 downto 3) = "111" and IPIPE.D(2 downto 0) < "101" then
OP_I <= ADD;
elsif IPIPE.D(5 downto 3) /= "111" and IPIPE.D(5 downto 3) /= "001" then
OP_I <= ADD;
end if;
when "001" | "010" =>
if IPIPE.D(5 downto 3) = "111" and IPIPE.D(2 downto 0) < "101" then
OP_I <= ADD;
elsif IPIPE.D(5 downto 3) /= "111" then
OP_I <= ADD;
end if;
when "100" =>
if IPIPE.D(5 downto 3) = "000" or IPIPE.D(5 downto 3) = "001" then
OP_I <= ADDX;
elsif IPIPE.D(5 downto 3) = "111" and IPIPE.D(2 downto 0) < "010" then
OP_I <= ADD;
elsif IPIPE.D(5 downto 3) /= "111" and IPIPE.D(5 downto 3) /= "001" then
OP_I <= ADD;
end if;
when "101" | "110" =>
if IPIPE.D(5 downto 3) = "000" or IPIPE.D(5 downto 3) = "001" then
OP_I <= ADDX;
elsif IPIPE.D(5 downto 3) = "111" and IPIPE.D(2 downto 0) < "010" then
OP_I <= ADD;
elsif IPIPE.D(5 downto 3) /= "111" then
OP_I <= ADD;
end if;
when "011" | "111" =>
if IPIPE.D(5 downto 3) = "111" and IPIPE.D(2 downto 0) < "101" then
OP_I <= ADDA;
elsif IPIPE.D(5 downto 3) /= "111" then
OP_I <= ADDA;
end if;
when others => -- U, X, Z, W, H, L, -.
null;
end case;
when x"E" => -- Shift / Rotate.
if IPIPE.D(11 downto 6) = "000011" and IPIPE.D(5 downto 3) = "111" and IPIPE.D(2 downto 0) < "010" then
OP_I <= ASR; -- Memory shifts.
elsif IPIPE.D(11 downto 6) = "000011" and IPIPE.D(5 downto 3) > "001" and IPIPE.D(5 downto 3) /= "111" then
OP_I <= ASR; -- Memory shifts.
elsif IPIPE.D(11 downto 6) = "000111" and IPIPE.D(5 downto 3) = "111" and IPIPE.D(2 downto 0) < "010" then
OP_I <= ASL; -- Memory shifts.
elsif IPIPE.D(11 downto 6) = "000111" and IPIPE.D(5 downto 3) > "001" and IPIPE.D(5 downto 3) /= "111" then
OP_I <= ASL; -- Memory shifts.
elsif IPIPE.D(11 downto 6) = "001011" and IPIPE.D(5 downto 3) = "111" and IPIPE.D(2 downto 0) < "010" then
OP_I <= LSR; -- Memory shifts.
elsif IPIPE.D(11 downto 6) = "001011" and IPIPE.D(5 downto 3) > "001" and IPIPE.D(5 downto 3) /= "111" then
OP_I <= LSR; -- Memory shifts.
elsif IPIPE.D(11 downto 6) = "001111" and IPIPE.D(5 downto 3) = "111" and IPIPE.D(2 downto 0) < "010" then
OP_I <= LSL; -- Memory shifts.
elsif IPIPE.D(11 downto 6) = "001111" and IPIPE.D(5 downto 3) > "001" and IPIPE.D(5 downto 3) /= "111" then
OP_I <= LSL; -- Memory shifts.
elsif IPIPE.D(11 downto 6) = "010011" and IPIPE.D(5 downto 3) = "111" and IPIPE.D(2 downto 0) < "010" then
OP_I <= ROXR; -- Memory shifts.
elsif IPIPE.D(11 downto 6) = "010011" and IPIPE.D(5 downto 3) > "001" and IPIPE.D(5 downto 3) /= "111" then
OP_I <= ROXR; -- Memory shifts.
elsif IPIPE.D(11 downto 6) = "010111" and IPIPE.D(5 downto 3) = "111" and IPIPE.D(2 downto 0) < "010" then
OP_I <= ROXL; -- Memory shifts.
elsif IPIPE.D(11 downto 6) = "010111" and IPIPE.D(5 downto 3) > "001" and IPIPE.D(5 downto 3) /= "111" then
OP_I <= ROXL; -- Memory shifts.
elsif IPIPE.D(11 downto 6) = "011011" and IPIPE.D(5 downto 3) = "111" and IPIPE.D(2 downto 0) < "010" then
OP_I <= ROTR; -- Memory shifts.
elsif IPIPE.D(11 downto 6) = "011011" and IPIPE.D(5 downto 3) > "001" and IPIPE.D(5 downto 3) /= "111" then
OP_I <= ROTR; -- Memory shifts.
elsif IPIPE.D(11 downto 6) = "011111" and IPIPE.D(5 downto 3) = "111" and IPIPE.D(2 downto 0) < "010" then
OP_I <= ROTL; -- Memory shifts.
elsif IPIPE.D(11 downto 6) = "011111" and IPIPE.D(5 downto 3) > "001" and IPIPE.D(5 downto 3) /= "111" then
OP_I <= ROTL; -- Memory shifts.
elsif IPIPE.D(8) = '0' and IPIPE.D(7 downto 6) < "11" and IPIPE.D(4 downto 3) = "00" then
OP_I <= ASR; -- Register shifts.
elsif IPIPE.D(8) = '1' and IPIPE.D(7 downto 6) < "11" and IPIPE.D(4 downto 3) = "00" then
OP_I <= ASL; -- Register shifts.
elsif IPIPE.D(8) = '0' and IPIPE.D(7 downto 6) < "11" and IPIPE.D(4 downto 3) = "01" then
OP_I <= LSR; -- Register shifts.
elsif IPIPE.D(8) = '1' and IPIPE.D(7 downto 6) < "11" and IPIPE.D(4 downto 3) = "01" then
OP_I <= LSL; -- Register shifts.
elsif IPIPE.D(8) = '0' and IPIPE.D(7 downto 6) < "11" and IPIPE.D(4 downto 3) = "10" then
OP_I <= ROXR; -- Register shifts.
elsif IPIPE.D(8) = '1' and IPIPE.D(7 downto 6) < "11" and IPIPE.D(4 downto 3) = "10" then
OP_I <= ROXL; -- Register shifts.
elsif IPIPE.D(8) = '0' and IPIPE.D(7 downto 6) < "11" and IPIPE.D(4 downto 3) = "11" then
OP_I <= ROTR; -- Register shifts.
elsif IPIPE.D(8) = '1' and IPIPE.D(7 downto 6) < "11" and IPIPE.D(4 downto 3) = "11" then
OP_I <= ROTL; -- Register shifts.
end if;
when x"F" => -- 1111, Coprocessor Interface / 68K40 Extensions.
OP_I <= UNIMPLEMENTED;
when others => -- U, X, Z, W, H, L, -.
null;
end case;
end process OP_DECODE;
end BEHAVIOR;