Subversion Repositories pentevo

Rev

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