Subversion Repositories pentevo

Rev

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