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 "vars.h"
  5. #include "tape.h"
  6. #include "memory.h"
  7.  
  8. #include "util.h"
  9. #include "png/zlib.h"
  10.  
  11. #define Z80FQ 3500000
  12.  
  13. // └ыЇртшЄ шч шьяєы№ёют Ёрчэющ фышэ√ (ўшёыю ёшьтюыют рыЇртшЄр эх сюыхх 256, ёё√ыъш юфэюсрщЄют√х)
  14. // -1 (UINT_MAX) - ╤яхЎшры№эюх чэрўхэшх - юёЄрэют ыхэЄ√
  15. // ─тр ёЄрЁ°шї сшЄр - Їыруш (ъръ т сыюъх 0x19 TZX 1.20):
  16. // 00: opposite to the current level (make an edge, as usual) - default
  17. // 01: same as the current level (no edge - prolongs the previous pulse)
  18. // 10: force low level
  19. // 11: force high level
  20. u32 tape_pulse[0x100];
  21. static unsigned max_pulses = 0;
  22. static unsigned tape_err = 0;
  23.  
  24. // ╠рёёшт ёё√ыюъ эр рыЇртшЄ (ёё√ыъш юфэюсрщЄют√х), ърцф√щ эют√щ ёшьтюы - ёьхэр яюы ЁэюёЄш ёшуэрыр
  25. // ═рўры№эр  яюы ЁэюёЄ№ яюыюцшЄхы№эр  (т√ёюъшщ єЁютхэ№ ёшуэрыр)
  26. u8 *tape_image = nullptr;
  27. static unsigned tape_imagesize = 0;
  28.  
  29. TAPEINFO *tapeinfo;
  30. unsigned tape_infosize;
  31.  
  32. static unsigned appendable;
  33.  
  34. typedef int (__cdecl *inflateInit__ptr)(z_streamp strm, const char *version, int stream_size);
  35. typedef int (__cdecl *inflate_ptr)(z_streamp strm, int flush);
  36. typedef int (__cdecl *inflateEnd_ptr)(z_streamp strm);
  37.  
  38. static inflateInit__ptr inflateInit__p = nullptr;
  39. static inflate_ptr inflate_p = nullptr;
  40. static inflateEnd_ptr inflateEnd_p = nullptr;
  41.  
  42. static HMODULE ZlibDll = nullptr;
  43.  
  44. bool ZlibInit()
  45. {
  46.     ZlibDll = LoadLibrary("zlib1.dll");
  47.     if(!ZlibDll)
  48.     {
  49.         return false;
  50.     }
  51.     inflateInit__p = (inflateInit__ptr)GetProcAddress(ZlibDll, "inflateInit_");
  52.     if(!inflateInit__p)
  53.     {
  54.         return false;
  55.     }
  56.     inflate_p = (inflate_ptr)GetProcAddress(ZlibDll,"inflate");
  57.     if(!inflate_p)
  58.     {
  59.         return false;
  60.     }
  61.     inflateEnd_p = (inflateEnd_ptr)GetProcAddress(ZlibDll,"inflateEnd");
  62.     if(!inflateEnd_p)
  63.     {
  64.         return false;
  65.     }
  66.     return true;
  67. }
  68.  
  69. void ZlibDone()
  70. {
  71.     if(ZlibDll)
  72.     {
  73.         FreeLibrary(ZlibDll);
  74.     }
  75. }
  76.  
  77. // ╚∙хЄ фышэє шьяєы№ёр т рыЇртшЄх ш тючтЁр∙рхЄ шэфхъё эрщфхээюую ¤ыхьхэЄр
  78. // ┼ёыш шьяєы№ё ё Єръющ °шЁшэющ эх эрщфхэ, юэ фюсрты хЄё  т ъюэхЎ ш тючтЁр∙рхЄё  хую шэфхъё
  79. // tape image contains indexes in tape_pulse[]
  80. static u8 find_pulse(u32 t, unsigned Flags = 0)
  81. {
  82.     if(max_pulses < _countof(tape_pulse))
  83.     {
  84.         double e = 0.10 * t; // ЁрчсЁюё 10%
  85.         for(unsigned i = 0; i < max_pulses; i++)
  86.         {
  87.             u32 pulse = tape_pulse[i] & tape_pulse_mask;
  88.             unsigned fl = (tape_pulse[i] >> 30) & 3;
  89.             if(fl == (Flags & 3) && (t - e) < pulse && pulse <= (t + e))
  90.             {
  91.                 return u8(i);
  92.             }
  93.         }
  94.         tape_pulse[max_pulses] = t | ((Flags & 3) << 30);
  95.         return u8(max_pulses++);
  96.     }
  97.     if(!tape_err)
  98.     {
  99.         errmsg("pulse table full");
  100.         tape_err = 1;
  101.     }
  102.     unsigned nearest = 0; int delta = INT_MAX;
  103.     for(unsigned i = 0; i < _countof(tape_pulse); i++)
  104.     {
  105.         u32 pulse = tape_pulse[i] & tape_pulse_mask;
  106.         unsigned fl = (tape_pulse[i] >> 30) & 3;
  107.         if(fl == (Flags & 3) && delta > abs((int)t - (int)pulse))
  108.         {
  109.             nearest = i;
  110.             delta = abs((int)t - (int)pulse);
  111.         }
  112.     }
  113.     return u8(nearest);
  114. }
  115.  
  116. void find_tape_index()
  117. {
  118.     for(unsigned i = 0; i < tape_infosize; i++)
  119.     {
  120.         if(comp.tape.play_pointer >= tape_image + tapeinfo[i].pos)
  121.         {
  122.             comp.tape.index = i;
  123.         }
  124.     }
  125.     temp.led.tape_started = -600 * Z80FQ;
  126. }
  127.  
  128. static void find_tape_sizes()
  129. {
  130.     for(unsigned i = 0; i < tape_infosize; i++)
  131.     {
  132.         unsigned end = (i == tape_infosize - 1) ? tape_imagesize : tapeinfo[i + 1].pos;
  133.  
  134.         unsigned sz = 0;
  135.         for(unsigned j = tapeinfo[i].pos; j < end; j++)
  136.         {
  137.             sz += tape_pulse[tape_image[j]] & tape_pulse_mask;
  138.         }
  139.         tapeinfo[i].t_size = sz;
  140.     }
  141. }
  142.  
  143. void stop_tape()
  144. {
  145.     // ╙ёыютш  фы  т√їюфр шї ЇєэъЎшш tape_bit()
  146.     comp.tape.edge_change = LLONG_MAX;
  147.     comp.tape.tape_bit = -1U;
  148.  
  149.     if(comp.tape.stopped) // ┼ёыш ыхэЄр єцх юёЄрэютыхэр, Єю эшўхую эх фхырхь
  150.     {
  151.         return;
  152.     }
  153.  
  154.     comp.tape.stopped = true;
  155.  
  156.     find_tape_index();
  157.  
  158.     const char *msg = "tape stopped";
  159.     if(comp.tape.play_pointer == comp.tape.end_of_tape) // ╧Ёш фюёЄшцхэшш ъюэЎр ыхэЄ√ эх фхырхь ртЄюяхЁхьюЄъє
  160.     {
  161.         msg = "end of tape";
  162.     }
  163.     else
  164.     {
  165.         comp.tape.play_pointer = nullptr;
  166.     }
  167.     strcpy(statusline, msg); statcnt = 40;
  168. }
  169.  
  170. void reset_tape()
  171. {
  172.     comp.tape.index = 0;
  173.     comp.tape.stopped = true;
  174.     comp.tape.play_pointer = nullptr;
  175.     comp.tape.edge_change = LLONG_MAX;
  176.     comp.tape.tape_bit = -1U;
  177. }
  178.  
  179. void start_tape()
  180. {
  181.     if(!tape_image)
  182.     {
  183.         return;
  184.     }
  185.  
  186.     comp.tape.play_pointer = tape_image + tapeinfo[comp.tape.index].pos;
  187.     comp.tape.end_of_tape = tape_image + tape_imagesize;
  188.  
  189.     if(comp.tape.play_pointer >= comp.tape.end_of_tape) // ╩юэхЎ ыхэЄ√, шуэюЁшЁєхь чряєёъ
  190.     {
  191.         return;
  192.     }
  193.     comp.tape.stopped = false;
  194.     comp.tape.edge_change = comp.t_states + cpu.t;
  195.     temp.led.tape_started = -600 * Z80FQ;
  196.     comp.tape.tape_bit = -1U;
  197.     strcpy(statusline, "tape started"); statcnt = 40;
  198. }
  199.  
  200. void closetape()
  201. {
  202.     if(tape_image)
  203.     {
  204.         free(tape_image);
  205.         tape_image = nullptr;
  206.     }
  207.     if(tapeinfo)
  208.     {
  209.         free(tapeinfo);
  210.         tapeinfo = nullptr;
  211.     }
  212.     comp.tape.play_pointer = nullptr; // stop tape
  213.     comp.tape.index = 0; // rewind tape
  214.     tape_err = max_pulses = tape_imagesize = tape_infosize = 0;
  215.     comp.tape.edge_change = LLONG_MAX;
  216.     comp.tape.tape_bit = -1U;
  217. }
  218.  
  219. static void reserve(unsigned datasize)
  220. {
  221.     const unsigned blocksize = 16384;
  222.     unsigned newsize = align_by(datasize + tape_imagesize + 1, blocksize);
  223.     if(!tape_image)
  224.     {
  225.         tape_image = (unsigned char*)malloc(newsize);
  226.     }
  227.     if(align_by(tape_imagesize, blocksize) < newsize)
  228.     {
  229.         tape_image = (unsigned char*)realloc(tape_image, newsize);
  230.     }
  231. }
  232.  
  233. static void makeblock(const unsigned char *data, unsigned size, unsigned pilot_t,
  234.     unsigned s1_t, unsigned s2_t, unsigned zero_t, unsigned one_t,
  235.     unsigned pilot_len, unsigned pause, unsigned char last = 8)
  236. {
  237.     reserve(size * 16 + pilot_len + 3);
  238.     if(pilot_len != -1U)
  239.     {
  240.         u8 t = find_pulse(pilot_t);
  241.         for(unsigned i = 0; i < pilot_len; i++)
  242.             tape_image[tape_imagesize++] = t;
  243.         tape_image[tape_imagesize++] = find_pulse(s1_t);
  244.         tape_image[tape_imagesize++] = find_pulse(s2_t);
  245.     }
  246.     u8 t0 = find_pulse(zero_t), t1 = find_pulse(one_t);
  247.     for(; size > 1; size--, data++)
  248.     {
  249.         for(unsigned char j = 0x80; j; j >>= 1)
  250.         {
  251.             tape_image[tape_imagesize++] = (*data & j) ? t1 : t0;
  252.             tape_image[tape_imagesize++] = (*data & j) ? t1 : t0;
  253.         }
  254.     }
  255.     for(unsigned char j = 0x80; j != (unsigned char)(0x80 >> last); j >>= 1) // last byte
  256.     {
  257.         tape_image[tape_imagesize++] = (*data & j) ? t1 : t0;
  258.         tape_image[tape_imagesize++] = (*data & j) ? t1 : t0;
  259.     }
  260.     if(pause)
  261.     {
  262.         tape_image[tape_imagesize++] = find_pulse(pause*(Z80FQ / 1000));
  263.     }
  264. }
  265.  
  266. static void desc(const unsigned char *data, unsigned size, char *dst)
  267. {
  268.     unsigned char crc = 0;
  269.     char prg[11];
  270.     unsigned i; //Alone Coder 0.36.7
  271.     for(/*unsigned*/ i = 0; i < size; i++)
  272.     {
  273.         crc ^= data[i];
  274.     }
  275.  
  276.     if(!*data && size == 19 && (data[1] == 0 || data[1] == 3))
  277.     {
  278.         for(i = 0; i < 10; i++)
  279.         {
  280.             prg[i] = (data[i + 2] < ' ' || data[i + 2] >= 0x80) ? '?' : char(data[i + 2]);
  281.         }
  282.         prg[10] = 0;
  283.         for(i = 9; i && prg[i] == ' '; prg[i--] = 0);
  284.         sprintf(dst, "%s: \"%s\" %d,%d", data[1] ? "Bytes" : "Program", prg,
  285.             *(const unsigned short*)(data + 14), *(const unsigned short*)(data + 12));
  286.     }
  287.     else if(*data == 0xFF)
  288.     {
  289.         sprintf(dst, "data block, %u bytes", size - 2);
  290.     }
  291.     else
  292.     {
  293.         sprintf(dst, "#%02X block, %u bytes", *data, size - 2);
  294.     }
  295.     sprintf(dst + strlen(dst), ", crc %s", crc ? "bad" : "ok");
  296. }
  297.  
  298. static bool alloc_infocell()
  299. {
  300.     TAPEINFO *tmp = (TAPEINFO*)realloc(tapeinfo, (tape_infosize + 1) * sizeof(TAPEINFO));
  301.     if(!tmp)
  302.     {
  303.         return false;
  304.     }
  305.     tapeinfo = tmp;
  306.     tapeinfo[tape_infosize].pos = tape_imagesize;
  307.     appendable = 0;
  308.     return true;
  309. }
  310.  
  311. static bool named_cell(const void *nm, unsigned sz = 0)
  312. {
  313.     if(!alloc_infocell())
  314.         return false;
  315.  
  316.     const size_t n = _countof(tapeinfo[tape_infosize].desc) - 1;
  317.     size_t len = min(n, sz ? sz : strlen((const char*)nm));
  318.     strncpy(tapeinfo[tape_infosize].desc, (const char*)nm, len);
  319.     tapeinfo[tape_infosize].desc[len] = 0;
  320.     tape_infosize++;
  321.     return true;
  322. }
  323.  
  324. int readTAP()
  325. {
  326.     unsigned char *ptr = snbuf;
  327.     closetape();
  328.     while(ptr < snbuf + snapsize)
  329.     {
  330.         unsigned size = *(unsigned short*)ptr; ptr += 2;
  331.         if(!size)
  332.         {
  333.             break;
  334.         }
  335.         alloc_infocell();
  336.         desc(ptr, size, tapeinfo[tape_infosize].desc);
  337.         tape_infosize++;
  338.         makeblock(ptr, size, 2168U, 667U, 735U, 855U, 1710U, (*ptr < 4) ? 8064U : 3220U, 1000U);
  339.         ptr += size;
  340.     }
  341.     find_tape_sizes();
  342.     return (ptr == snbuf + snapsize);
  343. }
  344.  
  345. #pragma pack(push, 1)
  346. struct TCswHdr
  347. {
  348.     char Signature[22];
  349.     u8 Term;
  350.     u8 VerMajor;
  351.     u8 VerMinor;
  352.     union
  353.     {
  354.         struct
  355.         {
  356.             u16 SampleRate;
  357.             u8 CompressionType;
  358.             u8 Flags;
  359.             u8 Reserved[3];
  360.             u8 Data[];
  361.         } Ver1;
  362.  
  363.         struct
  364.         {
  365.             u32 SampleRate;
  366.             u32 PulsesAfterDecompression;
  367.             u8 CompressionType;
  368.             u8 Flags;
  369.             u8 HeaderExtLen;
  370.             char EncAppDesc[16];
  371.             u8 ExtHdr[];
  372.         } Ver2;
  373.     };
  374. };
  375. #pragma pack(pop)
  376.  
  377. int readCSW()
  378. {
  379.     closetape();
  380.     named_cell("CSW tape image");
  381.  
  382.     const TCswHdr *CswHdr = (TCswHdr *)snbuf;
  383.     u8 CompType;
  384.     u32 SampleRate;
  385.     u8 Flags;
  386.     u32 DataOffset;
  387.     u32 PulsesCount;
  388.     switch(CswHdr->VerMajor)
  389.     {
  390.     case 1:
  391.         CompType = CswHdr->Ver1.CompressionType;
  392.         SampleRate = CswHdr->Ver1.SampleRate;
  393.         Flags = CswHdr->Ver1.Flags;
  394.         DataOffset = offsetof(TCswHdr, Ver1.Data);
  395.         PulsesCount = snapsize - 0x18; // ═хяюэ Єэр  ъюэёЄрэЄр
  396.         break;
  397.  
  398.     case 2:
  399.         CompType = CswHdr->Ver2.CompressionType;
  400.         SampleRate = CswHdr->Ver2.SampleRate;
  401.         Flags = CswHdr->Ver2.Flags;
  402.         DataOffset = offsetof(TCswHdr, Ver2.ExtHdr) + CswHdr->Ver2.HeaderExtLen;
  403.         PulsesCount = CswHdr->Ver2.PulsesAfterDecompression;
  404.         break;
  405.  
  406.     default: // unknown csw version
  407.         return 0;
  408.     }
  409.  
  410.     u32 UncompressedSize = snapsize;
  411.     switch(CompType)
  412.     {
  413.     case 2: // Z-RLE
  414.     {
  415.         if(!temp.ZlibSupport)
  416.             return 0;
  417.         static const size_t out_sz = sizeof(snbuf);
  418.         void *out = malloc(out_sz);
  419.         if(!out)
  420.             return 0;
  421.  
  422.         z_stream strm;
  423.         strm.zalloc = Z_NULL;
  424.         strm.zfree = Z_NULL;
  425.         strm.opaque = Z_NULL;
  426.         strm.avail_in = snapsize - DataOffset;
  427.         strm.next_in = snbuf + DataOffset;
  428.         int ret = inflateInit__p(&strm, ZLIB_VERSION, sizeof(strm));
  429.         if(ret != Z_OK)
  430.         {
  431.             free(out);
  432.             return 0;
  433.         }
  434.  
  435.         strm.avail_out = out_sz;
  436.         strm.next_out = (Byte *)out;
  437.         ret = inflate_p(&strm, Z_FINISH);
  438.         if(ret < 0)
  439.         {
  440.             free(out);
  441.             inflateEnd_p(&strm);
  442.             return 0;
  443.         }
  444.         UncompressedSize = out_sz - strm.avail_out;
  445.         memcpy(snbuf + DataOffset, out, UncompressedSize);
  446.         UncompressedSize += DataOffset;
  447.         free(out);
  448.         inflateEnd_p(&strm);
  449.     }
  450.     case 1: // RLE
  451.         break;
  452.  
  453.     default:
  454.         return 0; // unknown compression type
  455.     }
  456.  
  457.     unsigned rate = Z80FQ / SampleRate; // usually 3.5mhz / 44khz
  458.     if(!rate)
  459.         return 0;
  460.  
  461.     if(!(Flags & 1))
  462.     {
  463.         PulsesCount++;
  464.     }
  465.     PulsesCount++; // ─юяюыэшхЄы№э√щ шэЄхЁтры (ярєчр) т ъюэЎх CSW
  466.  
  467.     reserve(PulsesCount);
  468.  
  469.     if(!(Flags & 1))
  470.         tape_image[tape_imagesize++] = find_pulse(1);
  471.  
  472.     unsigned i = 0;
  473.     for(unsigned char *ptr = snbuf + DataOffset; ptr < snbuf + UncompressedSize; i++)
  474.     {
  475.         unsigned len = *ptr++ * rate;
  476.         if(!len)
  477.         {
  478.             len = *(unsigned*)ptr * rate;
  479.             ptr += 4;
  480.         }
  481.         tape_image[tape_imagesize++] = find_pulse(len);
  482.     }
  483.  
  484.     tape_image[tape_imagesize++] = find_pulse(Z80FQ / 10);
  485.     find_tape_sizes();
  486.     return 1;
  487. }
  488.  
  489. static void create_appendable_block()
  490. {
  491.     if(!tape_infosize || appendable)
  492.     {
  493.         return;
  494.     }
  495.     named_cell("set of pulses");
  496.     appendable = 1;
  497. }
  498.  
  499. static void parse_hardware(const unsigned char *ptr)
  500. {
  501.     unsigned n = *ptr++;
  502.     if(!n)
  503.     {
  504.         return;
  505.     }
  506.     named_cell("- HARDWARE TYPE ");
  507.     static char ids[] =
  508.         "computer\0"
  509.         "ZX Spectrum 16k\0"
  510.         "ZX Spectrum 48k, Plus\0"
  511.         "ZX Spectrum 48k ISSUE 1\0"
  512.         "ZX Spectrum 128k (Sinclair)\0"
  513.         "ZX Spectrum 128k +2 (Grey case)\0"
  514.         "ZX Spectrum 128k +2A, +3\0"
  515.         "Timex Sinclair TC-2048\0"
  516.         "Timex Sinclair TS-2068\0"
  517.         "Pentagon 128\0"
  518.         "Sam Coupe\0"
  519.         "Didaktik M\0"
  520.         "Didaktik Gama\0"
  521.         "ZX-81 or TS-1000 with  1k RAM\0"
  522.         "ZX-81 or TS-1000 with 16k RAM or more\0"
  523.         "ZX Spectrum 128k, Spanish version\0"
  524.         "ZX Spectrum, Arabic version\0"
  525.         "TK 90-X\0"
  526.         "TK 95\0"
  527.         "Byte\0"
  528.         "Elwro\0"
  529.         "ZS Scorpion\0"
  530.         "Amstrad CPC 464\0"
  531.         "Amstrad CPC 664\0"
  532.         "Amstrad CPC 6128\0"
  533.         "Amstrad CPC 464+\0"
  534.         "Amstrad CPC 6128+\0"
  535.         "Jupiter ACE\0"
  536.         "Enterprise\0"
  537.         "Commodore 64\0"
  538.         "Commodore 128\0"
  539.         "\0"
  540.         "ext. storage\0"
  541.         "Microdrive\0"
  542.         "Opus Discovery\0"
  543.         "Disciple\0"
  544.         "Plus-D\0"
  545.         "Rotronics Wafadrive\0"
  546.         "TR-DOS (BetaDisk)\0"
  547.         "Byte Drive\0"
  548.         "Watsford\0"
  549.         "FIZ\0"
  550.         "Radofin\0"
  551.         "Didaktik disk drives\0"
  552.         "BS-DOS (MB-02)\0"
  553.         "ZX Spectrum +3 disk drive\0"
  554.         "JLO (Oliger) disk interface\0"
  555.         "FDD3000\0"
  556.         "Zebra disk drive\0"
  557.         "Ramex Millenia\0"
  558.         "Larken\0"
  559.         "\0"
  560.         "ROM/RAM type add-on\0"
  561.         "Sam Ram\0"
  562.         "Multiface\0"
  563.         "Multiface 128k\0"
  564.         "Multiface +3\0"
  565.         "MultiPrint\0"
  566.         "MB-02 ROM/RAM expansion\0"
  567.         "\0"
  568.         "sound device\0"
  569.         "Classic AY hardware\0"
  570.         "Fuller Box AY sound hardware\0"
  571.         "Currah microSpeech\0"
  572.         "SpecDrum\0"
  573.         "AY ACB stereo; Melodik\0"
  574.         "AY ABC stereo\0"
  575.         "\0"
  576.         "joystick\0"
  577.         "Kempston\0"
  578.         "Cursor, Protek, AGF\0"
  579.         "Sinclair 2\0"
  580.         "Sinclair 1\0"
  581.         "Fuller\0"
  582.         "\0"
  583.         "mice\0"
  584.         "AMX mouse\0"
  585.         "Kempston mouse\0"
  586.         "\0"
  587.         "other controller\0"
  588.         "Trickstick\0"
  589.         "ZX Light Gun\0"
  590.         "Zebra Graphics Tablet\0"
  591.         "\0"
  592.         "serial port\0"
  593.         "ZX Interface 1\0"
  594.         "ZX Spectrum 128k\0"
  595.         "\0"
  596.         "parallel port\0"
  597.         "Kempston S\0"
  598.         "Kempston E\0"
  599.         "ZX Spectrum 128k +2A, +3\0"
  600.         "Tasman\0"
  601.         "DK'Tronics\0"
  602.         "Hilderbay\0"
  603.         "INES Printerface\0"
  604.         "ZX LPrint Interface 3\0"
  605.         "MultiPrint\0"
  606.         "Opus Discovery\0"
  607.         "Standard 8255 chip with ports 31,63,95\0"
  608.         "\0"
  609.         "printer\0"
  610.         "ZX Printer, Alphacom 32 & compatibles\0"
  611.         "Generic Printer\0"
  612.         "EPSON Compatible\0"
  613.         "\0"
  614.         "modem\0"
  615.         "VTX 5000\0"
  616.         "T/S 2050 or Westridge 2050\0"
  617.         "\0"
  618.         "digitaiser\0"
  619.         "RD Digital Tracer\0"
  620.         "DK'Tronics Light Pen\0"
  621.         "British MicroGraph Pad\0"
  622.         "\0"
  623.         "network adapter\0"
  624.         "ZX Interface 1\0"
  625.         "\0"
  626.         "keyboard / keypad\0"
  627.         "Keypad for ZX Spectrum 128k\0"
  628.         "\0"
  629.         "AD/DA converter\0"
  630.         "Harley Systems ADC 8.2\0"
  631.         "Blackboard Electronics\0"
  632.         "\0"
  633.         "EPROM Programmer\0"
  634.         "Orme Electronics\0"
  635.         "\0"
  636.         "\0";
  637.     for(unsigned i = 0; i < n; i++)
  638.     {
  639.         unsigned char type_n = *ptr++;
  640.         unsigned char id_n = *ptr++;
  641.         unsigned char value_n = *ptr++;
  642.         const char *type = ids, *id, *value;
  643.         unsigned j; //Alone Coder 0.36.7
  644.         for(/*unsigned*/ j = 0; j < type_n; j++)
  645.         {
  646.             if(!*type)
  647.             {
  648.                 break;
  649.             }
  650.             while(*(const short*)type)
  651.             {
  652.                 type++;
  653.             }
  654.             type += 2;
  655.         }
  656.         if(!*type)
  657.         {
  658.             type = id = "??";
  659.         }
  660.         else
  661.         {
  662.             id = type + strlen(type) + 1;
  663.             for(j = 0; j < id_n; j++)
  664.             {
  665.                 if(!*id)
  666.                 {
  667.                     id = "??";
  668.                     break;
  669.                 }
  670.                 id += strlen(id) + 1;
  671.             }
  672.         }
  673.         switch(value_n)
  674.         {
  675.         case 0: value = "compatible with"; break;
  676.         case 1: value = "uses"; break;
  677.         case 2: value = "compatible, but doesn't use"; break;
  678.         case 3: value = "incompatible with"; break;
  679.         default: value = "??";
  680.         }
  681.         char bf[512];
  682.         sprintf(bf, "%s %s: %s", value, type, id);
  683.         named_cell(bf);
  684.     }
  685.     named_cell("-");
  686. }
  687.  
  688. static inline bool IsPowerOfTwo(unsigned x)
  689. {
  690.     // x will check if x == 0 and !(x & (x - 1)) will check if x is a power of 2 or not
  691.     return x != 0 && (x & (x - 1)) == 0;
  692. }
  693.  
  694. int readTZX()
  695. {
  696.     unsigned char *ptr = snbuf;
  697.     closetape();
  698.     u32 pause;
  699.     unsigned t0;
  700.     unsigned char pl, last;
  701.     unsigned char *end;
  702.     char *p;
  703.     unsigned loop_n = 0, loop_p = 0;
  704.     unsigned TzxVer = (unsigned(ptr[8]) << 8U) | unsigned(ptr[9]);
  705.     char nm[512];
  706.  
  707.     ptr += 10; // ╧Ёюяєёъ чруюыютър
  708.  
  709.     while(ptr < snbuf + snapsize)
  710.     {
  711.         unsigned BlkId = *ptr++;
  712.         switch(BlkId)
  713.         {
  714.         case 0x10: // normal block
  715.         {
  716.             alloc_infocell();
  717.             unsigned size = *(unsigned short*)(ptr + 2);
  718.             pause = *(unsigned short*)ptr;
  719.             ptr += 4;
  720.             desc(ptr, size, tapeinfo[tape_infosize].desc);
  721.             tape_infosize++;
  722.             makeblock(ptr, size, 2168U, 667U, 735U, 855U, 1710U,
  723.                 (*ptr < 4) ? 8064U : 3220U, pause);
  724.             ptr += size;
  725.         }
  726.             break;
  727.         case 0x11: // turbo block
  728.         {
  729.             alloc_infocell();
  730.             unsigned size = 0xFFFFFF & *(unsigned*)(ptr + 0x0F);
  731.             desc(ptr + 0x12, size, tapeinfo[tape_infosize].desc);
  732.             tape_infosize++;
  733.             makeblock(ptr + 0x12, size,
  734.                 *(unsigned short*)ptr, *(unsigned short*)(ptr + 2),
  735.                 *(unsigned short*)(ptr + 4), *(unsigned short*)(ptr + 6),
  736.                 *(unsigned short*)(ptr + 8), *(unsigned short*)(ptr + 10),
  737.                 *(unsigned short*)(ptr + 13), ptr[12]);
  738.             // todo: test used bits - ptr+12
  739.             ptr += size + 0x12;
  740.         }
  741.             break;
  742.         case 0x12: // pure tone
  743.         {
  744.             create_appendable_block();
  745.             pl = u8(find_pulse(*(unsigned short*)ptr));
  746.             unsigned n = *(unsigned short*)(ptr + 2);
  747.             reserve(n);
  748.             for(unsigned i = 0; i < n; i++)
  749.             {
  750.                 tape_image[tape_imagesize++] = pl;
  751.             }
  752.             ptr += 4;
  753.         }
  754.             break;
  755.         case 0x13: // sequence of pulses of different lengths
  756.         {
  757.             create_appendable_block();
  758.             unsigned n = *ptr++;
  759.             reserve(n);
  760.             for(unsigned i = 0; i < n; i++, ptr += 2)
  761.             {
  762.                 tape_image[tape_imagesize++] = find_pulse(*(unsigned short*)ptr);
  763.             }
  764.         }
  765.             break;
  766.         case 0x14: // pure data block
  767.         {
  768.             create_appendable_block();
  769.             unsigned size = 0xFFFFFF & *(unsigned*)(ptr + 7);
  770.             makeblock(ptr + 0x0A, size, 0, 0, 0, *(unsigned short*)ptr,
  771.                 *(unsigned short*)(ptr + 2), -1U, *(unsigned short*)(ptr + 5), ptr[4]);
  772.             ptr += size + 0x0A;
  773.         }
  774.             break;
  775.         case 0x15: // direct recording
  776.         {
  777.             unsigned size = 0xFFFFFF & *(unsigned*)(ptr + 5);
  778.             t0 = *(unsigned short*)ptr;
  779.             pause = *(unsigned short*)(ptr + 2);
  780.             last = ptr[4];
  781.             named_cell("direct recording");
  782.             ptr += 8;
  783.             pl = 0;
  784.             unsigned n = 0;
  785.             for(unsigned i = 0; i < size; i++) // count number of pulses
  786.             {
  787.                 for(unsigned j = 0x80; j; j >>= 1)
  788.                 {
  789.                     if((ptr[i] ^ pl) & j)
  790.                     {
  791.                         n++;
  792.                         pl ^= -1;
  793.                     }
  794.                 }
  795.             }
  796.             unsigned t = 0;
  797.             pl = 0;
  798.             reserve(n + 2);
  799.             for(unsigned i = 1; i < size; i++, ptr++) // find pulses
  800.             {
  801.                 for(unsigned j = 0x80; j; j >>= 1)
  802.                 {
  803.                     t += t0;
  804.                     if((*ptr ^ pl) & j)
  805.                     {
  806.                         tape_image[tape_imagesize++] = find_pulse(t);
  807.                         pl ^= -1; t = 0;
  808.                     }
  809.                 }
  810.             }
  811.             // find pulses - last byte
  812.             for(unsigned j = 0x80; j != (unsigned char)(0x80 >> last); j >>= 1)
  813.             {
  814.                 t += t0;
  815.                 if((*ptr ^ pl) & j)
  816.                 {
  817.                     tape_image[tape_imagesize++] = find_pulse(t);
  818.                     pl ^= -1; t = 0;
  819.                 }
  820.             }
  821.             ptr++;
  822.             tape_image[tape_imagesize++] = find_pulse(t); // last pulse ???
  823.             if(pause)
  824.             {
  825.                 tape_image[tape_imagesize++] = find_pulse(pause*(Z80FQ / 1000));
  826.             }
  827.         }
  828.             break;
  829.  
  830.         case 0x19: // generalized data block
  831.         {
  832. #pragma pack(push, 1)
  833.             struct TTzxBlk19
  834.             {
  835.                 u32 Size;
  836.                 u16 Pause; // Pause after this block(ms)
  837.                 u32 Totp; // Total number of symbols in pilot/sync block (can be 0)
  838.                 u8 Npp; // Maximum number of pulses per pilot/sync symbol
  839.                 u8 Asp; // Number of pilot/sync symbols in the alphabet table (0=256)
  840.                 u32 Totd; // Total number of symbols in data stream(can be 0)
  841.                 u8 Npd; // Maximum number of pulses per data symbol
  842.                 u8 Asd; // Number of data symbols in the alphabet table (0=256)
  843.             };
  844.             struct TSymDef
  845.             {
  846.                 u8 Flags;
  847.                 u16 PulseLen[]; // Array of pulse lengths (Npp / Npd)
  848.             };
  849.             struct TPrle
  850.             {
  851.                 u8 Symbol; // Symbol to be represented
  852.                 u16 RepCnt; // Number of repetitions
  853.             };
  854. #pragma pack(pop)
  855.             auto Blk = (const TTzxBlk19 *)ptr;
  856.             const unsigned Asp = Blk->Asp == 0 ? 256U : Blk->Asp;
  857.             const unsigned Asd = Blk->Asd == 0 ? 256U : Blk->Asd;
  858.  
  859.             named_cell("generalized data block");
  860.             auto Pause = Blk->Pause;
  861.  
  862.             auto SymDefp = (const TSymDef *)(Blk + 1); // └ыЇртшЄ яшыюЄ Єюэр
  863.             const auto SympSize = sizeof(TSymDef) + Blk->Npp * sizeof(*SymDefp->PulseLen); // ╨рчьхЁ ёшьтюыр т рыЇртшЄх яшыюЄ Єюэр
  864.             auto Prle = (const TPrle *)(((const u8 *)SymDefp) + Asp * SympSize); // ╤шьтюы√ яшыюЄ Єюэр
  865.  
  866.             unsigned n = 0;
  867.  
  868.             // ╧юфёўхЄ ўшёыр шьяєы№ёют т яшыюЄ Єюэх
  869.             for(unsigned i = 0; i < Blk->Totp; i++)
  870.             {
  871.                 auto Sym = Prle[i].Symbol; // ╤шьтюы рыЇртшЄр
  872.                 assert(Sym < Asp);
  873.  
  874.                 auto RepCnt = Prle[i].RepCnt; // ╫шёыю яютЄюЁют ёшьтюыр
  875.                 auto Symp = (const TSymDef *)(((const u8 *)SymDefp) + Sym * SympSize); // ╬яшёрэшх ёшьтюыр т рыЇртшЄх
  876.  
  877.                 unsigned PulseCnt = 0; // ╫шёыю шьяєы№ёют т юфэюь ёшьтюых рыЇртшЄр
  878.                 for(unsigned j = 0; j < Blk->Npp && Symp->PulseLen[j] != 0; j++)
  879.                 {
  880.                     PulseCnt++;
  881.                 }
  882.                 n += PulseCnt * RepCnt;
  883.             }
  884.  
  885.             auto Np = n;
  886.  
  887.             auto SymDefd = (const TSymDef *)(Prle + Blk->Totp); // └ыЇртшЄ фрээ√ї
  888.             const auto SymdSize = sizeof(TSymDef) + Blk->Npd * sizeof(*SymDefd->PulseLen); // ╨рчьхЁ ёшьтюыр т рыЇртшЄх фрээ√ї
  889.             auto Data = (const u8 *)(((const u8 *)SymDefd) + Asd * SymdSize); // ─рээ√х
  890.  
  891.             const auto Nb = unsigned(ceil(log2(float(Asd))));
  892.             assert(IsPowerOfTwo(Nb)); // ╧юффхЁцър Єюы№ъю ъюфшЁютрэш  ёю ёЄхяхэ№■ фтющъш (1,2,4,8 сшЄ эр ёшьтюы)
  893.  
  894.             unsigned BitMask = (1U << Nb) - 1U;
  895.  
  896.             const auto Ds = unsigned(ceil(Nb * Blk->Totd / 8));
  897.  
  898.             // ╧юфёўхЄ ўшёыр шьяєы№ёют т фрээ√ї
  899.             for(unsigned i = 0; i < Ds; i++)
  900.             {
  901.                 auto Bits = Data[i];
  902.                 unsigned PulseCnt = 0; // ╫шёыю шьяєы№ёют т юфэюь ёшьтюых рыЇртшЄр
  903.  
  904.                 // ╧хЁхъюшЁютрэшх сшЄют т ёшьтюы√
  905.                 for(unsigned k = 0; k <= 8 - Nb; k++)
  906.                 {
  907.                     Bits = rol8(Bits, u8(Nb));
  908.                     auto Sym = unsigned(Bits & BitMask); // ╤шьтюы рыЇртшЄр
  909.                     assert(Sym < Asd);
  910.  
  911.                     auto Symd = (const TSymDef *)(((const u8 *)SymDefd) + Sym * SymdSize); // ╬яшёрэшх ёшьтюыр т рыЇртшЄх
  912.  
  913.                     for(unsigned j = 0; j < Blk->Npd && Symd->PulseLen[j] != 0; j++)
  914.                     {
  915.                         PulseCnt++;
  916.                     }
  917.                 }
  918.                 n += PulseCnt;
  919.             }
  920.  
  921.             if(Pause != 0)
  922.             {
  923.                 n++;
  924.             }
  925.  
  926.             reserve(n); // ┬√фхыхэшх ярь Єш яюф n шьяєы№ёют
  927.  
  928.             const auto MaxTapeImageSize = tape_imagesize + n;
  929.  
  930.             auto Npp = 0U;
  931.             // ├хэхЁрЎш  шьяєы№ёют яшыюЄ Єюэр
  932.             for(unsigned i = 0; i < Blk->Totp; i++)
  933.             {
  934.                 auto Sym = Prle[i].Symbol; // ╤шьтюы рыЇртшЄр
  935.                 assert(Sym < Asp);
  936.  
  937.                 auto RepCnt = Prle[i].RepCnt; // ╫шёыю яютЄюЁют ёшьтюыр
  938.                 auto Symp = (const TSymDef *)(((const u8 *)SymDefp) + Sym * SympSize); // ╬яшёрэшх ёшьтюыр т рыЇртшЄх
  939.  
  940.                 unsigned Flags = Symp->Flags & 3U;
  941.                 for(unsigned j = 0; j < Blk->Npp && Symp->PulseLen[j] != 0; j++)
  942.                 {
  943.                     auto t = Symp->PulseLen[j];
  944.                     for(unsigned k = 0; k < RepCnt; k++)
  945.                     {
  946.                         tape_image[tape_imagesize++] = find_pulse(t, Flags);
  947.                         Flags = 0;
  948.                         assert(tape_imagesize <= MaxTapeImageSize);
  949.                         Npp++;
  950.                     }
  951.                 }
  952.             }
  953.  
  954.             assert(Npp == Np);
  955.  
  956.             // ├хэхЁрЎш  шьяєы№ёют фрээ√ї
  957.             for(unsigned i = 0; i < Ds; i++)
  958.             {
  959.                 auto Bits = Data[i];
  960.  
  961.                 // ╧хЁхъюшЁютрэшх сшЄют т ёшьтюы√
  962.                 for(unsigned k = 0; k <= 8 - Nb; k++)
  963.                 {
  964.                     Bits = rol8(Bits, u8(Nb));
  965.                     auto Sym = unsigned(Bits & BitMask); // ╤шьтюы рыЇртшЄр
  966.                     assert(Sym < Asd);
  967.  
  968.                     auto Symd = (const TSymDef *)(((const u8 *)SymDefd) + Sym * SymdSize); // ╬яшёрэшх ёшьтюыр т рыЇртшЄх
  969.  
  970.                     unsigned Flags = Symd->Flags & 3U;
  971.                     for(unsigned j = 0; j < Blk->Npd && Symd->PulseLen[j] != 0; j++)
  972.                     {
  973.                         auto t = Symd->PulseLen[j];
  974.                         tape_image[tape_imagesize++] = find_pulse(t, Flags);
  975.                         Flags = 0;
  976.                         assert(tape_imagesize <= MaxTapeImageSize);
  977.                     }
  978.                 }
  979.             }
  980.  
  981.             if(Pause != 0)
  982.             {
  983.                 tape_image[tape_imagesize++] = find_pulse(Pause * (Z80FQ / 1000U));
  984.                 assert(tape_imagesize <= MaxTapeImageSize);
  985.             }
  986.  
  987.             ptr += Blk->Size + sizeof(Blk->Size);
  988.         }
  989.         break;
  990.  
  991.         case 0x20: // pause (silence) or 'stop the tape' command
  992.             pause = *(unsigned short*)ptr;
  993.             if(pause != 0)
  994.             {
  995.                 sprintf(nm, "pause %u ms", unsigned(pause));
  996.             }
  997.             else
  998.             {
  999.                 sprintf(nm, "stop the tape");
  1000.             }
  1001.             named_cell(nm);
  1002.             reserve(2); ptr += 2;
  1003.             if(!pause)
  1004.             { // at least 1ms pulse as specified in TZX 1.13
  1005.                 tape_image[tape_imagesize++] = find_pulse(Z80FQ / 1000);
  1006.                 pause = UINT32_MAX;
  1007.             }
  1008.             else
  1009.             {
  1010.                 pause *= Z80FQ / 1000;
  1011.             }
  1012.             tape_image[tape_imagesize++] = find_pulse(pause);
  1013.             break;
  1014.         case 0x21: // group start
  1015.         {
  1016.             unsigned n = *ptr++;
  1017.             named_cell(ptr, n); ptr += n;
  1018.             appendable = 1;
  1019.         }
  1020.             break;
  1021.         case 0x22: // group end
  1022.             break;
  1023.         case 0x23: // jump to block
  1024.             named_cell("* jump"); ptr += 2;
  1025.             break;
  1026.         case 0x24: // loop start
  1027.             loop_n = *(unsigned short*)ptr; loop_p = tape_imagesize; ptr += 2;
  1028.             break;
  1029.         case 0x25: // loop end
  1030.         {
  1031.             if(!loop_n)
  1032.             {
  1033.                 break;
  1034.             }
  1035.             unsigned size = tape_imagesize - loop_p;
  1036.             reserve((loop_n - 1) * size);
  1037.             for(unsigned i = 1; i < loop_n; i++)
  1038.             {
  1039.                 memcpy(tape_image + loop_p + i * size, tape_image + loop_p, size);
  1040.             }
  1041.             tape_imagesize += (loop_n - 1) * size;
  1042.             loop_n = 0;
  1043.         }
  1044.             break;
  1045.         case 0x26: // call
  1046.             named_cell("* call"); ptr += 2 + 2 * *(unsigned short*)ptr;
  1047.             break;
  1048.         case 0x27: // ret
  1049.             named_cell("* return");
  1050.             break;
  1051.         case 0x28: // select block
  1052.         {
  1053.             int l = _countof(nm);
  1054.             l -= sprintf(nm, "* choice: ");
  1055.             unsigned n = ptr[2];
  1056.             p = (char*)ptr + 3;
  1057.  
  1058.             for(unsigned i = 0; i < n; i++)
  1059.             {
  1060.                 unsigned size = *(unsigned char*)(p + 2);
  1061.                 l -= size;
  1062.                 if(i)
  1063.                 {
  1064.                     l -= 4;
  1065.                 }
  1066.  
  1067.                 if(l >= 0)
  1068.                 {
  1069.                     if(i)
  1070.                     {
  1071.                         strcat(nm, " / ");
  1072.                     }
  1073.  
  1074.                     char *q = nm + strlen(nm);
  1075.                     memcpy(q, p + 3, size);
  1076.                     q[size] = 0;
  1077.                 }
  1078.  
  1079.                 p += size + 3;
  1080.             }
  1081.             named_cell(nm);
  1082.             ptr += 2 + *(unsigned short*)ptr;
  1083.         }
  1084.         break;
  1085.         case 0x2A: // stop if 48k
  1086.             named_cell("* stop if 48K");
  1087.             ptr += 4 + *(unsigned*)ptr;
  1088.             break;
  1089.         case 0x30: // text description
  1090.         {
  1091.             unsigned n = *ptr++;
  1092.             named_cell(ptr, n); ptr += n;
  1093.             appendable = 1;
  1094.         }
  1095.             break;
  1096.         case 0x31: // message block
  1097.             named_cell("- MESSAGE BLOCK ");
  1098.             end = ptr + 2 + ptr[1]; pl = *end; *end = 0;
  1099.             for(p = (char*)ptr + 2; p < (const char*)end; p++)
  1100.             {
  1101.                 if(*p == 0x0D)
  1102.                 {
  1103.                     *p = 0;
  1104.                 }
  1105.             }
  1106.             for(p = (char*)ptr + 2; p < (const char*)end; p += strlen(p) + 1)
  1107.             {
  1108.                 named_cell(p);
  1109.             }
  1110.             *end = pl; ptr = end;
  1111.             named_cell("-");
  1112.             break;
  1113.         case 0x32: // archive info
  1114.             named_cell("- ARCHIVE INFO ");
  1115.             p = (char*)ptr + 3;
  1116.             for(unsigned i = 0; i < ptr[2]; i++)
  1117.             {
  1118.                 const char *info;
  1119.                 switch(*p++)
  1120.                 {
  1121.                 case 0: info = "Title"; break;
  1122.                 case 1: info = "Publisher"; break;
  1123.                 case 2: info = "Author"; break;
  1124.                 case 3: info = "Year"; break;
  1125.                 case 4: info = "Language"; break;
  1126.                 case 5: info = "Type"; break;
  1127.                 case 6: info = "Price"; break;
  1128.                 case 7: info = "Protection"; break;
  1129.                 case 8: info = "Origin"; break;
  1130.                 case -1:info = "Comment"; break;
  1131.                 default:info = "info"; break;
  1132.                 }
  1133.                 unsigned size = *(BYTE*)p + 1U;
  1134.                 char tmp = p[size]; p[size] = 0;
  1135.                 sprintf(nm, "%s: %s", info, p + 1);
  1136.                 p[size] = tmp; p += size;
  1137.                 named_cell(nm);
  1138.             }
  1139.             named_cell("-");
  1140.             ptr += 2 + *(unsigned short*)ptr;
  1141.             break;
  1142.         case 0x33: // hardware type
  1143.             parse_hardware(ptr);
  1144.             ptr += 1 + 3 * *ptr;
  1145.             break;
  1146.         case 0x34: // emulation info
  1147.             named_cell("* emulation info"); ptr += 8;
  1148.             break;
  1149.         case 0x35: // custom info
  1150.             if(!memcmp(ptr, "POKEs           ", 16))
  1151.             {
  1152.                 named_cell("- POKEs block ");
  1153.                 named_cell(ptr + 0x15, ptr[0x14]);
  1154.                 p = (char*)ptr + 0x15 + ptr[0x14];
  1155.                 unsigned n = *(unsigned char*)p++;
  1156.                 for(unsigned i = 0; i < n; i++)
  1157.                 {
  1158.                     named_cell(p + 1, *(unsigned char*)p);
  1159.                     p += *p + 1;
  1160.                     unsigned t = *(unsigned char*)p++;
  1161.                     strcpy(nm, "POKE ");
  1162.                     for(unsigned j = 0; j < t; j++)
  1163.                     {
  1164.                         sprintf(nm + strlen(nm), "%d,", *(unsigned short*)(p + 1));
  1165.                         if(*p & 0x10)
  1166.                         {
  1167.                             sprintf(nm + strlen(nm), "nn");
  1168.                         }
  1169.                         else
  1170.                         {
  1171.                             sprintf(nm + strlen(nm), "%d", *(unsigned char*)(p + 3));
  1172.                         }
  1173.                         if(!(*p & 0x08))
  1174.                         {
  1175.                             sprintf(nm + strlen(nm), "(page %d)", *p & 7);
  1176.                         }
  1177.                         strcat(nm, "; "); p += 5;
  1178.                     }
  1179.                     named_cell(nm);
  1180.                 }
  1181.                 *(unsigned*)nm = '-';
  1182.             }
  1183.             else
  1184.             {
  1185.                 sprintf(nm, "* custom info: %s", ptr);
  1186.                 nm[15 + 16] = 0;
  1187.             }
  1188.             named_cell(nm);
  1189.             ptr += 0x14 + *(unsigned*)(ptr + 0x10);
  1190.             break;
  1191.         case 0x40: // snapshot
  1192.             named_cell("* snapshot"); ptr += 4 + (0xFFFFFF & *(unsigned*)(ptr + 1));
  1193.             break;
  1194.         default:
  1195.             if(TzxVer >= 0x10A)
  1196.             {
  1197.                 // ┬ эрўрых ърцфюую эхёЄрэфрЁЄэюую сыюър шфхЄ хую фышэр
  1198.                 sprintf(nm, "* unknown id: 0x%X", ptr[-1]);
  1199.                 named_cell(nm);
  1200.                 u32 Skip = *(u32 *)ptr;
  1201.                 ptr += Skip + sizeof(u32);
  1202.             }
  1203.             else
  1204.             {
  1205.                 ptr += snapsize;
  1206.             }
  1207.         }
  1208.     }
  1209.     for(unsigned i = 0; i < tape_infosize; i++)
  1210.     {
  1211.         if(*(short*)tapeinfo[i].desc == WORD2('*', ' '))
  1212.         {
  1213.             if(strlen(tapeinfo[i].desc) < _countof(tapeinfo[i].desc) - sizeof(" [UNSUPPORTED]"))
  1214.             {
  1215.                 strcat(tapeinfo[i].desc, " [UNSUPPORTED]");
  1216.             }
  1217.             else
  1218.             {
  1219.                 strcpy(tapeinfo[i].desc + _countof(tapeinfo[i].desc) - sizeof(" [UNSUPPORTED]"), " [UNSUPPORTED]");
  1220.             }
  1221.         }
  1222.         if(*tapeinfo[i].desc == '-')
  1223.         {
  1224.             while(strlen(tapeinfo[i].desc) < sizeof(tapeinfo[i].desc) - 1)
  1225.             {
  1226.                 strcat(tapeinfo[i].desc, "-");
  1227.             }
  1228.         }
  1229.     }
  1230.     if(tape_imagesize && tape_pulse[tape_image[tape_imagesize - 1]] < Z80FQ / 10)
  1231.     {
  1232.         // small pause [rqd for 3ddeathchase]
  1233.         reserve(1);
  1234.         tape_image[tape_imagesize++] = find_pulse(Z80FQ / 10);
  1235.     }
  1236.     find_tape_sizes();
  1237.     return ptr == snbuf + snapsize;
  1238. }
  1239.  
  1240. unsigned char tape_bit() // used in io.cpp & sound.cpp
  1241. {
  1242.     __int64 cur = comp.t_states + cpu.t;
  1243.     if(cur < comp.tape.edge_change)
  1244.     {
  1245.         return (unsigned char)comp.tape.tape_bit;
  1246.     }
  1247.     while(comp.tape.edge_change < cur)
  1248.     {
  1249.         if(!temp.sndblock)
  1250.         {
  1251.             unsigned t = (unsigned)(comp.tape.edge_change - comp.t_states - temp.cpu_t_at_frame_start);
  1252.             if((int)t >= 0)
  1253.             {
  1254.                 unsigned tape_in = unsigned(conf.sound.micin_vol) & comp.tape.tape_bit;
  1255.                 comp.tape.sound.update(t, tape_in, tape_in);
  1256.             }
  1257.         }
  1258.         unsigned pulse;
  1259.         if(comp.tape.play_pointer == comp.tape.end_of_tape ||
  1260.             (pulse = tape_pulse[*comp.tape.play_pointer++]) == UINT32_MAX)
  1261.         {
  1262.             stop_tape();
  1263.         }
  1264.         else
  1265.         {
  1266.             unsigned Flags = (pulse >> 30) & 3;
  1267.             switch(Flags)
  1268.             {
  1269.             case 0: comp.tape.tape_bit ^= -1U; break; // opposite to the current level(make an edge, as usual) - default
  1270.             case 1: break; // same as the current level(no edge - prolongs the previous pulse)
  1271.             case 2: comp.tape.tape_bit = 0; break; // force low level
  1272.             case 3: comp.tape.tape_bit |= -1U; break; // force high level
  1273.             }
  1274.             comp.tape.edge_change += pulse & tape_pulse_mask;
  1275.         }
  1276.     }
  1277.     return (unsigned char)comp.tape.tape_bit;
  1278. }
  1279.  
  1280. void fast_tape()
  1281. {
  1282.     unsigned char *ptr = am_r(cpu.pc);
  1283.     unsigned p = *(unsigned*)ptr;
  1284.     if(p == WORD4(0x3D, 0x20, 0xFD, 0xA7))
  1285.     { // dec a:jr nz,$-1
  1286.         cpu.t += ((unsigned char)(cpu.a - 1)) * 16; cpu.a = 1;
  1287.         return;
  1288.     }
  1289.     if((unsigned short)p == WORD2(0x10, 0xFE))
  1290.     { // djnz $
  1291.         cpu.t += ((unsigned char)(cpu.b - 1)) * 13; cpu.b = 1;
  1292.         return;
  1293.     }
  1294.     if((unsigned short)p == WORD2(0x3D, 0xC2) && (cpu.pc & 0xFFFF) == (p >> 16))
  1295.     { // dec a:jp nz,$-1
  1296.         cpu.t += ((unsigned char)(cpu.a - 1)) * 14; cpu.a = 1;
  1297.         return;
  1298.     }
  1299.     if((p | WORD4(0, 0, 0, 0xFF)) == WORD4(0x04, 0xC8, 0x3E, 0xFF))
  1300.     {
  1301.         if(*(unsigned*)(ptr + 4) == WORD4(0xDB, 0xFE, 0x1F, 0xD0) &&
  1302.             *(unsigned*)(ptr + 8) == WORD4(0xA9, 0xE6, 0x20, 0x28) && ptr[12] == 0xF3)
  1303.         { // find edge (rom routine)
  1304.             for(;;)
  1305.             {
  1306.                 if(cpu.b == 0xFF)
  1307.                 {
  1308.                     return;
  1309.                 }
  1310.                 if((tape_bit() ? 0x20 : 0) ^ (cpu.c & 0x20))
  1311.                 {
  1312.                     return;
  1313.                 }
  1314.                 cpu.b++; cpu.t += 59;
  1315.             }
  1316.         }
  1317.         if(*(unsigned*)(ptr + 4) == WORD4(0xDB, 0xFE, 0xCB, 0x1F) &&
  1318.             *(unsigned*)(ptr + 8) == WORD4(0xA9, 0xE6, 0x20, 0x28) && ptr[12] == 0xF3)
  1319.         { // rra,ret nc => rr a (popeye2)
  1320.             for(;;)
  1321.             {
  1322.                 if(cpu.b == 0xFF)
  1323.                 {
  1324.                     return;
  1325.                 }
  1326.                 if((tape_bit() ^ cpu.c) & 0x20)
  1327.                 {
  1328.                     return;
  1329.                 }
  1330.                 cpu.b++; cpu.t += 58;
  1331.             }
  1332.         }
  1333.         if(*(unsigned*)(ptr + 4) == WORD4(0xDB, 0xFE, 0x1F, 0x00) &&
  1334.             *(unsigned*)(ptr + 8) == WORD4(0xA9, 0xE6, 0x20, 0x28) && ptr[12] == 0xF3)
  1335.         { // ret nc nopped (some bleep loaders)
  1336.             for(;;)
  1337.             {
  1338.                 if(cpu.b == 0xFF)
  1339.                 {
  1340.                     return;
  1341.                 }
  1342.                 if((tape_bit() ^ cpu.c) & 0x20)
  1343.                 {
  1344.                     return;
  1345.                 }
  1346.                 cpu.b++; cpu.t += 58;
  1347.             }
  1348.         }
  1349.         if(*(unsigned*)(ptr + 4) == WORD4(0xDB, 0xFE, 0xA9, 0xE6) &&
  1350.             *(unsigned*)(ptr + 8) == WORD4(0x40, 0xD8, 0x00, 0x28) && ptr[12] == 0xF3)
  1351.         { // no rra, no break check (rana rama)
  1352.             for(;;)
  1353.             {
  1354.                 if(cpu.b == 0xFF)
  1355.                 {
  1356.                     return;
  1357.                 }
  1358.                 if((tape_bit() ^ cpu.c) & 0x40)
  1359.                 {
  1360.                     return;
  1361.                 }
  1362.                 cpu.b++; cpu.t += 59;
  1363.             }
  1364.         }
  1365.         if(*(unsigned*)(ptr + 4) == WORD4(0xDB, 0xFE, 0x1F, 0xA9) &&
  1366.             *(unsigned*)(ptr + 8) == WORD4(0xE6, 0x20, 0x28, 0xF4))
  1367.         { // ret nc skipped: routine without BREAK checking (ZeroMusic & JSW)
  1368.             for(;;)
  1369.             {
  1370.                 if(cpu.b == 0xFF)
  1371.                 {
  1372.                     return;
  1373.                 }
  1374.                 if((tape_bit() ^ cpu.c) & 0x20)
  1375.                 {
  1376.                     return;
  1377.                 }
  1378.                 cpu.b++; cpu.t += 54;
  1379.             }
  1380.         }
  1381.     }
  1382.     if((p | WORD4(0, 0, 0, 0xFF)) == WORD4(0x04, 0x20, 0x03, 0xFF) &&
  1383.         ptr[6] == 0xDB && *(unsigned*)(ptr + 8) == WORD4(0x1F, 0xC8, 0xA9, 0xE6) &&
  1384.         (*(unsigned*)(ptr + 0x0C) | WORD4(0, 0, 0, 0xFF)) == WORD4(0x20, 0x28, 0xF1, 0xFF))
  1385.     { // find edge from Donkey Kong
  1386.         for(;;)
  1387.         {
  1388.             if(cpu.b == 0xFF)
  1389.             {
  1390.                 return;
  1391.             }
  1392.             if((tape_bit() ^ cpu.c) & 0x20)
  1393.             {
  1394.                 return;
  1395.             }
  1396.             cpu.b++; cpu.t += 59;
  1397.         }
  1398.     }
  1399.     if((p | WORD4(0, 0xFF, 0, 0)) == WORD4(0x3E, 0xFF, 0xDB, 0xFE) &&
  1400.         *(unsigned*)(ptr + 4) == WORD4(0xA9, 0xE6, 0x40, 0x20) &&
  1401.         (*(unsigned*)(ptr + 8) | WORD4(0xFF, 0, 0, 0)) == WORD4(0xFF, 0x05, 0x20, 0xF4))
  1402.     { // lode runner
  1403.         for(;;)
  1404.         {
  1405.             if(cpu.b == 1)
  1406.             {
  1407.                 return;
  1408.             }
  1409.             if((tape_bit() ^ cpu.c) & 0x40)
  1410.             {
  1411.                 return;
  1412.             }
  1413.             cpu.t += 52; cpu.b--;
  1414.         }
  1415.     }
  1416. }
  1417.  
  1418. // ╧хЁхїтрЄ ёЄюшЄ эр рфЁхёх 0x56B (фы  яюффхЁцъш эхёЄрэфрЁЄэ√ї чруЁєчўшъют)
  1419. void tape_traps()
  1420. {
  1421.     u32 pulse;
  1422.  
  1423.     // ┬їюф (фы  рфЁхёр 0x0556, фы  0x56B чэрўхэш  єцх шёяюЁўхэ√):
  1424.     // A - Їыруют√щ срщЄ (фюыцхэ ёютярфрЄ№ ё Їыруют√ь срщЄюь чряшёрээ√ь эр ыхэЄх)
  1425.     // IX - рфЁхё чруЁєчъш
  1426.     // DE - фышэр чруЁєцрхьюую сыюър
  1427.     // CF - 0 - verify, 1 - load
  1428.     //
  1429.     // ┬√їюф:
  1430.     // CF - 0 - ю°шсюъ эхЄ, 1 - ю°шсър чруЁєчъш
  1431.  
  1432.     /*
  1433.     LD_BYTES 0x0556 inc    d                   ; ═х ьхэ хЄ CF
  1434.                     ex     af, af'             ; A ш CF ёюїЁрэ ■Єё  т af'
  1435.                     dec    d
  1436.                     di
  1437.                     ld     a,0xF
  1438.                     out    (0xFE),a
  1439.                     ld     hl, 0x53F           ; SA_LD_RET = 0x53F
  1440.                     push   hl
  1441.                     in     a,(0xFE)
  1442.              0x0564 rra
  1443.                     and    0x20
  1444.                     or     2
  1445.              0x056A ld     c,a
  1446.     LD_BREAK 0x056B ret    nz
  1447.     */
  1448.  
  1449.     bool IsLoad = ((cpu.alt.f & CF) != 0);
  1450.     u8 Flag = cpu.alt.a;
  1451.  
  1452.     // ─ы  чруЁєчўшъют ъюЄюЁ√х эх яЁюїюф Є ўхЁхч рфЁхё 0x0564 фхырхЄё  яЁшэєфшЄхы№э√щ чряєёъ ыхэЄ√
  1453.     // ╧ЁшьхЁ Єръшї чруЁєчўшъют - чруЁєчўшъш юЄ Bill Gilbert (єёЄрэртыштр■Є эхёЄрэфрЁЄэ√х ЎтхЄр сюЁф■Ёр ш
  1454.     // фхыр■Є яхЁхїюф эр 0x056A)
  1455.     if(!comp.tape.play_pointer)
  1456.     {
  1457.         start_tape();
  1458.     }
  1459.  
  1460.     do
  1461.     {
  1462.         if(comp.tape.play_pointer >= comp.tape.end_of_tape ||
  1463.             (pulse = tape_pulse[*comp.tape.play_pointer++]) == UINT32_MAX)
  1464.         {
  1465.             stop_tape();
  1466.             return;
  1467.         }
  1468.     } while((pulse & tape_pulse_mask) > 770);
  1469.     comp.tape.play_pointer++;
  1470.  
  1471.     // loading flag byte
  1472.     cpu.l = 0;
  1473.     cpu.h = 0;
  1474.     for(unsigned bit = 0x80; bit; bit >>= 1)
  1475.     {
  1476.         if(comp.tape.play_pointer >= comp.tape.end_of_tape ||
  1477.             (pulse = tape_pulse[*comp.tape.play_pointer++]) == UINT32_MAX)
  1478.         {
  1479.             stop_tape();
  1480.             cpu.pc = 0x05DF;
  1481.             return;
  1482.         }
  1483.         cpu.l |= ((pulse & tape_pulse_mask) > 1240) ? bit : 0;
  1484.         comp.tape.play_pointer++;
  1485.     }
  1486.  
  1487.     if(cpu.l != Flag) // ╧Ёш эхёютярфхэшш Їыруютюую срщЄр яЁюяєёърхь сыюъ фрээ√ї
  1488.     {
  1489.         IsLoad = false;
  1490.     }
  1491.  
  1492.     cpu.h ^= cpu.l;
  1493.  
  1494.     // loading data
  1495.     do
  1496.     {
  1497.         cpu.l = 0;
  1498.         for(unsigned bit = 0x80; bit; bit >>= 1)
  1499.         {
  1500.             if(comp.tape.play_pointer >= comp.tape.end_of_tape ||
  1501.                 (pulse = tape_pulse[*comp.tape.play_pointer++]) == UINT32_MAX)
  1502.             {
  1503.                 stop_tape();
  1504.                 cpu.pc = 0x05DF;
  1505.                 return;
  1506.             }
  1507.             cpu.l |= ((pulse & tape_pulse_mask) > 1240) ? bit : 0;
  1508.             comp.tape.play_pointer++;
  1509.         }
  1510.         cpu.h ^= cpu.l;
  1511.         if(IsLoad)
  1512.         {
  1513.             cpu.DbgMemIf->wm(cpu.ix, cpu.l);
  1514.         }
  1515.         cpu.ix++;
  1516.         cpu.de--;
  1517.     } while(cpu.de & 0xFFFF);
  1518.  
  1519.     // loading CRC
  1520.     cpu.l = 0;
  1521.     for(unsigned bit = 0x80; bit; bit >>= 1)
  1522.     {
  1523.         if(comp.tape.play_pointer >= comp.tape.end_of_tape ||
  1524.             (pulse = tape_pulse[*comp.tape.play_pointer++]) == UINT32_MAX)
  1525.         {
  1526.             stop_tape();
  1527.             cpu.pc = 0x05DF;
  1528.             return;
  1529.         }
  1530.         cpu.l |= ((pulse & tape_pulse_mask) > 1240) ? bit : 0;
  1531.         comp.tape.play_pointer++;
  1532.     }
  1533.     cpu.h ^= cpu.l;
  1534.     cpu.pc = 0x05DF; // ld a,h / cp 01 / ret
  1535.     cpu.bc = 0xB001;
  1536.  
  1537.     comp.tape.play_pointer++;
  1538.     stop_tape();
  1539.  
  1540.     /*cpu.pc=0x0604; // the old one
  1541.     unsigned pulse;
  1542.     pulse = tape_pulse[*comp.tape.play_pointer++];
  1543.     if(pulse == -1) stop_tape();
  1544.     else{
  1545.       comp.t_states+=pulse;
  1546.       comp.tape.edge_change = comp.t_states + cpu.t + 520;
  1547.  
  1548.       cpu.b+=(pulse-520)/56;
  1549.       cpu.f|=CF;
  1550.     }*/
  1551. }
  1552.