---------------------------------------------------------------------------------------------------------
--
-- Name:            zpu_uart_debug.vhd
-- Created:         January 2019
-- Author(s):       Philip Smart
-- Description:     An extension of the simplistic UART Tx, still fixed at 8N1 with configurable baud rate
--                  but adding a debug serialisaztion FSM for output of ZPU runtime data.
-- Credits:         Originally using the simplistic UART as a guide, which was written by the following
--                  authors:-
--                  Philippe Carton, philippe.carton2 libertysurf.fr
--                  Juan Pablo Daniel Borgna, jpdborgna gmail.com
--                  Salvador E. Tropea, salvador inti.gob.ar
-- Copyright:       (c) 2019 Philip Smart <philip.smart@net2net.org>
--
-- History:         January 2019  - Initial module written using the simplistic UART as a guide but
--                                  adding cache and debug serialisation FSM.
--
---------------------------------------------------------------------------------------------------------
-- This source file is free software: you can redistribute it and-or modify
-- it under the terms of the GNU General Public License as published
-- by the Free Software Foundation, either version 3 of the License, or
-- (at your option) any later version.
--
-- This source file is distributed in the hope that it will be useful,
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-- GNU General Public License for more details.
--
-- You should have received a copy of the GNU General Public License
-- along with this program.  If not, see <http:--www.gnu.org-licenses->.
---------------------------------------------------------------------------------------------------------
library ieee;
library pkgs;
library work;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use work.zpu_pkg.all;

-- Based on the simplistic UART, handles 8N1 RS232 Rx/Tx with independent programmable baud rate and selectable FIFO buffers.
entity zpu_uart_debug is
    generic (
        TX_FIFO_BIT_DEPTH     : integer := DEBUG_MAX_TX_FIFO_BITS;
        DBG_FIFO_BIT_DEPTH    : integer := DEBUG_MAX_FIFO_BITS;
        CLK_FREQ              : integer := 100000000;
        TX_BAUD_RATE          : integer := DEBUG_TX_BAUD_RATE                   -- Default baud rate
    );
    port (
        -- CPU Interface
        CLK                   : in  std_logic;                                  -- memory master clock
        RESET                 : in  std_logic;                                  -- high active sync reset
        DEBUG_DATA            : zpu_dbg_t;
        CS                    : in  std_logic;                                  -- Chip Select.
        READY                 : out std_logic;                                  -- Debug processor ready to process new command.

        -- Serial data
        TXD                   : out std_logic
    );
end zpu_uart_debug;

architecture rtl of zpu_uart_debug is

    type DebugStates is 
    (
        ST_IDLE,
        ST_START,
        ST_ADD_SEPERATOR,
        ST_ADD_SPACE,
        ST_PRECR,
        ST_WRITE,
        ST_WRITEHEX,
        ST_WRITEBIN,
        ST_SPLITSPACE,
        ST_POSTSPACE,
        ST_POSTCRLF,
        ST_POSTLF,
        ST_END
    );

    signal SM_STATE               :  DebugStates;
    signal SM_BITCNT              :  integer range 0 to 7;
    signal SM_BYTECNT             :  integer;
    signal SM_WORDCNT             :  integer range 0 to 4;
    signal SM_NIBBLECNT           :  std_logic;
    signal SM_ADD_SEPERATOR       :  std_logic;
    signal SM_ADD_SPACE           :  std_logic;
    signal SM_SPLIT_DATA          :  std_logic_vector(1 downto 0);

    type TXSTATES is (idle, bits);
    signal TX_STATE               :  TXSTATES := idle;
    signal TX_BUFFER              :  std_logic_vector(17 downto 0);                   -- Transmit serialisation buffer.
    signal TX_DATA                :  std_logic_vector(7 downto 0);                    -- Transmit holding register.
    signal TX_DATA_LOADED         :  std_logic;                                       -- Data loaded into transmit buffer.
    signal TX_COUNTER             :  unsigned(15 downto 0);                           -- TX Clock generator counter.
    signal TX_CLOCK               :  std_logic;                                       -- TX Clock.
    signal TX_LOAD                :  std_logic;                                       -- Load byte into TX fifo.
    signal TX_FIFO_FULL           :  std_logic;                                       -- TX Fifo is full = 1.
    signal TX_WRITE_DATA          :  std_logic_vector(7  downto 0);                   -- write data
    signal SM_DATA_IN             :  std_logic_vector(63 downto 0);                   -- Buffered input data.
    signal DBGREC                 :  zpu_dbg_t;
    
    type ZPU_DBG_MEM_T is array (natural range 0 to ((2**DBG_FIFO_BIT_DEPTH)-1)) of zpu_dbg_t;
    attribute ramstyle            :  string;
    signal DBG_FIFO               :  ZPU_DBG_MEM_T;
    attribute ramstyle of DBG_FIFO:  signal is "M9K";
    signal DBG_FIFO_WR_ADDR       :  unsigned(DBG_FIFO_BIT_DEPTH-1 downto 0);
    signal DBG_FIFO_RD_ADDR       :  unsigned(DBG_FIFO_BIT_DEPTH-1 downto 0);

    -- FIFO buffers.
    --type TX_MEM_T is array (natural range 0 to ((2**TX_FIFO_BIT_DEPTH)-1)) of std_logic_vector(7 downto 0);
    type TX_MEM_T is array (natural range 0 to ((2**TX_FIFO_BIT_DEPTH)-1)) of std_logic_vector(7 downto 0);
    signal TX_FIFO                :  TX_MEM_T;
    -- TX Fifo address pointers.
    --signal TX_FIFO_WR_ADDR        :  unsigned(TX_FIFO_BIT_DEPTH-1 downto 0);
    --signal TX_FIFO_RD_ADDR        :  unsigned(TX_FIFO_BIT_DEPTH-1 downto 0);
    signal TX_FIFO_WR_ADDR        :  unsigned(TX_FIFO_BIT_DEPTH-1 downto 0);
    signal TX_FIFO_RD_ADDR        :  unsigned(TX_FIFO_BIT_DEPTH-1 downto 0);

begin
    -- Debug processor. External input provides a 32bit input which is translated to [1-4]x8bit characters
    -- or [1-4]byte Hex roeds and sent to the debug uart transmitter.
    --
    process(CLK, RESET, DBG_FIFO_RD_ADDR, DBG_FIFO_WR_ADDR)
        variable DBG_FULL_V                           : std_logic;
        variable DBG_EMPTY_V                          : std_logic;
    begin
        if DBG_FIFO_RD_ADDR = DBG_FIFO_WR_ADDR then
            DBG_EMPTY_V                               := '1';
        else
            DBG_EMPTY_V                               := '0';
        end if;

        if DBG_FIFO_WR_ADDR = DBG_FIFO_RD_ADDR-1 then
            DBG_FULL_V                                := '1';
        else
            DBG_FULL_V                                := '0';
        end if;

        -- If we are to fill the last fifo slot, set ready to false so that no more writes occur (if cpu checking).
        --
        if (DBG_FIFO_WR_ADDR - DBG_FIFO_RD_ADDR) > ((2**DBG_FIFO_BIT_DEPTH)-2) then
            READY                                     <= '0';
        elsif (DBG_FIFO_WR_ADDR - DBG_FIFO_RD_ADDR) < ((2**DBG_FIFO_BIT_DEPTH)-2) then
            READY                                     <= '1';
        else
            READY                                     <= '0';
        end if;

        if RESET='1' then
            TX_LOAD                                   <= '0';
            SM_STATE                                  <= ST_IDLE;
            SM_BYTECNT                                <= 0;
            SM_WORDCNT                                <= 0;
            SM_NIBBLECNT                              <= '1';
            SM_ADD_SPACE                              <= '0';
            SM_ADD_SEPERATOR                          <= '0';
            DBG_FIFO_WR_ADDR                          <= (others => '0');
            DBG_FIFO_RD_ADDR                          <= (others => '0');
            READY                                     <= '1';

        elsif rising_edge(CLK) then

            -- If cpu is writing a record to be processed, store in fifo if not full, otherwise wait.
            --
            if CS = '1' then
                -- Store data in FIFO if not full.
                --
                if DBG_FULL_V = '0' then
                    DBG_FIFO(to_integer(DBG_FIFO_WR_ADDR)) <= DEBUG_DATA;
                    DBG_FIFO_WR_ADDR                  <= DBG_FIFO_WR_ADDR + 1;
                end if;
            end if;

            -- When idle, if we have a record in the fifo, extract top record and process.
            --
            if SM_STATE = ST_IDLE and DBG_EMPTY_V = '0' then
                DBGREC                                <= DBG_FIFO(to_integer(DBG_FIFO_RD_ADDR)); 
                DBG_FIFO_RD_ADDR                      <= DBG_FIFO_RD_ADDR + 1;
                SM_STATE                              <= ST_START;
                SM_SPLIT_DATA                         <= "00";
            end if;

            -- Only add characters if the TX Fifo has space, otherwise suspend.
            --
            TX_LOAD                                   <= '0';
            if TX_FIFO_FULL = '0' then
                case SM_STATE is
                    when ST_IDLE =>
    
                    when ST_START =>
                        if SM_ADD_SEPERATOR = '1' then
                            SM_STATE                      <= ST_ADD_SEPERATOR;
                            SM_ADD_SEPERATOR              <= '0';
                        elsif SM_ADD_SPACE = '1' then
                            SM_STATE                      <= ST_ADD_SPACE;
                            SM_ADD_SPACE                  <= '0';
                        elsif DBGREC.FMT_PRE_SPACE = '1' then
                            SM_STATE                      <= ST_ADD_SPACE;
                            DBGREC.FMT_PRE_SPACE          <= '0';
                        elsif DBGREC.FMT_PRE_CR = '1' then
                            SM_STATE                      <= ST_PRECR;
                            DBGREC.FMT_PRE_CR             <= '0';
                        elsif DBGREC.WRITE_PC = '1' then
                            DBGREC.WRITE_PC               <= '0';
                            SM_BYTECNT                    <= 4;
                            SM_DATA_IN(63 downto 32)      <= std_logic_vector(to_unsigned(to_integer(unsigned(DBGREC.PC)), 32));
                            SM_ADD_SPACE                  <= '1';
                            SM_STATE                      <= ST_WRITEHEX;
                        elsif DBGREC.WRITE_SP = '1' then
                            DBGREC.WRITE_SP               <= '0';
                            SM_BYTECNT                    <= 4;
                            SM_DATA_IN(63 downto 32)      <= std_logic_vector(to_unsigned(to_integer(unsigned(DBGREC.SP)), 30)) & "00";
                            SM_ADD_SPACE                  <= '1';
                            SM_STATE                      <= ST_WRITEHEX;
                        elsif DBGREC.WRITE_STACK_TOS = '1' then
                            DBGREC.WRITE_STACK_TOS        <= '0';
                            SM_BYTECNT                    <= 4;
                            SM_DATA_IN(63 downto 32)      <= DBGREC.STACK_TOS;
                            SM_ADD_SPACE                  <= '1';
                            SM_STATE                      <= ST_WRITEHEX;
                        elsif DBGREC.WRITE_STACK_NOS = '1' then
                            DBGREC.WRITE_STACK_NOS        <= '0';
                            SM_BYTECNT                    <= 4;
                            SM_DATA_IN(63 downto 32)      <= DBGREC.STACK_NOS;
                            SM_ADD_SPACE                  <= '1';
                            SM_STATE                      <= ST_WRITEHEX;
                        elsif DBGREC.WRITE_OPCODE = '1' then
                            DBGREC.WRITE_OPCODE           <= '0';
                            SM_BYTECNT                    <= 1;
                            SM_DATA_IN(63 downto 56)      <= DBGREC.OPCODE;
                            SM_ADD_SEPERATOR              <= '1';
                            SM_STATE                      <= ST_WRITEHEX;
                        elsif DBGREC.WRITE_DECODED_OPCODE = '1' then
                            DBGREC.WRITE_DECODED_OPCODE   <= '0';
                            SM_BYTECNT                    <= 1;
                            SM_DATA_IN(63 downto 56)      <= "00" & DBGREC.DECODED_OPCODE;
                            SM_ADD_SPACE                  <= '1';
                            SM_STATE                      <= ST_WRITEHEX;
                        elsif DBGREC.FMT_SPLIT_DATA /= "00" then
                            SM_SPLIT_DATA                 <= DBGREC.FMT_SPLIT_DATA;
                            DBGREC.FMT_SPLIT_DATA         <= "00";
                        elsif DBGREC.WRITE_DATA = '1' then
                            DBGREC.WRITE_DATA             <= '0';
                            SM_BITCNT                     <= 7;
                            SM_BYTECNT                    <= to_integer(unsigned(DBGREC.DATA_BYTECNT)) + 1;
                            SM_WORDCNT                    <= 0;
                            SM_DATA_IN                    <= DBGREC.DATA;
                            if DBGREC.FMT_DATA_PRTMODE = "10" then
                                SM_STATE                  <= ST_WRITEBIN;
                            elsif DBGREC.FMT_DATA_PRTMODE = "01" then
                                SM_STATE                  <= ST_WRITEHEX;
                            else
                                SM_STATE                  <= ST_WRITE;
                            end if;
                        elsif DBGREC.WRITE_DATA2 = '1' then
                            DBGREC.WRITE_DATA2            <= '0';
                            SM_BYTECNT                    <= to_integer(unsigned(DBGREC.DATA2_BYTECNT)) + 1;
                            SM_BITCNT                     <= 7;
                            SM_WORDCNT                    <= 0;
                            SM_DATA_IN                    <= DBGREC.DATA2;
                            if DBGREC.FMT_DATA_PRTMODE = "10" then
                                SM_STATE                  <= ST_WRITEBIN;
                            elsif DBGREC.FMT_DATA_PRTMODE = "01" then
                                SM_STATE                  <= ST_WRITEHEX;
                            else
                                SM_STATE                  <= ST_WRITE;
                            end if;
                        elsif DBGREC.WRITE_DATA3 = '1' then
                            DBGREC.WRITE_DATA3            <= '0';
                            SM_BYTECNT                    <= to_integer(unsigned(DBGREC.DATA3_BYTECNT)) + 1;
                            SM_BITCNT                     <= 7;
                            SM_WORDCNT                    <= 0;
                            SM_DATA_IN                    <= DBGREC.DATA3;
                            if DBGREC.FMT_DATA_PRTMODE = "10" then
                                SM_STATE                  <= ST_WRITEBIN;
                            elsif DBGREC.FMT_DATA_PRTMODE = "01" then
                                SM_STATE                  <= ST_WRITEHEX;
                            else
                                SM_STATE                  <= ST_WRITE;
                            end if;
                        elsif DBGREC.WRITE_DATA4 = '1' then
                            DBGREC.WRITE_DATA4            <= '0';
                            SM_BYTECNT                    <= to_integer(unsigned(DBGREC.DATA4_BYTECNT)) + 1;
                            SM_BITCNT                     <= 7;
                            SM_WORDCNT                    <= 0;
                            SM_DATA_IN                    <= DBGREC.DATA4;
                            if DBGREC.FMT_DATA_PRTMODE = "10" then
                                SM_STATE                  <= ST_WRITEBIN;
                            elsif DBGREC.FMT_DATA_PRTMODE = "01" then
                                SM_STATE                  <= ST_WRITEHEX;
                            else
                                SM_STATE                  <= ST_WRITE;
                            end if;
                        else
                            SM_STATE                      <= ST_END;
                        end if;
    
                    when ST_ADD_SPACE =>
                        TX_WRITE_DATA(7 downto 0)         <= X"20";
                        TX_LOAD                           <= '1';
                        SM_STATE                          <= ST_START;
    
                    when ST_ADD_SEPERATOR =>
                        TX_WRITE_DATA(7 downto 0)         <= X"2E";
                        TX_LOAD                           <= '1';
                        SM_STATE                          <= ST_START;
    
                    when ST_PRECR =>
                        TX_WRITE_DATA(7 downto 0)         <= X"0D";
                        TX_LOAD                           <= '1';
                        SM_STATE                          <= ST_START;
    
                    when ST_WRITE =>
                        if SM_BYTECNT > 0 then
                            TX_WRITE_DATA(7 downto 0)     <= SM_DATA_IN(63 downto 56);
                            TX_LOAD                       <= '1';
                            SM_DATA_IN(63 downto 8)       <= SM_DATA_IN(55 downto 0);
                            SM_BYTECNT                    <= SM_BYTECNT - 1;
                        else
                            SM_STATE                      <= ST_START;
                        end if;
    
                    when ST_WRITEHEX =>
                        if SM_BYTECNT > 0 then
                            if unsigned(SM_DATA_IN(63 downto 60)) < 10 then
                                TX_WRITE_DATA(7 downto 0) <= std_logic_vector(unsigned(SM_DATA_IN(63 downto 60)) + X"30");
                            else
                                TX_WRITE_DATA(7 downto 0) <= std_logic_vector(unsigned(SM_DATA_IN(63 downto 60)) + X"57");
                            end if;
                            TX_LOAD                       <= '1';
                            SM_DATA_IN(63 downto 4)       <= SM_DATA_IN(59 downto 0);
                            if SM_NIBBLECNT = '0' then
                                SM_BYTECNT                <= SM_BYTECNT - 1;
                                if SM_SPLIT_DATA = "01" and SM_WORDCNT = 0 then
                                    SM_STATE              <= ST_SPLITSPACE;
                                    SM_WORDCNT            <= 0;
                                elsif SM_SPLIT_DATA = "10" and SM_WORDCNT = 1 then
                                    SM_STATE              <= ST_SPLITSPACE;
                                    SM_WORDCNT            <= 0;
                                elsif SM_SPLIT_DATA = "11" and SM_WORDCNT > 2 then
                                    SM_STATE              <= ST_SPLITSPACE;
                                    SM_WORDCNT            <= 0;
                                else
                                    SM_WORDCNT            <= SM_WORDCNT + 1;
                                end if;
                            end if;
                            SM_NIBBLECNT                  <= not SM_NIBBLECNT;
                        else
                            SM_STATE                      <= ST_START;
                        end if;

                    when ST_WRITEBIN =>
                        if SM_BYTECNT > 0 then
                            if SM_DATA_IN(63) = '1' then
                                TX_WRITE_DATA(7 downto 0) <= X"31";
                            else
                                TX_WRITE_DATA(7 downto 0) <= X"30";
                            end if;
                            TX_LOAD                       <= '1';
                            SM_DATA_IN(63 downto 1)       <= SM_DATA_IN(62 downto 0);
                            if SM_BITCNT > 0 then
                                SM_BITCNT                 <= SM_BITCNT-1;
                            else
                                SM_BITCNT                 <= 7;
                                SM_BYTECNT                <= SM_BYTECNT - 1;
                            end if;
                        else
                            SM_STATE                      <= ST_START;
                        end if;

                    when ST_SPLITSPACE =>
                        TX_WRITE_DATA(7 downto 0)         <= X"20";
                        TX_LOAD                           <= '1';
                        SM_STATE                          <= ST_WRITEHEX;
    
                    when ST_POSTSPACE =>
                        TX_WRITE_DATA(7 downto 0)         <= X"20";
                        TX_LOAD                           <= '1';
                        SM_STATE                          <= ST_END;
    
                    when ST_POSTCRLF =>
                        TX_WRITE_DATA(7 downto 0)         <= X"0D";
                        TX_LOAD                           <= '1';
                        SM_STATE                          <= ST_POSTLF;
    
                    when ST_POSTLF =>
                        TX_WRITE_DATA(7 downto 0)         <= X"0A";
                        TX_LOAD                           <= '1';
                        SM_STATE                          <= ST_END;
    
                    when ST_END =>
                        if DBGREC.FMT_POST_SPACE = '1' then
                            SM_STATE                      <= ST_POSTSPACE;
                            DBGREC.FMT_POST_SPACE         <= '0';
                        elsif DBGREC.FMT_POST_CRLF = '1' then
                            SM_STATE                      <= ST_POSTCRLF;
                            DBGREC.FMT_POST_CRLF          <= '0';
                        else
                            SM_STATE                      <= ST_IDLE;
                        end if;
                end case;
            end if;
        end if;
    end process;

    -- Tx Clock generation
    -- Very simple - the counter is reset when either it reaches zero or
    -- the Tx is idle, and counts down once per system clock tick.
    process(CLK, RESET)
    begin
        if RESET='1' then
            TX_CLOCK                   <= '0';
            TX_COUNTER                 <= to_unsigned(CLK_FREQ/TX_BAUD_RATE, TX_COUNTER'length); 
        elsif rising_edge(CLK) then
            TX_CLOCK                   <= '0';

            if TX_STATE = idle then
                TX_COUNTER             <= to_unsigned(CLK_FREQ/TX_BAUD_RATE, TX_COUNTER'length);
            else
                TX_COUNTER             <= TX_COUNTER-1;
                if TX_COUNTER = 0 then
                    TX_CLOCK           <= '1';
                    TX_COUNTER         <= to_unsigned(CLK_FREQ/TX_BAUD_RATE, TX_COUNTER'length);
                end if;
            end if;
        end if;
    end process;

    
    -- Data Tx
    -- Similarly to the Rx routine, we use a shift register larger than the word,
    -- which also includes a marker bit.  This time the marker bit is a zero, and when
    -- the zero reaches bit 8, we know we've transmitted the entire word plus one stop bit.
    process(clk,RESET,TX_STATE,TX_FIFO_RD_ADDR,TX_FIFO_WR_ADDR)
        variable TX_FULL_V             : std_logic;
        variable TX_EMPTY_V            : std_logic;
        variable DATA_HEX_LSB          : std_logic_vector(7 downto 0);
        variable DATA_HEX_MSB          : std_logic_vector(7 downto 0);
    begin
        if TX_FIFO_RD_ADDR=TX_FIFO_WR_ADDR then
            TX_EMPTY_V                 := '1';
        else
            TX_EMPTY_V                 := '0';
        end if;

        if TX_FIFO_WR_ADDR = TX_FIFO_RD_ADDR-1 then
            TX_FULL_V                  := '1';
        else
            TX_FULL_V                  := '0';
        end if;

        -- Full is set when we are almost full or an unspecified state and reset when the data in the buffer is 256 bytes less than
        -- maximum.
        if (TX_FIFO_WR_ADDR - TX_FIFO_RD_ADDR) > ((2**TX_FIFO_BIT_DEPTH)-16) then
            TX_FIFO_FULL               <= '1';
        elsif (TX_FIFO_WR_ADDR - TX_FIFO_RD_ADDR) < ((2**TX_FIFO_BIT_DEPTH)-256) then
            TX_FIFO_FULL               <= '0';
        else
            TX_FIFO_FULL               <= '1';
        end if;

        if RESET='1' then
            TX_STATE                   <= idle;
            TX_DATA_LOADED             <= '0';
            TXD                        <= '1';
            TX_FIFO_FULL               <= '0';
            TX_FIFO_WR_ADDR            <= (others => '0');
            TX_FIFO_RD_ADDR            <= (others => '0');

        elsif rising_edge(clk) then

            -- If CPU writes data, load into FIFO.
            --
            if TX_LOAD = '1' then

                -- Store data in FIFO if not full.
                --
                if TX_FULL_V = '0' then
                    TX_FIFO(to_integer(TX_FIFO_WR_ADDR)) <= TX_WRITE_DATA(7 downto 0);
                    TX_FIFO_WR_ADDR    <= TX_FIFO_WR_ADDR + 1;
                end if;
            end if;

            -- If FIFO enabled, pop the next byte into the TX holding register.
            if TX_DATA_LOADED = '0' and TX_EMPTY_V = '0' then
                TX_DATA                <= TX_FIFO(to_integer(TX_FIFO_RD_ADDR)); 
                TX_FIFO_RD_ADDR        <= TX_FIFO_RD_ADDR + 1;
                TX_DATA_LOADED         <= '1';
            end if;

            -- TX state machine, serialise the TX buffer.
            case TX_STATE is
                when idle =>
                    -- If data loaded into the TX holding register and we are at idle (ie last byte transmitted),
                    -- load into the transmit buffer and commence transmission.
                    --
                    if TX_DATA_LOADED = '1' then
                        TX_BUFFER      <= "0111111111" & TX_DATA;    -- marker bit + data
                        TX_STATE       <= bits;
                        TXD            <= '0';                       -- Start bit
                        TX_DATA_LOADED <= '0';
                    end if;
                when bits =>
                    if TX_CLOCK='1' then
                        TXD            <= TX_BUFFER(0);
                        TX_BUFFER      <= '0' & TX_BUFFER(17 downto 1);

                        if TX_BUFFER(8) = '0' then                  -- Marker bit has reached bit 8
                            TX_STATE   <= idle;
                        end if;
                    end if;
                when others =>
                    TX_STATE           <= idle;
            end case;
        end if;
    end process;
end architecture;
