-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathnextlib.bas
More file actions
3819 lines (3321 loc) · 95.9 KB
/
nextlib.bas
File metadata and controls
3819 lines (3321 loc) · 95.9 KB
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
' vim:ts=4:et:
' ---------------------------------------------------------
' NextLib v8.00 - David Saphier / em00k 2024
' Help and thanks Boriel, Flash, Baggers, Britlion, Shiru, Mike Dailly
' Matt Davies for help on the fastPLotL2
' ---------------------------------------------------------
#ifndef __NEXTLIB__
#define __NEXTLIB__
#pragma push(case_insensitive)
#pragma case_insensitive = TRUE
#pragma zxnext = TRUE
' the following consts are courtesy of ped7g https://github.com/ped7g/SpecBong/blob/master/constants.i.asm
asm
BIT_UP equ 4 ; 16
BIT_DOWN equ 5 ; 32
BIT_LEFT equ 6 ; 64
BIT_RIGHT equ 7 ; 128
DIR_NONE equ %00000000
DIR_UP equ %00010000
DIR_DOWN equ %00100000
DIR_LEFT equ %01000000
DIR_RIGHT equ %10000000
DIR_UP_I equ %11101111
DIR_DOWN_I equ %11011111
DIR_LEFT_I equ %10111111
DIR_RIGHT_I equ %01111111
;-----------------------------------------------------------------------------
;-- I/O ports - ZX Spectrum classic (48, 128, Timex, Pentagon, ...) ports
ULA_P_FE equ $FE ; BORDER + MIC + BEEP + read Keyboard
TIMEX_P_FF equ $FF ; Timex video control port
ZX128_MEMORY_P_7FFD equ $7FFD ; ZX Spectrum 128 ports
ZX128_MEMORY_P_DFFD equ $DFFD
ZX128P3_MEMORY_P_1FFD equ $1FFD
AY_REG_P_FFFD equ $FFFD
AY_DATA_P_BFFD equ $BFFD
Z80_DMA_PORT_DATAGEAR equ $6B ; on ZXN the zxnDMA handles this in zxnDMA mode
Z80_DMA_PORT_MB02 equ $0B ; on ZXN the zxnDMA handles this in Zilog mode
DIVMMC_CONTROL_P_E3 equ $E3
SPI_CS_P_E7 equ $E7
SPI_DATA_P_EB equ $EB
KEMPSTON_MOUSE_X_P_FBDF equ $FBDF
KEMPSTON_MOUSE_Y_P_FFDF equ $FFDF
KEMPSTON_MOUSE_B_P_FADF equ $FADF ; kempston mouse wheel+buttons
KEMPSTON_JOY1_P_1F equ $1F
KEMPSTON_JOY2_P_37 equ $37
;-----------------------------------------------------------------------------
;-- I/O ports - ZX Spectrum NEXT specific ports
TBBLUE_REGISTER_SELECT_P_243B equ $243B
; -- port $243B = 9275 Read+Write (detection bitmask: %0010_0100_0011_1011)
; -- selects NextREG mapped at port TBBLUE_REGISTER_ACCESS_P_253B
TBBLUE_REGISTER_ACCESS_P_253B equ $253B
; -- port $253B = 9531 Read?+Write? (detection bitmask: %0010_0101_0011_1011)
; -- data for selected NextREG (read/write depends on the register selected)
; indexes into DAC_CHANNEL_* def-arrays, depending on the type of DAC you want to use
DAC_GS_COVOX_INDEX equ 1
DAC_PENTAGON_ATM_INDEX equ 2
DAC_SPECDRUM_INDEX equ 3
DAC_SOUNDRIVE1_INDEX equ 4
DAC_SOUNDRIVE2_INDEX equ 5
DAC_COVOX_INDEX equ 6
DAC_PROFI_COVOX_INDEX equ 7
; -- enable 8bit DACs with PERIPHERAL_3_NR_08, use DAC_*_INDEX to access particular set of ports
;DEFARRAY DAC_CHANNEL_A @@, @@, $FB, $DF, $1F, $F1, @@, $3F
;DEFARRAY DAC_CHANNEL_B @@, $B3, @@, @@, $0F, $F3, $0F, @@
;DEFARRAY DAC_CHANNEL_C @@, $B3, @@, @@, $4F, $F9, $4F, @@
;DEFARRAY DAC_CHANNEL_D @@, @@, $FB, $DF, $5F, $FB, @@, $5F
; -- like for example: ld bc,DAC_CHANNEL_B[DAC_PROFI_COVOX_INDEX]
I2C_SCL_P_103B equ $103B ; i2c bus port (clock) (write only?)
I2C_SDA_P_113B equ $113B ; i2c bus port (data) (read+write)
UART_TX_P_133B equ $133B ; UART tx port (read+write)
UART_RX_P_143B equ $143B ; UART rx port (read+write)
UART_CTRL_P_153B equ $153B ; UART control port (read+write)
ZILOG_DMA_P_0B equ $0B
ZXN_DMA_P_6B equ $6B
; -- port $6B = 107 Read+Write (detection bitmask: %xxxx_xxxx_0110_1011)
; - The zxnDMA is mostly compatible with Zilog DMA chip (Z8410) (at least
; as far as old ZX apps are concerned), but has many modifications.
; - core3.1.1 update - Zilog/zxnDMA mode is now selected by port number, not PERIPHERAL_2_NR_06!
; - core3.0 update - (REMOVED) specific behaviour details can be selected (PERIPHERAL_2_NR_06)
LAYER2_ACCESS_P_123B equ $123B
; -- port $123B = 4667 Read+Write (detection bitmask: %0001_0010_0011_1011)
; - see ports.txt or wiki for details (has become a bit more complex over time)
LAYER2_ACCESS_WRITE_OVER_ROM equ $01 ; map Layer2 bank into ROM area (0000..3FFF) for WRITE-only (reads as ROM)
LAYER2_ACCESS_L2_ENABLED equ $02 ; enable Layer2 (make banks form nextreg $12 visible)
LAYER2_ACCESS_READ_OVER_ROM equ $04 ; map Layer2 bank into ROM area (0000..3FFF) for READ-only
LAYER2_ACCESS_SHADOW_OVER_ROM equ $08 ; bank selected by bits 6-7 is from "shadow Layer 2" banks range (nextreg $13)
LAYER2_ACCESS_BANK_OFFSET equ $10 ; bit 2-0 is bank offset for current active mapping +0..+7 (other bits are reserved, use 0)
LAYER2_ACCESS_OVER_ROM_BANK_M equ $C0 ; (mask of) value 0..3 selecting bank mapped for R/W (Nextreg $12 or $13)
LAYER2_ACCESS_OVER_ROM_BANK_0 equ $00 ; screen lines 0..63 (256x192) or columns 0..63 (320x256) or columns 0..127 (640x256)
LAYER2_ACCESS_OVER_ROM_BANK_1 equ $40 ; screen lines 64..127 (256x192) or columns 64..127 (320x256) or columns 128..255 (640x256)
LAYER2_ACCESS_OVER_ROM_BANK_2 equ $80 ; screen lines 128..191 (256x192) or columns 128..191 (320x256) or columns 256..383 (640x256)
LAYER2_ACCESS_OVER_ROM_48K equ $C0 ; maps all 0..191 lines into $0000..$BFFF region (256x192) or 2/3 of columns in 320x256/640x256
SPRITE_STATUS_SLOT_SELECT_P_303B equ $303B
; -- port $303B = 12347 Read+Write (detection bitmask: %0011_0000_0011_1011)
; -- write:
; - sets both "sprite slot" (0..63) and "pattern slot" (0..63 +128)
; - once the sprite/pattern slots are set, they act independently and
; each port ($xx57 and $xx5B) will auto-increment its own slot index
; (to resync one can write to this port again).
; - the +128 flag will make the pattern upload start at byte 128 of pattern
; slot (second half of slot)
; - The sprite-slot (sprite-attributes) may be optionally interlinked with
; NextReg $34 (feature controlled by NextReg $34)
; - auto-increments of slot position from value 63 are officially
; "undefined behaviour", wrap to 0 is not guaranteed. (only setting slots
; explicitly back to valid 0..63 will make your code future-proof)
; -- read (will also reset both collision and max-sprites flags):
; - bit 1 = maximum sprites per line hit (set when sprite renderer ran
; out of time when preparing next scanline)
; - bit 0 = collision flag (set when any sprites draw non-transparent
; pixel at the same location)
; Both flags contain values for current scanline already at the beginning
; of scanline (sprite engine renders one line ahead into buffer and updates
; flags progressively as it renders the sprites)
SPRITE_STATUS_MAXIMUM_SPRITES equ $02
SPRITE_STATUS_COLLISION equ $01
SPRITE_SLOT_SELECT_PATTERN_HALF equ 128 ; add it to 0..63 index to make pattern upload start at second half of pattern
SPRITE_ATTRIBUTE_P_57 equ $57
; -- port $xx57 = 87 write-only (detection bitmask: %xxxx_xxxx_0101_0111)
; - writing 4 or 5 bytes long structures to control particular sprite
; - after 4/5 bytes block the sprite slot index is auto-incremented
; - for detailed documentation check official docs or wiki (too long)
SPRITE_PATTERN_P_5B equ $5B
; -- port $xx5B = 91 write-only (detection bitmask: %xxxx_xxxx_0101_1011)
; - each pattern slot is 256 bytes long = one 16x16 pattern of 8-bit pixels
; or two 16x16 patterns of 4-bit pixels.
; - Patterns are uploaded in "English" order (left to right, top to bottom),
; one byte encodes single pixel in 8 bit mode and two pixels in 4 bit
; mode (bits 7-4 are "left" pixel, 3-0 are "right" pixel)
; - pixels are offset (index) into active sprite palette
TURBO_SOUND_CONTROL_P_FFFD equ $FFFD ; write with bit 7 = 1 (port shared with AY)
;-----------------------------------------------------------------------------
;-- NEXT HW Registers (NextReg)
MACHINE_ID_NR_00 equ $00
NEXT_VERSION_NR_01 equ $01
NEXT_RESET_NR_02 equ $02
MACHINE_TYPE_NR_03 equ $03
ROM_MAPPING_NR_04 equ $04 ;In config mode, allows RAM to be mapped to ROM area.
PERIPHERAL_1_NR_05 equ $05 ;Sets joystick mode, video frequency and Scandoubler.
PERIPHERAL_2_NR_06 equ $06 ;Enables turbo/50Hz/60Hz keys, DivMMC, Multiface and audio (beep/AY)
TURBO_CONTROL_NR_07 equ $07
PERIPHERAL_3_NR_08 equ $08 ;ABC/ACB Stereo, Internal Speaker, SpecDrum, Timex Video Modes, Turbo Sound Next, RAM contention and [un]lock 128k paging.
PERIPHERAL_4_NR_09 equ $09 ;Sets scanlines, AY mono output, Sprite-id lockstep, disables Kempston and divMMC ports.
PERIPHERAL_5_NR_0A equ $0A ;Mouse buttons and DPI settings (core 3.1.5)
NEXT_VERSION_MINOR_NR_0E equ $0E
ANTI_BRICK_NR_10 equ $10
VIDEO_TIMING_NR_11 equ $11
LAYER2_RAM_BANK_NR_12 equ $12 ;bank number where visible Layer 2 video memory begins.
LAYER2_RAM_SHADOW_BANK_NR_13 equ $13 ;bank number for "shadow" write-over-rom mapping
GLOBAL_TRANSPARENCY_NR_14 equ $14 ;Sets the color treated as transparent for ULA/Layer2/LoRes
SPRITE_CONTROL_NR_15 equ $15 ;LoRes mode, Sprites configuration, layers priority
; bit 7: enable LoRes mode
; bit 6: sprite rendering (1=sprite 0 on top of other, 0=sprite 0 at bottom)
; bit 5: If 1, the clipping works even in "over border" mode
; 4-2: layers priority: 000=SLU, 001=LSU, 010=SUL, 011=LUS, 100=USL, 101=ULS, 110=S,mix(U+L), 111=S,mix(U+L-5)
; bit 1: enable sprites over border, bit 0: show sprites
LAYER2_XOFFSET_NR_16 equ $16
LAYER2_YOFFSET_NR_17 equ $17
CLIP_LAYER2_NR_18 equ $18
CLIP_SPRITE_NR_19 equ $19
CLIP_ULA_LORES_NR_1A equ $1A
CLIP_TILEMAP_NR_1B equ $1B
CLIP_WINDOW_CONTROL_NR_1C equ $1C ;set to 15 to reset all clip-window indices to 0
VIDEO_LINE_MSB_NR_1E equ $1E
VIDEO_LINE_LSB_NR_1F equ $1F
VIDEO_INTERUPT_CONTROL_NR_22 equ $22 ;Controls the timing of raster interrupts and the ULA frame interrupt.
VIDEO_INTERUPT_VALUE_NR_23 equ $23
ULA_XOFFSET_NR_26 equ $26 ;since core 3.0
ULA_YOFFSET_NR_27 equ $27 ;since core 3.0
HIGH_ADRESS_KEYMAP_NR_28 equ $28 ;reads first 8b part of value written to $44 (even unfinished 16b write)
LOW_ADRESS_KEYMAP_NR_29 equ $29
HIGH_DATA_TO_KEYMAP_NR_2A equ $2A
LOW_DATA_TO_KEYMAP_NR_2B equ $2B
DAC_B_MIRROR_NR_2C equ $2C ;reads as MSB of Pi I2S left side sample, LSB waits at $2D
DAC_AD_MIRROR_NR_2D equ $2D ;another alias for $2D, reads LSB of value initiated by $2C or $2E read
SOUNDDRIVE_DF_MIRROR_NR_2D equ $2D ;Nextreg port-mirror of port 0xDF
DAC_C_MIRROR_NR_2E equ $2E ;reads as MSB of Pi I2S right side sample, LSB waits at $2D
TILEMAP_XOFFSET_MSB_NR_2F equ $2F
TILEMAP_XOFFSET_LSB_NR_30 equ $30
TILEMAP_YOFFSET_NR_31 equ $31
LORES_XOFFSET_NR_32 equ $32
LORES_YOFFSET_NR_33 equ $33
SPRITE_ATTR_SLOT_SEL_NR_34 equ $34 ;Sprite-attribute slot index for $35-$39/$75-$79 port $57 mirrors
SPRITE_ATTR0_NR_35 equ $35 ;port $57 mirror in nextreg space (accessible to copper)
SPRITE_ATTR1_NR_36 equ $36
SPRITE_ATTR2_NR_37 equ $37
SPRITE_ATTR3_NR_38 equ $38
SPRITE_ATTR4_NR_39 equ $39
PALETTE_INDEX_NR_40 equ $40 ;Chooses a ULANext palette number to configure.
PALETTE_VALUE_NR_41 equ $41 ;Used to upload 8-bit colors to the ULANext palette.
PALETTE_FORMAT_NR_42 equ $42 ;ink-mask for ULANext modes
PALETTE_CONTROL_NR_43 equ $43 ;Enables or disables ULANext interpretation of attribute values and toggles active palette.
PALETTE_VALUE_9BIT_NR_44 equ $44 ;Holds the additional blue color bit for RGB333 color selection.
TRANSPARENCY_FALLBACK_COL_NR_4A equ $4A ;8-bit colour to be drawn when all layers are transparent
SPRITE_TRANSPARENCY_I_NR_4B equ $4B ;index of transparent colour in sprite palette (only bottom 4 bits for 4-bit patterns)
TILEMAP_TRANSPARENCY_I_NR_4C equ $4C ;index of transparent colour in tilemap graphics (only bottom 4 bits)
MMU0_0000_NR_50 equ $50 ;Set a Spectrum RAM page at position 0x0000 to 0x1FFF
MMU1_2000_NR_51 equ $51 ;Set a Spectrum RAM page at position 0x2000 to 0x3FFF
MMU2_4000_NR_52 equ $52 ;Set a Spectrum RAM page at position 0x4000 to 0x5FFF
MMU3_6000_NR_53 equ $53 ;Set a Spectrum RAM page at position 0x6000 to 0x7FFF
MMU4_8000_NR_54 equ $54 ;Set a Spectrum RAM page at position 0x8000 to 0x9FFF
MMU5_A000_NR_55 equ $55 ;Set a Spectrum RAM page at position 0xA000 to 0xBFFF
MMU6_C000_NR_56 equ $56 ;Set a Spectrum RAM page at position 0xC000 to 0xDFFF
MMU7_E000_NR_57 equ $57 ;Set a Spectrum RAM page at position 0xE000 to 0xFFFF
COPPER_DATA_NR_60 equ $60
COPPER_CONTROL_LO_NR_61 equ $61
COPPER_CONTROL_HI_NR_62 equ $62
COPPER_DATA_16B_NR_63 equ $63 ; same as $60, but waits for full 16b before write
VIDEO_LINE_OFFSET_NR_64 equ $64 ; (core 3.1.5)
ULA_CONTROL_NR_68 equ $68
DISPLAY_CONTROL_NR_69 equ $69
LORES_CONTROL_NR_6A equ $6A
TILEMAP_CONTROL_NR_6B equ $6B
TILEMAP_DEFAULT_ATTR_NR_6C equ $6C
TILEMAP_BASE_ADR_NR_6E equ $6E ;Tilemap base address of map
TILEMAP_GFX_ADR_NR_6F equ $6F ;Tilemap definitions (graphics of tiles)
LAYER2_CONTROL_NR_70 equ $70
LAYER2_XOFFSET_MSB_NR_71 equ $71 ; for 320x256 and 640x256 L2 modes (core 3.0.6+)
SPRITE_ATTR0_INC_NR_75 equ $75 ;port $57 mirror in nextreg space (accessible to copper) (slot index++)
SPRITE_ATTR1_INC_NR_76 equ $76
SPRITE_ATTR2_INC_NR_77 equ $77
SPRITE_ATTR3_INC_NR_78 equ $78
SPRITE_ATTR4_INC_NR_79 equ $79
USER_STORAGE_0_NR_7F equ $7F
EXPANSION_BUS_ENABLE_NR_80 equ $80
EXPANSION_BUS_CONTROL_NR_81 equ $81
INTERNAL_PORT_DECODING_0_NR_82 equ $82 ;bits 0-7
INTERNAL_PORT_DECODING_1_NR_83 equ $83 ;bits 8-15
INTERNAL_PORT_DECODING_2_NR_84 equ $84 ;bits 16-23
INTERNAL_PORT_DECODING_3_NR_85 equ $85 ;bits 24-31
EXPANSION_BUS_DECODING_0_NR_86 equ $86 ;bits 0-7 mask
EXPANSION_BUS_DECODING_1_NR_87 equ $87 ;bits 8-15 mask
EXPANSION_BUS_DECODING_2_NR_88 equ $88 ;bits 16-23 mask
EXPANSION_BUS_DECODING_3_NR_89 equ $89 ;bits 24-31 mask
EXPANSION_BUS_PROPAGATE_NR_8A equ $8A ;Monitoring internal I/O or adding external keyboard
ALTERNATE_ROM_NR_8C equ $8C ;Enable alternate ROM or lock 48k ROM
ZX_MEM_MAPPING_NR_8E equ $8E ;shortcut to set classic zx128+3 memory model at one place
PI_GPIO_OUT_ENABLE_0_NR_90 equ $90 ;pins 0-7
PI_GPIO_OUT_ENABLE_1_NR_91 equ $91 ;pins 8-15
PI_GPIO_OUT_ENABLE_2_NR_92 equ $92 ;pins 16-23
PI_GPIO_OUT_ENABLE_3_NR_93 equ $93 ;pins 24-27
PI_GPIO_0_NR_98 equ $98 ;pins 0-7
PI_GPIO_1_NR_99 equ $99 ;pins 8-15
PI_GPIO_2_NR_9A equ $9A ;pins 16-23
PI_GPIO_3_NR_9B equ $9B ;pins 24-27
PI_PERIPHERALS_ENABLE_NR_A0 equ $A0
PI_I2S_AUDIO_CONTROL_NR_A2 equ $A2
;PI_I2S_CLOCK_DIVIDE_NR_A3 equ $A3 ; REMOVED in core 3.1.5 (no more master-mode)
ESP_WIFI_GPIO_OUTPUT_NR_A8 equ $A8
ESP_WIFI_GPIO_NR_A9 equ $A9
EXTENDED_KEYS_0_NR_B0 equ $B0 ;read Next compound keys as standalone keys (outside of zx48 matrix)
EXTENDED_KEYS_1_NR_B1 equ $B1 ;read Next compound keys as standalone keys (outside of zx48 matrix)
;DIVMMC_TRAP_ENABLE_1_NR_B2 equ $B2 ; NOT IMPLEMENTED in core yet (as of 3.1.4), may happen in future
;DIVMMC_TRAP_ENABLE_2_NR_B4 equ $B4 ; NOT IMPLEMENTED in core yet (as of 3.1.4), may happen in future
DEBUG_LED_CONTROL_NR_FF equ $FF ;Turns debug LEDs on and off on TBBlue implementations that have them.
;-----------------------------------------------------------------------------
;-- common memory addresses
MEM_ROM_CHARS_3C00 equ $3C00 ; actual chars start at $3D00 with space
MEM_ZX_SCREEN_4000 equ $4000
MEM_ZX_ATTRIB_5800 equ $5800
MEM_LORES0_4000 equ $4000
MEM_LORES1_6000 equ $6000
MEM_TIMEX_SCR0_4000 equ $4000
MEM_TIMEX_SCR1_6000 equ $6000
;-----------------------------------------------------------------------------
;-- Copper commands
COPPER_NOOP equ %00000000
COPPER_WAIT_H equ %10000000
COPPER_HALT_B equ $FF ; 2x $FF = wait for (511,63) = infinite wait
;-----------------------------------------------------------------------------
; DMA (Register 6)
DMA_RESET equ $C3
DMA_RESET_PORT_A_TIMING equ $C7
DMA_RESET_PORT_B_TIMING equ $CB
DMA_LOAD equ $CF
DMA_CONTINUE equ $D3
DMA_DISABLE_INTERUPTS equ $AF
DMA_ENABLE_INTERUPTS equ $AB
DMA_RESET_DISABLE_INTERUPTS equ $A3
DMA_ENABLE_AFTER_RETI equ $B7
DMA_READ_STATUS_BYTE equ $BF
DMA_REINIT_STATUS_BYTE equ $8B
DMA_START_READ_SEQUENCE equ $A7
DMA_FORCE_READY equ $B3
DMA_DISABLE equ $83
DMA_ENABLE equ $87
DMA_READ_MASK_FOLLOWS equ $BB
end asm
#DEFINE NextReg(REG,VAL) \
ASM\
DW $91ED\
DB REG\
DB VAL\
END ASM
#DEFINE OUTINB \
Dw $90ED
' old break macro
'define BREAK \
'DB $c5,$DD,$01,$0,$0,$c1 \
#define BREAK \
DB $c5,$FD,$00,$0,$0,$c1 \
#define BBREAK \
ASM\
BREAK\
END ASM
#DEFINE MUL_DE \
DB $ED,$30\
#DEFINE SWAPNIB \
DB $ED,$23
#DEFINE ADD_HL_A \
DB $ED,$31\
#DEFINE PIXELADD \
DB $ED,$94\
#DEFINE SETAE \
DB $ED,$95\
#DEFINE PIXELDN \
DB $ED,$93\
#DEFINE TEST val \
DB $ED,$27\
DB val
#DEFINE ADDBC value \
DB $ED,$36\
DW value
#DEFINE ADDHLA \
DB $ED,$31\
#DEFINE ADDDEA \
DB $ED,$32\
#DEFINE ADDBCA \
DB $ED,$33\
#DEFINE PUSHD value \
DB $ED,$8A\
DW value
#DEFINE DIHALT \
ASM\
di\
halt\
end asm
#DEFINE nnextreg reg,value\
ASM\
dw $91ed\
db reg\
db value\
end asm\
#DEFINE nextregna reg \
dw $92ed \
db reg
#DEFINE ESXDOS \
rst 8
#DEFINE getreg(REG) \
db $3e,REG,$01,$3b,$24,$ed,$79,$04,$ed,$78
#Define ReenableInts \
ld a,(itbuff) : or a : jr z,$+3 : ei
#Define EnableSFX \
asm : ld a,1 : ld (sfxenablednl),a : end asm
#Define DisableSFX \
asm : xor a : ld (sfxenablednl),a : end asm
#Define EnableMusic \
asm : ld a,1 : ld (sfxenablednl+1),a : end asm
#Define DisableMusic \
asm : ld a,2 : ld (sfxenablednl+1),a : end asm
asm
M_GETSETDRV equ $89
F_OPEN equ $9a
F_CLOSE equ $9b
F_READ equ $9d
F_WRITE equ $9e
F_SEEK equ $9f
F_STAT equ $a1
F_SIZE equ $ac
FA_READ equ $01
FA_APPEND equ $06
FA_OVERWRITE equ $0C
LAYER2_ACCESS_PORT EQU $123B
end asm
'border 0 : paper 0: ink 7 : cls
Sub MMU8(byval nn as ubyte, byval na as ubyte)
asm
PROC
LOCAL NREG
LD a,(IX+5) ; slot
add a,$50 ; NextREG $50 - $57 for slot
ld (NREG),a ; store at NREG
LD a,(IX+7) ; get memory bank selected
DW $92ED ; lets select correctly slot
NREG: DB 0 ;
ENDP
end asm
end sub
Sub fastcall MMU8new(byval slot as ubyte, byval memorybank as ubyte)
' changes 8kb slots valid slots 0-7 mapped as below
' banks 16 - 223
' Area 16k 8k def
' $0000-$1fff 1 0 ROM ROM (255) Normally ROM. Writes mappable by layer 2. IRQ and NMI routines here.
' $2000-$3fff 1 ROM (255) Normally ROM. Writes mapped by Layer 2.
' $4000-$5fff 2 2 5 10 Normally used for normal/shadow ULA screen.
' $6000-$7fff 3 11 Timex ULA extended attribute/graphics area.
' $8000-$9fff 3 4 2 4 Free RAM.
' $a000-$bfff 5 5 Free RAM.
' $c000-$dfff 4 6 0 0 Free RAM. Only this area is remappable by 128 memory management.
' $e000-$ffff 7 1 Free RAM. Only this area is remappable by 128 memory management.
'
' 16kb 8kb
' 8-15 16-31 $060000-$07ffff 128K Extra RAM
' 16-47 32-95 $080000-$0fffff 512K 1st extra IC RAM (available on unexpanded Next)
' 48-79 96-159 $100000-$17ffff 512K 2nd extra IC RAM (only available on expanded Next)
' 80-111 160-223 $180000-$1fffff 512K 3rd extra IC RAM (only available on expanded Next)'
' Fastcall a is first param, next on stack
asm
;BREAK
PROC
LOCAL NREG
add a,$50 ; A= 1st param so add $50 for MMU $50-$57
ld (NREG),a ; store at NREG
pop de ; dont need this but need off the stack
pop af ; get second param in af, this will be the bank
DW $92ED ; lets select correctly slot
NREG: DB 0 ;
push de ; fix stack before leaving
ENDP
end asm
end sub
Sub fastcall MMU16(byval memorybank as ubyte)
' changes 16kb 128k style bank @ $c000, supports full ram
' now works slots 6 and 7 will be changed
' asm
' ; bank 16-31 32-95 96-159 169-223
' ;BREAK
' ld d,a ; 4
' AND %00000111 ; 4
' ld bc,$7ffd ; 10
' out (c),a ; 12
' ;and 248
' ;ld (23388),a
' ld a,d ; 4
' AND %11110000 ; 4
' SWAPNIB ; 16
' ld b,$df ; 7
' out (c),a ; 12 = 73 t states
' end asm
' old routine before optimization
' ; bank 16-31 32-95 96-159 169-223
asm
ld a,(IX+5) ; 19 ts
;BREAK
AND %00000111 ; 4
ld bc,$7ffd ; 10
out (c),a ; 12
ld a,(IX+5) ; 19
AND %11110000 ; 4
srl a ; 8
srl a ; 8
srl a ; 8
srl a ; 8
ld bc,$dffd ; 10
out (c),a ; 12 = 122
end asm
end sub
Function fastcall GetMMU(byval slot as ubyte) as ubyte
asm
ld bc,$243B ; Register Select
add a,$50 ; a = slot already so add $50 for slot regs
out(c),a ;
ld bc,$253B ; reg access
in a,(c)
end asm
END function
function fastcall checkints() as ubyte
asm
start:
; Detect if interrupts were enabled
; The value of IFF2 is copied to the P/V flag by LD A,I and LD A,R.
ex af,af'
ld a,i
ld a,r
jp po,intsdisable
ld a,1 ; ints on
ld (itbuff),a
ex af,af'
ret
intsdisable:
xor a ; ints off
ld (itbuff),a
ex af,af'
ret
itbuff:
db 0
end asm
end function
Function GetReg(byval slot as ubyte) as ubyte
asm
push bc
ld bc,$243B ; Register Select
out(c),a ;
ld bc,$253B ; reg access
in a,(c)
pop bc
end asm
END function
sub Debug(BYVAL x as UBYTE,byval y as ubyte, s as string)
' fast print, doesnt need the print library '
asm
PROC
;BREAK
ld l,(IX+8) ; address string start containing string size
ld h,(IX+9)
push hl ; save this
ld b,0 ; flatten b
ld c,(hl) ; first byte is length of strin
push bc ; save it
CHAN_OPEN EQU 5633
ld a,2 ; upper screen
call CHAN_OPEN ; get the channel sorted
ld a,22 ; AT
rst 16 ; print
ld a,(IX+5) ; x
rst 16
ld a,(IX+7) ; y
rst 16
pop bc ; pop back length
pop de ; pop back start
inc de
inc de
call 8252 ; use rom print
ENDP
end asm
end sub
sub fastcall ShowLayer2(byval switch as ubyte)
' 0 to disable layer 2
' 1 to enable layer 2
asm
or a : jr z,disable
nextreg $69,%10000000
ret
disable:
nextreg $69,0
end asm
end sub
Sub fastcall ScrollLayer(byval x as ubyte,byval y as ubyte)
asm
PROC
pop hl ; store ret address
nextreg $16,a ; a has x
pop af
nextreg $17,a ; now a as y
push hl
ENDP
end asm
end sub
SUB fastcall PlotL2(byVal X as ubyte, byval Y as ubyte, byval T as ubyte)
ASM
; PlotL2 (c) 2020 David Saphier / em00k
;BREAK
;ld (outplot+1),bc
pop hl ; save return address off stack
ld e,a ; put a into e
ld bc,LAYER2_ACCESS_PORT
pop af ; pop stack into a = Y
ld d,a ; put into d
and $c0 ; yy00 0000
cp $c0
jr z,.skip_wrap1
jr .no_wrap
xor a
skip_wrap1:
pop af : jr skip_wrap2
.no_wrap:
end asm
LayerShadow:
asm
or 3 ; yy00 0011
out (c),a ; select 8k-bank
ld a,d ; yyyy yyyy
and 63 ; 00yy yyyy
ld d,a
pop af ; get colour/map value off stack
ld (de),a ; set pixel value
skip_wrap2:
ld a,2 ; 0000 0010
out (c),a ; Layer2 writes off
push hl ; restore return address
outplot:
;ld bc,0
; 6-7 Video RAM bank select
; 3 Shadow Layer 2 RAM select
; 1 Layer 2 visible
; 0 Enable Layer 2 write paging
END ASM
end sub
SUB fastcall PlotL2Shadow(byVal X as ubyte, byval Y as ubyte, byval T as ubyte)
ASM
;BREAK
ld bc,LAYER2_ACCESS_PORT
pop hl ; save return address
ld e,a ; put a into e
pop af ; pop stack into a
ld d,a ; put into d
and 192 ; yy00 0000
or 1 ; yy00 0011
out (c),a ; select 8k-bank
ld a,d ; yyyy yyyy
and 63 ; 00yy yyyy
ld d,a
pop af ; get colour/map value
ld (de),a ; set pixel value
ld a,0 ; 0000 0010
out (c),a ; select ROM?
push hl ; restore return address
END ASM
end sub
SUB fastcall CIRCLEL2(byval x as ubyte, byval y as ubyte, byval radius as ubyte, byval col as ubyte)
ASM
;BREAK
PROC
LOCAL __CIRCLEL2_LOOP
LOCAL __CIRCLEL2_NEXT
LOCAL __circle_col
LOCAL circdone
pop ix ; return address off stack
ld e,a ; x
pop af
ld d,a
pop af
ld h,a
pop af
ld (__circle_col+1),a
CIRCLEL2:
; __FASTCALL__ Entry: D, E = Y, X point of the center
; A = Radious
__CIRCLEL2:
push de
;ld h,a
ld a, h
exx
pop de ; D'E' = x0, y0
ld h, a ; H' = r
ld c, e
ld a, h
add a, d
ld b, a
call __CIRCLEL2_PLOT ; PLOT (x0, y0 + r)
ld b, d
ld a, h
add a, e
ld c, a
call __CIRCLEL2_PLOT ; PLOT (x0 + r, y0)
ld c, e
ld a, d
sub h
ld b, a
call __CIRCLEL2_PLOT ; PLOT (x0, y0 - r)
ld b, d
ld a, e
sub h
ld c, a
call __CIRCLEL2_PLOT ; PLOT (x0 - r, y0)
exx
ld b, 0 ; B = x = 0
ld c, h ; C = y = Radius
ld hl, 1
or a
sbc hl, bc ; HL = f = 1 - radius
ex de, hl
ld hl, 0
or a
sbc hl, bc ; HL = -radius
add hl, hl ; HL = -2 * radius
ex de, hl ; DE = -2 * radius = ddF_y, HL = f
xor a ; A = ddF_x = 0
ex af, af' ; Saves it
__CIRCLEL2_LOOP:
ld a, b
cp c
jp nc,circdone ; Returns when x >= y
bit 7, h ; HL >= 0? : if (f >= 0)...
jp nz, __CIRCLEL2_NEXT
dec c ; y--
inc de
inc de ; ddF_y += 2
add hl, de ; f += ddF_y
__CIRCLEL2_NEXT:
inc b ; x++
ex af, af'
add a, 2 ; 1 Cycle faster than inc a, inc a
inc hl ; f++
push af
add a, l
ld l, a
ld a, h
adc a, 0 ; f = f + ddF_x
ld h, a
pop af
ex af, af'
push bc
exx
pop hl ; H'L' = Y, X
ld a, d
add a, h
ld b, a ; B = y0 + y
ld a, e
add a, l
ld c, a ; C = x0 + x
call __CIRCLEL2_PLOT ; plot(x0 + x, y0 + y)
ld a, d
add a, h
ld b, a ; B = y0 + y
ld a, e
sub l
ld c, a ; C = x0 - x
call __CIRCLEL2_PLOT ; plot(x0 - x, y0 + y)
ld a, d
sub h
ld b, a ; B = y0 - y
ld a, e
add a, l
ld c, a ; C = x0 + x
call __CIRCLEL2_PLOT ; plot(x0 + x, y0 - y)
ld a, d
sub h
ld b, a ; B = y0 - y
ld a, e
sub l
ld c, a ; C = x0 - x
call __CIRCLEL2_PLOT ; plot(x0 - x, y0 - y)
ld a, d
add a, l
ld b, a ; B = y0 + x
ld a, e
add a, h
ld c, a ; C = x0 + y
call __CIRCLEL2_PLOT ; plot(x0 + y, y0 + x)
ld a, d
add a, l
ld b, a ; B = y0 + x
ld a, e
sub h
ld c, a ; C = x0 - y
call __CIRCLEL2_PLOT ; plot(x0 - y, y0 + x)
ld a, d
sub l
ld b, a ; B = y0 - x
ld a, e
add a, h
ld c, a ; C = x0 + y
call __CIRCLEL2_PLOT ; plot(x0 + y, y0 - x)
ld a, d
sub l
ld b, a ; B = y0 - x
ld a, e
sub h
ld c, a ; C = x0 + y
call __CIRCLEL2_PLOT ; plot(x0 - y, y0 - x)
exx
jp __CIRCLEL2_LOOP
__CIRCLEL2_PLOT:
push de
push af
ld e,c ; put b into e x
ld d,b ; put c into d y
ld a,d
ld bc,$123B
and 192 ; yy00 0000
or 3 ; yy00 0011
out (c),a ; select 8k-bank
ld a,d ; yyyy yyyy
and 63 ; 00yy yyyy
ld d,a
__circle_col:
ld a,255
ld (de),a ; set pixel value
ld a,2 ; 0000 0010
out (c),a ; select ROM?
pop af
pop de
ret
circdone:
push ix
; BREAK
ENDP
END ASM
end sub
Sub fastcall NextRegA(reg as ubyte,value as ubyte)
asm
PROC
LOCAL reg
;ld a,(IX+5) ; 19
ld (reg),a ; 17
;ld a,(IX+7) ; 19
pop hl ; 10
pop af ; 10
DW $92ED ; 20
reg:
db 0
push hl ; 11 68 T (old 75t)
ENDP
end asm
end sub
sub fastcall swapbank(byVal bank as ubyte)
asm
di ; disable ints
ld e,a
lD a,(23388)
AND 248
OR e ; select bank e
LD BC,32765
LD (23388),A
OUT (C),A
EI
END ASM
end sub
SUB zx7Unpack(source as uinteger, dest AS uinteger)
' dzx7 by einar saukas et al '
' source address, destination address
ASM
; push hl
; push ix
; LD L, (IX+4)
; LD H, (IX+5)
LD E, (IX+6)
LD D, (IX+7)
call dzx7_turbo
jp zx7end
dzx7_turbo:
ld a, $80
dzx7s_copy_byte_loop:
ldi ; copy literal byte
dzx7s_main_loop:
call dzx7s_next_bit
jr nc, dzx7s_copy_byte_loop ; next bit indicates either literal or sequence
; determine number of bits used for length (Elias gamma coding)
push de
ld bc, 0
ld d, b
dzx7s_len_size_loop:
inc d
call dzx7s_next_bit
jr nc, dzx7s_len_size_loop
; determine length
dzx7s_len_value_loop:
call nc, dzx7s_next_bit
rl c
rl b
jr c, dzx7s_exit ; check end marker
dec d
jr nz, dzx7s_len_value_loop
inc bc ; adjust length
; determine offset
ld e, (hl) ; load offset flag (1 bit) + offset value (7 bits)
inc hl
defb $cb, $33 ; opcode for undocumented instruction "SLL E" aka "SLS E"
jr nc, dzx7s_offset_end ; if offset flag is set, load 4 extra bits
ld d, $10 ; bit marker to load 4 bits
dzx7s_rld_next_bit:
call dzx7s_next_bit
rl d ; insert next bit into D
jr nc, dzx7s_rld_next_bit ; repeat 4 times, until bit marker is out
inc d ; add 128 to DE
srl d ; retrieve fourth bit from D
dzx7s_offset_end:
rr e ; insert fourth bit into E
; copy previous sequence
ex (sp), hl ; store source, restore destination
push hl ; store destination
sbc hl, de ; HL = destination - offset - 1
pop de ; DE = destination
ldir
dzx7s_exit:
pop hl ; restore source address (compressed data)
jr nc, dzx7s_main_loop
dzx7s_next_bit:
add a, a ; check next bit
ret nz ; no more bits left?
ld a, (hl) ; load another group of 8 bits