-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathkernl80a.4th
1103 lines (1009 loc) · 21.1 KB
/
kernl80a.4th
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
\ This is the file kernl80a.4th, included by the cross compiler.
\ created 1994 by L.C. Benschop.
\ copyleft (c) 1994-2014 by the sbc09 team, see AUTHORS for more details.
\ Most Z80 primitives: ; Copyright (c) 1994,1995 Bradford J. Rodriguez
\ copyleft (c) 2022 L.C. Benschop for Cerberus 2080.
\ license: GNU General Public License version 3, see LICENSE for more details.
\ It is extensively commented as it must serve as an introduction to the
\ construction of Forth compilers.
\ Lines starting with \G are comments that are included in the glossary.
ALSO TRANSIENT DEFINITIONS
FORWARD THROW
FORWARD COLD
FORWARD WARM
PREVIOUS DEFINITIONS
ALSO ASSEMBLER DEFINITIONS
PREVIOUS DEFINITIONS
ASSEMBLE HEX
\ PART 0: Boot vectors.
ORIGIN ORG
C3 C, TRANSIENT COLD ASSEMBLER
C3 C, TRANSIENT WARM ASSEMBLER \ Jumps to cold and warm entry points.
ENDASM
DECIMAL
CROSS-COMPILE
\ PART 1: Runtime parts of defining words
\ Note: the NEXT and NEXTHL macros are defined in assmz80.4th.
\ NEXT is expanded in-line.
\ Run-time part for constants:
\ Gets Parameter field addres on data stack from CALL instruction.
LABEL DOCON
POP HL \ Get param address
PUSH BC \ Store old TOS
LD C, (HL)
INC HL
LD B, (HL) \ Loads new TOS from paramter field
NEXT
ENDASM
\ Run-time part for variables
LABEL DOVAR
POP HL \ Get param address
PUSH BC \ Store old TOS
LD C, L
LD B, H \ Param address to TOS
NEXT
ENDASM
\ Run-time part for colon definitions
\ Paramter addres will be new IP
LABEL DOCOL
DEC IX
LD 0 (IX+), D
DEC IX
LD 0 (IX+), E \ Push IP to return stack
POP HL \ Get paramter field addres, new IP
NEXTHL
ENDASM
\ Run-time part of CREATE DOES> defining words.
\ Each defined word contains a CALL to the part after DOES>, which
\ starts with a CALL to DODOES.
LABEL DODOES
DEC IX
LD 0 (IX+), D
DEC IX
LD 0 (IX+), E \ Push IP on return stack
POP HL \ New instruction ptr, thread after DOES>.
POP DE \ PFA of defined word, result of CALL to CALL DODOES
PUSH BC \ Push old
LD C, E
LD B, D \ PFA to TOS
NEXTHL
ENDASM
\ PART 2: Code definitions, laid out by compiler.
CODE LIT ( --- n)
\G Run-time part of LITERAL. Pushes next cell in instruction thread to stack.
PUSH BC \ Push old TOS
EX DE, HL \ IP now in HL
LD C, (HL)
INC HL
LD B, (HL) \ Load TOS from next cell in thread.
INC HL
NEXTHL
END-CODE
CODE BRANCH ( --- )
\G High-level unconditional jump, loads IP from next cell in instruction
\G thread
LABEL BR
EX DE, HL
LD E, (HL)
INC HL
LD D, (HL)
NEXT
END-CODE
CODE ?BRANCH ( f ---)
\G High-level conditonal jump, jumps only if TOS=0
LD A, C
OR B \ Test TOS=0
POP BC \ Pop next entry into TOS
JR Z, BR
INC DE \ skip branch address
INC DE
NEXT
END-CODE
CODE EXECUTE ( xt ---)
\G Execute the word with execution token xt.
LD L, C
LD H, B \ Move CFA to HL
POP BC \ Pop next stack entry into TOS
JP (HL) \ Jump to it
END-CODE
CODE EXIT ( --- )
\G Return from colon definition.
LD L, 0 (IX+)
INC IX
LD H, 0 (IX+) \ Pop IP from Return stack
INC IX
NEXTHL
END-CODE
CODE UNNEST ( --- )
\G Synonym for EXIT, used by compiler, so decompiler can use this as end of
\G colon definition.
LD L, 0 (IX+)
INC IX
LD H, 0 (IX+)
INC IX
NEXTHL
END-CODE
CODE (DO) ( n1 n2 ---)
\G Runtime part of DO. n2 is initial counter, n1 is limit
POP HL
LABEL DO1
LD A, L
LD L, C
LD C, A
LD A, H
XOR $80 \ XOR limit with 0x8000
LD H, B
LD B, A \ Swap BC and HL. start in HL, limit xor 0x8000 in BC
AND A
SBC HL, BC \ HL = start - (limit xor 0x8000)
DEC IX
LD 0 (IX+), B
DEC IX
LD 0 (IX+), C \ Push Limit ^ 0x8000 on return stack
DEC IX
LD 0 (IX+), H
DEC IX
LD 0 (IX+), L \ Push modified start value on return stack
\ terminate when crossing limit-1, limit in any directions.
\ End-of-loop condition is indicated by overflow flag when adding
\ modified loop variable.
\ regardless of positive or negative increment in +LOOP.
POP BC \ Load new TOS
NEXT
END-CODE
CODE (?DO) ( n1 n2 ---)
\G Runtime part of ?DO. n2 is initial counter, n1 is limit
\G The next cell contains a branch address to skip the
\G loop when limit and start are equal.
POP HL
AND A
SBC HL, BC \ Compare start and limit.
0<> IF
ADD HL, BC \ Add back to restore HL
INC DE
INC DE \ Skip branch address.
JR DO1 \ Continue into (DO) function.
THEN
POP BC \ Load new TOS
JP BR \ Branch beyond loop if operands were equal.
END-CODE
LABEL ENDLOOP
INC DE
INC DE \ Skip branch back address.
EX DE, HL
LD DE, 4
ADD IX, DE \ Remove 2 loop values from return stack
NEXTHL
ENDASM
CODE (LOOP) ( --- )
\G Runtime part of LOOP
PUSH BC
LD BC, 1
LABEL LOOP1
LD L, 0 (IX+)
LD H, 1 (IX+) \ Get loop variable
AND A
ADC HL, BC \ Add increment to loop variable. Need to use ADC not ADD
\ because ADD HL,reg does not change parity/overflow
POP BC \ Restore TOS
JP PE, ENDLOOP \ End-of-loop when overflow flag is set.
\ On Z80 this is even parity.
LD 0 (IX+), L
LD 1 (IX+), H \ Store updated loop variable back
EX DE, HL
LD E, (HL)
INC HL
LD D, (HL) \ Load IP from cell after (LOOP), branch back.
NEXT
END-CODE
CODE (+LOOP) ( n ---)
\G Runtime part of +LOOP
JR LOOP1 \ Loop increment is already in BC
END-CODE
CODE (LEAVE) ( ---)
\G Runtime of LEAVE
EX DE, HL
LD DE, 4
ADD IX, DE \ Remove two cells from return stack
LD E, (HL)
INC HL
LD D, (HL) \ Load IP from cell after LEAVE, branch out.
NEXT
END-CODE
\ PART 3: Code definitions used in programs.
CODE I ( --- n)
\G Get loop variable of innermost loop.
\ As the loop variable is stored in modifed form to facilitate end-of-loop
\ testing, we need to reverse this when obtaining I.
PUSH BC \ Save old TOS
LD L, 0 (IX+)
LD H, 1 (IX+) \ Load (modified) loop variable
LD C, 2 (IX+)
LD B, 3 (IX+)
ADD HL, BC \ Add limit^xor 0x8000 to obtain original loop variable.
LD C, L
LD B, H \ Put in TOS
NEXT
END-CODE
CODE I' ( ---n)
\G Get limit variable of innermost loop.
PUSH BC
LD C, 2 (IX+)
LD A, 3 (IX+)
XOR $80 \ Undo the XOR 0x8000
LD B, A
NEXT
END-CODE
CODE J ( ---n)
\G Get loop variable of next outer loop.
PUSH BC \ Save old TOS
LD L, 4 (IX+)
LD H, 5 (IX+) \ Load (modified) loop variable
LD C, 6 (IX+)
LD B, 7 (IX+)
ADD HL, BC \ Add limit to obtain original loop variable.
LD C, L
LD B, H \ Put in TOS
NEXT
END-CODE
CODE UNLOOP ( --- )
\G Undo return stack effect of loop, can be followed by EXIT
EX DE, HL
LD DE, 4
ADD IX, DE \ Remove 2 cells from return stack.
NEXTHL
END-CODE
CODE R@ ( --- x)
\G x is a copy of the top of the return stack.
PUSH BC
LD C, 0 (IX+)
LD B, 1 (IX+)
NEXT
END-CODE
CODE >R ( x ---)
\G Push x on the return stack.
DEC IX
LD 0 (IX+), B
DEC IX
LD 0 (IX+), C
POP BC
NEXT
END-CODE
CODE R> ( --- x)
\G Pop the top of the return stack and place it on the stack.
PUSH BC
LD C, 0 (IX+)
INC IX
LD B, 0 (IX+)
INC IX
NEXT
END-CODE
CODE RP@ ( --- a-addr)
\G Return the address of the return stack pointer.
PUSH BC
PUSH IX
POP BC
NEXT
END-CODE
CODE RP! ( a-addr --- )
\G Set the return stack pointer to a-addr.
PUSH BC
POP IX
POP BC
NEXT
END-CODE
CODE SP@ ( --- a-addr)
\G Return the address of the stack pointer (before SP@ was executed).
\G Note: TOS is in a register, hence stack pointer points to next cell.
LD HL, 0
ADD HL, SP
PUSH BC
LD C, L
LD B, H
NEXT
END-CODE
CODE SP! ( a-addr ---)
\G Set the stack pointer to a-addr.
LD L, C
LD H, B
LD SP, HL
NEXT
END-CODE
CODE UM* ( u1 u2 --- ud)
\G Multiply two unsigned numbers, giving double result.
PUSH BC \ store TOS
EXX \ Use shadow register set.
POP BC \ Get TOS back (operand 1)
POP DE \ Get other operand.
LD HL, 0 \ Initialize MSW of result, DE will be replaced by LSW
LD A, $11 \ 17 iteration
OR A \ Clear carry
BEGIN
RR H \ Rotate HL:DE 1 bit right (LSB of DE gets to carry).
RR L
RR D
RR E
U< IF
ADD HL, BC \ If carry, add BC operand.
THEN \ Any carry from this add will be shifted back in.
DEC A
0= UNTIL
PUSH DE \ Push result
PUSH HL
EXX \ Back to normal registers
POP BC
NEXT
END-CODE
CODE UM/MOD ( ud u1 --- urem uquot)
\G Divide the unsigned double number ud by u1, giving unsigned quotient
\G and remainder.
PUSH BC \ Store divisor
EXX \ Use shadow registers
POP BC \ Get divisor back
POP HL
POP DE \ Get dividend in HL:DE
LD A, $10 \ 16 iterations
SLA E
RL D \ Shift HL:DE left.
BEGIN
ADC HL, HL \ Continue left shift
U< IF
OR A \ If carry, unconditionally subtract BC
SBC HL, BC
OR A \ and clear carry
ELSE
SBC HL, BC \ else conditonal subtraction
U< IF
ADD HL, BC \ if borrow, undo subtraction
SCF \ and set carry
THEN
THEN
RL E \ shift quotient bit in.
RL D
DEC A
0= UNTIL
LD A, D
CPL
LD B, A
LD A, E
CPL
LD C, A \ Complement quotient, to BC
PUSH HL \ Push remainder
PUSH BC \ Push quotient
EXX \ back to normal registers
POP BC \ quotient to TOS
NEXT
END-CODE
CODE + ( n1 n2 ---n3)
\G Add the top two numbers on the stack.
POP HL
ADD HL, BC
LD C, L
LD B, H
NEXT
END-CODE
CODE - ( w1 w2 ---w3)
\G Subtract the top two numbers on the stack (w2 from w1).
POP HL
AND A
SBC HL, BC
LD C, L
LD B, H
NEXT
END-CODE
CODE NEGATE ( n1 --- -n1)
\G Negate top number on the stack.
LD HL, 0
AND A
SBC HL, BC
LD C, L
LD B, H
NEXT
END-CODE
CODE AND ( x1 x2 ---x3)
\G Bitwise and of the top two cells on the stack.
POP HL
LD A, C
AND L
LD C, A
LD A, B
AND H
LD B, A
NEXT
END-CODE
CODE OR ( x1 x2 ---x3)
\G Bitwise or of the top two cells on the stack.
POP HL
LD A, C
OR L
LD C, A
LD A, B
OR H
LD B, A
NEXT
END-CODE
CODE XOR ( x1 x2 ---x3)
\G Bitwise exclusive or of the top two cells on the stack.
POP HL
LD A, C
XOR L
LD C, A
LD A, B
XOR H
LD B, A
NEXT
END-CODE
CODE 1+ ( w1 --- w2)
\G Add 1 to the top of the stack.
INC BC
NEXT
END-CODE
CODE 1- ( w1 --- w2)
\G Subtract 1 from the top of the stack.
DEC BC
NEXT
END-CODE
CODE 2+ ( w1 --- w2)
\G Add 2 to the top of the stack.
INC BC
INC BC
NEXT
END-CODE
CODE 2- ( w1 --- w2)
\G Subtract 2 from the top of the stack.
DEC BC
DEC BC
NEXT
END-CODE
CODE 2* ( w1 --- w2)
\G Multiply w1 by 2.
SLA C
RL B
NEXT
END-CODE
CODE 2/ ( n1 --- n2)
\G Divide signed number n1 by 2.
SRA B
RR C
NEXT
END-CODE
CODE D+ ( d1 d2 --- d3)
\G Add the double numbers d1 and d2.
EXX
POP HL
POP DE
POP BC
ADD HL, BC
PUSH HL
PUSH DE
EXX
POP HL
ADC HL, BC
LD C, L
LD B, H
NEXT
END-CODE
CODE DNEGATE ( d1 --- d2)
\G Negate the top double number on the stack.
POP HL
LD A, L
CPL
LD L, A
LD A, H
CPL
LD H, A
INC HL
PUSH HL
LD A, C
CPL
LD C, A
LD A, B
CPL
LD B, A
LD A, L
OR H
0= IF
INC BC
THEN
NEXT
END-CODE
CODE LSHIFT ( x1 u --- x2)
\G Shift x1 left by u bits, zeros are added to the right.
POP HL
LD B, C
LD A, C
AND A
0<> IF
BEGIN
ADD HL, HL
B--0= UNTIL
THEN
LD C, L
LD B, H
NEXT
END-CODE
CODE RSHIFT ( x1 u --- x2)
\G Shift x1 right by u bits, zeros are added to the left.
POP HL
LD B, C
LD A, C
AND A
0<> IF
BEGIN
SRL H
RR L
B--0= UNTIL
THEN
LD C, L
LD B, H
NEXT
END-CODE
CODE DROP ( x --- )
\G Discard the top item on the stack.
POP BC
NEXT
END-CODE
CODE DUP ( x --- x x )
\G Duplicate the top cell on the stack.
PUSH BC
NEXT
END-CODE
CODE SWAP ( n1 n2 --- n2 n1)
\G Swap the two top items on the stack.
POP HL
PUSH BC
LD C, L
LD B, H
NEXT
END-CODE
CODE OVER ( x1 x2 --- x1 x2 x1)
\G Copy the second cell of the stack.
POP HL
PUSH HL
PUSH BC
LD C, L
LD B, H
NEXT
END-CODE
CODE ROT ( x1 x2 x3 --- x2 x3 x1)
\G Rotate the three top items on the stack.
POP HL
EX (SP), HL
PUSH BC
LD C, L
LD B, H
NEXT
END-CODE
CODE -ROT ( x1 x2 x3 --- x3 x1 x2)
\G Rotate the three top items on the stack reverse direction compared to ROT.
LD L, C
LD H, B
POP BC
EX (SP), HL
PUSH HL
NEXT
END-CODE
CODE 2DROP ( d ---)
\G Discard the top double number on the stack.
POP BC
POP BC
NEXT
END-CODE
CODE 2DUP ( d --- d d )
\G Duplicate the top cell on the stack, but only if it is nonzero.
POP HL
PUSH HL
PUSH BC
PUSH HL
NEXT
END-CODE
CODE 2SWAP ( d1 d2 --- d2 d1)
\G Swap the top two double numbers on the stack.
EXX
POP HL
EXX
POP HL
EXX
EX (SP), HL
EXX
PUSH BC
EXX
PUSH HL
EXX
LD C, L
LD B, H
NEXT
END-CODE
CODE 2OVER ( d1 d2 --- d1 d2 d1)
\G Take a copy of the second double number of the stack and push it on the
\G stack.
EXX
POP DE
POP BC
POP HL
PUSH HL
PUSH BC
PUSH DE
EXX
PUSH BC
EXX
PUSH HL
PUSH BC
EXX
POP BC
NEXT
END-CODE
CODE PICK ( u --- x)
\G place a copy of stack cell number u on the stack. 0 PICK is DUP, 1 PICK
\G is OVER etc.
LD L, C
LD H, B
ADD HL, HL
ADD HL, SP
LD C, (HL)
INC HL
LD B, (HL)
NEXT
END-CODE
CODE ROLL ( u ---)
\G Move stack cell number u to the top. 1 ROLL is SWAP, 2 ROLL is ROT etc.
PUSH BC
EXX
EX (SP), HL
INC HL
ADD HL, HL
LD C, L
LD B, H
ADD HL, SP
LD E, (HL)
INC HL
LD D, (HL)
PUSH DE
LD E, L
LD D, H
DEC HL
DEC HL
LDDR
POP HL
POP BC
EX (SP), HL
EXX
POP BC
NEXT
END-CODE
CODE C@ ( c-addr --- c)
\G Fetch character c at c-addr.
LD A, (BC)
LD C, A
LD B, 0
NEXT
END-CODE
CODE @ ( a-addr --- x)
\G Fetch cell x at a-addr.
LD A, (BC)
LD L, A
INC BC
LD A, (BC)
LD C, L
LD B, A
NEXT
END-CODE
CODE C! ( c c-addr ---)
\G Store character c at c-addr
POP HL
LD A, L
LD (BC), A
POP BC
NEXT
END-CODE
CODE ! ( x a-addr ---)
\G Store cell x at a-addr
POP HL
LD A, L
LD (BC), A
INC BC
LD A, H
LD (BC), A
POP BC
NEXT
END-CODE
CODE +! ( w a-addr ---)
\G Add w to the contents of the cell at a-addr.
POP HL
LD A, (BC)
ADD A, L
LD (BC), A
INC BC
LD A, (BC)
ADC A, H
LD (BC), A
POP BC
NEXT
END-CODE
CODE 2@ ( a-addr --- d)
\G Fetch double number d at a-addr.
LD L, C
LD H, B
LD C, (HL)
INC HL
LD B, (HL)
INC HL
LD A, (HL)
INC HL
LD H, (HL)
LD L, A
PUSH HL
NEXT
END-CODE
CODE 2! ( d a-addr ---)
\G Store the double number d at a-addr.
LD L, C
LD H, B
POP BC
LD (HL), C
INC HL
LD (HL), B
INC HL
POP BC
LD (HL), C
INC HL
LD (HL), B
POP BC
NEXT
END-CODE
CODE 0= ( x --- f)
\G f is true if and only if x is 0.
LD A, B
OR C
SUB 1 \ Get a carry if and only if BC=0
SBC A, A \ Get 0 if no carry, 0FFh if carry.
LD C, A
LD B, A \ Flag value to TOS
NEXT
END-CODE
CODE 0< ( n --- f)
\G f is true if and only if n is less than 0.
RL B \ Get MSB of TOS to carry
SBC A, A \ Get 0 if no carry, 0FFh if carry.
LD C, A
LD B, A \ Flag value to TOS
NEXT
END-CODE
LABEL YES \ Store a true flag on stack.
DEC BC \ Change false to true flag.
NEXT
ENDASM
LABEL LESS_OVF \ overflow detected, less if not negative
JP P, YES
NEXT
ENDASM
CODE < ( n1 n2 --- f)
\G f is true if and only if signed number n1 is less than n2.
POP HL
XOR A
SBC HL, BC \ Subtract n1-n2
LD BC, 0 \ False result to TOS
JP PE, LESS_OVF
JP M, YES \ No overflow, less if negative
NEXT
END-CODE
CODE U< ( u1 u2 --- f)
\G f is true if and only if unsigned number u1 is less than u2.
POP HL
XOR A
SBC HL, BC \ Subtract u1-u2
SBC A, A \ Get 0 if no carry, 0FFh if carry.
LD B, A
LD C, A \ Flag value to TOS
NEXT
END-CODE
CODE = ( x1 x2 --- f)
\G f is true if and only if x1 is equal to x2.
POP HL
AND A
SBC HL, BC
LD BC, 0
JR Z, YES
NEXT
END-CODE
CODE INVERT ( x1 --- x2)
\G Invert all the bits of x1 (one's complement)
LD A, C
CPL
LD C, A
LD A, B
CPL
LD B, A
NEXT
END-CODE
CODE CMOVE ( c-addr1 c-addr2 u ---)
\G Copy u bytes starting at c-addr1 to c-addr2, proceeding in ascending
\G order.
PUSH BC
EXX
POP BC
POP DE
POP HL
LD A, C
OR B
0<> IF
LDIR
THEN
EXX
POP BC
NEXT
END-CODE
CODE CMOVE> ( c-addr1 c-addr2 u ---)
\G Copy a block of u bytes starting at c-addr1 to c-addr2, proceeding in
\G descending order.
PUSH BC
EXX
POP BC
POP DE
POP HL
LD A, C
OR B
0<> IF
ADD HL, BC
DEC HL
EX DE, HL
ADD HL, BC
DEC HL
EX DE, HL
LDDR
THEN
EXX
POP BC
NEXT
END-CODE
CODE FILL ( c-addr u c ---)
\G Fill a block of u bytes starting at c-addr with character c.
LD A, C
EXX
POP BC
POP HL
EX AF, AF'
LD A, C
OR B
0<> IF
EX AF, AF'
LD (HL), A \ Write first byte
LD E, L
LD D, H
INC DE
DEC BC
LD A, C
OR B
0<> IF
LDIR \ Copy byte to next lcoation repeatedly.
THEN
THEN
EXX
POP BC
NEXT
END-CODE
CODE (FIND) ( c-addr u nfa --- cfa/word f )
\G find the string at c-addr, length u in the dictionary starting at nfa.
\G Search in a single hash chain. Return the cfa of the found word. If
\G If the word is not found, return the string addres instead. Flag values:
\G 0 for not found, 1 for immediate word, -1 for normal word.
PUSH BC
EXX
POP DE
POP BC \ Get string length in C
PUSH DE
BEGIN
POP DE \ nfa in DE
POP HL \ string start in HL
PUSH HL
PUSH DE
LD A, (DE) \ Get count byte at nfa
INC DE
AND $1F \ remove flag bits
CP C \ Compare with string length.
0= IF \ count bytes match
LD B, A
LABEL CMPLOOP
LD A, (DE)
INC DE
CP (HL)
INC HL
0= IF
DJNZ CMPLOOP