forked from antoniovillena/CargandoLeches
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathtorpes.asm
20295 lines (16230 loc) · 794 KB
/
torpes.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
define consta $69
org $0000
output torpes.rom
;*****************************************
;** Part 1. RESTART ROUTINES AND TABLES **
;*****************************************
; -----------
; THE 'START'
; -----------
; At switch on, the Z80 chip is in Interrupt Mode 0.
; The Spectrum uses Interrupt Mode 1.
; This location can also be 'called' to reset the machine.
; Typically with PRINT USR 0.
;; START
L0000: DI ; Disable Interrupts.
XOR A ; Signal coming from START.
ld hl, $ffff ; Set pointer to top of possible physical RAM.
jp L11C8 ; Jump forward to common code at START-NEW.
; -------------------
; THE 'ERROR' RESTART
; -------------------
; The error pointer is made to point to the position of the error to enable
; the editor to highlight the error position if it occurred during syntax
; checking. It is used at 37 places in the program. An instruction fetch
; on address $0008 may page in a peripheral ROM such as the Sinclair
; Interface 1 or Disciple Disk Interface. This was not an original design
; concept and not all errors pass through here.
;; ERROR-1
L0008: LD HL,($5C5D) ; Fetch the character address from CH_ADD.
LD ($5C5F),HL ; Copy it to the error pointer X_PTR.
JR L0053 ; Forward to continue at ERROR-2.
; -----------------------------
; THE 'PRINT CHARACTER' RESTART
; -----------------------------
; The A register holds the code of the character that is to be sent to
; the output stream of the current channel. The alternate register set is
; used to output a character in the A register so there is no need to
; preserve any of the current main registers (HL, DE, BC).
; This restart is used 21 times.
;; PRINT-A
L0010: JP L15F2 ; Jump forward to continue at PRINT-A-2.
; ---
DEFB $FF, $FF, $FF ; Five unused locations.
DEFB $FF, $FF ;
; -------------------------------
; THE 'COLLECT CHARACTER' RESTART
; -------------------------------
; The contents of the location currently addressed by CH_ADD are fetched.
; A return is made if the value represents a character that has
; relevance to the BASIC parser. Otherwise CH_ADD is incremented and the
; tests repeated. CH_ADD will be addressing somewhere -
; 1) in the BASIC program area during line execution.
; 2) in workspace if evaluating, for example, a string expression.
; 3) in the edit buffer if parsing a direct command or a new BASIC line.
; 4) in workspace if accepting input but not that from INPUT LINE.
;; GET-CHAR
L0018: LD HL,($5C5D) ; fetch the address from CH_ADD.
LD A,(HL) ; use it to pick up current character.
;; TEST-CHAR
L001C: CALL L007D ; routine SKIP-OVER tests if the character is
; relevant.
RET NC ; Return if it is significant.
; ------------------------------------
; THE 'COLLECT NEXT CHARACTER' RESTART
; ------------------------------------
; As the BASIC commands and expressions are interpreted, this routine is
; called repeatedly to step along the line. It is used 83 times.
;; NEXT-CHAR
L0020: CALL L0074 ; routine CH-ADD+1 fetches the next immediate
; character.
JR L001C ; jump back to TEST-CHAR until a valid
; character is found.
; ---
DEFB $FF, $FF, $FF ; unused
; -----------------------
; THE 'CALCULATE' RESTART
; -----------------------
; This restart enters the Spectrum's internal, floating-point, stack-based,
; FORTH-like language.
; It is further used recursively from within the calculator.
; It is used on 77 occasions.
;; FP-CALC
L0028: JP L335B ; jump forward to the CALCULATE routine.
; ---
DEFB $FF, $FF, $FF ; spare - note that on the ZX81, space being a
DEFB $FF, $FF ; little cramped, these same locations were
; used for the five-byte end-calc literal.
; ------------------------------
; THE 'CREATE BC SPACES' RESTART
; ------------------------------
; This restart is used on only 12 occasions to create BC spaces
; between workspace and the calculator stack.
;; BC-SPACES
L0030: PUSH BC ; Save number of spaces.
LD HL,($5C61) ; Fetch WORKSP.
PUSH HL ; Save address of workspace.
JP L169E ; Jump forward to continuation code RESERVE.
; --------------------------------
; THE 'MASKABLE INTERRUPT' ROUTINE
; --------------------------------
; This routine increments the Spectrum's three-byte FRAMES counter fifty
; times a second (sixty times a second in the USA ).
; Both this routine and the called KEYBOARD subroutine use the IY register
; to access system variables and flags so a user-written program must
; disable interrupts to make use of the IY register.
;; MASK-INT
L0038: PUSH AF ; Save the registers that will be used but not
PUSH HL ; the IY register unfortunately.
LD HL,($5C78) ; Fetch the first two bytes at FRAMES1.
INC HL ; Increment lowest two bytes of counter.
LD ($5C78),HL ; Place back in FRAMES1.
LD A,H ; Test if the result was zero.
OR L ;
JR NZ,L0048 ; Forward, if not, to KEY-INT
INC (IY+$40) ; otherwise increment FRAMES3 the third byte.
; Now save the rest of the main registers and read and decode the keyboard.
;; KEY-INT
L0048: PUSH BC ; Save the other main registers.
PUSH DE ;
CALL L02BF ; Routine KEYBOARD executes a stage in the
; process of reading a key-press.
POP DE ;
POP BC ; Restore registers.
POP HL ;
POP AF ;
EI ; Enable Interrupts.
RET ; Return.
; ---------------------
; THE 'ERROR-2' ROUTINE
; ---------------------
; A continuation of the code at 0008.
; The error code is stored and after clearing down stacks, an indirect jump
; is made to MAIN-4, etc. to handle the error.
;; ERROR-2
L0053: POP HL ; drop the return address - the location
; after the RST 08H instruction.
LD L,(HL) ; fetch the error code that follows.
; (nice to see this instruction used.)
; Note. this entry point is used when out of memory at REPORT-4.
; The L register has been loaded with the report code but X-PTR is not
; updated.
;; ERROR-3
L0055: LD (IY+$00),L ; Store it in the system variable ERR_NR.
LD SP,($5C3D) ; ERR_SP points to an error handler on the
; machine stack. There may be a hierarchy
; of routines.
; To MAIN-4 initially at base.
; or REPORT-G on line entry.
; or ED-ERROR when editing.
; or ED-FULL during ed-enter.
; or IN-VAR-1 during runtime input etc.
JP L16C5 ; Jump to SET-STK to clear the calculator stack
; and reset MEM to usual place in the systems
; variables area and then indirectly to MAIN-4,
; etc.
; ---
DEFB $FF, $FF, $FF ; Unused locations
DEFB $FF, $FF, $FF ; before the fixed-position
DEFB $FF ; NMI routine.
; ------------------------------------
; THE 'NON-MASKABLE INTERRUPT' ROUTINE
; ------------------------------------
;
; There is no NMI switch on the standard Spectrum or its peripherals.
; When the NMI line is held low, then no matter what the Z80 was doing at
; the time, it will now execute the code at 66 Hex.
; This Interrupt Service Routine will jump to location zero if the contents
; of the system variable NMIADD are zero or return if the location holds a
; non-zero address. So attaching a simple switch to the NMI as in the book
; "Spectrum Hardware Manual" causes a reset. The logic was obviously
; intended to work the other way. Sinclair Research said that, since they
; had never advertised the NMI, they had no plans to fix the error "until
; the opportunity arose".
;
; Note. The location NMIADD was, in fact, later used by Sinclair Research
; to enhance the text channel on the ZX Interface 1.
; On later Amstrad-made Spectrums, and the Brazilian Spectrum, the logic of
; this routine was indeed reversed but not as at first intended.
;
; It can be deduced by looking elsewhere in this ROM that the NMIADD system
; variable pointed to L121C and that this enabled a Warm Restart to be
; performed at any time, even while playing machine code games, or while
; another Spectrum has been allowed to gain control of this one.
;
; Software houses would have been able to protect their games from attack by
; placing two zeros in the NMIADD system variable.
;; RESET
L0066: PUSH AF ; save the
PUSH HL ; registers.
LD HL,($5CB0) ; fetch the system variable NMIADD.
LD A,H ; test address
OR L ; for zero.
JR NZ,L0070 ; skip to NO-RESET if NOT ZERO
JP (HL) ; jump to routine ( i.e. L0000 )
;; NO-RESET
L0070: POP HL ; restore the
POP AF ; registers.
RETN ; return to previous interrupt state.
; ---------------------------
; THE 'CH ADD + 1' SUBROUTINE
; ---------------------------
; This subroutine is called from RST 20, and three times from elsewhere
; to fetch the next immediate character following the current valid character
; address and update the associated system variable.
; The entry point TEMP-PTR1 is used from the SCANNING routine.
; Both TEMP-PTR1 and TEMP-PTR2 are used by the READ command routine.
;; CH-ADD+1
L0074: LD HL,($5C5D) ; fetch address from CH_ADD.
;; TEMP-PTR1
L0077: INC HL ; increase the character address by one.
;; TEMP-PTR2
L0078: LD ($5C5D),HL ; update CH_ADD with character address.
X007B: LD A,(HL) ; load character to A from HL.
RET ; and return.
; --------------------------
; THE 'SKIP OVER' SUBROUTINE
; --------------------------
; This subroutine is called once from RST 18 to skip over white-space and
; other characters irrelevant to the parsing of a BASIC line etc. .
; Initially the A register holds the character to be considered
; and HL holds its address which will not be within quoted text
; when a BASIC line is parsed.
; Although the 'tab' and 'at' characters will not appear in a BASIC line,
; they could be present in a string expression, and in other situations.
; Note. although white-space is usually placed in a program to indent loops
; and make it more readable, it can also be used for the opposite effect and
; spaces may appear in variable names although the parser never sees them.
; It is this routine that helps make the variables 'Anum bEr5 3BUS' and
; 'a number 53 bus' appear the same to the parser.
;; SKIP-OVER
L007D: CP $21 ; test if higher than space.
RET NC ; return with carry clear if so.
CP $0D ; carriage return ?
RET Z ; return also with carry clear if so.
; all other characters have no relevance
; to the parser and must be returned with
; carry set.
CP $10 ; test if 0-15d
RET C ; return, if so, with carry set.
CP $18 ; test if 24-32d
CCF ; complement carry flag.
RET C ; return with carry set if so.
; now leaves 16d-23d
INC HL ; all above have at least one extra character
; to be stepped over.
CP $16 ; controls 22d ('at') and 23d ('tab') have two.
JR C,L0090 ; forward to SKIPS with ink, paper, flash,
; bright, inverse or over controls.
; Note. the high byte of tab is for RS232 only.
; it has no relevance on this machine.
INC HL ; step over the second character of 'at'/'tab'.
;; SKIPS
L0090: SCF ; set the carry flag
LD ($5C5D),HL ; update the CH_ADD system variable.
RET ; return with carry set.
; ------------------
; THE 'TOKEN' TABLES
; ------------------
; The tokenized characters 134d (RND) to 255d (COPY) are expanded using
; this table. The last byte of a token is inverted to denote the end of
; the word. The first is an inverted step-over byte.
;; TKN-TABLE
L0095: DEFB '?'+$80
DEFM "RN"
DEFB 'D'+$80
DEFM "INKEY"
DEFB '$'+$80
DEFB 'P','I'+$80
DEFB 'F','N'+$80
DEFM "POIN"
DEFB 'T'+$80
DEFM "SCREEN"
DEFB '$'+$80
DEFM "ATT"
DEFB 'R'+$80
DEFB 'A','T'+$80
DEFM "TA"
DEFB 'B'+$80
DEFM "VAL"
DEFB '$'+$80
DEFM "COD"
DEFB 'E'+$80
DEFM "VA"
DEFB 'L'+$80
DEFM "LE"
DEFB 'N'+$80
DEFM "SI"
DEFB 'N'+$80
DEFM "CO"
DEFB 'S'+$80
DEFM "TA"
DEFB 'N'+$80
DEFM "AS"
DEFB 'N'+$80
DEFM "AC"
DEFB 'S'+$80
DEFM "AT"
DEFB 'N'+$80
DEFB 'L','N'+$80
DEFM "EX"
DEFB 'P'+$80
DEFM "IN"
DEFB 'T'+$80
DEFM "SQ"
DEFB 'R'+$80
DEFM "SG"
DEFB 'N'+$80
DEFM "AB"
DEFB 'S'+$80
DEFM "PEE"
DEFB 'K'+$80
DEFB 'I','N'+$80
DEFM "US"
DEFB 'R'+$80
DEFM "STR"
DEFB '$'+$80
DEFM "CHR"
DEFB '$'+$80
DEFM "NO"
DEFB 'T'+$80
DEFM "BI"
DEFB 'N'+$80
; The previous 32 function-type words are printed without a leading space
; The following have a leading space if they begin with a letter
DEFB 'O','R'+$80
DEFM "AN"
DEFB 'D'+$80
DEFB $3C,'='+$80 ; <=
DEFB $3E,'='+$80 ; >=
DEFB $3C,$3E+$80 ; <>
DEFM "LIN"
DEFB 'E'+$80
DEFM "THE"
DEFB 'N'+$80
DEFB 'T','O'+$80
DEFM "STE"
DEFB 'P'+$80
DEFM "DEF F"
DEFB 'N'+$80
DEFM "CA"
DEFB 'T'+$80
DEFM "FORMA"
DEFB 'T'+$80
DEFM "MOV"
DEFB 'E'+$80
DEFM "ERAS"
DEFB 'E'+$80
DEFM "OPEN "
DEFB '#'+$80
DEFM "CLOSE "
DEFB '#'+$80
DEFM "MERG"
DEFB 'E'+$80
DEFM "VERIF"
DEFB 'Y'+$80
DEFM "BEE"
DEFB 'P'+$80
DEFM "CIRCL"
DEFB 'E'+$80
DEFM "IN"
DEFB 'K'+$80
DEFM "PAPE"
DEFB 'R'+$80
DEFM "FLAS"
DEFB 'H'+$80
DEFM "BRIGH"
DEFB 'T'+$80
DEFM "INVERS"
DEFB 'E'+$80
DEFM "OVE"
DEFB 'R'+$80
DEFM "OU"
DEFB 'T'+$80
DEFM "LPRIN"
DEFB 'T'+$80
DEFM "LLIS"
DEFB 'T'+$80
DEFM "STO"
DEFB 'P'+$80
DEFM "REA"
DEFB 'D'+$80
DEFM "DAT"
DEFB 'A'+$80
DEFM "RESTOR"
DEFB 'E'+$80
DEFM "NE"
DEFB 'W'+$80
DEFM "BORDE"
DEFB 'R'+$80
DEFM "CONTINU"
DEFB 'E'+$80
DEFM "DI"
DEFB 'M'+$80
DEFM "RE"
DEFB 'M'+$80
DEFM "FO"
DEFB 'R'+$80
DEFM "GO T"
DEFB 'O'+$80
DEFM "GO SU"
DEFB 'B'+$80
DEFM "INPU"
DEFB 'T'+$80
DEFM "LOA"
DEFB 'D'+$80
DEFM "LIS"
DEFB 'T'+$80
DEFM "LE"
DEFB 'T'+$80
DEFM "PAUS"
DEFB 'E'+$80
DEFM "NEX"
DEFB 'T'+$80
DEFM "POK"
DEFB 'E'+$80
DEFM "PRIN"
DEFB 'T'+$80
DEFM "PLO"
DEFB 'T'+$80
DEFM "RU"
DEFB 'N'+$80
DEFM "SAV"
DEFB 'E'+$80
DEFM "RANDOMIZ"
DEFB 'E'+$80
DEFB 'I','F'+$80
DEFM "CL"
DEFB 'S'+$80
DEFM "DRA"
DEFB 'W'+$80
DEFM "CLEA"
DEFB 'R'+$80
DEFM "RETUR"
DEFB 'N'+$80
DEFM "COP"
DEFB 'Y'+$80
; ----------------
; THE 'KEY' TABLES
; ----------------
; These six look-up tables are used by the keyboard reading routine
; to decode the key values.
;
; The first table contains the maps for the 39 keys of the standard
; 40-key Spectrum keyboard. The remaining key [SHIFT $27] is read directly.
; The keys consist of the 26 upper-case alphabetic characters, the 10 digit
; keys and the space, ENTER and symbol shift key.
; Unshifted alphabetic keys have $20 added to the value.
; The keywords for the main alphabetic keys are obtained by adding $A5 to
; the values obtained from this table.
;; MAIN-KEYS
L0205: DEFB $42 ; B
DEFB $48 ; H
DEFB $59 ; Y
DEFB $36 ; 6
DEFB $35 ; 5
DEFB $54 ; T
DEFB $47 ; G
DEFB $56 ; V
DEFB $4E ; N
DEFB $4A ; J
DEFB $55 ; U
DEFB $37 ; 7
DEFB $34 ; 4
DEFB $52 ; R
DEFB $46 ; F
DEFB $43 ; C
DEFB $4D ; M
DEFB $4B ; K
DEFB $49 ; I
DEFB $38 ; 8
DEFB $33 ; 3
DEFB $45 ; E
DEFB $44 ; D
DEFB $58 ; X
DEFB $0E ; SYMBOL SHIFT
DEFB $4C ; L
DEFB $4F ; O
DEFB $39 ; 9
DEFB $32 ; 2
DEFB $57 ; W
DEFB $53 ; S
DEFB $5A ; Z
DEFB $20 ; SPACE
DEFB $0D ; ENTER
DEFB $50 ; P
DEFB $30 ; 0
DEFB $31 ; 1
DEFB $51 ; Q
DEFB $41 ; A
;; E-UNSHIFT
; The 26 unshifted extended mode keys for the alphabetic characters.
; The green keywords on the original keyboard.
L022C: DEFB $E3 ; READ
DEFB $C4 ; BIN
DEFB $E0 ; LPRINT
DEFB $E4 ; DATA
DEFB $B4 ; TAN
DEFB $BC ; SGN
DEFB $BD ; ABS
DEFB $BB ; SQR
DEFB $AF ; CODE
DEFB $B0 ; VAL
DEFB $B1 ; LEN
DEFB $C0 ; USR
DEFB $A7 ; PI
DEFB $A6 ; INKEY$
DEFB $BE ; PEEK
DEFB $AD ; TAB
DEFB $B2 ; SIN
DEFB $BA ; INT
DEFB $E5 ; RESTORE
DEFB $A5 ; RND
DEFB $C2 ; CHR$
DEFB $E1 ; LLIST
DEFB $B3 ; COS
DEFB $B9 ; EXP
DEFB $C1 ; STR$
DEFB $B8 ; LN
;; EXT-SHIFT
; The 26 shifted extended mode keys for the alphabetic characters.
; The red keywords below keys on the original keyboard.
L0246: DEFB $7E ; ~
DEFB $DC ; BRIGHT
DEFB $DA ; PAPER
DEFB $5C ; \
DEFB $B7 ; ATN
DEFB $7B ; {
DEFB $7D ; }
DEFB $D8 ; CIRCLE
DEFB $BF ; IN
DEFB $AE ; VAL$
DEFB $AA ; SCREEN$
DEFB $AB ; ATTR
DEFB $DD ; INVERSE
DEFB $DE ; OVER
DEFB $DF ; OUT
DEFB $7F ; (Copyright character)
DEFB $B5 ; ASN
DEFB $D6 ; VERIFY
DEFB $7C ; |
DEFB $D5 ; MERGE
DEFB $5D ; ]
DEFB $DB ; FLASH
DEFB $B6 ; ACS
DEFB $D9 ; INK
DEFB $5B ; [
DEFB $D7 ; BEEP
;; CTL-CODES
; The ten control codes assigned to the top line of digits when the shift
; key is pressed.
L0260: DEFB $0C ; DELETE
DEFB $07 ; EDIT
DEFB $06 ; CAPS LOCK
DEFB $04 ; TRUE VIDEO
DEFB $05 ; INVERSE VIDEO
DEFB $08 ; CURSOR LEFT
DEFB $0A ; CURSOR DOWN
DEFB $0B ; CURSOR UP
DEFB $09 ; CURSOR RIGHT
DEFB $0F ; GRAPHICS
;; SYM-CODES
; The 26 red symbols assigned to the alphabetic characters of the keyboard.
; The ten single-character digit symbols are converted without the aid of
; a table using subtraction and minor manipulation.
L026A: DEFB $E2 ; STOP
DEFB $2A ; *
DEFB $3F ; ?
DEFB $CD ; STEP
DEFB $C8 ; >=
DEFB $CC ; TO
DEFB $CB ; THEN
DEFB $5E ; ^
DEFB $AC ; AT
DEFB $2D ; -
DEFB $2B ; +
DEFB $3D ; =
DEFB $2E ; .
DEFB $2C ; ,
DEFB $3B ; ;
DEFB $22 ; "
DEFB $C7 ; <=
DEFB $3C ; <
DEFB $C3 ; NOT
DEFB $3E ; >
DEFB $C5 ; OR
DEFB $2F ; /
DEFB $C9 ; <>
DEFB $60 ; pound
DEFB $C6 ; AND
DEFB $3A ; :
;; E-DIGITS
; The ten keywords assigned to the digits in extended mode.
; The remaining red keywords below the keys.
L0284: DEFB $D0 ; FORMAT
DEFB $CE ; DEF FN
DEFB $A8 ; FN
DEFB $CA ; LINE
DEFB $D3 ; OPEN #
DEFB $D4 ; CLOSE #
DEFB $D1 ; MOVE
DEFB $D2 ; ERASE
DEFB $A9 ; POINT
DEFB $CF ; CAT
;*******************************
;** Part 2. KEYBOARD ROUTINES **
;*******************************
; Using shift keys and a combination of modes the Spectrum 40-key keyboard
; can be mapped to 256 input characters
; ---------------------------------------------------------------------------
;
; 0 1 2 3 4 -Bits- 4 3 2 1 0
; PORT PORT
;
; F7FE [ 1 ] [ 2 ] [ 3 ] [ 4 ] [ 5 ] | [ 6 ] [ 7 ] [ 8 ] [ 9 ] [ 0 ] EFFE
; ^ | v
; FBFE [ Q ] [ W ] [ E ] [ R ] [ T ] | [ Y ] [ U ] [ I ] [ O ] [ P ] DFFE
; ^ | v
; FDFE [ A ] [ S ] [ D ] [ F ] [ G ] | [ H ] [ J ] [ K ] [ L ] [ ENT ] BFFE
; ^ | v
; FEFE [SHI] [ Z ] [ X ] [ C ] [ V ] | [ B ] [ N ] [ M ] [sym] [ SPC ] 7FFE
; ^ $27 $18 v
; Start End
; 00100111 00011000
;
; ---------------------------------------------------------------------------
; The above map may help in reading.
; The neat arrangement of ports means that the B register need only be
; rotated left to work up the left hand side and then down the right
; hand side of the keyboard. When the reset bit drops into the carry
; then all 8 half-rows have been read. Shift is the first key to be
; read. The lower six bits of the shifts are unambiguous.
; -------------------------------
; THE 'KEYBOARD SCANNING' ROUTINE
; -------------------------------
; From keyboard and s-inkey$
; Returns 1 or 2 keys in DE, most significant shift first if any
; key values 0-39 else 255
;; KEY-SCAN
L028E: LD L,$2F ; initial key value
; valid values are obtained by subtracting
; eight five times.
LD DE,$FFFF ; a buffer to receive 2 keys.
LD BC,$FEFE ; the commencing port address
; B holds 11111110 initially and is also
; used to count the 8 half-rows
;; KEY-LINE
L0296: IN A,(C) ; read the port to A - bits will be reset
; if a key is pressed else set.
CPL ; complement - pressed key-bits are now set
AND $1F ; apply 00011111 mask to pick up the
; relevant set bits.
JR Z,L02AB ; forward to KEY-DONE if zero and therefore
; no keys pressed in row at all.
LD H,A ; transfer row bits to H
LD A,L ; load the initial key value to A
;; KEY-3KEYS
L029F: INC D ; now test the key buffer
RET NZ ; if we have collected 2 keys already
; then too many so quit.
;; KEY-BITS
L02A1: SUB $08 ; subtract 8 from the key value
; cycling through key values (top = $27)
; e.g. 2F> 27>1F>17>0F>07
; 2E> 26>1E>16>0E>06
SRL H ; shift key bits right into carry.
JR NC,L02A1 ; back to KEY-BITS if not pressed
; but if pressed we have a value (0-39d)
LD D,E ; transfer a possible previous key to D
LD E,A ; transfer the new key to E
JR NZ,L029F ; back to KEY-3KEYS if there were more
; set bits - H was not yet zero.
;; KEY-DONE
L02AB: DEC L ; cycles 2F>2E>2D>2C>2B>2A>29>28 for
; each half-row.
RLC B ; form next port address e.g. FEFE > FDFE
JR C,L0296 ; back to KEY-LINE if still more rows to do.
LD A,D ; now test if D is still FF ?
INC A ; if it is zero we have at most 1 key
; range now $01-$28 (1-40d)
RET Z ; return if one key or no key.
CP $28 ; is it capsshift (was $27) ?
RET Z ; return if so.
CP $19 ; is it symbol shift (was $18) ?
RET Z ; return also
LD A,E ; now test E
LD E,D ; but first switch
LD D,A ; the two keys.
CP $18 ; is it symbol shift ?
RET ; return (with zero set if it was).
; but with symbol shift now in D
; ----------------------
; THE 'KEYBOARD' ROUTINE
; ----------------------
; Called from the interrupt 50 times a second.
;
;; KEYBOARD
L02BF: CALL L028E ; routine KEY-SCAN
RET NZ ; return if invalid combinations
; then decrease the counters within the two key-state maps
; as this could cause one to become free.
; if the keyboard has not been pressed during the last five interrupts
; then both sets will be free.
LD HL,$5C00 ; point to KSTATE-0
;; K-ST-LOOP
L02C6: BIT 7,(HL) ; is it free ? (i.e. $FF)
JR NZ,L02D1 ; forward to K-CH-SET if so
INC HL ; address the 5-counter
DEC (HL) ; decrease the counter
DEC HL ; step back
JR NZ,L02D1 ; forward to K-CH-SET if not at end of count
LD (HL),$FF ; else mark this particular map free.
;; K-CH-SET
L02D1: LD A,L ; make a copy of the low address byte.
LD HL,$5C04 ; point to KSTATE-4
; (ld l,$04 would do)
CP L ; have both sets been considered ?
JR NZ,L02C6 ; back to K-ST-LOOP to consider this 2nd set
; now the raw key (0-38d) is converted to a main key (uppercase).
CALL L031E ; routine K-TEST to get main key in A
RET NC ; return if just a single shift
LD HL,$5C00 ; point to KSTATE-0
CP (HL) ; does the main key code match ?
JR Z,L0310 ; forward to K-REPEAT if so
; if not consider the second key map.
EX DE,HL ; save kstate-0 in de
LD HL,$5C04 ; point to KSTATE-4
CP (HL) ; does the main key code match ?
JR Z,L0310 ; forward to K-REPEAT if so
; having excluded a repeating key we can now consider a new key.
; the second set is always examined before the first.
BIT 7,(HL) ; is the key map free ?
JR NZ,L02F1 ; forward to K-NEW if so.
EX DE,HL ; bring back KSTATE-0
BIT 7,(HL) ; is it free ?
RET Z ; return if not.
; as we have a key but nowhere to put it yet.
; continue or jump to here if one of the buffers was free.
;; K-NEW
L02F1: LD E,A ; store key in E
LD (HL),A ; place in free location
INC HL ; advance to the interrupt counter
LD (HL),$05 ; and initialize counter to 5
INC HL ; advance to the delay
LD A,($5C09) ; pick up the system variable REPDEL
LD (HL),A ; and insert that for first repeat delay.
INC HL ; advance to last location of state map.
LD C,(IY+$07) ; pick up MODE (3 bytes)
LD D,(IY+$01) ; pick up FLAGS (3 bytes)
PUSH HL ; save state map location
; Note. could now have used, to avoid IY,
; ld l,$41; ld c,(hl); ld l,$3B; ld d,(hl).
; six and two threes of course.
CALL L0333 ; routine K-DECODE
POP HL ; restore map pointer
LD (HL),A ; put the decoded key in last location of map.
;; K-END
L0308: LD ($5C08),A ; update LASTK system variable.
SET 5,(IY+$01) ; update FLAGS - signal a new key.
RET ; return to interrupt routine.
; -----------------------
; THE 'REPEAT KEY' BRANCH
; -----------------------
; A possible repeat has been identified. HL addresses the raw key.
; The last location of the key map holds the decoded key from the first
; context. This could be a keyword and, with the exception of NOT a repeat
; is syntactically incorrect and not really desirable.
;; K-REPEAT
L0310: INC HL ; increment the map pointer to second location.
LD (HL),$05 ; maintain interrupt counter at 5.
INC HL ; now point to third location.
DEC (HL) ; decrease the REPDEL value which is used to
; time the delay of a repeat key.
RET NZ ; return if not yet zero.
LD A,($5C0A) ; fetch the system variable value REPPER.
LD (HL),A ; for subsequent repeats REPPER will be used.
INC HL ; advance
;
LD A,(HL) ; pick up the key decoded possibly in another
; context.
; Note. should compare with $A5 (RND) and make
; a simple return if this is a keyword.
; e.g. cp $a5; ret nc; (3 extra bytes)
JR L0308 ; back to K-END
; ----------------------
; THE 'KEY-TEST' ROUTINE
; ----------------------
; also called from s-inkey$
; begin by testing for a shift with no other.
;; K-TEST
L031E: LD B,D ; load most significant key to B
; will be $FF if not shift.
LD D,$00 ; and reset D to index into main table
LD A,E ; load least significant key from E
CP $27 ; is it higher than 39d i.e. FF
RET NC ; return with just a shift (in B now)
CP $18 ; is it symbol shift ?
JR NZ,L032C ; forward to K-MAIN if not
; but we could have just symbol shift and no other
BIT 7,B ; is other key $FF (ie not shift)
RET NZ ; return with solitary symbol shift
;; K-MAIN
L032C: LD HL,L0205 ; address: MAIN-KEYS
ADD HL,DE ; add offset 0-38
LD A,(HL) ; pick up main key value
SCF ; set carry flag
RET ; return (B has other key still)
; ----------------------------------
; THE 'KEYBOARD DECODING' SUBROUTINE
; ----------------------------------
; also called from s-inkey$
;; K-DECODE
L0333: LD A,E ; pick up the stored main key
CP $3A ; an arbitrary point between digits and letters
JR C,L0367 ; forward to K-DIGIT with digits, space, enter.
DEC C ; decrease MODE ( 0='KLC', 1='E', 2='G')
JP M,L034F ; to K-KLC-LET if was zero
JR Z,L0341 ; to K-E-LET if was 1 for extended letters.
; proceed with graphic codes.
; Note. should selectively drop return address if code > 'U' ($55).
; i.e. abort the KEYBOARD call.
; e.g. cp 'V'; jr c,addit; pop af ;pop af ;;addit etc. (6 extra bytes).
; (s-inkey$ never gets into graphics mode.)
;; addit
ADD A,$4F ; add offset to augment 'A' to graphics A say.
RET ; return.
; Note. ( but [GRAPH] V gives RND, etc ).
; ---
; the jump was to here with extended mode with uppercase A-Z.
;; K-E-LET
L0341: LD HL,L022C-$41 ; base address of E-UNSHIFT L022c.
; ( $01EB in standard ROM ).
INC B ; test B is it empty i.e. not a shift.
JR Z,L034A ; forward to K-LOOK-UP if neither shift.
LD HL,L0246-$41 ; Address: $0205 L0246-$41 EXT-SHIFT base
;; K-LOOK-UP
L034A: LD D,$00 ; prepare to index.
ADD HL,DE ; add the main key value.
LD A,(HL) ; pick up other mode value.
RET ; return.
; ---
; the jump was here with mode = 0
;; K-KLC-LET
L034F: LD HL,L026A-$41 ; prepare base of sym-codes
BIT 0,B ; shift=$27 sym-shift=$18
JR Z,L034A ; back to K-LOOK-UP with symbol-shift
BIT 3,D ; test FLAGS is it 'K' mode (from OUT-CURS)
JR Z,L0364 ; skip to K-TOKENS if so
BIT 3,(IY+$30) ; test FLAGS2 - consider CAPS LOCK ?
RET NZ ; return if so with main code.
INC B ; is shift being pressed ?
; result zero if not
RET NZ ; return if shift pressed.
ADD A,$20 ; else convert the code to lower case.