Subversion Repositories pentevo

Rev

Rev 796 | 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 "vars.h"
  5. #include "wd93crc.h"
  6.  
  7. #include "util.h"
  8.  
  9. //static u8 old_status;
  10. //static __int64 last_t;
  11.  
  12. void WD1793::process()
  13. {
  14.    time = comp.t_states + cpu.t;
  15.  
  16.    if(!(sign_status & SIG_HLD) && !(system & 0x20))
  17.    {
  18.        seldrive->motor = 0;
  19.    }
  20.  
  21.    if (seldrive->rawdata)
  22.        status &= ~WDS_NOTRDY;
  23.    else
  24.        status |= WDS_NOTRDY;
  25.  
  26.    if (!(cmd & 0x80) || (cmd & 0xF0) == 0xD0) // seek / step / restore / interrupt commands
  27.    {
  28.       status &= ~WDS_INDEX;
  29.  
  30.       if(state != S_IDLE)
  31.       {
  32.           status &= ~(WDS_TRK00 | WDS_INDEX);
  33.           if (!seldrive->track) status |= WDS_TRK00;
  34.       }
  35.  
  36.       // todo: test spinning
  37.       // ╠шэшьры№эр  °шЁшэр шэфхъёэюую шьяєы№ёр 10ьъё яЁш f=2╠├Ў, 20ьъё яЁш f=1╠├Ў
  38.       if (seldrive->rawdata && seldrive->motor && ((time + tshift) % (Z80FQ / FDD_RPS) < (Z80FQ * 4 / 1000)))
  39.       {
  40.           // index every turn, len=4ms (if disk present)
  41.          if(state == S_IDLE)
  42.          {
  43.              if(time < idx_tmo)
  44.                  status |= WDS_INDEX;
  45.          }
  46.          else
  47.          {
  48.              status |= WDS_INDEX;
  49.          }
  50.       }
  51.  
  52. /*
  53.       if(((old_status ^ status) & WDS_INDEX))
  54.       {
  55.           printf("%9lld: %8lld: ip %s, cmd=0x%02x, dat=0x%02x, trk=0x%02x, st=0x%02x\n",
  56.               (time + tshift), ((time + tshift) - last_t ),
  57.               (status & WDS_INDEX) ? "0->1" : "1->0", cmd, data, track, status);
  58.           last_t = time + tshift;
  59.       }
  60. */
  61.    }
  62. //   old_status = status;
  63.  
  64.    for (;;)
  65.    {
  66.       if(!seldrive->motor)
  67.       {
  68.           status |= WDS_NOTRDY;
  69.       }
  70.       else
  71.       {
  72.           status &= ~WDS_NOTRDY;
  73.       }
  74.  
  75.       switch (state)
  76.       {
  77.  
  78.          // ----------------------------------------------------
  79.  
  80.          case S_IDLE:
  81.             status &= ~WDS_BUSY;
  82.             if(idx_cnt >= 15 || time > idx_tmo)
  83.             {
  84.                 idx_cnt = 15;
  85.                 status &= WDS_NOTRDY;
  86.                 status |= WDS_NOTRDY;
  87.                 seldrive->motor = 0;
  88.                 sign_status &= ~SIG_HLD;
  89.             }
  90.             rqs = INTRQ;
  91.             return;
  92.  
  93.          case S_WAIT:
  94.             if (time < next)
  95.                 return;
  96.             state = state2;
  97.             break;
  98.  
  99.          // ----------------------------------------------------
  100.          // ╧юфрэр ъюьрэфр Єшяр 2 шыш 3 (read/write)/(read am/read trk/write trk)
  101.          case S_DELAY_BEFORE_CMD:
  102.             if (!conf.wd93_nodelay && (cmd & CMD_DELAY)) // ╧ЁютхЁър сшЄр E=1
  103.                 next += (Z80FQ*15/1000); // 15ms delay
  104.             state2 = S_WAIT_HLT_RW;
  105.             state = S_WAIT;
  106.             break;
  107.  
  108.          case S_WAIT_HLT_RW:
  109.             if(!(system & 0x08)) // HLT = 0 (схёъюэхўэюх юцшфрэшх HLT)
  110.             {
  111.                 return;
  112.             }
  113.  
  114.             state = S_CMD_RW;
  115.  
  116.          case S_CMD_RW:
  117.             if (((cmd & 0xE0) == 0xA0 || (cmd & 0xF0) == 0xF0) && conf.trdos_wp[drive])
  118.             {
  119.                status |= WDS_WRITEP;
  120.                state = S_IDLE;
  121.                break;
  122.             }
  123.  
  124.             if ((cmd & 0xC0) == 0x80 || (cmd & 0xF8) == 0xC0)
  125.             {
  126.                // read/write sectors or read am - find next AM
  127.                end_waiting_am = next + 5*Z80FQ/FDD_RPS; // max wait disk 5 turns
  128.                find_marker();
  129.                break;
  130.             }
  131.  
  132.             if ((cmd & 0xF8) == 0xF0) // write track
  133.             {
  134.                rqs = DRQ;
  135.                status |= WDS_DRQ;
  136.                next += 3*seldrive->t.ts_byte;
  137.                state2 = S_WRTRACK;
  138.                state = S_WAIT;
  139.                break;
  140.             }
  141.  
  142.             if ((cmd & 0xF8) == 0xE0) // read track
  143.             {
  144.                load();
  145.                rwptr = 0;
  146.                rwlen = seldrive->t.trklen;
  147.                state2 = S_READ;
  148.                getindex();
  149.                break;
  150.             }
  151.  
  152.             // else unknown command
  153.             state = S_IDLE;
  154.             break;
  155.  
  156.         case S_FOUND_NEXT_ID:
  157.             if (!seldrive->rawdata)
  158.             { // no disk - wait again
  159.                end_waiting_am = next + 5*Z80FQ/FDD_RPS;
  160.         nextmk:
  161.                find_marker();
  162.                break;
  163.             }
  164.             if (next >= end_waiting_am)
  165.             {
  166.             nf:
  167.                 status |= WDS_NOTFOUND;
  168.                 state = S_IDLE;
  169.                 break;
  170.             }
  171.             if (foundid == -1U)
  172.                 goto nf;
  173.  
  174.             status &= ~WDS_CRCERR;
  175.             load();
  176.  
  177.             if (!(cmd & 0x80)) // verify after seek
  178.             {
  179.                if (seldrive->t.hdr[foundid].c != track)
  180.                    goto nextmk;
  181.                if (!seldrive->t.hdr[foundid].c1)
  182.                {
  183.                    status |= WDS_CRCERR;
  184.                    goto nextmk;
  185.                }
  186.                state = S_IDLE; break;
  187.             }
  188.  
  189.             if ((cmd & 0xF0) == 0xC0) // read AM
  190.             {
  191.                rwptr = unsigned(seldrive->t.hdr[foundid].id - seldrive->t.trkd);
  192.                rwlen = 6;
  193.  
  194.          read_first_byte:
  195.                u8 data_mask = 0;
  196.                if(seldrive->t.trkwp) // яЁютхЁ хь ърЁЄє ёсющэ√ї срщЄют
  197.                {
  198.                    if(seldrive->t.test_wp(rwptr))
  199.                    {
  200.                        data_mask = 0xFF;
  201.                        seldrive->t.hdr[foundid].c1 = 0; // bad address crc
  202.                    }
  203.                }
  204.                data = seldrive->t.trkd[rwptr++];
  205.                data ^= data_mask;
  206.                rwlen--;
  207.                rqs = DRQ; status |= WDS_DRQ;
  208.                next += seldrive->t.ts_byte;
  209.                state = S_WAIT;
  210.                state2 = S_READ;
  211.                break;
  212.             }
  213.  
  214.             // else R/W sector(s)
  215.             if (seldrive->t.hdr[foundid].c != track || seldrive->t.hdr[foundid].n != sector)
  216.                 goto nextmk;
  217.             if ((cmd & CMD_SIDE_CMP_FLAG) && (((cmd >> CMD_SIDE_SHIFT) ^ seldrive->t.hdr[foundid].s) & 1))
  218.                 goto nextmk;
  219.             if (!seldrive->t.hdr[foundid].c1)
  220.             {
  221.                 status |= WDS_CRCERR;
  222.                 goto nextmk;
  223.             }
  224.  
  225.             if (cmd & 0x20) // write sector(s)
  226.             {
  227.                rqs = DRQ; status |= WDS_DRQ;
  228.                next += seldrive->t.ts_byte*9;
  229.                state = S_WAIT; state2 = S_WRSEC;
  230.                break;
  231.             }
  232.  
  233.             // read sector(s)
  234.             if (!seldrive->t.hdr[foundid].data)
  235.                 goto nextmk; // ╤хъЄюЁ схч чюэ√ фрээ√ї
  236.             if(!conf.wd93_nodelay)
  237.                 next += seldrive->t.ts_byte*(seldrive->t.hdr[foundid].data - seldrive->t.hdr[foundid].id); // ╟рфхЁцър эр яЁюяєёъ чруюыютър ёхъЄюЁр ш яЁюсхыр ьхцфє чруюыютъюь ш чюэющ фрээ√ї
  238.             state = S_WAIT;
  239.             state2 = S_RDSEC;
  240.             break;
  241.  
  242.          case S_RDSEC:
  243.             if (seldrive->t.hdr[foundid].data[-1] == 0xF8)
  244.                 status |= WDS_RECORDT;
  245.             else
  246.                 status &= ~WDS_RECORDT;
  247.             rwptr = unsigned(seldrive->t.hdr[foundid].data - seldrive->t.trkd); // ╤ьх∙хэшх чюэ√ фрээ√ї ёхъЄюЁр (т срщЄрї) юЄэюёшЄхы№эю эрўрыр ЄЁхър
  248.             rwlen = 128U << (seldrive->t.hdr[foundid].l & 3); // [vv]
  249.             goto read_first_byte;
  250.  
  251.          case S_READ:
  252.             if (notready())
  253.                 break;
  254.             load();
  255.  
  256.             if(!seldrive->t.trkd)
  257.             {
  258.                 status |= WDS_NOTFOUND;
  259.                 state = S_IDLE;
  260.                 break;
  261.             }
  262.  
  263.             if (rwlen)
  264.             {
  265.                trdos_load = ROMLED_TIME;
  266.                if (rqs & DRQ)
  267.                    status |= WDS_LOST;
  268.  
  269.                u8 data_mask = 0;
  270.                if(seldrive->t.trkwp) // яЁютхЁ хь ърЁЄє ёсющэ√ї срщЄют
  271.                {
  272.                    if(seldrive->t.test_wp(rwptr))
  273.                    {
  274.                        data_mask = 0xFF;
  275.                        if ((cmd & 0xE0) == 0x80) // read sector
  276.                        {
  277.                            seldrive->t.hdr[foundid].c2 = 0; // bad data crc
  278.                        }
  279.                        if ((cmd & 0xF0) == 0xC0) // read address
  280.                        {
  281.                            seldrive->t.hdr[foundid].c1 = 0; // bad address crc
  282.                        }
  283.                    }
  284.                }
  285.                data = seldrive->t.trkd[rwptr++];
  286.                data ^= data_mask;
  287.                rwlen--;
  288.                rqs = DRQ;
  289.                status |= WDS_DRQ;
  290.  
  291.                if (!conf.wd93_nodelay)
  292.                    next += seldrive->t.ts_byte;
  293.                else
  294.                    next = time + 1;
  295.                state = S_WAIT;
  296.                state2 = S_READ;
  297.             }
  298.             else
  299.             {
  300.                if ((cmd & 0xE0) == 0x80) // read sector
  301.                {
  302.                   if (!seldrive->t.hdr[foundid].c2)
  303.                       status |= WDS_CRCERR;
  304.                   if (cmd & CMD_MULTIPLE)
  305.                   {
  306.                       sector++;
  307.                       state = S_CMD_RW;
  308.                       break;
  309.                   }
  310.                }
  311.  
  312.                // FIXME: ┬Ёхьхээ√щ їръ фы  zx-format 3
  313.                if (((cmd & 0xF8) == 0xE0) && (seldrive->t.trklen < MAX_TRACK_LEN)) // read track
  314.                {
  315.                    status |= WDS_LOST;
  316.                }
  317.  
  318.                if ((cmd & 0xF0) == 0xC0) // read address
  319.                {
  320.                   if (!seldrive->t.hdr[foundid].c1)
  321.                       status |= WDS_CRCERR;
  322.                }
  323.                state = S_IDLE;
  324.             }
  325.             break;
  326.  
  327.  
  328.          case S_WRSEC:
  329.             load();
  330.             if (rqs & DRQ)
  331.             {
  332.                 status |= WDS_LOST;
  333.                 state = S_IDLE;
  334.                 break;
  335.             }
  336.             seldrive->optype |= 1;
  337.             rwptr = unsigned(seldrive->t.hdr[foundid].id + 6 + 11 + 11 - seldrive->t.trkd);
  338.             for (rwlen = 0; rwlen < 12; rwlen++)
  339.                 seldrive->t.write(rwptr++, 0, 0);
  340.             for (rwlen = 0; rwlen < 3; rwlen++)
  341.                 seldrive->t.write(rwptr++, 0xA1, 1);
  342.             seldrive->t.write(rwptr++, (cmd & CMD_WRITE_DEL)? 0xF8 : 0xFB, 0);
  343.             rwlen = 128U << (seldrive->t.hdr[foundid].l & 3); // [vv]
  344.             state = S_WRITE;
  345.             break;
  346.  
  347.          case S_WRITE:
  348.             if (notready())
  349.                 break;
  350.             if(rqs & DRQ)
  351.             {
  352.                 status |= WDS_LOST;
  353.                 data = 0;
  354.             }
  355.             trdos_save = ROMLED_TIME;
  356.             seldrive->t.write(rwptr++, data, 0); rwlen--;
  357.             if (rwptr == seldrive->t.trklen) rwptr = 0;
  358.             seldrive->t.sf = JUST_SEEK; // invalidate sectors
  359.             if (rwlen)
  360.             {
  361.                if (!conf.wd93_nodelay) next += seldrive->t.ts_byte;
  362.                state = S_WAIT; state2 = S_WRITE;
  363.                rqs = DRQ; status |= WDS_DRQ;
  364.             }
  365.             else
  366.             {
  367.                unsigned len = (128U << (seldrive->t.hdr[foundid].l & 3)) + 1; //[vv]
  368.                unsigned char sc[2056];
  369.                if (rwptr < len)
  370.                {
  371.                    memcpy(sc, seldrive->t.trkd + seldrive->t.trklen - rwptr, rwptr);
  372.                    memcpy(sc + rwptr, seldrive->t.trkd, len - rwptr);
  373.                }
  374.                else
  375.                    memcpy(sc, seldrive->t.trkd + rwptr - len, len);
  376.                unsigned crc = wd93_crc(sc, len);
  377.                seldrive->t.write(rwptr++, (BYTE)crc, 0);
  378.                seldrive->t.write(rwptr++, (BYTE)(crc >> 8), 0);
  379.                seldrive->t.write(rwptr, 0xFF, 0);
  380.                if (cmd & CMD_MULTIPLE)
  381.                {
  382.                    sector++;
  383.                    state = S_CMD_RW;
  384.                    break;
  385.                }
  386.                state = S_IDLE;
  387.             }
  388.             break;
  389.  
  390.          case S_WRTRACK:
  391.             if (rqs & DRQ)
  392.             {
  393.                 status |= WDS_LOST;
  394.                 state = S_IDLE;
  395.                 break;
  396.             }
  397.             seldrive->optype |= 2;
  398.             state2 = S_WR_TRACK_DATA;
  399.             start_crc = 0;
  400.             getindex();
  401.             end_waiting_am = next + 5 * Z80FQ /FDD_RPS;
  402.          break;
  403.  
  404.          case S_WR_TRACK_DATA:
  405.          {
  406.             if (notready())
  407.                 break;
  408.             trdos_format = ROMLED_TIME;
  409.             if (rqs & DRQ)
  410.             {
  411.                 status |= WDS_LOST;
  412.                 data = 0;
  413.             }
  414.             seldrive->t.seek(seldrive, seldrive->track, side, JUST_SEEK);
  415.             seldrive->t.sf = JUST_SEEK; // invalidate sectors
  416.  
  417.             if(!seldrive->t.trkd)
  418.             {
  419.                 state = S_IDLE;
  420.                 break;
  421.             }
  422.  
  423.             unsigned char marker = 0, byte = data;
  424.             unsigned crc;
  425.             switch(data)
  426.             {
  427.             case 0xF5:
  428.                 byte = 0xA1;
  429.                 marker = 1;
  430.                 start_crc = rwptr + 1;
  431.             break;
  432.  
  433.             case 0xF6:
  434.                 byte = 0xC2;
  435.                 marker = 1;
  436.             break;
  437.  
  438.             case 0xF7:
  439.                 crc = wd93_crc(seldrive->t.trkd + start_crc, rwptr - start_crc);
  440.                 byte = crc & 0xFF;
  441.             break;
  442.             }
  443.  
  444.             seldrive->t.write(rwptr++, byte, marker);
  445.             rwlen--;
  446.             if (data == 0xF7)
  447.             {
  448.                 seldrive->t.write(rwptr++, (crc >> 8) & 0xFF, 0);
  449.                 rwlen--; // second byte of CRC16
  450.             }
  451.  
  452.             if ((int)rwlen > 0)
  453.             {
  454.                if (!conf.wd93_nodelay)
  455.                    next += seldrive->t.ts_byte;
  456.                state2 = S_WR_TRACK_DATA;
  457.                state = S_WAIT;
  458.                rqs = DRQ;
  459.                status |= WDS_DRQ;
  460.                break;
  461.             }
  462.             state = S_IDLE;
  463.             break;
  464.          }
  465.  
  466.          // ----------------------------------------------------
  467.  
  468.          case S_TYPE1_CMD: // ╧юфрэр ъюьрэфр Єшяр 1 (restore/seek/step)
  469.             status &= ~(WDS_CRCERR | WDS_SEEKERR | WDS_WRITEP);
  470.             rqs = 0;
  471.  
  472.             if (conf.trdos_wp[drive])
  473.                 status |= WDS_WRITEP;
  474.  
  475.             seldrive->motor = (cmd & CMD_SEEK_HEADLOAD) || (system & 0x20) ? next + 2*Z80FQ : 0;
  476.  
  477.             state2 = S_SEEKSTART; // default is seek/restore
  478.  
  479.             if (cmd & 0xE0)  // single step
  480.             {
  481.                if (cmd & 0x40) // step in / step out
  482.                    stepdirection = (cmd & CMD_SEEK_DIR) ? -1 : 1;
  483.                state2 = S_STEP;
  484.             }
  485.  
  486.             next += (Z80FQ*14)/1000000;
  487.             state = S_WAIT; // ╟рфхЁцър 14ьъё яхЁхф яю тыхэхшь ёЄрЄєёр BUSY
  488.          break;
  489.  
  490.  
  491.          case S_STEP:
  492.          {
  493.             status |= WDS_BUSY;
  494.             trdos_seek = ROMLED_TIME;
  495.  
  496.             if (seldrive->track == 0 && stepdirection < 0) // яЁютхЁър TRK00
  497.             {
  498.                 track = 0;
  499.                 state = S_VERIFY; // ╬сЁрсюЄър сшЄр ъюьрэф√ V
  500.                 break;
  501.             }
  502.  
  503.             // ╬сЁрсюЄърсшЄр T=1 (фы  seek тёхуфр 1, фы  restore тёхуфр 0, эю юсэютыхэшх ЁхушёЄЁр ЄЁ¤ър фхырхЄё )
  504.             if (!(cmd & 0xF0) || (cmd & CMD_SEEK_TRKUPD))
  505.                 track += stepdirection;
  506.  
  507.             if(seldrive->motor)
  508.             {
  509.                 seldrive->track += stepdirection;
  510.                 if (seldrive->track == (unsigned char)-1)
  511.                     seldrive->track = 0;
  512.                 if (seldrive->track >= MAX_PHYS_CYL)
  513.                     seldrive->track = MAX_PHYS_CYL;
  514.                 seldrive->t.clear();
  515.             }
  516.  
  517.             static const unsigned steps[] = { 6,12,20,30 };
  518.             if (!conf.wd93_nodelay)
  519.                 next += steps[cmd & CMD_SEEK_RATE]*Z80FQ/1000;
  520.  
  521.             #ifndef MOD_9X
  522.             if (!conf.wd93_nodelay && conf.fdd_noise)
  523.                 Beep((stepdirection > 0)? 600 : 800, 2);
  524.             #endif
  525.  
  526.             state2 = (cmd & 0xE0) ? S_VERIFY /*╩юьрэфр step*/: S_SEEK /*╩юьрэфр seek/restore*/;
  527.             state = S_WAIT;
  528.             break;
  529.          }
  530.  
  531.          case S_SEEKSTART:
  532.             status |= WDS_BUSY;
  533.  
  534.             if (!(cmd & 0x10)) // ╩юьрэфр restore
  535.             {
  536.                 if (!conf.wd93_nodelay)
  537.                 {
  538.                     state2 = S_RESTORE;
  539.                     next += (Z80FQ*21)/1000000; // чрфхЁцър ~21ьъё яхЁхф чруЁєчъющ ЁхушёЄЁр ЄЁ¤ър
  540.                     state = S_WAIT;
  541.                     break;
  542.                 }
  543.  
  544.                 state = S_RESTORE;
  545.                 break;
  546.             }
  547.             state = S_SEEK;
  548.             break;
  549.  
  550.          case S_RESTORE:
  551.             track = 0xFF;
  552.             data = 0;
  553.             state = S_SEEK;
  554.             break;
  555.  
  556.          case S_SEEK:
  557.             if (data == track)
  558.             {
  559.                 state = S_VERIFY;
  560.                 break;
  561.             }
  562.             stepdirection = (data < track) ? -1 : 1;
  563.             state = S_STEP;
  564.             break;
  565.  
  566.          case S_VERIFY:
  567.             if (!(cmd & CMD_SEEK_VERIFY)) // ╧ЁютхЁър эюьхЁр ЄЁ¤ър эх эєцэр V=0
  568.             {
  569.                 status |= WDS_BUSY;
  570.                 state2 = S_IDLE;
  571.                 state = S_WAIT;
  572.                 idx_tmo = next + 15 * Z80FQ/FDD_RPS; // 15 disk turns
  573.                 next += (105*Z80FQ)/1000000; // ╟рфхЁцър 105ьъё ёю ёЄрЄєёюь BUSY
  574.                 break;
  575.             }
  576.  
  577.             // ╧ЁютхЁър эюьхЁр ЄЁ¤ър эєцэр V=1
  578.             sign_status |= SIG_HLD;
  579.  
  580.             // ╬цшфрэшх 15ьё
  581.             //       |
  582.             //       v
  583.             // ╬цшфрэшх HLT == 1
  584.             //       |
  585.             //       v
  586.             // S_VERIFY2
  587.             if (!conf.wd93_nodelay)
  588.             {
  589.                 next += (15*Z80FQ)/1000; // ╟рфхЁцър 15ьё
  590.                 state2 = S_WAIT_HLT;
  591.                 state = S_WAIT;
  592.                 break;
  593.             }
  594.             state = S_WAIT_HLT;
  595.  
  596.          case S_WAIT_HLT:
  597.             if(!(system & 0x08)) // HLT = 0 (схёъюэхўэюх юцшфрэшх HLT)
  598.             {
  599.                 return;
  600.             }
  601.             state = S_VERIFY2;
  602.  
  603.          case S_VERIFY2:
  604.             end_waiting_am = next + 6*Z80FQ/FDD_RPS; // max wait disk 6 turns
  605.             load();
  606.             find_marker();
  607.             break;
  608.  
  609.          // ----------------------------------------------------
  610.  
  611.          case S_EJECT1:
  612.              next = time + 10 * (Z80FQ / 1000); // ╟рфхЁцър 10ьё
  613.  
  614.              state2 = S_EJECT2;
  615.              state = S_WAIT;
  616.              break;
  617.  
  618.          case S_EJECT2:
  619.              status &= ~WDS_WRITEP;
  620.  
  621.              EjectPending = false;
  622.              state = S_IDLE;
  623.              break;
  624.  
  625.          // ----------------------------------------------------
  626.  
  627.          default:
  628.             errexit("WD1793 in wrong state");
  629.       }
  630.    }
  631. }
  632.  
  633. void WD1793::find_marker()
  634. {
  635.    if (conf.wd93_nodelay && seldrive->track != track)
  636.        seldrive->track = track;
  637.    load();
  638.  
  639.    foundid = -1U;
  640.    if (seldrive->motor && seldrive->rawdata)
  641.    {
  642.       unsigned div = seldrive->t.trklen*seldrive->t.ts_byte; // ─ышэр фюЁюцъш т ЄръЄрї cpu
  643.       unsigned i = (unsigned)((next+tshift) % div) / seldrive->t.ts_byte; // ╧ючшЎш  срщЄр ёююЄтхЄёЄтє■∙хую Єхъє∙хьє ЄръЄє эр фюЁюцъх
  644.       unsigned wait = -1U;
  645.  
  646.       // ╧юшёъ чруюыютър ьшэшьры№эю юЄёЄю ∙хую юЄ Єхъє∙хую срщЄр
  647.       for (unsigned is = 0; is < seldrive->t.s; is++)
  648.       {
  649.          unsigned pos = unsigned(seldrive->t.hdr[is].id - seldrive->t.trkd); // ╤ьх∙хэшх (т срщЄрї) чруюыютър юЄэюёшЄхы№эю эрўрыр фюЁюцъш
  650.          unsigned dist = (pos > i)? pos-i : seldrive->t.trklen+pos-i; // ╨рёёЄю эшх (т срщЄрї) юЄ чруюыютър фю Єхъє∙хую срщЄр
  651.          if (dist < wait)
  652.          {
  653.              wait = dist;
  654.              foundid = is;
  655.          }
  656.       }
  657.  
  658.       if (foundid != -1U)
  659.           wait *= seldrive->t.ts_byte; // ╟рфхЁцър т ЄръЄрї юЄ Єхъє∙хую ЄръЄр фю ЄръЄр ўЄхэш  яхЁтюую срщЄр чруюыютър
  660.       else
  661.           wait = 10*Z80FQ/FDD_RPS;
  662.  
  663.       if (conf.wd93_nodelay && foundid != -1U)
  664.       {
  665.          // adjust tshift, that id appares right under head
  666.          unsigned pos = unsigned(seldrive->t.hdr[foundid].id - seldrive->t.trkd + 2);
  667.          tshift = (unsigned)(((pos * seldrive->t.ts_byte) - (next % div) + div) % div);
  668.          wait = 100; // delay=0 causes fdc to search infinitely, when no matched id on track
  669.       }
  670.  
  671.       next += wait;
  672.    } // else no index pulses - infinite wait
  673.    else
  674.    {
  675.        next = comp.t_states + cpu.t + 1;
  676.    }
  677.  
  678.    if (seldrive->rawdata && next > end_waiting_am)
  679.    {
  680.        next = end_waiting_am;
  681.        foundid = -1U;
  682.    }
  683.    state = S_WAIT;
  684.    state2 = S_FOUND_NEXT_ID;
  685. }
  686.  
  687. char WD1793::notready()
  688. {
  689.    // fdc is too fast in no-delay mode, wait until cpu handles DRQ, but not more 'end_waiting_am'
  690.    if (conf.wd93_nodelay && (rqs & DRQ) && (next < (end_waiting_am - 5*Z80FQ/FDD_RPS) + (600*Z80FQ)/1000))
  691.    {
  692.        state2 = state;
  693.        state = S_WAIT;
  694.        next += seldrive->t.ts_byte;
  695.        return 1;
  696.    }
  697.  
  698.    return 0;
  699. }
  700.  
  701. void WD1793::getindex()
  702. {
  703.    unsigned trlen = seldrive->t.trklen*seldrive->t.ts_byte;
  704.    unsigned ticks = (unsigned)((next+tshift) % trlen);
  705.    if (!conf.wd93_nodelay)
  706.        next += (trlen - ticks);
  707.    rwptr = 0;
  708.    rwlen = seldrive->t.trklen;
  709.    state = S_WAIT;
  710. }
  711.  
  712. void WD1793::load()
  713. {
  714.    seldrive->t.seek(seldrive, seldrive->track, side, LOAD_SECTORS);
  715. }
  716.  
  717. unsigned char WD1793::in(unsigned char port)
  718. {
  719.    process();
  720.    if (port & 0x80)
  721.        return rqs | (system & 0x3F);
  722.    if (port == 0x1F)
  723.    {
  724.        rqs &= ~INTRQ;
  725.        return RdStatus();
  726.    }
  727.    if (port == 0x3F)
  728.        return track;
  729.    if (port == 0x5F)
  730.        return sector;
  731.    if (port == 0x7F)
  732.    {
  733.        status &= ~WDS_DRQ;
  734.        rqs &= ~DRQ;
  735.        return data;
  736.    }
  737.    return 0xFF;
  738. }
  739.  
  740. u8 WD1793::RdStatus()
  741. {
  742.     if(!(cmd & 0x80))
  743.     {
  744.         // hld & hlt
  745.         return status | (((sign_status & SIG_HLD) && (system & 8)) ? WDS_HEADL : 0);
  746.     }
  747.     return status;
  748. }
  749.  
  750.  
  751. void WD1793::out(unsigned char port, unsigned char val)
  752. {
  753.    process();
  754.  
  755.    if(EjectPending)
  756.    {
  757.        return;
  758.    }
  759.  
  760.    if (port == 0x1F)
  761.    { // cmd
  762. //       printf("%9lld: cmd=0x%02x, dat=0x%02x, trk=0x%02x, st=0x%02x\n", time + tshift, val, data, track, status);
  763.  
  764.       // force interrupt (type 4)
  765.       if ((val & 0xF0) == 0xD0)
  766.       {
  767.          u8 Cond = (val & 0xF);
  768.          next = comp.t_states + cpu.t;
  769.          idx_cnt = 0;
  770.          idx_tmo = next + 15 * Z80FQ/FDD_RPS; // 15 disk turns
  771.          cmd = val;
  772.  
  773.          if(Cond == 0)
  774.          {
  775.              state = S_IDLE; rqs = 0;
  776.              status &= ~WDS_BUSY;
  777.              return;
  778.          }
  779.  
  780.          if(Cond & 8) // unconditional int
  781.          {
  782.              state = S_IDLE; rqs = INTRQ;
  783.              status &= ~WDS_BUSY;
  784.              return;
  785.          }
  786.  
  787.          if(Cond & 4) // int by idam (unimplemented yet)
  788.          {
  789.              state = S_IDLE; rqs = INTRQ;
  790.              status &= ~WDS_BUSY;
  791.              return;
  792.          }
  793.  
  794.          if(Cond & 2) // int 1->0 rdy (unimplemented yet)
  795.          {
  796.              state = S_IDLE; rqs = INTRQ;
  797.              status &= ~WDS_BUSY;
  798.              return;
  799.          }
  800.  
  801.          if(Cond & 1) // int 0->1 rdy (unimplemented yet)
  802.          {
  803.              state = S_IDLE; rqs = INTRQ;
  804.              status &= ~WDS_BUSY;
  805.              return;
  806.          }
  807.  
  808.          return;
  809.       }
  810.  
  811.       if (status & WDS_BUSY)
  812.           return;
  813.       cmd = val;
  814.       next = comp.t_states + cpu.t;
  815.       status |= WDS_BUSY;
  816.       rqs = 0;
  817.       idx_cnt = 0;
  818.       idx_tmo = LLONG_MAX;
  819.  
  820.       //-----------------------------------------------------------------------
  821.  
  822.       if (cmd & 0x80) // read/write command (type 2, 3)
  823.       {
  824.          status = (status | WDS_BUSY) & ~(WDS_DRQ | WDS_LOST | WDS_NOTFOUND | WDS_RECORDT | WDS_WRITEP);
  825.  
  826.          // continue disk spinning
  827.          seldrive->motor = next + 2*Z80FQ;
  828.  
  829.          // abort if no disk
  830.          if (status & WDS_NOTRDY)
  831.          {
  832.              state2 = S_IDLE;
  833.              state = S_WAIT;
  834.              next = comp.t_states + cpu.t + Z80FQ/FDD_RPS;
  835.              rqs = INTRQ;
  836.              return;
  837.          }
  838.  
  839.          sign_status |= SIG_HLD;
  840.  
  841.          state = S_DELAY_BEFORE_CMD;
  842.          return;
  843.       }
  844.  
  845.       // (type 1)
  846.       if(cmd & CMD_SEEK_HEADLOAD) // h = 1
  847.           sign_status |= SIG_HLD;
  848.       else
  849.           sign_status &= ~SIG_HLD;
  850.  
  851.       // else seek/step command
  852.       status &= ~WDS_BUSY;
  853.       state = S_TYPE1_CMD;
  854.       return;
  855.    }
  856.  
  857.    //=======================================================================
  858.  
  859.    if (port == 0x3F)
  860.    {
  861.        track = val;
  862.        return;
  863.    }
  864.  
  865.    if (port == 0x5F)
  866.    {
  867.        sector = val;
  868.        return;
  869.    }
  870.  
  871.    if (port == 0x7F)
  872.    {
  873.        data = val;
  874.        rqs &= ~DRQ;
  875.        status &= ~WDS_DRQ;
  876.        return;
  877.    }
  878.  
  879.    if (port & 0x80) // FF
  880.    { // system
  881.       drive = val & 3;
  882.       side = ~(val >> 4) & 1;
  883.       seldrive = &fdd[drive];
  884.       seldrive->t.clear();
  885.  
  886.       if (!(val & 0x04))
  887.       { // reset
  888.          status &= ~WDS_NOTRDY;
  889.          rqs = INTRQ;
  890.          seldrive->motor = 0;
  891.          idx_cnt = 0;
  892.  
  893.          // ╚ч юяшёрэш  ёшуэрыр /MR FD 179X-02 floppy disk formatter/controller (WD may 80)
  894.          state = S_TYPE1_CMD;
  895.          cmd = 3; // restore
  896.          sector = 1;
  897.       }
  898.       else
  899.       {
  900.           if((system ^ val) & SYS_HLT) // hlt 0->1
  901.           {
  902.               if(!(status & WDS_BUSY))
  903.               {
  904.                   idx_cnt++; // ├хэхЁрЎш  шэфхъёэюую шьяєы№ёр ўхЁхч фшюф т ъюэЄЁюыыхЁх шфє∙шщ ё сшЄр HLT яюЁЄр FF эр /index
  905.               }
  906.           }
  907.       }
  908.  
  909.       if(val & 0x20) // ┬ quorum сшЄ D5 єяЁрты хЄ ьюЄюЁюь фшёъютюфр
  910.       {
  911.           sign_status |= SIG_HLD;
  912.           seldrive->motor = next + 2*Z80FQ;
  913.       }
  914.       system = val;
  915.    }
  916. }
  917.  
  918. void WD1793::Eject(unsigned Drive)
  919. {
  920.     if(seldrive == &fdd[Drive]) //├хэхЁрЎш  яюёыхфютрЄхы№эюёЄш т√эшьрэш  фшёъхЄ√ (/WPRT->1->0)
  921.     {
  922.         status |= WDS_WRITEP;
  923.         state = S_EJECT1;
  924.         EjectPending = true;
  925.     }
  926.     fdd[Drive].free();
  927. }
  928.  
  929. void WD1793::trdos_traps()
  930. {
  931.    unsigned pc = (cpu.pc & 0xFFFF);
  932.    if (pc < 0x3DFD)
  933.        return;
  934.  
  935.    // ╧ючшЎшюэшЁютрэшх эр ёюёхфэ■■ фюЁюцъє (ярєчр)
  936.    if (pc == 0x3DFD && bankr[0][0x3DFD] == 0x3E && bankr[0][0x3DFF] == 0x0E)
  937.    {
  938.        cpu.pc = cpu.DbgMemIf->rm(cpu.sp++);
  939.        cpu.pc |= unsigned(cpu.DbgMemIf->rm(cpu.sp++) << 8U);
  940.        cpu.a = 0;
  941.        cpu.c = 0;
  942.    }
  943.  
  944.    // ╧ючшЎшюэшЁютрэшх эр яЁюшчтюы№эє■ фюЁюцъє (ярєчр)
  945.    if (pc == 0x3EA0 && bankr[0][0x3EA0] == 0x06 && bankr[0][0x3EA2] == 0x3E)
  946.    {
  947.        cpu.pc = cpu.DbgMemIf->rm(cpu.sp++);
  948.        cpu.pc |= unsigned(cpu.DbgMemIf->rm(cpu.sp++) << 8U);
  949.        cpu.a = 0;
  950.        cpu.b = 0;
  951.    }
  952.  
  953.    if (pc == 0x3E01 && bankr[0][0x3E01] == 0x0D)
  954.    {
  955.        cpu.a = cpu.c = 1;
  956.        return;
  957.    } // no delays
  958.  
  959.    if (pc == 0x3FEC && bankr[0][0x3FED] == 0xA2 &&
  960.               (state == S_READ || (state2 == S_READ && state == S_WAIT)))
  961.    {
  962.       trdos_load = ROMLED_TIME;
  963.       if (rqs & DRQ)
  964.       {
  965.          cpu.DbgMemIf->wm(cpu.hl, data); // move byte from controller
  966.          cpu.hl++;
  967.          cpu.b--;
  968.          rqs &= ~DRQ;
  969.          status &= ~WDS_DRQ;
  970.       }
  971.  
  972.       if(seldrive->t.trkd)
  973.       {
  974.           while (rwlen)
  975.           { // move others
  976.              cpu.DbgMemIf->wm(cpu.hl, seldrive->t.trkd[rwptr++]);
  977.              rwlen--;
  978.              cpu.hl++;
  979.              cpu.b--;
  980.           }
  981.       }
  982.       cpu.pc += 2; // skip INI
  983.       return;
  984.    }
  985.    if (pc == 0x3FD1 && bankr[0][0x3FD2] == 0xA3 &&
  986.               (rqs & DRQ) && (rwlen>1) && (state == S_WRITE || (state2 == S_WRITE && state == S_WAIT)))
  987.    {
  988.       trdos_save = ROMLED_TIME;
  989.       while (rwlen > 1)
  990.       {
  991.          seldrive->t.write(rwptr++, cpu.DbgMemIf->rm(cpu.hl), 0);
  992.          rwlen--;
  993.          cpu.hl++;
  994.          cpu.b--;
  995.       }
  996.       cpu.pc += 2; // skip OUTI
  997.       return;
  998.    }
  999. }
  1000.