Subversion Repositories pentevo

Rev

Rev 1134 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed

  1. #include "std.h"
  2.  
  3. #include "emul.h"
  4. #include "funcs.h"
  5. #include "vars.h"
  6. #include "draw.h"
  7. #include "memory.h"
  8. #include "atm.h"
  9. #include "profi.h"
  10. #include "sndrender/sndcounter.h"
  11. #include "sndrender/dev_moonsound.h"
  12. #include "sound.h"
  13. #include "gs.h"
  14. #include "sdcard.h"
  15. #include "zc.h"
  16. #include "tape.h"
  17. #include "zxevo.h"
  18. #include "upd765.h"
  19. #include "zxusbnet.h"
  20.  
  21. void out(unsigned port, unsigned char val)
  22. {
  23.    port &= 0xFFFF;
  24.    u8 p1 = (port & 0xFF);
  25.    brk_port_out = port; brk_port_val = val;
  26.  
  27.    // ┬ эрўрых фх°шЇЁрЎш  яюЁЄют яю яюыэ√ь 8сшЄ
  28.  
  29.    if(conf.ula_plus)
  30.    {
  31.        if(port == 0xBF3B)
  32.        {
  33.            comp.ula_plus_group = val >> 6;
  34.            if(comp.ula_plus_group == 0)
  35.            {
  36.                comp.ula_plus_pal_idx = val & 0x3F;
  37.            }
  38.            return;
  39.        }
  40.  
  41.        if(port == 0xFF3B)
  42.        {
  43.            if(comp.ula_plus_group == 0)
  44.            {
  45.                comp.comp_pal[comp.ula_plus_pal_idx] = val;
  46.                temp.comp_pal_changed = 1;
  47.                return;
  48.            }
  49.  
  50.            if(comp.ula_plus_group == 1)
  51.            {
  52.                bool en = (val & 1) != 0;
  53.                if(comp.ula_plus_en != en)
  54.                {
  55.                    comp.ula_plus_en = en;
  56.                    if(comp.ula_plus_en)
  57.                    {
  58.                        temp.rflags |= RF_COMPPAL | RF_PALB;
  59.                    }
  60.                    else
  61.                    {
  62.                        temp.rflags &= unsigned(~(RF_COMPPAL | RF_PALB));
  63.                    }
  64.                    video_color_tables();
  65.                    temp.comp_pal_changed = 1;
  66.                }
  67.                return;
  68.            }
  69.            return;
  70.        }
  71.    }
  72.  
  73.    #ifdef MOD_GS
  74.    // 10111011 | BB
  75.    // 10110011 | B3
  76.    // 00110011 | 33
  77.    if ((port & 0xFF) == 0x33 && conf.gs_type) // 33
  78.    {
  79.        out_gs(p1, val);
  80.        return;
  81.    }
  82.    if ((port & 0xF7) == 0xB3 && conf.gs_type) // BB, B3
  83.    {
  84.        out_gs(p1, val);
  85.        return;
  86.    }
  87.    #endif
  88.  
  89.    // ZXM-MoonSound
  90.    if (conf.sound.moonsound &&
  91.        (conf.mem_model == MM_PROFI ? !(comp.pDFFD & 0x80) : 1) &&
  92.        (((p1 & 0xFC) == 0xC4) || ((p1 & 0xFE) == 0xC2)))
  93.    {
  94.        if (zxmmoonsound.write(port, val))
  95.            return;
  96.    }
  97.  
  98.    // z-controller
  99.    if (conf.zc && (port & 0xFF) == 0x57 )
  100.    {
  101.       if ((port & 0x80FF) == 0x8057 && conf.mem_model == MM_ATM3
  102.          &&(comp.flags & CF_DOSPORTS))
  103.          return;
  104.        Zc.Wr(port, val);
  105.        return;
  106.    }
  107.    
  108.    if(conf.wiznet && (port & 0xff) == 0xab ){
  109.       pXXAB_Write(port,val);
  110.       return;
  111.    }
  112.    // divide эр nemo яюЁЄрї
  113.    if(conf.ide_scheme == IDE_NEMO_DIVIDE)
  114.    {
  115.        if((port & 0x1E) == 0x10) // rrr1000x
  116.        {
  117.            if((port & 0xFF) == 0x11)
  118.            {
  119.                comp.ide_write = val;
  120.                comp.ide_hi_byte_w = 0;
  121.                comp.ide_hi_byte_w1 = 1;
  122.                return;
  123.            }
  124.  
  125.            if((port & 0xFE) == 0x10)
  126.            {
  127.                comp.ide_hi_byte_w ^= 1;
  128.  
  129.                if(comp.ide_hi_byte_w1) // ┴√ыр чряшё№ т яюЁЄ 0x11 (ёЄрЁ°шщ срщЄ єцх чряюьэхэ)
  130.                {
  131.                    comp.ide_hi_byte_w1 = 0;
  132.                }
  133.                else
  134.                {
  135.                    if(comp.ide_hi_byte_w) // ╟ряюьшэрхь ьырф°шщ срщЄ
  136.                    {
  137.                        comp.ide_write = val;
  138.                        return;
  139.                    }
  140.                    else // ╠хэ хь ёЄрЁ°шщ ш ьырф°шщ срщЄ√ ьхёЄрьш (ъръ ¤Єюую юцшфрхЄ write_hdd_5)
  141.                    {
  142.                        u8 tmp = comp.ide_write;
  143.                        comp.ide_write = val;
  144.                        val = tmp;
  145.                    }
  146.                }
  147.            }
  148.            else
  149.            {
  150.                comp.ide_hi_byte_w = 0;
  151.            }
  152.            goto write_hdd_5;
  153.        }
  154.        else if((port & 0xFF) == 0xC8)
  155.        {
  156.            return hdd.write(8, val);
  157.        }
  158.    }
  159.  
  160.    if(conf.mem_model == MM_ATM3)
  161.    {
  162.            switch(port & 0xFF){
  163.                    case 0xBF:   // ╧юЁЄ Ёрё°шЁхэшщ яхэЄхт√
  164.                                 if((comp.pBF ^ val) & comp.pBF & 8) // D3: 1->0
  165.                                 {
  166.                                         nmi_pending  = 1;
  167.                                         trdos_in_nmi = comp.flags&CF_TRDOS;
  168.                                 }
  169.                            comp.pBF = val;
  170.                            set_banks();
  171.                            return;
  172.                    case 0xBE:   // ╧юЁЄ ЁрчсыюъшЁютъш RAM0 └╥╠3
  173.                            if(cpu.nmi_in_progress&&(cpu.nmi_in_progress==conf.trdos_IORam))
  174.                            {
  175.                                   if(trdos_in_nmi)
  176.                                           comp.flags |= CF_SETDOSROM|CF_TRDOS;
  177.                                   cpu.nmi_in_progress = false;
  178.                                   set_banks();
  179.                                   return;
  180.                            }
  181.                            comp.pBE = 2; // ёўхЄўшъ фы  т√їюфр шч nmi
  182.                            return;
  183.                    case 0xBD:   // яюЁЄ рфЁхёр сЁ ъяюшэЄр ш ьрёъш яхЁхїтрЄр яюЁЄют FDD
  184.                            switch(port & 0xEFFF){
  185.                                    case 0x00BD:
  186.                                            comp.brk_addr &= 0xFF00;
  187.                                            comp.brk_addr |= ((u16)val)&0x00FF;
  188.                                            break;
  189.                                    case 0x01BD:
  190.                                            comp.brk_addr &= 0x00FF;
  191.                                            comp.brk_addr |= ( ((u16)val) << 8 )&0xFF00;
  192.                                            break;
  193.                                    case 0x03BD:
  194.                                            comp.fddIO2Ram_mask = val;
  195.                                            break;                                          
  196.                            }
  197.                            return;
  198.            }
  199.    }
  200.  
  201.    if (comp.flags & CF_DOSPORTS)
  202.    {
  203.       if(conf.mem_model == MM_ATM3 && (p1 & 0x1F) == 0x0F && !(((p1 >> 5) - 1) & 4))
  204.       {
  205.           // 2F = 001|01111b
  206.           // 4F = 010|01111b
  207.           // 6F = 011|01111b
  208.           // 8F = 100|01111b
  209.                      comp.wd_shadow[(p1 >> 5) - 1] = val;
  210.       }
  211.       if (conf.ide_scheme == IDE_ATM && (port & 0x1F) == 0x0F)
  212.       {
  213.          if (port & 0x100) { comp.ide_write = val; return; }
  214.       write_hdd_5:
  215.          port >>= 5;
  216.       write_hdd:
  217.          port &= 7;
  218.          if (port)
  219.              hdd.write(port, val);
  220.          else
  221.              hdd.write_data(unsigned(val | (comp.ide_write << 8)));
  222.          return;
  223.       }
  224.  
  225.       if ((port & 0x18A3) == (0xFFFE & 0x18A3))
  226.       { // SMUC
  227.          if (conf.smuc)
  228.          {
  229.             if ((port & 0xA044) == (0xDFBA & 0xA044))
  230.             { // clock
  231.                if (comp.pFFBA & 0x80)
  232.                    cmos_write(val);
  233.                else
  234.                    comp.cmos_addr = val;
  235.                return;
  236.             }
  237.             if ((port & 0xA044) == (0xFFBA & 0xA044))
  238.             { // SMUC system port
  239.                if ((val & 1) && (conf.ide_scheme == IDE_SMUC))
  240.                    hdd.reset();
  241.                comp.nvram.write(val);
  242.                comp.pFFBA = val;
  243.                return;
  244.             }
  245.             if ((port & 0xA044) == (0x7FBA & 0xA044))
  246.             {
  247.                 comp.p7FBA = val;
  248.                 return;
  249.             }
  250.          }
  251.          if ((port & 0x8044) == (0xFFBE & 0x8044) && conf.ide_scheme == IDE_SMUC)
  252.          { // FFBE, FEBE
  253.             if(comp.pFFBA & 0x80)
  254.             {
  255.                 if(!(port & 0x100))
  256.                     hdd.write(8, val); // control register
  257.                 return;
  258.             }
  259.  
  260.             if (!(port & 0x2000))
  261.             {
  262.                 comp.ide_write = val;
  263.                 return;
  264.             }
  265.             port >>= 8;
  266.                 goto write_hdd;
  267.          }
  268.       }
  269.  
  270.       if (conf.mem_model == MM_ATM710 || conf.mem_model == MM_ATM3)
  271.       {
  272.          if ((conf.mem_model == MM_ATM3) && ((port & 0x3FFF) == 0x37F7)) // x7f7 ATM3 4Mb memory manager
  273.          {
  274.              unsigned idx = ((comp.p7FFD & 0x10) >> 2) | ((port >> 14) & 3);
  275.              comp.pFFF7[idx] = (comp.pFFF7[idx] & ~0x1FFU) | (val ^ 0xFF); // always ram
  276.              set_banks();
  277.              return;
  278.          }
  279.  
  280.          if (p1 == 0x77) // xx77
  281.          {
  282.              set_atm_FF77(port, val);
  283.              return;
  284.          }
  285.  
  286.          u32 mask = (conf.mem_model == MM_ATM3) ? /*0x3FFF*/ 0x0FFF : 0x00FF; // lvd fix: pentevo hardware decodes fully only low byte,
  287.                         // so using eff7 in shadow mode lead to outting to fff7,
  288.                                                                               // unlike this was in unreal!
  289.          if ((port & mask) == (0x3FF7 & mask)) // xff7
  290.          {
  291.              comp.pFFF7[((comp.p7FFD & 0x10) >> 2) | ((port >> 14) & 3)] = unsigned(((val & 0xC0) << 2) | (val & 0x3F)) ^ 0x33FU;
  292.              set_banks();
  293.              return;
  294.          }
  295.  
  296.          if ((p1 & 0x9F) == 0x9F && !(comp.aFF77 & 0x4000))
  297.              atm_writepal(port, val); // don't return - write to TR-DOS system port
  298.       }
  299.  
  300.       if(conf.mem_model == MM_PROFI)
  301.       {
  302.           if((comp.p7FFD & 0x10) && (comp.pDFFD & 0x20)) // modified ports
  303.           {
  304.               // BDI ports
  305.               if((p1 & 0x9F) == 0x83) // WD93 ports
  306.               {
  307.                   comp.wd.out((p1 & 0x60) | 0x1F, val);
  308.                   return;
  309.               }
  310.  
  311.               if((p1 & 0xE3) == 0x23) // port FF
  312.               {
  313.                   comp.wd.out(0xFF, val);
  314.                   return;
  315.               }
  316.  
  317.               // RTC
  318.               if((port & 0x9F) == 0x9F && conf.cmos)
  319.               {
  320.                 if(port & 0x20)
  321.                 {
  322.                     comp.cmos_addr = val;
  323.                     return;
  324.                 }
  325.                 cmos_write(val);
  326.                 return;
  327.               }
  328.  
  329.               // IDE (AB=10101011, CB=11001011, EB=11101011)
  330.               if ((p1 & 0x9F) == 0x8B && (conf.ide_scheme == IDE_PROFI))
  331.               {
  332.                   if(p1 & 0x40)
  333.                   {    // cs1
  334.                       if (!(p1 & 0x20))
  335.                       {
  336.                           comp.ide_write = val;
  337.                           return;
  338.                       }
  339.                       port >>= 8;
  340.                       goto write_hdd;
  341.                   }
  342.  
  343.                   // cs3
  344.                   if(p1 & 0x20)
  345.                   {
  346.                       if(((port>>8) & 7) == 6)
  347.                           hdd.write(8, val);
  348.                       return;
  349.                   }
  350.               }
  351.           }
  352.           else
  353.           {
  354.               // BDI ports
  355.               if((p1 & 0x83) == 0x03)  // WD93 ports 1F, 3F, 5F, 7F
  356.               {
  357.                   comp.wd.out((p1 & 0x60) | 0x1F,val);
  358.                   return;
  359.               }
  360.  
  361.               if((p1 & 0xE3) == ((comp.pDFFD & 0x20) ? 0xA3 : 0xE3)) // port FF
  362.               {
  363.                   comp.wd.out(0xFF,val);
  364.                   return;
  365.               }
  366.           }
  367.       } // profi
  368.  
  369.       if(conf.mem_model == MM_QUORUM /* && !(comp.p00 & Q_TR_DOS)*/) // cpm ports
  370.       {
  371.           if((p1 & 0xFC) == 0x80) // 80, 81, 82, 83
  372.           {
  373.               p1 = u8(((p1 & 3) << 5) | 0x1F);
  374.  
  375.               comp.wd.out(p1, val);
  376.               return;
  377.           }
  378.  
  379.           if(p1 == 0x85) // 85
  380.           {
  381. //            01 -> 00 A
  382. //            10 -> 01 B
  383. //            00 -> 11 D (unused)
  384. //            11 -> 11 D (unused)
  385.               static const u8 drv_decode[] = { 3, 0, 1, 3 };
  386.               u8 drv = drv_decode[val & 3];
  387.               comp.wd.out(0xFF, ((val & ~3) ^ 0x10) | 0xCC | 8 | drv);
  388.               return;
  389.           }
  390.       } // quorum
  391.       else if ((p1 & 0x1F) == 0x1F) // 1F, 3F, 5F, 7F, FF
  392.       {
  393.                   if(p1 & 0x80) {
  394.                         comp.trdos_last_ff = val & 0x1f;
  395.                   }
  396.                   if((comp.flags & CF_TRDOS)&&conf.trdos_IORam&&(bankr[0]==base_dos_rom)&&(p1 & 0x80)){
  397.                      comp.wd.out(p1, val);
  398.                          if( ( (1<<comp.wd.drive) & comp.fddIO2Ram_mask ) && ( ( cpu.pc & 0xc000 ) == 0 ) ){
  399.                                 trdos_in_nmi = comp.flags&CF_TRDOS;
  400.                                 cpu.nmi_in_progress=conf.trdos_IORam;
  401.                                 set_banks();
  402.                          }
  403.                   }else if((comp.flags & CF_TRDOS) && ( ( cpu.pc & 0xc000 ) == 0 )
  404.                           && conf.trdos_IORam && (1<<comp.wd.drive)&comp.fddIO2Ram_mask && (bankr[0]==base_dos_rom))
  405.                   {
  406.                      trdos_in_nmi = comp.flags&CF_TRDOS;
  407.                          cpu.nmi_in_progress=conf.trdos_IORam;
  408.                          set_banks();
  409.                   }else{
  410.                      comp.wd.out(p1, val);
  411.                   }
  412.           return;
  413.       }
  414.       // don't return - out to port #FE works in trdos!
  415.    }
  416.    else // эх dos
  417.    {
  418.        if((p1 == 0x3F) && (conf.sound.ay_scheme == AY_SCHEME_FULLER)) // fuller AY register select
  419.        {
  420.            ay[0].select(val);
  421.            return;
  422.        }
  423.        if((p1 == 0x5F) && (conf.sound.ay_scheme == AY_SCHEME_FULLER)) // fuller AY data
  424.        {
  425.            ay[0].write(temp.sndblock ? 0 : cpu.t, val);
  426.            return;
  427.        }
  428.  
  429.          if(((port & 0xA3) == 0xA3) && (conf.ide_scheme == IDE_DIVIDE))
  430.          {
  431.              if((port & 0xFF) == 0xA3)
  432.              {
  433.                  comp.ide_hi_byte_w ^= 1;
  434.                  if(comp.ide_hi_byte_w)
  435.                  {
  436.                      comp.ide_write = val;
  437.                      return;
  438.                  }
  439.                  u8 tmp = comp.ide_write;
  440.                  comp.ide_write = val;
  441.                  val = tmp;
  442.              }
  443.              else
  444.              {
  445.                  comp.ide_hi_byte_w = 0;
  446.              }
  447.              port >>= 2;
  448.              goto write_hdd;
  449.          }
  450.  
  451.          if ((unsigned char)port == 0x1F && conf.sound.ay_scheme == AY_SCHEME_POS)
  452.          {
  453.              comp.active_ay = val & 1;
  454.              return;
  455.          }
  456.  
  457.          if (!(port & 6) && (conf.ide_scheme == IDE_NEMO || conf.ide_scheme == IDE_NEMO_A8))
  458.          {
  459.              unsigned hi_byte = (conf.ide_scheme == IDE_NEMO)? (port & 1) : (port & 0x100);
  460.              if (hi_byte)
  461.              {
  462.                  comp.ide_write = val;
  463.                  return;
  464.              }
  465.              if ((port & 0x18) == 0x08)
  466.              {
  467.                  if ((port & 0xE0) == 0xC0)
  468.                      hdd.write(8, val);
  469.                  return;
  470.              } // CS1=0,CS0=1,reg=6
  471.              if ((port & 0x18) != 0x10)
  472.                  return; // invalid CS0,CS1
  473.              goto write_hdd_5;
  474.          }
  475.    }
  476.  
  477.    if((port & 0xFF) == 0x00 && conf.mem_model == MM_QUORUM)
  478.    {
  479.        comp.p00 = val;
  480.        set_banks();
  481.        return;
  482.    }
  483.  
  484.    #ifdef MOD_VID_VD
  485.    if ((unsigned char)port == 0xDF)
  486.    {
  487.        comp.pVD = val;
  488.        comp.vdbase = (comp.pVD & 4)? vdmem[comp.pVD & 3] : 0;
  489.        return;
  490.    }
  491.    #endif
  492.  
  493.    // port #FE
  494.    bool pFE;
  495.  
  496.    // scorp  xx1xxx10 /dos=1 (sc16 green)
  497.    if((conf.mem_model == MM_SCORP || conf.mem_model == MM_PROFSCORP))
  498.        pFE = ((port & 0x23) == (0xFE & 0x23)) && !(comp.flags & CF_DOSPORTS);
  499.    else if(conf.mem_model == MM_QUORUM) // 1xx11xx0
  500.        pFE = ((port & 0x99) == (0xFE & 0x99));
  501.    else // others xxxxxxx0
  502.        pFE = !(port & 1);
  503.  
  504.    if (pFE)
  505.    {
  506. //[vv]      assert(!(val & 0x08));
  507.  
  508.       spkr_dig = (val & 0x10) ? conf.sound.beeper_vol : 0;
  509.       mic_dig = (val & 0x08) ? conf.sound.micout_vol : 0;
  510.  
  511.       // speaker & mic
  512.       if ((comp.pFE ^ val) & 0x18)
  513.       {
  514. //          __debugbreak();
  515.           flush_dig_snd();
  516.       }
  517.  
  518.  
  519.       unsigned char new_border = (val & 7);
  520.       if (conf.mem_model == MM_ATM710 || conf.mem_model == MM_ATM3 || conf.mem_model == MM_ATM450)
  521.           new_border |= ((port & 8) ^ 8);
  522.       if (comp.border_attr ^ new_border)
  523.           update_screen();
  524.       comp.border_attr = new_border;
  525.  
  526.       if (conf.mem_model == MM_ATM450)
  527.           set_atm_aFE((unsigned char)port);
  528.  
  529.       if (conf.mem_model == MM_PROFI)
  530.       {
  531.         if(!(port & 0x80) && (comp.pDFFD & 0x80))
  532.         {
  533.           profi_writepal(u8(~(port >> 8)));
  534.         }
  535.       }
  536.  
  537.       comp.pFE = val;
  538.       // do not return! intro to navy seals (by rst7) uses out #FC for to both FE and 7FFD
  539.    }
  540.  
  541.    // #xD
  542.    if (!(port & 2))
  543.    {
  544.  
  545.       if (conf.sound.covoxDD && (unsigned char)port == 0xDD)
  546.       { // port DD - covox
  547. //         __debugbreak();
  548.          flush_dig_snd();
  549.          covDD_vol = val*conf.sound.covoxDD_vol/0x100;
  550.          return;
  551.       }
  552.  
  553.       if (!(port & 0x8000)) // zx128 port
  554.       {
  555.          // 0001xxxxxxxxxx0x (bcig4) // 1FFD
  556.          // 0010xxxxxxxxxx0x (bcig4) // 2FFD
  557.          // 0011xxxxxxxxxx0x (bcig4) // 3FFD
  558.           if((port & (3 << 14)) == 0 && conf.mem_model == MM_PLUS3)
  559.           {
  560.               unsigned Idx = (port >> 12) & 3;
  561.               switch(Idx)
  562.               {
  563.               case 1: // 1FFD
  564.                   goto set1FFD;
  565.               case 3: // 3FFD
  566.                   Upd765.out(val);
  567.                   return;
  568.               }
  569.           }
  570.  
  571.          if ((port & 0xC003) == (0x1FFD & 0xC003) && conf.mem_model == MM_KAY)
  572.              goto set1FFD;
  573.  
  574.          // 00xxxxxxxx1xxx01 (sc16 green)
  575.          if ((port & 0xC023) == (0x1FFD & 0xC023) && (conf.mem_model == MM_SCORP || conf.mem_model == MM_PROFSCORP))
  576.          {
  577. set1FFD:
  578.             comp.p1FFD = val;
  579.             set_banks();
  580.             return;
  581.          }
  582.  
  583.          // gmx
  584.          if(port == 0x7EFD && conf.mem_model == MM_PROFSCORP)
  585.          {
  586.             comp.p7EFD = val;
  587.             set_banks();
  588.             return;
  589.          }
  590.  
  591.          if (conf.mem_model == MM_ATM450 && (port & 0x8202) == (0x7DFD & 0x8202))
  592.          {
  593.              atm_writepal(port, val);
  594.              return;
  595.          }
  596.  
  597.          // if (conf.mem_model == MM_ATM710 && (port & 0x8202) != (0x7FFD & 0x8202)) return; // strict 7FFD decoding on ATM-2
  598.  
  599.          // 01xxxxxxxx1xxx01 (sc16 green)
  600.          if ((port & 0xC023) != (0x7FFD & 0xC023) && (conf.mem_model == MM_SCORP || conf.mem_model == MM_PROFSCORP))
  601.              return;
  602.          // 0xxxxxxxxxx11x0x
  603.          if ((port & 0x801A) != (0x7FFD & 0x801A) && (conf.mem_model == MM_QUORUM))
  604.              return;
  605.  
  606.          // 7FFD
  607.          if (comp.p7FFD & 0x20)
  608.          { // 48k lock
  609.             // #EFF7.2 forces lock
  610.             if ((comp.pEFF7 & EFF7_LOCKMEM) && conf.mem_model == MM_PENTAGON && conf.ramsize == 1024)
  611.                 return;
  612.  
  613.                         if ((comp.pEFF7 & EFF7_LOCKMEM) && conf.mem_model == MM_ATM3) // lvd added eff7 to atm3
  614.                                 return;
  615.  
  616.                                
  617.             // if not pentagon-1024 or pentevo (atm3) --(added by lvd)-- or profi with #DFFD.4 set, apply lock
  618.             if (!((conf.ramsize == 1024 && conf.mem_model == MM_PENTAGON) ||
  619.                               (conf.mem_model == MM_ATM3)                             ||
  620.                   (conf.mem_model == MM_PROFI && (comp.pDFFD & 0x10)))) // molodcov_alex
  621.                 return;
  622.          }
  623.  
  624.          if ((comp.p7FFD ^ val) & 0x08)
  625.              update_screen();
  626.  
  627.          comp.p7FFD = val;
  628.          set_banks();
  629.          return;
  630.       }
  631.  
  632.       // xx0xxxxxxxxxxx0x (3.2) [vv]
  633.       if ((port & 0x2002) == (0xDFFD & 0x2002) && conf.mem_model == MM_PROFI)
  634.       {
  635.           comp.pDFFD = val;
  636.           set_banks();
  637.           return;
  638.       }
  639.  
  640.       if (conf.mem_model == MM_ATM450 && (port & 0x8202) == (0xFDFD & 0x8202))
  641.       {
  642.           comp.pFDFD = val;
  643.           set_banks();
  644.           return;
  645.       }
  646.  
  647.       // 1x0xxxxxxxx11x0x
  648.       if ((port & 0xA01A) == (0x80FD & 0xA01A) && conf.mem_model == MM_QUORUM)
  649.       {
  650.           comp.p80FD = val;
  651.           set_banks();
  652.           return;
  653.       }
  654.  
  655.       if ((port & 0xC0FF) == 0xC0FD && conf.sound.ay_scheme >= AY_SCHEME_SINGLE)
  656.       { // A15=A14=1, FxFD - AY select register
  657.          if ((conf.sound.ay_scheme == AY_SCHEME_CHRV) && ((val & 0xF0) == 0xF0)) //Alone Coder
  658.          {
  659.             if (conf.sound.ay_chip == (SNDCHIP::CHIP_YM2203))
  660.              {
  661.                                  comp.tfmstat = val;
  662.                  fmsoundon0 = val & 4;
  663.                  tfmstatuson0 = val & 2;
  664.              } //Alone Coder 0.36.6
  665.             comp.active_ay = val & 1;
  666.                         return;
  667.          };
  668.                  if((conf.sound.saa1099 == SAA_TFM_PRO)&&((comp.tfmstat&CF_TFM_SAA)==0)){
  669.                     Saa1099.WrCtl(val);
  670.                  }else{
  671.             unsigned n_ay = (conf.sound.ay_scheme == AY_SCHEME_QUADRO)? (port >> 12) & 1 : comp.active_ay;
  672.             ay[n_ay].select(val);
  673.                  }
  674.          return;
  675.       }
  676.  
  677.       if ((port & 0xC000)==0x8000 && conf.sound.ay_scheme)
  678.       {  // BFFD - AY data register
  679.                  if((conf.sound.saa1099 == SAA_TFM_PRO)&&((comp.tfmstat&CF_TFM_SAA)==0)){
  680.                     Saa1099.WrData(temp.sndblock ? 0 : cpu.t, val);
  681.                  }else{
  682.                     unsigned n_ay = (conf.sound.ay_scheme == AY_SCHEME_QUADRO)? (port >> 12) & 1 : comp.active_ay;
  683.             ay[n_ay].write(temp.sndblock? 0 : cpu.t, val);
  684.             if (conf.input.mouse == 2 && ay[n_ay].get_activereg() == 14)
  685.                 input.aymouse_wr(val);
  686.                  }
  687.          return;
  688.       }
  689.       return;
  690.    }
  691.  
  692.    if (conf.sound.sd && (port & 0xAF) == 0x0F)
  693.    { // soundrive
  694. //      __debugbreak();
  695.       if ((unsigned char)port == 0x0F) comp.p0F = val;
  696.       if ((unsigned char)port == 0x1F) comp.p1F = val;
  697.       if ((unsigned char)port == 0x4F) comp.p4F = val;
  698.       if ((unsigned char)port == 0x5F) comp.p5F = val;
  699.       flush_dig_snd();
  700.       sd_l = (conf.sound.sd_vol * (comp.p0F+comp.p1F)) >> 8;
  701.       sd_r = (conf.sound.sd_vol * (comp.p4F+comp.p5F)) >> 8;
  702.       return;
  703.    }
  704.    if (conf.sound.covoxFB && !(port & 4))
  705.    { // port FB - covox
  706. //      __debugbreak();
  707.       flush_dig_snd();
  708.       covFB_vol = val*conf.sound.covoxFB_vol/0x100;
  709.       return;
  710.    }
  711.  
  712.    if (conf.sound.saa1099 == SAA_ZXM && ((port & 0xFF) == 0xFF)) // saa1099
  713.    {
  714.        if(port & 0x100)
  715.            Saa1099.WrCtl(val);
  716.        else
  717.            Saa1099.WrData(temp.sndblock? 0 : cpu.t, val);
  718.        return;
  719.    }
  720.  
  721.    if( (port == 0xEFF7) && ( (conf.mem_model==MM_PENTAGON) || (conf.mem_model==MM_ATM3)
  722.            || conf.mem_model == MM_ATM710 ) ) // lvd added eff7 to atm3
  723.    {
  724.       unsigned char oldpEFF7 = comp.pEFF7; //Alone Coder 0.36.4
  725.       comp.pEFF7 = (comp.pEFF7 & conf.EFF7_mask) | (val & ~conf.EFF7_mask);
  726.           if(conf.mem_model == MM_ATM710)
  727.                   return;
  728.       comp.pEFF7 |= EFF7_GIGASCREEN; // [vv] disable turbo
  729. //    if ((comp.pEFF7 ^ oldpEFF7) & EFF7_GIGASCREEN) {
  730. //      conf.frame = frametime;
  731. //      if ((conf.mem_model == MM_PENTAGON)&&(comp.pEFF7 & EFF7_GIGASCREEN))conf.frame = 71680;
  732. //      apply_sound();
  733. //    } //Alone Coder removed 0.37.1
  734.  
  735.       if (!(comp.pEFF7 & EFF7_4BPP))
  736.       {
  737.           temp.offset_vscroll = 0;
  738.           temp.offset_vscroll_prev = 0;
  739.           temp.offset_hscroll = 0;
  740.           temp.offset_hscroll_prev = 0;
  741.       }
  742.  
  743.       if ((comp.pEFF7 ^ oldpEFF7) & (EFF7_ROCACHE | EFF7_LOCKMEM))
  744.           set_banks(); //Alone Coder 0.36.4
  745.       return;
  746.    }
  747.    if (conf.cmos && (((comp.pEFF7 & EFF7_CMOS) &&
  748.                 (conf.mem_model == MM_PENTAGON || conf.mem_model == MM_ATM710)) ||
  749.                 conf.mem_model == MM_ATM3))
  750.    {
  751.       unsigned mask = (conf.mem_model == MM_ATM3 && (comp.flags & CF_DOSPORTS)) ? ~0x100U : 0xFFFF;
  752.  
  753.       if (port == (0xDFF7 & mask))
  754.       {
  755.           comp.cmos_addr = val;
  756.           return;
  757.       }
  758.       if (port == (0xBFF7 & mask))
  759.       {
  760.              /*if (comp.cmos_addr >= 0xF0 && (val & 0xf0) == 0x10 && conf.mem_model == MM_ATM3){
  761.                         comp.fddIO2Ram_mask=val;
  762.                  }else */
  763.                  if (comp.cmos_addr >= 0xF0 && val <= 2 && conf.mem_model == MM_ATM3)
  764.          {//thims added
  765.             if (val < 2)
  766.             {
  767.                input.buffer_enabled = false;
  768.                static unsigned version = 0;
  769.                if (!version)
  770.                {
  771.                   unsigned day, year;
  772.                   char month[8];
  773.                   static const char months[] = "JanFebMarAprMayJunJulAugSepOctNovDec";
  774.                   sscanf(__DATE__, "%s %d %d", month, &day, &year);
  775.                   version = day | ((strstr(months, month) - months) / 3 + 1) << 5 | (year - 2000) << 9;
  776.                }
  777.                
  778.                strcpy((char*)cmos + 0xF0, "UnrealSpeccy");
  779.                *(unsigned*)(cmos + 0xFC) = version;
  780.             }
  781.             else input.buffer_enabled = true;
  782.          }
  783.          else cmos_write(val);
  784.          return;
  785.       }
  786.    }
  787.    if ((port & 0xF8FF) == 0xF8EF && modem.open_port)
  788.        modem.write((port >> 8) & 7, val);
  789. }
  790.  
  791. __inline unsigned char in1(unsigned port)
  792. {
  793.    port &= 0xFFFF;
  794.    brk_port_in = port;
  795.  
  796.    u8 p1 = (port & 0xFF);
  797.  
  798. /*
  799.    if((port & 0xFF) == 0xF0)
  800.        __debugbreak();
  801.  
  802.    if((comp.flags & CF_DOSPORTS) && port == 0xFADF)
  803.        __debugbreak();
  804. */
  805.  
  806.    // ┬ эрўрых фх°шЇЁрЎш  яюЁЄют яю яюыэ√ь 8сшЄ
  807.  
  808.    if(conf.ula_plus && port == 0xFF3B)
  809.    {
  810.        if(comp.ula_plus_group == 0)
  811.        {
  812.            return comp.comp_pal[comp.ula_plus_pal_idx];
  813.        }
  814.  
  815.        if(comp.ula_plus_group == 1)
  816.        {
  817.            u8 val = comp.ula_plus_en ? 1 : 0;
  818.            return val;
  819.        }
  820.        return 0xFF;
  821.    }
  822.  
  823.    // ngs
  824.    #ifdef MOD_GS
  825.    if ((port & 0xF7) == 0xB3 && conf.gs_type)
  826.        return in_gs(p1);
  827.    #endif
  828.  
  829.    // ZXM-MoonSound
  830.    if (conf.sound.moonsound &&
  831.        (conf.mem_model == MM_PROFI ? !(comp.pDFFD & 0x80) : 1) &&
  832.        (((p1 & 0xFC) == 0xC4) || ((p1 & 0xFE) == 0xC2)))
  833.    {
  834.        u8 val = 0xFF;
  835.  
  836.        if (zxmmoonsound.read(port, val))
  837.            return val;
  838.    }
  839.  
  840.    // z-controller
  841.    if (conf.zc && (port & 0xFF) == 0x57)
  842.    {
  843.       // no shadow-mode ZXEVO patch here since 0x57 port in read mode is the same
  844.           // as in noshadow-mode, i.e. no A15 is used to decode port.
  845.       return Zc.Rd(port);
  846.    }
  847.    
  848.    if(conf.wiznet && (port & 0xff) == 0xab ){
  849.        return pXXAB_Read(port);
  850.    }
  851.  
  852.    if(conf.mem_model == MM_ATM3)
  853.    {
  854.        // ╧юЁЄ Ёрё°шЁхэшщ └╥╠3
  855.        if((port & 0xFF) == 0xBF)
  856.            return comp.pBF;
  857.  
  858.        if(((port & 0xFF) == 0xBE) || ((port & 0xFF) == 0xBD))
  859.        {
  860.            u8 port_hi = (port >> 8) & 0xFF;
  861.            if((port_hi & ~7) == 0) // ╫Єхэшх эх шэтхЁЄшЁютрээюую эюьхЁр ёЄЁрэшЎ√
  862.            {
  863.                unsigned PgIdx = port_hi & 7;
  864.                return (comp.pFFF7[PgIdx] & 0xFF) ^ 0xFF;
  865.            }
  866.  
  867.            switch(port_hi)
  868.            {
  869.            case 0x8: // ram/rom
  870.            {
  871.                u8 RamRomMask = 0;
  872.                for(unsigned i = 0; i < 8; i++)
  873.                    RamRomMask |= ((comp.pFFF7[i] >> 8) & 1) << i;
  874.                return ~RamRomMask;
  875.            }
  876.            case 0x9: //dos7ffd
  877.            {
  878.                u8 RamRomMask = 0;
  879.                for(unsigned i = 0; i < 8; i++)
  880.                    RamRomMask |= ((comp.pFFF7[i] >> 9) & 1) << i;
  881.                return ~RamRomMask;
  882.            }
  883.            case 0xA: return comp.p7FFD;
  884.            case 0xB: return comp.pEFF7; // lvd - added EFF7 reading in pentevo (atm3)
  885.  
  886.            // lvd: fixed bug with no-anding bits from aFF77, added CF_TRDOS to bit 4
  887.                    // lvd: changed bit 4 to dos state, remembered during nmi
  888.            case 0xC: return (((comp.aFF77 >> 14) << 7) & 0x0080) | (((comp.aFF77 >> 9) << 6) & 0x0040) | (((comp.aFF77 >> 8) << 5) & 0x0020) | (/*(comp.flags & CF_TRDOS)*/trdos_in_nmi?0x0010:0) | (comp.pFF77 & 0xF);
  889.            case 0xD: return atm_readpal();
  890.                    case 0xE: return zxevo_readfont();
  891.                    
  892.                    // breakpoint address readback
  893.                    case 0x10: return comp.brk_addr&0x00FF;
  894.                    case 0x11: return (comp.brk_addr>>8)&0x00FF;
  895.                    
  896.                    //read fddIO2Ram_mask
  897.                    case 0x13: return comp.fddIO2Ram_mask;
  898.                    
  899.                    //read scanline
  900.                    case 0x14: return ((cpu.t / 224)>>1)&0x00FF;
  901.                    
  902.            }
  903.        }
  904.    }
  905.  
  906.    // divide эр nemo яюЁЄрї
  907.    if(conf.ide_scheme == IDE_NEMO_DIVIDE)
  908.    {
  909.        if(((port & 0x1E) == 0x10)) // rrr1000x
  910.        {
  911.            if((port & 0xFF) == 0x11)
  912.            {
  913.                comp.ide_hi_byte_r = 0;
  914.                return comp.ide_read;
  915.            }
  916.  
  917.            if((port & 0xFE) == 0x10)
  918.            {
  919.                comp.ide_hi_byte_r ^= 1;
  920.                if(!comp.ide_hi_byte_r)
  921.                {
  922.                    return comp.ide_read;
  923.                }
  924.            }
  925.            else
  926.            {
  927.                comp.ide_hi_byte_r = 0;
  928.            }
  929.            goto read_hdd_5;
  930.        }
  931.        else if((port & 0xFF) == 0xC8)
  932.        {
  933.         return hdd.read(8);
  934.        }
  935.    }
  936.  
  937.    // quorum additional keyboard port
  938.    if((conf.mem_model == MM_QUORUM) && ((port & 0xFF) == 0x7E))
  939.    {
  940.       u8 val = input.read_quorum(u8(port >> 8));
  941.       return val;
  942.    }
  943.  
  944.    if (comp.flags & CF_DOSPORTS)
  945.    {
  946.       if(conf.mem_model == MM_ATM3 && (p1 & 0x1F) == 0x0F && !(((p1 >> 5) - 1) & 4))
  947.       {
  948.           // 2F = 001|01111b
  949.           // 4F = 010|01111b
  950.           // 6F = 011|01111b
  951.           // 8F = 100|01111b
  952.                   return comp.wd_shadow[(p1 >> 5) - 1];
  953.                        
  954.      }
  955.  
  956.  
  957.       if (conf.ide_scheme == IDE_ATM && (port & 0x1F) == 0x0F)
  958.       {
  959.          if (port & 0x100)
  960.              return comp.ide_read;
  961.       read_hdd_5:
  962.          port >>= 5;
  963.       read_hdd:
  964.          port &= 7;
  965.          if (port)
  966.              return hdd.read(port);
  967.          unsigned v = hdd.read_data();
  968.          comp.ide_read = (unsigned char)(v >> 8);
  969.          return (unsigned char)v;
  970.       }
  971.  
  972.       if ((port & 0x18A3) == (0xFFFE & 0x18A3))
  973.       { // SMUC
  974.          if (conf.smuc)
  975.          {
  976.             if ((port & 0xA044) == (0xDFBA & 0xA044)) return cmos_read(); // clock
  977.             if ((port & 0xA044) == (0xFFBA & 0xA044)) return comp.nvram.out; // SMUC system port
  978.             if ((port & 0xA044) == (0x7FBA & 0xA044)) return comp.p7FBA | 0x37; // was 0x3F, bit 3 seems to be used in profrom to indicate presence of HDD (Muchkin)
  979.             if ((port & 0xA044) == (0x5FBA & 0xA044)) return 0x3F;
  980.             if ((port & 0xA044) == (0x5FBE & 0xA044)) return 0x57;
  981.             if ((port & 0xA044) == (0x7FBE & 0xA044)) return 0x57;
  982.          }
  983.          if ((port & 0x8044) == (0xFFBE & 0x8044) && conf.ide_scheme == IDE_SMUC)
  984.          { // FFBE, FEBE
  985.             if(comp.pFFBA & 0x80)
  986.             {
  987.                 if(!(port & 0x100))
  988.                     return hdd.read(8); // alternate status
  989.                 return 0xFF; // obsolete register
  990.             }
  991.  
  992.             if (!(port & 0x2000))
  993.                 return comp.ide_read;
  994.             port >>= 8;
  995.             goto read_hdd;
  996.          }
  997.       }
  998.  
  999.       if (conf.mem_model == MM_PROFI) // molodcov_alex
  1000.       {
  1001.           if((comp.p7FFD & 0x10) && (comp.pDFFD & 0x20))
  1002.           { // modified ports
  1003.             // BDI ports
  1004.             if((p1 & 0x9F) == 0x83)
  1005.                 return comp.wd.in((p1 & 0x60) | 0x1F);  // WD93 ports (1F, 3F, 7F)
  1006.             if((p1 & 0xE3) == 0x23)
  1007.                 return comp.wd.in(0xFF);                // port FF
  1008.  
  1009.             // RTC
  1010.             if((port & 0x9F) == 0x9F && conf.cmos)
  1011.             {
  1012.                 if(!(port & 0x20))
  1013.                     return cmos_read();
  1014.             }
  1015.  
  1016.             // IDE
  1017.             if((p1 & 0x9F) == 0x8B && (conf.ide_scheme == IDE_PROFI))
  1018.             {
  1019.                 if(p1 & 0x40) // cs1
  1020.                 {
  1021.                     if (p1 & 0x20)
  1022.                         return comp.ide_read;
  1023.                     port >>= 8;
  1024.                     goto read_hdd;
  1025.                 }
  1026.             }
  1027.           }
  1028.           else
  1029.           {
  1030.               // BDI ports
  1031.               if((p1 & 0x83) == 0x03)
  1032.                   return comp.wd.in((p1 & 0x60) | 0x1F);  // WD93 ports
  1033.               if((p1 & 0xE3) == ((comp.pDFFD & 0x20) ? 0xA3 : 0xE3))
  1034.                   return comp.wd.in(0xFF);                // port FF
  1035.           }
  1036.       }
  1037.  
  1038.       if(conf.mem_model == MM_QUORUM /* && !(comp.p00 & Q_TR_DOS) */) // cpm ports
  1039.       {
  1040.           if((p1 & 0xFC) == 0x80) // 80, 81, 82, 83
  1041.           {
  1042.               p1 = u8(((p1 & 3) << 5) | 0x1F);
  1043.               return comp.wd.in(p1);
  1044.           }
  1045.       }
  1046.           // 1F = 0001|1111b
  1047.           // 3F = 0011|1111b
  1048.           // 5F = 0101|1111b
  1049.           // 7F = 0111|1111b
  1050.           // DF = 1101|1111b яюЁЄ ь√°ш
  1051.           // FF = 1111|1111b
  1052.       else if ((p1 & 0x9F) == 0x1F || p1 == 0xFF) {// 1F, 3F, 5F, 7F, FF
  1053.                   if((comp.flags & CF_TRDOS) && conf.trdos_IORam && ( ( cpu.pc & 0xc000 ) == 0 )
  1054.                                 &&((1<<comp.wd.drive)&comp.fddIO2Ram_mask)&&(bankr[0]==base_dos_rom))
  1055.                   {
  1056.               comp.fddIO2Ram_wr_disable = true;
  1057.                       cpu.nmi_in_progress=conf.trdos_IORam;
  1058.                           trdos_in_nmi = comp.flags&CF_TRDOS;
  1059.                           set_banks();
  1060.                           return 0xff;
  1061.                   }else{
  1062.                       if(conf.trdos_IORam && (p1&0x80))
  1063.                           {  
  1064.                                 return (comp.wd.in(p1) & 0xE0) | comp.trdos_last_ff;
  1065.                           }
  1066.                           return comp.wd.in(p1);
  1067.                   }
  1068.           }
  1069.    }
  1070.    else // эх dos
  1071.    {
  1072.        if(((port & 0xA3) == 0xA3) && (conf.ide_scheme == IDE_DIVIDE))
  1073.        {
  1074.            if((port & 0xFF) == 0xA3)
  1075.            {
  1076.                comp.ide_hi_byte_r ^= 1;
  1077.                if(!comp.ide_hi_byte_r)
  1078.                {
  1079.                    return comp.ide_read;
  1080.                }
  1081.            }
  1082.            else
  1083.            {
  1084.                comp.ide_hi_byte_r = 0;
  1085.            }
  1086.            port >>= 2;
  1087.            goto read_hdd;
  1088.        }
  1089.  
  1090.  
  1091.        if (!(port & 6) && (conf.ide_scheme == IDE_NEMO || conf.ide_scheme == IDE_NEMO_A8))
  1092.        {
  1093.           unsigned hi_byte = (conf.ide_scheme == IDE_NEMO)? (port & 1) : (port & 0x100);
  1094.           if(hi_byte)
  1095.               return comp.ide_read;
  1096.           comp.ide_read = 0xFF;
  1097.           if((port & 0x18) == 0x08)
  1098.               return ((port & 0xE0) == 0xC0)? hdd.read(8) : 0xFF; // CS1=0,CS0=1,reg=6
  1099.           if((port & 0x18) != 0x10)
  1100.               return 0xFF; // invalid CS0,CS1
  1101.           goto read_hdd_5;
  1102.        }
  1103.    }
  1104.  
  1105.  
  1106.    
  1107.    
  1108.    if (!(port & 0x20))
  1109.    { // kempstons
  1110.       port = (port & 0xFFFF) | 0xFA00; // A13,A15 not used in decoding
  1111.       if ((port == 0xFADF || port == 0xFBDF || port == 0xFFDF) && conf.input.mouse == 1)
  1112.       { // mouse
  1113.          input.mouse_joy_led |= 1;
  1114.          if (port == 0xFBDF)
  1115.              return input.kempston_mx();
  1116.          if (port == 0xFFDF)
  1117.              return input.kempston_my();
  1118.          return input.mbuttons;
  1119.       }
  1120.       input.mouse_joy_led |= 2;
  1121.       unsigned char res = (conf.input.kjoy)? input.kjoy : 0xFF;
  1122.       if (conf.mem_model == MM_SCORP || conf.mem_model == MM_PROFSCORP)
  1123.          res = (res & 0x1F) | (comp.wd.in(0xFF) & 0xE0);
  1124.       return res;
  1125.    }
  1126.  
  1127.    // fuller joystick
  1128.    if((p1 == 0x7F) && conf.input.fjoy)
  1129.    {
  1130.        input.mouse_joy_led |= 2;
  1131.        return  input.fjoy;
  1132.    }
  1133.  
  1134.    // port #FE
  1135.    bool pFE;
  1136.  
  1137.    // scorp  xx1xxx10 (sc16)
  1138.    if((conf.mem_model == MM_SCORP || conf.mem_model == MM_PROFSCORP))
  1139.        pFE = ((port & 0x23) == (0xFE & 0x23)) && !(comp.flags & CF_DOSPORTS);
  1140.    else if(conf.mem_model == MM_QUORUM) // 1xx11xx0
  1141.        pFE = ((port & 0x99) == (0xFE & 0x99));
  1142.    else // others xxxxxxx0
  1143.        pFE = !(port & 1);
  1144.  
  1145.    if (pFE)
  1146.    {
  1147.       if ((cpu.pc & 0xFFFF) == 0x0564 && bankr[0][0x0564]==0x1F && conf.tape_autostart && comp.tape.stopped)
  1148.           start_tape();
  1149.       u8 val = input.read(u8(port >> 8));
  1150.       if (conf.mem_model == MM_ATM450)
  1151.           val = (val & 0x7F) | atm450_z(cpu.t);
  1152.       return val;
  1153.    }
  1154.  
  1155.    if ((port & 0x8202) == (0x7FFD & 0x8202) && (conf.mem_model == MM_ATM710 || conf.ide_scheme == IDE_ATM))
  1156.    { // ATM-2 IDE+DAC/ADC
  1157.       unsigned char irq = 0x40;
  1158.       if (conf.ide_scheme == IDE_ATM) irq = (hdd.read_intrq() & 0x40);
  1159.       return irq + 0x3F;
  1160.    }
  1161.  
  1162.    // 0001xxxxxxxxxx0x (bcig4) // 1FFD
  1163.    // 0010xxxxxxxxxx0x (bcig4) // 2FFD
  1164.    // 0011xxxxxxxxxx0x (bcig4) // 3FFD
  1165.    if((port & ((3 << 14) | 2)) == 0 && conf.mem_model == MM_PLUS3)
  1166.    {
  1167.        unsigned Idx = (port >> 12) & 3;
  1168.        switch(Idx)
  1169.        {
  1170.        case 2: // 2FFD
  1171.            return Upd765.in(Idx);
  1172.        case 3: // 3FFD
  1173.            return Upd765.in(Idx);
  1174.        }
  1175.    }
  1176.  
  1177.    if ((unsigned char)port == 0xFD && conf.sound.ay_scheme >= AY_SCHEME_SINGLE)
  1178.    {
  1179.       if((conf.sound.ay_scheme == AY_SCHEME_CHRV) && (conf.sound.ay_chip == (SNDCHIP::CHIP_YM2203)) && (tfmstatuson0 == 0))
  1180.           return 0x7f /*always ready*/; //Alone Coder 0.36.6
  1181.       if ((port & 0xC0FF) != 0xC0FD) return 0xFF;
  1182.       unsigned n_ay = (conf.sound.ay_scheme == AY_SCHEME_QUADRO)? (port >> 12) & 1 : comp.active_ay;
  1183.       // else FxFD - read selected AY register
  1184.       if (conf.input.mouse == 2 && ay[n_ay].get_activereg() == 14) { input.mouse_joy_led |= 1; return input.aymouse_rd(); }
  1185.       return ay[n_ay].read();
  1186.    }
  1187.  
  1188. //   if ((port & 0x7F) == 0x7B) { // FB/7B
  1189.    if ((port & 0x04) == 0x00)
  1190.    { // FB/7B //Alone Coder 0.36.6 (for MODPLAYi)
  1191.       if (conf.mem_model == MM_ATM450)
  1192.       {
  1193.          comp.aFB = (unsigned char)port;
  1194.          set_banks();
  1195.       }
  1196.       else if (conf.cache)
  1197.       {
  1198.          comp.flags &= ~CF_CACHEON;
  1199.          if (port & 0x80) comp.flags |= CF_CACHEON;
  1200.          set_banks();
  1201.       }
  1202.       return 0xFF;
  1203.    }
  1204.  
  1205.    if (conf.cmos && ((comp.pEFF7 & EFF7_CMOS) || conf.mem_model == MM_ATM3 || conf.mem_model == MM_ATM710))
  1206.    {
  1207.       unsigned mask = (conf.mem_model == MM_ATM3 && (comp.flags & CF_DOSPORTS)) ? ~0x100U : 0xFFFF;
  1208.       if(port == (0xBFF7 & mask))
  1209.           return cmos_read();
  1210.    }
  1211.  
  1212.    if ((port & 0xF8FF) == 0xF8EF && modem.open_port)
  1213.        return modem.read((port >> 8) & 7);
  1214.  
  1215.    if (conf.portff && ((port & 0xFF) == 0xFF))
  1216.    {
  1217.       update_screen();
  1218.       if (vmode != 2) return 0xFF; // ray is not in paper
  1219.       unsigned ula_t = (cpu.t+temp.border_add) & temp.border_and;
  1220.       return temp.base[vcurr->atr_offs + (ula_t - vcurr[-1].next_t)/4];
  1221.    }
  1222.    return 0xFF;
  1223. }
  1224.  
  1225. unsigned char in(unsigned port)
  1226. {
  1227.    brk_port_val = in1(port);
  1228.    return brk_port_val;
  1229. }
  1230.  
  1231. #undef in_trdos
  1232. #undef out_trdos
  1233.