-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy patheforth.asm
1930 lines (1738 loc) · 53.9 KB
/
eforth.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
; MISC-16 eForth port
; Special CPU registers
pc equ 0
pc+2 equ 1
pc+4 equ 2
pc+6 equ 3
[a] equ 7
a equ 8
pcs equ 1
pcz equ 2
pcc equ 4
a- equ 9
a+ equ 11
a^ equ 12
a| equ 13
a& equ 14
a>> equ 15
; UART registers
tx equ 0xfffc ; Transmit register
?tx equ 0xfffd ; Bit 0 transmiter busy
rx equ 0xfffe ; Receive register
?rx equ 0xffff ; Bit 0 receive register empty
org 0x10
mov pc,start
start dw cold
; Data and return stack
rp0 dw rp0
org 0x100
underflow dw 0,0,0,0
sp0 dw underflow
; Terminal input buffer
tibb org 0x12d
; System variables
sp dw 0 ; Stack pointer
rp dw 0 ; Return stack pointer
ip dw 0 ; Interpreter pointer
t0 dw 0 ; Temporary variables
t1 dw 0
t2 dw 0
t3 dw 0
; Literals
#0 dw 0
#1 dw 1
#2 dw 2
#16 dw 16
#ff dw 0xff
#ff00 dw 0xff00
#ffff dw 0xffff
; ( -- w )
; Push an inline literal
dolit mov a,ip
mov t0,[a]
mov a+,#1
mov ip,a
mov a,sp
mov a-,#1
mov sp,a
mov [a],t0
mov pc,dnext
; ( -- )
; Process colon list t0
dolist dw dolist1
dolist1 mov a,rp
mov a+,#1
mov rp,a
mov [a],ip
mov ip,t0
dolist2 mov a,ip
mov t0,[a]
mov a+,#1
mov ip,a
mov pc,t0
; ( -- )
; Execute next word on list
dnext dw dolist2
; ( -- )
; Run time code for the single index loop
donext mov a,rp ; RP points to index
mov a,[a]
mov a-,#1 ; Decrement index
mov t0,a
mov a,rp
mov pcc,donext1 ; Jump if loop finished (index was 0 before decrementing)
mov [a],t0 ; Store new index
mov a,ip ; IP points to location of word to jump back to
mov ip,[a]
mov pc,dnext
donext1 dw donext2 ; Loop has finished
donext2 mov a-,#1 ; Decrement RP (remove index from return stack)
mov rp,a
mov a,ip ; Skip next word
mov a+,#1
mov ip,a
mov pc,dnext ; Execute next word on list
; ( f -- )
; Branch if flag is zero
qbranch mov a,sp
mov t0,[a]
mov a+,#1
mov sp,a
mov a,ip
mov t1,[a]
mov a+,#1
mov ip,a
mov a,t0
mov pcz,pc+4
mov pc,dnext
mov ip,t1
mov pc,dnext
; ( -- )
; Branch to an inline address
branch mov a,ip
mov ip,[a]
mov pc,dnext
; ( -- a )
; Initialize the return stack pointer
rpstore mov rp,rp0
mov pc,dnext
; ( -- a )
; Initialize the data stack pointer
spstore mov sp,sp0
mov pc,dnext
; ( -- a )
; Run time routine for variable and create
dovar mov t0,pc+4
mov pc,dolist
dw rfrom,twom,exit
; ( -- b )
; Return the address of a compiled string
dostr mov t0,pc+4
mov pc,dolist
dw rfrom,rfrom,twom,dup,count,plus
dw onep,twod,tor,swap,tor,exit
; ( n -- char )
; Convert n to a printable character
tochar mov t0,pc+4
mov pc,dolist
dw dup,dolit,0x7f,bl,within
dw qbranch,tochar1
dw drop,dolit,'.'
tochar1 dw exit
; ( -- )
; Run time routine of ."
dotqp mov t0,pc+4
mov pc,dolist
dw dostr,count,type,exit
; ( -- a )
; Variable used during construction of numeric output strings
hld mov t0,pc+4
mov pc,dolist
dw dovar,0
; ( u -- c )
; Convert digit u to a character
digit mov t0,pc+4
mov pc,dolist
dw dolit,9,over,less
dw dolit,39,and,plus
dw dolit,'0',plus,exit
; ( n base -- n c )
; Extract the least significant digit from n
extract mov t0,pc+4
mov pc,dolist
dw dolit,0,swap,ummod
dw swap,digit,exit
; ( n -- b u )
; Convert a signed integer to a numeric string
str mov t0,pc+4
mov pc,dolist
dw dup,tor,abs,bdigs,digs,rfrom,sign,edigs,exit
; ( -- n )
; Return the length of the terminal input buffer
tibl mov t0,pc+4
mov pc,dolist
dw dolit,sp,twom,tib,sub,exit
; ( -- a )
; Variable used to track the number of characters in the input buffer
ntib mov t0,pc+4
mov pc,dolist
dw dovar,0
; ( bot eot cur -- bot eot cur )
; Backup the cursor by one character
bksp mov t0,pc+4
mov pc,dolist
dw tor,over,rfrom,swap,over,xor
dw qbranch,bksp1
dw dolit,8,dup,emit,space,emit
dw onem
bksp1 dw exit
; ( bot eot cur c -- bot eot cur )
; Accept and echo the key stroke and bump the cursor
tap mov t0,pc+4
mov pc,dolist
dw dup,emit,over,cstore,onep,exit
; ( bot eot cur c -- bot eot cur )
; Process a key stroke, CR or backspace
ktap mov t0,pc+4
mov pc,dolist
dw dup,dolit,13,xor
dw qbranch,ktap1
dw dolit,8,xor
dw qbranch,ktap2
dw bl,tap,exit
ktap1 dw space,drop,swap,drop,dup,exit
ktap2 dw bksp,exit
; ( -- a )
; Character pointer while parsing input stream
inn mov t0,pc+4
mov pc,dolist
dw dovar,0
; ( -- a )
; Execution vector of eval
teval mov t0,pc+4
mov pc,dolist
dw dovar,0
; ( -- a )
; Pointer to name field of last word in dictionary
context mov t0,pc+4
mov pc,dolist
dw dovar,0
; ( -- a )
; Pointer to name field of last word in dictionary
last mov t0,pc+4
mov pc,dolist
dw dovar,0
; ( -- )
; Link a successfully defined word into the dictionary
overt mov t0,pc+4
mov pc,dolist
dw last,at,context,store,exit
; ( c base -- u t )
; Convert a character to its numeric value. A flag indicates success
digitq mov t0,pc+4
mov pc,dolist
dw tor,dolit,'0',sub
dw dolit,9,over,less
dw qbranch,digitq1
dw dolit,39,sub
dw dup,dolit,10,less,or
digitq1 dw dup,rfrom,uless,exit
; ( na -- ca )
; Return code address from name address
cfa mov t0,pc+4
mov pc,dolist
dw dup,cat ; Get length of name and flags
dw dolit,0x3f,and ; Mask flags
dw plus ; Add length to name address
dw twod,onep ; Divide by two and round up
dw exit
; ( a a -- a a F )
; Compare two strings return true if they match
sameq mov t0,pc+4
mov pc,dolist
dw over,over
dw dup,cat,dolit,0x3F,and,tor ; Setup for loop with character count
dw branch,sameq2 ; Branch for first iteration
sameq1 dw over,cat,over,cat ; Get string characters
dw equal,qbranch,sameq3 ; Compare, branch if no match
sameq2 dw onep,swap,onep ; Increment pointers
dw donext,sameq1 ; Next
dw ddrop,dolit,-1,exit ; Strings match, tidy up and return true
sameq3 dw rfrom,drop ; Match failed, cleanup for loop
dw ddrop,dolit,0,exit ; Strings don't match tidy up and return false
; ( a -- ca na | a F )
; Search dictionary for a string, return code and name field address if found else false
nameq mov t0,pc+4
mov pc,dolist
dw context,at ; Last word in dictionary
nameq1 dw dup,qbranch,nameq2 ; Branch if start of dictionary reached
dw over,at,over,at ; First two cells of strings
dw dolit,0x3fff,and ; Mask dictionary string compile and immediate flags
dw equal,qbranch,nameq3 ; Branch if first cells are not equal
dw sameq,qbranch,nameq3 ; Branch if strings don't match
dw swap,drop,dup,cfa,swap ; Name found, drop search string and push code field address
nameq2 dw exit
nameq3 dw dolit,2,sub
dw at,twom,branch,nameq1 ; Move to next word in dictionary
; ( w -- )
; Compile top item to dictionary as an integer literal
literal mov t0,pc+4
mov pc,dolist
dw compile,dolit
dw comma,exit
; ( a -- )
; Interpret a word. If failed, try to convert it to an integer
interpret mov t0,pc+4
mov pc,dolist
dw nameq,qdup,qbranch,interpret1
dw cat,dolit,0x80,and
dw abortqp
db 12,'compile only'
dw execute,exit
interpret1 dw numberq,qbranch,interpret2
dw exit
interpret2 dw error
; ( a -- )
; Compile next word to dictionary as a token or literal
scompile mov t0,pc+4
mov pc,dolist
dw nameq,qdup ; Defined?
dw qbranch,scompile2
dw cat,dolit,0x40,and ; Immediate?
dw qbranch,scompile1
dw execute,exit ; Its immediate, execute
scompile1 dw comma,exit ; Its not immediate, compile
scompile2 dw numberq ; Number?
dw qbranch,scompile3
dw literal,exit ; Its a number, compile
scompile3 dw space,count,type,dotqp
db 2,' ?'
dw context,at,last,store,quit
; ( -- F | c T)
; Return true and the next character from the input buffer or false if the buffer is empty
tibfrom mov t0,pc+4
mov pc,dolist
dw inn,at,ntib,at,xor,dup,qbranch,tibfrom1 ; Buffer empty?
dw tib,inn,at,plus,cat ; No, read character
dw dolit,1,inn,pstore ; Increment parsing pointer
dw swap,zequal,not ; True flag
tibfrom1 dw exit
; ( c -- b u )
; Scan input stream and return counted string delimited by c
parse mov t0,pc+4
mov pc,dolist
dw tor ; Save delimiter
dw rat,bl,xor,not,qbranch,parse2 ; Branch if delimiter is not space
parse1 dw tibfrom,qbranch,parse2 ; Read next character, branch if buffer is empty
dw bl,xor,qbranch,parse1 ; Loop if character is space
dw dolit,-1,inn,pstore ; Backup parsing index to first character after spaces
parse2 dw inn,at,tib,plus ; Address of start of string
dw dolit,0 ; Initialize character count
parse3 dw tibfrom,qbranch,parse4 ; Read next character, branch if buffer empty
dw rat,xor,qbranch,parse4 ; Branch if delimeter
dw onep,branch,parse3 ; Increment character count
parse4 dw rfrom,drop,exit ; Remove delimiter from return stack
; ( b u a -- a )
; Build a counted string with u characters from b
packs mov t0,pc+4
mov pc,dolist
dw dup,tor ; Save address of word buffer
dw ddup,cstore ; Store the character count first
dw onep,ddup,plus ; Go to the end of the string
dw dolit,0,swap,store ; Fill then end with 0's
dw swap,cmove ; Copy the string
dw rfrom,exit ; Leave only the buffer address
; ( -- )
; Abort if the data stack underflows
qstack mov t0,pc+4
mov pc,dolist
dw depth,zless ; Stack depth < 0?
dw abortqp
db 10,' underflow'
qstack1 dw exit
; ( -- )
; Interpret the input stream
eval mov t0,pc+4
mov pc,dolist
eval1 dw bl,word,dup,cat ; Parse a word
dw qbranch,eval2 ; Branch if character count is 0
dw teval,atexecute,qstack ; Evaluate and check for stack underflow
dw branch,eval1 ; Repeat until word gets a null string
eval2 dw drop,exit ; Discard string address and display prompt
; ( a -- a )
; Display a warning message if the word already exists
qunique mov t0,pc+4
mov pc,dolist
dw dup,nameq
dw qbranch,qunique1
dw dotqp,
db 11,' redefined '
dw over,count,type
qunique1 dw drop,exit
; ( -- )
; Create dictionary header from input buffer word. Abort if word is null
header mov t0,pc+4
mov pc,dolist
dw last,at,twod,comma ; Compile link field
dw here,last,store ; Set new word as last defined word
dw bl,word ; Copy word from input buffer to top of dictionary
dw dup,cat,zequal,abortqp ; Abort if string length is null
db 5,' name'
dw qunique ; Display warning if word already exists in dictionary
dw cat,here,plus,onep ; Add new word string length onto top of dictionary pointer
dw dup,dolit,1,and ; Is dictionary pointer is on a word boundry?
dw qbranch,header1
dw dolit,0
dw over,cstore,onep ; No, pad string with null and advance pointer by 1
header1 dw dp,store ; Store new end of dictionary pointer
dw exit ; Return true
; ( -- )
; Compile the next address in colon list to the dictionary
compile mov t0,pc+4
mov pc,dolist
dw rfrom,dup ; Get the next word address in the list
dw twom,at,comma ; Convert and compile address
dw onep,tor,exit ; Adjust return address
; ( -- )
; Compile dolist macro
ddolist mov t0,pc+4
mov pc,dolist
dw dolit,pc+4,comma
dw dolit,t0,comma ; mov t0,pc+4
dw dolit,dolist,comma
dw dolit,pc,comma ; mov pc,dolist
dw exit
; ( -- )
; Compile a literal string up to next "
strcq mov t0,pc+4
mov pc,dolist
dw dolit,'"',word ; Move string to dictionary
dw count,swap,drop ; Length of string, discard string address
dw here,plus,onep ; Add count-string length to dictionary pointer
dw dup,dolit,1,and ; Is dictionary pointer on a word boundry?
dw qbranch,strcq1
dw dolit,0
dw over,cstore,onep ; No, pad string with null and advance pointer by 1
strcq1 dw dp,store,exit ; Update dictionary pointer
; ( -- a )
; Run time routine compiled by $". Return address of a compiled string.
strqp mov t0,pc+4
mov pc,dolist
dw dostr,exit
; ( f -- )
; Run time routine of abort" Abort with a message.
abortqp mov t0,pc+4
mov pc,dolist
dw qbranch,abortqp1 ; Branch if flag is false
dw dostr,count,type ; Read and display error message
dw quit ; Restart text interpreter
abortqp1 dw dostr,drop,exit ; Read a drop error message
; ( a -- )
; Display error message in buffer at a and execute quit
error mov t0,pc+4
mov pc,dolist
dw space,count,type
dw dolit,'?',emit
dw quit
; ( -- )
; Display 'ok' only while interpreting
dotok mov t0,pc+4
mov pc,dolist
dw dolit,interpret
dw teval,at,equal
dw qbranch,dotok1
dw dotqp
db 3,' ok'
dotok1 dw exit
; ( -- a )
; Compile a forward branch instruction
ahead mov t0,pc+4
mov pc,dolist
dw compile,branch
dw here
dw dolit,0,comma
dw exit
; execute ( ca -- )
; Execute the word at ca
dw 0
_execute db 7,'execute'
execute mov a,sp
mov t0,[a]
mov a+,#1
mov sp,a
mov pc,t0
; exit ( -- )
; Terminate a a colon definition
dw _execute
_exit db 4,'exit'
exit mov a,rp
mov ip,[a]
mov a-,#1
mov rp,a
mov pc,dnext
; emit ( c -- )
; Send character c to the output device.
dw _exit
_emit db 4,'emit'
emit mov t0,pc+2 ; Load t0 with address of next instruction
mov a>>,?tx ; Shift transmit busy bit into carry
mov pcc,t0 ; Loop to previous instruction if carry set
mov a,sp
mov tx,[a] ; Read stack and transmit character
mov a+,#1 ; Decrement stack pointer
mov sp,a ; Store stack pointer
mov pc,dnext
; key ( -- c )
; Return input character
dw _emit
_key db 3,'key'
key mov t0,pc+2 ; Load t0 with address of next instruction
mov a>>,?rx ; Shift receive empty bit into carry
mov pcc,t0 ; Loop to previous instruction if carry set
mov a,sp
mov a-,#1 ; Increment stack pointer
mov sp,a ; Store stack pointer
mov [a],rx ; Push character onto stack
mov pc,dnext
; ?key ( -- F | c T )
; Return true and input character or false if no character received
dw _key
_qkey db 4,'?key'
qkey mov a>>,?rx ; Shift receive empty bit into carry
mov pcc,pc+4 ; Skip next instruction if no key pressed
mov pc,#qkey2
mov t0,#0 ; No key pressed, False flag
mov a,sp ; Push flag onto stack
qkey1 mov a-,#1
mov sp,a
mov [a],t0
mov pc,dnext ; Execute next word on list
qkey2 mov a,sp
mov a-,#1
mov sp,a
mov [a],rx ; Push key value onto stack
mov t0,#ffff ; True flag
mov pc,#qkey1
#qkey1 dw qkey1
#qkey2 dw qkey2
; ! ( w a -- )
; Pop the data stack to memory
dw _qkey
_store db 1,'!'
store mov a,sp
mov t0,[a]
mov a+,#1
mov t1,[a]
mov a+,#1
mov sp,a
mov a>>,t0
mov [a],t1
mov pc,dnext
; @ ( a -- w )
; Push memory location to the data stack
dw _store
_at db 1,'@'
at mov a+,#0
mov a,sp
mov a>>,[a]
mov t0,[a]
mov a,sp
mov [a],t0
mov pc,dnext
; c! ( c b -- )
; Pop the data stack to byte memory
dw _at
_cstore db 2,'c!'
cstore mov a,sp
mov t0,[a]
mov a+,#1
mov t1,[a]
mov a+,#1
mov sp,a ; Update stack pointer
mov a>>,t0 ; Shift address
mov t0,a
mov a,[a] ; Read value from memory
mov pcc,#cstore1 ; Jump if writing to low byte
mov a&,#ff
mov t2,a
mov a,t1
mov a+,a
mov a+,a
mov a+,a
mov a+,a
mov a+,a
mov a+,a
mov a+,a
mov a+,a
mov pc,#cstore2
cstore1 mov a&,#ff00
mov t2,a
mov a,t1
mov a&,#ff
cstore2 mov a|,t2
mov t1,a ; Write a to [t0]
mov a,t0
mov [a],t1
mov pc,dnext
#cstore1 dw cstore1
#cstore2 dw cstore2
; c@ ( b -- c )
; Push byte memory location to the data stack
dw _cstore
_cat db 2,'c@'
cat mov a+,#0 ; Clear carry
mov a,sp
mov a>>,[a] ; Read top value from stack and shift left
mov a,[a]
mov pcc,pc+6 ; Skip next 2 instructions if carry set
mov t0,pc+4 ; t0 address of instruction after next "return address"
mov pc,cat1 ; Jump to "subtroutine"
mov a&,#ff
mov t0,a
mov a,sp
mov [a],t0
mov pc,dnext
cat1 dw cat2
cat2 mov a>>,a
mov a>>,a
mov a>>,a
mov a>>,a
mov a>>,a
mov a>>,a
mov a>>,a
mov a>>,a
mov pc,t0
; r> ( -- w )
; Pop the return stack to the data stack
dw _cat
_rfrom db 2,'r>'
rfrom mov a,rp
mov t0,[a] ; Read return stack to t0
mov a-,#1
mov rp,a ; Update return stack pointer
mov a,sp
mov a-,#1
mov sp,a ; Update stack pointer
mov [a],t0 ; Store value to stack
mov pc,dnext
; r@ ( -- w )
; Copy top of return stack to the data stack
dw _rfrom
_rat db 2,'r@'
rat mov a,rp
mov t0,[a] ; Read return stack to t0
mov a,sp
mov a-,#1
mov sp,a ; Update stack pointer
mov [a],t0 ; Store value to stack
mov pc,dnext
; >r ( w -- )
; Push the data stack to the return stack
dw _rat
_tor db 2,'>r'
tor mov a,sp
mov t0,[a] ; Read stack to t0
mov a+,#1
mov sp,a ; Update stack pointer
mov a,rp
mov a+,#1
mov rp,a ; Update return stack pointer
mov [a],t0 ; Store value to return stack
mov pc,dnext
; drop ( w -- )
; Discard top stack item
dw _tor
_drop db 4,'drop'
drop mov a,sp
mov a+,#1
mov sp,a
mov pc,dnext
; dup ( w -- w w )
; Duplicate the top stack item
dw _drop
_dup db 3,'dup'
dup mov a,sp
mov t0,[a] ; Read stack to t0
mov a-,#1
mov sp,a ; Update stack pointer
mov [a],t0 ; Write value to stack
mov pc,dnext
; swap ( w1 w2 -- w2 w1 )
; Exchange top two stack items
dw _dup
_swap db 4,'swap'
swap mov a,sp
mov t0,[a] ; Read stack to t0
mov a+,#1
mov t1,[a] ; Read next on stack to t1
mov [a],t0 ; Write t0 to next on stack
mov a-,#1
mov [a],t1 ; Write t1 to stack
mov pc,dnext
; over ( w1 w2 -- w1 w2 w1 )
; Copy second stack item to top
dw _swap
_over db 4,'over'
over mov a,sp
mov a+,#1
mov t0,[a] ; Read next on stack to t0
mov a-,#2
mov sp,a ; Update stack pointer
mov [a],t0 ; Store t0 to stack
mov pc,dnext
; pick ( ... +n -- ... w )
; Copy the nth stack item to tos
dw _over
_pick db 4,'pick'
pick mov a,sp
mov a,[a] ; Read stack
mov a+,sp ; Move stack pointer back by value
mov a+,#1 ; Plus one to account for value just read
mov t0,[a] ; Read stack
mov a,sp ; Restore stack pointer
mov [a],t0 ; Store value read to stack
mov pc,dnext
; depth ( -- n )
; Return the depth of the data stack
dw _pick
_depth db 5,'depth'
depth mov a,sp0 ; Read location of start fo stack
mov a-,sp ; Subract stack pointer
mov t0,a ; t0 is depth
mov a,sp ; Push depth onto stack
mov a-,#1
mov sp,a
mov [a],t0
mov pc,dnext
; 0< ( n -- t )
; Return true if n is negative
dw _depth
_zless db 2,'0<'
zless mov a,sp
mov a,[a] ; Read stack
mov pcs,pc+6 ; Skip next two insructions if negative
mov t0,#0 ; False flag
mov pc,pc+4 ; Skip next instruction
mov t0,#ffff ; True flag
mov a,sp ; Get stack pointer
mov [a],t0 ; Write flag to stack
mov pc,dnext
; 0= ( n -- t)
; Return true if n is zero
dw _zless
_zequal db 2,'0='
zequal mov a,sp
mov a,[a]
mov pcz,pc+4
mov a,#1
mov a-,#1
mov t0,a
mov a,sp
mov [a],t0
mov pc,dnext
; and ( w w -- w )
; Bitwise and
dw _zequal
_and db 3,'and'
and mov a,sp
mov t0,[a]
mov a+,#1
mov sp,a
mov a,[a]
mov a&,t0
mov t0,a
mov a,sp
mov [a],t0
mov pc,dnext
; or ( w w -- w )
; Bitwise inclusive or
dw _and
_or db 2,'or'
or mov a,sp
mov t0,[a]
mov a+,#1
mov sp,a
mov a,[a]
mov a|,t0
mov t0,a
mov a,sp
mov [a],t0
mov pc,dnext
; xor ( w w -- w)
; Bitwise exclusive or
dw _or
_xor db 3,'xor'
xor mov a,sp
mov t0,[a]
mov a+,#1
mov sp,a
mov a,[a]
mov a^,t0
mov t0,a
mov a,sp
mov [a],t0
mov pc,dnext
; um+ ( w w -- w cy )
; Add two numbers, return the sum and carry flag
dw _xor
_uplus db 3,'um+'
uplus mov a,sp
mov t0,[a]
mov a+,#1
mov a,[a]
mov a+,t0
mov t0,a
mov a,sp
mov [a],#1
mov pcc,pc+4
mov [a],#0
mov a+,#1
mov [a],t0
mov pc,dnext
; 1+ ( a -- a+1 )
; Increment top item
dw _uplus
_onep db 2,'1+'
onep mov a,sp
mov a,[a]
mov a+,#1
mov t0,a
mov a,sp
mov [a],t0
mov pc,dnext
; 1- ( a -- a-1 )
; Decrement top item
dw _onep
_onem db 2,'1-'
onem mov a,sp
mov a,[a]
mov a-,#1
mov t0,a
mov a,sp
mov [a],t0
mov pc,dnext
; 2/ ( w - w/2 )
; Divide the top item by two
dw _onem
_twod db 2,'2/'
twod mov a+,#0 ; Clear carry
mov a,sp
mov a>>,[a]
mov t0,a
mov a,sp
mov [a],t0
mov pc,dnext
; 2* ( w - w*2 )
; Multiply the top item by two
dw _twod
_twom db 2,'2*'
twom mov a,sp
mov a,[a]
mov a+,a
mov t0,a
mov a,sp
mov [a],t0
mov pc,dnext
; cr ( -- )
; Output a carriage return and a line feed
dw _twom
_cr db 2,'cr'
cr mov t0,pc+4
mov pc,dolist
dw dolit,13,emit,dolit,10,emit,exit
; space ( -- )
; Send the blank character to the output device
dw _cr
_space db 5,'space'
space mov t0,pc+4
mov pc,dolist
dw dolit,32,emit,exit
; equal ( w w -- f )
; Return true if the top two items are equal
dw _space
_equal db 1,'='
equal mov t0,pc+4
mov pc,dolist
dw xor,qbranch,equal1
dw dolit,0,exit
equal1 dw dolit,-1,exit
; + ( w w -- sum )
; Add the top two items
dw _equal
_plus db 1,'+'
plus mov t0,pc+4
mov pc,dolist
dw uplus,drop,exit
; type ( b u -- )
; Output u characters from b
dw _plus
_type db 4,'type'
type mov t0,pc+4
mov pc,dolist
dw tor,branch,type2
type1 dw dup,cat,tochar,emit,onep
type2 dw donext,type1,drop,exit
; count ( b - b+1 u )
; Return byte count of a string and add 1 to byte address
dw _type
_count db 5,'count'
count mov t0,pc+4
mov pc,dolist
dw dup,onep,swap,cat,exit
; char ( -- c )
; Parse next word and return its first character.
dw _count
_char db 4,'char'
char mov t0,pc+4
mov pc,dolist
dw bl,parse,drop,cat,exit
; allot ( n -- )
; Allocate n bytes to the dictionary, if n is odd 1 will be added
dw _char
_allot db 5,'allot'
allot mov t0,pc+4
mov pc,dolist
dw dup,dolit,1,and ; Is n odd?
dw qbranch,allot1
dw onep ; Yes, increment to make a even number of bytes
allot1 dw dp,pstore ; Update dictionary pointer
dw exit