Subversion Repositories pentevo

Rev

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