-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathforth.asm
5229 lines (5225 loc) · 101 KB
/
forth.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
;
;******************************************************************************
;
; 8051 eForth 1.1 by C. H. Ting, 1990
;
; This eForth system was developed using chipForth from Forth, Inc.
; and tested on a Micromint BCC52 single board computer.
; The eForth Model was developed by Bill Muench and C. H. Ting.
;
; The goal of this implementation is to show that the eForth Model
; can be ported to a ROM based 8 bit microprocessor, Intel 8051.
; Deviations from the original eForth Model are:
;
; All kernel words are assembled as DB statements.
; Memory map is tailored to a ROM based system.
; %colon and %user are modified to compile LJMP doLIST.
; call, compiles a LCALL with a flipped destination address.
; USER, VARIABLE and : are modified to use above 'call,'.
; FORTH vocabulary pointer is a pair user variables.
; BYE is deleted.
;
; To assemble this source file and generate a ROM image,
; type the following commands using MASM and LINK:
; >MASM 8051;
; >LINK 8051;
; The resulting 8051.EXE contains the binary image suitable
; for PROM programming. The actual image is offset by 200H
; bytes from the beginning of the .EXE file. This image
; must be placed in a PROM from 0 to 1FFFH, and it uses a RAM
; chip from 8000H to 9FFFH. If your system does not have
; this memory configuration, modify the memory pointers in
; the source file accordingly. Places to be modified are
; marked by '******'.
;
; 8051 is a slow processor. Do not expect great performance
; of this implementation, considering that most words are in high
; level. Your are encouraged to recode some of the high level words
; to optimize its performance.
;
; Direct your questions and contributions to:
;
; Dr. C. H. Ting
; 156 14th Avenue
; San Mateo, CA 94402
; (415) 571-7639
;
;******************************************************************************
;
; Notes -
;
; All tests and timings were done on a 8031AH running at 11.059200 Mhz.
;
; Rearrange usage of registers slightly. I'm not sure why the good doctor
; used register bank one instead of zero, and then put some of the variables
; in bank 0 space. I moved them out of there, so that an assembly routine
; can do a 'clr rs0', and use the bank 0 registers without wrecking the
; forth environment. Notice that SAME? takes advantage of that.
;
; It's amazing how long it took to figure out why the original FIND routine
; worked at all. It's was all because PACK$ fills the trailing bytes with
; null (0's). The routine SAME? only compared words, which meant that an
; odd size name (including the length byte) should not have matched. But
; becase PACK$ did fill with null, it did compare. Not well documented.
;
; SAME? is still in the .ASM file, but commented out. I don't know how
; many folks might have written words that need it. If you do, uncomment
; it out, and reassemble.
;
; Removed CELLS (commented out, code still in file), and fixed system to
; assume a word (cell) size of 16 bits. I don't see this becoming a 32
; bit forth anytime soon.
;
; Question: Will user variables ALWAYS be in RAM? If not, fix EMIT for
; a 'CLR A' 'MOVC A,@A+DPTR' sequence, instead of 'MOVX A,@DPTR'. I
; can't really see a reason why user variables would be in ROM... Kinda
; defeats the purpose, right?
;
; %sforth and SASMBLY allow switching between forth and assembly execution
; in the middle of a word definition. Handy for using words like EMIT in
; TYPE. However, they do require careful use, because registers aren't
; saved, etc, etc, etc...
;
; Converting TYPE to assembly improved the character output rate from 1354
; characters per second to 1595 cps. Speeding up TX! resulted in a speed
; up to over 1920 characters per second. Test was creating a string of
; 60 characters (S) and using the following word. : TEST 0 8192 S COUNT
; TYPE NEXT ; (In this test, COUNT was already in assembly).
;
; Converting UM* to assembly resulted in an incredible speed up. The
; test word of : TEST 0 20000 FOR $FFFF $FFFF UM* 2DROP NEXT ; took 4
; minutes and 6 seconds. The recoded version of UM* resulted in the
; word taking 5 seconds to execute. Not bad... Also improved the
; speed */MOD.
;
; Convert UM/MOD to assembly also improved speed. The test word was
; : TEST 0 20000 FOR $FFFF $0FFF $3333 UM/MOD 2DROP NEXT ; and took 5
; minutes and 20 seconds. The recoded version took about 14 seconds,
; and cost only an additional 23 bytes. Also dramatically improved the
; speed of EXTRACT, which is used by DIG for numerical output.
;
; AUTOBAUD works by measuring the duration of the start bit of a incoming
; word. It then takes that period and compares it to a table, which con-
; tains timer values normalized to 11.059200mhz. The values in the table
; are the period of a given baud rate (say, 1200 baud), plus and minus 3%.
; This allows small variations in timings from the host to be accounted
; for. The timer and SMOD bit value are read from the table, and timer 1
; is programmed. Also read from the table is the baud rate as a binary
; value. This is stored into the user variable BAUDRATE so that a program
; may interrogate the current rate. A small side note here. I cannot
; explain why you get an extra space and the ' ok' does not emit when the
; baud rate is changed. If you figure it out, I'd sure like to know...
;
; CI@ and CI! will not read or write the SFR (Special Function Registers).
; This is because that memory cannot be accessed indirectly, and CI@ and
; CI! use indirect addressing. It does, however, allow you to used an
; 8032/8052 with the extra 128 bytes of internal memory.
;
; There are several words that can be enabled or disabled, depending on
; whether you intend to embed this forth, or use it interactively. These
; switches are at about line 250, or so. I have converted these words to
; real forth, and if you need them for debugging, they can be uploaded
; fairly quickly.
;
; Stack picture of a double is ( dl dh -- )
;
; HOLD take advantage of the fact that the user variables (currently) all
; reside in one page. Because of this, DPL is increment and decremented
; in the routine without worrying abour DPH. Should the user variables
; ever start spanning a page, HOLD may need to be fixed.
;
; Delete the words DIGIT and EXTRACT because nothing used them except
; the HOLD and # routines. These words don't seem to be in any of the
; 'standard' forth vocabularys, so their removal shouldn't cause any
; problems.
;
; Deleted the words xio, FILE, HAND, CONSOLE, I/O and PACE. I see no
; reason why you need a file mode here. If you need to upload code from
; a PC, use something like CrossTalk or SmartCommIII, and set the character
; and line pacing modes to echo (I.e., wait for character echo on both
; normal characters, and end of line characters.) The 100 or so bytes
; taken by these routines can be put to better use... I did leave the
; user variables 'PROMPT, 'ECHO, 'TAP, 'EXPECT, 'EMIT, '?KEY, so your
; program can change the console handlers, if needed.
;
; I think I understand how the vocubulary stuff works. The word 'forth'
; is setup with the last name in the dictionary. Executing this word
; returns the address of it's storage, which is 2 16 bit words. The
; first is the last word in the dictionary, and the second is the link
; to another (?0 dictionary. Initially, CONTEXT points to these 2 words,
; which are updated by words like CREATE, :, and CONSTANT, etc. I'd
; like to add VOCABULARY to the system, but my understanding of how all
; that stuff inter-relates is still a little (a lotta...) hazy...
; Executing the word 'FORTH' restores the CONTEXT pointer back to 'forth'.
;
; Changed all the MOVC instructions to MOVX. I don't see anyway that
; this forth can be modified (without getting ridiculous, at any rate)
; to run as a harvard architecture system. Freed up some space in doing
; that, mainly because I could get rid of the CLR A in front of most
; every MOVC. MOVC is still used in the AutoRate routine, because of the
; table access.
;
; Not sure what to do about LEAVE. One version of forth (FPC 3.53) says
; that the F83 standard requires LEAVE to immediately exit the DO..LOOP.
; The BryteForth manuals says that LEAVE sets the loop limit to the index
; value, and terminates at the next execution of LOOP or +LOOP. I went
; and implemented it as the FPC model (Mostly because it seems more useful,
; plus I don't have a copy of the standards!)
;
; DO..LOOP type loops have this format in memory: (DO) <x> ... (LOOP) <y>.
; <x> is the address of the next word after <y>. This is so that ?DO knows
; how to skip the words between DO and LOOP. <y> is the address of the word
; after <x>. This is there so that LOOP knows where to resume the loop.
; You can confuse the compiler by building a word like this: : BLOWUP
; 10 0 DO ." Hi!" I 5 = IF ." I=5" LOOP THEN ." I<>5" LOOP ;. This
; causes LOOP to store the skip address of the IF to the LOOP back address.
; After that, THEN stores the LOOP back address to the IF skip address.
; Finally, the second LOOP occurrence blows the stack because it was
; expecting the value DO pushed for the LOOP skip back address.
;
; When converting -TRAILING to assembly, I noticed that Tings original
; version treated any character less than 32 as a space character. Several
; other Forths I examined treated the space character only as a space
; character. This seemed more correct, so I fixed this version to treat
; only spaces as spaces. The assembly version takes about 12 more bytes
; but gains a lot of speed.
;
; In retrospect, I couldn't decide which LEAVE I liked better (immediate
; or non-immediate). So I added support for both. The equates IM_LEAVE
; defines whether delayed or immediate LEAVEs happen. I think I prefer
; the immediate LEAVE. Changing this equates automatically adjusts DO,
; UNDO, etc for which ever mode.
;
; I want to convert this Forth to Metalinks' ASM51 assembler, for 2 main
; reasons. The main is the generic jmp/call facility, which would free up
; a good deal of space. The other is that the Metalink assembler is
; supposedly public domain (the marketing guys there were surprised to learn
; that!). I tried the conversion, and lo! Within 10 minutes I had found
; a MAJOR flaw in their assembler. If you use ORG statements that do not
; grow from low to high, it gets mad and generates phase error messages. A
; call to tech support yielded "Yea, you're right. You found a bug we
; didn't know about, and it's broke. Sorry..." Stay tuned for a new ver-
; sion of Metalinks ASM51, folks...
;
;******************************************************************************
;
; Revision History -
;
; 1.01 - xx/xx/90 - CHT - Written
; 1.02 - 12/31/90 - JCW - Converted To 8031 Assembler Format
; 1.03 - 01/01/90 - JCW - Add Equates, Memory Map Expectations
; 1.04 - 01/01/91 - JCW - Macro'ized PUSH/POP/PUSHIP/POPIP Sequences
; 1.05 - 01/01/91 - JCW - Add Forth Commenting To %colon Definitions
; 1.06 - 01/02/91 - JCW - Added 1 0 -1 1+ 2+ 1- 2- BYE NIP R>DROP P1@
; P1! P3@ P3! C, NOP
; 1.07 - 01/02/91 - JCW - Converted @EXECUTE COUNT BL CELL- CELL+ = ABS -
; NEGATE + NOT 2DROP To Assembly
; 1.08 - 01/03/91 - JCW - Optimized As Many Existing Assembly Words As
; Possible
; 1.09 - 01/04/91 - JCW - Removed Dependancy On Code Word Alignment. Freed
; Up Quite A Bit Of Space. Converted %user To
; Call DOUSER Directly, Rather Than Through DOLIST.
; 1.10 - 01/05/91 - JCW - Added CSAME? Which Compares 2 Buffers For 'N'
; Bytes (SAME? Compares Words). Convert 'find'
; To Use CSAME? Also Optimized Register Usage So
; That All Parameters Are Kept In Registers.
; 1.11 - 01/05/91 - JCW - Removed Dependancy On Dictionary Alignment. Also
; Added DUP>R, And Fixed Colon Definitions To Use.
; Deleted ALIGNED And SAME? From Dictionary.
; 1.12 - 01/05/91 - JCW - Removed CELLS, Add 2* 2/. Convert PICK And DEPTH
; To Assembly, And Fix To Assume A 16 Bit Cell Size.
; Converted 2DUP To Assembly.
; 1.13 - 01/08/91 - JCW - Convert doVAR And ROT To Assembly. Wife Says
; Spending Too Much Time On 'Puter, So It's Been
; A Few Days Since I Could Mess With This. Sigh...
; 1.14 - 01/09/91 - JCW - Convert DNEGATE And U< To Assembly, Add -ROT.
; 1.15 - 01/10/91 - JCW - Convert SPACE, CMOVE, FILL, ?KEY, EMIT, TYPE And
; +! To Assembly. Add %sforth, SASMBLY And >.
; 1.16 - 01/12/91 - JCW - Convert CR And _TYPE To Assembly. Speed Up TX!.
; Fix PACK$ Not To Aligned To A Word Boundary. Add
; EVEN And ODD.
; 1.17 - 01/12/91 - JCW - Convert UM*, * And */MOD To Assembly (See Note).
; 1.18 - 01/13/91 - JCW - Convert >NAME To Assembly.
; 1.19 - 01/18/91 - JCW - Convert NAME>, MAX, MIN, 2@, 2! And SPACES To
; Assembly.
; 1.20 - 01/30/91 - JCW - Convert UM/MOD, M/MOD And /MOD To Assembly.
; 1.21 - 01/31/91 - JCW - Added CBITS, Convert EXTRACT To Assembly.
; 1.22 - 02/17/91 - JCW - Convert DIGIT? And NUMBER? To Assembly.
; 1.23 - 02/18/91 - JCW - Added AUTOBAUD And User Variable BAUD.
; 1.24 - 02/18/91 - JCW - Added CI! And CI@
; 1.25 - 02/19/91 - JCW - Added FREE, I, J, ERASE, BLANKS, JOIN, SPLIT, FLIP
; 1.26 - 02/20/91 - JCW - Added TOGGLE, UPPER, Convert Inline Push And Pop
; Sequences To Subroutines. Added PopReturn. Also
; Added Conditional Assembly Flags For Some Words.
; 1.27 - 02/23/91 - JCW - Added +-, D+-, S->D, DABS, D+, 0>, 0=, MU/MOD
; 1.28 - 02/24/91 - JCW - Added TUCK, UD., UD.R, D., D.R, (.), (D.), Fixed
; EXTRACT, #, #S And #> To Handle Double Numbers.
; 1.29 - 02/24/91 - JCW - Added UPC, Which If Non 0 Converts Lower Case
; Words To Upper, But Does Not Affect Embedded Text.
; 1.30 - 02/24/91 - JCW - Removed Words DIGIT And EXTRACT. Converted
; # And HOLD To Assembly.
; 1.31 - 02/28/91 - JCW - Delete xio, FILE, HAND, I/O, CONSOLE, PACE.
; Change QUIT Not To Check The Prompt Address
; To Decide Whether Or Not To Output ' ok'
; 1.32 - 02/28/91 - JCW - Added CONSTANT, Convert do$ To Assembly, Convert
; All MOVC References To MOVX (See Note Above).
; Change Run Time Names Of $"| To ($") And ."|
; To (.")
; 1.33 - 03/03/91 - JCW - Added DO, ?DO, LOOP, +LOOP, (DO), (?DO), (LOOP),
; (+LOOP), LEAVE, (LEAVE), ?LEAVE, (?LEAVE), UNDO.
; Fixed I, J To Work With DO, ?DO.
; 1.34 - 03/08/91 - JCW - Deleted FOR, AFT, NEXT.
; 1.35 - 03/10/91 - JCW - Convert -TRAILING To Assembly, Add Equate Switch
; For Immediate And Non-Immediate LEAVE.
;
; Things To Do --
;
; Convert find To Assembly, Is Space Available.
; Fix M/MOD and UM/MOD To Return A Double Qoutient, Instead Of Single.
; Fix (PARSE) And dm+ Not To Use (NEXT).
; Convert (PARSE) To Assembly.
; Use Assembler That Has Generic Jump Capability.
; Shift Code So That %code Routine Are At Top (For Generic Jumps).
;
;******************************************************************************
;
; Version Control
;
Ver_Major equ 001h ; Major Release Version
Ver_Minor equ 035h ; Minor Extension
;
; Option Select
;
IM_LEAVE equ -1 ; 0 For Non Immediate LEAVE
Word_DOTS equ 0 ; 0 For No .S Word
Word_SEE equ 0 ; 0 For No SEE Word
Word_DUMP equ 0 ; 0 For No DUMP Word
Word_WORDS equ 0 ; 0 For No WORDS Word
Word_TNAME equ 0 ; 0 For No >NAME Word
Word_AUTOBAUD equ -1 ; 0 For No AUTOBAUD Word (Etc...)
;
; Constants
;
Lex_CO equ 00040h ; Lexicon Compile Only Bit
Lex_IM equ 00080h ; Lexicon Immediate Bit
Lex_LN equ 0001fh ; Lexicon + Length Bit Mask (Keep Bits)
;
WrdLen equ 2 ; Size Of A Cell
DfltBase equ 10 ; Default Radix
VocDpt equ 8 ; Depth Of Vocabulary Stack
;
ASC_BS equ 008h ; Back Space
ASC_LF equ 00ah ; Line Feed
ASC_CR equ 00dh ; Carriage Return
;
Calll equ 0012h ; NOP CALL Opcodes
;
;******************************************************************************
;
; Memory Map --> (Assumes ROM 0000-1FFFH, RAM 6000-8000H)
;
; IP - N/A - N/A - Forth Instruction Pointer
; TP - N/A - N/A - Top Of Stack Value
; CP - 6000- NP - Grows Lo To Hi - Non-ROM Code Area (CP Is Next Available)
; NP - CP -7CFF - Grows Lo To Hi - Non-ROM Name Area (NP Is Next Available)
; SP - 7D00-7DFF - Grows Hi To Lo - Forth Parameter Stack
; RP - 7E00-7EFF - Grows Hi To Lo - Forth Return Stack
; UP - 7F00-7FFF - Grows Lo To Hi - User Variables (Vectored Execution Words)
;
; Note That The Terminal Input Buffer (TIB) Shares The 256 Byte Page With The
; Forth Return Stack. The Return Stack Grows From High To Low, While The
; TIB Fills From Low To High. It Might Be A Good Idea To Move The TIB Into
; It's Own 256 Byte Page.
;
RamBtm equ 06000h ; Bottom Of RAM Memory
RamLen equ 02000h ; Length Of RAM Memory
RamEnd equ RamBtm+RamLen ; Top Of RAM Memory
RomBtm equ 00000h ; Start Of ROM
RomLen equ 02000h ; Length Of ROM
RomTop equ RomBtm+RomLen ; Top Of ROM
;
UP0Len equ 00100h ; User Area Size In Cells
RP0Len equ 00100h ; Return Stack/TIB Size
SP0Len equ 00100h ; Data Stack Size
;
UP0Btm equ RamEnd-UP0Len ; Start Of User Area (UP0)(7F00)
UP0Top equ UP0Btm+UP0Len-2 ; Last Addr Of User Area (UP0)(7FFF)
TIBBtm equ UP0Btm-RP0Len ; Terminal Input Buffer (TIB)
RP0Btm equ UP0Btm-RP0Len ; Start Of Return Stack (RP0)(7E00)
RP0Top equ RP0Btm+RP0Len-2 ; Last Addr Of Return Stack (RP0)(7EFE)
SP0Btm equ RP0Btm-RP0Len ; Start Of Data Stack (SP0)(7D00)
SP0Top equ SP0Btm+SP0Len-2 ; Last Addr Of Parm Stack (SP0)(7DFE)
UNmTop equ SP0Btm-2 ; Start Of User Names (NP)
UCdBtm equ RamBtm ; Start Of User Code (CP)
NamTop equ RomBtm+RomLen-2 ; Initial Name Dictionary
;
; Initialize Assembly Variables
;
_link = 0 ; Force A Null Link First Time
_name = NamTop ; Initialize Name Pointer
_code = CodBtm ; Initialize Code Pointer
_user = 4*WrdLen ; First User Variable Offset
;
;******************************************************************************
;
; eForth Model Register Equates
;
;spl equ r0
;rpl equ r1
;sph equ r4
;rph equ r5
;tpl equ r2
;tph equ r3
;ipl equ r6
;iph equ r7
gpl equ 010h
gph equ 011h
stk equ 012h
;
;******************************************************************************
;
; Compile A Code Definition Header. Align To A Byte Boundary
;
macro %code
\2 equ $
_len = (\0 & 01fh)
_name = _name-((_len+5))
org _name
dw \2
dw _link
_link = $
db \0,\1
org \2
endmac
;
; Compile A Colon Definition Header.
;
macro %colon
%code \0,\1,\2
lcall DOLIST
endmac
;
; Compile a user variable header.
;
macro %user
%code \0,\1,\2
lcall DOUSER
dw _user
\2_Vec equ _user+UP0Btm
_user = _user+WrdLen
endmac
;
; Compile An Inline String.
;
macro %dmm
dw \0
_len = $
db 0,\1
_code = $
org _len
db _code-_len-1
org _code
endmac
;
; During assembly execution, switch to forth. Complements SASMBLY.
;
macro %sforth
lcall DOLIST
endmac
;
; Pseudo 16 bit TP load
;
macro %loadtp
mov tpl,#low(\0)
mov tph,#high(\0)
endmac
;
;******************************************************************************
;
; System Power Up And Reset Entry Point
;
org RomBtm
ljmp SysStart ; Jump Start System
reti ; Return From IE0 Interrupt
db 0,0,0,0,0,0,0 ; Filler
reti ; Return From TF0 Interrupt
db 0,0,0,0,0,0,0 ; Filler
reti ; Return From IE1 Interrupt
db 0,0,0,0,0,0,0 ; Filler
reti ; Return From TF1 Interrupt
db 0,0,0,0,0,0,0 ; Filler
reti ; Return From RI+TI Interrupt
db 0,0,0,0,0,0,0 ; Filler
reti ; Return From TF2+EXF2 Interrupt
;
;******************************************************************************
;
; Defaulted User Variables. Routine COLD Moves These To The User Area. MUST
; Be In The Same Order As User Variables Are Defined.
;
UsrBtm: dw 0 ; Reserved
dw 0 ; Reserved
dw 0 ; Reserved
dw 0 ; Reserved
dw SP0Top ; SP0
dw RP0Top ; RP0
dw QRX ; '?KEY
dw TXSTORE ; 'EMIT
dw ACCEPT ; 'EXPECT
dw KTAP ; 'TAP
dw TXSTORE ; 'ECHO
dw DOTOK ; 'PROMPT
dw DfltBase ; BASE
dw 0 ; tmp
dw 0 ; SPAN
dw 0 ; >IN
dw 0 ; #TIB
dw TIBBtm ; TIB
dw 0 ; CSP
dw INTER ; 'EVAL
dw NUMBERQ ; 'NUMBER
dw 0 ; HLD
dw 0 ; HANDLER
dw 0 ; CONTEXT Pointer
dw 0 ; Vocab Stack 1 (VocDpt)
dw 0 ; Vocab Stack 2
dw 0 ; Vocab Stack 3
dw 0 ; Vocab Stack 4
dw 0 ; Vocab Stack 5
dw 0 ; Vocab Stack 6
dw 0 ; Vocab Stack 7
dw 0 ; Vocab Stack 8
dw 0 ; CURRENT Pointer
dw 0 ; Vocabulary Link Pointer
dw UCdBtm ; CP
dw UNmTop ; NP
dw LstNam ; LAST
dw LstNam ; FORTH
dw 0 ; Vocabulary Link
dw 0 ; Current Baud Rate
dw 1 ; UPC
UsrLst equ $ ; Last Address Of User Area
UsrLen equ UsrLst-UsrBtm ; Length Of User Area
;
;******************************************************************************
;
; Start Of Dictionary Code
;
CodBtm: nop
SysStart: mov ie,#000h ; No Interrupts
mov sp,#stk ; Stack Starts At 0012h Internal
mov psw,#008h ; Select Register Set 1
mov rpl,#low(RP0Top); Load Low Of Return Pointer
mov rph,#high(RP0Top); Load High Of Return Pointer
mov spl,#low(SP0Top); Load Low Of Stack Pointer
mov sph,#high(SP0Top); Load High Of Stack Pointer
mov p2,sph ; Setup Page Register For Stack High
ljmp COLD ; Start User Application
;
;******************************************************************************
;
; AutoRate - Determine Baud Rate Of Serial Port By Timing Start Bit. Tables
; Are Setup To Allow +-3% Variation In Timing. If Can't Get A
; Good Baud Rate, Just Keep Trying. Return B/A With Current
; Baud Rate.
;
if Word_AUTOBAUD
AutoRate: mov scon,#052h ; Mode 3 Serial Port
mov tmod,#021h ; Timer 1 Mode 2, Timer 0 Mode 1
mov sbuf,#000h ; Send A Null For First Character
setb tr1 ; Start Timer 1 Up
clr rs0 ; Switch To Register Bank 0
;
; Wait For Start Bit, Run Timer While Start Bit High
;
Aut_0: clr ri ; Ignore Any Character In SBUF
clr tr0 ; Cancel Timer 0
mov th0,#000h ; Clear Timer 0 High
mov tl0,#000h ; Clear Timer 0 Low
jb p3.0,$ ; Wait For Start Bit High
setb tr0 ; Start Timer 0 Running
jnb p3.0,$ ; Wait For Start Bit To Go Lo
clr tr0 ; Cancel Timer 0
;
; Timer 0 Has Start Bit Period. Test Against Table.
;
mov dptr,#Table ; Point To Table
Aut_1: mov a,#0 ; Set For MOVC
movc a,@a+dptr ; Get High Byte From Table
cjne a,th0,Aut_2 ; Compare
mov a,#1 ; Set For MOVC
movc a,@a+dptr ; Get Low Byte From Table
cjne a,tl0,Aut_2 ; Compare
Aut_2: jc Aut_4 ; If Greater, Try Next Entry
mov a,#2 ; Set For MOVC
movc a,@a+dptr ; Get High Byte From Table
cjne a,th0,Aut_3 ; Compare
mov a,#3 ; Set For MOVC
movc a,@a+dptr ; Get Low Byte From Table
cjne a,tl0,Aut_3 ; Compare
setb c ; Flip Status
Aut_3: jnc Aut_4 ; If Less, Try Next Entry
;
mov a,#4 ; Point To SMOD Status Byte
movc a,@a+dptr ; Get SMOD Byte
mov pcon,a ; Store It Back
mov a,#5 ; Point To Speed Byte
movc a,@a+dptr ; Get Speed Byte
mov th1,a ; Setup Baud Rate Timer
mov tl1,a ; Setup Baud Rate Timer
jnb ri,$ ; Wait For Character
clr ri ; Say Character Received Isn't There
mov a,#6 ; Offset To Baud Rate High
movc a,@a+dptr ; Get High Of Baud Rate In Binary
mov b,a ; Store In B
mov a,#7 ; Offset To Baud Rate Low
movc a,@a+dptr ; Get Low Of Baud Rate In Binary
setb rs0 ; Back To Register Bank 1
ret ; Return To Caller
;
Aut_4: mov a,#8 ; Number Bytes In Record
add a,dpl ; Add In DPL
mov dpl,a ; Back To DPL
jnc Aut_5 ; If No Carry, Skip
inc dph ; Increment High Of DPTR
Aut_5: movx a,@dptr ; Get Byte
cjne a,#-1,Aut_1 ; While Not -1, Loop
sjmp Aut_0 ; Try Again
;
; All Values Calculated For 11.059200Mhz
;
Table: dw 6328, 5960, 00040h, 00150; 150
dw 3164, 2980, 000a0h, 00300; 300
dw 2109, 1987, 000c0h, 00450; 450
dw 1582, 1490, 000d0h, 00600; 600
dw 0791, 0745, 000e8h, 01200; 1200
dw 0527, 0497, 000f0h, 01800; 1800
dw 0396, 0372, 000f4h, 02400; 2400
dw 0264, 0248, 000f8h, 03600; 3600
dw 0198, 0186, 000fah, 04800; 4800
dw 0132, 0124, 000fch, 07200; 7200
dw 0099, 0093, 000fdh, 09600; 9600
dw 0066, 0062, 000feh, 14400; 14400
dw 0049, 0047, 080fdh, 19200; 19200
dw -1
endif
;
;******************************************************************************
;
; RETURN - The Forth Inner Interpreter
;
PopReturn: lcall PopSP
Return: mov dpl,ipl
mov dph,iph
AltReturn: movx a,@dptr
mov b,a
inc dptr
movx a,@dptr
mov dph,b
mov dpl,a
mov a,ipl
add a,#002h
mov ipl,a
jnc Ret_1
inc iph
Ret_1: clr a
jmp @a+dptr
;
PopSP: inc spl
movx a,@spl
mov tph,a
inc spl
movx a,@spl
mov tpl,a
ret
;
PushSP: mov a,tpl
movx @spl,a
dec spl
mov a,tph
movx @spl,a
dec spl
ret
;
PopDP: inc spl
movx a,@spl
mov dph,a
inc spl
movx a,@spl
mov dpl,a
ret
;
PushDP: mov a,dpl
movx @spl,a
dec spl
mov a,dph
movx @spl,a
dec spl
ret
;
PopIP: mov p2,rph
inc rpl
movx a,@rpl
mov iph,a
inc rpl
movx a,@rpl
mov ipl,a
mov p2,sph
ret
;
NextIPRet: mov dpl,ipl
mov dph,iph
movx a,@dptr
mov iph,a
inc dptr
movx a,@dptr
mov ipl,a
ljmp Return
;
LoadNextIP: mov a,ipl
add a,#2
mov ipl,a
jnc Loa_1
inc iph
Loa_1: ret
;
PushIPRS: mov p2,rph
mov a,ipl
movx @rpl,a
dec rpl
mov a,iph
movx @rpl,a
dec rpl
mov p2,sph
ret
;
PopSPRS: mov p2,rph
inc rpl
movx a,@rpl
mov tph,a
inc rpl
movx a,@rpl
mov tpl,a
mov p2,sph
ret
;
PopDPRS: mov p2,rph
inc rpl
movx a,@rpl
mov dph,a
inc rpl
movx a,@rpl
mov dpl,a
mov p2,sph
ret
;
PushSPRS: mov p2,rph
mov a,tpl
movx @rpl,a
dec rpl
mov a,tph
movx @rpl,a
dec rpl
mov p2,sph
ret
;
PushDPRS: mov p2,rph
mov a,dpl
movx @rpl,a
dec rpl
mov a,dph
movx @rpl,a
dec rpl
mov p2,sph
ret
;
;******************************************************************************
;
; The Kernel
;
; doLIT ( -- w )
; Push an inline literal.
;
%code Lex_CO+5,'doLIT',DOLIT
lcall LitConCmn
inc dptr
mov ipl,dpl
mov iph,dph
ljmp AltReturn
;
; doCON ( -- a )
; Run time routine for CONSTANT
;
%code Lex_CO+5,'doCON',DOCON
lcall LitConCmn
lcall PopIP
ljmp Return
;
LitConCmn: lcall PushSP
mov dpl,ipl
mov dph,iph
movx a,@dptr
mov tph,a
inc dptr
movx a,@dptr
mov tpl,a
ret
;
; doLIST ( a -- )
; Process colon list.
;
%code Lex_CO+6,'doLIST',DOLIST
lcall PushIPRS
pop iph
pop ipl
ljmp Return
;
; (NEXT) ( -- )
; Run time code for the single index loop.
; R> R> DUP IF 1 - >R @ >R EXIT THEN DROP CELL+ >R ;
;
%code Lex_CO+6,'(NEXT)',PNEXTP
mov p2,rph
inc rpl
inc rpl
movx a,@rpl
clr c
subb a,#001h
movx @rpl,a
dec rpl
movx a,@rpl
subb a,#000h
movx @rpl,a
inc rpl
mov p2,sph
jnc Nex_1
lcall LoadNextIP
ljmp Return
;
Nex_1: dec rpl
dec rpl
ljmp NextIPRet
;
; ?branch ( f -- )
; Branch if flag is zero.
;
%code Lex_CO+7,'?branch',QBRAN
mov a,tpl
orl a,tph
jz Qbr_1
lcall LoadNextIP
ljmp PopReturn
Qbr_1: lcall PopSP
ljmp NextIPRet
;
; branch ( -- )
; Branch to an inline address.
;
%code Lex_CO+6,'branch',BRAN
ljmp NextIPRet
;
; EXECUTE ( cfa -- )
; Execute the word at cfa.
;
%code 7,'EXECUTE',EXECUTE
mov dpl,tpl
mov dph,tph
lcall PopSP
clr a
jmp @a+dptr
;
; EXIT ( -- )
; Terminate a colon definition.
;
%code 4,'EXIT',EXIT
lcall PopIP
ljmp Return
;
; ! ( n1 a1 -- )
; Pop the data stack to memory.
;
%code 1,'!',STORE
mov dpl,tpl
mov dph,tph
inc spl
movx a,@spl
movx @dptr,a
inc dptr
inc spl
movx a,@spl
movx @dptr,a
ljmp PopReturn
;
; @ ( a -- w )
; Push memory location to the data stack.
;
%code 1,'@',GET
mov dpl,tpl
mov dph,tph
movx a,@dptr
mov tph,a
inc dptr
movx a,@dptr
mov tpl,a
ljmp Return
;
; C! ( c a -- )
; Pop the data stack to byte memory.
;
%code 2,'C!',CSTORE
mov dpl,tpl
mov dph,tph
inc spl
inc spl
movx a,@spl
movx @dptr,a
ljmp PopReturn
;
; C@ ( b -- c )
; Push byte memory location to the data stack.
;
%code 2,'C@',CAT
mov dpl,tpl
mov dph,tph
movx a,@dptr
mov tpl,a
mov tph,#000h
ljmp Return
;
; >R ( w -- )
; Push the data stack to the return stack.
;
%code Lex_CO+2,'>R',TOR
lcall PushSPRS
ljmp PopReturn
;
; R@ ( -- w )
; Copy top of return stack to the data stack.
;
%code 2,'R@',RAT
lcall PushSP
mov dpl,rpl
mov dph,rph
inc dpl
movx a,@dptr
mov tph,a
inc dpl
movx a,@dptr
mov tpl,a
ljmp Return
;
; R> ( -- w )
; Pop the return stack to the data stack.
;
%code 2,'R>',RFROM
lcall PushSP
lcall PopSPRS
ljmp Return
ret
;
; RP@ ( -- a )
; Push the current RP to the data stack.
;
%code 3,'RP@',RPAT
lcall PushSP
mov tpl,rpl
mov tph,rph
ljmp Return
;
; RP! ( a -- )
; Set the return stack pointer.
;
%code Lex_CO+3,'RP!',RPSTORE
mov rpl,tpl
mov rph,tph
ljmp PopReturn
;
; SP@ ( -- a )
; Push the current data stack pointer.
;
%code 3,'SP@',SPAT
lcall PushSP
mov tpl,spl
mov tph,sph
ljmp Return
;
; SP! ( a -- )
; Set the data stack pointer.
;
%code 3,'SP!',SPSTORE
mov spl,tpl
mov sph,tph
ljmp PopReturn
;
; DUP ( w -- w w )
; Duplicate the top stack item.
;
%code 3,'DUP',DUP
lcall PushSP
ljmp Return
;
; ?DUP ( w -- w w | 0 )
; Dup tos if its is not zero.
;
%code 4,'?DUP',QDUP
mov a,tpl
orl a,tph
jz Qdu_1
lcall PushSP
Qdu_1: ljmp Return
;
; DROP ( w -- )
; Discard top stack item.
;
%code 4,'DROP',DROP
ljmp PopReturn
;
; SWAP ( w1 w2 -- w2 w1 )
; Exchange top two stack items.
;
%code 4,'SWAP',_SWAP
inc spl
movx a,@spl
xch a,tph
movx @spl,a
inc spl
movx a,@spl
xch a,tpl
movx @spl,a
dec spl
dec spl
ljmp Return
;
; OVER ( w1 w2 -- w1 w2 w1 )
; Copy second stack item to top.
;
%code 4,'OVER',OVER
mov dpl,spl
mov dph,sph
lcall PushSP
inc dpl