-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathFORTH.4
3486 lines (2834 loc) · 95.8 KB
/
FORTH.4
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
\
\ -----
$list
\
\ 32-bit protected-mode subroutine threaded forth, by rick vannorman
\
\ basic model considerations:
\
\ the data stack is based on BP, the return stack on SP
\ and top of data stack is maintained in EBX
\ CODE words begin with the sequence XCHG SP,BP (which means that
\ inside each code word, the stack may be used freely) and end-CODE
\ compiles the corresponding XCHG SP,BP followed by a RET instruction
\ during compilation, any code word with a non-zero macro byte will be
\ copied instead of called, and the XCHG SP,BP instructions will be
\ optimized out if possible.
\ headers are almost standard, ending at paragraph alignment:
\ | link | # | c | c | c | ... | c | M |
\ the macro field M is 7 bits, the msb is a marker bit
\ 0 if normal definition (to be called)
\ 1-7e if a macro to be copied (n is number of bytes)
\
\ -----
8 EQU =VOCS \ vocabulary stack depth
499 EQU =THREADS \ number of dictionary threads, should be prime
=THREADS THREADS-T ! \ tell meta compiler how many threads
EXISTS #DOS [IF] 0 EQU =ORIGIN [THEN]
EXISTS #OS2 [IF] $28000 EQU =ORIGIN [THEN]
=ORIGIN TBASE ! \ the base address of the target image
=ORIGIN $100 + EQU =PWR \ power on reset entry
=PWR $008 + EQU =DP_INIT
=PWR $010 + EQU =INIT
=PWR $100 + EQU =KERNEL
\
\ memory map, simple version (copy at end of file also)
\
\ |--<psp>--|--<init>--|--<dict>--
\ |0 |100 |200
\
\ |----<dict>----//----<dstk|tib>----<rstk|user>----|----<reserv>----|
\ | |tib= |up= |res= |
\ |200 | up-tib-rp | res-#up | em-#res |em
\ | =sp| =rp| | |
\
\
\ -----
\ initialization parameters
\ first, change the concept of reserved memory. os2 needs none, but dos
\ needs at least a meg. ALLOCATE in the dos system will pull from
\ this region; in OS2 will take from global memory pool
=INIT ORG
HERE EQU 'EM $00100000 DW \ 1meg dictionary
HERE EQU 'RES#
EXISTS #DOS [IF] $00024000 DW [THEN] \ 4096 bytes reserved for block buffers, etc
\ 128K bytes for edbuf, 4096 for misc editor
EXISTS #OS2 [IF] $00001000 DW [THEN] \ 4096 bytes reserved for block buffers, etc
HERE EQU 'UP# $00000400 DW \ 256 cells for user variables
HERE EQU 'RP# $0000C000 DW \ 2048 cells for return stack
HERE EQU 'TIB# $00000100 DW \ 256 bytes for tib
\ -----
\ start of kernel
=KERNEL ORG
\ -----
\ special Interpreters
\ variables call this, cannot be expanded
LABEL DOVAR ( -- a )
4 # BP SUB \ decrement sp
BX 0 [BP] MOV \ and push tos
BX POP \ get address of data
RET
\ constants call this
LABEL DOCON ( -- n )
4 # BP SUB
DI POP \ get address of data (delay slot for BP)
BX 0 [BP] MOV \ (delay slot for DI)
0 [DI] BX MOV \ data to tos
RET
\ constants call this
LABEL DO2CON ( -- n )
8 # BP SUB
DI POP \ get address of data (delay slot for BP)
BX 4 [BP] MOV \ (delay slot for DI)
4 [DI] BX MOV \ data to tos
BX 0 [BP] MOV \ (delay slot for DI)
0 [DI] BX MOV \ data to tos
RET
\ -----
\ user variables
LABEL DOUSER ( -- a )
4 # BP SUB \
DI POP \ address of user offset (BP delay slot)
BX 0 [BP] MOV \
SI BX MOV \ get base of user memory
0 [DI] BX ADD \ index into user memory
RET
\ -----
\ reserved space variables
VARIABLE RS \ the reserved space base address, set by COLD
LABEL DODS ( -- a )
4 # BP SUB \ push tos
DI POP \ address of ds offset (BP delay slot)
BX 0 [BP] MOV \ via bp
RS #) BX MOV \ get base of reserved space
0 [DI] BX ADD \ index into ds memory
RET
\ -----
\ a token for compilation.
\ forces the optimizer to behave around branches
CODE _BEGIN END-CODE
\ unconditional branch. exists only as a macro pattern.
CODE _AGAIN
0 #) JMP \ branch to be filled in
END-CODE
\ conditional branch. exists only as a macro pattern
CODE _IF
BX BX OR \ test tos
BX POP \ get new tos
1 L# JNZ \ skip long branch
0 #) JMP \ branch to be filled in to target
1 L: END-CODE
\ -----
\ do loops
\ push limit and initial on the return stack, modified so that the
\ first overflow results in loop termination. macro pattern only.
CODE _DO ( n1 n2 -- )
ax pop \ ax=n1, bx=n2
8 # bp sub
$80000000 # ax add \ ax=ax+80000000 (bp delay slot)
ax 4 [bp] mov
ax bx sub \ bx = bx - ax
bx 0 [bp] mov
bx pop \ new tos
END-CODE
\ conditional branch. exists only as a macro pattern
CODE _?DO
AX POP \ get ax
AX PUSH \ replace for real _DO
AX BX CMP \ test for equal
1 L# JNE \ if not equal, is ok to start loop
BX POP \ discard n1
BX POP \ and n2
0 #) JMP \ long jump for THEN to patch
1 L: END-CODE
\ loop end; increment the index, check for overflow. macro pattern only.
CODE _LOOP \ could be even faster if jmp didn't have to be last instruction
1 # 0 [bp] add \ top of return stack + 1
8 [bp] bp lea \ discard indices
1 L# jo \ iterate if no overflow
8 # bp sub \ restore indices
0 #) JMP \ jmp to top of loop
1 L: END-CODE
\ loop end; add an arbitrary integer to the index, check for overflow
\ macro pattern only
CODE _+LOOP \ could be even faster if jmp didn't have to be last instruction
BX 0 [bp] add \ top of return stack + TOS
bx pop
8 [bp] bp lea \ discard indices
1 L# jo \ iterate if no overflow
8 # bp sub \ restore indices
0 #) JMP \ jmp to top of loop
1 L: END-CODE
\ discard do loop indices from return stack, prepare for EXIT or LEAVE.
\ macro only
CODE UNLOOP ( -- )
8 # BP ADD
END-CODE
COMPILE-ONLY
\ calculate the loop index. macro only
CODE I ( -- n )
bx push \ push tos into nos
0 [bp] bx mov \ get rtos
4 [bp] bx add \ and add rnos to form i
END-CODE
COMPILE-ONLY
\ calculate the outer loop index. macro only
CODE J ( -- n )
bx push \ push tos into nos
8 [bp] bx mov \ get rtos
12 [bp] bx add \ and add rnos
END-CODE
COMPILE-ONLY
\ calculate the outer loop index. macro only
CODE K ( -- n )
bx push \ push tos into nos
16 [bp] bx mov \ get rtos
20 [bp] bx add \ and add rnos
END-CODE
COMPILE-ONLY
\ -----
\ execution modifiers
\ compile a RETurn instruction. macro only
XCODE EXIT RET
END-XCODE
COMPILE-ONLY
\ exit if condition is true
CODE ?EXIT ( flag -- )
BX BX OR
BX POP
1 L# JZ
BP SP XCHG
RET
1 L: END-CODE
\ jump to an address.
XCODE EXECUTE ( addr -- )
BX AX MOV
0 [BP] BX MOV
4 # BP ADD
AX JMP
END-XCODE
NO-EXPAND
\ jump through a pointer if the pointer is non-zero
XCODE @EXECUTE ( addr -- )
0 [BX] AX MOV
0 [BP] BX MOV
4 # BP ADD
AX AX OR
1 L# JZ
AX JMP
1 L: END-XCODE
NO-EXPAND
\ -----
\ has to be defined early
VARIABLE 'THROW
: THROW 'THROW @EXECUTE ;
\ -----
\ memory fetch and store. 32-, 16-, and 8-bit words
\ x is the value stored at a-addr.
CODE @ ( a-addr -- x )
00 [BX] BX MOV
END-CODE
\ Store x at a-addr
CODE ! ( x a-addr -- )
AX POP
AX 0 [BX] MOV
BX POP
END-CODE
\ fetch a 16 bit value from addr
CODE H@ ( h-addr -- n )
AX AX XOR
OP: 0 [BX] AX MOV
AX BX MOV
END-CODE
\ store a 16 bit value at addr
CODE H! ( n h-addr -- )
AX POP \ get N
OP: AX 0 [BX] MOV \ write 16 bits
BX POP
END-CODE
\ fetch an 8 bit value from addr
CODE C@ ( c-addr -- char )
AX AX XOR
00 [BX] AL MOV
AX BX MOV
END-CODE
\ store char at c-addr
CODE C! ( char c-addr -- )
AX POP
AL 00 [BX] MOV
BX POP
END-CODE
\ -----
\ misc memory operations
\ Add n|u to the single-cell number at a-addr.
CODE +! ( n|u a-addr -- )
AX POP
AX 0 [BX] ADD
BX POP
END-CODE
\ subtract n|u to the single-cell number at a-addr.
CODE -! ( n|u a-addr -- )
AX POP
AX 0 [BX] SUB
BX POP
END-CODE
\ add u to the byte variable at c-addr
CODE C+! ( u c-addr -- )
AX POP
AL 0 [BX] ADD
BX POP
end-CODE
\ logical-or u with the byte variable at c-addr
CODE COR! ( u c-addr -- )
AX POP
AL 0 [BX] OR
BX POP
END-CODE
CODE @+ ( addr -- addr+cell [addr] )
0 [BX] AX MOV
4 # BX ADD
BX PUSH
AX BX MOV
END-CODE
\ -----
\ return stack maniuplation
\ the address of the return stack pointer
CODE RP@ ( -- a-addr )
BX PUSH
BP BX MOV
END-CODE
\ set the return stack pointer.
CODE RP! ( a-addr -- )
BX BP MOV
BX POP
END-CODE
\ move x from the return stack to the data stack
CODE R> ( -- x ) ( R: x -- )
BX PUSH
0 [BP] BX MOV
4 # BP ADD
END-CODE
COMPILE-ONLY
\ copy x from the return stack to the data stack
CODE R@ ( -- x ) ( R: x -- x )
BX PUSH
00 [BP] BX MOV
END-CODE
COMPILE-ONLY
\ move x to the return stack.
CODE >R ( x -- ) ( R: -- x )
4 # BP SUB
BX 0 [BP] MOV
BX POP
END-CODE
COMPILE-ONLY
\ copy x from the data stack to the return stack
CODE DUP>R ( x -- x ) ( R: -- x )
4 # BP SUB
BX 0 [BP] MOV
END-CODE
COMPILE-ONLY
\ discard x from the return stack
CODE R>DROP ( -- ) ( R: x -- )
4 # BP ADD
END-CODE
COMPILE-ONLY
\ -----
\ double number return stack manipulation
\ transfer cell pair x1 x2 to the return stack.
\ "SWAP >R >R"
CODE 2>R ( x1 x2 -- ) ( R: -- x1 x2 )
8 # BP SUB
BX 0 [BP] MOV
BX POP
BX 4 [BP] MOV
BX POP
END-CODE
COMPILE-ONLY
\ copy the cell pair from the return stack to the data stack.
\ "R> R> 2DUP >R >R SWAP"
CODE 2R@ ( -- x1 x2 ) ( R: x1 x2 -- x1 x2 )
BX PUSH
4 [BP] BX MOV
BX PUSH
0 [BP] BX MOV
END-CODE
COMPILE-ONLY
\ transfer cell pair x1 x2 from the return stack to the data stack.
\ "R> R> SWAP"
CODE 2R> ( -- x1 x2 ) ( R: x1 x2 -- )
BX PUSH
4 [BP] BX MOV
BX PUSH
0 [BP] BX MOV
8 # BP ADD
END-CODE
COMPILE-ONLY
\ -----
\ n is the correct number of cells to put on the return stack
CODE N>R ( x1 x2 .. xn n -- ) ( R: -- x1 x2 .. xn n )
0 [BP] DX MOV \ get return address
bx push
bx inc
bx cx mov \ count of cells
bx bx add \ bx * 2
bx bx add \ bx * 4 is number of bytes for indexing
bx bp sub \ new top of return stack
bp BX mov \ copy for use, leave bp for later
1 L: 4 # BX ADD
AX POP
AX 0 [BX] MOV \ get nx into return stack
CX DEC
1 L# JNZ \ and repeat
2 L: bx pop \ get new tos
DX 0 [BP] MOV
end-code
no-expand
COMPILE-ONLY
\ n is the correct number of cells to get from the return stack
CODE NR> ( -- x1 x2 .. xn N ) ( R: x1 x2 .. xn N )
bx push \ save tos
bp sp xchg \ swap stacks
dx pop \ return address
cx pop \ n
2 L# jcxz \ skip if zero
cx bx mov \ into b
cx ax mov \ another copy
bx bx add \ bx * 2
bx bx add \ bx * 4 is number of bytes for indexing
bx bp sub \ new top of data stack
bp di mov \ copy for use, leave bp for later
1 L: 0 [DI] pop \ get nx into return stack
4 # di add \ and move to next
CX DEC
1 L# JNZ \ and repeat
2 L: dx push \ replace return address
bp sp xchg \ swap stacks
ax bx mov \ return n to stack
end-code
no-expand
COMPILE-ONLY
CODE NR@ ( N -- N )
BX SHL
BX SHL
BP BX ADD \ ADDRESS OF ITEM
0 [BX] BX MOV \ GET ITEM
END-CODE
CODE NR! ( N N -- N )
BX SHL
BX SHL
BP BX ADD \ ADDRESS OF ITEM
AX POP \ GET ITEM
AX 0 [BX] MOV \ WRITE ITEM
BX POP
END-CODE
\ -----
\ data stack manipulation
\ the address of the data stack
CODE SP@ ( -- a-addr )
BX PUSH
SP BX MOV
END-CODE
\ set the data stack pointer.
CODE SP! ( a-addr -- )
BX SP MOV
BX POP
END-CODE
\ remove x from the data stack
CODE DROP ( x -- )
BX POP
END-CODE
\ duplicate x
CODE DUP ( x -- x x )
BX PUSH
END-CODE
\ exchange x1 and x2
CODE SWAP ( x1 x2 -- x2 x1 )
AX POP
BX PUSH
AX BX MOV
END-CODE
\ place a copy of x1 on top of the stack
CODE OVER ( x1 x2 -- x1 x2 x1 )
BX PUSH
SP DI MOV
4 [DI] BX MOV
END-CODE
CODE UNDER+ ( n x n1 -- n+n1 x )
BX AX MOV
BX POP
CX POP
AX CX ADD
CX PUSH
END-CODE
\ rotate top three stack entries
CODE ROT ( x1 x2 x3 -- x2 x3 x1 )
BX AX MOV
CX POP
BX POP
CX PUSH
AX PUSH
END-CODE
\ reverse rotation top three stack entries. "ROT ROT"
CODE -ROT ( x1 x2 x3 -- x3 x1 x2 )
BX AX MOV
BX POP
CX POP
AX PUSH
CX PUSH
END-CODE
\ drop the first item below the top of stack
CODE NIP ( x1 x2 -- x2 )
AX POP
END-CODE
\ copy the first (top) stack item below the second stack item.
CODE TUCK ( x1 x2 -- x2 x1 x2 )
AX POP
BX PUSH
AX PUSH
END-CODE
\ write logical true to a-addr
CODE ON ( a-addr -- )
-1 # 0 [BX] MOV
BX POP
END-CODE
\ write logical false to a-addr
CODE OFF ( a-addr -- )
0 # 0 [BX] MOV
BX POP
END-CODE
\ do nothing
CODE NOOP
NOP
END-CODE
\ -----
\ boolean logic
\ x3 is the bit-by-bit logical 'and' of x1 and x2.
CODE AND ( x1 x2 -- x3 )
AX POP
AX BX AND
END-CODE
\ x3 is the bit-by-bit logical 'or' of x1 and x2.
CODE OR ( x1 x2 -- x3)
AX POP
AX BX OR
END-CODE
\ x3 is the bit-by-bit logical 'exclusive-or' of x1 and x2.
CODE XOR ( x1 x2 -- x3)
AX POP
AX BX XOR
END-CODE
\ invert all bits of x1, giving x2
CODE INVERT ( x1 -- x2 )
BX NOT
END-CODE
\ exchange the low 2 bytes of x1
CODE BFLIP ( x1 -- x2 )
BL BH XCHG
END-CODE
\ exchange the high and low halves of x1
CODE FLIP ( x1 -- x2 )
16 # CL MOV
BX CL ROL
END-CODE
\ -----
\ 32 bit arithmetic
\ Add n2|u2 to n1|u1, giving the sum n3|u3.
\ Carry and overflow ignored.
CODE + ( n1|u1 n2|u2 -- n3|u3 )
AX POP
AX BX ADD
END-CODE
\ Subtract n2|u2 from n1|u1, giving the difference n3|u3.
\ Carry and overflow ignored
CODE - ( n1|u1 n2|u2 -- n3|u3 )
AX POP
BX AX SUB
AX BX MOV
END-CODE
\ n2 is the negation of n1
CODE NEGATE ( n1 -- n2 )
BX NEG
END-CODE
\ n2 is the absolute value of n1.
CODE ABS ( n1 -- +n2 )
BX BX OR
1 L# JNS
BX NEG
1 L: END-CODE
\ -----
\ comparisons
\ flag is true if n is less than zero.
CODE 0< ( n -- flag )
BX BX ADD
BX BX SBB
END-CODE
\ flag is true if n is equal to zero.
CODE 0= ( n -- flag )
BX NEG
BX BX SBB
BX NOT
END-CODE
\ flag is true if n is equal to zero.
CODE NOT ( n -- flag )
BX NEG
BX BX SBB
BX NOT
END-CODE
\ flag is true if n is not equal to zero
CODE 0<> ( n -- flag )
BX NEG
BX BX SBB
END-CODE
\ flag is true if x1 is bit-for-bit the same as x2.
CODE = ( x1 x2 -- flag )
AX POP
BX AX XOR \ Resultant AX is 0 if equal
1 # AX SUB \ Borrow-out set only if AX is 0
BX BX SBB \ -1 only if AX is 0
END-CODE
\ flag is true if any bit of x1 different from x2.
CODE <> ( x1 x2 -- flag )
AX POP
BX AX XOR \ Resultant AX is 0 if equal
AX NEG \ Borrow-out set only if AX is 0
BX BX SBB \ -1 only if AX is 0
END-CODE
\ flag is true if u1 is less than u2
CODE U< ( u1 u2 -- flag )
AX POP
BX AX SUB
BX BX SBB
END-CODE
\ flag is true if n1 is less than n2.
CODE < ( n1 n2 -- flag )
AX POP
BX AX SUB \ cx:ax - dx:bx
0 # BX MOV \ false
1 L# JGE \ branch if false is correct
BX DEC \ make false true
1 L: END-CODE
\ flag is true if u1 is greater than u2
CODE U> ( u1 u2 -- flag )
AX POP
AX BX SUB
BX BX SBB
END-CODE
\ flag is true if n1 is greater than n2.
CODE > ( n1 n2 -- flag )
AX POP
BX AX SUB
0 # BX MOV
1 L# JLE
BX DEC
1 L: END-CODE
\ flag is true if n1 is greater than or equal to n2.
CODE >= ( n n -- flag )
AX POP
BX AX SUB
0 # BX MOV
1 L# JL
BX DEC
1 L: END-CODE
\ flag is true if n1 is less than of equal to n2.
CODE <= ( n1 n2 -- flag )
AX POP
BX AX SUB
0 # BX MOV
1 L# JG
BX DEC
1 L: END-CODE
\ flag is true if n1 is greater than zero.
CODE 0> ( n1 -- flag )
0 # BX CMP
0 # BX MOV
1 L# JLE
BX DEC
1 L: END-CODE
\ ----- min and max
\ n3 is the greater of n1 and n2
CODE MAX ( n1 n2 -- n3 )
AX POP
AX BX CMP
1 L# JG
AX BX MOV
1 L: END-CODE
\ n3 is the lesser of n1 and n2
CODE MIN ( n1 n2 -- n3 )
AX POP
AX BX CMP
1 L# JL
AX BX MOV
1 L: END-CODE
\ Duplicate x if it is non-zero.
CODE ?DUP ( x -- 0 | x x )
BX BX OR
1 L# JE
BX PUSH
1 L: END-CODE
\ flag is true if n1|u1 is less than n3|u3 and not less than n2|u2.
\ all comparisons are performed in a circular number space.
: WITHIN ( n1|u1 n2|u2 n3|u3 -- flag )
OVER - >R - R> U< ;
\ ----- multiply
\ multiply u1 by u2 giving the unsigned double-cell product ud. all values
\ and arithmetic are unsigned
CODE UM* ( u1 u2 -- ud )
AX POP
BX MUL
AX PUSH
DX BX MOV
END-CODE
\ Multiply n1|u1 by n2|u2 giving the product n3|u3.
CODE * ( n|u1 n|u2 -- n|u3 )
AX POP
BX MUL
AX BX MOV
END-CODE
\ ----- divide
\ divide ud by u1, giving the quotient u3 and the remainder u2. all values
\ and arithmetic are unsighed.
CODE (UM/MOD) ( ud u -- ur uq )
\ CODE UM/MOD ( ud u -- ur uq )
DX POP
AX POP
DX BX CMP
1 L# JBE \ avoids interrupt 0 for divisor too small & divide by 0
BX DIV
DX PUSH
AX BX MOV
\ 2 L# JU \ in-line expansion of END-CODE would optimize further
BP SP XCHG
RET
1 L: BX PUSH \ division by zero returns zero
2 L: END-CODE
NO-EXPAND
-10 CONSTANT -10
: UM/MOD ( ud u -- ur uq )
?DUP IF (UM/MOD) EXIT THEN
-10 THROW ; \ division by zero
\ ----- simple constant arithmetic
\ Add 1 to n1|u1 giving the sum n2|u2.
CODE 1+ ( n1|u1 -- n2|u2 )
BX INC
END-CODE
\ Add 2 to n1|u1 giving the sum n2|u2.
CODE 2+ ( n -- n+2 )
2 # BX ADD
END-CODE
\ Subtract 1 from n1|u1 giving the difference n2|u2.
CODE 1- ( n1|u1 -- n2|u2 )
BX DEC
END-CODE
\ Subtract 2 from n1|u1 giving the difference n2|u2.
CODE 2- ( n -- n-2 )
2 # BX SUB
END-CODE
\ x2 is the result of shifting x1 one bit toward the least-significant
\ bit, leaving the most-significant bit unchanged
CODE 2/ ( x1 -- x2 )
BX SAR
END-CODE
\ d2 is the result of shifting d1 one bit toward the least-significant
\ bit, leaving the most-significant bit unchanged
CODE D2/ ( d1 -- d2 )
SP DI MOV
BX SAR
0 [DI] RCR
END-CODE
\ x2 is the result of shifting x1 one bit toward the most-significant
\ bit, filling the vacated least-significant bit with zero.
CODE 2* ( x1 -- x2 )
BX SHL
END-CODE
\ d2 is the result of shifting d1 one bit toward the most-significant
\ bit, filling the vacated least-significant bit with zero.
CODE D2* ( d1 -- d2 )
SP DI MOV
0 [DI] SHL
BX RCL
END-CODE
\ u2 is the result of shifting u1 one bit toward the least-significant
\ bit, filling the most-significant bit with zero.
CODE U2/ ( u1 -- u2 )
BX SHR
END-CODE
\ Perform a logical right shift of n bit-places on x1, giving x2.
\ If n is
\ positive, shift the bits n places toward the most-significant bit.
\ If n is negative, shift them toward the least-significant bits.
\ Put zero into the places "uncovered" by the shift.
CODE RSHIFT ( x1 n -- x2 )
BX CX MOV \ shift count into cx
BX POP \ x1 into bx
BX CL SHR \ shift right
END-CODE \ continue
\ Perform a logical left shift of n bit-places on 1, giving x2.
CODE LSHIFT ( x1 n -- x2 )
BX CX MOV \ shift count into cx
BX POP \ x1 into bx
BX CL SHL \ logical shift left if positive
END-CODE \ continue
\ -----
\ portability model for memory
\ The definition of CELL is used as the prototype for literals.
\ n is the size of a cell specified in address units
CODE CELL ( -- n )
BX PUSH
4 # BX MOV
END-CODE
\ add the size of a cell, specified in address units, to a-addr1,
\ giving a-addr2
CODE CELL+ ( a-addr1 -- a-addr2 )
4 # BX ADD
END-CODE
\ subtract the size of a cell, specified in address units, from a-addr1,
\ giving a-addr2
CODE CELL- ( a-addr1 -- a-addr2 )
4 # BX SUB
END-CODE
\ n2 is the size, in address units, of n1 cells
CODE CELLS ( n1 -- n2 )
BX SHL
BX SHL
END-CODE
\ add the size of one character, specified in address units, to
\ c-addr1, giving c-addr2
CODE CHAR+ ( c-addr1 -- c-addr2 )
BX INC
END-CODE
\ n2 is the size, in address units, of n1 characters
CODE CHARS ( n1 -- n2 )
END-CODE
\ ----- system constants
32 CONSTANT BL ( -- char ) \ char is the character value for a space
0 CONSTANT 0 ( -- n ) \ n is a constant zero
1 CONSTANT 1 ( -- n ) \ n is a constant one
2 CONSTANT 2 ( -- n ) \ n is a constant two
-1 CONSTANT -1 ( -- n ) \ n is a constant negative one
0 CONSTANT FALSE ( -- flag ) \ flag is false
-1 CONSTANT TRUE ( -- flag ) \ flag is true
\ n is the number of vocabularies allowed in the search order CONTEXT
=VOCS CONSTANT #VOCS ( -- n )
\ n is the number of threads in a wordlist
=THREADS CONSTANT #THREADS ( -- n )
\ c-addr is the address of a character string, and u is the string's
\ character count. this function will always return false.
: ENVIRONMENT? ( c-addr u -- false )
DROP DROP FALSE ; \ always false
\ -----
\ strings
\ return the character string specification for the counted string
\ stored at c-addr1. c-addr2 is the address of the first character
\ after c-addr1. u is the contents of the character at c-addr1, which
\ is the length in characters of the string at c-addr1
CODE COUNT ( b -- b+1 n )
0 [BX] AL MOV \ count into al
BX INC \ b+1
BX PUSH \ SAVE
BX BX XOR \ big zero
AL BL MOV \ count to tos
END-CODE