Subversion Repositories pentevo

Rev

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

  1. #include "std.h"
  2.  
  3. #include "emul.h"
  4. #include "vars.h"
  5. #include "util.h"
  6.  
  7. #include "upd765.h"
  8.  
  9. #if 0
  10. #define dprintf printf
  11. #else
  12. #define dprintf(...)
  13. #endif
  14.  
  15. static unsigned CalcCmdLen(u8 Cmd)
  16. {
  17.     Cmd &= 0x1F;
  18.     unsigned CmdLen;
  19.     switch(Cmd)
  20.     {
  21.     case 0b00010: CmdLen = 8; break; // read track
  22.     case 0b00011: CmdLen = 2; break; // specify
  23.     case 0b00100: CmdLen = 1; break; // sense drive status
  24.     case 0b00101: CmdLen = 8; break; // write data
  25.     case 0b00110: CmdLen = 8; break; // read data
  26.     case 0b00111: CmdLen = 1; break; // recalibrate
  27.     case 0b01000: CmdLen = 0; break; // sense interrupt status
  28.     case 0b01001: CmdLen = 8; break; // write deleted data
  29.     case 0b01010: CmdLen = 1; break; // read id
  30.     case 0b01100: CmdLen = 8; break; // read deleted data
  31.     case 0b01101: CmdLen = 5; break; // format track
  32.     case 0b01111: CmdLen = 2; break; // seek
  33.     case 0b10001: CmdLen = 8; break; // scan equal
  34.     case 0b11001: CmdLen = 8; break; // scan low or equal
  35.     case 0b11101: CmdLen = 8; break; // scan high or equal
  36.     default: CmdLen = 0;
  37.     }
  38.     return CmdLen;
  39. }
  40.  
  41. TUpd765::TUpd765()
  42. {
  43.     SelDrive = &comp.fdd[0];
  44. }
  45.  
  46. void TUpd765::out(u8 data)
  47. {
  48.     // 3FFD (ЁхушёЄЁ ъюьрэф/фрээ√ї)
  49.     if(Msr & (MSR_CB | MSR_EXM))
  50.     {
  51.         dprintf("upd765:   error fdc is busy, d=0x%02X, msr=0x%02X\n", data, Msr);
  52.         return;
  53.     }
  54.  
  55.     if(DataPtr < _countof(Data))
  56.     {
  57.         if(DataPtr == 0) // ╧хЁхфрхЄё  ъюф ъюьрэф√
  58.         {
  59.             CmdLen = CalcCmdLen(data);
  60.  
  61.         }
  62.         Data[DataPtr++] = data;
  63.     }
  64.     if(DataPtr == CmdLen + 1) // execute command
  65.     {
  66.         Msr |= MSR_CB;
  67.         ResultPtr = 0;
  68.         ReadData = false;
  69.         // ╟р∙шЄ√ шёяюы№чє■Є ЇръЄ, ўЄю т +3 шёяюы№чєхЄё  Єюы№ъю ьырф°шщ сшЄ шч us
  70.         // ╧ю¤Єюьє яЁш us=2 т√сшЁрхЄё  ЄюЄ цх фшёъютюф ўЄю ш яЁш us=0
  71.         // untouchables, batman the movie, chase h.q.
  72.         auto Cmd = Data[0] & 0x1F;
  73.         switch(Cmd)
  74.         {
  75.         case 0b00011: // specify
  76.             dprintf("upd765: specify: srt=%u, hut=%u, hlt=%u, nd=%u\n", Data[1] >> 4U, Data[1] & 0xFU, Data[2] >> 1U, Data[2] & 1U);
  77.             Msr &= ~(MSR_DIO | MSR_CB); // CPU->FDC
  78.             break;
  79.         case 0b00100: // sense drv st
  80.         {
  81.             auto us{ (Data[1] & 3U) };
  82.             auto hd{ (Data[1] >> 2U) & 1U };
  83.             SelDrive = &comp.fdd[us];
  84.  
  85.             St3 &= ~3;
  86.             St3 |= ST3_RY | us;
  87.             if(pc[us] == 0)
  88.             {
  89.                 St3 |= ST3_T0;
  90.             }
  91.             else
  92.             {
  93.                 St3 &= ~ST3_T0;
  94.             }
  95.             Result[0] = &St3;
  96.             ResultLen = 1;
  97.             Msr |= MSR_RQM | MSR_DIO; // CPU<-FDC
  98.             dprintf("upd765: sense drv st: hd=%u, us=%u, st3=0x%02X\n", hd, us, St3);
  99.             break;
  100.         }
  101.         case 0b00110: // read data
  102.         case 0b01100: // read deleted data
  103.             ReadData = true;
  104.         case 0b00010: // read track
  105.         {
  106.             c = Data[2];
  107.             h = Data[3];
  108.             r = Data[4];
  109.             n = Data[5];
  110.             auto mt = (Data[0] >> 7U) & 1U;
  111.             auto sk = (Data[0] >> 5U) & 1U;
  112.             auto us = Data[1] & 1U;
  113.             SelDrive = &comp.fdd[us];
  114.             ph[us] = (Data[1] >> 2U) & 1U;
  115.             eot = Data[6];
  116.  
  117.             const char *CmdStr{ };
  118.             switch(Cmd)
  119.             {
  120.             case 0b00010: CmdStr = "track"; break; // read track
  121.             case 0b00110: CmdStr = "data"; break; // read data
  122.             case 0b01100: CmdStr = "deleted data"; break; // read deleted data
  123.             }
  124.  
  125.             load();
  126.  
  127.             auto SecHdr = SelDrive->t.get_sector(r, n);
  128.  
  129.             dprintf("upd765: read %s: mt=%u, sk=%u, hd=%u, us=%u, c=%u, h=%u, r=%u, n=%u, eot=%u, dtl=%u, pc=%u, ph=%u\n",
  130.                 CmdStr, mt, sk, ph[us], us, c, h, r, n, eot, Data[8], pc[us], ph[us]);
  131.  
  132.             if(SecHdr != nullptr)
  133.             {
  134.                 pr[us] = u8(SecHdr - SelDrive->t.hdr);
  135.                 DataLen = SecHdr->datlen;
  136.                 MaxDataLen = unsigned(MAX_TRACK_LEN - (SecHdr->data - SelDrive->t.trkd));
  137.             }
  138.  
  139.             Msr |= MSR_EXM;
  140.             St0 = u8((ph[us] << 2U) | us);
  141.             St1 = 0;
  142.             St2 = 0;
  143.  
  144.             if(SecHdr == nullptr || SecHdr->data == nullptr)
  145.             {
  146.                 Msr &= ~MSR_EXM;
  147.                 if(ReadData)
  148.                 {
  149.                     St0 |= ST0_AT1;
  150.                 }
  151.                 St1 |= ST1_ND;
  152.                 DataLen = 0;
  153.             }
  154.  
  155.             if(SecHdr != nullptr && SecHdr->c1 == 0)
  156.             {
  157.                 Msr &= ~MSR_EXM;
  158.                 St0 |= ST0_AT1;
  159.                 St1 |= ST1_DE;
  160.                 DataLen = 0;
  161.             }
  162.  
  163.             if(SecHdr != nullptr && (Cmd == 0b00110 && (SecHdr->Flags & SECHDR::FL_DDAM) ||
  164.                 Cmd == 0b01100 && !(SecHdr->Flags & SECHDR::FL_DDAM)))
  165.             {
  166.                 St2 |= ST2_CM;
  167.                 if(sk != 0) // skip data/deleted data
  168.                 {
  169.                     Msr &= ~MSR_EXM;
  170.                     DataLen = 0;
  171.                 }
  172.             }
  173.  
  174.             if(SecHdr != nullptr && SecHdr->c != c)
  175.             {
  176.                 St2 |= ST2_WC;
  177.  
  178.                 if(c == 0xFF)
  179.                 {
  180.                     St2 |= ST2_BC;
  181.                 }
  182.             }
  183.  
  184.             Result[0] = &St0;
  185.             Result[1] = &St1;
  186.             Result[2] = &St2;
  187.             Result[3] = &c;
  188.             Result[4] = &h;
  189.             Result[5] = &r;
  190.             Result[6] = &n;
  191.             ResultLen = 7;
  192.             Msr |= MSR_RQM | MSR_DIO; // CPU<-FDC
  193.             break;
  194.         }
  195.         case 0b00111: // recalibrate
  196.         {
  197.             auto us{ Data[1] & 3U };
  198.             SelDrive = &comp.fdd[us];
  199.             trdos_seek = ROMLED_TIME;
  200.             dprintf("upd765: recalibrate: us=%u\n", us);
  201.             pc[us] = 0;
  202.             ph[us] = 0;
  203.             pr[us] = 0;
  204.             seek();
  205.             St0 = u8(ST0_SE | us);
  206.             St3 |= ST3_T0;
  207.             Msr &= ~(MSR_DIO | MSR_CB); // CPU->FDC
  208.             break;
  209.         }
  210.         case 0b01000: // sense int
  211.         {
  212.             Result[0] = &St0;
  213.             Result[1] = &pc[SelDrive->Id];
  214.             ResultLen = 2;
  215.             Msr |= MSR_RQM | MSR_DIO; // CPU<-FDC
  216.             dprintf("upd765: sense int: st0=0x%02X, pc=%u, c=%u\n", St0, pc[SelDrive->Id], c);
  217.             break;
  218.         }
  219.         case 0b01010: // read id
  220.         {
  221.             u8 us{ u8(Data[1] & 1U) };
  222.             ph[us] = (Data[1] >> 2U) & 1U;
  223.             SelDrive = &comp.fdd[us];
  224.  
  225.             load();
  226.  
  227.             St0 = u8((ph[us] << 2U) | us);
  228.             St1 = 0;
  229.             St2 = 0;
  230.  
  231.             const auto opr = pr[us];
  232.             if(SelDrive->t.s == 0) // ╥Ё¤ъ схч ёхъЄюЁют
  233.             {
  234.                 St1 |= ST1_MA;
  235.             }
  236.             else
  237.             {
  238.                 const auto &SecHdr = SelDrive->t.hdr[pr[us]];
  239.                 pr[us]++;
  240.                 if(pr[us] >= SelDrive->t.s)
  241.                 {
  242.                     pr[us] = 0;
  243.                 }
  244.                 c = SecHdr.c;
  245.                 h = SecHdr.s;
  246.                 r = SecHdr.n;
  247.                 n = SecHdr.l;
  248.  
  249.                 if(SecHdr.c1 == 0)
  250.                 {
  251.                     St1 |= ST1_DE | ST1_ND;
  252.                 }
  253.  
  254.                 if(c == 0xFF && c != SecHdr.c)
  255.                 {
  256.                     St2 |= ST2_BC;
  257.                 }
  258.             }
  259.  
  260.             Result[0] = &St0;
  261.             Result[1] = &St1;
  262.             Result[2] = &St2;
  263.             Result[3] = &c;
  264.             Result[4] = &h;
  265.             Result[5] = &r;
  266.             Result[6] = &n;
  267.             ResultLen = 7;
  268.             Msr |= MSR_RQM | MSR_DIO; // CPU<-FDC
  269.             dprintf("upd765: read id: hd=%u, us=%u, c=%u, h=%u, r=%u, n=%u, pc=%u, ph=%u, pr=%u\n",
  270.                 h, Data[1] & 3U, c, h, r, n, pc[us], ph[us], opr);
  271.             break;
  272.         }
  273.         case 0b01111: // seek
  274.         {
  275.             trdos_seek = ROMLED_TIME;
  276.             u8 us{ u8(Data[1] & 3U) };
  277.             auto oph = ph[us];
  278.             auto opc = pc[us];
  279.             ph[us] = (Data[1] >> 2U) & 1U;
  280.             pc[us] = u8(Data[2]);
  281.             SelDrive = &comp.fdd[us];
  282.             if(oph != ph[us] || opc != pc[us])
  283.             {
  284.                 pr[us] = 0;
  285.             }
  286.             dprintf("upd765: seek: hd=%u, us=%u, ncn=%u\n", ph[us], us, pc[us]);
  287.             seek();
  288.             St0 = u8(ST0_SE | (ph[us] << 2U) | us);
  289.             if(pc[us] != 0)
  290.             {
  291.                 St3 &= ~ST3_T0;
  292.             }
  293.             Msr &= ~(MSR_DIO | MSR_CB); // CPU->FDC
  294.             break;
  295.         }
  296.         default:
  297.             dprintf("upd765: unk cmd=0x%02X\n", Data[0]);
  298.             St0 = ST0_IC;
  299.             Result[0] = &St0;
  300.             ResultLen = 1;
  301.             Msr |= MSR_RQM | MSR_DIO; // CPU<-FDC
  302.             break;
  303.         }
  304.         DataPtr = 0;
  305.     }
  306. }
  307.  
  308. static unsigned PollCnt = 10;
  309. static unsigned DataLenPrev = 0;
  310.  
  311. u8 TUpd765::in(u8 port)
  312. {
  313.     switch(port)
  314.     {
  315.         case 2: // 2FFD (main status register)
  316. //            printf("upd765: read msr: msr=0x%02X\n", Msr);
  317.             if(DataLen != 0)
  318.             {
  319.                 if(PollCnt == 0)
  320.                 {
  321.                     ReadDataReg();
  322.                     St1 |= ST1_OR;
  323.                 }
  324.                 else
  325.                 {
  326.                     if(DataLen == DataLenPrev)
  327.                     {
  328.                         PollCnt--;
  329.                     }
  330.                 }
  331.                 DataLenPrev = DataLen;
  332.             }
  333.             else
  334.             {
  335.                 PollCnt = 10;
  336.             }
  337.             return Msr; // фхЄхъЄ +3/+2A юёє∙хёЄты хЄё  яю сшЄє D7 main status register (хёыш 1, Єю +3)
  338.         case 3: // 3FFD (ЁхушёЄЁ фрээ√ї)
  339.             return ReadDataReg();
  340.     }
  341.     return 0xFF;
  342. }
  343.  
  344. u8 TUpd765::ReadDataReg()
  345. {
  346.     if(DataLen != 0) // ─рээ√х
  347.     {
  348.         trdos_load = ROMLED_TIME;
  349.  
  350.         const auto *SecHdr = &SelDrive->t.hdr[pr[SelDrive->Id]];//SelDrive->t.get_sector(r, n);
  351.         auto DataIdx = SecHdr->datlen - DataLen;
  352.         auto Data = SecHdr->data[DataIdx];
  353.  
  354.         DataLen--;
  355.         MaxDataLen--;
  356.  
  357.         bool Overrun = false;
  358.         if(MaxDataLen == 0)
  359.         {
  360.             Overrun = (DataLen != 0);
  361.             DataLen = 0;
  362.         }
  363.  
  364.         if(DataLen == 0)
  365.         {
  366.             pr[SelDrive->Id]++;// = u8(SecHdr - SelDrive->t.hdr + 1);
  367.             pr[SelDrive->Id] %= SelDrive->t.s;
  368.         }
  369.  
  370.         if(DataLen == 0 && SecHdr->c2 == 0)
  371.         {
  372.             Msr &= ~MSR_EXM;
  373.             St0 &= ~ST0_IC_MASK;
  374.             St0 |= ST0_AT1;
  375.             St1 |= ST1_DE;
  376.             St2 |= ST2_DD;
  377.             Data ^= rdtsc(); // ╬°шсър crc т чюэх фрээ√ї ёхъЄюЁр
  378.  
  379.             dprintf("upd765:   data transfer complete1\n");
  380.             return Data;
  381.         }
  382.  
  383.         if(DataLen == 0 && r < eot)
  384.         {
  385.             r++;
  386.             SecHdr = SelDrive->t.get_sector(r, n);
  387.             if(SecHdr == nullptr) // ╤хъЄюЁ эх эрщфхэ
  388.             {
  389.                 St0 &= ~ST0_IC_MASK;
  390.                 St0 |= ST0_AT1;
  391.  
  392.                 St1 |= ST1_ND;
  393.                 St1 |= ST1_MA;
  394.                 St2 |= ST2_MD;
  395.  
  396.                 DataLen = 0;
  397.             }
  398.             else
  399.             {
  400.                 pr[SelDrive->Id] = u8(SecHdr - SelDrive->t.hdr);
  401.                 pr[SelDrive->Id] %= SelDrive->t.s;
  402.  
  403.                 n = SecHdr->l;
  404.                 DataLen = SecHdr->datlen;
  405.  
  406.                 if(SecHdr->c1 == 0)
  407.                 {
  408.                     St0 &= ~ST0_IC_MASK;
  409.                     St0 |= ST0_AT1;
  410.  
  411.                     St1 |= ST1_DE;
  412.                     St2 |= ST2_DD;
  413.                     DataLen = 0;
  414.                 }
  415.             }
  416.         }
  417.  
  418.         if(ReadData && DataLen == 0 && (r >= eot || Overrun))
  419.         {
  420.             St0 &= ~ST0_IC_MASK;
  421.             St0 |= ST0_AT1;
  422.  
  423.             St1 |= ST1_EN; // ┬ёхуфр єёЄрэютыхэ эр +3 (ёь. ъюььхэЄрЁшш т фшчрёёхьсыхЁх +3dos (0x204A))
  424.         }
  425.  
  426.         if(DataLen == 0)
  427.         {
  428.             dprintf("upd765:   data transfer complete2\n");
  429.             Msr &= ~MSR_EXM;
  430.         }
  431.         return Data;
  432.     }
  433.     else // ╨хчєы№ЄрЄ√
  434.     {
  435.         assert((Msr & MSR_EXM) == 0);
  436.         if(ResultPtr < ResultLen)
  437.         {
  438.             u8 Res = *Result[ResultPtr++];
  439.             dprintf("upd765:   read result: 0x%02X\n", Res);
  440.             if(ResultPtr == ResultLen)
  441.             {
  442.                 dprintf("upd765:   read result complete\n");
  443.                 assert((Msr & (MSR_DIO | MSR_CB)) != 0);
  444.                 Msr &= ~(MSR_DIO | MSR_CB); // CPU->FDC
  445.                 St0 &= ~ST0_IC_MASK;
  446.                 St0 |= ST0_IC;
  447.             }
  448.             return Res;
  449.         }
  450.         else
  451.         {
  452.             dprintf("upd765:   error no result to read\n");
  453.         }
  454.     }
  455.  
  456.     return 0xFF;
  457. }
  458.  
  459. void TUpd765::load()
  460. {
  461.     seek(LOAD_SECTORS);
  462. }
  463.  
  464. void TUpd765::seek(SEEK_MODE SeekMode)
  465. {
  466.     auto cyl{ pc[SelDrive->Id] /*/ 2*/ };
  467.     if(cyl > 42)
  468.     {
  469.         cyl = 42;
  470.     }
  471.     SelDrive->track = cyl;
  472.     SelDrive->t.seek(SelDrive, cyl, ph[SelDrive->Id], SeekMode);
  473. }
  474.  
  475. TUpd765 Upd765;
  476.