Subversion Repositories pentevo

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
716 lvd 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
unsigned tape_pulse[0x100]; // Алфавит из импульсов разной длины (число символов алфавита не более 256, ссылки однобайтовые)
14
unsigned max_pulses = 0;
15
unsigned tape_err = 0;
16
 
17
unsigned char *tape_image = 0; // Массив ссылок на алфавит (ссылки однобайтовые)
18
unsigned tape_imagesize = 0;
19
 
20
TAPEINFO *tapeinfo;
21
unsigned tape_infosize;
22
 
23
unsigned appendable;
24
 
25
typedef int (__cdecl *inflateInit__ptr)(z_streamp strm, const char *version, int stream_size);
26
typedef int (__cdecl *inflate_ptr)(z_streamp strm, int flush);
27
typedef int (__cdecl *inflateEnd_ptr)(z_streamp strm);
28
 
29
static inflateInit__ptr inflateInit__p = 0;
30
static inflate_ptr inflate_p = 0;
31
static inflateEnd_ptr inflateEnd_p = 0;
32
 
33
static HMODULE ZlibDll = 0;
34
 
35
bool ZlibInit()
36
{
37
    ZlibDll = LoadLibrary("zlib1.dll");
38
    if(!ZlibDll)
39
        return false;
40
    inflateInit__p = (inflateInit__ptr)GetProcAddress(ZlibDll, "inflateInit_");
41
    if(!inflateInit__p)
42
        return false;
43
    inflate_p = (inflate_ptr)GetProcAddress(ZlibDll,"inflate");
44
    if(!inflate_p)
45
        return false;
46
    inflateEnd_p = (inflateEnd_ptr)GetProcAddress(ZlibDll,"inflateEnd");
47
    if(!inflateEnd_p)
48
        return false;
49
    return true;
50
}
51
 
52
void ZlibDone()
53
{
54
    if(ZlibDll)
55
        FreeLibrary(ZlibDll);
56
}
57
 
58
// Ищет длину импульса в алфавите и возвращает индекс найденного элемента
59
// Если импульс с такой шириной не найден, он добавляется в конец и возвращается его индекс
60
// tape image contains indexes in tape_pulse[]
61
unsigned find_pulse(unsigned t)
62
{
63
   if (max_pulses < _countof(tape_pulse))
64
   {
65
      double e = 0.10 * t; // разброс 10%
66
      for (unsigned i = 0; i < max_pulses; i++)
67
      {
68
         if ((t - e) < tape_pulse[i] && tape_pulse[i] <= (t + e))
69
         {
70
             return i;
71
         }
72
      }
73
      tape_pulse[max_pulses] = t;
74
      return max_pulses++;
75
   }
76
   if (!tape_err)
77
   {
78
       errmsg("pulse table full");
79
       tape_err = 1;
80
   }
81
   unsigned nearest = 0; int delta = 0x7FFFFFFF;
82
   for (unsigned i = 0; i < _countof(tape_pulse); i++)
83
   {
84
      if (delta > abs((int)t - (int)tape_pulse[i]))
85
      {
86
         nearest = i;
87
         delta = abs((int)t - (int)tape_pulse[i]);
88
      }
89
   }
90
   return nearest;
91
}
92
 
93
void find_tape_index()
94
{
95
   for (unsigned i = 0; i < tape_infosize; i++)
96
      if (comp.tape.play_pointer >= tape_image + tapeinfo[i].pos)
97
         comp.tape.index = i;
98
   temp.led.tape_started = -600*3500000;
99
}
100
 
101
void find_tape_sizes()
102
{
103
   for (unsigned i = 0; i < tape_infosize; i++) {
104
      unsigned end = (i == tape_infosize-1) ? tape_imagesize : tapeinfo[i+1].pos;
105
 
106
      unsigned sz = 0;
107
      for (unsigned j = tapeinfo[i].pos; j < end; j++)
108
         sz += tape_pulse[tape_image[j]];
109
      tapeinfo[i].t_size = sz;
110
   }
111
}
112
 
113
void stop_tape()
114
{
115
   find_tape_index();
116
   const char *msg = "tape stopped";
117
   if (comp.tape.play_pointer == comp.tape.end_of_tape)
118
      comp.tape.index = 0, msg = "end of tape";
119
   comp.tape.play_pointer = 0;
120
   strcpy(statusline, msg); statcnt = 40;
121
   comp.tape.edge_change = 0x7FFFFFFFFFFFFFFFULL;
122
   comp.tape.tape_bit = -1;
123
}
124
 
125
void reset_tape()
126
{
127
   comp.tape.index = 0;
128
   comp.tape.play_pointer = 0;
129
   comp.tape.edge_change = 0x7FFFFFFFFFFFFFFFULL;
130
   comp.tape.tape_bit = -1;
131
}
132
 
133
void start_tape()
134
{
135
   if (!tape_image) return;
136
   strcpy(statusline, "tape started"); statcnt = 40;
137
   comp.tape.play_pointer = tape_image + tapeinfo[comp.tape.index].pos;
138
   comp.tape.end_of_tape = tape_image + tape_imagesize;
139
   comp.tape.edge_change = comp.t_states + cpu.t;
140
   temp.led.tape_started = -600*3500000;
141
   comp.tape.tape_bit = -1;
142
}
143
 
144
void closetape()
145
{
146
   if (tape_image) free(tape_image), tape_image = 0;
147
   if (tapeinfo) free(tapeinfo), tapeinfo = 0;
148
   comp.tape.play_pointer = 0; // stop tape
149
   comp.tape.index = 0; // rewind tape
150
   tape_err = max_pulses = tape_imagesize = tape_infosize = 0;
151
   comp.tape.edge_change = 0x7FFFFFFFFFFFFFFFULL;
152
   comp.tape.tape_bit = -1;
153
}
154
 
155
void reserve(unsigned datasize)
156
{
157
   const int blocksize = 16384;
158
   unsigned newsize = align_by(datasize+tape_imagesize+1, blocksize);
159
   if (!tape_image) tape_image = (unsigned char*)malloc(newsize);
160
   if (align_by(tape_imagesize, blocksize) < newsize) tape_image = (unsigned char*)realloc(tape_image, newsize);
161
}
162
 
163
void makeblock(const unsigned char *data, unsigned size, unsigned pilot_t,
164
      unsigned s1_t, unsigned s2_t, unsigned zero_t, unsigned one_t,
165
      unsigned pilot_len, unsigned pause, unsigned char last = 8)
166
{
167
   reserve(size*16 + pilot_len + 3);
168
   if (pilot_len != -1) {
169
      unsigned t = find_pulse(pilot_t);
170
      for (unsigned i = 0; i < pilot_len; i++)
171
         tape_image[tape_imagesize++] = t;
172
      tape_image[tape_imagesize++] = find_pulse(s1_t);
173
      tape_image[tape_imagesize++] = find_pulse(s2_t);
174
   }
175
   unsigned t0 = find_pulse(zero_t), t1 = find_pulse(one_t);
176
   for (; size>1; size--, data++)
177
      for (unsigned char j = 0x80; j; j >>= 1)
178
         tape_image[tape_imagesize++] = (*data & j) ? t1 : t0,
179
         tape_image[tape_imagesize++] = (*data & j) ? t1 : t0;
180
   for (unsigned char j = 0x80; j != (unsigned char)(0x80 >> last); j >>= 1) // last byte
181
      tape_image[tape_imagesize++] = (*data & j) ? t1 : t0,
182
      tape_image[tape_imagesize++] = (*data & j) ? t1 : t0;
183
   if (pause) tape_image[tape_imagesize++] = find_pulse(pause*3500);
184
}
185
 
186
void desc(const unsigned char *data, unsigned size, char *dst)
187
{
188
   unsigned char crc = 0; char prg[10];
189
   unsigned i; //Alone Coder 0.36.7
190
   for (/*unsigned*/ i = 0; i < size; i++) crc ^= data[i];
191
   if (!*data && size == 19 && (data[1] == 0 || data[1] == 3)) {
192
      for (i = 0; i < 10; i++) prg[i] = (data[i+2] < ' ' || data[i+2] >= 0x80) ? '?' : data[i+2];
193
      for (i = 9; i && prg[i] == ' '; prg[i--] = 0);
194
      sprintf(dst, "%s: \"%s\" %d,%d", data[1] ? "Bytes":"Program", prg,
195
         *(unsigned short*)(data+14), *(unsigned short*)(data+12));
196
   } else if (*data == 0xFF) sprintf(dst, "data block, %d bytes", size-2);
197
   else sprintf(dst, "#%02X block, %d bytes", *data, size-2);
198
   sprintf(dst + strlen(dst), ", crc %s", crc ? "bad":"ok");
199
}
200
 
201
static bool alloc_infocell()
202
{
203
   TAPEINFO *tmp = (TAPEINFO*)realloc(tapeinfo, (tape_infosize+1)*sizeof(TAPEINFO));
204
   if(!tmp)
205
   {
206
       return false;
207
   }
208
   tapeinfo = tmp;
209
   tapeinfo[tape_infosize].pos = tape_imagesize;
210
   appendable = 0;
211
   return true;
212
}
213
 
214
bool named_cell(const void *nm, unsigned sz = 0)
215
{
216
   if(!alloc_infocell())
217
       return false;
218
 
219
   const size_t n = _countof(tapeinfo[tape_infosize].desc)-1;
220
   size_t len = min(n, sz ? sz : strlen((const char*)nm));
221
   strncpy(tapeinfo[tape_infosize].desc, (const char*)nm, len);
222
   tapeinfo[tape_infosize].desc[len] = 0;
223
   tape_infosize++;
224
   return true;
225
}
226
 
227
int readTAP()
228
{
229
   unsigned char *ptr = snbuf; closetape();
230
   while (ptr < snbuf+snapsize) {
231
      unsigned size = *(unsigned short*)ptr; ptr += 2;
232
      if (!size) break;
233
      alloc_infocell();
234
      desc(ptr, size, tapeinfo[tape_infosize].desc);
235
      tape_infosize++;
236
      makeblock(ptr, size, 2168, 667, 735, 855, 1710, (*ptr < 4) ? 8064 : 3220, 1000);
237
      ptr += size;
238
   }
239
   find_tape_sizes();
240
   return (ptr == snbuf+snapsize);
241
}
242
 
243
#pragma pack(push, 1)
244
struct TCswHdr
245
{
246
    char Signature[22];
247
    u8 Term;
248
    u8 VerMajor;
249
    u8 VerMinor;
250
    union
251
    {
252
        struct
253
        {
254
            u16 SampleRate;
255
            u8 CompressionType;
256
            u8 Flags;
257
            u8 Reserved[3];
723 lvd 258
            u8 Data[1];
716 lvd 259
        } Ver1;
260
 
261
        struct
262
        {
263
            u32 SampleRate;
264
            u32 PulsesAfterDecompression;
265
            u8 CompressionType;
266
            u8 Flags;
267
            u8 HeaderExtLen;
268
            char EncAppDesc[16];
723 lvd 269
            u8 ExtHdr[1];
716 lvd 270
        } Ver2;
271
    };
272
};
273
#pragma pack(pop)
274
 
275
int readCSW()
276
{
277
   closetape();
278
   named_cell("CSW tape image");
279
 
280
   const TCswHdr *CswHdr = (TCswHdr *)snbuf;
281
   u8 CompType;
282
   u32 SampleRate;
283
   u8 Flags;
284
   u32 DataOffset;
285
   u32 PulsesCount;
286
   switch(CswHdr->VerMajor)
287
   {
288
   case 1:
289
       CompType = CswHdr->Ver1.CompressionType;
290
       SampleRate = CswHdr->Ver1.SampleRate;
291
       Flags = CswHdr->Ver1.Flags;
292
       DataOffset = offsetof(TCswHdr, Ver1.Data);
293
       PulsesCount = snapsize - 0x18; // Непонятная константа
294
   break;
295
 
296
   case 2:
297
       CompType = CswHdr->Ver2.CompressionType;
298
       SampleRate = CswHdr->Ver2.SampleRate;
299
       Flags = CswHdr->Ver2.Flags;
300
       DataOffset = offsetof(TCswHdr, Ver2.ExtHdr) + CswHdr->Ver2.HeaderExtLen;
301
       PulsesCount = CswHdr->Ver2.PulsesAfterDecompression;
302
   break;
303
 
304
   default: // unknown csw version
305
       return 0;
306
   }
307
 
308
   u32 UncompressedSize = snapsize;
309
   switch(CompType)
310
   {
311
   case 2: // Z-RLE
312
       {
313
           if(!temp.ZlibSupport)
314
               return 0;
315
           static const size_t out_sz = sizeof(snbuf);
316
           void *out = malloc(out_sz);
317
           if(!out)
318
               return 0;
319
 
320
           z_stream strm;
321
           strm.zalloc = Z_NULL;
322
           strm.zfree = Z_NULL;
323
           strm.opaque = Z_NULL;
324
           strm.avail_in = snapsize - DataOffset;
325
           strm.next_in = snbuf + DataOffset;
326
           int ret = inflateInit__p(&strm, ZLIB_VERSION, sizeof(strm));
327
           if(ret != Z_OK)
328
           {
329
               free(out);
330
               return 0;
331
           }
332
 
333
           strm.avail_out = out_sz;
334
           strm.next_out = (Byte *)out;
335
           ret = inflate_p(&strm, Z_FINISH);
336
           if(ret < 0)
337
           {
338
               free(out);
339
               inflateEnd_p(&strm);
340
               return 0;
341
           }
342
           UncompressedSize = out_sz - strm.avail_out;
343
           memcpy(snbuf + DataOffset, out, UncompressedSize);
344
           UncompressedSize += DataOffset;
345
           free(out);
346
           inflateEnd_p(&strm);
347
       }
348
   case 1: // RLE
349
   break;
350
 
351
   default:
352
       return 0; // unknown compression type
353
   }
354
 
355
   unsigned rate = Z80FQ / SampleRate; // usually 3.5mhz / 44khz
356
   if (!rate)
357
       return 0;
358
 
359
   reserve(PulsesCount);
360
 
361
   if (!(Flags & 1))
362
       tape_image[tape_imagesize++] = find_pulse(1);
363
 
364
   unsigned i = 0;
365
   for (unsigned char *ptr = snbuf + DataOffset; ptr < snbuf + UncompressedSize; i++)
366
   {
367
      unsigned len = *ptr++ * rate;
368
      if (!len)
369
      {
370
          len = *(unsigned*)ptr * rate;
371
          ptr += 4;
372
      }
373
      tape_image[tape_imagesize++] = find_pulse(len);
374
   }
375
 
376
   tape_image[tape_imagesize++] = find_pulse(Z80FQ/10);
377
   find_tape_sizes();
378
   return 1;
379
}
380
 
381
void create_appendable_block()
382
{
383
   if (!tape_infosize || appendable) return;
384
   named_cell("set of pulses"); appendable = 1;
385
}
386
 
387
void parse_hardware(const unsigned char *ptr)
388
{
389
   unsigned n = *ptr++;
390
   if (!n) return;
391
   named_cell("- HARDWARE TYPE ");
392
   static char ids[] =
393
     "computer\0"
394
        "ZX Spectrum 16k\0"
395
        "ZX Spectrum 48k, Plus\0"
396
        "ZX Spectrum 48k ISSUE 1\0"
397
        "ZX Spectrum 128k (Sinclair)\0"
398
        "ZX Spectrum 128k +2 (Grey case)\0"
399
        "ZX Spectrum 128k +2A, +3\0"
400
        "Timex Sinclair TC-2048\0"
401
        "Timex Sinclair TS-2068\0"
402
        "Pentagon 128\0"
403
        "Sam Coupe\0"
404
        "Didaktik M\0"
405
        "Didaktik Gama\0"
406
        "ZX-81 or TS-1000 with  1k RAM\0"
407
        "ZX-81 or TS-1000 with 16k RAM or more\0"
408
        "ZX Spectrum 128k, Spanish version\0"
409
        "ZX Spectrum, Arabic version\0"
410
        "TK 90-X\0"
411
        "TK 95\0"
412
        "Byte\0"
413
        "Elwro\0"
414
        "ZS Scorpion\0"
415
        "Amstrad CPC 464\0"
416
        "Amstrad CPC 664\0"
417
        "Amstrad CPC 6128\0"
418
        "Amstrad CPC 464+\0"
419
        "Amstrad CPC 6128+\0"
420
        "Jupiter ACE\0"
421
        "Enterprise\0"
422
        "Commodore 64\0"
423
        "Commodore 128\0"
424
        "\0"
425
     "ext. storage\0"
426
        "Microdrive\0"
427
        "Opus Discovery\0"
428
        "Disciple\0"
429
        "Plus-D\0"
430
        "Rotronics Wafadrive\0"
431
        "TR-DOS (BetaDisk)\0"
432
        "Byte Drive\0"
433
        "Watsford\0"
434
        "FIZ\0"
435
        "Radofin\0"
436
        "Didaktik disk drives\0"
437
        "BS-DOS (MB-02)\0"
438
        "ZX Spectrum +3 disk drive\0"
439
        "JLO (Oliger) disk interface\0"
440
        "FDD3000\0"
441
        "Zebra disk drive\0"
442
        "Ramex Millenia\0"
443
        "Larken\0"
444
        "\0"
445
     "ROM/RAM type add-on\0"
446
        "Sam Ram\0"
447
        "Multiface\0"
448
        "Multiface 128k\0"
449
        "Multiface +3\0"
450
        "MultiPrint\0"
451
        "MB-02 ROM/RAM expansion\0"
452
        "\0"
453
     "sound device\0"
454
        "Classic AY hardware\0"
455
        "Fuller Box AY sound hardware\0"
456
        "Currah microSpeech\0"
457
        "SpecDrum\0"
458
        "AY ACB stereo; Melodik\0"
459
        "AY ABC stereo\0"
460
        "\0"
461
     "joystick\0"
462
        "Kempston\0"
463
        "Cursor, Protek, AGF\0"
464
        "Sinclair 2\0"
465
        "Sinclair 1\0"
466
        "Fuller\0"
467
        "\0"
468
     "mice\0"
469
        "AMX mouse\0"
470
        "Kempston mouse\0"
471
        "\0"
472
     "other controller\0"
473
        "Trickstick\0"
474
        "ZX Light Gun\0"
475
        "Zebra Graphics Tablet\0"
476
        "\0"
477
     "serial port\0"
478
        "ZX Interface 1\0"
479
        "ZX Spectrum 128k\0"
480
        "\0"
481
     "parallel port\0"
482
        "Kempston S\0"
483
        "Kempston E\0"
484
        "ZX Spectrum 128k +2A, +3\0"
485
        "Tasman\0"
486
        "DK'Tronics\0"
487
        "Hilderbay\0"
488
        "INES Printerface\0"
489
        "ZX LPrint Interface 3\0"
490
        "MultiPrint\0"
491
        "Opus Discovery\0"
492
        "Standard 8255 chip with ports 31,63,95\0"
493
        "\0"
494
     "printer\0"
495
        "ZX Printer, Alphacom 32 & compatibles\0"
496
        "Generic Printer\0"
497
        "EPSON Compatible\0"
498
        "\0"
499
     "modem\0"
500
        "VTX 5000\0"
501
        "T/S 2050 or Westridge 2050\0"
502
        "\0"
503
     "digitaiser\0"
504
        "RD Digital Tracer\0"
505
        "DK'Tronics Light Pen\0"
506
        "British MicroGraph Pad\0"
507
        "\0"
508
     "network adapter\0"
509
        "ZX Interface 1\0"
510
        "\0"
511
     "keyboard / keypad\0"
512
        "Keypad for ZX Spectrum 128k\0"
513
        "\0"
514
     "AD/DA converter\0"
515
        "Harley Systems ADC 8.2\0"
516
        "Blackboard Electronics\0"
517
        "\0"
518
     "EPROM Programmer\0"
519
        "Orme Electronics\0"
520
        "\0"
521
     "\0";
522
   for (unsigned i = 0; i < n; i++) {
523
      unsigned char type_n = *ptr++;
524
      unsigned char id_n = *ptr++;
525
      unsigned char value_n = *ptr++;
526
      const char *type = ids, *id, *value;
527
      unsigned j; //Alone Coder 0.36.7
528
      for (/*unsigned*/ j = 0; j < type_n; j++) {
529
         if (!*type) break;
530
         while (*(short*)type) type++;
531
         type += 2;
532
      }
533
      if (!*type) type = id = "??"; else {
534
         id = type + strlen(type) + 1;
535
         for (j = 0; j < id_n; j++) {
536
            if (!*id) { id = "??"; break; }
537
            id += strlen(id)+1;
538
         }
539
      }
540
      switch (value_n) {
541
         case 0: value = "compatible with"; break;
542
         case 1: value = "uses"; break;
543
         case 2: value = "compatible, but doesn't use"; break;
544
         case 3: value = "incompatible with"; break;
545
         default: value = "??";
546
      }
547
      char bf[512]; sprintf(bf, "%s %s: %s", value, type, id);
548
      named_cell(bf);
549
   }
550
   named_cell("-");
551
}
552
 
553
int readTZX()
554
{
555
   const unsigned char *ptr = snbuf;
556
   closetape();
557
   unsigned size, pause, i, j, n, t, t0;
558
   unsigned char pl, last;
559
   const unsigned char *end;
560
   char *p;
561
   unsigned loop_n = 0, loop_p;
562
   unsigned TzxVer = (ptr[8] << 8) | ptr[9];
563
   char nm[512];
564
 
565
   ptr += 10; // Пропуск заголовка
566
 
567
   while (ptr < snbuf+snapsize)
568
   {
569
      switch (*ptr++) {
570
         case 0x10: // normal block
571
            alloc_infocell();
572
            size = *(unsigned short*)(ptr+2);
573
            pause = *(unsigned short*)ptr;
574
            ptr += 4;
575
            desc(ptr, size, tapeinfo[tape_infosize].desc);
576
            tape_infosize++;
577
            makeblock(ptr, size, 2168, 667, 735, 855, 1710,
578
                (*ptr < 4) ? 8064 : 3220, pause);
579
            ptr += size;
580
            break;
581
         case 0x11: // turbo block
582
            alloc_infocell();
583
            size = 0xFFFFFF & *(unsigned*)(ptr+0x0F);
584
            desc(ptr + 0x12, size, tapeinfo[tape_infosize].desc);
585
            tape_infosize++;
586
            makeblock(ptr + 0x12, size,
587
               *(unsigned short*)ptr, *(unsigned short*)(ptr+2),
588
               *(unsigned short*)(ptr+4), *(unsigned short*)(ptr+6),
589
               *(unsigned short*)(ptr+8), *(unsigned short*)(ptr+10),
590
               *(unsigned short*)(ptr+13), ptr[12]);
591
            // todo: test used bits - ptr+12
592
            ptr += size + 0x12;
593
            break;
594
         case 0x12: // pure tone
595
            create_appendable_block();
596
            pl = find_pulse(*(unsigned short*)ptr);
597
            n = *(unsigned short*)(ptr+2);
598
            reserve(n);
599
            for (i = 0; i < n; i++) tape_image[tape_imagesize++] = pl;
600
            ptr += 4;
601
            break;
602
         case 0x13: // sequence of pulses of different lengths
603
            create_appendable_block();
604
            n = *ptr++;
605
            reserve(n);
606
            for (i = 0; i < n; i++, ptr += 2)
607
               tape_image[tape_imagesize++] = find_pulse(*(unsigned short*)ptr);
608
            break;
609
         case 0x14: // pure data block
610
            create_appendable_block();
611
            size = 0xFFFFFF & *(unsigned*)(ptr+7);
612
            makeblock(ptr + 0x0A, size, 0, 0, 0, *(unsigned short*)ptr,
613
                      *(unsigned short*)(ptr+2), -1, *(unsigned short*)(ptr+5), ptr[4]);
614
            ptr += size + 0x0A;
615
            break;
616
         case 0x15: // direct recording
617
            size = 0xFFFFFF & *(unsigned*)(ptr+5);
618
            t0 = *(unsigned short*)ptr;
619
            pause = *(unsigned short*)(ptr+2);
620
            last = ptr[4];
621
            named_cell("direct recording");
622
            ptr += 8;
623
            pl = 0; n = 0;
624
            for (i = 0; i < size; i++) // count number of pulses
625
               for (j = 0x80; j; j >>= 1)
626
                  if ((ptr[i] ^ pl) & j) n++, pl ^= -1;
627
            t = 0; pl = 0;
628
            reserve(n+2);
629
            for (i = 1; i < size; i++, ptr++) // find pulses
630
               for (j = 0x80; j; j >>= 1) {
631
                  t += t0;
632
                  if ((*ptr ^ pl) & j) {
633
                     tape_image[tape_imagesize++] = find_pulse(t);
634
                     pl ^= -1; t = 0;
635
                  }
636
               }
637
            // find pulses - last byte
638
            for (j = 0x80; j != (unsigned char)(0x80 >> last); j >>= 1) {
639
               t += t0;
640
               if ((*ptr ^ pl) & j) {
641
                  tape_image[tape_imagesize++] = find_pulse(t);
642
                  pl ^= -1; t = 0;
643
               }
644
            }
645
            ptr++;
646
            tape_image[tape_imagesize++] = find_pulse(t); // last pulse ???
647
            if (pause) tape_image[tape_imagesize++] = find_pulse(pause*3500);
648
            break;
649
         case 0x20: // pause (silence) or 'stop the tape' command
650
            pause = *(unsigned short*)ptr;
651
            sprintf(nm, pause? "pause %d ms" : "stop the tape", pause);
652
            named_cell(nm);
653
            reserve(2); ptr += 2;
654
            if (!pause) { // at least 1ms pulse as specified in TZX 1.13
655
               tape_image[tape_imagesize++] = find_pulse(3500);
656
               pause = -1;
657
            } else pause *= 3500;
658
            tape_image[tape_imagesize++] = find_pulse(pause);
659
            break;
660
         case 0x21: // group start
661
            n = *ptr++;
662
            named_cell(ptr, n); ptr += n;
663
            appendable = 1;
664
            break;
665
         case 0x22: // group end
666
            break;
667
         case 0x23: // jump to block
668
            named_cell("* jump"); ptr += 2;
669
            break;
670
         case 0x24: // loop start
671
            loop_n = *(unsigned short*)ptr; loop_p = tape_imagesize; ptr += 2;
672
            break;
673
         case 0x25: // loop end
674
            if (!loop_n) break;
675
            size = tape_imagesize - loop_p;
676
            reserve((loop_n-1) * size);
677
            for (i = 1; i < loop_n; i++)
678
               memcpy(tape_image + loop_p + i*size, tape_image + loop_p, size);
679
            tape_imagesize += (loop_n-1) * size;
680
            loop_n = 0;
681
            break;
682
         case 0x26: // call
683
            named_cell("* call"); ptr += 2 + 2 * *(unsigned short*)ptr;
684
            break;
685
         case 0x27: // ret
686
            named_cell("* return");
687
            break;
688
         case 0x28: // select block
689
            {
690
                int l = _countof(nm);
691
                l -= sprintf(nm, "* choice: ");
692
                n = ptr[2];
693
                p = (char*)ptr+3;
694
 
695
                for (i = 0; i < n; i++)
696
                {
697
                   size = *(unsigned char*)(p+2);
698
                   l -= size;
699
                   if(i)
700
                       l -= 4;
701
 
702
                   if(l >= 0)
703
                   {
704
                       if (i)
705
                           strcat(nm, " / ");
706
 
707
                       char *q = nm + strlen(nm);
708
                       memcpy(q, p+3, size);
709
                       q[size] = 0;
710
                   }
711
 
712
                   p += size+3;
713
                }
714
                named_cell(nm);
715
                ptr += 2 + *(unsigned short*)ptr;
716
            }
717
            break;
718
         case 0x2A: // stop if 48k
719
            named_cell("* stop if 48K");
720
            ptr += 4 + *(unsigned*)ptr;
721
            break;
722
         case 0x30: // text description
723
            n = *ptr++;
724
            named_cell(ptr, n); ptr += n;
725
            appendable = 1;
726
            break;
727
         case 0x31: // message block
728
            named_cell("- MESSAGE BLOCK ");
729
            end = ptr + 2 + ptr[1]; pl = *end; *(char *)end = 0;
730
            for (p = (char*)ptr+2; p < (char*)end; p++)
731
               if (*p == 0x0D) *p = 0;
732
            for (p = (char*)ptr+2; p < (char*)end; p += strlen(p)+1)
733
               named_cell(p);
734
            *(char *)end = pl; ptr = end;
735
            named_cell("-");
736
            break;
737
         case 0x32: // archive info
738
            named_cell("- ARCHIVE INFO ");
739
            p = (char*)ptr + 3;
740
            for (i = 0; i < ptr[2]; i++) {
741
               const char *info;
742
               switch (*p++) {
743
                  case 0: info = "Title"; break;
744
                  case 1: info = "Publisher"; break;
745
                  case 2: info = "Author"; break;
746
                  case 3: info = "Year"; break;
747
                  case 4: info = "Language"; break;
748
                  case 5: info = "Type"; break;
749
                  case 6: info = "Price"; break;
750
                  case 7: info = "Protection"; break;
751
                  case 8: info = "Origin"; break;
752
                  case -1:info = "Comment"; break;
753
                  default:info = "info"; break;
754
               }
755
               unsigned size = *(BYTE*)p+1;
756
               char tmp = p[size]; p[size] = 0;
757
               sprintf(nm, "%s: %s", info, p+1);
758
               p[size] = tmp; p += size;
759
               named_cell(nm);
760
            }
761
            named_cell("-");
762
            ptr += 2 + *(unsigned short*)ptr;
763
            break;
764
         case 0x33: // hardware type
765
            parse_hardware(ptr);
766
            ptr += 1 + 3 * *ptr;
767
            break;
768
         case 0x34: // emulation info
769
            named_cell("* emulation info"); ptr += 8;
770
            break;
771
         case 0x35: // custom info
772
            if (!memcmp(ptr, "POKEs           ", 16)) {
773
               named_cell("- POKEs block ");
774
               named_cell(ptr+0x15, ptr[0x14]);
775
               p = (char*)ptr + 0x15 + ptr[0x14];
776
               n = *(unsigned char*)p++;
777
               for (i = 0; i < n; i++) {
778
                  named_cell(p+1, *(unsigned char*)p);
779
                  p += *p+1;
780
                  t = *(unsigned char*)p++;
781
                  strcpy(nm, "POKE ");
782
                  for (j = 0; j < t; j++) {
783
                     sprintf(nm+strlen(nm), "%d,", *(unsigned short*)(p+1));
784
                     sprintf(nm+strlen(nm), *p & 0x10 ? "nn" : "%d", *(unsigned char*)(p+3));
785
                     if (!(*p & 0x08)) sprintf(nm+strlen(nm), "(page %d)", *p & 7);
786
                     strcat(nm, "; "); p += 5;
787
                  }
788
                  named_cell(nm);
789
               }
790
               *(unsigned*)nm = '-';
791
            } else sprintf(nm, "* custom info: %s", ptr), nm[15+16] = 0;
792
            named_cell(nm);
793
            ptr += 0x14 + *(unsigned*)(ptr+0x10);
794
            break;
795
         case 0x40: // snapshot
796
            named_cell("* snapshot"); ptr += 4 + (0xFFFFFF & *(unsigned*)(ptr + 1));
797
            break;
798
         default:
799
            if(TzxVer >= 0x10A)
800
            {
801
                // В начале каждого нестандартного блока идет его длина
802
                sprintf(nm, "* unknown id: 0x%X", ptr[-1]);
803
                named_cell(nm);
804
                u32 Skip = *(u32 *)ptr;
805
                ptr += Skip + sizeof(u32);
806
            }
807
            else
808
            {
809
                ptr += snapsize;
810
            }
811
      }
812
   }
813
   for (i = 0; i < tape_infosize; i++) {
814
      if (*(short*)tapeinfo[i].desc == WORD2('*', ' '))
815
      {
816
         if(strlen(tapeinfo[i].desc) < _countof(tapeinfo[i].desc) - sizeof(" [UNSUPPORTED]"))
817
             strcat(tapeinfo[i].desc, " [UNSUPPORTED]");
818
         else
819
         {
820
             strcpy(tapeinfo[i].desc + _countof(tapeinfo[i].desc) - sizeof(" [UNSUPPORTED]"), " [UNSUPPORTED]");
821
         }
822
      }
823
      if (*tapeinfo[i].desc == '-')
824
         while (strlen(tapeinfo[i].desc) < sizeof(tapeinfo[i].desc)-1)
825
            strcat(tapeinfo[i].desc, "-");
826
   }
827
   if (tape_imagesize && tape_pulse[tape_image[tape_imagesize-1]] < 350000)
828
      reserve(1), tape_image[tape_imagesize++] = find_pulse(350000); // small pause [rqd for 3ddeathchase]
829
   find_tape_sizes();
830
   return (ptr == snbuf+snapsize);
831
}
832
 
833
unsigned char tape_bit() // used in io.cpp & sound.cpp
834
{
835
   __int64 cur = comp.t_states + cpu.t;
836
   if (cur < comp.tape.edge_change)
837
       return (unsigned char)comp.tape.tape_bit;
838
   while (comp.tape.edge_change < cur)
839
   {
840
      if (!temp.sndblock)
841
      {
842
         unsigned t = (unsigned)(comp.tape.edge_change - comp.t_states - temp.cpu_t_at_frame_start);
843
         if ((int)t >= 0)
844
         {
845
            unsigned tape_in = conf.sound.micin_vol & comp.tape.tape_bit;
846
//            comp.tape.sound.update(t, tape_in, tape_in); //Alone Coder
847
            comp.tape_sound.update(t, tape_in, tape_in); //Alone Coder
848
         }
849
      }
850
      unsigned pulse; comp.tape.tape_bit ^= -1;
851
      if (comp.tape.play_pointer == comp.tape.end_of_tape ||
852
          (pulse = tape_pulse[*comp.tape.play_pointer++]) == -1)
853
              stop_tape();
854
      else
855
          comp.tape.edge_change += pulse;
856
   }
857
   return (unsigned char)comp.tape.tape_bit;
858
}
859
 
860
void fast_tape()
861
{
862
   unsigned char *ptr = am_r(cpu.pc);
863
   unsigned p = *(unsigned*)ptr;
864
   if (p == WORD4(0x3D,0x20,0xFD,0xA7))
865
   { // dec a:jr nz,$-1
866
      cpu.t += ((unsigned char)(cpu.a-1))*16; cpu.a = 1;
867
      return;
868
   }
869
   if ((unsigned short)p == WORD2(0x10,0xFE))
870
   { // djnz $
871
      cpu.t += ((unsigned char)(cpu.b-1))*13; cpu.b = 1;
872
      return;
873
   }
874
   if ((unsigned short)p == WORD2(0x3D,0xC2) && (cpu.pc & 0xFFFF)==(p>>16))
875
   { // dec a:jp nz,$-1
876
      cpu.t += ((unsigned char)(cpu.a-1))*14; cpu.a = 1;
877
      return;
878
   }
879
   if ((p | WORD4(0,0,0,0xFF)) == WORD4(0x04,0xC8,0x3E,0xFF))
880
   {
881
      if (*(unsigned*)(ptr+4) == WORD4(0xDB,0xFE,0x1F,0xD0) &&
882
          *(unsigned*)(ptr+8) == WORD4(0xA9,0xE6,0x20,0x28) && ptr[12] == 0xF3)
883
      { // find edge (rom routine)
884
         for (;;)
885
         {
886
            if (cpu.b == 0xFF)
887
                return;
888
            if ((tape_bit() ? 0x20 : 0) ^ (cpu.c & 0x20))
889
                return;
890
            cpu.b++; cpu.t += 59;
891
         }
892
      }
893
      if (*(unsigned*)(ptr+4) == WORD4(0xDB,0xFE,0xCB,0x1F) &&
894
          *(unsigned*)(ptr+8) == WORD4(0xA9,0xE6,0x20,0x28) && ptr[12] == 0xF3)
895
      { // rra,ret nc => rr a (popeye2)
896
         for (;;)
897
         {
898
            if (cpu.b == 0xFF) return;
899
            if ((tape_bit() ^ cpu.c) & 0x20) return;
900
            cpu.b++; cpu.t += 58;
901
         }
902
      }
903
      if (*(unsigned*)(ptr+4) == WORD4(0xDB,0xFE,0x1F,0x00) &&
904
          *(unsigned*)(ptr+8) == WORD4(0xA9,0xE6,0x20,0x28) && ptr[12] == 0xF3)
905
      { // ret nc nopped (some bleep loaders)
906
         for (;;)
907
         {
908
            if (cpu.b == 0xFF) return;
909
            if ((tape_bit() ^ cpu.c) & 0x20) return;
910
            cpu.b++; cpu.t += 58;
911
         }
912
      }
913
      if (*(unsigned*)(ptr+4) == WORD4(0xDB,0xFE,0xA9,0xE6) &&
914
          *(unsigned*)(ptr+8) == WORD4(0x40,0xD8,0x00,0x28) && ptr[12] == 0xF3)
915
      { // no rra, no break check (rana rama)
916
         for (;;)
917
         {
918
            if (cpu.b == 0xFF) return;
919
            if ((tape_bit() ^ cpu.c) & 0x40) return;
920
            cpu.b++; cpu.t += 59;
921
         }
922
      }
923
      if (*(unsigned*)(ptr+4) == WORD4(0xDB,0xFE,0x1F,0xA9) &&
924
          *(unsigned*)(ptr+8) == WORD4(0xE6,0x20,0x28,0xF4))
925
      { // ret nc skipped: routine without BREAK checking (ZeroMusic & JSW)
926
         for (;;)
927
         {
928
            if (cpu.b == 0xFF) return;
929
            if ((tape_bit() ^ cpu.c) & 0x20) return;
930
            cpu.b++; cpu.t += 54;
931
         }
932
      }
933
   }
934
   if ((p | WORD4(0,0,0,0xFF)) == WORD4(0x04,0x20,0x03,0xFF) &&
935
        ptr[6] == 0xDB && *(unsigned*)(ptr+8) == WORD4(0x1F,0xC8,0xA9,0xE6) &&
936
        (*(unsigned*)(ptr+0x0C) | WORD4(0,0,0,0xFF)) == WORD4(0x20,0x28,0xF1,0xFF))
937
   { // find edge from Donkey Kong
938
      for (;;) {
939
         if (cpu.b == 0xFF) return;
940
         if ((tape_bit() ^ cpu.c) & 0x20) return;
941
         cpu.b++; cpu.t += 59;
942
      }
943
   }
944
   if ((p | WORD4(0,0xFF,0,0)) == WORD4(0x3E,0xFF,0xDB,0xFE) &&
945
       *(unsigned*)(ptr+4) == WORD4(0xA9,0xE6,0x40,0x20) &&
946
       (*(unsigned*)(ptr+8) | WORD4(0xFF,0,0,0)) == WORD4(0xFF,0x05,0x20,0xF4))
947
   { // lode runner
948
      for (;;)
949
      {
950
         if (cpu.b == 1) return;
951
         if ((tape_bit() ^ cpu.c) & 0x40) return;
952
         cpu.t += 52; cpu.b--;
953
      }
954
   }
955
}
956
 
957
void tape_traps()
958
{
959
   unsigned pulse;
960
   do
961
   {
962
       if(comp.tape.play_pointer>=comp.tape.end_of_tape ||
963
          (pulse=tape_pulse[*comp.tape.play_pointer++])==-1)
964
       {
965
           stop_tape();
966
           return;
967
       }
968
   }while(pulse > 770);
969
   comp.tape.play_pointer++;
970
 
971
   // loading header
972
   cpu.l=0;
973
   cpu.h = 0;
974
   for(unsigned bit=0x80;bit;bit>>=1)
975
   {
976
       if(comp.tape.play_pointer>=comp.tape.end_of_tape||
977
         (pulse=tape_pulse[*comp.tape.play_pointer++])==-1)
978
       {
979
         stop_tape();
980
         cpu.pc = 0x05DF;
981
         return;
982
       }
983
       cpu.l |= (pulse>1240) ? bit : 0;
984
       comp.tape.play_pointer++;
985
   }
986
   cpu.h ^= cpu.l;
987
 
988
   // loading data
989
   do
990
   {
991
     cpu.l = 0;
992
     for(unsigned bit=0x80; bit; bit >>= 1)
993
     {
994
       if(comp.tape.play_pointer >= comp.tape.end_of_tape ||
995
          (pulse = tape_pulse[*comp.tape.play_pointer++])==-1)
996
       {
997
         stop_tape();
998
         cpu.pc = 0x05DF;
999
         return;
1000
       }
1001
       cpu.l |= (pulse > 1240) ? bit : 0;
1002
       comp.tape.play_pointer++;
1003
     }
1004
     cpu.h ^= cpu.l;
1005
     cpu.DbgMemIf->wm(cpu.ix++, cpu.l);
1006
     cpu.de--;
1007
   }while(cpu.de & 0xFFFF);
1008
 
1009
   // loading CRC
1010
   cpu.l = 0;
1011
   for(unsigned bit = 0x80; bit; bit >>= 1)
1012
   {
1013
     if(comp.tape.play_pointer>=comp.tape.end_of_tape||
1014
       (pulse=tape_pulse[*comp.tape.play_pointer++])==-1)
1015
     {
1016
       stop_tape();
1017
       cpu.pc = 0x05DF;
1018
       return;
1019
     }
1020
     cpu.l |= (pulse > 1240) ? bit : 0;
1021
     comp.tape.play_pointer++;
1022
   }
1023
   cpu.h ^= cpu.l;
1024
   cpu.pc = 0x05DF; // ld a,h / cp 01 / ret
1025
   cpu.bc = 0xB001;
1026
 
1027
   comp.tape.play_pointer++;
1028
   stop_tape();
1029
 
1030
     /*cpu.pc=0x0604; // the old one
1031
     unsigned pulse;
1032
     pulse = tape_pulse[*comp.tape.play_pointer++];
1033
     if(pulse == -1) stop_tape();
1034
     else{
1035
       comp.t_states+=pulse;
1036
       comp.tape.edge_change = comp.t_states + cpu.t + 520;
1037
 
1038
       cpu.b+=(pulse-520)/56;
1039
       cpu.f|=CF;
1040
     }*/
1041
}