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;