forked from WillStevens/basic1K
-
Notifications
You must be signed in to change notification settings - Fork 0
/
basic8080.lst
2285 lines (2283 loc) · 111 KB
/
basic8080.lst
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
0000 ; Will Stevens
0000 ; 25th Feb 2023
0000 ; 1K 8080 BASIC
0000 ; GPL v3
0000 ;
0000 ; Terminal settings:
0000 ;
0000 ; Assumes that outputting a newline requires
0000 ; CR and LF, and that pressing return on the
0000 ; terminal sends CR alone. 1K BASIC echoes all
0000 ; characters it receives back to the terminal.
0000 ; I believe that these settings are compatible
0000 ; with using a Teletype Model 33 in full duplex
0000 ; mode. If using a VT100 terminal emulator, LNM
0000 ; must be reset so that pressing Return sends
0000 ; CR alone.
0000 ;
0000 ; Post-assembly checklist
0000 ;
0000 ; 1. LineNumSub is at address 223h
0000 ; 2. DivSub is atvaddress 1ffh
0000 ; 3. LO(AbsSub)>LO(NextSub)
0000 ; 4. In LineStartsWithInt, the jump to
0000 ; DeleteProgramLine is on the same
0000 ; page as DeleteProgramLine
0000 ; 5. Program does not exceed 1k
0000 ; 6. In ClassLookup, check that QuoteClass
0000 ; has LSBit different from othet class
0000 ; routines.
0000 ; 7. Ready is at address 00BB
0000 ; 8. Code before 'Ready:' does not overlap with
0000 ; 'Ready:', Can be seen from the HEX file.
0000 ; 9. AbsSub is at address 01BA
0000 ;
0000 ; Development log:
0000 ; 2023-03-03 About 450 bytes long
0000 ; 2023-03-08 About 750 bytes long
0000 ; 2023-03-11 About 840 bytes long
0000 ; 2023-03-12 About 930 bytes long.
0000 ; String tokens added.
0000 ; * and / yet to be added.
0000 ; Some scope for size optimization.
0000 ; 2023-03-12 About 940 bytes long
0000 ; * added
0000 ; some reduction in code size done
0000 ; 2023-03-16 About 970 bytes long
0000 ; unsigned / and integer output added
0000 ; about 30 bytes could be saved
0000 ; by using RST in place of call
0000 ; in some places
0000 ; 2023-03-17 About 940 bytes long
0000 ; 2023-03-17 About 970 bytes long
0000 ; INPUT added
0000 ; 2023-03-19 About 960 bytes long
0000 ; some bug fixes
0000 ; capable of playing lunar lander
0000 ; 2023-03-22 About 970 bytes long
0000 ; signed / added
0000 ; 2023-03-24 About 950 bytes long
0000 ; more code size reductions
0000 ; signed integer parsing supported
0000 ; 2023-03-24 About 940 bytes long
0000 ; more code size reductions
0000 ; 2023-03-27 About 950 bytes long
0000 ; simplified operator calling and
0000 ; simplified a few operators
0000 ; working on memory rotate function needed
0000 ; for line deletion and insertion
0000 ; 2023-04-09 About 970 bytes long.
0000 ; more code size reductions
0000 ; first draft of memory rotate function added
0000 ; 2023-04-12 About 995 bytes long
0000 ; line deletion function more complete
0000 ; looking for better way of decreasing
0000 ; PROG_PTR after line deletion
0000 ; 2023-04-16 About 986 bytes long
0000 ; line deletion apparently working
0000 ; some code size reductions
0000 ; 2023-04-16 About 963 bytes long
0000 ; further code size reductions
0000 ; 2023-04-17 About 930 bytes long
0000 ; looked for subroutine code sharing and
0000 ; LXI trick optimisations.
0000 ; Likely that some bugs will have been
0000 ; introduced when doing this
0000 ; 2023-04-18 About 900 bytes long
0000 ; greatly reduced CharClass size
0000 ; 2023-04-20 About 880 bytes long
0000 ; more code size reduction
0000 ; 2023-04-23 About 970 bytes long
0000 ; first draft of code for LIST added
0000 ; 2023-04-25 About 970 bytes long
0000 ; LIST command working
0000 ; 2023-04-27 About 950 bytes long
0000 ; More code size reduction
0000 ; 2023-04-28 About 950 bytes long
0000 ; used RST_CompareJump to save
0000 ; 2 bytes for every CPI JZ where
0000 ; the jump is to same page
0000 ; 2023-04-28 Free space: 78 bytes
0000 ; 2023-04-29 Free space: 84 bytes
0000 ; Initialise PROG_PTR at start
0000 ; Added NEW and END
0000 ; Added direct statement handling
0000 ; 2023-04-30 Free space: 86 bytes
0000 ; Fixed bugs with deleting first and
0000 ; last program lines
0000 ; 2023-05-02 Free space: about 60 bytes
0000 ; added code to allow out-of-order
0000 ; line number entry (first draft)
0000 ; 2023-05-02 Free space: about 54 bytes
0000 ; all basic functionality now implemented
0000 ; items to improve:
0000 ; division
0000 ; syntax checking
0000 ; 2023-05-04 Free space: about 79 bytes
0000 ; more code size reduction
0000 ; partly through handling EndProgram
0000 ; and LineNum better in threaded code
0000 ; likely to have introduced bugs
0000 ; 2023-05-07 Free space: about 69 bytes
0000 ; Improved expression evaluation by
0000 ; making it recursively callable
0000 ; and no longer requiring operator stack
0000 ; and about 20 bytes shorter.
0000 ; Used freed space for more syntax checks
0000 ; 2023-05-08 Free space: about 44 bytes
0000 ; First draft of support for array var @
0000 ; 2023-05-17 Free space: About 100 bytes
0000 ; First draft of new parser from
0000 ; experiments/parsing3.asm.
0000 ; Still need to modify string representation
0000 ; and change how INPUT parses integer,
0000 ; and check string token doesn't interfere
0000 ; after TokenList, and check order in
0000 ; TokenList.
0000 ; Seems likely that enough space has been
0000 ; freed to be able to implement FOR...NEXT
0000 ; 2023-05-19 Free space: About 101 bytes
0000 ; Issues listed above have been addressed now
0000 ; Testing needed to iron out problems
0000 ; 2023-05-26 Free space: About 84 bytes
0000 ; various bug fixes
0000 ; PRINT allows comma at end to suppress
0000 ; newline.
0000 ; Show > prompt symbol when ready.
0000 ; 2023-05-27 Free space: About 17 bytes
0000 ; Added FOR NEXT (no STEP yet)
0000 ; Need more space
0000 ; 2023-05-27 Free space: About 36 bytes
0000 ; Made a few small byte savings, and put
0000 ; token subs onto page 2 so that last one
0000 ; can flow onto page 3, freeing some space
0000 ; in page 2 to avoid having to jump out.
0000 ; One TODO to action
0000 ; 2023-05-28 Free space: About 42 bytes
0000 ; 2023-05-29 Free space: About 53 bytes
0000 ; Made some changes to * and / which I hope
0000 ; are improvements (efficienxy + code size)
0000 ; but testing needed to confirm this.
0000 ; 2023-06-02 Free space: About 12 bytes
0000 ; Added support for STEP to FOR loops
0000 ; Noted where Z flag is in known state
0000 ; in JMP instructions, because there is
0000 ; potential space saving by having
0000 ; 2-byte in-page JMP, JNZ or JZ,
0000 ; code shared with RST_CompareJump
0000 ; 2023-06-03 Free space: About 10 bytes
0000 ; STEP works in +ve direction only
0000 ; Fixing will require more space
0000 ; Would also like to add ABS, RND, USR
0000 ; But probably need about 60 bytes for that
0000 ; 2023-06-03 Free space: About 19 bytes
0000 ; Added in-page JZ to free up space
0000 ; Likely to have introduced errors
0000 ; 2023-06-04 Free space: About 25 bytes
0000 ; Shortened PrintSub
0000 ; 2023-06-04 Free space: about -21 bytes
0000 ; Implementing ABS and USR and skeleton
0000 ; of RND makes it 21 bytes over budget.
0000 ; So it seems reasonable to think that
0000 ; space can be made for these.
0000 ; 2023-06-05 Free space: about -15 bytes
0000 ; 2023-06-19 Free space: about 6 bytes
0000 ; Replaced memory rotate with triple reversal
0000 ; algorithm. Back below size limit, but need
0000 ; to rearrange things to realize this.
0000 ; 2023-06-22 Free space: about 10 bytes
0000 ; All free space is in the RST area, which I
0000 ; am reluctant to use because I expect that
0000 ; when I try to target actual hardware I will
0000 ; need to extend PutChar, and maybe have
0000 ; some initialization code for e.g. UART.
0000 ; So discounting this I am 2 bytes over
0000 ; budget, and haven't implemented RND
0000 ; function yet
0000 ; 2023-06-23 Free space : 18 bytes
0000 ; Saved space with more sharing between
0000 ; LET and INPUT
0000 ; Ready to do a lot of testing
0000 ; 2023-06-28 Free space : 20 bytes
0000 ; 2023-06-28 Free space : 19 bytes
0000 ; Fixed enough bugs that lunar lander works
0000 ; Function calls don't work yet
0000 ; 2023-07-01 Free space : 24 bytes
0000 ; ABS function works
0000 ; RND function currently does nothing
0000 ; need to make implementation of RND
0000 ; that fits in 17 bytes
0000 ; 2023-07-04 Free space : 20 bytes
0000 ; Implemented simple lookup-based RND
0000 ; replaced newline RST with LDAX B, INX B
0000 ; saved a few bytes in LIST
0000 ; 2023-07-05 Free space : 11 bytes
0000 ; Implemented XORSHIFT RND function
0000 ; 2023-07-08 Free space: 10 bytes
0000 ; 2023-07-12 Free space: 15 bytes
0000 ; Fixed forgotten issue where STEP in FOR
0000 ; loop didn't work if negative
0000 ; 2023-07-13 Free space: 13 bytes
0000 ; Extended variable range up to 32
0000 ; So that user has 31 variables and array
0000 ; var 30 can be used to work out
0000 ; remaining memory
0000 ; var 31 is RNG seed
0000 ; 2023-07-15 Noticed bug where -32768 isn't
0000 ; displayed
0000 ; 2023-07-15 When playing REVERSE, saw corrupted
0000 ; array, which implies that bug where stack
0000 ; continually growing
0000 ; 2023-07-16 Above two issues fixed. Former
0000 ; required change to PrintInteger. Latter
0000 ; was due to a GOTO from within FOR loop,
0000 ; in REVERSE and not necessarily a problem
0000 ; with this interpreter
0000 ; 2024-01-01 Fixed bug where parse error wasn't
0000 ; displayed as ? during LIST
0000 ; 2024-01-28 Fixed bug where @ was displayed as M
0000 ; during LIST
0000 ; 2024-02-07 Working on corrections to comparison
0000 ; operators. Not in working state. Made I/O
0000 ; compatible with Dick Whipple's Front Panel
0000 ; 8080 simulator
0000 ; 2024-02-08 May have fixed comparison operator
0000 ; problem. Need to save 2 bytes to be able to
0000 ; test it
0000 ; 2024-02-08 Reclaimed some space so that 3FEh is
0000 ; the last byte uses. Free space 5 bytes.
0000 ; 2024-02-18 Worked towards reclaiming 4 bytes in
0000 ; the tokenizer. Good chance of being
0000 ; incorrect, will require debugging.
0000 ; 2024-02-20 Debugged above changes and
0000 ; they seem okau. Free space 9 bytes
0000 ; 2024-02-22 Rearranged RSTs and added CPI to end
0000 ; of RST_LDAXB_INXB_CPI to save memory.
0000 ; Free space still 9 bytes but now
0000 ; 7 of those are at the end of 1K, so are
0000 ; easy to make use of.
0000 ; Need to check movement and alignment
0000 ; of subroutines.
0000 ; It would be useful to have a checklist of
0000 ; all dependencies that need to be checked
0000 ; when there are large movements in memory.
0000 ;
0000 ; Next things to do:
0000 ; - unterminated string check
0000 ; - forbidding excess chars in tokens
0000 ; - correct operator precedence for * /
0000 ; - error on divide by zero
0000 ; not sure whether all 4 can be done in
0000 ; only 7 bytes
0000 ; 2024-02-25 Added unterminated string check and
0000 ; didvide by zero error. 2 bytes over budget.
0000 ; 2024-02-25 Realised that removing reatriction
0000 ; that RUN, LIST and NEW only allowed in
0000 ; direct mode would will probably save a
0000 ; sufficient number of bytes to finish all
0000 ; outstanding work
0000 ; 2024-02-28 Sveral changes related to issues
0000 ; listed above, Divide by zero and
0000 ; unterminated string now generate error
0000 ; messages. 2 bytes free which should be
0000 ; enough to make * and / equal precedence,
0000 ; but will test everything else first. Issue
0000 ; about tokens with excess chars not being
0000 ; detected as errors will remain unfixed in
0000 ; first release.
0000 ; 2024-03-01 Found bug where recent changes
0000 ; caused DeleteProgramLine to move page.
0000 ; In the course of fixing it, may have saved
0000 ; 5 bytes. Need to test that fix is correct.
0000 ; 2024-03-01 Fixed a bug introduced on 28 Feb
0000 ; where ExecuteDirect was called without
0000 ; setting B. Wrote 'game of life' example
0000 ; program. When printing newline, added CR
0000 ; before after discovering that some
0000 ; terminals need this. Need to free up
0000 ; 1 byte to fix operator precedence issue
0000 ; 2024-03-02 This version correcly runs
0000 ; lander.bas, reverse.bas, life.bas,
0000 ; operatortests.bas, operatortests2.bas,
0000 ; looptests.bas
0000 ; 2024-03-02 Freed up 1 byte by removing
0000 ; redundant STC
0000 ; 2024-03-03 Added code to make * same
0000 ; precedence as / (needs testing).
0000 ; Changed RNG from XORSHIFT to LCG.
0000 ; This saved 3 bytes.
0000 ; Need to experiment with LCG constant
0000 ; for best RNG performance.
0000 ; Behaviour of RNG function changed so
0000 ; that max valid input parameter is 256,
0000 ; because low order bits of RNG have
0000 ; low period. Only high ordet bits of
0000 ; RNG are used for return value.
0000 ; 2024-03-04 Altered EndProgram address.
0000 ; Temporarily tried making RAM start at 1000h
0000 ; to check that this doesn't cause problems
0000 ; 2024-03-06 Changed IO to support Stefan Tramms
0000 ; 8080 emulator.
0000 ; 2024-03-11 Moved start of RAM back to 0400h
0000 ; 2024-03-12 Changed initialisation so that
0000 ; spurious char is no longer output on
0000 ; reset or NEW.
0000 ; 2024-03-15 Realised during testing that
0000 ; ExpEvaluate can sometimes try to return
0000 ; when stack isn't a return address.
0000 ; Realised that ExpEvaluate must either
0000 ; succeed or fail, with no backtrack.
0000 ; This required substantial changes to
0000 ; PrintSub, especially a change to how it
0000 ; knows if it has just had a comma. This
0000 ; is now done based on parity of H.
0000 ; To be retested.
0000 ;
0000 ; Had an idea that operators and statements
0000 ; could reside on different pages, creating
0000 ; more space for both, and perhaps removing
0000 ; the need for some of the Jumps out of
0000 ; page 2 to statement implementation.
0000 ;2024-03-23
0000 ; Changed INPUT so that it doesn't display
0000 ; a prompt. It was confusing to have the
0000 ; > prompt as is used in direct mode. Instead
0000 ; programs that need a prompt before input
0000 ; can use the multistatement line
0000 ; PRINT "?", INPUT A
0000 ; 2024-03-25 Found a fix for problem where
0000 ; -32768/2 has wrong sign. It costs 3 bytes
0000 ; so need to find 2 byte saving before Ready
0000 ; and 1 byte saving after Ready
0000 ; 2024-03-26 In the process of making major
0000 ; rearrangements to save several bytes and
0000 ; fix the bug mentioned above.
0000 ; 2024-03-27 Major rearrangements have been done.
0000 ; Net reault is to save 5 bytes, but need
0000 ; to carefully check whether any same-page
0000 ; assumptions are violated
0000 ; 2024-03-28 Found and fixed several bugs related
0000 ; to above changes. Execution of ? token
0000 ; seems to take too long, implying a
0000 ; remaining bug. 9 bytes free now, 5 of
0000 ; which are contiguous at the end of the
0000 ; program.
0000 ; 2024-03-29 Two bugs to fix : prompt appears
0000 ; twice after entering first line.
0000 ; detection of syntax errors is slow
0000 ; 2024-04-01 Fixed several bugs introduced above.
0000 ; Need to run all tests again.
0000 ; 2024-04-03 Changed newline behaviour so that
0000 ; VT100 terminals require LNM reset rather
0000 ; than set.
0000 ; 2024-04-04 Reclaimed 2 bytes in
0000 ; DigitClassNotEnd. Used those two bytes to
0000 ; add a colon token. It can be used as a
0000 ; statement separator in multi-statement
0000 ; lines.
0000 ; 2024-04-10 Modified PrintSub so that it no
0000 ; longer uses parity bit and should work
0000 ; on Z80
0000 ; For development purposes assume we have
0000 ; 1K ROM from 0000h-03FFh containing BASIC
0000 ; 1K RAM from 0400h-0800h
0000 RAM_BASE: EQU 0400h
0000 RAM_TOP: EQU 0800h
0000 ; Token values
0000 ; 0-31 are variables (0 = @)
0000 ; IntegerToken must be one more than last var
0000 INTEGERTOKEN: EQU 32
0000 QUESTIONMARKTOKEN: EQU 33
0000 STRINGTOKEN: EQU 34
0000 ; Callable tokens are low byte of subroutine to call
0000 ; Errors are displayed as Ex where x is an error
0000 ; code which is tbe address on the stack when
0000 ; Error subroutine is called.
0000 ; Input buffer is just 8 bytes long
0000 ; used by input statement to get an integer.
0000 ; If there is a buffer overflow because user
0000 ; enters too much, the behaviour is system
0000 ; dependent - e.g. if writes above RAM
0000 ; space do nothing then its not a problem.
0000 ; If memory space repeats and lower 1K
0000 ; is ROM then also not much of a problem.
0000 INPUT_BUFFER: EQU RAM_TOP-8
0000 STACK_INIT: EQU RAM_TOP-8
0000 ; this must be on a 256 byte boundary
0000 VAR_SPACE: EQU RAM_BASE
0000 ; 30 words, first of which is not
0000 ; accessible to user, so can be
0000 ; used for PROG_PTR
0000 PROG_PTR: EQU RAM_BASE
0000 ; 2 words accessible to user as variables
0000 ; 30 and 31 (^ and _)
0000 PROG_PARSE_PTR: EQU RAM_BASE+60
0000 RNG_SEED: EQU RAM_BASE+62
0000 PROG_BASE: EQU RAM_BASE+64
0000 .ORG 00h
0000 ; I would like this to be:
0000 ; LXI H,PROG_BASE
0000 ; SHLD PROG_PTR
0000 ; JMP Ready
0000 ;
0000 ; But this doesn't fit in 8 bytes.
0000 ; Instead we find a place in the program
0000 ; that already has "LXI B,PROG_BASE" and
0000 ; follow it with "dw Ready" and set SP to that
0000 ; address, then POP H from
0000 ; the stack and store it in PROG_PTR, then
0000 ; RET will jump to Ready.
0000 ; We must ensure that Ready is at an address
0000 ; that corresponds to a harmless instruction.
0000 ; 00B8 to 00BF is a good range to aim for
0000 ; because B8-BF are CMP instructions which
0000 ; affect flags and nothing else.
0000 31 85 02 LXI SP,ExecuteProgram+1
0003 E1 POP H
0004 22 00 04 SHLD PROG_PTR
0007 C9 RET
0008 .ORG 08h
0008 ; PutChar is called frequently
0008 ; PutChar must return with Z set
0008 PUTCHAR:
0008 ; port 1 is for char I/O
0008 D3 01 OUT 1
000A ;
000A ; Having the wait loop after the character
000A ; is output will slow down I/O when running
000A ; on hardware, but I can't think of a way
000A ; of fitting this into 8 bytes otherwise.
000A ;
000A PUTCHARWAITLOOP: ; address 000ah
000A ; TODO change these few instructions
000A ; if targetting hardware
000A AF XRA A
000B C9 RET
000C ;IN 1
000C ;ANI 040h
000C ;RZ
000C ;db 0c3h ; opcode for JMP
000C ; the following two bytes are
000C ; 0ah and 00h, so this jumps to
000C ; PutCharWaitLoop
000C ;
0010 .ORG 10h
0010 0A LDAX B ; opcode 0ah
0011 00 NOP ; opcode 00h
0012 03 INX B
0013 E3 XTHL
0014 BE CMP M
0015 23 INX H
0016 E3 XTHL
0017 C9 RET
0018 ;
0018 .ORG 18h
0018 ; byte after RST is compared with A
0018 ; if equal then jump to address on same page.
0018 ;
0018 ; only use where performance is not
0018 ; important (parsing, printing)
0018 E3 XTHL
0019 BE CMP M
001A 23 INX H
001B C3 21 00 JMP CompareJump_Entry
001E ;
001E ; 2 bytes free
0020 .ORG 20h
0020 E3 XTHL
0021 COMPAREJUMP_ENTRY:
0021 C2 25 00 JNZ JZPage_Skip
0024 6E MOV L,M
0025 JZPAGE_SKIP:
0025 23 INX H
0026 EXPAPPLYOP: ; shared code
0026 E3 XTHL
0027 C9 RET
0028 .ORG 28h
0028 COMPAREHLDE:
0028 ; compare HL and DE, return
0028 ; Z equal, NZ if not equal
0028 ; C equal, NC if not equal
0028 ; A will be zero if Z is set
0028 7D MOV A,L
0029 AB XRA E
002A C0 RNZ
002B 7C MOV A,H
002C AA XRA D
002D C0 RNZ
002E 37 STC
002F C9 RET
0030 .ORG 30h
0030 NEGATEDE:
0030 ;flags are not affected
0030 ;
0030 ; decrement and invert so that we end
0030 ; up with D in A - sometimes handy
0030 1B DCX D
0031 7B MOV A,E
0032 2F CMA
0033 5F MOV E,A
0034 7A MOV A,D
0035 2F CMA
0036 57 MOV D,A
0037 C9 RET
0038 .ORG 38h
0038 ; BC points to program
0038 ; DE contains value
0038 ; Stack is used for both operands and
0038 ; operators
0038 EXPEVALUATE:
0038 ; ExpEvaluate must not be called
0038 ; from page 1, The hi byte of the return address
0038 ; is a marker to distinguish it from an operator.
0038 ; Only operators have hi byte = 1
0038 EXPEVALUATENUM:
0038 ; Expecting ( var integer or - sign
0038 ; or function call
**MACRO UNROLL - RST_LDAXB_INXB_CPI
0038 D7 RST 2
0039 BB DB LeftBraceToken&0ffh
**MACRO UNROLL - RST_JZPAGE
003A E7 RST 4
003B 9F DB (ExpLeftBrace&0ffh)-1
**MACRO UNROLL - RST_COMPAREJUMP
003C DF RST 3
003D E6 73 DB SubSub&0xff,(ExpNegate&0ffh)-1
003F ;
003F ; last function
003F FE BF CPI (RndSub+1)&0ffh
0041 D4 B1 00 CNC Error
0044 ; first function
0044 FE B8 CPI AbsSub&0ffh
0046 D2 A1 00 JNC FunctionCall ; between RndSub and AbsSub
0049 ;
0049 FE 20 CPI IntegerToken
004B DA 55 00 JC ExpVar
004E ;
004E ; Integer token is one more than last var
004E ; token so if carry is set then it is a var
004E ;
004E C4 B1 00 CNZ Error
0051 ; Fall through to ExpInteger
0051 EXPINTEGER:
0051 60 MOV H,B
0052 69 MOV L,C
0053 03 INX B
0054 03 INX B
0055 ;
0055 ; fall through with carry clear
0055 EXPVAR:
0055 ; carry set if jumped to here
0055 ;
0055 DC EE 02 CC GetVarLocation
0058 EXPVARGETVALUE:
0058 5E MOV E,M
0059 23 INX H
005A 56 MOV D,M
005B EXPEVALUATEOP:
005B ;Expecting operator or right bracket or
005B ;end of expression
005B ;
005B ;Are there operators on the stack?
005B E1 POP H
005C ;
005C ; H will be 0, 2 or 3 if no operators on
005C ; stack (i.e. high byte of return address)
005C ;
005C 7C MOV A,H
005D 3D DCR A
005E C2 6D 00 JNZ SkipExpApplyOp
0061 ;
0061 ; if L is equal to MulSub then apply it.
0061 ; this gives * same precedence as /
0061 ;MOV A,L
0061 ;RST_CompareJump
0061 ;DB (MulSub&0ffh),(ExpApplyOp&0ffh)-1
0061 ;
0061 7D MOV A,L
0062 FE E7 CPI NegateSub&0ffh
0064 D2 26 00 JNC ExpApplyOp
0067 ;
0067 0A LDAX B
0068 ;
0068 ; No longer needed since case below
0068 ; includes this
0068 ;CPI Operators&0ffh
0068 ; Is it the end of the expression?
0068 ;JC ExpApplyOp
0068 ;
0068 ; Does operator on stack have GTE precedence?
0068 ; (or end of expression, when A < operators)
0068 3D DCR A
0069 BD CMP L
006A ;
006A DA 26 00 JC ExpApplyOp ; apply the operator
006D ; that was on the stack
006D ;
006D SKIPEXPAPPLYOP:
006D E5 PUSH H ; put operator that was on stack
006E ; back onto stack
006E ;
006E 0A LDAX B
006F ;
006F FE CD CPI Operators&0ffh
0071 ; Is it the end of the expression?
0071 D8 RC
0072 ;
0072 03 INX B
0073 ;
0073 ; fall through
0073 21 DB 21h ; LXI H eats 2 bytes
0074 EXPNEGATE:
0074 3C INR A
0075 11 00 00 LXI D,0
0078 ;
0078 21 5B 00 LXI H,ExpEvaluateOp ; address to return to
007B ; after operator is called
007B E5 PUSH H
007C ;
007C ; Put 0 onto stack and operator onto
007C ; operator stack
007C ;
007C D5 PUSH D ; operand
007D 6F MOV L,A
007E 24 INR H ; Assumes H was 0 and needs to be 1
007F E5 PUSH H
0080 ;
0080 C3 38 00 JMP ExpEvaluateNum
0083 FORSUBIMPL:
0083 ; Stack contains return address:
0083 ; ExecuteProgramLoop - EPL
0083 ; Keep it there even though it isn't used by
0083 ; ForSub, it will be used by NextSub
0083 ;
0083 E5 PUSH H ; stack contains <SP> VL+1, EPL
0084 ;
0084 ; check that we have a 'TO' token
**MACRO UNROLL - RST_LDAXB_INXB_CPI
0084 D7 RST 2
0085 A9 DB ToToken&0ffh
0086 C4 B1 00 CNZ Error
0089 ;
**MACRO UNROLL - RST_EXPEVALUATE
0089 FF RST 7
**MACRO UNROLL - RST_NEGATEDE
008A F7 RST 6
008B ;
008B D5 PUSH D ; stack contains <SP> -T,VL+1, EPL
008C ; T is target
008C ;
008C ; step is going to be 1 unless we encounter
008C ; a STEP token
008C 11 01 00 LXI D,1
008F 0A LDAX B
0090 ;
0090 ; check for optional STEP token
**MACRO UNROLL - RST_COMPAREJUMP
0090 DF RST 3
0091 AA 93 DB StepToken&0ffh,(ForWithStep&0ffh)-1
0093 21 DB 21h ; LXI H opcode eats the next 2 bytes
0094 FORWITHSTEP:
0094 ; we have step token
0094 03 INX B
**MACRO UNROLL - RST_EXPEVALUATE
0095 FF RST 7
0096 ;
0096 E1 POP H
0097 E1 POP H ; H contains VL+1
0098 ;
0098 ; B contains the start address of the
0098 ; loop (LS)
0098 ;
0098 C5 PUSH B ; stack contains -T <SP> LS,EPL
0099 3B DCX SP
009A 3B DCX SP ; stack contains <SP> -T,LS,EPL
009B D5 PUSH D ; stack contains <SP>,S,-T,LS,EPL
009C E5 PUSH H ; stack contains <SP>,VL+1,S,-T,LS,EPL
009D ;
009D C3 89 02 JMP ExecuteProgramLoop
00A0 EXPLEFTBRACE:
00A0 0B DCX B
00A1 FUNCTIONCALL:
00A1 ; push return address
00A1 21 5B 00 LXI H,ExpEvaluateOp
00A4 E5 PUSH H
00A5 ; A contains the address to call on page 1
00A5 ; push function address
00A5 6F MOV L,A
00A6 24 INR H ; Assumes H was 0 and is now 1
00A7 E5 PUSH H
00A8 ;
00A8 ; fall through
00A8 ; This must be before Error so that it
00A8 ; can fall through
00A8 EXPBRACKETEDB:
**MACRO UNROLL - RST_LDAXB_INXB_CPI
00A8 D7 RST 2
00A9 BB DB LeftBraceToken&0ffh
00AA C4 B1 00 CNZ Error
**MACRO UNROLL - RST_EXPEVALUATE
00AD FF RST 7
00AE ;
**MACRO UNROLL - RST_LDAXB_INXB_CPI
00AE D7 RST 2
00AF AB DB RightBraceToken&0ffh
00B0 C8 RZ
00B1 ;
00B1 ; fall through
00B1 ;Display error code and go back to line entry
00B1 ERROR:
00B1 CD 41 02 CALL CRLF
00B4 3E 45 MVI A,'E'
**MACRO UNROLL - RST_PUTCHAR
00B6 CF RST 1
00B7 D1 POP D
00B8 CD 64 03 CALL PrintInteger
00BB ;
00BB ; fall through
00BB ;
00BB ; we need ready to be at an address
00BB ; corresponding to harmless opcodes when
00BB ; executed in ExecuteProgram
00BB .ORG 00bbh
00BB READY:
00BB ; Set stack pointer
00BB ; Do this every time to guard against
00BB ; GOSUB with no RETURN errors
00BB ;
00BB 31 F8 07 LXI SP,STACK_INIT
00BE ;
00BE CD 41 02 CALL CRLF
00C1 ;
00C1 ; Use this if no CRLF is needed
00C1 ; and sure that stack can't be wrong
00C1 READYNONEWLINE:
00C1 ;
00C1 2A 00 04 LHLD PROG_PTR
00C4 E5 PUSH H ; push it because we need it after
00C5 ; GetLine
00C5 CD 32 01 CALL GetLine
00C8 ;
00C8 36 80 MVI M,EndProgram&0ffh
00CA ;
00CA 22 3C 04 SHLD PROG_PARSE_PTR
00CD E1 POP H
00CE ;
00CE E5 PUSH H
00CF C1 POP B
00D0 ;
00D0 7E MOV A,M
00D1 ; Regardless of which branch taken
00D1 ; we need this marker here.
00D1 ; This overwrites the token to execute,
00D1 ; but we've already got that in A
00D1 36 80 MVI M,EndProgram&0ffh
00D3 ;
00D3 FE 20 CPI IntegerToken
00D5 C2 8A 02 JNZ ExecuteDirect
00D8 ;
00D8 LINESTARTSWITHINT:
00D8 ; Get the line number into DE
00D8 23 INX H
00D9 5E MOV E,M
00DA 23 INX H
00DB 56 MOV D,M
00DC 23 INX H
00DD ;
00DD ; Is it an integer all by itself?
00DD ; If so then delete the line
00DD ;
00DD ; call GetLineNum to find either the line, or
00DD ; pointer to next location in program after it
00DD ;
00DD 66 MOV H,M ; preserve M (GetLineNum doesn't touch H)
00DE CD FD 02 CALL GetLineNum
00E1 7C MOV A,H
00E2 2A 00 04 LHLD PROG_PTR
00E5 F5 PUSH PSW
00E6 ;
**MACRO UNROLL - RST_COMPAREJUMP
00E6 DF RST 3
00E7 80 DB EndProgram&0ffh
00E8 F8 DB (DeleteProgramLine&0ffh)-1
00E9 ;
00E9 F1 POP PSW
00EA ; if GetLineNum returns a match then this is
00EA ; an error, user must delete line first
00EA CC B1 00 CZ Error
00ED ;
00ED ; do a memory rotate with
00ED ; first = GetLine/ATNLN address
00ED ; middle = PROG_PTR
00ED ; last = PROG_PARSE_PTR
00ED ;
00ED 36 23 MVI M,LineNumSub&0ffh ; undo what we did earlier
00EF EB XCHG
00F0 2A 3C 04 LHLD PROG_PARSE_PTR
00F3 ;
00F3 E5 PUSH H ; last
00F4 C5 PUSH B ; first
00F5 ;
00F5 D5 PUSH D ; middle
00F6 ;
00F6 ; carry is clear here from the call to
00F6 ; GetLineNum
00F6 ;
00F6 C3 09 01 JMP Entry
00F9 DELETEPROGRAMLINE:
00F9 ; 25 bytes
00F9 F1 POP PSW
00FA ;
00FA C2 C1 00 JNZ ReadyNoNewLine ; line not found, do nothing
00FD E5 PUSH H
00FE C5 PUSH B ; first
00FF E5 PUSH H ; last
0100 ;
0100 09 DAD B ; HL=PROG_PTR+first
0101 ;
0101 03 INX B
0102 CD 18 03 CALL ATNLN_Int ; Z is set when this is called
0105 ;
0105 ;set HL to what we want PROG_PTR to be
0105 50 MOV D,B
0106 59 MOV E,C
**MACRO UNROLL - RST_NEGATEDE
0107 F7 RST 6
0108 ;
0108 19 DAD D ; HL=PROG_PTR+first-middle
0109 ;
0109 ; because DAD D above always causes HL
0109 ; to decrease, it must set carry
0109 ; so STC below is not needed
0109 ;STC ; skip first reverse in memory rotate
0109 ; because we don't care about the
0109 ; line being deleted
0109 ;
0109 ENTRY:
0109 ; carry is clear if coming from insert
0109 ;
0109 C5 PUSH B ; middle (or first)
010A 22 00 04 SHLD PROG_PTR
010D ;
010D MEMORYROTATE:
010D ; 27 bytes
010D ; stack must contain (from top down)
010D ; first, middle, first, last
010D ; DE = middle
010D ; HL = Last
010D D4 1A 01 CNC Reverse
0110 CD 17 01 CALL ReverseDH
0113 01 C1 00 LXI B,ReadyNoNewLine
0116 C5 PUSH B
0117 REVERSEDH:
0117 E1 POP H
0118 D1 POP D
0119 E3 XTHL
011A REVERSE:
011A ; HL = last (i.e 1 after the last byte to swap)
011A ; DE = first
011A REVERSELOOP:
**MACRO UNROLL - RST_COMPAREHLDE
011A EF RST 5
011B C8 RZ
011C 2B DCX H
**MACRO UNROLL - RST_COMPAREHLDE
011D EF RST 5
011E C8 RZ
011F ;
011F 46 MOV B,M
0120 1A LDAX D
0121 77 MOV M,A
0122 78 MOV A,B
0123 12 STAX D
0124 13 INX D
0125 ;
0125 C3 1A 01 JMP ReverseLoop
0128 ; GetLine sits entirely in page 1
0128 ; good - it uses RST_CompareJump in two
0128 ; places, so be careful if moving it
0128 ; Also it assumes ClassLookup on same page
0128 ; as NoCharClass
0128 NLTESTTRUE:
0128 ; error if we are in the middle
0128 ; of a string
0128 7D MOV A,L
0129 FE 7A CPI QuoteClassExpEnd&0ffh
012B CC B1 00 CZ Error
012E ;
012E E1 POP H
012F ;
012F C3 41 02 JMP CRLF
0132 GETLINE:
0132 ; HL points where we want the line to be
0132 ; parsed to.
0132 ; On return HL points to byte after what we've
0132 ; got.
0132 ;
0132 3E 3E MVI A,'>'
**MACRO UNROLL - RST_PUTCHAR
0134 CF RST 1
0135 GETLINENOPROMPT:
0135 E5 PUSH H
0136 ; is there a better way of setting B to a
0136 ; non-newline? Any other regs known not
0136 ; to have this value?
0136 0E 00 MVI C,0
0138 FRESHSTART:
0138 21 65 01 LXI H,NoCharClass
013B ;
013B NLTEST:
013B ; check for newline
013B 79 MOV A,C
**MACRO UNROLL - RST_COMPAREJUMP
013C DF RST 3
013D 0D 27 DB 13,(NLTestTrue&0ffh)-1
013F ;
013F NEXTCHARLOOP:
013F ; This code is compatable with Stefan Tramm's
013F ; 8080 emulator
013F DB 00 IN 0
0141 A7 ANA A
**MACRO UNROLL - RST_JZPAGE
0142 E7 RST 4
0143 3E DB (NextCharLoop&0ffh)-1
0144 DB 01 IN 1
0146 4F MOV C,A
0147 D3 01 OUT 1 ; echo
0149 ;
0149 ; Do we have the same class as before?
0149 E5 PUSH H
014A 21 C7 02 LXI H,ClassLookup-1
014D ; Test for quote first
014D ; This doesn't save spave, but takes 3 bytes
014D ; away from class lookup and puts them here
014D ; so can be used to change odd/even of
014D ; ...Class subroutines
014D ;RST_CompareJump
014D ;DB 34,(LC_QuoteTestTrue-1)&0ffh
014D LOOKUPCLASSLOOP:
014D 2C INR L
014E BE CMP M
014F 2C INR L
0150 DA 4D 01 JC LookupClassLoop
0153 LC_QUOTETESTTRUE:
0153 46 MOV B,M
0154 E1 POP H
0155 ;
0155 ; are L and B equal?
0155 7D MOV A,L
0156 A8 XRA B
0157 ; Z if they are equal, NZ if not
0157 E9 PCHL ; Jump based on previous CharClass pointer
0158 DIGITCLASS:
**MACRO UNROLL - RST_JZPAGE
0158 E7 RST 4
0159 69 DB (DigitClassNotEnd&0ffh)-1
015A DIGITCLASSEND:
015A ; Write token into program
015A ; need to preserve DE, don't care about HL
015A E3 XTHL
015B 36 20 MVI M,IntegerToken
015D 23 INX H
015E 73 MOV M,E
015F 23 INX H
0160 36 DB 36h ; opcode for MVI M eats next byte
0161 WRITE_SHARED_ATSP:
0161 D1 POP D
0162 WRITE_SHARED:
0162 72 MOV M,D
0163 WRITE_SHARED_WRITTEN:
0163 23 INX H
0164 E3 XTHL
0165 NOCHARCLASS:
0165 68 MOV L,B
0166 AF XRA A ; set Z
0167 57 MOV D,A ; reset state information
0168 5F MOV E,A
0169 E9 PCHL
016A DIGITCLASSNOTEND:
016A ;
016A D5 PUSH D