Subversion Repositories pentevo

Rev

Rev 1153 | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed | ?url?

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