OpenCores
URL https://opencores.org/ocsvn/fpz8/fpz8/trunk

Subversion Repositories fpz8

[/] [fpz8_cpu_v1.vhd] - Rev 3

Compare with Previous | Blame | View Log

-- FPz8 mk1 v0.99
-- Zilog Z8 Encore! 100% compatible softcore
-- Author: 	Fábio Pereira (fabio.jve@gmail.com)
-- Version: 0.99	Nov, 24th, 2016	(changed LDWX instruction, interrupts, condition code function, debugger command processor)
-- Version: 0.91	Nov, 15th, 2016
-- Version:	0.9		Nov, 11th, 2016
 
-- FPz8 is a softcore almost 100% object-code compatible with the Z8 encore microcontroller line. Current implementation includes 
-- 2kb of file registers (RAM), 16kb of program memory (using FPGA RAM), 8 vectored interrupts with programmable priority, 
-- full-featured onchip debugger 100% compatible with Zilog's OCD and ZDS-II IDE.
-- It was designed to work as a SoC and everything (except the USB chip) fits inside a single FPGA (I have used an Altera 
-- Cyclone IV EP4CE6 device). The debugger connection makes use of a serial-to-USB chip (it is part of the low-cost FPGA 
-- board used on the project).
-- In a near future I plan to add some more features to the device (such as a timer and maybe other peripherals).
-- The idea behind the FPz8 was to learn more on VHDL and FPGAs (this is my second design using these technologies). I also 
-- believe FPz8 can be a very interesting tool for learning/teaching VHDL, computing and microprocessors/microcontrollers 
-- programming.
 
-- You are free to use and to modify FPz8 to fit your needs, except for comercial use (I don't expect anyone would do that anyway).
-- If you want to contribute to the project, contact me and share your thoughts.
-- Don't forget to credit the author!
 
-- Note: currently there are only a few SFRs physically implemented, they are:
-- 0xFC0 - IRQ0
-- 0xFC1 - IRQ0ENH
-- 0xFC2 - IRQ0ENL
-- 0xFCF - IRQCTL
-- 0xFD2 - PAIN
-- 0xFD3 - PAOUT
-- 0xFF8 - FCTL
-- 0xFFC - FLAGS
-- 0xFFD - RP
-- 0xFFE - SPH
-- 0xFFF - SPL
 
-- What else is missing from the original architecture?
-- A: no watchdog (WDT instruction runs as a NOP), no LDE and LDEI instructions (data memory related), no option bytes,
--    no data memory related debug commands, no CRC debug command, no ID bytes
 
-- FPz8 was tested on an EP4CE6 mini board (50MHz clock)
-- http://www.ebay.com/itm/EP4CE6-Mini-Board-USB-Blaster-Altera-Cyclone-IV-FPGA-CPLD-Nano-Size-
 
-- This work is licensed under the Creative Commons Attribution 4.0 International License.
-- To view a copy of this license, visit http://creativecommons.org/licenses/by/4.0/.
 
library ieee ;
use ieee.std_logic_1164.all ;
use ieee.numeric_std.all;
use ieee.std_logic_unsigned.all ;
 
entity fpz8_cpu_v1 IS
	port
	(
		IAB			: buffer std_logic_vector(15 downto 0);	-- instruction address bus (16 bits)
		IDB			: in std_logic_vector(7 downto 0);		-- instruction data bus (8 bits)
		IWDB		: out std_logic_vector(7 downto 0);		-- instruction write data bus (8 bits)
		FRAB		: buffer std_logic_vector(11 downto 0);	-- file register address bus (12 bits)
		FRIDB		: in std_logic_vector(7 downto 0);		-- memory input data bus (8 bits)
		FRODB		: out std_logic_vector(7 downto 0);		-- memory output data bus (8 bits)
		RIDB		: in std_logic_vector(7 downto 0);		-- register input data bus (8 bits)
		RODB		: out std_logic_vector(7 downto 0);		-- register output data bus (8 bits)		
		PGM_WR		: out std_logic;						-- program memory write enable
		WR			: buffer std_logic;						-- write enable
		REG_SEL		: buffer std_logic;						-- SFR select (addresses F00 to FFF, except internal registers)
		MEM_SEL		: buffer std_logic;						-- memory select
		INT0		: in std_logic;							-- interrupt 0 input (vector 0x0016)
		INT1		: in std_logic;							-- interrupt 1 input (vector 0x0014)
		INT2		: in std_logic;							-- interrupt 2 input (vector 0x0012)
		INT3		: in std_logic;							-- interrupt 3 input (vector 0x0010)
		INT4		: in std_logic;							-- interrupt 4 input (vector 0x000E)
		INT5		: in std_logic;							-- interrupt 5 input (vector 0x000C)
		INT6		: in std_logic;							-- interrupt 6 input (vector 0x000A)
		INT7		: in std_logic;							-- interrupt 7 input (vector 0x0008)
		DBG_RX		: in std_logic;							-- debugger receive input
		DBG_TX		: buffer std_logic;						-- debugger transmit output
		PAOUT		: out std_logic_vector(7 downto 0);		-- port A output data
		PAIN		: in std_logic_vector(7 downto 0);		-- port A input data
		CLK			: in std_logic;							-- main clock
		CLK_OUT		: buffer std_logic;						-- main clock output
		CLK_OUTN	: out std_logic;						-- main inverted clock output
		STOP		: buffer std_logic;						-- stop output	 
		RESET_OUT	: out std_logic;						-- reset output
		RESET		: in std_logic							-- CPU reset			
	);
end fpz8_cpu_v1;
 
architecture cpu of fpz8_cpu_v1 is
 
type Tinstqueue is array (0 TO 7) of std_logic_vector(7 downto 0);
type Tflags is record
	C,Z,S,V,D,H,F2,F1			: std_logic;
end record;
shared variable CPU_FLAGS, ALU_FLAGS		: Tflags;
shared variable ALU_NOUPDATE				: std_logic;
shared variable IRQE						: std_logic;
shared variable IRQ0						: std_logic_vector(7 downto 0);		-- interrupts 0-7 flags
shared variable IRQ0ENH,IRQ0ENL				: std_logic_vector(7 downto 0);		-- interrupts 0-7 enable high and low
shared variable SP 							: std_logic_vector(11 downto 0);	-- stack pointer
shared variable RP							: std_logic_vector(7 downto 0);		-- register pointer
shared variable FCTL						: std_logic_vector(7 downto 0);		-- flash control
shared variable PAOUT_BUFFER				: std_logic_vector(7 downto 0);
signal 			RXSYNC1, RXSYNC2			: std_logic;
ATTRIBUTE preserve							: boolean;
ATTRIBUTE preserve OF RXSYNC1				: signal IS true;
ATTRIBUTE preserve OF RXSYNC2				: signal IS true;
signal IRQ0_LATCH							: std_logic_vector(7 downto 0);		-- current state of IRQ inputs
attribute preserve of IRQ0_LATCH			: signal is true;
 
constant ALU_ADD 	: std_logic_vector(3 downto 0):=x"0";	-- CZSVH D=0
constant ALU_ADC 	: std_logic_vector(3 downto 0):=x"1";	-- CZSVH D=0
constant ALU_SUB 	: std_logic_vector(3 downto 0):=x"2";	-- CZSVH D=1
constant ALU_SBC 	: std_logic_vector(3 downto 0):=x"3";	-- CZSVH D=1
constant ALU_OR	 	: std_logic_vector(3 downto 0):=x"4";	-- ZS V=0
constant ALU_AND 	: std_logic_vector(3 downto 0):=x"5";	-- ZS V=0
constant ALU_TCM 	: std_logic_vector(3 downto 0):=x"6";	-- ZS V=0
constant ALU_TM  	: std_logic_vector(3 downto 0):=x"7";	-- ZS V=0
constant ALU_CPC  	: std_logic_vector(3 downto 0):=x"9";	-- CZSV
constant ALU_CP  	: std_logic_vector(3 downto 0):=x"A";	-- CZSV
constant ALU_XOR 	: std_logic_vector(3 downto 0):=x"B";	-- ZS V=0
constant ALU_BSWAP  : std_logic_vector(3 downto 0):=x"D";	-- ZS V=0
constant ALU_LD  	: std_logic_vector(3 downto 0):=x"E";	-- Load does not change any flag
 
constant LU2_RLC	: std_logic_vector(3 downto 0):=x"1";	-- CZSV
constant LU2_INC	: std_logic_vector(3 downto 0):=x"2";	-- ZSV
constant LU2_DEC	: std_logic_vector(3 downto 0):=x"3";	-- ZSV
constant LU2_DA		: std_logic_vector(3 downto 0):=x"4";	-- CZS
constant LU2_COM	: std_logic_vector(3 downto 0):=x"6";	-- ZS V=0
constant LU2_LD		: std_logic_vector(3 downto 0):=x"7";	-- Load does not change any flag
constant LU2_RL		: std_logic_vector(3 downto 0):=x"9";	-- CZSV
constant LU2_SRL	: std_logic_vector(3 downto 0):=x"A";	-- CZSV
constant LU2_CLR	: std_logic_vector(3 downto 0):=x"B";	-- Clear does not change any flag
constant LU2_RRC	: std_logic_vector(3 downto 0):=x"C";	-- CZSV
constant LU2_SRA	: std_logic_vector(3 downto 0):=x"D";	-- CZSV
constant LU2_RR		: std_logic_vector(3 downto 0):=x"E";	-- CZSV
constant LU2_SWAP	: std_logic_vector(3 downto 0):=x"F";	-- ZS
 
-- Debug commands
constant DBGCMD_READ_REV		: std_logic_vector(7 downto 0):=x"00";
constant DBGCMD_READ_STATUS		: std_logic_vector(7 downto 0):=x"02";
constant DBGCMD_READ_RUNCOUNTER	: std_logic_vector(7 downto 0):=x"03";
constant DBGCMD_WRITE_CTRL		: std_logic_vector(7 downto 0):=x"04";
constant DBGCMD_READ_CTRL		: std_logic_vector(7 downto 0):=x"05";
constant DBGCMD_WRITE_PC		: std_logic_vector(7 downto 0):=x"06";
constant DBGCMD_READ_PC			: std_logic_vector(7 downto 0):=x"07";
constant DBGCMD_WRITE_REG		: std_logic_vector(7 downto 0):=x"08";
constant DBGCMD_READ_REG		: std_logic_vector(7 downto 0):=x"09";
constant DBGCMD_WRITE_PROGRAM	: std_logic_vector(7 downto 0):=x"0A";
constant DBGCMD_READ_PROGRAM	: std_logic_vector(7 downto 0):=x"0B";
constant DBGCMD_READ_CRC		: std_logic_vector(7 downto 0):=x"0E";
constant DBGCMD_STEP			: std_logic_vector(7 downto 0):=x"10";
constant DBGCMD_STUFF			: std_logic_vector(7 downto 0):=x"11";
constant DBGCMD_EXEC			: std_logic_vector(7 downto 0):=x"12";
 
-- DATAWRITE controls where data to be written actually goes (an internal register, an external register (through register data bus) or RAM)
procedure DATAWRITE
	(	ADDRESS	: in std_logic_vector(11 downto 0);
		DATA	: in std_logic_vector(7 downto 0)) is
begin
	if (ADDRESS>=x"F00") then		----------------------------------------------- it is a SFR address
		if (ADDRESS=x"FFC") then	---------------------------------------------------- FLAGS register
			CPU_FLAGS.C := DATA(7);
			CPU_FLAGS.Z := DATA(6);
			CPU_FLAGS.S := DATA(5);
			CPU_FLAGS.V := DATA(4);
			CPU_FLAGS.D := DATA(3);
			CPU_FLAGS.H := DATA(2);
			CPU_FLAGS.F2 := DATA(1);
			CPU_FLAGS.F1 := DATA(0);
		elsif (ADDRESS=x"FFD") then RP := DATA;	------------------------------------------- RP register
		elsif (ADDRESS=x"FFE") then SP(11 downto 8) := DATA(3 downto 0);	-------------- SPH register
		elsif (ADDRESS=x"FFF") then SP(7 downto 0) := DATA;	------------------------------ SPL register
		elsif (ADDRESS=x"FF8") then	----------------------------------------------------- FCTL register
			if (DATA=x"73") then FCTL:=x"01";
			elsif (DATA=x"8C" and FCTL=x"01") then FCTL:=x"03";
			elsif (DATA=x"95") then FCTL:=x"04";
			else FCTL:=x"00";
			end if;
		elsif (ADDRESS=x"FC0") then	IRQ0 := DATA; --------------------------------------- IRQ0 register
		elsif (ADDRESS=x"FC1") then IRQ0ENH := DATA;	------------------------------ IRQ0ENH register
		elsif (ADDRESS=x"FC2") then IRQ0ENL := DATA;	------------------------------ IRQ0ENL register
		elsif (ADDRESS=x"FCF") then	IRQE := DATA(7);	------------------------------- IRQCTL register
		elsif (ADDRESS=x"FD3") then ---------------------------------------------------- PAOUT register
			PAOUT <= DATA;	
			PAOUT_BUFFER := DATA;
		else -- if it is not an internal SFR but ADDRESS>=0xF00 then it is an external register
			REG_SEL <= '1';	-- enable external register select
			RODB <= DATA;	-- output data on register output data bus
		end if;
	else	-- if ADDRESS < 0xF00 then it is a RAM register
		MEM_SEL <= '1';		-- enable external memory select
		FRODB <= DATA;		-- output data on file register output data bus
	end if;		
end datawrite;
 
-- DATAREAD controls where the data to be read actually comes from (an internal register, an external register (through register data bus) or RAM)
impure function DATAREAD
	(ADDRESS	: in std_logic_vector(11 downto 0))
	return std_logic_vector is
begin
	if (ADDRESS>=x"F00") then	-------------------------------- it is a SFR address
		if (ADDRESS=x"FFC") then	--------------------------------- FLAGS register
			return (CPU_FLAGS.C,CPU_FLAGS.Z,CPU_FLAGS.S,CPU_FLAGS.V,CPU_FLAGS.D,CPU_FLAGS.H,CPU_FLAGS.F2,CPU_FLAGS.F1);
		elsif (ADDRESS=x"FFD") then return RP;	------------------------ RP register
		elsif (ADDRESS=x"FFE") then	----------------------------------- SPH register
			return "0000" & SP(11 downto 8);
		elsif (ADDRESS=x"FFF") then return SP(7 downto 0);	----------- SPL register
		elsif (ADDRESS=x"FF8") then return FCTL;	------------------ FCTL register
		elsif (ADDRESS=x"FC0") then	return IRQ0;	------------------ IRQ0 register
		elsif (ADDRESS=x"FC1") then return IRQ0ENH;	--------------- IRQ0ENH register
		elsif (ADDRESS=x"FC2") then return IRQ0ENL;	--------------- IRQ0ENL register
		elsif (ADDRESS=x"FCF") then return IRQE&"0000000";	-------- IRQCTL register
		elsif (ADDRESS=x"FD2") then return PAIN;	------------------ PAIN register
		elsif (ADDRESS=x"FD3") then return PAOUT_BUFFER;	--------- PAOUT register
		else 
			REG_SEL <= '1';
			return RIDB;
		end if;
	else
		MEM_SEL <= '1';
		return FRIDB;
	end if;		
end DATAREAD;
 
-- CONDITIONCODE returns the result of a logical condition (for conditional jumps)
function CONDITIONCODE
	(	CONDITION	: in std_logic_vector(3 downto 0)) return STD_LOGIC is
begin
	case CONDITION is
		when x"0" =>
			return '0';
		when x"1" =>
			return CPU_FLAGS.S xor CPU_FLAGS.V;
		when x"2" =>
			return CPU_FLAGS.Z or (CPU_FLAGS.S xor CPU_FLAGS.V);
		when x"3" =>
			return CPU_FLAGS.C or CPU_FLAGS.Z;
		when x"4" =>
			return CPU_FLAGS.V;
		when x"5" =>
			return CPU_FLAGS.S;
		when x"6" =>
			return CPU_FLAGS.Z;
		when x"7" =>
			return CPU_FLAGS.C;
		when x"8" =>
			return '1';
		when x"9" =>
			return NOT (CPU_FLAGS.S xor CPU_FLAGS.V);
		when x"A" =>
			return NOT (CPU_FLAGS.Z or (CPU_FLAGS.S xor CPU_FLAGS.V));
		when x"B" =>
			return (NOT CPU_FLAGS.C) AND (NOT CPU_FLAGS.Z);
		when x"C" =>
			return NOT CPU_FLAGS.V;
		when x"D" =>
			return NOT CPU_FLAGS.S;
		when x"E" =>
			return NOT CPU_FLAGS.Z;
		when others =>
			return NOT CPU_FLAGS.C;
	end case;
end CONDITIONCODE;
 
-- ADDRESSER12 generates a 12-bit address (it decides when to use escaped addressing mode)
function ADDRESSER12
	(	ADDR	: in std_logic_vector(11 downto 0)) return std_logic_vector is
begin
	if (ADDR(11 downto 4)=x"EE") then		-- escaped addressing mode (work register)
		return RP(3 downto 0) & RP(7 downto 4) & ADDR(3 downto 0);
	elsif (ADDR(11 downto 8)=x"E") then		-- escaped addressing mode (register)
		return RP(3 downto 0) & ADDR(7 downto 0);
	else return ADDR;						-- full address
	end if;
end ADDRESSER12;
 
-- ADDRESSER8 generates a 12-bit address from an 8-bit address (it decides when to use escaped addressing mode)
function ADDRESSER8
	(	ADDR	: in std_logic_vector(7 downto 0)) return std_logic_vector is
begin
	if (ADDR(7 downto 4)=x"E") then		-- escaped addressing mode (register)
		return RP(3 downto 0) & RP(7 downto 4) & ADDR(3 downto 0);
	else return RP(3 downto 0) & ADDR(7 downto 0);	-- full address
	end if;
end ADDRESSER8;
 
-- ADDRESSER4 generates a 12-bit address from a 4-bit address (using RP register)
function ADDRESSER4
	(	ADDR	: in std_logic_vector(3 downto 0)) return std_logic_vector is
begin
	return RP(3 downto 0) & RP(7 downto 4) & ADDR;
end ADDRESSER4;
 
-- ALU is the arithmetic and logic unit, it receives two 8-bit operands along with a 4-bit operation code and a carry input, returning an 8-bit result
function ALU
	(	ALU_OP	: in std_logic_vector(3 downto 0);
		OPER1	: in std_logic_vector(7 downto 0);
		OPER2	: in std_logic_vector(7 downto 0);
		CIN		: in STD_LOGIC) return std_logic_vector is
variable RESULT : std_logic_vector(7 downto 0);
variable HALF1,HALF2	: std_logic_vector(4 downto 0);
begin
	ALU_NOUPDATE := '0';
	case ALU_OP is
		when ALU_ADD =>		-- ADD operation **************************************************
			HALF1 := ('0'&OPER1(3 downto 0))+('0'&OPER2(3 downto 0));
			ALU_FLAGS.H := HALF1(4);
			HALF2 := ('0'&OPER1(7 downto 4))+('0'&OPER2(7 downto 4))+HALF1(4);
			RESULT := HALF2(3 downto 0) & HALF1(3 downto 0);
			ALU_FLAGS.C := HALF2(4);
			if (OPER1(7)=OPER2(7)) then
				if (OPER1(7)/=RESULT(7)) then ALU_FLAGS.V :='1'; else ALU_FLAGS.V :='0';
				end if;
			else ALU_FLAGS.V:='0';
			end if;
		when ALU_ADC =>		-- ADC operation **************************************************
			HALF1 := ('0'&OPER1(3 downto 0))+('0'&OPER2(3 downto 0)+(CIN));
			ALU_FLAGS.H := HALF1(4);
			HALF2 := ('0'&OPER1(7 downto 4))+('0'&OPER2(7 downto 4))+HALF1(4);
			RESULT := HALF2(3 downto 0) & HALF1(3 downto 0);
			ALU_FLAGS.C := HALF2(4);
			if (OPER1(7)=OPER2(7)) then
				if (OPER1(7)/=RESULT(7)) then ALU_FLAGS.V :='1'; else ALU_FLAGS.V :='0';
				end if;
			else ALU_FLAGS.V:='0';
			end if;			
		when ALU_SUB =>		-- SUB operation **************************************************
			HALF1 := ('0'&OPER1(3 downto 0))-('0'&(OPER2(3 downto 0)));
			ALU_FLAGS.H := (HALF1(4));
			HALF2 := ('0'&OPER1(7 downto 4))-('0'&(OPER2(7 downto 4)))-HALF1(4);
			RESULT := HALF2(3 downto 0) & HALF1(3 downto 0);
			ALU_FLAGS.C := (HALF2(4));
			if (OPER1(7)/=OPER2(7)) then
				if (OPER1(7)=RESULT(7)) then ALU_FLAGS.V :='1'; else ALU_FLAGS.V :='0';
				end if;
			else ALU_FLAGS.V:='0';
			end if;
		when ALU_SBC =>		-- SBC operation **************************************************
			HALF1 := ('0'&OPER1(3 downto 0))-('0'&(OPER2(3 downto 0)))-CIN;
			ALU_FLAGS.H := (HALF1(4));
			HALF2 := ('0'&OPER1(7 downto 4))-('0'&(OPER2(7 downto 4)))-HALF1(4);
			RESULT := HALF2(3 downto 0) & HALF1(3 downto 0);
			ALU_FLAGS.C := (HALF2(4));
			if (OPER1(7)/=OPER2(7)) then
				if (OPER1(7)=RESULT(7)) then ALU_FLAGS.V :='1'; else ALU_FLAGS.V :='0';
				end if;
			else ALU_FLAGS.V:='0';
			end if;	
		when ALU_OR =>	-- Logical or operation ***********************************************
			RESULT := OPER1 or OPER2;
		when ALU_AND =>	-- Logical AND operation **********************************************
			RESULT := OPER1 AND OPER2;
		when ALU_TCM => -- Test Complement Mask operation *************************************
			RESULT := (NOT OPER1) AND OPER2;
			ALU_NOUPDATE := '1';
		when ALU_TM =>	-- Test Mask operation ************************************************
			RESULT := OPER1 AND OPER2;
			ALU_NOUPDATE := '1';
		when ALU_CPC =>		-- CPC operation **************************************************
			HALF1 := ('0'&OPER1(3 downto 0))-('0'&(OPER2(3 downto 0)))-CIN;
			ALU_FLAGS.H := (HALF1(4));
			HALF2 := ('0'&OPER1(7 downto 4))-('0'&(OPER2(7 downto 4)))-HALF1(4);
			RESULT := HALF2(3 downto 0) & HALF1(3 downto 0);
			ALU_FLAGS.C := (HALF2(4));
			if (OPER1(7)/=OPER2(7)) then
				if (OPER1(7)=RESULT(7)) then ALU_FLAGS.V :='1'; else ALU_FLAGS.V :='0';
				end if;
			else ALU_FLAGS.V:='0';
			end if;
			ALU_NOUPDATE := '1';			
		when ALU_CP =>	-- Compare operation **************************************************
			HALF1 := ('0'&OPER1(3 downto 0))-('0'&(OPER2(3 downto 0)));
			ALU_FLAGS.H := (HALF1(4));
			HALF2 := ('0'&OPER1(7 downto 4))-('0'&(OPER2(7 downto 4)))-HALF1(4);
			RESULT := HALF2(3 downto 0) & HALF1(3 downto 0);
			ALU_FLAGS.C := (HALF2(4));
			if (OPER1(7)/=OPER2(7)) then
				if (OPER1(7)=RESULT(7)) then ALU_FLAGS.V :='1'; else ALU_FLAGS.V :='0';
				end if;
			else ALU_FLAGS.V:='0';
			end if;
			ALU_NOUPDATE := '1';
		when ALU_XOR =>	-- Logical xor operation **********************************************
			RESULT := OPER1 xor OPER2;
		when ALU_BSWAP =>	-- Bit Swap operation *********************************************
			RESULT := OPER2(0)&OPER2(1)&OPER2(2)&OPER2(3)&OPER2(4)&OPER2(5)&OPER2(6)&OPER2(7);			
		when others =>	-- Load operation *****************************************************
			RESULT := OPER2;
 
	end case;
	if (RESULT(7 downto 0)=x"00") then ALU_FLAGS.Z := '1'; else ALU_FLAGS.Z := '0';
	end if;
	ALU_FLAGS.S := RESULT(7);
	return RESULT(7 downto 0);
end ALU;	
 
-- LU2 is the second logic unit, it performs mostly logical operations not covered by the ALU
function LU2
	(	LU2_OP	: in std_logic_vector(3 downto 0);
		OPER	: in std_logic_vector(7 downto 0);
		DIN		: in std_logic;
		HIN		: in std_logic;
		CIN		: in std_logic) return std_logic_vector is
variable RESULT : std_logic_vector(7 downto 0);
begin
	case LU2_OP is
		when LU2_RLC =>		-- RLC operation **************************************************
			ALU_FLAGS.C := OPER(7);
			RESULT := OPER(6)&OPER(5)&OPER(4)&OPER(3)&OPER(2)&OPER(1)&OPER(0)&CIN;
		when LU2_INC =>		-- INC operation **************************************************
			RESULT := OPER+1;	
			if (RESULT=x"00") then ALU_FLAGS.C:='1'; else ALU_FLAGS.C:='0';
			end if;
		when LU2_DEC =>		-- DEC operation **************************************************
			RESULT := OPER-1;
			if (RESULT=x"FF") then ALU_FLAGS.C:='1'; else ALU_FLAGS.C:='0';
			end if;
		when LU2_DA =>		-- DA operation ***************************************************
			if (DIN='0') then	-- decimal adjust following an add operation
				if (OPER(3 downto 0)>x"9" or HIN='1') then
					RESULT := ALU(ALU_ADD,OPER,x"06",'0');
				else RESULT := OPER;
				end if;
				if (RESULT(7 downto 4)>x"9" or ALU_FLAGS.C='1') then
					RESULT := ALU(ALU_ADD,RESULT,x"60",'0');
				end if;
			else	-------------- decimal adjust following a sub operation
			end if;
		when LU2_COM =>		-- COM operation **************************************************
			RESULT := NOT OPER;
		when LU2_RL =>		-- RL operation ***************************************************
			ALU_FLAGS.C := OPER(7);
			RESULT := OPER(6)&OPER(5)&OPER(4)&OPER(3)&OPER(2)&OPER(1)&OPER(0)&ALU_FLAGS.C;
		when LU2_SRL =>		-- SRL operation **************************************************
			ALU_FLAGS.C := OPER(0);
			RESULT := '0'&OPER(7)&OPER(6)&OPER(5)&OPER(4)&OPER(3)&OPER(2)&OPER(1);				
		when LU2_RRC =>		-- RRC operation **************************************************
			ALU_FLAGS.C := OPER(0);
			RESULT := CIN&OPER(7)&OPER(6)&OPER(5)&OPER(4)&OPER(3)&OPER(2)&OPER(1);	
		when LU2_RR =>		-- RR operation ***************************************************
			ALU_FLAGS.C := OPER(0);
			RESULT := ALU_FLAGS.C&OPER(7)&OPER(6)&OPER(5)&OPER(4)&OPER(3)&OPER(2)&OPER(1);
		when LU2_SRA =>		-- SRA operation **************************************************
			ALU_FLAGS.C := OPER(0);
			RESULT := OPER(7)&OPER(7)&OPER(6)&OPER(5)&OPER(4)&OPER(3)&OPER(2)&OPER(1);					
		when LU2_SWAP =>	-- SWAP operation *************************************************
			RESULT := OPER(3)&OPER(2)&OPER(1)&OPER(0)&OPER(7)&OPER(6)&OPER(5)&OPER(4);
		when LU2_LD =>		-- LOAD operation *************************************************
			RESULT := OPER;
		when others =>		-- CLR operation **************************************************
			RESULT := x"00";
	end case;
	if (OPER(7)/=RESULT(7)) then ALU_FLAGS.V :='1'; else ALU_FLAGS.V :='0';
	end if;	
	if (RESULT=x"00") then ALU_FLAGS.Z := '1'; else ALU_FLAGS.Z := '0';
	end if;
	ALU_FLAGS.S := RESULT(7);
	return RESULT;
end LU2;
 
-- ADDER16 adds a signed 8-bit offset to a 16-bit address
function ADDER16
	(	ADDR16	: in std_logic_vector(15 downto 0);
		OFFSET	: in std_logic_vector(7 downto 0)) return std_logic_vector is
begin
	if (OFFSET(7)='0') then return ADDR16 + (x"00" & OFFSET);
	else return ADDR16 + (x"FF" & OFFSET);
	end if;
end ADDER16;
 
begin
	clock_out: process(CLK,RESET)
	variable CKDIVIDER		: integer range 0 to 2;
	begin
		if (RESET='1') then
			CKDIVIDER := 0;
			CLK_OUTN <= '1';
			CLK_OUT <= '0';
		elsif (rising_edge(CLK)) then
			CLK_OUTN <= '1';
			CLK_OUT <= '0';
			CKDIVIDER := CKDIVIDER + 1;
			if (CKDIVIDER=0) then	-- main clock (50MHz) is divided by 3, resulting in a 16.66MHz system clock
				CLK_OUT <= '1';
				CLK_OUTN <= '0';
			end if;
		end if;
	end process;	-- clock_out process
	-- main process controls debugging and instruction fetching and decoding along
	main: process (CLK_OUT,RESET,DBG_RX)
	-- CPU state machine
	type Tcpu_state is (
		CPU_DECOD,
		CPU_INDRR,						-- indirect rr mode
		CPU_MUL, CPU_MUL1, CPU_MUL2,	-- MUL instruction
		CPU_XADTOM,						-- address with offset to memory
		CPU_MTOXAD, CPU_MTOXAD2,		-- memory to address with offset
		CPU_XRTOM,						-- register with offset to memory
		CPU_XRRTORR, CPU_XRRTORR2,		-- register pair with offset to register pair
		CPU_XRRTORR3, CPU_XRRTORR4,
		CPU_IMTOIRR, CPU_MTOIRR,		-- indirect and direct to indirect register pair addressing mode
		CPU_IRRS, CPU_IRRS2,			-- indirect register pair as source
		CPU_XRRD, CPU_XRRD2, CPU_XRRD3,	-- indexed rr pair as destination
		CPU_XRRS, CPU_XRRS2, CPU_XRRS3,	-- indexed rr pair as source
		CPU_IND1, CPU_IND2,				-- indirect memory access
		CPU_ISMD1,						-- indirect source to memory destination
		CPU_TMA,						-- Two memory access instructions (register to/with register)
		CPU_OMA,						-- One memory access instructions (immediate to/with register)
		CPU_OMA2,						-- One memory access instructions (immediate to/with register) logic unit related
		CPU_DMAB,						-- Decrement address bus (for word access)
		CPU_LDW, CPU_LDW2, CPU_LDW3,	-- load word instruction
		CPU_LDW4, CPU_LDW5,
		CPU_LDPTOIM, CPU_LDPTOIM2,		-- load program to indirect memory
		CPU_LDPTOM, CPU_LDPTOM2,		-- load program to memory
		CPU_LDPTOM3, CPU_LDPTOM4,		
		CPU_LDMTOP, CPU_LDMTOP2,		-- load memory to program
		CPU_BIT,						-- BIT instruction
		CPU_IBTJ, CPU_BTJ,				-- BTJ instruction
		CPU_DJNZ,						-- DJNZ instruction
		CPU_INDJUMP, CPU_INDJUMP2,		-- indirect JP
		CPU_TRAP, CPU_TRAP2,			-- TRAP instruction
		CPU_INDSTACK, CPU_INDSTACK2,	-- indirect stacking
		CPU_STACK, CPU_STACK1,			-- stacking operations
		CPU_STACK2, CPU_STACK3,
		CPU_UNSTACK, CPU_UNSTACK2,		-- unstacking operations
		CPU_UNSTACK3,					
		CPU_STORE,						-- store results, no change to the flags
		CPU_VECTOR, CPU_VECTOR2,		-- vectoring stages
		CPU_RESET,						-- reset state
		CPU_ILLEGAL						-- illegal state
	);
	type Tfetch_state is (
		F_ADDR,		-- instruction queue is initializing, reset pointers and empty queue
		F_READ		-- instruction queue is fetching opcodes
	);
	type Tdbg_uartrxstate is (
		DBGST_NOSYNC,			-- debug UART receiver is not synchronized to the host
		DBGST_WAITSTART,		-- debug UART receiver is waiting for a 0x80 char
		DBGST_MEASURING,		-- debug UART receiver is measuring a possible sync char
		DBGST_IDLE,				-- debug UART receiver is synchronized and awaiting commands
		DBGST_START,			-- debug UART received a start bit
		DBGST_RECEIVING,		-- debug UART is receiving new command/data
		DBGST_ERROR				-- debug UART receiver is in error state
	);
	type Tdbg_uarttxstate is (
		DBGTX_INIT,				-- debug UART transmitter is initializing
		DBGTX_IDLE,				-- debug UART transmitter is waiting new data to transmit
		DBGTX_START,			-- debug UART transmitter is sending a start bit
		DBGTX_TRASMITTING,		-- debug UART transmitter is sending data
		DBGTX_BREAK, 			-- debug UART transmitter is preparing to send a break
		DBGTX_BREAK2			-- debug UART is waiting for the break complete
	);
	type Tdbg_command is (
		DBG_WAIT_CMD,							-- debugger is waiting for commands
		DBG_SEND_REV, DBG_SEND_REV2,			-- debugger is processing a read revision command
		DBG_SEND_STATUS,						-- debugger is processing a read OCDST command
		DBG_WRITE_CTRL,							-- debugger is processing a write OCDCTRL command
		DBG_SEND_CTRL,							-- debugger is processing a read OCDCTRL command
		DBG_WRITE_PC, DBG_WRITE_PC2,			-- debugger is processing a PC write command
		DBG_SEND_PC, DBG_SEND_PC2,				-- debugger is processing a PC read command
		DBG_WRITE_REG, DBG_READ_REG,			-- debugger is processing a read/write to registers
		DBG_REG, DBG_REG2, DBG_REG3, 			-- debugger is processing a read/write to registers
		DBG_REG4, DBG_REG5,						-- debugger is processing a read/write to registers
		DBG_WRITE_PROGMEM, DBG_READ_PROGMEM,	-- debugger is processing a read/write to program memory
		DBG_PROGMEM, DBG_PROGMEM2, 				-- debugger is processing a read/write to program memory
		DBG_PROGMEM3, DBG_PROGMEM4, 			-- debugger is processing a read/write to program memory
		DBG_PROGMEM5, DBG_PROGMEM6,				-- debugger is processing a read/write to program memory
		DBG_STEP, 								-- debugger is processing a step command
		DBG_STUFF, 								-- debugger is processing a stuff command
		DBG_EXEC, DBG_EXEC2, DBG_EXEC3			-- debugger is processing a execute command
	);
	type Tdbg_uart is record
		RX_STATE	: Tdbg_uartrxstate;
		TX_STATE	: Tdbg_uarttxstate;
		RX_DONE		: std_logic;						-- new data is available
		TX_EMPTY	: std_logic;						-- tx buffer is empty
		DBG_SYNC	: std_logic;						-- debugger is synchronized to host
		WRT			: std_logic;						-- write/read command flag
		LAST_SMP	: std_logic;						-- last sample read from DBG_RX pin
		SIZE		: std_logic_vector(15 downto 0);	-- 16-bit size of command
		TXSHIFTREG	: std_logic_vector(8 downto 0);		-- transmitter shift register
		RXSHIFTREG	: std_logic_vector(8 downto 0);		-- receiver shift register
		TX_DATA		: std_logic_vector(7 downto 0);		-- TX buffer
		RX_DATA		: std_logic_vector(7 downto 0);		-- RX buffer
		RXCNT		: integer range 0 to 15;			-- received bit counter
		TXCNT		: integer range 0 to 15;			-- transmitted bit counter
		BAUDPRE		: integer range 0 to 2;				-- baud prescaler
		BAUDCNTRX	: std_logic_vector(11 downto 0);	-- RX baud divider
		BAUDCNTTX	: std_logic_vector(11 downto 0);	-- TX baud divider
		BITTIMERX	: std_logic_vector(11 downto 0);	-- RX bit-time register (1/2 bit-time)
		BITTIMETX	: std_logic_vector(11 downto 0);	-- TX bit-time register
	end record;
	variable CPU_STATE 		: TCPU_STATE;  						-- current CPU state 
	variable DBG_UART		: Tdbg_uart;
	variable DBG_CMD		: Tdbg_command;
	variable CAN_FETCH		: std_logic;						-- controls whether the instruction queue can actually fetch opcodes
	variable LU_INSTRUCTION	: std_logic;						-- indicates a LU2-related instruction
	variable INT_FLAG		: std_logic;						-- indicates an interrupt
	variable WORD_DATA		: std_logic;						-- indicates a 16-bit data instruction
	variable HALT			: std_logic;						-- indicates the CPU is halted
	variable PC 			: std_logic_vector(15 downto 0);	-- program counter
	variable FETCH_ADDR		: std_logic_vector(15 downto 0);	-- next address to be fetched
	variable DEST_ADDR16	: std_logic_vector(15 downto 0);	-- temporary 16-bit destination address
	variable DEST_ADDR		: std_logic_vector(11 downto 0);	-- temporary 12-bit destination address
	variable TEMP_DATA		: std_logic_vector(7 downto 0);		-- temporary 8-bit data
	variable OLD_IRQ0		: std_logic_vector(7 downto 0);		-- previous state of IRQ inputs
	variable INTVECT		: std_logic_vector(7 downto 0);		-- current interrupt vector (lower 8-bits)
	variable RESULT			: std_logic_vector(7 downto 0);		-- temporary 8-bit result
	variable TEMP_OP		: std_logic_vector(3 downto 0);		-- ALU/LU2 operation code
	variable ATM_COUNTER	: integer range 0 to 3;				-- temporary interrupt disable counter (ATM instruction)
	variable NUM_BYTES		: integer range 0 to 5;				-- number of bytes decoded
	type Tinstructionqueue is record
		WRPOS				: integer range 0 to 7;				-- instruction queue write pointer
		RDPOS				: integer range 0 to 7;				-- instruction queue read pointer
		CNT					: integer range 0 to 7;				-- instruction queue available bytes
		FETCH_STATE			: tfetch_state;		
		QUEUE				: Tinstqueue;
		FULL				: std_logic;						-- indicates whether the queue is full or not
	end record;
	variable IQUEUE			: Tinstructionqueue;
	type Tocdcr is record
		DBGMODE				: std_logic;
		BRKEN				: std_logic;
		DBGACK				: std_logic;
		BRKLOOP				: std_logic;
		RST					: std_logic;
	end record;
	variable OCDCR			: Tocdcr;
	type Tocdflags is record
		SINGLESTEP			: std_logic;
	end record;
	variable OCD			: Tocdflags;
 
	begin
		RESET_OUT <= RESET or OCDCR.RST;
		if (RESET='1') then	-- reset operations		
			IAB <= x"0002";
			FRAB <= x"000";
			IWDB <= x"00";
			SP := x"000";
			RP := x"00";
			WR <= '0';
			PGM_WR <= '0';
			STOP <= '0';
			CAN_FETCH := '1';
			FETCH_ADDR := x"0000";
			DBG_UART.RX_STATE := DBGST_NOSYNC;
			DBG_UART.TX_STATE := DBGTX_INIT;
			OCDCR.DBGMODE := '0';
			OCDCR.BRKEN := '0';
			OCDCR.DBGACK := '0';
			OCDCR.BRKLOOP := '0';				
			OCD.SINGLESTEP := '0';
			OCDCR.RST := '0';
			RXSYNC1 <= '1';
			RXSYNC2 <= '1';
			DBG_UART.LAST_SMP := '1';
			IQUEUE.FETCH_STATE := F_ADDR;
			IRQE := '0';
			IRQ0 := x"00";
			OLD_IRQ0 := x"00";
			IRQ0ENH := x"00";
			IRQ0ENL := x"00";
			ATM_COUNTER := 0;
			CPU_STATE := CPU_VECTOR;			
		elsif (rising_edge(CLK_OUT)) then
			IRQ0_LATCH <= INT7&INT6&INT5&INT4&INT3&INT2&INT1&INT0;
			if (OLD_IRQ0(0)/=IRQ0_LATCH(0)) then IRQ0(0) := '1'; end if;
			if (OLD_IRQ0(1)/=IRQ0_LATCH(1)) then IRQ0(1) := '1'; end if;
			if (OLD_IRQ0(2)/=IRQ0_LATCH(2)) then IRQ0(2) := '1'; end if;
			if (OLD_IRQ0(3)/=IRQ0_LATCH(3)) then IRQ0(3) := '1'; end if;
			if (OLD_IRQ0(4)/=IRQ0_LATCH(4)) then IRQ0(4) := '1'; end if;
			if (OLD_IRQ0(5)/=IRQ0_LATCH(5)) then IRQ0(5) := '1'; end if;
			if (OLD_IRQ0(6)/=IRQ0_LATCH(6)) then IRQ0(6) := '1'; end if;
			if (OLD_IRQ0(7)/=IRQ0_LATCH(7)) then IRQ0(7) := '1'; end if;
			OLD_IRQ0 := IRQ0_LATCH;
 
			WR <= '0';
			PGM_WR <= '0';
 
			-- start of instruction queue FSM
			if (CAN_FETCH='1') then
				if (IQUEUE.FETCH_STATE=F_ADDR) then
					FETCH_ADDR := PC;
					IAB <= PC;
					IQUEUE.WRPOS := 0;
					IQUEUE.RDPOS := 0;
					IQUEUE.CNT := 0;						
					IQUEUE.FETCH_STATE := F_READ;
				else
					if (IQUEUE.FULL='0') then
						IQUEUE.QUEUE(IQUEUE.WRPOS) := IDB;
						FETCH_ADDR := FETCH_ADDR + 1;
						IAB <= FETCH_ADDR;
						IQUEUE.WRPOS := IQUEUE.WRPOS + 1;
						IQUEUE.CNT := IQUEUE.CNT + 1;
					end if;
				end if;
			end if;
			if (IQUEUE.CNT=7) then IQUEUE.FULL:='1'; else IQUEUE.FULL:='0'; 
			end if;
			-- end of instruction queue FSM	
 
			-- start of debugger UART
			DBG_UART.BAUDPRE := DBG_UART.BAUDPRE+1;	-- baudrate prescaler
			if (DBG_UART.BAUDPRE=0) then 
				DBG_UART.BAUDCNTRX := DBG_UART.BAUDCNTRX+1;
				DBG_UART.BAUDCNTTX := DBG_UART.BAUDCNTTX+1;
			end if;
			RXSYNC2 <= DBG_RX;		-- DBG_RX input synchronization
			RXSYNC1 <= RXSYNC2;		-- RXSYNC1 is a synchronized DBG_RX signal
			case DBG_UART.RX_STATE is
				when DBGST_NOSYNC =>
					DBG_UART.DBG_SYNC := '0';
					DBG_UART.RX_DONE := '0';
					DBG_CMD := DBG_WAIT_CMD;
					DBG_UART.RX_STATE := DBGST_WAITSTART;
				when DBGST_WAITSTART =>
					if (RXSYNC1='0' and DBG_UART.LAST_SMP='1') then
						DBG_UART.RX_STATE := DBGST_MEASURING;
						DBG_UART.BAUDCNTRX := x"000";
					end if;
				when DBGST_MEASURING =>
					if (DBG_UART.BAUDCNTRX/=x"FFF") then 
						if (RXSYNC1='1') then
							DBG_UART.DBG_SYNC := '1';
							DBG_UART.RX_STATE := DBGST_IDLE;
							DBG_UART.BITTIMERX := "0000"&DBG_UART.BAUDCNTRX(11 downto 4);
							DBG_UART.BITTIMETX := "000"&DBG_UART.BAUDCNTRX(11 downto 3);
						end if;
					else
						DBG_UART.RX_STATE := DBGST_NOSYNC;
					end if;
				when DBGST_IDLE =>
					DBG_UART.BAUDCNTRX:=x"000";
					DBG_UART.RXCNT:=0;
					if (RXSYNC1='0' and DBG_UART.LAST_SMP='1') then	-- it's a start bit
						DBG_UART.RX_STATE := DBGST_START;				
					end if;
				when DBGST_START =>
					if (DBG_UART.BAUDCNTRX=DBG_UART.BITTIMERX) then
						DBG_UART.BAUDCNTRX:=x"000";
						if (RXSYNC1='0') then
							DBG_UART.RX_STATE := DBGST_RECEIVING;
						else
							DBG_UART.RX_STATE := DBGST_ERROR;
							DBG_UART.TX_STATE := DBGTX_BREAK;
						end if;
					end if;
				when DBGST_RECEIVING =>
					if (DBG_UART.BAUDCNTRX=DBG_UART.BITTIMETX) then
						DBG_UART.BAUDCNTRX:=x"000";
						-- one bit time elapsed, sample RX input
						DBG_UART.RXSHIFTREG := RXSYNC1 & DBG_UART.RXSHIFTREG(8 downto 1);
						DBG_UART.RXCNT := DBG_UART.RXCNT + 1;
						if (DBG_UART.RXCNT=9) then
							if (RXSYNC1='1') then
								-- if the stop bit is 1, rx is completed ok
								DBG_UART.RX_DATA := DBG_UART.RXSHIFTREG(7 downto 0);
								DBG_UART.RX_DONE := '1';
								DBG_UART.RX_STATE := DBGST_IDLE;
							else
								-- if the stop bit is 0, it is a break char, reset receiver
								DBG_UART.RX_STATE := DBGST_ERROR;
								DBG_UART.TX_STATE := DBGTX_BREAK;
							end if;
						end if;
					end if;
				when others =>
			end case;
			DBG_UART.LAST_SMP := RXSYNC1;
			case DBG_UART.TX_STATE is
				when DBGTX_INIT =>
					DBG_UART.TX_EMPTY := '1';
					DBG_UART.TX_STATE:=DBGTX_IDLE;
				when DBGTX_IDLE =>	-- UART is idle and not transmitting
					DBG_TX <= '1';
					if (DBG_UART.TX_EMPTY='0' and DBG_UART.DBG_SYNC='1') then	-- there is new data in TX_DATA register
						DBG_UART.BAUDCNTTX:=x"000";
						DBG_UART.TX_STATE := DBGTX_START;
					end if;
				when DBGTX_START =>
					if (DBG_UART.BAUDCNTTX=DBG_UART.BITTIMETX) then
						DBG_UART.BAUDCNTTX:=x"000";
						DBG_UART.TXSHIFTREG := '1'&DBG_UART.TX_DATA;
						DBG_UART.TXCNT := 10;
						DBG_UART.TX_STATE := DBGTX_TRASMITTING;
						DBG_TX <= '0';
					end if;
				when DBGTX_TRASMITTING =>	-- UART is shifting data
					if (DBG_UART.BAUDCNTTX=DBG_UART.BITTIMETX) then
						DBG_UART.BAUDCNTTX:=x"000";
						DBG_TX <= DBG_UART.TXSHIFTREG(0);
						DBG_UART.TXSHIFTREG := '1'&DBG_UART.TXSHIFTREG(8 downto 1);
						DBG_UART.TXCNT :=DBG_UART.TXCNT - 1;
						if (DBG_UART.TXCNT=0) then 
							DBG_UART.TX_STATE:=DBGTX_IDLE;
							DBG_UART.TX_EMPTY := '1';
						end if;
					end if;
				when DBGTX_BREAK =>					
					DBG_UART.BAUDCNTTX:=x"000";
					DBG_UART.TX_STATE:=DBGTX_BREAK2;
				when DBGTX_BREAK2 =>
					DBG_TX <= '0';
					DBG_UART.RX_STATE := DBGST_NOSYNC;
					if (DBG_UART.BAUDCNTTX=x"FFF") then	
						DBG_UART.TX_STATE:=DBGTX_INIT;
					end if;
			end case;		
			if (RXSYNC1='0') then DBG_TX <='0';	-- this mimics open-collector feature of OCD communication
			end if;
			-- end of the debugger UART		
 
			-- This is the instruction decoder
			case CPU_STATE IS	
				when CPU_DECOD =>
					TEMP_OP := ALU_LD;					-- default ALU operation is load
					LU_INSTRUCTION := '0';				-- default is ALU operation (instead of LU2)
					INT_FLAG := '0';					-- reset temporary interrupt flag
					WORD_DATA := '0';					-- default is 8-bit operation
					INTVECT := x"00";					-- default vector is 0x00
					NUM_BYTES := 0;						-- default instruction length is 0 bytes
 
					-- start of debugger command processor
					case DBG_CMD is
						when DBG_WAIT_CMD =>
							if (DBG_UART.RX_DONE='1') then
								case DBG_UART.RX_DATA is
									when DBGCMD_READ_REV =>		DBG_CMD := DBG_SEND_REV;
									when DBGCMD_READ_STATUS =>	DBG_CMD := DBG_SEND_STATUS;
									when DBGCMD_WRITE_CTRL =>	DBG_CMD := DBG_WRITE_CTRL;
									when DBGCMD_READ_CTRL =>	DBG_CMD := DBG_SEND_CTRL;
									when DBGCMD_WRITE_PC =>		DBG_CMD := DBG_WRITE_PC;
									when DBGCMD_READ_PC =>		DBG_CMD := DBG_SEND_PC;
									when DBGCMD_WRITE_REG =>	DBG_CMD := DBG_WRITE_REG;
									when DBGCMD_READ_REG =>		DBG_CMD := DBG_READ_REG;
									when DBGCMD_WRITE_PROGRAM=>	DBG_CMD := DBG_WRITE_PROGMEM;
									when DBGCMD_READ_PROGRAM=>	DBG_CMD := DBG_READ_PROGMEM;
									when DBGCMD_STEP =>			DBG_CMD := DBG_STEP;
									when DBGCMD_STUFF =>		DBG_CMD := DBG_STUFF;
									when DBGCMD_EXEC =>			DBG_CMD := DBG_EXEC;
									when others =>				
								end case;
								DBG_UART.RX_DONE:='0';
							end if;
						when DBG_SEND_REV =>	-- read revision first byte
							if (DBG_UART.TX_EMPTY='1') then
								DBG_UART.TX_DATA:=x"01";
								DBG_UART.TX_EMPTY:='0';
								DBG_CMD := DBG_SEND_REV2;
							end if;
						when DBG_SEND_REV2 =>	-- read revision second byte
							if (DBG_UART.TX_EMPTY='1') then
								DBG_UART.TX_DATA:=x"00";
								DBG_UART.TX_EMPTY:='0';
								DBG_CMD := DBG_WAIT_CMD;
							end if;
						when DBG_SEND_STATUS =>	-- read OCD status
							if (DBG_UART.TX_EMPTY='1') then
								DBG_UART.TX_DATA:=OCDCR.DBGMODE&HALT&"000000";
								DBG_UART.TX_EMPTY:='0';
								DBG_CMD := DBG_WAIT_CMD;
							end if;
						when DBG_WRITE_CTRL =>	-- write OCD control register
							if (DBG_UART.RX_DONE='1') then
								DBG_UART.RX_DONE:='0';
								OCDCR.DBGMODE := DBG_UART.RX_DATA(7);
								OCDCR.BRKEN := DBG_UART.RX_DATA(6);
								OCDCR.DBGACK := DBG_UART.RX_DATA(5);
								OCDCR.BRKLOOP := DBG_UART.RX_DATA(4);
								OCDCR.RST := DBG_UART.RX_DATA(0);
								if (OCDCR.RST='1') then CPU_STATE:=CPU_RESET;
								end if;
								DBG_CMD := DBG_WAIT_CMD;
							end if;
						when DBG_SEND_CTRL =>	-- read OCD control register
							if (DBG_UART.TX_EMPTY='1') then
								DBG_UART.TX_DATA:=OCDCR.DBGMODE&OCDCR.BRKEN&OCDCR.DBGACK&OCDCR.BRKLOOP&"000"&OCDCR.RST;
								DBG_UART.TX_EMPTY:='0';
								DBG_CMD := DBG_WAIT_CMD;
							end if;			
						when DBG_WRITE_PC =>	-- write PC high byte
							if (DBG_UART.RX_DONE='1' and OCDCR.DBGMODE='1') then
								DBG_UART.RX_DONE:='0';
								CAN_FETCH := '0';
								PC(15 downto 8) := DBG_UART.RX_DATA;
								DBG_CMD := DBG_WRITE_PC2;
							end if;
						when DBG_WRITE_PC2 =>	-- write PC low byte
							if (DBG_UART.RX_DONE='1') then
								DBG_UART.RX_DONE:='0';
								PC(7 downto 0) := DBG_UART.RX_DATA;
								IQUEUE.FETCH_STATE := F_ADDR;
								IQUEUE.CNT := 0;
								CAN_FETCH := '1';
								DBG_CMD := DBG_WAIT_CMD;
							end if;
						when DBG_SEND_PC =>		-- read PC high byte
							if (DBG_UART.TX_EMPTY='1') then
								DBG_UART.TX_DATA:=PC(15 downto 8);
								DBG_UART.TX_EMPTY:='0';
								DBG_CMD := DBG_SEND_PC2;
							end if;
						when DBG_SEND_PC2 =>	-- read PC high byte
							if (DBG_UART.TX_EMPTY='1') then
								DBG_UART.TX_DATA:=PC(7 downto 0);
								DBG_UART.TX_EMPTY:='0';
								DBG_CMD := DBG_WAIT_CMD;
							end if;					
						when DBG_WRITE_REG =>	-- write to SFR/user registers
							DBG_UART.WRT := '1';
							DBG_CMD := DBG_REG;
						when DBG_READ_REG =>	-- read SFR/user registers
							DBG_UART.WRT := '0';
							DBG_CMD := DBG_REG;					
						when DBG_REG =>			-- proceed with register read/write
							if (DBG_UART.RX_DONE='1' and OCDCR.DBGMODE='1') then
								FRAB(11 downto 8) <= DBG_UART.RX_DATA(3 downto 0);
								DBG_UART.RX_DONE:='0';
								DBG_CMD := DBG_REG2;
							end if;
						when DBG_REG2 =>
							if (DBG_UART.RX_DONE='1') then
								FRAB(7 downto 0) <= DBG_UART.RX_DATA;
								DBG_UART.RX_DONE:='0';
								DBG_CMD := DBG_REG3;
							end if;
						when DBG_REG3 =>
							if (DBG_UART.RX_DONE='1') then
								DBG_UART.SIZE := x"00"&DBG_UART.RX_DATA;
								DBG_UART.RX_DONE:='0';
								DBG_CMD := DBG_REG4;
							end if;
						when DBG_REG4 =>
							if (DBG_UART.WRT='1') then
								if (DBG_UART.RX_DONE='1') then
									CPU_STATE := CPU_OMA;
									TEMP_DATA := DBG_UART.RX_DATA;
									DBG_UART.RX_DONE:='0';
									DBG_CMD := DBG_REG5;
								end if;
							else
								if (DBG_UART.TX_EMPTY='1') then
									DBG_UART.TX_DATA:=DATAREAD(FRAB);
									DBG_UART.TX_EMPTY:='0';
									DBG_CMD := DBG_REG5;
								end if;
							end if;
						when DBG_REG5 =>
							FRAB <= FRAB + 1;
							DBG_UART.SIZE := DBG_UART.SIZE - 1;
							if (DBG_UART.SIZE=x"0000") then
								DBG_CMD := DBG_WAIT_CMD; 
							else DBG_CMD := DBG_REG4;
							end if;
						when DBG_WRITE_PROGMEM =>
							DBG_UART.WRT := '1';
							DBG_CMD := DBG_PROGMEM;
						when DBG_READ_PROGMEM =>
							DBG_UART.WRT := '0';
							DBG_CMD := DBG_PROGMEM;					
						when DBG_PROGMEM =>
							if (DBG_UART.RX_DONE='1') then
								CAN_FETCH := '0';
								IAB(15 downto 8) <= DBG_UART.RX_DATA;
								DBG_UART.RX_DONE:='0';
								DBG_CMD := DBG_PROGMEM2;
							end if;
						when DBG_PROGMEM2 =>
							if (DBG_UART.RX_DONE='1') then
								IAB(7 downto 0) <= DBG_UART.RX_DATA;
								DBG_UART.RX_DONE:='0';
								DBG_CMD := DBG_PROGMEM3;
							end if;					
						when DBG_PROGMEM3 =>
							if (DBG_UART.RX_DONE='1') then
								DBG_UART.SIZE(15 downto 8) := DBG_UART.RX_DATA;
								DBG_UART.RX_DONE:='0';
								DBG_CMD := DBG_PROGMEM4;
							end if;					
						when DBG_PROGMEM4 =>
							if (DBG_UART.RX_DONE='1') then
								DBG_UART.SIZE(7 downto 0) := DBG_UART.RX_DATA;
								DBG_UART.RX_DONE:='0';
								DBG_CMD := DBG_PROGMEM5;
							end if;
						when DBG_PROGMEM5 =>
							if (DBG_UART.WRT='1') then
								if (DBG_UART.RX_DONE='1') then
									IWDB <= DBG_UART.RX_DATA;
									DBG_UART.RX_DONE:='0';
									PGM_WR <= '1';
									DBG_CMD := DBG_PROGMEM6;
								end if;
							else
								if (DBG_UART.TX_EMPTY='1') then
									DBG_UART.TX_DATA:=IDB;
									DBG_UART.TX_EMPTY:='0';
									DBG_CMD := DBG_PROGMEM6;
								end if;
							end if;
						when DBG_PROGMEM6 =>
							IAB <= IAB + 1;
							DBG_UART.SIZE := DBG_UART.SIZE - 1;
							if (DBG_UART.SIZE=x"0000") then 
								DBG_CMD := DBG_WAIT_CMD; 
								CAN_FETCH := '1';
								IQUEUE.CNT := 0;
								IQUEUE.FETCH_STATE := F_ADDR;						
							else DBG_CMD := DBG_PROGMEM5;
							end if;
						when DBG_STEP =>
							OCD.SINGLESTEP:='1';
							IQUEUE.FETCH_STATE := F_ADDR;
							DBG_CMD := DBG_WAIT_CMD;
						when DBG_STUFF =>
							if (DBG_UART.RX_DONE='1' and OCDCR.DBGMODE='1') then
								IQUEUE.QUEUE(IQUEUE.RDPOS) := DBG_UART.RX_DATA;
								DBG_UART.RX_DONE:='0';
								DBG_CMD := DBG_STEP;
							end if;
						when DBG_EXEC =>
							if (OCDCR.DBGMODE='1') then
								OCD.SINGLESTEP:='1';
								CAN_FETCH:='0';
								IQUEUE.CNT := 0;
								IQUEUE.FETCH_STATE := F_ADDR;
							end if;
							DBG_CMD := DBG_EXEC2;
						when DBG_EXEC2 =>
							if (DBG_UART.RX_DONE='1') then
								if (OCDCR.DBGMODE='0') then DBG_CMD := DBG_WAIT_CMD;
								else
									IQUEUE.QUEUE(IQUEUE.WRPOS) := DBG_UART.RX_DATA;
									DBG_UART.RX_DONE:='0';
									IQUEUE.WRPOS := IQUEUE.WRPOS + 1;
									IQUEUE.CNT := IQUEUE.CNT + 1;
									DBG_CMD := DBG_EXEC3;
								end if;
							end if;
						when DBG_EXEC3 =>
							if (OCD.SINGLESTEP='1') then DBG_CMD := DBG_EXEC2; else 
								DBG_CMD := DBG_WAIT_CMD;
								IQUEUE.FETCH_STATE := F_ADDR;
							end if;
						when others =>
					end case;
					-- end of debugger command processor
 
					if (ATM_COUNTER/=3) then ATM_COUNTER := ATM_COUNTER+1;
					else	-- interrupt processing *****************************************************************************
						if (IRQE='1') then	-- if interrupts are enabled
							-- first the highest priority level interrupts
							if ((IRQ0(7)='1') and (IRQ0ENH(7)='1') and IRQ0ENL(7)='1') then
								INTVECT:=x"08";
								IRQ0(7):='0';
							elsif ((IRQ0(6)='1') and (IRQ0ENH(6)='1') and IRQ0ENL(6)='1') then 
								INTVECT:=x"0A";
								IRQ0(6):='0';
							elsif ((IRQ0(5)='1') and (IRQ0ENH(5)='1') and IRQ0ENL(5)='1') then 
								INTVECT:=x"0C";
								IRQ0(5):='0';
							elsif ((IRQ0(4)='1') and (IRQ0ENH(4)='1') and IRQ0ENL(4)='1') then 
								INTVECT:=x"0E";
								IRQ0(4):='0';
							elsif ((IRQ0(3)='1') and (IRQ0ENH(3)='1') and IRQ0ENL(3)='1') then 
								INTVECT:=x"10";
								IRQ0(3):='0';
							elsif ((IRQ0(2)='1') and (IRQ0ENH(2)='1') and IRQ0ENL(2)='1') then 
								INTVECT:=x"12";
								IRQ0(2):='0';
							elsif ((IRQ0(1)='1') and (IRQ0ENH(1)='1') and IRQ0ENL(1)='1') then 
								INTVECT:=x"14";
								IRQ0(1):='0';
							elsif ((IRQ0(0)='1') and (IRQ0ENH(0)='1') and IRQ0ENL(0)='1') then 
								INTVECT:=x"16";
								IRQ0(0):='0';
							-- now priority level 2 interrupts
							elsif ((IRQ0(7)='1') and (IRQ0ENH(7)='1') and IRQ0ENL(7)='0') then
								INTVECT:=x"08";
								IRQ0(7):='0';
							elsif ((IRQ0(6)='1') and (IRQ0ENH(6)='1') and IRQ0ENL(6)='0') then 
								INTVECT:=x"0A";
								IRQ0(6):='0';
							elsif ((IRQ0(5)='1') and (IRQ0ENH(5)='1') and IRQ0ENL(5)='0') then 
								INTVECT:=x"0C";
								IRQ0(5):='0';
							elsif ((IRQ0(4)='1') and (IRQ0ENH(4)='1') and IRQ0ENL(4)='0') then 
								INTVECT:=x"0E";
								IRQ0(4):='0';
							elsif ((IRQ0(3)='1') and (IRQ0ENH(3)='1') and IRQ0ENL(3)='0') then 
								INTVECT:=x"10";
								IRQ0(3):='0';
							elsif ((IRQ0(2)='1') and (IRQ0ENH(2)='1') and IRQ0ENL(2)='0') then 
								INTVECT:=x"12";
								IRQ0(2):='0';
							elsif ((IRQ0(1)='1') and (IRQ0ENH(1)='1') and IRQ0ENL(1)='0') then 
								INTVECT:=x"14";
								IRQ0(1):='0';
							elsif ((IRQ0(0)='1') and (IRQ0ENH(0)='1') and IRQ0ENL(0)='0') then 
								INTVECT:=x"16";
								IRQ0(0):='0';
							-- now priority level 1 interrupts
							elsif ((IRQ0(7)='1') and (IRQ0ENH(7)='0') and IRQ0ENL(7)='1') then
								INTVECT:=x"08";
								IRQ0(7):='0';
							elsif ((IRQ0(6)='1') and (IRQ0ENH(6)='0') and IRQ0ENL(6)='1') then 
								INTVECT:=x"0A";
								IRQ0(6):='0';
							elsif ((IRQ0(5)='1') and (IRQ0ENH(5)='0') and IRQ0ENL(5)='1') then 
								INTVECT:=x"0C";
								IRQ0(5):='0';
							elsif ((IRQ0(4)='1') and (IRQ0ENH(4)='0') and IRQ0ENL(4)='1') then 
								INTVECT:=x"0E";
								IRQ0(4):='0';
							elsif ((IRQ0(3)='1') and (IRQ0ENH(3)='0') and IRQ0ENL(3)='1') then 
								INTVECT:=x"10";
								IRQ0(3):='0';
							elsif ((IRQ0(2)='1') and (IRQ0ENH(2)='0') and IRQ0ENL(2)='1') then 
								INTVECT:=x"12";
								IRQ0(2):='0';
							elsif ((IRQ0(1)='1') and (IRQ0ENH(1)='0') and IRQ0ENL(1)='1') then 
								INTVECT:=x"14";
								IRQ0(1):='0';
							elsif ((IRQ0(0)='1') and (IRQ0ENH(0)='0') and IRQ0ENL(0)='1') then 
								INTVECT:=x"16";
								IRQ0(0):='0';						
							end if;
							if (INTVECT/=x"00") then
								if (OCDCR.DBGMODE='0' or (OCDCR.DBGMODE='1' and OCD.SINGLESTEP='1')) then
									DEST_ADDR16 := PC;
									IAB <= x"00"&INTVECT;	-- build the interrupt vector address
									SP := SP - 1;			-- prepare stack pointer by decrementing it
									FRAB <= SP;				-- put SP on FRAB
									CAN_FETCH := '0';		-- disable instruction fetching
									OCD.SINGLESTEP := '0';	-- disable stepping
									IQUEUE.CNT := 0;		-- set queue empty
									STOP <= '0';			-- disable stop bit
									HALT := '0';			-- disable halt mode
									INT_FLAG := '1';		-- signal it is an interrupt stacking operation
									CPU_STATE := CPU_VECTOR;
								end if;
							end if;
						end if; -- if IRQE=1
					end if;	-- if ATM_COUNTER...
					if (STOP='0' and HALT='0') then
						if (OCDCR.DBGMODE='0' or (OCDCR.DBGMODE='1' and OCD.SINGLESTEP='1')) then
							------------------------------------------------------------------------------------------------------------------------------
							--**************************************************************************************************************************--
							--                                                     5-byte instructions                                                  --
							--**************************************************************************************************************************--
							------------------------------------------------------------------------------------------------------------------------------
							if (IQUEUE.CNT>=5) then	-- 5-byte instructions
								---------------------------------------------------------------------------------------------------- 2nd page instructions
								if (IQUEUE.QUEUE(IQUEUE.RDPOS)=x"1F") then
									---------------------------------------------------------------------------------------------- CPC ER2,ER1 instruction
									if (IQUEUE.QUEUE(IQUEUE.RDPOS+1)=x"A8") then
										FRAB <= ADDRESSER12((IQUEUE.QUEUE(IQUEUE.RDPOS+3)(3 downto 0)) & IQUEUE.QUEUE(IQUEUE.RDPOS+4));
										DEST_ADDR := ADDRESSER12((IQUEUE.QUEUE(IQUEUE.RDPOS+2)) & IQUEUE.QUEUE(IQUEUE.RDPOS+3)(7 downto 4));
										TEMP_OP := ALU_CPC;
										NUM_BYTES := 5;
										CPU_STATE := CPU_TMA;
									---------------------------------------------------------------------------------------------- CPC IMM,ER1 instruction
									elsif (IQUEUE.QUEUE(IQUEUE.RDPOS+1)=x"A9") then
										FRAB <= ADDRESSER12((IQUEUE.QUEUE(IQUEUE.RDPOS+3)(3 downto 0)) & IQUEUE.QUEUE(IQUEUE.RDPOS+4));
										TEMP_DATA := IQUEUE.QUEUE(IQUEUE.RDPOS+2);
										TEMP_OP := ALU_CPC;
										NUM_BYTES := 5;
										CPU_STATE := CPU_OMA;
									--------------------------------------------------------------------------------------------- LDWX ER1,ER2 instruction
									elsif (IQUEUE.QUEUE(IQUEUE.RDPOS+1)=x"E8") then
										FRAB <= ADDRESSER12((IQUEUE.QUEUE(IQUEUE.RDPOS+2)) & IQUEUE.QUEUE(IQUEUE.RDPOS+3)(7 downto 4));
										DEST_ADDR := ADDRESSER12((IQUEUE.QUEUE(IQUEUE.RDPOS+3)(3 downto 0)) & IQUEUE.QUEUE(IQUEUE.RDPOS+4));
										NUM_BYTES := 5;
										CPU_STATE := CPU_LDW;						
									end if;
								end if;
							end if;
 
							------------------------------------------------------------------------------------------------------------------------------
							--**************************************************************************************************************************--
							--                                                     4-byte instructions                                                  --
							--**************************************************************************************************************************--
							------------------------------------------------------------------------------------------------------------------------------
							if (IQUEUE.CNT>=4) then	-- 4-byte instructions
								if (IQUEUE.QUEUE(IQUEUE.RDPOS)(3 downto 0)=x"9") then	------------------------------------------------ column 9 instructions
									case IQUEUE.QUEUE(IQUEUE.RDPOS)(7 downto 4) is
										when x"8" =>	------------------------------------------------------------------------- LDX rr1,r2,X instruction
										when x"9" =>	------------------------------------------------------------------------ LEA rr1,rr2,X instruction
										when x"C" =>
											CPU_STATE := CPU_ILLEGAL;
										when x"D" =>
											CPU_STATE := CPU_ILLEGAL;
										when x"F" =>
											CPU_STATE := CPU_ILLEGAL;
										when others =>	-------------------------------------------------------------- IM,ER1 addressing mode instructions
											FRAB <= ADDRESSER12((IQUEUE.QUEUE(IQUEUE.RDPOS+2)(3 downto 0)) & IQUEUE.QUEUE(IQUEUE.RDPOS+3));
											TEMP_DATA := IQUEUE.QUEUE(IQUEUE.RDPOS+1);
											TEMP_OP := IQUEUE.QUEUE(IQUEUE.RDPOS)(7 downto 4);
											NUM_BYTES := 4;
											CPU_STATE := CPU_OMA;																		
									end case;						
								elsif (IQUEUE.QUEUE(IQUEUE.RDPOS)(3 downto 0)=x"8") then	-------------------------------------------- column 8 instructions
									case IQUEUE.QUEUE(IQUEUE.RDPOS)(7 downto 4) is
										when x"8" =>	------------------------------------------------------------------------- LDX r1,rr2,X instruction
										when x"9" =>	-------------------------------------------------------------------------- LEA r1,r2,X instruction
										when x"C" =>	-------------------------------------------------------------------------------- PUSHX instruction
										when x"D" =>	--------------------------------------------------------------------------------- POPX instruction
										when x"F" =>
											CPU_STATE := CPU_ILLEGAL;
										when others =>	------------------------------------------------------------- ER2,ER1 addressing mode instructions
											FRAB <= ADDRESSER12((IQUEUE.QUEUE(IQUEUE.RDPOS+1)) & IQUEUE.QUEUE(IQUEUE.RDPOS+2)(7 downto 4));
											DEST_ADDR := ADDRESSER12((IQUEUE.QUEUE(IQUEUE.RDPOS+2)(3 downto 0)) & IQUEUE.QUEUE(IQUEUE.RDPOS+3));
											TEMP_OP := IQUEUE.QUEUE(IQUEUE.RDPOS)(7 downto 4);
											NUM_BYTES := 4;
											CPU_STATE := CPU_TMA;																			
									end case;
								---------------------------------------------------------------------------------------------------- 2nd page instructions
								elsif (IQUEUE.QUEUE(IQUEUE.RDPOS)=x"1F") then
									------------------------------------------------------------------------------------------------ CPC R2,R1 instruction
									TEMP_OP := ALU_CPC;
									if (IQUEUE.QUEUE(IQUEUE.RDPOS+1)=x"A4") then
										FRAB <= ADDRESSER8(IQUEUE.QUEUE(IQUEUE.RDPOS+3));
										DEST_ADDR := ADDRESSER8(IQUEUE.QUEUE(IQUEUE.RDPOS+2));
										NUM_BYTES := 4;
										CPU_STATE := CPU_TMA;
									----------------------------------------------------------------------------------------------- CPC IR2,R1 instruction
									elsif (IQUEUE.QUEUE(IQUEUE.RDPOS+1)=x"A5") then
										DEST_ADDR := ADDRESSER8(IQUEUE.QUEUE(IQUEUE.RDPOS+3));
										FRAB <= ADDRESSER8(IQUEUE.QUEUE(IQUEUE.RDPOS+2));
										NUM_BYTES := 4;
										CPU_STATE := CPU_ISMD1;
									----------------------------------------------------------------------------------------------- CPC R1,IMM instruction
									elsif (IQUEUE.QUEUE(IQUEUE.RDPOS+1)=x"A6") then
										FRAB <= ADDRESSER8(IQUEUE.QUEUE(IQUEUE.RDPOS+2));
										TEMP_DATA := IQUEUE.QUEUE(IQUEUE.RDPOS+3);
										NUM_BYTES := 4;
										CPU_STATE := CPU_OMA;
									---------------------------------------------------------------------------------------------- CPC IR1,IMM instruction
									elsif (IQUEUE.QUEUE(IQUEUE.RDPOS+1)=x"A7") then
										FRAB <= ADDRESSER8(IQUEUE.QUEUE(IQUEUE.RDPOS+2));
										TEMP_DATA := IQUEUE.QUEUE(IQUEUE.RDPOS+3);
										NUM_BYTES := 4;
										CPU_STATE := CPU_IND1;						
									end if;
								end if;
							end if;
 
							------------------------------------------------------------------------------------------------------------------------------
							--**************************************************************************************************************************--
							--                                                     3-byte instructions                                                  --
							--**************************************************************************************************************************--
							------------------------------------------------------------------------------------------------------------------------------
							if (IQUEUE.CNT>=3) then	-- 3-byte instructions
								if (IQUEUE.QUEUE(IQUEUE.RDPOS)(3 downto 0)=x"D") then	-------------------------------------------------- JP cc,DirectAddress
									if (CONDITIONCODE(IQUEUE.QUEUE(IQUEUE.RDPOS)(7 downto 4))='1') then 
										PC := IQUEUE.QUEUE(IQUEUE.RDPOS+1) & IQUEUE.QUEUE(IQUEUE.RDPOS+2);
										IQUEUE.FETCH_STATE := F_ADDR;
									else
										NUM_BYTES := 3;
									end if;
								elsif (IQUEUE.QUEUE(IQUEUE.RDPOS)(3 downto 0)=x"9") then	-------------------------------------------- column 9 instructions
									if (IQUEUE.QUEUE(IQUEUE.RDPOS)(7 downto 4)=x"8") then	----------------------------------------- LDX rr1,r2,X instruction
										FRAB <= ADDRESSER4(IQUEUE.QUEUE(IQUEUE.RDPOS+1)(3 downto 0));							-- source address				
										DEST_ADDR := ADDRESSER4(IQUEUE.QUEUE(IQUEUE.RDPOS+1)(7 downto 4));						-- dest address
										RESULT := IQUEUE.QUEUE(IQUEUE.RDPOS+2);													-- RESULT = offset (X)
										NUM_BYTES := 3;
										CPU_STATE := CPU_XRRD;
									elsif (IQUEUE.QUEUE(IQUEUE.RDPOS)(7 downto 4)=x"9") then	------------------------------------ LEA rr1,rr2,X instruction
										FRAB <= ADDRESSER4(IQUEUE.QUEUE(IQUEUE.RDPOS+1)(3 downto 0));							-- source address				
										DEST_ADDR := ADDRESSER4(IQUEUE.QUEUE(IQUEUE.RDPOS+1)(7 downto 4));						-- dest address
										RESULT := IQUEUE.QUEUE(IQUEUE.RDPOS+2);
										NUM_BYTES := 3;
										CPU_STATE := CPU_XRRTORR;
									end if;
								elsif (IQUEUE.QUEUE(IQUEUE.RDPOS)(3 downto 0)=x"8") then	-------------------------------------------- column 8 instructions
									if (IQUEUE.QUEUE(IQUEUE.RDPOS)(7 downto 4)=x"8") then	----------------------------------------- LDX r1,rr2,X instruction
										FRAB <= ADDRESSER4(IQUEUE.QUEUE(IQUEUE.RDPOS+1)(3 downto 0));							-- source address				
										DEST_ADDR := ADDRESSER4(IQUEUE.QUEUE(IQUEUE.RDPOS+1)(7 downto 4));						-- dest address
										RESULT := IQUEUE.QUEUE(IQUEUE.RDPOS+2);													-- RESULT = offset (X)
										NUM_BYTES := 3;
										CPU_STATE := CPU_XRRS;
									elsif (IQUEUE.QUEUE(IQUEUE.RDPOS)(7 downto 4)=x"9") then	-------------------------------------- LEA r1,r2,X instruction
										FRAB <= ADDRESSER4(IQUEUE.QUEUE(IQUEUE.RDPOS+1)(3 downto 0));							-- source address				
										DEST_ADDR := ADDRESSER4(IQUEUE.QUEUE(IQUEUE.RDPOS+1)(7 downto 4));						-- dest address
										RESULT := IQUEUE.QUEUE(IQUEUE.RDPOS+2);
										NUM_BYTES := 3;
										CPU_STATE := CPU_XRTOM;						
									elsif (IQUEUE.QUEUE(IQUEUE.RDPOS)(7 downto 4)=x"C") then	---------------------------------------- PUSHX ER2 instruction
										SP := SP - 1;
										FRAB <= ADDRESSER12(IQUEUE.QUEUE(IQUEUE.RDPOS+1)&IQUEUE.QUEUE(IQUEUE.RDPOS+2)(7 downto 4));
										DEST_ADDR := SP;
										NUM_BYTES := 3;
										CPU_STATE := CPU_TMA;
									elsif (IQUEUE.QUEUE(IQUEUE.RDPOS)(7 downto 4)=x"D") then	----------------------------------------- POPX ER2 instruction
										FRAB <= SP;
										DEST_ADDR := ADDRESSER12(IQUEUE.QUEUE(IQUEUE.RDPOS+1)&IQUEUE.QUEUE(IQUEUE.RDPOS+2)(7 downto 4));
										SP := SP + 1;
										NUM_BYTES := 3;
										CPU_STATE := CPU_TMA;
									end if;
								elsif (IQUEUE.QUEUE(IQUEUE.RDPOS)(3 downto 0)=x"7") then	-------------------------------------------- column 7 instructions
									case IQUEUE.QUEUE(IQUEUE.RDPOS)(7 downto 4) is
										when x"8" =>	------------------------------------------------------------------------- LDX IRR2,IR1 instruction
											FRAB <= ADDRESSER8(IQUEUE.QUEUE(IQUEUE.RDPOS+1));
											DEST_ADDR := ADDRESSER8(IQUEUE.QUEUE(IQUEUE.RDPOS+2));
											NUM_BYTES := 3;
											CPU_STATE := CPU_IRRS;
										when x"9" =>	------------------------------------------------------------------------- LDX IR2,IRR1 instruction
											FRAB <= ADDRESSER8(IQUEUE.QUEUE(IQUEUE.RDPOS+1));
											DEST_ADDR := ADDRESSER8(IQUEUE.QUEUE(IQUEUE.RDPOS+2));
											NUM_BYTES := 3;
											CPU_STATE := CPU_IMTOIRR;
										when x"C" =>	--------------------------------------------------------------------------- LD r1,r2,X instruction
											FRAB <= ADDRESSER4(IQUEUE.QUEUE(IQUEUE.RDPOS+1)(3 downto 0));							-- source address				
											DEST_ADDR := ADDRESSER4(IQUEUE.QUEUE(IQUEUE.RDPOS+1)(7 downto 4));						-- dest address
											RESULT := IQUEUE.QUEUE(IQUEUE.RDPOS+2);													-- RESULT = offset (X)
											NUM_BYTES := 3;
											CPU_STATE := CPU_XADTOM;
										when x"D" =>	--------------------------------------------------------------------------- LD r2,r1,X instruction
											FRAB <= RP(3 downto 0) & RP(7 downto 4) & IQUEUE.QUEUE(IQUEUE.RDPOS+1)(7 downto 4);
											DEST_ADDR := RP(3 downto 0) & RP(7 downto 4) & IQUEUE.QUEUE(IQUEUE.RDPOS+1)(3 downto 0);
											RESULT := IQUEUE.QUEUE(IQUEUE.RDPOS+2);
											NUM_BYTES := 3;
											CPU_STATE := CPU_MTOXAD;
										when x"F" =>	------------------------------------------------------------------------ BTJ p,b,Ir1,X instruction
										when others =>	----------------------------------------------------------------------------- IR1,imm instructions
											FRAB <= ADDRESSER8(IQUEUE.QUEUE(IQUEUE.RDPOS+1));
											TEMP_DATA := IQUEUE.QUEUE(IQUEUE.RDPOS+2);
											TEMP_OP := IQUEUE.QUEUE(IQUEUE.RDPOS)(7 downto 4);
											NUM_BYTES := 3;
											CPU_STATE := CPU_IND1;																				
									end case;						
								elsif (IQUEUE.QUEUE(IQUEUE.RDPOS)(3 downto 0)=x"6") then	-------------------------------------------- column 6 instructions
									case IQUEUE.QUEUE(IQUEUE.RDPOS)(7 downto 4) is
										when x"8" =>	-------------------------------------------------------------------------- LDX IRR2,R1 instruction
											FRAB <= ADDRESSER8(IQUEUE.QUEUE(IQUEUE.RDPOS+1));
											DEST_ADDR := ADDRESSER8(IQUEUE.QUEUE(IQUEUE.RDPOS+2));
											NUM_BYTES := 3;
											LU_INSTRUCTION := '1';	-- in this mode this flag is used to signal the direct register addressing mode
											CPU_STATE := CPU_IRRS;								
										when x"9" =>	-------------------------------------------------------------------------- LDX R2,IRR1 instruction
											FRAB <= ADDRESSER8(IQUEUE.QUEUE(IQUEUE.RDPOS+1));
											DEST_ADDR := ADDRESSER8(IQUEUE.QUEUE(IQUEUE.RDPOS+2));
											NUM_BYTES := 3;
											CPU_STATE := CPU_MTOIRR;
										when x"C" =>	-- illegal, decoded at 1-byte decoder
											--CPU_STATE := CPU_ILLEGAL;	-- uncommenting this adds +400 LEs to the design!!!
										when x"D" =>	------------------------------------------------------------------------------ CALL DA instruction
										when x"F" =>	------------------------------------------------------------------------- BTJ p,b,r1,X instruction
										when others =>	------------------------------------------------------------------------------ R1,imm instructions
											FRAB <= ADDRESSER8(IQUEUE.QUEUE(IQUEUE.RDPOS+1));
											TEMP_DATA := IQUEUE.QUEUE(IQUEUE.RDPOS+2);
											TEMP_OP := IQUEUE.QUEUE(IQUEUE.RDPOS)(7 downto 4);
											NUM_BYTES := 3;
											CPU_STATE := CPU_OMA;																				
									end case;						
								elsif (IQUEUE.QUEUE(IQUEUE.RDPOS)(3 downto 0)=x"5") then	-------------------------------------------- column 5 instructions
									case IQUEUE.QUEUE(IQUEUE.RDPOS)(7 downto 4) is
										when x"8" =>	-------------------------------------------------------------------------- LDX Ir1,ER2 instruction
											FRAB <= IQUEUE.QUEUE(IQUEUE.RDPOS+1)(3 downto 0) & IQUEUE.QUEUE(IQUEUE.RDPOS+2);				
											DEST_ADDR := ADDRESSER4(IQUEUE.QUEUE(IQUEUE.RDPOS+1)(7 downto 4));					-- dest address
											NUM_BYTES := 3;
											CPU_STATE := CPU_IND2;
										when x"9" =>	-------------------------------------------------------------------------- LDX Ir2,ER1 instruction
											FRAB <= RP(3 downto 0) & RP(7 downto 4) & IQUEUE.QUEUE(IQUEUE.RDPOS+1)(7 downto 4);
											DEST_ADDR := IQUEUE.QUEUE(IQUEUE.RDPOS+1)(3 downto 0) & IQUEUE.QUEUE(IQUEUE.RDPOS+2);
											NUM_BYTES := 3;
											CPU_STATE := CPU_ISMD1;								
										when x"C" =>	------------------------------------------------------------------------- LDC Ir1,Irr2 instruction
										when x"D" =>	----------------------------------------------------------------------------- BSWAP R1 instruction
										when x"F" =>	---------------------------------------------------------------------------- LD R2,IR1 instruction
										when others =>	------------------------------------------------------------------------------ IR2,R1 instructions
											DEST_ADDR := ADDRESSER8(IQUEUE.QUEUE(IQUEUE.RDPOS+2));
											FRAB <= ADDRESSER8(IQUEUE.QUEUE(IQUEUE.RDPOS+1));
											TEMP_OP := IQUEUE.QUEUE(IQUEUE.RDPOS)(7 downto 4);
											NUM_BYTES := 3;
											CPU_STATE := CPU_ISMD1;																				
									end case;						
								elsif (IQUEUE.QUEUE(IQUEUE.RDPOS)(3 downto 0)=x"4") then	-------------------------------------------- column 4 instructions
									case IQUEUE.QUEUE(IQUEUE.RDPOS)(7 downto 4) is
										when x"8" =>	--------------------------------------------------------------------------- LDX r1,ER2 instruction
											FRAB <= IQUEUE.QUEUE(IQUEUE.RDPOS+1)(3 downto 0) & IQUEUE.QUEUE(IQUEUE.RDPOS+2);			
											DEST_ADDR := ADDRESSER4(IQUEUE.QUEUE(IQUEUE.RDPOS+1)(7 downto 4));					-- dest address
											NUM_BYTES := 3;
											CPU_STATE := CPU_TMA;							
										when x"9" =>	--------------------------------------------------------------------------- LDX r2,ER1 instruction
											FRAB <= RP(3 downto 0) & RP(7 downto 4) & IQUEUE.QUEUE(IQUEUE.RDPOS+1)(7 downto 4);
											DEST_ADDR := IQUEUE.QUEUE(IQUEUE.RDPOS+1)(3 downto 0) & IQUEUE.QUEUE(IQUEUE.RDPOS+2);
											NUM_BYTES := 3;
											CPU_STATE := CPU_TMA;							
										when x"C" =>	------------------------------------------------------------------------------ JP Irr1 instruction
										when x"D" =>	---------------------------------------------------------------------------- CALL Irr1 instruction
										when x"F" =>	----------------------------------------------------------------------------- MULT RR1 instruction
										when others =>	------------------------------------------------------------------------------- R2,R1 instructions
											FRAB <= ADDRESSER8(IQUEUE.QUEUE(IQUEUE.RDPOS+1));
											DEST_ADDR := ADDRESSER8(IQUEUE.QUEUE(IQUEUE.RDPOS+2));
											TEMP_OP := IQUEUE.QUEUE(IQUEUE.RDPOS)(7 downto 4);
											NUM_BYTES := 3;
											CPU_STATE := CPU_TMA;																				
									end case;					
								end if;
								------------------------------------------------------------------------------------------------- BTJ p,b,r1,X instruction
								------------------------------------------------------------------------------------------------ BTJ p,b,Ir1,X instruction
								if (IQUEUE.QUEUE(IQUEUE.RDPOS)=x"F6" or IQUEUE.QUEUE(IQUEUE.RDPOS)=x"F7") then
									FRAB <= ADDRESSER4(IQUEUE.QUEUE(IQUEUE.RDPOS+1)(3 downto 0));							-- source address				
									TEMP_OP := IQUEUE.QUEUE(IQUEUE.RDPOS+1)(7 downto 4);	-- TEMP_OP has the polarity (bit 3) and bit number (bits 2:0)
									RESULT := IQUEUE.QUEUE(IQUEUE.RDPOS+2);					-- RESULT has the offset X
									NUM_BYTES := 3;
									if (IQUEUE.QUEUE(IQUEUE.RDPOS)(0)='0') then CPU_STATE := CPU_BTJ;	else CPU_STATE := CPU_IBTJ;
									end if;
								---------------------------------------------------------------------------------------------------- LD R2,IR1 instruction
								elsif (IQUEUE.QUEUE(IQUEUE.RDPOS)=x"F5") then
									FRAB <= ADDRESSER8(IQUEUE.QUEUE(IQUEUE.RDPOS+1));
									DEST_ADDR := ADDRESSER8(IQUEUE.QUEUE(IQUEUE.RDPOS+2));
									NUM_BYTES := 3;
									CPU_STATE := CPU_IND2;						
								------------------------------------------------------------------------------------------------------ CALL DA instruction
								elsif (IQUEUE.QUEUE(IQUEUE.RDPOS)=x"D6") then
									DEST_ADDR16 := PC + 3;
									PC := IQUEUE.QUEUE(IQUEUE.RDPOS+1) & IQUEUE.QUEUE(IQUEUE.RDPOS+2);
									SP := SP - 1;
									FRAB <= SP;				
									LU_INSTRUCTION := '0';	-- this is used to indicate wether the stacking is due to a CALL or INT, 0 for a CALL
									IQUEUE.FETCH_STATE := F_ADDR;
									CPU_STATE := CPU_STACK;
								---------------------------------------------------------------------------------------------------- 2nd page instructions
								elsif (IQUEUE.QUEUE(IQUEUE.RDPOS)=x"1F") then
									-------------------------------------------------------------------------------------------------- PUSH IM instruction
									if (IQUEUE.QUEUE(IQUEUE.RDPOS+1)=x"70") then
										SP := SP - 1;
										FRAB <= SP;
										TEMP_DATA := IQUEUE.QUEUE(IQUEUE.RDPOS+2);
										NUM_BYTES := 3;
										CPU_STATE := CPU_OMA;
									------------------------------------------------------------------------------------------------ CPC r1,r2 instruction
									elsif (IQUEUE.QUEUE(IQUEUE.RDPOS+1)=x"A2") then
										FRAB <= ADDRESSER4(IQUEUE.QUEUE(IQUEUE.RDPOS+2)(3 downto 0));							-- source address				
										DEST_ADDR := ADDRESSER4(IQUEUE.QUEUE(IQUEUE.RDPOS+2)(7 downto 4));						-- dest address
										TEMP_OP := ALU_CPC;
										NUM_BYTES := 3;
										CPU_STATE := CPU_TMA;
									----------------------------------------------------------------------------------------------- CPC r1,Ir2 instruction
									elsif (IQUEUE.QUEUE(IQUEUE.RDPOS+1)=x"A3") then
										FRAB <= ADDRESSER4(IQUEUE.QUEUE(IQUEUE.RDPOS+2)(3 downto 0));							-- source address				
										DEST_ADDR := ADDRESSER4(IQUEUE.QUEUE(IQUEUE.RDPOS+2)(7 downto 4));						-- dest address
										TEMP_OP := ALU_CPC;
										NUM_BYTES := 3;
										CPU_STATE := CPU_ISMD1;
									--------------------------------------------------------------------------------------------------- SRL R1 instruction
									elsif (IQUEUE.QUEUE(IQUEUE.RDPOS+1)=x"C0") then
										FRAB <= ADDRESSER8(IQUEUE.QUEUE(IQUEUE.RDPOS+2));
										TEMP_OP := LU2_SRL;
										NUM_BYTES := 3;
										CPU_STATE := CPU_OMA2;
									-------------------------------------------------------------------------------------------------- SRL IR1 instruction
									elsif (IQUEUE.QUEUE(IQUEUE.RDPOS+1)=x"C1") then
										FRAB <= ADDRESSER8(IQUEUE.QUEUE(IQUEUE.RDPOS+2));
										TEMP_OP := LU2_SRL;
										NUM_BYTES := 3;
										CPU_STATE := CPU_IND1;
										LU_INSTRUCTION := '1';						
									end if;
								end if;
							end if;
 
							------------------------------------------------------------------------------------------------------------------------------
							--**************************************************************************************************************************--
							--                                                     2-byte instructions                                                  --
							--**************************************************************************************************************************--
							------------------------------------------------------------------------------------------------------------------------------
							if (IQUEUE.CNT>=2) then	-- 2-byte instructions
								if (IQUEUE.QUEUE(IQUEUE.RDPOS)(3 downto 0)=x"C") then	------------------------------------------------- LD r,IMM instruction
									FRAB <= ADDRESSER4(IQUEUE.QUEUE(IQUEUE.RDPOS)(7 downto 4));
									DATAWRITE(ADDRESSER4(IQUEUE.QUEUE(IQUEUE.RDPOS)(7 downto 4)),IQUEUE.QUEUE(IQUEUE.RDPOS+1));
									NUM_BYTES := 2;
									CPU_STATE := CPU_STORE;
								elsif (IQUEUE.QUEUE(IQUEUE.RDPOS)(3 downto 0)=x"B") then	-------------------------------------------- JR cc,RelativeAddress
									PC := PC + 2;
									if (CONDITIONCODE(IQUEUE.QUEUE(IQUEUE.RDPOS)(7 downto 4))='1') then
										PC := ADDER16(PC,IQUEUE.QUEUE(IQUEUE.RDPOS+1));
										IQUEUE.FETCH_STATE := F_ADDR;
									else
										IQUEUE.RDPOS := IQUEUE.RDPOS + 2;
										IQUEUE.CNT := IQUEUE.CNT - 2;							
									end if;
									CPU_STATE := CPU_DECOD;
								elsif (IQUEUE.QUEUE(IQUEUE.RDPOS)(3 downto 0)=x"A") then	------------------------------------------- DJNZ r,RelativeAddress
									FRAB <= ADDRESSER4(IQUEUE.QUEUE(IQUEUE.RDPOS)(7 downto 4));
									PC := PC + 2;
									DEST_ADDR16 := ADDER16(PC,IQUEUE.QUEUE(IQUEUE.RDPOS+1)); 					
									IQUEUE.RDPOS := IQUEUE.RDPOS + 2;
									IQUEUE.CNT := IQUEUE.CNT - 2;
									IQUEUE.FETCH_STATE := F_ADDR;
									CPU_STATE := CPU_DJNZ;
								elsif (IQUEUE.QUEUE(IQUEUE.RDPOS)(3 downto 0)=x"3") then	-------------------------------------------- column 3 instructions
									case IQUEUE.QUEUE(IQUEUE.RDPOS)(7 downto 4) is
										when x"8" =>	------------------------------------------------------------------------ LDEI Ir1,Irr2 instruction
										when x"9" =>	------------------------------------------------------------------------ LDEI Ir2,Irr1 instruction
										when x"C" =>	------------------------------------------------------------------------ LDCI Ir1,Irr2 instruction
											RESULT(3 downto 0) := IQUEUE.QUEUE(IQUEUE.RDPOS+1)(3 downto 0);
											FRAB <= ADDRESSER4(IQUEUE.QUEUE(IQUEUE.RDPOS+1)(7 downto 4));
											NUM_BYTES := 2;
											CAN_FETCH := '0';
											LU_INSTRUCTION := '0';	-- indicates it is a read from program memory
											WORD_DATA := '1';		-- indicates it is a LDCI instruction
											CPU_STATE := CPU_LDPTOIM;
										when x"D" =>	------------------------------------------------------------------------ LDCI Ir2,Irr1 instruction
											RESULT(3 downto 0) := IQUEUE.QUEUE(IQUEUE.RDPOS+1)(3 downto 0);
											FRAB <= ADDRESSER4(IQUEUE.QUEUE(IQUEUE.RDPOS+1)(7 downto 4));
											NUM_BYTES := 2;
											CAN_FETCH := '0';
											LU_INSTRUCTION := '1';	-- indicates it is a write onto program memory
											WORD_DATA := '1';		-- indicates it is a LDCI instruction
											CPU_STATE := CPU_LDPTOIM;
										when x"F" =>	---------------------------------------------------------------------------- LD Ir1,r2 instruction
											FRAB <= ADDRESSER4(IQUEUE.QUEUE(IQUEUE.RDPOS+1)(3 downto 0));
											DEST_ADDR := ADDRESSER4(IQUEUE.QUEUE(IQUEUE.RDPOS+1)(7 downto 4));
											NUM_BYTES := 2;
											CPU_STATE := CPU_IND2;
										when others =>	--------------------------------------------------------------------------- Ir2 to r1 instructions
											FRAB <= ADDRESSER4(IQUEUE.QUEUE(IQUEUE.RDPOS+1)(3 downto 0));							-- source address				
											DEST_ADDR := ADDRESSER4(IQUEUE.QUEUE(IQUEUE.RDPOS+1)(7 downto 4));						-- dest address
											TEMP_OP := IQUEUE.QUEUE(IQUEUE.RDPOS)(7 downto 4);
											NUM_BYTES := 2;
											CPU_STATE := CPU_ISMD1;						
									end case;						
								elsif (IQUEUE.QUEUE(IQUEUE.RDPOS)(3 downto 0)=x"2") then	-------------------------------------------- column 2 instructions
									case IQUEUE.QUEUE(IQUEUE.RDPOS)(7 downto 4) is
										when x"8" =>	-------------------------------------------------------------------------- LDE r1,Irr2 instruction
										when x"9" =>	-------------------------------------------------------------------------- LDE r2,Irr1 instruction
										when x"C" =>	-------------------------------------------------------------------------- LDC r1,Irr2 instruction
											FRAB <= ADDRESSER4(IQUEUE.QUEUE(IQUEUE.RDPOS+1)(3 downto 0));
											DEST_ADDR := ADDRESSER4(IQUEUE.QUEUE(IQUEUE.RDPOS+1)(7 downto 4));
											NUM_BYTES := 2;
											CAN_FETCH := '0';
											LU_INSTRUCTION := '0';
											CPU_STATE := CPU_LDPTOM;
										when x"D" =>	-------------------------------------------------------------------------- LDC r2,Irr1 instruction
											FRAB <= ADDRESSER4(IQUEUE.QUEUE(IQUEUE.RDPOS+1)(3 downto 0));
											DEST_ADDR := ADDRESSER4(IQUEUE.QUEUE(IQUEUE.RDPOS+1)(7 downto 4));
											NUM_BYTES := 2;
											CAN_FETCH := '0';
											LU_INSTRUCTION := '1';
											CPU_STATE := CPU_LDPTOM;
										when x"E" =>	--------------------------------------------------------------------------- BIT p,b,r1 instruction
											FRAB <= ADDRESSER4(IQUEUE.QUEUE(IQUEUE.RDPOS+1)(3 downto 0));
											TEMP_OP := IQUEUE.QUEUE(IQUEUE.RDPOS+1)(7 downto 4);	-- TEMP_OP has the polarity (bit 3) and bit number (bits 2:0)
											RESULT := IQUEUE.QUEUE(IQUEUE.RDPOS+2);					-- RESULT has the offset X
											NUM_BYTES := 2;
											CPU_STATE := CPU_BIT;
										when x"F" =>	----------------------------------------------------------------------------- TRAP imm instruction
											FRAB <= "000" & IQUEUE.QUEUE(IQUEUE.RDPOS+1) & '0';
											DEST_ADDR16 := PC + 2;
											NUM_BYTES := 2;
											CPU_STATE := CPU_TRAP;
										when others =>	---------------------------------------------------------------------------- r2 to r1 instructions
											FRAB <= ADDRESSER4(IQUEUE.QUEUE(IQUEUE.RDPOS+1)(3 downto 0));							-- source address				
											DEST_ADDR := ADDRESSER4(IQUEUE.QUEUE(IQUEUE.RDPOS+1)(7 downto 4));						-- dest address
											TEMP_OP := IQUEUE.QUEUE(IQUEUE.RDPOS)(7 downto 4);
											NUM_BYTES := 2;
											CPU_STATE := CPU_TMA;					
									end case;						
								elsif (IQUEUE.QUEUE(IQUEUE.RDPOS)(3 downto 0)=x"1") then	-------------------------------------------- column 1 instructions
									case IQUEUE.QUEUE(IQUEUE.RDPOS)(7 downto 4) is
										when x"0" =>	------------------------------------------------------------------------------ SRP IMM instruction	
											RP := IQUEUE.QUEUE(IQUEUE.RDPOS+1);
											NUM_BYTES := 2;
											CPU_STATE := CPU_DECOD;
										when x"5" =>	------------------------------------------------------------------------------ POP IR1 instruction
											FRAB <= SP;
											DEST_ADDR := ADDRESSER8(IQUEUE.QUEUE(IQUEUE.RDPOS+1));
											SP := SP + 1;
											NUM_BYTES := 2;
											CPU_STATE := CPU_IND2;								
										when x"7" =>	----------------------------------------------------------------------------- PUSH IR1 instruction
											SP := SP - 1;
											FRAB <= ADDRESSER8(IQUEUE.QUEUE(IQUEUE.RDPOS+1));
											DEST_ADDR := SP;
											NUM_BYTES := 2;
											CPU_STATE := CPU_ISMD1;								
										when x"8" =>	--------------------------------------------------------------------------------- DECW instruction
											FRAB <= ADDRESSER8(IQUEUE.QUEUE(IQUEUE.RDPOS+1));
											TEMP_OP := LU2_DEC;
											WORD_DATA := '1';
											NUM_BYTES := 2;
											CPU_STATE := CPU_INDRR;							
										when x"A" =>	--------------------------------------------------------------------------------- INCW instruction
											FRAB <= ADDRESSER8(IQUEUE.QUEUE(IQUEUE.RDPOS+1));
											TEMP_OP := LU2_INC;
											WORD_DATA := '1';
											NUM_BYTES := 2;
											CPU_STATE := CPU_INDRR;
										when others =>	--------------------------------------------------------------------------------- IR1 instructions
											FRAB <= ADDRESSER8(IQUEUE.QUEUE(IQUEUE.RDPOS+1));
											TEMP_OP := IQUEUE.QUEUE(IQUEUE.RDPOS)(7 downto 4);
											NUM_BYTES := 2;
											CPU_STATE := CPU_IND1;
											LU_INSTRUCTION := '1';
									end case;
								elsif (IQUEUE.QUEUE(IQUEUE.RDPOS)(3 downto 0)=x"0") then	-------------------------------------------- column 0 instructions
									case IQUEUE.QUEUE(IQUEUE.RDPOS)(7 downto 4) is
										when x"0" =>	---------------------------------------------------------------------------------- BRK instruction	
											-- do nothing, BRK decoding is done in 1-byte instruction section
										when x"5" =>	---------------------------------------------------------------------------------- POP instruction
											FRAB <= SP;
											DEST_ADDR := ADDRESSER8(IQUEUE.QUEUE(IQUEUE.RDPOS+1));
											SP := SP + 1;
											NUM_BYTES := 2;
											CPU_STATE := CPU_TMA;
										when x"7" =>	--------------------------------------------------------------------------------- PUSH instruction
											SP := SP - 1;
											FRAB <= ADDRESSER8(IQUEUE.QUEUE(IQUEUE.RDPOS+1));
											DEST_ADDR := SP;
											NUM_BYTES := 2;
											CPU_STATE := CPU_TMA;							
										when x"8" =>	--------------------------------------------------------------------------------- DECW instruction
											DEST_ADDR := ADDRESSER8(IQUEUE.QUEUE(IQUEUE.RDPOS+1));
											FRAB <= DEST_ADDR+1;
											TEMP_OP := LU2_DEC;
											WORD_DATA := '1';
											NUM_BYTES := 2;
											CPU_STATE := CPU_OMA2;							
										when x"A" =>	--------------------------------------------------------------------------------- INCW instruction
											DEST_ADDR := ADDRESSER8(IQUEUE.QUEUE(IQUEUE.RDPOS+1));
											FRAB <= DEST_ADDR+1;
											TEMP_OP := LU2_INC;
											WORD_DATA := '1';
											NUM_BYTES := 2;
											CPU_STATE := CPU_OMA2;
										when others =>	---------------------------------------------------------------------------------- R1 instructions
											FRAB <= ADDRESSER8(IQUEUE.QUEUE(IQUEUE.RDPOS+1));
											TEMP_OP := IQUEUE.QUEUE(IQUEUE.RDPOS)(7 downto 4);
											NUM_BYTES := 2;
											CPU_STATE := CPU_OMA2;
									end case;
								end if;	
								---------------------------------------------------------------------------------------------------------- MUL instruction 
								if (IQUEUE.QUEUE(IQUEUE.RDPOS)=x"F4") then
									FRAB <= ADDRESSER8(IQUEUE.QUEUE(IQUEUE.RDPOS+1));
									NUM_BYTES := 2;
									CPU_STATE := CPU_MUL;
								---------------------------------------------------------------------------------------------------- CALL IRR1 instruction
								elsif (IQUEUE.QUEUE(IQUEUE.RDPOS)=x"D4") then
									DEST_ADDR16 := PC + 2;
									FRAB <= ADDRESSER8(IQUEUE.QUEUE(IQUEUE.RDPOS+1));
									IQUEUE.FETCH_STATE := F_ADDR;
									CPU_STATE := CPU_INDSTACK;
								------------------------------------------------------------------------------------------------------ JP IRR1 instruction
								elsif (IQUEUE.QUEUE(IQUEUE.RDPOS)=x"C4") then
									FRAB <= ADDRESSER8(IQUEUE.QUEUE(IQUEUE.RDPOS+1));
									IQUEUE.FETCH_STATE := F_ADDR;
									CPU_STATE := CPU_INDJUMP;
								----------------------------------------------------------------------------------------------------- BSWAP R1 instruction
								elsif (IQUEUE.QUEUE(IQUEUE.RDPOS)=x"D5") then
									FRAB <= ADDRESSER8(IQUEUE.QUEUE(IQUEUE.RDPOS+1));
									TEMP_OP := ALU_BSWAP;
									NUM_BYTES := 2;
									CPU_STATE := CPU_OMA;
								------------------------------------------------------------------------------------------------- LDC Ir1,Irr2 instruction
								elsif (IQUEUE.QUEUE(IQUEUE.RDPOS)=x"C5") then
									RESULT(3 downto 0) := IQUEUE.QUEUE(IQUEUE.RDPOS+1)(3 downto 0);
									FRAB <= ADDRESSER4(IQUEUE.QUEUE(IQUEUE.RDPOS+1)(7 downto 4));
									NUM_BYTES := 2;
									CAN_FETCH := '0';
									LU_INSTRUCTION := '0';
									CPU_STATE := CPU_LDPTOIM;						
								end if;
							end if;
 
							------------------------------------------------------------------------------------------------------------------------------
							--**************************************************************************************************************************--
							--                                                     1-byte instructions                                                  --
							--**************************************************************************************************************************--
							------------------------------------------------------------------------------------------------------------------------------
							if (IQUEUE.CNT>=1) then	-- 1-byte instructions
								if (IQUEUE.QUEUE(IQUEUE.RDPOS)(3 downto 0)=x"F") then	------------------------------------------------ column F instructions
									case IQUEUE.QUEUE(IQUEUE.RDPOS)(7 downto 4) is
										when x"0" =>	---------------------------------------------------------------------------------- NOP instruction	
											NUM_BYTES := 1;
										when x"1" =>	------------------------------------------------------------------------------ page 2 instructions
										when x"2" =>
											ATM_COUNTER := 0;
											NUM_BYTES := 1;
										when x"3" =>
											CPU_STATE := CPU_ILLEGAL;
										when x"4" =>
											CPU_STATE := CPU_ILLEGAL;
										when x"5" =>	---------------------------------------------------------------------------------- WDT instruction
											NUM_BYTES := 1;
										when x"6" =>	--------------------------------------------------------------------------------- STOP instruction
											NUM_BYTES := 1;
											STOP <= '1';
										when x"7" =>	--------------------------------------------------------------------------------- HALT instruction
											NUM_BYTES := 1;
											HALT := '1';
										when x"8" =>	----------------------------------------------------------------------------------- DI instruction
											IRQE := '0';
											NUM_BYTES := 1;
										when x"9" =>	----------------------------------------------------------------------------------- EI instruction
											IRQE := '1';
											NUM_BYTES := 1;							
										when x"A" =>	---------------------------------------------------------------------------------- RET instruction
											NUM_BYTES := 1;
											FRAB <= SP;
											CPU_STATE := CPU_UNSTACK2;	
										when x"B" =>	--------------------------------------------------------------------------------- IRET instruction
											NUM_BYTES := 1;
											IRQE := '1';
											FRAB <= SP;
											CPU_STATE := CPU_UNSTACK3;
										when x"C" =>	---------------------------------------------------------------------------------- RCF instruction
											CPU_FLAGS.C := '0';
											NUM_BYTES := 1;
										when x"D" =>	---------------------------------------------------------------------------------- SCF instruction
											CPU_FLAGS.C := '1';
											NUM_BYTES := 1;
										when x"E" =>	---------------------------------------------------------------------------------- CCF instruction
											CPU_FLAGS.C := not CPU_FLAGS.C;
											NUM_BYTES := 1;	
										when others =>	---------------------------------------------------------------------------------- R1 instructions
											CPU_STATE := CPU_ILLEGAL;
									end case;
								elsif (IQUEUE.QUEUE(IQUEUE.RDPOS)(3 downto 0)=x"E") then	------------------------------------------------ INC r instruction
									FRAB <= RP(3 downto 0) & RP(7 downto 4) & IQUEUE.QUEUE(IQUEUE.RDPOS)(7 downto 4);
									TEMP_OP := LU2_INC;
									NUM_BYTES := 1;
									CPU_STATE := CPU_OMA2;
								elsif (IQUEUE.QUEUE(IQUEUE.RDPOS)=x"00") then	-------------------------------------------------------------- BRK instruction
									if (OCDCR.BRKEN='1') then		-- the BRK instruction is enabled
										if (OCDCR.DBGACK='1') then
											if (DBG_UART.TX_EMPTY='1') then
												DBG_UART.TX_DATA:=x"FF";
												DBG_UART.TX_EMPTY:='0';
											end if;
										end if;
										if (OCDCR.BRKLOOP='0') then	-- if loop on BRK is disabled
											OCDCR.DBGMODE := '1';	-- set DBGMODE halting CPU
										end if;
									else
										NUM_BYTES := 1;			-- remove the instruction from queue (execute as a NOP)
									end if;
								elsif (IQUEUE.QUEUE(IQUEUE.RDPOS)=x"C9" or IQUEUE.QUEUE(IQUEUE.RDPOS)=x"D9" or IQUEUE.QUEUE(IQUEUE.RDPOS)=x"F9" or 
										IQUEUE.QUEUE(IQUEUE.RDPOS)=x"F8" or IQUEUE.QUEUE(IQUEUE.RDPOS)=x"C6") then	--------------------------- illegal opcode
									CPU_STATE:= CPU_ILLEGAL;
									NUM_BYTES := 1;
								end if;
							end if;
						end if;	-- if DBGMODE=0...
					end if; -- if not stopped or halted
					PC := PC + NUM_BYTES;						-- update PC after instruction
					IQUEUE.RDPOS := IQUEUE.RDPOS + NUM_BYTES;	-- update QUEUE read pointer
					IQUEUE.CNT := IQUEUE.CNT - NUM_BYTES;		-- update QUEUE available bytes
					if (OCD.SINGLESTEP='1') then													-- if we are stepping instructions
						if (NUM_BYTES/=0 or IQUEUE.FETCH_STATE=F_ADDR) then OCD.SINGLESTEP:='0';	-- if a instruction was decoded, reset step flag
						end if;
					end if;
				when CPU_MUL =>	-- MUL ***********************************************************************************************************
					TEMP_DATA := DATAREAD(FRAB);		-- read first operand
					FRAB <= FRAB + 1;					-- go to the next operand 
					CPU_STATE := CPU_MUL1;
				when CPU_MUL1 =>
					DEST_ADDR16 := TEMP_DATA * DATAREAD(FRAB);	-- multiply previous operand by the second operand and store temporarily
					DATAWRITE(FRAB,DEST_ADDR16(7 downto 0));	-- prepare to write the lower byte in current memory address 
					WR <= '1';
					CPU_STATE := CPU_MUL2;
				when CPU_MUL2 =>
					FRAB <= FRAB - 1;							-- decrement memory address (point to the first operand)
					DATAWRITE(FRAB,DEST_ADDR16(15 downto 8));	-- write the higher byte
					CPU_STATE := CPU_STORE;						-- complete store operation
				when CPU_XRRTORR =>	-- LEA *******************************************************************************************************
					TEMP_DATA := DATAREAD(FRAB);				-- read the operand and store it
					FRAB <= FRAB + 1;							-- go to the next memory address
					CPU_STATE := CPU_XRRTORR2;
				when CPU_XRRTORR2 =>
					-- read next operand and perform a 16 bit add with the offset previously in result
					DEST_ADDR16 := ADDER16(TEMP_DATA & DATAREAD(FRAB),RESULT);	
					FRAB <= DEST_ADDR;							-- point to the destination address
					DATAWRITE(FRAB,DEST_ADDR16(15 downto 8));	-- store the higher byte of the 16-bit result
					CPU_STATE := CPU_XRRTORR3;
				when CPU_XRRTORR3 =>
					WR <= '1';
					CPU_STATE := CPU_XRRTORR4;
				when CPU_XRRTORR4 =>
					FRAB <= FRAB + 1;							-- go to the next memory address
					DATAWRITE(FRAB,DEST_ADDR16(7 downto 0));	-- store the lower byte of the 16-bit result
					CPU_STATE := CPU_STORE;						-- complete store operation
				when CPU_MTOXAD =>	-- MEMORY TO INDEXED 8-BIT ADDRESS ***************************************************************************
					TEMP_DATA := DATAREAD(FRAB);				-- read operand from memory
					FRAB <= DEST_ADDR;							-- update address bus with destination address
					CPU_STATE := CPU_MTOXAD2;
				when CPU_MTOXAD2 =>
					FRAB <= RP(3 downto 0)&(DATAREAD(FRAB) + RESULT);	-- update address bus indexed result
					DATAWRITE(FRAB,TEMP_DATA);					-- prepare to write data on destination (indexed) address
					CPU_STATE := CPU_STORE;						-- perform store (WR=1)
				when CPU_XADTOM => 	-- INDEXED 8-BIT ADDRESS TO MEMORY ***************************************************************************
					FRAB <= RP(3 downto 0)&(DATAREAD(FRAB) + RESULT);
					CPU_STATE := CPU_TMA;
				when CPU_XRTOM =>	-- LEA *******************************************************************************************************
					TEMP_DATA := DATAREAD(FRAB)+RESULT;
					FRAB <= DEST_ADDR;
					DATAWRITE(FRAB,TEMP_DATA);
					CPU_STATE := CPU_STORE;
				when CPU_IMTOIRR =>	-- INDIRECT MEMORY TO INDIRECT ADDRESS READ FROM REGISTER PAIR ***********************************************
					FRAB <= RP(3 downto 0) & DATAREAD(FRAB);	-- source address is read from indirect register
					CPU_STATE := CPU_MTOIRR;
				when CPU_MTOIRR =>	-- MEMORY TO INDIRECT ADDRESS READ FROM REGISTER PAIR ********************************************************
					TEMP_DATA := DATAREAD(FRAB);				-- reads data from the source (FRAB) address and store it into TEMP_DATA
					FRAB <= DEST_ADDR;							-- FRAB points to the indirect destination register pair
					RESULT := x"00";
					CPU_STATE := CPU_XRRD2;						-- proceed as X indexed register pair destination
				when CPU_IRRS =>	-- RR PAIR AS INDIRECT SOURCE ADDRESS ************************************************************************
					DEST_ADDR16(15 downto 8) := DATAREAD(FRAB);
					FRAB <= FRAB + 1;
					CPU_STATE := CPU_IRRS2;
				when CPU_IRRS2 =>
					DEST_ADDR16(7 downto 0) := DATAREAD(FRAB);
					FRAB <= DEST_ADDR16(11 downto 0);
					if (LU_INSTRUCTION='1') then 
						CPU_STATE:= CPU_TMA;				-- if it is direct addressing mode, go to TMA
					else
						CPU_STATE := CPU_IND2;				-- if it is indirect addressing mode, go to IND2
					end if;
				when CPU_XRRD =>	-- RR PAIR PLUS OFFSET AS DESTINATION ADDRESS ****************************************************************
					TEMP_DATA := DATAREAD(FRAB);				-- reads data from the source (FRAB) address and store it into TEMP_DATA
					FRAB <= DEST_ADDR;
					CPU_STATE := CPU_XRRD2;
				when CPU_XRRD2 =>
					DEST_ADDR16(15 downto 8) := DATAREAD(FRAB);
					FRAB <= FRAB + 1;
					CPU_STATE := CPU_XRRD3;
				when CPU_XRRD3 =>
					DEST_ADDR16(7 downto 0) := DATAREAD(FRAB);
					FRAB <= ADDER16(DEST_ADDR16,RESULT)(11 downto 0);
					DATAWRITE(FRAB,TEMP_DATA);
					CPU_STATE := CPU_STORE;
				when CPU_XRRS =>	-- RR PAIR PLUS OFFSET AS SOURCE ADDRESS *********************************************************************
					DEST_ADDR16(15 downto 8) := DATAREAD(FRAB);
					FRAB <= FRAB + 1;
					CPU_STATE := CPU_XRRS2;
				when CPU_XRRS2 =>
					DEST_ADDR16(7 downto 0) := DATAREAD(FRAB);
					FRAB <= ADDER16(DEST_ADDR16,RESULT)(11 downto 0);
					CPU_STATE := CPU_XRRS3;
				when CPU_XRRS3 =>
					TEMP_DATA := DATAREAD(FRAB);
					FRAB <= DEST_ADDR;
					DATAWRITE(FRAB,TEMP_DATA);
					CPU_STATE := CPU_STORE;
				when CPU_INDRR =>	-- INDIRECT DESTINATION ADDRESS FOR WORD INSTRUCTIONS (DECW AND INCW) ****************************************
					FRAB <= (RP(3 downto 0) & DATAREAD(FRAB))+1;	-- the destination address is given by indirect address
					CPU_STATE := CPU_OMA2;
				when CPU_ISMD1 =>	-- INDIRECT SOURCE ADDRESS ***********************************************************************************
					FRAB <= RP(3 downto 0) & DATAREAD(FRAB);	-- source address is read from indirect register
					CPU_STATE := CPU_TMA;
				when CPU_IND2 =>	-- READS REGISTER AND PERFORM OPERATION ON AN INDIRECT DESTINATION *******************************************
					TEMP_DATA := DATAREAD(FRAB);				-- reads data from the source (FRAB) address and store it into TEMP_DATA
					FRAB <= DEST_ADDR;						-- place the address of the indirect register on FRAB
					CPU_STATE := CPU_IND1;					-- proceed to the indirect
				when CPU_IND1 =>	-- INDIRECT DESTINATION ADDRESS ******************************************************************************
					FRAB <= RP(3 downto 0) & DATAREAD(FRAB);	-- the destination address is given by indirect address
					if (LU_INSTRUCTION='0') then CPU_STATE := CPU_OMA;					-- proceed with one memory access
					else CPU_STATE := CPU_OMA2;											-- proceed with one memory access (logic unit related)
					end if;
				when CPU_TMA =>		-- TWO MEMORY ACCESS, READS SOURCE OPERAND FROM MEMORY *******************************************************
					TEMP_DATA := DATAREAD(FRAB);			-- reads data from the source (FRAB) address and store it into TEMP_DATA
					FRAB <= DEST_ADDR;						-- place destination address (DEST_ADDR) on memory address bus (FRAB)
					CPU_STATE := CPU_OMA;					-- proceed to the last stage
				when CPU_OMA =>		-- ONE MEMORY ACCESS stage ***********************************************************************************
					-- this stage performs TEMP_OP operation between TEMP_DATA and data read from current (FRAB) address (destination)
					RESULT := ALU(TEMP_OP,DATAREAD(FRAB),TEMP_DATA,CPU_FLAGS.C);
					if (TEMP_OP<ALU_OR) then
						CPU_FLAGS.C := ALU_FLAGS.C;
						CPU_FLAGS.V := ALU_FLAGS.V;
						CPU_FLAGS.Z := ALU_FLAGS.Z;
						CPU_FLAGS.S := ALU_FLAGS.S;
						CPU_FLAGS.H := ALU_FLAGS.H;
						CPU_FLAGS.D := TEMP_OP(1);
					elsif (TEMP_OP=ALU_CP or TEMP_OP=ALU_CPC) then
						CPU_FLAGS.C := ALU_FLAGS.C;
						CPU_FLAGS.V := ALU_FLAGS.V;
						CPU_FLAGS.Z := ALU_FLAGS.Z;
						CPU_FLAGS.S := ALU_FLAGS.S;
					elsif (TEMP_OP/=ALU_LD) then
						CPU_FLAGS.Z := ALU_FLAGS.Z;
						CPU_FLAGS.S := ALU_FLAGS.S;
						CPU_FLAGS.V := '0';				
					end if;
					if (ALU_NOUPDATE='0') then
						DATAWRITE(FRAB,RESULT);
						WR <= '1';
					end if;
					CPU_STATE := CPU_DECOD;
					if (WORD_DATA='1') then
						CPU_STATE := CPU_LDW;
					end if;
				when CPU_OMA2 =>	-- ONE MEMORY ACCESS stage logic unit related ****************************************************************
					-- this stage performs TEMP_OP LU2 operation on data read from current (FRAB) address
					RESULT := LU2(TEMP_OP,DATAREAD(FRAB),CPU_FLAGS.D,CPU_FLAGS.H,CPU_FLAGS.C);
					if (TEMP_OP=LU2_DEC or TEMP_OP=LU2_INC) then
						CPU_FLAGS.V := ALU_FLAGS.V;
						CPU_FLAGS.Z := ALU_FLAGS.Z;
						CPU_FLAGS.S := ALU_FLAGS.S;
					elsif (TEMP_OP=LU2_COM) then
						CPU_FLAGS.V := '0';
						CPU_FLAGS.Z := ALU_FLAGS.Z;
						CPU_FLAGS.S := ALU_FLAGS.S;
					elsif (TEMP_OP=LU2_SWAP) then
						CPU_FLAGS.Z := ALU_FLAGS.Z;
						CPU_FLAGS.S := ALU_FLAGS.S;
					elsif (TEMP_OP=LU2_DA) then
						CPU_FLAGS.C := ALU_FLAGS.C;
						CPU_FLAGS.Z := ALU_FLAGS.Z;
						CPU_FLAGS.S := ALU_FLAGS.S;					
					elsif (TEMP_OP=LU2_LD) then
						CPU_FLAGS.V := ALU_FLAGS.V;
						CPU_FLAGS.S := ALU_FLAGS.S;
						CPU_FLAGS.Z := CPU_FLAGS.Z and ALU_FLAGS.Z;
					elsif (TEMP_OP/=LU2_CLR) then
						CPU_FLAGS.C := ALU_FLAGS.C;
						CPU_FLAGS.V := ALU_FLAGS.V;
						CPU_FLAGS.Z := ALU_FLAGS.Z;
						CPU_FLAGS.S := ALU_FLAGS.S;				
					end if;
					DATAWRITE(FRAB,RESULT);
					WR <= '1';
					if (WORD_DATA='1') then
						WORD_DATA := '0';
						if (ALU_FLAGS.C='0') then TEMP_OP := LU2_LD;
						end if;
						CPU_STATE := CPU_DMAB;
					else CPU_STATE := CPU_DECOD;				
					end if;
				when CPU_DMAB =>	-- DECREMENT MEMORY ADDRESS BUS ******************************************************************************
					FRAB <= FRAB - 1;
					CPU_STATE := CPU_OMA2;
				when CPU_LDW =>		-- LOAD WORD INSTRUCTION *************************************************************************************
					-- read higher byte from source operand
					TEMP_DATA := DATAREAD(FRAB);
					FRAB <= FRAB + 1;
					CPU_STATE := CPU_LDW2;
				when CPU_LDW2 =>
					-- read lower byte from source operand
					RESULT := DATAREAD(FRAB);
					FRAB <= DEST_ADDR;
					CPU_STATE := CPU_LDW3;
				when CPU_LDW3 =>
					-- write higher byte to destination operand
					DATAWRITE(FRAB,TEMP_DATA);
					WR <= '1';
					CPU_STATE := CPU_LDW4;					
				when CPU_LDW4 =>
					-- points FRAB to lower byte of destination address
					FRAB <= FRAB + 1;					
					CPU_STATE := CPU_LDW5;
				when CPU_LDW5 =>
					DATAWRITE(FRAB,RESULT);
					CPU_STATE := CPU_STORE;
				when CPU_LDPTOIM =>	-- LOAD PROGRAM TO INDIRECT MEMORY **************************************************************************
					TEMP_DATA := DATAREAD(FRAB);
					DEST_ADDR := RP(3 downto 0) & TEMP_DATA;	-- the destination address is read from the indirect address
					if (WORD_DATA='1') then
						-- it is a LDCI instruction, so we have to increment the indirect address after the operation
						DATAWRITE(FRAB,TEMP_DATA+1);
						WR <= '1';
						CPU_STATE := CPU_LDPTOIM2;
					else
						-- it is a LDC instruction, proceed the load instruction
						FRAB <= ADDRESSER4(RESULT(3 downto 0));		-- the source address (program memory) is read from source register pair
						CPU_STATE := CPU_LDPTOM;
					end if;
				when CPU_LDPTOIM2 =>
					FRAB <= ADDRESSER4(RESULT(3 downto 0));		-- the source address (program memory) is read from source register pair
					CPU_STATE := CPU_LDPTOM;				
				when CPU_LDPTOM =>	-- LOAD PROGRAM TO MEMORY ***********************************************************************************
					IAB(15 downto 8) <= DATAREAD(FRAB);	-- read the high address from the first register
					FRAB <= FRAB + 1;
					CPU_STATE := CPU_LDPTOM2;
				when CPU_LDPTOM2 =>	
					IAB(7 downto 0) <= DATAREAD(FRAB);	-- read the low address from the second register
					FRAB <= DEST_ADDR;
					if (LU_INSTRUCTION='0') then 
						CPU_STATE := CPU_LDPTOM3;		-- if it is a read from program memory
					else
						CPU_STATE := CPU_LDMTOP;		-- if it is a write onto program memory
					end if;
				when CPU_LDPTOM3 =>	-- READ PROGRAM MEMORY AND STORE INTO RAM *******************************************************************
					DATAWRITE(FRAB,IDB);
					WR <= '1';
					CAN_FETCH := '1';	-- re-enable fetching
					FETCH_ADDR := PC;
					IAB <= PC;
					CPU_STATE := CPU_DECOD;
					if (WORD_DATA='1') then
						CPU_STATE := CPU_LDPTOM4;
					end if;
				when CPU_LDPTOM4 =>
					DEST_ADDR := ADDRESSER4(RESULT(3 downto 0));
					FRAB <= DEST_ADDR+1;
					TEMP_OP := LU2_INC;
					CPU_STATE := CPU_OMA2;
				when CPU_LDMTOP =>	-- READ RAM AND STORE ONTO PROGRAM MEMORY *******************************************************************
					IWDB <= DATAREAD(FRAB);	-- IWDB receive the content of RAM
					PGM_WR <= '1';			-- enable program memory write signal
					CPU_STATE := CPU_LDMTOP2;
				when CPU_LDMTOP2 =>				
					CAN_FETCH := '1';		-- re-enable instruction fetching
					FETCH_ADDR := PC;
					IAB <= PC;
					CPU_STATE := CPU_DECOD;
					if (WORD_DATA='1') then
						CPU_STATE := CPU_LDPTOM4;
					end if;
				when CPU_BIT =>		-- BIT INSTRUCTION *******************************************************************************************
					TEMP_DATA := DATAREAD(FRAB);
					TEMP_DATA(to_integer(unsigned(TEMP_OP(2 downto 0)))):=TEMP_OP(3);
					DATAWRITE(FRAB,TEMP_DATA);
					WR <= '1';
					CPU_STATE := CPU_DECOD;
				when CPU_IBTJ =>	-- INDIRECT BIT TEST JUMP INSTRUCTION ************************************************************************
					FRAB <= RP(3 downto 0) & DATAREAD(FRAB);
					CPU_STATE := CPU_BTJ;
				when CPU_BTJ =>		-- BIT TEST JUMP INSTRUCTION *********************************************************************************
					TEMP_DATA := DATAREAD(FRAB);
					if (TEMP_DATA(to_integer(unsigned(TEMP_OP(2 downto 0))))=TEMP_OP(3)) then
						PC := ADDER16(PC,RESULT);
						IQUEUE.FETCH_STATE := F_ADDR;
					end if; 
					CPU_STATE := CPU_DECOD;
				when CPU_DJNZ =>	-- DECREMENT AND JUMP IF NOT ZERO INSTRUCTION ****************************************************************
					RESULT := LU2(LU2_DEC,DATAREAD(FRAB),'0','0','0');
					if (ALU_FLAGS.Z='0') then	-- result is not zero, then jump relative
						PC := DEST_ADDR16;
						IQUEUE.FETCH_STATE := F_ADDR;
					end if;
					DATAWRITE(FRAB,RESULT);
					WR <= '1';
					CPU_STATE := CPU_DECOD;
				when CPU_INDJUMP =>	-- INDIRECT JUMP INSTRUCTION *********************************************************************************
					PC(15 downto 8) := DATAREAD(FRAB);
					FRAB <= FRAB + 1;
					CPU_STATE:= CPU_INDJUMP2;
				when CPU_INDJUMP2 =>
					PC(7 downto 0) := DATAREAD(FRAB);
					IQUEUE.FETCH_STATE := F_ADDR;
					CPU_STATE := CPU_DECOD;
				when CPU_TRAP =>	-- TRAP INSTRUCTION ******************************************************************************************
					PC(15 downto 8) := DATAREAD(FRAB);
					FRAB <= FRAB + 1;
					CPU_STATE:= CPU_TRAP2;
				when CPU_TRAP2 =>
					PC(7 downto 0) := DATAREAD(FRAB);
					SP := SP - 1;
					FRAB <= SP;
					IQUEUE.FETCH_STATE := F_ADDR;
					LU_INSTRUCTION := '1';
					CPU_STATE := CPU_STACK;
				when CPU_INDSTACK =>	-- INDIRECT CALL INSTRUCTION *****************************************************************************
					PC(15 downto 8) := DATAREAD(FRAB);
					FRAB <= FRAB + 1;
					CPU_STATE:= CPU_INDSTACK2;
				when CPU_INDSTACK2 =>
					PC(7 downto 0) := DATAREAD(FRAB);
					SP := SP - 1;
					FRAB <= SP;
					IQUEUE.FETCH_STATE := F_ADDR;
					CPU_STATE := CPU_STACK;
				when CPU_VECTOR =>		-- LOAD PC WITH ADDRESS STORED IN PROGRAM MEMORY *********************************************************
					PC(15 downto 8) := IDB;		-- read high byte of destination address
					IAB <= IAB + 1;
					CPU_STATE := CPU_VECTOR2;
				when CPU_VECTOR2 =>
					PC(7 downto 0) := IDB;		-- read low byte of destination address
					IQUEUE.FETCH_STATE := F_ADDR;	-- reset queue FSM
					CAN_FETCH := '1';				-- restart fetching
					if (INT_FLAG='1') then CPU_STATE := CPU_STACK;
					else CPU_STATE := CPU_DECOD;
					end if;
				when CPU_STACK =>	-- PUSH PC 7:0 INTO THE STACK ********************************************************************************
					DATAWRITE(FRAB,DEST_ADDR16(7 downto 0));
					WR <= '1';
					CPU_STATE := CPU_STACK1;
				when CPU_STACK1 =>
					SP := SP - 1;
					FRAB <= SP;				
					CPU_STATE := CPU_STACK2;
				when CPU_STACK2 =>	-- PUSH PC 15:8 INTO THE STACK *******************************************************************************
					DATAWRITE(FRAB,DEST_ADDR16(15 downto 8));
					WR <= '1';
					if (INT_FLAG='1') then
						CPU_STATE := CPU_STACK3;
					else					
						CPU_STATE := CPU_DECOD;
					end if;
				when CPU_STACK3 =>	-- PUSH FLAGS INTO THE STACK *********************************************************************************
					SP := SP - 1;
					FRAB <= SP;
					DATAWRITE(FRAB,CPU_FLAGS.C&CPU_FLAGS.Z&CPU_FLAGS.S&CPU_FLAGS.V&CPU_FLAGS.D&CPU_FLAGS.H&CPU_FLAGS.F2&CPU_FLAGS.F1);
					IRQE := '0';
					CPU_STATE := CPU_STORE;			
				when CPU_UNSTACK3 =>	-- POP FLAGS FROM STACK **********************************************************************************
					TEMP_DATA := DATAREAD(FRAB);
					CPU_FLAGS.C := TEMP_DATA(7);
					CPU_FLAGS.Z := TEMP_DATA(6);
					CPU_FLAGS.S := TEMP_DATA(5);
					CPU_FLAGS.V := TEMP_DATA(4);
					CPU_FLAGS.D := TEMP_DATA(3);
					CPU_FLAGS.H := TEMP_DATA(2);
					CPU_FLAGS.F2 := TEMP_DATA(1);
					CPU_FLAGS.F1 := TEMP_DATA(0);
					SP := SP + 1;
					FRAB <= SP;
					CPU_STATE := CPU_UNSTACK2;				
				when CPU_UNSTACK2 =>	-- POP PC(15:8) FROM STACK *******************************************************************************
					DEST_ADDR16(15 downto 8) := DATAREAD(FRAB);
					SP := SP + 1;
					FRAB <= SP;
					CPU_STATE := CPU_UNSTACK;
				when CPU_UNSTACK =>		-- POP PC(7:0) FROM STACK ********************************************************************************
					DEST_ADDR16(7 downto 0) := DATAREAD(FRAB);
					SP := SP + 1;
					PC := DEST_ADDR16;
					IQUEUE.FETCH_STATE := F_ADDR;			
					CPU_STATE := CPU_DECOD;
				when CPU_STORE =>	-- stores data into memory
					WR <= '1';		-- enable write signal (it is automatically disabled on CPU_DECOD state)
					CPU_STATE := CPU_DECOD;	-- proceed to main decoding state
				when CPU_ILLEGAL =>	-- An illegal opcode was fetched 
				when CPU_RESET =>		-- SOFTWARE RESET (TRIGGERED BY OCD RESET BIT) ***********************************************************
					IAB <= x"0002";
					FRAB <= x"000";
					IWDB <= x"00";
					SP := x"000";
					RP := x"00";
					WR <= '0';
					PGM_WR <= '0';
					STOP <= '0';
					CAN_FETCH := '1';
					FETCH_ADDR := x"0000";
					RXSYNC1 <= '1';
					RXSYNC2 <= '1';
					DBG_UART.LAST_SMP := '1';
					IQUEUE.FETCH_STATE := F_ADDR;
					IRQE := '0';
					IRQ0 := x"00";
					OLD_IRQ0 := x"00";
					IRQ0ENH := x"00";
					IRQ0ENL := x"00";
					OCDCR.RST := '0';
					ATM_COUNTER := 0;
					CPU_STATE := CPU_VECTOR;			
				when others =>
					CPU_STATE := CPU_DECOD;
			end case;	
			-- end of the main decoder
		end if;
	end process;
end CPU;

Compare with Previous | Blame | View Log

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.