forked from redcode/SpecEmu
-
Notifications
You must be signed in to change notification settings - Fork 0
/
TapeHandling.asm
2174 lines (1648 loc) · 72.5 KB
/
TapeHandling.asm
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
include Tapes.inc
StartStopTape PROTO
SaveTapeChildDlgProc PROTO :DWORD,:DWORD,:DWORD,:DWORD
SetBlock19TapePolarity PROTO :BYTE
Set_Tape_Pause PROTO :WORD
Is_TZX_Data_Block PROTO :BYTE
.data
WAVBlockHeader db BLOCK_WAV
TapeWavHeader BYTE WAVHEADERSIZE dup(?)
ERR_WaveFileError db "Wave File Error", 0
CSWBlockHeader db BLOCK_CSW
TapeCSWHeader CSWHEADER <>
ERR_CSWFileError db "CSW File Error", 0
szTapeFilter db "Tape files (*.tap;*.blk;*.tzx;*.wav;*.csw;*.pzx)", 0, "*.tap;*.blk;*.tzx;*.wav;*.csw;*.pzx", 0, 0
TZX_End_Pause_Block db SPECIAL_PAUSE_BLOCK
dw 2 ; 2 ms
.data?
align 4
PZX TPZX <>
;--------------------------------------------------------------------------------
.code
WAIT_PULSE macro
local looplabel
call FlipEar
mov TZXJump, offset looplabel
looplabel: mov ax, TapeTStates
sub ax, TZXCountDown
retcc c
mov TapeTStates, ax
endm
PULSE_LOW macro
ifc EarBit ne 0 then call FlipEar
endm
PULSE_HIGH macro
ifc EarBit ne 64 then call FlipEar
endm
InsertTape proc
local ofn: OPENFILENAME
invoke GetFileName, hWnd, SADD ("Insert Tape"), addr szTapeFilter, addr ofn, addr inserttapefilename, addr TZXExt
ifc eax eq 0 then ret ; return error
invoke ReadFileType, addr inserttapefilename
ret
InsertTape endp
InsertTape_1 proc uses ebx esi edi,
lpFilename: DWORD
mov TapePlaying, FALSE ; turn the tape off
mov SL_LoopCount, 0 ; reset load sensing code parameters
mov SL_LoaderPC, 0
.if $fnc (szLen, lpFilename) < 5
return FALSE ; error loading tape
.endif
m2m Filename, lpFilename
invoke szRight, lpFilename, addr TapeExtBuffer, 4
invoke lcase, addr TapeExtBuffer
mov TapeDataBlockCnt, 0
mov FirstTAPBlockPtr, 0
switch dword ptr [TapeExtBuffer]
case "pat."
call OpenTAP_TZXFile
case "klb."
call OpenTAP_TZXFile
case "xzt."
call OpenTAP_TZXFile
case "vaw."
call OpenWAVFile
case "wsc."
call OpenCSWFile
case "xzp."
call OpenPZXFile
.else
return FALSE ; error loading tape
endsw
.if eax == TRUE ; tape loaded successfully?
invoke SetDirtyLines ; force tape icon in border to appear if enabled in options
strncpy lpFilename, addr inserttapefilename, sizeof inserttapefilename
.if inhibit_recent_file == FALSE
strncpy lpFilename, addr szRecentFileName, sizeof szRecentFileName
invoke AddRecentFile
.endif
; tape autoload is unavailable for DivIDE
.if (AutoloadTapes == TRUE) && (DivIDEEnabled == FALSE)
invoke GetAsyncKeyState, VK_SHIFT
test ax, 8000h
.if ZERO?
ADDMESSAGE "Autoloading tape"
call ResetSpectrum
invoke Set_RunTo_Condition, RUN_TO_AUTOLOADTAPE
mov autotype_stage, 0
mov autotype_CODE_block, FALSE
.if FirstTAPBlockPtr != 0
mov eax, FirstTAPBlockPtr
.if dword ptr [eax] == 03000013h
; this is a standard code block header
mov autotype_CODE_block, TRUE
.endif
.endif
; turn on maximum emulation speed for the tape autoload typing
mov MAXIMUMAUTOLOADTYPE, TRUE
invoke Set_Autotype_Rom_Point ; sets autotype ROM pointer and PC address
switch HardwareMode
case HW_16, HW_48
mov autotype_keybuffer, offset autotapekeys_48_BASIC
ifc autotype_CODE_block eq TRUE then mov autotype_keybuffer, offset autotapekeys_48_CODE
case HW_128
mov autotype_keybuffer, offset autotapekeys_128_BASIC
ifc autotype_CODE_block eq TRUE then mov autotype_keybuffer, offset autotapekeys_128_CODE
case HW_PLUS2
mov autotype_keybuffer, offset autotapekeys_128_BASIC
ifc autotype_CODE_block eq TRUE then mov autotype_keybuffer, offset autotapekeys_128_CODE
case HW_PLUS2A, HW_PLUS3
mov autotype_keybuffer, offset autotapekeys_Plus3_BASIC
ifc autotype_CODE_block eq TRUE then mov autotype_keybuffer, offset autotapekeys_Plus3_CODE
case HW_PENTAGON128
mov autotype_keybuffer, offset autotapekeys_128_BASIC
ifc autotype_CODE_block eq TRUE then mov autotype_keybuffer, offset autotapekeys_128_CODE
case HW_TC2048
mov autotype_keybuffer, offset autotapekeys_48_BASIC
ifc autotype_CODE_block eq TRUE then mov autotype_keybuffer, offset autotapekeys_48_CODE
case HW_TK90X
mov autotype_keybuffer, offset autotapekeys_48_BASIC
ifc autotype_CODE_block eq TRUE then mov autotype_keybuffer, offset autotapekeys_48_CODE
endsw
.endif
.endif
mov eax, TRUE ; tape loaded successfully
.endif
; ensure EAR bit starts as low when loading a new tape; preserve the success/failure return value (EAX) too
ifc EarBit ne 0 then push eax : call FlipEar : pop eax
ret ; return with success/failure return value
InsertTape_1 endp
OpenCSWFile:
invoke CloseTapeFile
invoke CreateFile, Filename, GENERIC_READ, FILE_SHARE_READ or FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL
ifc eax eq INVALID_HANDLE_VALUE then xor eax, eax
mov TapeFileHandle, eax
.if TapeFileHandle == 0
return FALSE
.endif
invoke ReadFile, TapeFileHandle, ADDR TapeCSWHeader, sizeof CSWHEADER, ADDR BytesMoved, NULL
cmp [BytesMoved], sizeof CSWHEADER
jne OpenTapeFail
strncpy Filename, addr CSWfilename, sizeof CSWfilename
mov LastDataBlockPauseLocation, 0
mov edi, [TZXBlockPtrs] ; store our block pointers here
mov [edi], offset CSWBlockHeader
add edi, 4
xor eax, eax
mov [edi], eax
mov CSW_Load_Handle, $fnc (OpenCSW, Filename)
ifc eax eq NULL then jmp OpenTapeFail
mov LoadTapeType, Type_CSW
jmp TapeInit
OpenWAVFile:
invoke CloseTapeFile
invoke CreateFile, Filename, GENERIC_READ, FILE_SHARE_READ or FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL
ifc eax eq INVALID_HANDLE_VALUE then xor eax, eax
mov TapeFileHandle, eax
.if TapeFileHandle == 0
return FALSE
.endif
invoke ReadFile, TapeFileHandle, ADDR TapeWavHeader, WAVHEADERSIZE, ADDR BytesMoved, NULL
cmp [BytesMoved], WAVHEADERSIZE
jne OpenTapeFail
strncpy Filename, addr WAVfilename, sizeof WAVfilename
lea esi, TapeWavHeader
mov ax, [esi+22] ; num channels
mov WAVChannels, ax
movzx eax, word ptr [esi+24] ; sample frequency, Hz
.if (eax == 0) || (WAVChannels == 0)
invoke ShowMessageBox, hWnd, SADD("Invalid WAV file"),
ADDR ERR_WaveFileError,
MB_OK or MB_ICONINFORMATION
jmp OpenTapeFail
.endif
; invoke IntDiv, 3500000, eax
invoke Div2Int, 3500000, eax
mov WAVPulseLength, ax
movzx eax, word ptr [esi+34] ; bits per sample
mov WAVBits, eax
.if (eax != 8) && (eax != 16)
invoke ShowMessageBox, hWnd, SADD("SpecEmu only supports 8 bit and 16 bit wave recordings"),
ADDR ERR_WaveFileError,
MB_OK or MB_ICONINFORMATION
jmp OpenTapeFail
.endif
mov LastDataBlockPauseLocation, 0
mov edi, [TZXBlockPtrs] ; store our block pointers here
mov [edi], offset WAVBlockHeader
add edi, 4
xor eax, eax
mov [edi], eax
mov LoadTapeType, Type_WAV
jmp TapeInit
OpenPZXFile:
invoke CloseTapeFile
invoke ReadFileToMemory, Filename, addr _tapfileptr, addr _tapfilesize
or eax, eax
je OpenTapeFail
mov edi, [TZXBlockPtrs] ; store our block pointers here
mov esi, [_tapfileptr] ; start of pzx file in memory
mov edx, esi
add edx, [_tapfilesize] ; end of pzx file area
lodsd
cmp eax, "TXZP"
jne OpenTapeFail
lodsd ; size of the block
.if (eax < 2) || (byte ptr [esi] != 1)
jmp OpenTapeFail ; fail for blocksize < 2 or not a v1 PZX file
.endif
add esi, eax ; esi = first PZX block
mov LoadTapeType, Type_PZX
mov TZXAvail, @EVAL (edx - esi) ; TZXAvail = max available PZX bytes left
NextPZXBlock:
mov dword ptr [edi], 0
cmp esi, edx
je AppendPZXBlock ; reached end of PZX file
jc @F ; more PZX blocks to come
mov dword ptr [edi-4], 0 ; null invalid PZX block pointer
jmp TapeInit
@@: mov [edi], esi ; store PZX block pointer
add edi, 4
sub TZXAvail, 8 ; ensure we have at least "block header" bytes available
jc OpenTapeFail
mov eax, [esi] ; eax = block ID
mov ebx, [esi+4] ; ebx = block size
add esi, 8 ; esi = block data
sub TZXAvail, ebx ; ensure we have at least "block size" bytes available
jc OpenTapeFail
add esi, ebx ; advance to next PZX block
jmp NextPZXBlock
AppendPZXBlock:
mov dword ptr [edi], offset PZX_FinalPulse ; store PZX_FinalPulse PZX block pointer
mov dword ptr [edi+4], 0
jmp TapeInit
.data
PZX_FinalPulse db "****"
dd 0
.code
; initialise PZX block for playing
Init_PZX_Block:
mov esi, BlockData
mov eax, [esi] ; eax = PZX block ID
mov ecx, [esi+4] ; ecx = block size
add esi, 8 ; esi = block data
mov PZX.BlockData, esi
mov PZX.BlockSize, ecx
cmp eax, "SLUP"
je InitPZX_PULS
cmp eax, "ATAD"
je InitPZX_DATA
cmp eax, "SUAP"
je InitPZX_PAUS
cmp eax, "POTS"
je InitPZX_STOP
cmp eax, "****"
je InitPZX_FINAL
jmp IncPlayNextBlock ; skip unknown PZX block type
;PULS - Pulse sequence
;---------------------
;0 u16 count - bits 0-14 optional (see bit 15) repeat count, always greater than zero
; bit 15 repeat count present: 0 not present 1 present
;2 u16 duration1 - bits 0-14 low/high (see bit 15) pulse duration bits
; bit 15 duration encoding: 0 duration1 1 ((duration1<<16)+duration2)
;4 u16 duration2 - optional (see bit 15 of duration1) low bits of pulse duration
;... ditto repeated until the end of the block
align 16
InitPZX_PULS:
ifc EarBit ne 0 then call FlipEar
NextPZX_PULS:
cmp PZX.BlockSize, 0
je IncPlayNextBlock
mov esi, PZX.BlockData
mov PZX.Count, 1
sub PZX.BlockSize, 2
jc IncPlayNextBlock
movzx eax, word ptr [esi] ; u16 count
add esi, 2
mov PZX.Duration, eax
.if eax > 8000h
and eax, 7FFFh
mov PZX.Count, eax
sub PZX.BlockSize, 2
jc IncPlayNextBlock
movzx eax, word ptr [esi] ; u16 duration1
add esi, 2
mov PZX.Duration, eax
.endif
.if eax >= 8000h
and eax, 7FFFh
shl eax, 16
sub PZX.BlockSize, 2
jc IncPlayNextBlock
mov ax, [esi] ; u16 duration2
mov PZX.Duration, eax
add esi, 2
.endif
mov PZX.BlockData, esi
.if PZX.Duration == 0
test PZX.Count, 1
.if !ZERO?
call FlipEar ; flip ear if count is odd
.endif
jmp NextPZX_PULS ; back for next pulse from block
.endif
.while PZX.Count > 0
dec PZX.Count
m2m PZX.Duration1, PZX.Duration
mov TZXJump, offset @F
@@: movzx eax, TapeTStates
mov ebx, PZX.Duration
sub ebx, eax
jbe @F
mov PZX.Duration, ebx
mov TapeTStates, 0
ret
@@: neg ebx
mov TapeTStates, bx
m2m PZX.Duration, PZX.Duration1
call FlipEar
.endw
jmp NextPZX_PULS
align 16
InitPZX_DATA:
lodsd
mov ecx, eax
and ecx, 7FFFFFFFh
mov PZX.NumDataStreamBits, ecx
and eax, (1 shl 31)
.if ZERO?
ifc EarBit ne 0 then call FlipEar
.else
ifc EarBit ne 64 then call FlipEar
.endif
lodsw
mov PZX.TailPulse, ax
lodsb
mov PZX.Data_p0, al
lodsb
mov PZX.Data_p1, al
mov PZX.Data_s0, esi
movzx eax, PZX.Data_p0
lea esi, [esi+eax*2]
mov PZX.Data_s1, esi
movzx eax, PZX.Data_p1
lea esi, [esi+eax*2]
mov PZX.DataStream, esi
mov PZX.BitNumber, 7
PZXData_NextDataBit:
cmp PZX.NumDataStreamBits, 0
je PZXData_TailPulse
dec PZX.NumDataStreamBits
mov esi, PZX.DataStream
movzx cx, PZX.BitNumber
bt [esi], cx
setc bh
sub cl, 1
adc esi, 0
and cl, 7
mov PZX.DataStream, esi
mov PZX.BitNumber, cl
.if bh == 0
mov esi, PZX.Data_s0
movzx eax, PZX.Data_p0
.else
mov esi, PZX.Data_s1
movzx eax, PZX.Data_p1
.endif
mov PZX.PulseSequence, esi
mov PZX.PulseCount, eax
PZXData_PulsesLoop:
cmp PZX.PulseCount, 0
je PZXData_NextDataBit
dec PZX.PulseCount
mov esi, PZX.PulseSequence
movzx eax, word ptr [esi]
add PZX.PulseSequence, 2
mov PZX.Duration, eax
.if PZX.Duration > 0
mov TZXJump, offset @F
@@: movzx eax, TapeTStates
mov ebx, PZX.Duration
sub ebx, eax
jbe @F
mov PZX.Duration, ebx
mov TapeTStates, 0
ret
@@: neg ebx
mov TapeTStates, bx
.endif
call FlipEar
jmp PZXData_PulsesLoop
PZXData_TailPulse:
.if PZX.TailPulse > 0
mov TZXJump, offset @F
@@: mov ax, TapeTStates
mov bx, PZX.TailPulse
sub bx, ax
jbe @F
mov PZX.TailPulse, bx
mov TapeTStates, 0
ret
@@: neg bx
mov TapeTStates, bx
.endif
jmp IncPlayNextBlock
align 16
InitPZX_PAUS:
lodsd
mov ecx, eax
and ecx, 7FFFFFFFh
mov PZX.Pause, ecx
and eax, (1 shl 31)
.if ZERO?
ifc EarBit ne 0 then call FlipEar
.else
ifc EarBit ne 64 then call FlipEar
.endif
mov TZXJump, offset PZXPauseDelay
PZXPauseDelay:
movzx eax, TapeTStates
mov ecx, PZX.Pause
sub ecx, eax
jbe @F
mov PZX.Pause, ecx
mov TapeTStates, 0
ret
@@: neg ecx
mov TapeTStates, cx
jmp IncPlayNextBlock
align 16
InitPZX_STOP:
switch word ptr [esi]
case 1
switch HardwareMode
case HW_16, HW_48, HW_TC2048, HW_TK90X
invoke StartStopTape
endsw
.else
invoke StartStopTape
endsw
jmp IncPlayNextBlock
; extend the final pulse before ending tape playback - allows for DATA blocks with TAIL pulses of 0...
align 16
InitPZX_FINAL:
mov TZXJump, offset @F
@@: mov ax, TapeTStates
sub ax, 1710
retcc c
mov TapeTStates, ax
jmp IncPlayNextBlock
OpenTAP_TZXFile:
invoke CloseTapeFile
invoke CreateFile, Filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL
ifc eax eq INVALID_HANDLE_VALUE then xor eax, eax
mov TapeFileHandle, eax
.if TapeFileHandle == 0
return FALSE
.endif
invoke GetFileSize, TapeFileHandle, NULL
.if (eax == -1) || (eax < 12)
jmp OpenTapeFail
.endif
mov _tapfilesize, eax
invoke GlobalAlloc, GMEM_FIXED or GMEM_ZEROINIT, _tapfilesize
cmp eax, NULL
je OpenTapeFail
mov _tapfileptr, eax
mov ReadStart, eax
mov eax, _tapfilesize
mov ReadLen, eax
call ReadTAPFile
cmp _tapfilesize, eax
jne OpenTapeFail
mov LastDataBlockPauseLocation, 0 ; init last data block pause ptr to zero
mov esi, [_tapfileptr]
lea edi, _ZXTape_str
mov cl, 7
@@: mov al, [edi]
inc edi
cmp al, [esi]
jne TapeisTAP
inc esi
dec cl
jnz @B
TapeisTZX: mov LoadTapeType, Type_TZX
mov edi, [TZXBlockPtrs] ; store our block pointers here
mov esi, [_tapfileptr] ; start of tzx file in memory
mov edx, esi
add edx, [_tapfilesize] ; end of tzx file area
add esi, 10 ; skip to body of first block
NextTZXBlock:
xor eax, eax
mov [edi], eax
cmp esi, edx
je TapeInit ; reached end of TZX file
jc NextTZXBl1 ; more TZX blocks to come
sub edi, 4
xor eax, eax
mov [edi], eax ; null invalid TZX block pointer
jmp TapeInit
NextTZXBl1: mov [edi], esi
add edi, 4
; set TZXAvail to the max available TZX bytes left
mov TZXAvail, @EVAL (edx - esi)
xor ebx, ebx
mov al, [esi]
inc esi
.if al == 10h
mov LastDataBlockPauseLocation, esi
inc TapeDataBlockCnt
.if TapeDataBlockCnt == 1
lea eax, [esi+2] ; ptr to TAP block data
mov FirstTAPBlockPtr, eax
.endif
mov bx, [esi+2]
add ebx, 4
add esi, ebx
jmp NextTZXBlock
.endif
.if al == 11h
lea ecx, [esi+13]
mov LastDataBlockPauseLocation, ecx
inc TapeDataBlockCnt
mov ebx, [esi+15]
and ebx, 00FFFFFFh
add ebx, 12h
add esi, ebx
jmp NextTZXBlock
.endif
.if al == 12h
inc TapeDataBlockCnt
add esi, 4
jmp NextTZXBlock
.endif
.if al == 13h
inc TapeDataBlockCnt
xor eax, eax
mov al, [esi]
inc esi
shl eax, 1
add esi, eax
jmp NextTZXBlock
.endif
.if al == 14h
inc TapeDataBlockCnt
lea ecx, [esi+5]
mov LastDataBlockPauseLocation, ecx
mov ebx, [esi+7]
and ebx, 00FFFFFFh
add ebx, 10
add esi, ebx
jmp NextTZXBlock
.endif
.if al == 15h
inc TapeDataBlockCnt
lea ecx, [esi+2]
mov LastDataBlockPauseLocation, ecx
mov ebx, [esi+5]
and ebx, 00FFFFFFh
add ebx, 8
add esi, ebx
jmp NextTZXBlock
.endif
.if al == 18h
inc TapeDataBlockCnt
mov eax, [esi]
add eax, 4
add esi, eax
jmp NextTZXBlock
.endif
.if al == 19h
inc TapeDataBlockCnt
ifc TZXAvail lt 18 then jmp OpenTapeFail
mov eax, [esi]
ifc TZXAvail lt eax then jmp OpenTapeFail
add eax, 4
add esi, eax
jmp NextTZXBlock
.endif
.if al == 20h
add esi, 2
jmp NextTZXBlock
.endif
.if al == 21h
mov bl, [esi]
inc ebx
add esi, ebx
jmp NextTZXBlock
.endif
.if al == 22h
jmp NextTZXBlock
.endif
.if al == 23h
add esi, 2
jmp NextTZXBlock
.endif
.if al == 24h
add esi, 2
jmp NextTZXBlock
.endif
.if al == 25h
jmp NextTZXBlock
.endif
.if al == 26h
mov bx, [esi]
shl ebx, 1
add ebx, 2
add esi, ebx
jmp NextTZXBlock
.endif
.if al == 27h
jmp NextTZXBlock
.endif
.if al == 28h
mov bx, [esi]
add ebx, 2
add esi, ebx
jmp NextTZXBlock
.endif
.if al == 2Ah
add esi, 4
jmp NextTZXBlock
.endif
.if al == 2Bh
add esi, 5
jmp NextTZXBlock
.endif
.if al == 30h
mov bl, [esi]
inc ebx
add esi, ebx
jmp NextTZXBlock
.endif
.if al == 31h
mov bl, [esi+1]
add ebx, 2
add esi, ebx
jmp NextTZXBlock
.endif
.if al == 32h
mov bx, [esi]
add ebx, 2
add esi, ebx
jmp NextTZXBlock
.endif
.if al == 33h
mov bl, [esi]
xor cx, cx
mov cl, bl
shl bx, 1
add bx, cx
inc ebx
add esi, ebx
jmp NextTZXBlock
.endif
.if al == 34h
add esi, 8
jmp NextTZXBlock
.endif
.if al == 35h
mov ebx, [esi+10h]
add ebx, 14h
add esi, ebx
jmp NextTZXBlock
.endif
.if al == 40h
mov ebx, [esi+1]
and ebx, 00FFFFFFh
add ebx, 4
add esi, ebx
jmp NextTZXBlock
.endif
.if al == 5Ah
add esi, 9
jmp NextTZXBlock
.endif
sub edi, 4
xor eax, eax
mov [edi], eax ; null ptr to unknown block type
jmp TapeInit
TapeisTAP: mov LoadTapeType, Type_TAP ; treat ALL blocks as Standard speed blocks (10h)
mov edi, TZXBlockPtrs
mov esi, _tapfileptr
mov edx, esi
add edx, _tapfilesize
@@: inc TapeDataBlockCnt
.if TapeDataBlockCnt == 1
mov FirstTAPBlockPtr, esi
.endif
mov [edi], esi
add edi, 4
movzx eax, word ptr [esi]
add eax, 2
add esi, eax
cmp esi, edx
jc @B
; if non-zero, the last block length overran the filesize, so we remove the last TAP block pointer to prevent a segfault
.if !ZERO?
sub edi, 4
.endif
xor eax, eax
mov [edi], eax
; come here when a tape (of any type) has been successfully inserted
TapeInit:
; terminate TZX files with a special pause block to complete the last edge
.if LoadTapeType == Type_TZX
mov [edi], offset TZX_End_Pause_Block
mov dword ptr [edi+4], 0
.endif
mov al, LoadTapeType
.if (al == Type_TAP) || (al == Type_TZX)
invoke CloseHandle, TapeFileHandle ; TAP and TZX files are closed upon loading
mov TapeFileHandle, 0
.endif
mov [TZXCurrBlock], 0
mov [TZXJump], offset PlayNextBlock
mov [TZXPause], 0
PULSE_LOW
mov esi, [TZXBlockPtrs]
xor cx, cx
@@: lodsd
or eax, eax
je @F
inc cx
jmp @B
@@: mov [TZXBlockCount], cx
return TRUE ; signal tape loaded successfully
OpenTapeFail:
invoke CloseTapeFile
ret
Is_TZX_Data_Block proc tzx_ID: BYTE
switch tzx_ID
case 10h..15h, 18h..19h
return True
endsw
return False
Is_TZX_Data_Block endp
Set_Tape_Pause proc uses esi edi ebx,
pauselen :WORD
.if LoadTapeType == Type_TZX
mov edi, TZXBlockPtrs
movzx ebx, TZXCurrBlock
.while True
inc ebx ; move beyond the current block
.break .if bx >= TZXBlockCount
mov esi, [edi+ebx*4]
or esi, esi
.break .if ZERO?
mov al, [esi]
.break .if (al == 20h) && (word ptr [esi+1] == 0) ; fall through to use 2 ms on STOP TAPE block
.if $fnc (Is_TZX_Data_Block, al) == True ; test current TZX block ID
mov ax, pauselen
mov TZXWantPause, ax
ret
.endif
.endw
mov TZXWantPause, 2