-- 
-- swioports.vhd
--   Switched I/O ports ($40-$4F)
--   Revision 3
-- 
-- Copyright (c) 2011 KdL
-- All rights reserved.
--
-- Redistribution and use of this source code or any derivative works, are 
-- permitted provided that the following conditions are met:
--
-- 1. Redistributions of source code must retain the above copyright notice, 
--    this list of conditions and the following disclaimer.
-- 2. Redistributions in binary form must reproduce the above copyright 
--    notice, this list of conditions and the following disclaimer in the 
--    documentation and/or other materials provided with the distribution.
-- 3. Redistributions may not be sold, nor may they be used in a commercial 
--    product or activity without specific prior written permission.
--
-- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
-- "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 
-- TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 
-- PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 
-- CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 
-- EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 
-- PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
-- OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 
-- WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 
-- OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 
-- ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
--

library ieee;
    use ieee.std_logic_1164.all;
    use ieee.std_logic_unsigned.all;

entity switched_io_ports is
    port(   -- 'MAIN' group
            clk21m          : in    std_logic;
            reset           : in    std_logic;
            req             : in    std_logic;
            ack             : out   std_logic;
            wrt             : in    std_logic;
            adr             : in    std_logic_vector( 15 downto 0 );
            dbi             : out   std_logic_vector(  7 downto 0 );
            dbo             : in    std_logic_vector(  7 downto 0 );
            -- 'REGS" group
            io40_n          : inout std_logic_vector(  7 downto 0 );        -- ID Manufacturers/Devices :   $08 (008), $D4 (212=1chipMSX), $FF (255=null)
            io41_id212_n    : inout std_logic_vector(  7 downto 0 );        -- $41 ID212 states         :   Smart Commands
            io42_id212      : inout std_logic_vector(  7 downto 0 );        -- $42 ID212 states         :   Virtual DIP-SW states
            io43_id212      : inout std_logic_vector(  7 downto 0 );        -- $43 ID212 states         :   Lock Mask for port $42 functions, cmt and reset key
            io44_id212      : inout std_logic_vector(  7 downto 0 );        -- $44 ID212 states         :   Lights Mask have the green leds control when Lights Mode is enabled
            OpllVol         : inout std_logic_vector(  2 downto 0 );        -- OPLL Volume
            SccVol          : inout std_logic_vector(  2 downto 0 );        -- SCC Volume
            PsgVol          : inout std_logic_vector(  2 downto 0 );        -- PSG Volume
            MstrVol         : inout std_logic_vector(  2 downto 0 );        -- Master Volume
            CustomSpeed     : inout std_logic_vector(  3 downto 0 );        -- Counter limiter of CPU wait control
            tMegaSD         : inout std_logic;                              -- Turbo on MegaSD access   :   3.58MHz to 5.37MHz autoselection
            tPanaRedir      : inout std_logic;                              -- Pana Redirection switch
            VdpMode         : inout std_logic;                              -- VDP High Speed Mode
            V9938_n         : inout std_logic;                              -- V9938 Status             :   0=V9938, 1=V9958
            Mapper_req      : inout std_logic;                              -- Mapper req               :   Warm or Cold Reset are necessary to complete the request
            Mapper_ack      : out   std_logic;                              -- Current Mapper state
            MegaSD_req      : inout std_logic;                              -- MegaSD req               :   Warm or Cold Reset are necessary to complete the request
            MegaSD_ack      : out   std_logic;                              -- Current MegaSD state
            io41_id008_n    : inout std_logic;                              -- $41 ID008 BIT-0 state    :   0=5.37MHz, 1=3.58MHz (write_n only)
            swioKmap        : inout std_logic;                              -- Keyboard layout selector
            CmtScro         : inout std_logic;                              -- CMT state
            swioCmt         : inout std_logic;                              -- CMT enabler
            LightsMode      : inout std_logic;                              -- Custom green led states
            Red_sta         : inout std_logic;                              -- Custom red led state
            LastRst_sta     : inout std_logic;                              -- Last reset state         :   0=Cold Reset, 1=Warm Reset
            RstReq_sta      : inout std_logic;                              -- Reset request state      :   0=No, 1=Yes
            Blink_ena       : inout std_logic;                              -- MegaSD blink led enabler
            pseudoStereo    : inout std_logic;                              -- RCA-LEFT(red)=External Audio Card / RCA-RIGHT(white)=Internal Sounds
            async5m         : inout std_logic;                              -- Asynchronous tPana       :   External Slots 5.37MHz (Off) or 3.58MHz (On)
            DefKmap         : inout std_logic;                              -- Default keyboard layout  :   0=JP, 1=Non-JP (as UK,FR,..) 
            -- 'DIP-SW' group
            ff_dip_req      : in    std_logic_vector(  7 downto 0 );        -- DIP-SW states/reqs
            ff_dip_ack      : inout std_logic_vector(  7 downto 0 );        -- DIP-SW acks
            -- 'KEYS' group
            SdPaus          : in    std_logic;
            Scro            : in    std_logic;
            ff_Scro         : in    std_logic;
            Reso            : in    std_logic;
            ff_Reso         : in    std_logic;
            FKeys           : in    std_logic_vector(  7 downto 0 );
            vFKeys          : in    std_logic_vector(  7 downto 0 );
            LevCtrl         : inout std_logic_vector(  2 downto 0 );        -- Volume and high-speed level
            GreenLvEna      : out   std_logic;
            -- 'RESET' group
            swioRESET_n     : inout std_logic;                              -- Reset Pulse
            warmRESET       : inout std_logic                               -- 0=Cold Reset, 1=Warm Reset
    );
end switched_io_ports;

architecture RTL of switched_io_ports is

    signal  swio_ack        : std_logic;                                    -- Main ack signal

begin
    -- out assignment: 'ports $40-$4F'
                -- $40 => read_n/write ($41 ID008 BIT-0 is not here, it's a write_n only signal)
    dbi <=  io40_n                              when( (adr(3 downto 0) = "0000") )else
                -- $43 ID008 for compatibility => read only
            "00000000"                          when( (adr(3 downto 0) = "0011") and (io40_n = "11110111") )else
                -- $41 ID212 smart commands => read_n/write
            io41_id212_n                        when( (adr(3 downto 0) = "0001") and (io40_n = "00101011") )else
                -- $42 ID212 virtual dip-sw states => read/write_n
            io42_id212                          when( (adr(3 downto 0) = "0010") and (io40_n = "00101011") )else
                -- $43 ID212 lock mask => read/write_n
                -- [MSB] megasd/mapper/resetkey/slot2/slot1/cmt/display/turbo [LSB]
            io43_id212                          when( (adr(3 downto 0) = "0011") and (io40_n = "00101011") )else
                -- $44 ID212 green leds mask of lights mode => read/write_n
            io44_id212                          when( (adr(3 downto 0) = "0100") and (io40_n = "00101011") )else
                -- $45 ID212 [MSB] master status & volume / psg status & volume [LSB] => read/write_n
            (MstrVol(2) and MstrVol(1) and MstrVol(0)) & not MstrVol & (not (PsgVol(2) or PsgVol(1) or PsgVol(0))) & PsgVol when( (adr(3 downto 0) = "0101") and (io40_n = "00101011") )else
                -- $46 ID212 [MSB] any scc status & volume / opll status & volume [LSB] => read/write_n
            (not (SccVol(2) or SccVol(1) or SccVol(0))) & SccVol & (not (OpllVol(2) or OpllVol(1) or OpllVol(0))) & OpllVol when( (adr(3 downto 0) = "0110") and (io40_n = "00101011") )else
                -- $47 ID212 [MSB] megasd_req/mapper_req/vdpmode/pana_redir/turbo_megasd/custom_speed_lev(1-7) [LSB] => read only
            MegaSD_req & Mapper_req & VdpMode & tPanaRedir & tMegaSD & ("001" - CustomSpeed(2 downto 0))
                                                when( (adr(3 downto 0) = "0111") and (io40_n = "00101011") )else
                -- $48 ID212 states as below => read only
            Blink_ena & RstReq_sta & LastRst_sta & Red_sta & LightsMode & CmtScro & swioKmap & not io41_id008_n
                                                when( (adr(3 downto 0) = "1000") and (io40_n = "00101011") )else
                -- $49 ID212 states as below => read only
            "000000" & async5m & pseudoStereo
                                                when( (adr(3 downto 0) = "1001") and (io40_n = "00101011") )else
                -- $4A ID212 => all
                -- ... ID212 => free
                -- $4D ID212 => regs
                -- $4E ID212 states as below => read only
            ff_dip_req                          when( (adr(3 downto 0) = "1110") and (io40_n = "00101011") )else
                -- $4F ID212 [MSB] def_keyb_layout/swio_rel_n(1-127) [LSB] => read only
            DefKmap & "0000011"                 when( (adr(3 downto 0) = "1111") and (io40_n = "00101011") )else
                -- Not found
            "11111111";

    ack <=  swio_ack;

    process( reset, clk21m )
    begin
        if( reset = '1' )then

            swioRESET_n <=  '1';                        -- End of Reset pulse
            io40_n      <=  "11111111";                 -- Default when system boot (Machine On)
            ---------------------------------------------------------------------------------------
            DefKmap     <=  '0';                        -- Default Keyboard Layout (0=JP, 1=NON-JP)
            ---------------------------------------------------------------------------------------
            if( warmRESET /= '1' )then
                -- Cold Reset
--              io41_id212_n    <=  "00000000";         -- Smart Commands   will be zero at 1st boot
                io42_id212      <=  ff_dip_req;         -- Virtual DIP-SW   are DIP-SW
                ff_dip_ack      <=  ff_dip_req;         -- Sync to its req
                io43_id212      <=  "00X00000";         -- Lock Mask        is  Full Unlocked
                io44_id212      <=  "00000000";         -- Lights Mask      is  Full Off
                OpllVol         <=  "111";              -- Default OPLL Volume (old preset "110")
                SccVol          <=  "111";              -- Default SCC Volume (old preset "110")
                PsgVol          <=  "111";              -- Default PSG Volume (old preset "011")
                MstrVol         <=  "000";              -- Default Master Volume
                CustomSpeed     <=  "0010";             -- Custom Turbo     (old 10.74MHz)
                tMegaSD         <=  '1';                -- Turbo MegaSD
                tPanaRedir      <=  '0';                -- Pana Redirection
                VdpMode         <=  '0';                -- VDP High Speed   is  On  
                Mapper_req      <=  ff_dip_req(6);      -- Set Mapper state to  DIP-SW7 state
                Mapper_ack      <=  ff_dip_req(6);      -- Prevent system crash using DIP-SW7
                MegaSD_req      <=  ff_dip_req(7);      -- Set MegaSD state to  DIP-SW8 state
                MegaSD_ack      <=  ff_dip_req(7);      -- Prevent system crash using DIP-SW8
                io41_id008_n    <=  '1';                -- CPU Clock        is  3.58MHz
                swioKmap        <=  DefKmap;            -- Keyboard Layout  to  Default
                swioCmt         <=  '0';                -- CMT              is  Off
                LightsMode      <=  '0';                -- Lights Mode      is  Auto
                Red_sta         <=  not io41_id008_n;   -- Red Led          is  Turbo 5.37MHz
                LastRst_sta     <=  '0';                -- Cold state
                Blink_ena       <=  '1';                -- MegaSD Blink     is  On
                pseudoStereo    <=  '0';                -- Pseudo-Stereo    is  Off
                async5m         <=  '0';                -- Async. tPana     is  Off
            else
                -- Warm Reset
                io42_id212(6)   <=  Mapper_req;         -- Set Mapper state to  last required
                Mapper_ack      <=  Mapper_req;         -- Confirm the last Mapper state
                io42_id212(7)   <=  MegaSD_req;         -- Set MegaSD state to  last required
                MegaSD_ack      <=  MegaSD_req;         -- Confirm the last MegaSD state
                LastRst_sta     <=  '1';                -- Warm state
            end if;

        elsif( clk21m'event and clk21m = '1' )then
            if( warmRESET /= '0' )then
                warmRESET   <=  '0';                    -- End of Warm Reset cycle
            else
                -- in assignment: 'Green Level Enabler'
                GreenLvEna  <=  '0';
                -- in assignment: 'Reset Request State' (internal signal)
                if( (Mapper_req /= io42_id212(6)) or (MegaSD_req /= io42_id212(7)) )then
                    RstReq_sta  <=  '1';                                    -- Yes
                else
                    RstReq_sta  <=  '0';                                    -- No
                end if;
                -- in assignment: 'Red State'
                if( LightsMode = '0')then
                    Red_sta     <=  not io41_id008_n;
                end if;
                -- in assignment: 'DIP-SW' (under 1chipMSX)
                if( ff_dip_req(0) /= ff_dip_ack(0) )then                    -- DIP-SW1      is  TURBO state
                    if( io43_id212(0) = '0' )then                           -- BIT[0]=0     of  Lock Mask
                        io41_id008_n    <=  '1';                            -- 5.37MHz      is  Off
                        io42_id212(0)   <=  ff_dip_req(0);                  -- 3.58MHz      or  Custom Turbo
                        ff_dip_ack(0)   <=  ff_dip_req(0);
                    end if;
                end if;
                if( ff_dip_req(1) /= ff_dip_ack(1) )then                    -- DIP-SW2      is  DISPLAY(A) state
                    if( io43_id212(1) = '0' )then                           -- BIT[1]=0     of  Lock Mask
                        io42_id212(1)   <=  ff_dip_req(1);
                        ff_dip_ack(1)   <=  ff_dip_req(1);
                    end if; 
                end if;
                if( ff_dip_req(2) /= ff_dip_ack(2) )then                    -- DIP-SW3      is  DISPLAY(B) state
                    if( io43_id212(1) = '0' )then                           -- BIT[1]=0     of  Lock Mask
                        io42_id212(2)   <=  ff_dip_req(2);
                        ff_dip_ack(2)   <=  ff_dip_req(2);
                    end if; 
                end if;
                if( ff_dip_req(3) /= ff_dip_ack(3) )then                    -- DIP-SW4      is  SLOT1 state
                    if( io43_id212(3) = '0' )then                           -- BIT[3]=0     of  Lock Mask
                        io42_id212(3)   <=  ff_dip_req(3);
                        ff_dip_ack(3)   <=  ff_dip_req(3);
                    end if; 
                end if;
                if( ff_dip_req(4) /= ff_dip_ack(4) )then                    -- DIP-SW5      is  SLOT2(A) state
                    if( io43_id212(4) = '0' )then                           -- BIT[4]=0     of  Lock Mask
                        io42_id212(4)   <=  ff_dip_req(4);
                        ff_dip_ack(4)   <=  ff_dip_req(4);
                    end if;
                end if;
                if( ff_dip_req(5) /= ff_dip_ack(5) )then                    -- DIP-SW6      is  SLOT2(B) state
                    if( io43_id212(4) = '0' )then                           -- BIT[4]=0     of  Lock Mask
                        io42_id212(5)   <=  ff_dip_req(5);
                        ff_dip_ack(5)   <=  ff_dip_req(5);
                    end if;
                end if;
                if( ff_dip_req(6) /= ff_dip_ack(6) )then                    -- DIP-SW7      is  MAPPER state
                    if( io43_id212(6) = '0' )then                           -- BIT[6]=0     of  Lock Mask
                        Mapper_req      <=  ff_dip_req(6);
                        ff_dip_ack(6)   <=  ff_dip_req(6);
                    end if;
                end if;
                if( ff_dip_req(7) /= ff_dip_ack(7) )then                    -- DIP-SW8      is  MEGASD state
                    if( io43_id212(7) = '0' )then                           -- BIT[7]=0     of  Lock Mask
                        MegaSD_req      <=  ff_dip_req(7);
                        ff_dip_ack(7)   <=  ff_dip_req(7);
                    end if;
                end if;
                -- in assignment: 'Toggle Keys' (from keyboard)
                if( SdPaus = '0' )then
                    if( Fkeys(7) = '0' )then
                        if( io43_id212(0) = '0' )then                       -- BIT[0]=0     of  Lock Mask
                            if( Fkeys(0) /= vFKeys(0) )then                 -- F12          is  TURBO selector
                                if( io41_id008_n = '1' and io42_id212(0) = '0' )then
                                    io41_id008_n    <=  '0';                -- 3.58MHz      >>  5.37MHz
                                elsif( io41_id008_n = '0' and io42_id212(0) = '0' )then
                                    io41_id008_n    <=  '1';
                                    io42_id212(0)   <=  '1';                -- 5.37MHz      >>  Custom Turbo
                                else
                                    io42_id212(0)   <=  '0';                -- Custom Turbo >>  3.58MHz
                                end if;
                            end if;
                        end if;
                        if( io43_id212(1) = '0' )then                       -- BIT[1]=0     of  Lock Mask
                            if( ff_Reso /= Reso )then                       -- PRTSCR       is  DISPLAY selector (next)
                                case io42_id212(2 downto 1) is
                                when "00"   =>  io42_id212(2)           <=  '1';    --  Y/C     to  RGB
                                when "10"   =>  io42_id212(2 downto 1)  <=  "01";   --  RGB     to  VGA
                                when "01"   =>  io42_id212(2)           <=  '1';    --  VGA     to  VGA+
                                when "11"   =>  io42_id212(2 downto 1)  <=  "00";   --  VGA+    to  Y/C
                                end case;
                            end if;
                        end if;
                        if( io43_id212(2) = '0' )then                       -- BIT[2]=0     of  Lock Mask
                            if( Fkeys(5 downto 1) /= vFKeys(5 downto 1) )then
                                GreenLvEna  <=  '1';
                                LevCtrl     <=  "111";
                            end if;
                            if( Fkeys(1) /= vFKeys(1) )then                 -- F11          is  OPLL Volume Up
                                if( OpllVol /= "111" )then
                                    LevCtrl <= OpllVol + 1;
                                    OpllVol <= OpllVol + 1;
                                end if;
                            end if;
                            if( Fkeys(2) /= vFKeys(2) )then                 -- F10          is  SCC Volume Up
                                if( SccVol /= "111" )then
                                    LevCtrl <= SccVol + 1;
                                    SccVol  <= SccVol + 1;
                                end if;
                            end if;
                            if( Fkeys(3) /= vFKeys(3) )then                 -- F9           is  PSG Volume Up
                                if( PsgVol /= "111" )then
                                    LevCtrl <= PsgVol + 1;
                                    PsgVol  <= PsgVol + 1;
                                end if;
                            end if;
                            if( Fkeys(4) /= vFkeys(4) )then                 -- PGDOWN       is  Master Volume Down
                                if( MstrVol /= "111" )then
                                    LevCtrl <= not (MstrVol + 1);
                                    MstrVol <= MstrVol + 1;
                                else
                                    LevCtrl <= "000";                                   
                                end if;
                            end if;
                            if( Fkeys(5) /= vFkeys(5) )then                 -- PGUP         is  Master Volume Up
                                if( MstrVol /= "000" )then
                                    LevCtrl <= not (MstrVol - 1);
                                    MstrVol <= MstrVol - 1;
                                end if;
                            end if;
                            if( ff_Scro /= Scro )then                       -- SCRLK        is  CMT selector
                                swioCmt     <=  not swioCmt;
                            end if;
                        end if;
                    else                                                    --  BIT[0]=0    of  Lock Mask
                        if( io43_id212(0) = '0' and io42_id212(0) = '1' )then
                            if( Fkeys(5 downto 4) /= vFKeys(5 downto 4) )then
                                GreenLvEna  <=  '1';
                            end if;
                            if( Fkeys(5) /= vFkeys(5) )then                 -- SHIFT+PGUP   is  Custom Turbo selector (clock up)
                                if( CustomSpeed /= "0010" )then
                                    LevCtrl     <= "010" - CustomSpeed(2 downto 0);
                                    CustomSpeed <= CustomSpeed - 1;
                                else
                                    LevCtrl <= "111";
                                end if;
                            end if;
                            if( Fkeys(4) /= vFkeys(4) )then                 -- SHIFT+PGDOWN is  Custom Turbo selector (clock down)
                                if( CustomSpeed /= "1000" )then
                                    LevCtrl     <= "000" - CustomSpeed(2 downto 0);
                                    CustomSpeed <= CustomSpeed + 1;
                                else
                                    LevCtrl <= "001";
                                end if;
                            end if;
                        end if;
                        if( io43_id212(1) = '0' )then                       -- BIT[1]=0     of  Lock Mask
                            if( ff_Reso /= Reso )then                       -- SHIFT+PRTSCR is  DISPLAY selector (previous)
                                case io42_id212(2 downto 1) is
                                when "11"   =>  io42_id212(2)           <=  '0';    --  VGA+    to  VGA
                                when "01"   =>  io42_id212(2 downto 1)  <=  "10";   --  VGA     to  RGB
                                when "10"   =>  io42_id212(2)           <=  '0';    --  RGB     to  Y/C
                                when "00"   =>  io42_id212(2 downto 1)  <=  "11";   --  Y/C     to  VGA+
                                end case;
                            end if;
                        end if;
                        if( io43_id212(2) = '0' )then                       -- BIT[2]=0     of  Lock Mask
                            if( Fkeys(3 downto 1) /= vFKeys(3 downto 1) )then
                                GreenLvEna  <=  '1';
                                LevCtrl     <=  "000";
                            end if;                         
                            if( Fkeys(1) /= vFKeys(1) )then                 -- SHIFT+F11    is  OPLL Volume Down
                                if( OpllVol /= "000" )then
                                    LevCtrl <= OpllVol - 1;
                                    OpllVol <= OpllVol - 1;
                                end if;
                            end if;
                            if( Fkeys(2) /= vFKeys(2) )then                 -- SHIFT+F10    is  SCC Volume Down
                                if( SccVol /= "000" )then
                                    LevCtrl <= SccVol - 1;
                                    SccVol  <= SccVol - 1;
                                end if;
                            end if;
                            if( Fkeys(3) /= vFKeys(3) )then                 -- SHIFT+F9     is  PSG Volume Down
                                if( PsgVol /= "000" )then
                                    LevCtrl <= PsgVol - 1;
                                    PsgVol  <= PsgVol - 1;
                                end if;
                            end if;
                        end if;
                        if( io43_id212(3) = '0' )then                       -- BIT[3]=0     of  Lock Mask
                            if( Fkeys(0) /= vFKeys(0) )then                 -- SHIFT+F12    is  SLOT1 selector
                                io42_id212(3)   <=  not io42_id212(3);
                            end if;                                         -- EXTERNAL SLOT1   >> <<   INTERNAL SCC-I(A)
                        end if;
                        if( io43_id212(4) = '0' )then                       -- BIT[4]=0     of  Lock Mask
                            if( ff_Scro /= Scro )then                       -- SHIFT+SCRLK  is  SLOT2 selector
                                case io42_id212(5 downto 4) is
                                when "00"   =>  io42_id212(5)           <=  '1';    --  EXTERNAL SLOT2      to  INTERNAL ASCII 8K
                                when "10"   =>  io42_id212(5 downto 4)  <=  "01";   --  INTERNAL ASCII 8K   to  INTERNAL SCC-I(B)
                                when "01"   =>  io42_id212(5)           <=  '1';    --  INTERNAL SCC-I(B)   to  INTERNAL ASCII 16K
                                when "11"   =>  io42_id212(5 downto 4)  <=  "00";   --  INTERNAL ASCII 16K  to  EXTERNAL SLOT2
                                end case;
                            end if;                                         -- [Hint!] You can get SCC-I(B) quickly with a SHIFT+'double'SCRLK
                        end if;
                    end if;
                end if;
                -- in assignment: 'Port $40 [ID Manufacturers/Devices]' (read_n/write)
                if( req = '1' and wrt = '1' and (adr(3 downto 0) = "0000") )then
                    case dbo is
                        when "00001000" =>  io40_n  <=  "11110111";         --  ID 008 => $08
                        when "11010100" =>  io40_n  <=  "00101011";         --  ID 212 => $D4 => 1chipMSX
                        when others     =>  io40_n  <=  "11111111";         --  invalid IDs
                    end case;
                end if;
                -- in assignment: 'Port $41 ID008 BIT[0] [Turbo 5.37MHz]' (write_n only)
                if( req = '1' and wrt = '1' and (adr(3 downto 0) = "0001")  and (io40_n = "11110111") )then
                    if( tPanaRedir = '0')then
                        io41_id008_n    <=  dbo(0);                         -- 3.58MHz  >>      << 5.37MHz
                        io42_id212(0)   <=  '0';                            -- 5.37MHz  have priority over 3.58MHz
                    else
                        io41_id008_n    <=  '1';                            -- Custom Turbo
                        io42_id212(0)   <=  not dbo(0);
                    end if;
                end if;
                -- in assignment: 'Port $41 ID212 [Smart Commands]' (write only)
                if( req = '1' and wrt = '1' and (adr(3 downto 0) = "0001")  and (io40_n = "00101011") )then
                    io41_id212_n    <=  not dbo;
                    case dbo is
                        -- SMART CODES  #000
--                      when "00000000" =>                                  -- Null Command (Reserved)
--                          null;
                        -- SMART CODES  #001, #002  
                        when "00000001" =>                                  -- True 5.37MHz     via ID008 (Default)
                            tPanaRedir      <=  '0';
                        when "00000010" =>                                  -- Custom Speed     via ID008
                            tPanaRedir      <=  '1';
                        -- SMART CODES  #003, #004, #005, #006, #007, #008, #009, #010
                        when "00000011" =>                                  -- Standard         3.58MHz
                            io41_id008_n    <=  '1';
                            io42_id212(0)   <=  '0';
                        when "00000100" =>                                  -- Custom Speed 1   4.10MHz
                            io41_id008_n    <=  '1';
                            io42_id212(0)   <=  '1';
                            CustomSpeed     <=  "1000";
                        when "00000101" =>                                  -- Custom Speed 2   4.48MHz
                            io41_id008_n    <=  '1';
                            io42_id212(0)   <=  '1';
                            CustomSpeed     <=  "0111";
                        when "00000110" =>                                  -- Custom Speed 3   4.90MHz
                            io41_id008_n    <=  '1';
                            io42_id212(0)   <=  '1';
                            CustomSpeed     <=  "0110";
                        when "00000111" =>                                  -- Custom Speed 4   5.39MHz
                            io41_id008_n    <=  '1';
                            io42_id212(0)   <=  '1';
                            CustomSpeed     <=  "0101";
                        when "00001000" =>                                  -- Custom Speed 5   6.10MHz
                            io41_id008_n    <=  '1';
                            io42_id212(0)   <=  '1';
                            CustomSpeed     <=  "0100";
                        when "00001001" =>                                  -- Custom Speed 6   6.96MHz
                            io41_id008_n    <=  '1';
                            io42_id212(0)   <=  '1';
                            CustomSpeed     <=  "0011";
                        when "00001010" =>                                  -- Custom Speed 7   8.06MHz (Default)
                            io41_id008_n    <=  '1';
                            io42_id212(0)   <=  '1';
                            CustomSpeed     <=  "0010";
                        -- SMART CODES  #011, #012
                        when "00001011" =>                                  -- Turbo MegaSD     Off
                            tMegaSD         <=  '0';
                        when "00001100" =>                                  -- Turbo MegaSD     On  (Default)
                            tMegaSD         <=  '1';
                        -- SMART CODES  #013, #014, #015, #016, #017, #018, #19, #20
                        when "00001101" =>                                  -- Ext. Slot1       + Ext. Slot2
                            io42_id212(5 downto 3)  <=  "000";
                        when "00001110" =>                                  -- Int. SCC-I Slot1 + Ext. Slot2
                            io42_id212(5 downto 3)  <=  "001";
                        when "00001111" =>                                  -- Ext. Slot1       + Int. SCC-I Slot2
                            io42_id212(5 downto 3)  <=  "010";
                        when "00010000" =>                                  -- Int. SCC-I Slot1 + Int. SCC-I Slot2
                            io42_id212(5 downto 3)  <=  "011";
                        when "00010001" =>                                  -- Ext. Slot1       + Int. ASCII8K Slot2
                            io42_id212(5 downto 3)  <=  "100";
                        when "00010010" =>                                  -- Int. SCC-I Slot1 + Int. ASCII8K Slot2
                            io42_id212(5 downto 3)  <=  "101";
                        when "00010011" =>                                  -- Ext. Slot1       + Int. ASCII16K Slot2
                            io42_id212(5 downto 3)  <=  "110";                              
                        when "00010100" =>                                  -- Int. SCC-I Slot1 + Int. ASCII16K Slot2
                            io42_id212(5 downto 3)  <=  "111";
                        -- SMART CODES  #021, #022
                        when "00010101" =>                                  -- Japanese Keyboard Layout
                            swioKmap        <=  '0';
                        when "00010110" =>                                  -- Non-Japanese Keyboard Layout
                            swioKmap        <=  '1';
                        -- SMART CODES  #023, #024, #025, #026
                        when "00010111" =>                                  -- Display Mode 15KHz Composite or S-Video
                            io42_id212(2 downto 1)  <=  "00";
                        when "00011000" =>                                  -- Display Mode 15KHz RGB+Audio(Mono)
                            io42_id212(2 downto 1)  <=  "10";
                        when "00011001" =>                                  -- Display Mode 31Khz VGA
                            io42_id212(2 downto 1)  <=  "01";
                        when "00011010" =>                                  -- Display Mode 31Khz VGA High Luminance
                            io42_id212(2 downto 1)  <=  "11";
                        -- SMART CODES  #027, #028
                        when "00011011" =>                                  -- VDP High Speed Mode is Off (Default)
                            VdpMode         <=  '0';
                        when "00011100" =>                                  -- VDP High Speed Mode is On (V9958 only)
                            VdpMode         <=  '1' and V9938_n;
                        -- SMART CODES  #029, #030
                        when "00011101" =>                                  -- MegaSD Off       (warm reset is required)
                            MegaSD_req      <=  '0';
                        when "00011110" =>                                  -- MegaSD On        (warm reset is required)
                            MegaSD_req      <=  '1';
                        -- SMART CODES  #031, #032, #033, #034, #035
                        when "00011111" =>                                  -- MegaSD Blink Off + DIP-SW8 State On
                            Blink_ena       <=  '0';
                        when "00100000" =>                                  -- MegaSD Blink On  + DIP-SW8 State Off (Default)
                            Blink_ena       <=  '1';                        -- This mode have priority when Lights Mode is On                           
                        when "00100001" =>                                  -- Lights Mode      is  Auto (Default)
                            LightsMode      <=  '0';                        -- Red Led          is  Turbo 5.37MHz
                        when "00100010" =>                                  -- Lights Mode      is  On + Red Off
                            LightsMode      <=  '1';
                            Red_sta         <=  '0';
                        when "00100011" =>                                  -- Lights Mode      is  On + Red On
                            LightsMode      <=  '1';
                            Red_sta         <=  '1';
                        -- SMART CODES  #036, #037, #038
                        when "00100100" =>                                  -- Mute Volume Preset
                            OpllVol         <=  "000";
                            SccVol          <=  "000";
                            PsgVol          <=  "000";
                            MstrVol         <=  "000";
                        when "00100101" =>                                  -- Original Volume Preset
                            OpllVol         <=  "110";
                            SccVol          <=  "110";
                            PsgVol          <=  "011";
                            MstrVol         <=  "000";
                        when "00100110" =>                                  -- Default Volume Preset
                            OpllVol         <=  "111";
                            SccVol          <=  "111";
                            PsgVol          <=  "111";
                            MstrVol         <=  "000";
                        -- SMART CODES  #039, #040
                        when "00100111" =>
                            swioCmt         <=  '0';                        -- CMT Off          (Default)
                        when "00101000" =>
                            swioCmt         <=  '1';                        -- CMT On
                        -- SMART CODES  #041, #042
                        when "00101001" =>                                  -- Turbo Locked
                            io43_id212(0)   <=  '1';
                        when "00101010" =>                                  -- Turbo Unlocked
                            io43_id212(0)   <=  '0';
                        -- SMART CODES  #043, #044
                        when "00101011" =>                                  -- Display Locked
                            io43_id212(1)   <=  '1';
                        when "00101100" =>                                  -- Display Unlocked
                            io43_id212(1)   <=  '0';
                        -- SMART CODES  #045, #046
                        when "00101101" =>                                  -- Audio Mixer & CMT Locked
                            io43_id212(2)   <=  '1';
                        when "00101110" =>                                  -- Audio Mixer & CMT Unlocked
                            io43_id212(2)   <=  '0';
                        -- SMART CODES  #047, #048
                        when "00101111" =>                                  -- Slot1 Locked
                            io43_id212(3)   <=  '1';
                        when "00110000" =>                                  -- Slot1 Unlocked
                            io43_id212(3)   <=  '0';
                        -- SMART CODES  #049, #050
                        when "00110001" =>                                  -- Slot2 Locked
                            io43_id212(4)   <=  '1';
                        when "00110010" =>                                  -- Slot2 Unlocked
                            io43_id212(4)   <=  '0';
                        -- SMART CODES  #051, #052
                        when "00110011" =>                                  -- Slot1 + Slot2 Locked
                            io43_id212(4 downto 3)  <=  "11";
                        when "00110100" =>                                  -- Slot1 + Slot2 Unlocked
                            io43_id212(4 downto 3)  <=  "00";
                        -- SMART CODES  #053, #054
                        when "00110101" =>                                  -- Reset Key Locked
                            io43_id212(5)   <=  '1';
                        when "00110110" =>                                  -- Reset Key Unlocked
                            io43_id212(5)   <=  '0';
                        -- SMART CODES  #055, #056
                        when "00110111" =>                                  -- Mapper Locked
                            io43_id212(6)   <=  '1';
                        when "00111000" =>                                  -- Mapper Unlocked
                            io43_id212(6)   <=  '0';
                        -- SMART CODES  #057, #058
                        when "00111001" =>                                  -- MegaSD Locked
                            io43_id212(7)   <=  '1';
                        when "00111010" =>                                  -- MegaSD Unlocked
                            io43_id212(7)   <=  '0';
                        -- SMART CODES  #059, #060
                        when "00111011" =>                                  -- Full Locked
                            io43_id212      <=  "11111111";
                        when "00111100" =>                                  -- Full Unlocked
                            io43_id212      <=  "00000000";
                         -- SMART CODES  #061, #062
                        when "00111101" =>                                  -- Pseudo Stereo Off (default)
                            pseudoStereo    <=  '0';
                        when "00111110" =>                                  -- Pseudo Stereo On
                            pseudoStereo    <=  '1';
                         -- SMART CODES  #063, #064
                        when "00111111" =>                                  -- Asynchronous tPana Off (default)
                            async5m         <=  '0';
                        when "01000000" =>                                  -- Asynchronous tPana On (external slots 3.58MHz)
                            async5m         <=  '1';
                        -- SMART CODES  #65, #..., #127                     -- Free Group
                        -- SMART CODE   #128
                        when "10000000" =>                                  -- Null Command (useful for programming)
                            null;
                        -- SMART CODES  #129, #..., #210                    -- Free Group
                        -- SMART CODE   #211
                        when "11010011" =>                                  -- Keyboard Layout Restore
                            swioKmap        <=  DefKmap;
                        -- SMART CODE   #212
                        when "11010100" =>
                            null;                                           -- Null Command
                        -- SMART CODES  #213
                        when "11010101" =>                                  -- Turbo Restore
                            io42_id212(0)   <=  ff_dip_req(0);
                            ff_dip_ack(0)   <=  ff_dip_req(0);
                            CustomSpeed     <=  "0010";
                            tMegaSD         <=  '1';
                            tPanaRedir      <=  '0';
                            io41_id008_n    <=  '1';
                            Red_sta         <=  not io41_id008_n;
                        -- SMART CODES  #214, #..., #249                    -- Free Group
                        -- SMART CODES  #250
                        when "11111010" =>                                  -- Set the Last Reset state to Cold Reset
                            LastRst_sta     <=  '0';
                        -- SMART CODES  #251, #252, #253, #254
                        when "11111011" =>                                  -- Cold Reset (Volume will be reset)
                            swioRESET_n     <=  '0';
                        when "11111100" =>                                  -- Mapper 2048KB    + Warm Reset (Volume will not reset)
                            Mapper_req      <=  '0';
                            warmRESET       <=  '1';
                            swioRESET_n     <=  '0';
                        when "11111101" =>                                  -- Warm Reset (Volume will not reset)
                            warmRESET       <=  '1';
                            swioRESET_n     <=  '0';
                        when "11111110" =>                                  -- Mapper 4096KB    + Warm Reset (Volume will not reset)
                            Mapper_req      <=  '1';
                            warmRESET       <=  '1';
                            swioRESET_n     <=  '0';
                        -- SMART CODE   #255
                        when "11111111" =>                                  -- System Restore
                            io42_id212(5 downto 0)  <=  ff_dip_req(5 downto 0);
                            ff_dip_ack(5 downto 0)  <=  ff_dip_req(5 downto 0);
                            io43_id212      <=  "00000000";
                            io44_id212      <=  "00000000";
                            OpllVol         <=  "111";
                            SccVol          <=  "111";
                            PsgVol          <=  "111";
                            MstrVol         <=  "000";
                            CustomSpeed     <=  "0010";
                            tMegaSD         <=  '1';
                            tPanaRedir      <=  '0';
                            VdpMode         <=  '0';
                            Mapper_req      <=  ff_dip_req(6);
                            MegaSD_req      <=  ff_dip_req(7);
                            io41_id008_n    <=  '1';
                            swioKmap        <=  DefKmap;
                            swioCmt         <=  '0';
                            LightsMode      <=  '0';
                            Red_sta         <=  not io41_id008_n;
                            Blink_ena       <=  '1';
                            pseudoStereo    <=  '0';
                            async5m         <=  '0';
                        -- ALL UNUSED CODES
                        when others     =>
                            io41_id212_n    <=  "11111111";                 -- Not found
                    end case;
                end if;
                -- in assignment: 'Port $42 ID212 [Virtual DIP-SW]' (read/write_n, always unlocked)
                if( req = '1' and wrt = '1' and (adr(3 downto 0) = "0010")  and (io40_n = "00101011") )then
                    io41_id008_n                <=  '1';                    -- Custom Turbo have priority over 5.37MHz
                    io42_id212(5 downto 0)      <=  not dbo(5 downto 0);    -- BIT[0-5]
                    Mapper_req                  <=  not dbo(6);             -- BIT[6]
                    MegaSD_req                  <=  not dbo(7);             -- BIT[7]
                end if;
                -- in assignment: 'Port $43 ID212 [Lock Mask]' (read/write_n)
                if( req = '1' and wrt = '1' and (adr(3 downto 0) = "0011")  and (io40_n = "00101011") )then
                    io43_id212          <=  not dbo;
                end if;
                -- in assignment: 'Port $44 ID212 [Green Leds Mask]' (read/write_n)
                if( req = '1' and wrt = '1' and (adr(3 downto 0) = "0100")  and (io40_n = "00101011") )then
                    io44_id212          <=  not dbo;
                end if;
                -- in assignment: 'Port $45 ID212 [Master/Psg Volume]' (read/write_n)
                if( req = '1' and wrt = '1' and (adr(3 downto 0) = "0101")  and (io40_n = "00101011") )then
                    PsgVol              <=  not dbo(2 downto 0);
                    MstrVol             <=  dbo(6 downto 4);
                end if;
                -- in assignment: 'Port $46 ID212 [Scc/Opll Volume]' (read/write_n)
                if( req = '1' and wrt = '1' and (adr(3 downto 0) = "0110")  and (io40_n = "00101011") )then
                    OpllVol             <=  not dbo(2 downto 0);
                    SccVol              <=  not dbo(6 downto 4);
                end if;
            end if;
        end if;
    end process;

    -- detection of main ack signal
    process( reset, clk21m )
    begin
        if( reset = '1' )then
            swio_ack    <= '0';
        elsif( clk21m'event and clk21m = '1' and warmRESET /= '1' )then
            swio_ack    <= req;                                             -- Protected until the end of Warm Reset
        end if;
    end process;

end RTL;
