forked from makarcz/vm6502
-
Notifications
You must be signed in to change notification settings - Fork 0
/
eh_basic_kow.asm
8724 lines (7130 loc) · 245 KB
/
eh_basic_kow.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
; The code below was copied and adapted from Lee Davison’s
; code of EhBasic to be ran in Michal Kowalski's 6502 emulator.
; Original comments and credits follow:
;
; Enhanced BASIC to assemble under 6502 simulator, $ver 2.22
; $E7E1 $E7CF $E7C6 $E7D3 $E7D1 $E7D5 $E7CF $E81E $E825
; 2.00 new revision numbers start here
; 2.01 fixed LCASE$() and UCASE$()
; 2.02 new get value routine done
; 2.03 changed RND() to galoise method
; 2.04 fixed SPC()
; 2.05 new get value routine fixed
; 2.06 changed USR() code
; 2.07 fixed STR$()
; 2.08 changed INPUT and READ to remove need for $00 start to input buffer
; 2.09 fixed RND()
; 2.10 integrated missed changes from an earlier version
; 2.20 added ELSE to IF .. THEN and fixed IF .. GOTO <statement> to cause error
; 2.21 fixed IF .. THEN RETURN to not cause error
; 2.22 fixed RND() breaking the get byte routine
; zero page use ..
LAB_WARM = $00 ; BASIC warm start entry point
Wrmjpl = LAB_WARM+1; BASIC warm start vector jump low byte
Wrmjph = LAB_WARM+2; BASIC warm start vector jump high byte
Usrjmp = $0A ; USR function JMP address
Usrjpl = Usrjmp+1 ; USR function JMP vector low byte
Usrjph = Usrjmp+2 ; USR function JMP vector high byte
Nullct = $0D ; nulls output after each line
TPos = $0E ; BASIC terminal position byte
TWidth = $0F ; BASIC terminal width byte
Iclim = $10 ; input column limit
Itempl = $11 ; temporary integer low byte
Itemph = Itempl+1 ; temporary integer high byte
nums_1 = Itempl ; number to bin/hex string convert MSB
nums_2 = nums_1+1 ; number to bin/hex string convert
nums_3 = nums_1+2 ; number to bin/hex string convert LSB
Srchc = $5B ; search character
Temp3 = Srchc ; temp byte used in number routines
Scnquo = $5C ; scan-between-quotes flag
Asrch = Scnquo ; alt search character
XOAw_l = Srchc ; eXclusive OR, OR and AND word low byte
XOAw_h = Scnquo ; eXclusive OR, OR and AND word high byte
Ibptr = $5D ; input buffer pointer
Dimcnt = Ibptr ; # of dimensions
Tindx = Ibptr ; token index
Defdim = $5E ; default DIM flag
Dtypef = $5F ; data type flag, $FF=string, $00=numeric
Oquote = $60 ; open quote flag (b7) (Flag: DATA scan; LIST quote; memory)
Gclctd = $60 ; garbage collected flag
Sufnxf = $61 ; subscript/FNX flag, 1xxx xxx = FN(0xxx xxx)
Imode = $62 ; input mode flag, $00=INPUT, $80=READ
Cflag = $63 ; comparison evaluation flag
TabSiz = $64 ; TAB step size (was input flag)
next_s = $65 ; next descriptor stack address
; these two bytes form a word pointer to the item
; currently on top of the descriptor stack
last_sl = $66 ; last descriptor stack address low byte
last_sh = $67 ; last descriptor stack address high byte (always $00)
des_sk = $68 ; descriptor stack start address (temp strings)
; = $70 ; End of descriptor stack
ut1_pl = $71 ; utility pointer 1 low byte
ut1_ph = ut1_pl+1 ; utility pointer 1 high byte
ut2_pl = $73 ; utility pointer 2 low byte
ut2_ph = ut2_pl+1 ; utility pointer 2 high byte
Temp_2 = ut1_pl ; temp byte for block move
FACt_1 = $75 ; FAC temp mantissa1
FACt_2 = FACt_1+1 ; FAC temp mantissa2
FACt_3 = FACt_2+1 ; FAC temp mantissa3
dims_l = FACt_2 ; array dimension size low byte
dims_h = FACt_3 ; array dimension size high byte
TempB = $78 ; temp page 0 byte
Smeml = $79 ; start of mem low byte (Start-of-Basic)
Smemh = Smeml+1 ; start of mem high byte (Start-of-Basic)
Svarl = $7B ; start of vars low byte (Start-of-Variables)
Svarh = Svarl+1 ; start of vars high byte (Start-of-Variables)
Sarryl = $7D ; var mem end low byte (Start-of-Arrays)
Sarryh = Sarryl+1 ; var mem end high byte (Start-of-Arrays)
Earryl = $7F ; array mem end low byte (End-of-Arrays)
Earryh = Earryl+1 ; array mem end high byte (End-of-Arrays)
Sstorl = $81 ; string storage low byte (String storage (moving down))
Sstorh = Sstorl+1 ; string storage high byte (String storage (moving down))
Sutill = $83 ; string utility ptr low byte
Sutilh = Sutill+1 ; string utility ptr high byte
Ememl = $85 ; end of mem low byte (Limit-of-memory)
Ememh = Ememl+1 ; end of mem high byte (Limit-of-memory)
Clinel = $87 ; current line low byte (Basic line number)
Clineh = Clinel+1 ; current line high byte (Basic line number)
Blinel = $89 ; break line low byte (Previous Basic line number)
Blineh = Blinel+1 ; break line high byte (Previous Basic line number)
Cpntrl = $8B ; continue pointer low byte
Cpntrh = Cpntrl+1 ; continue pointer high byte
Dlinel = $8D ; current DATA line low byte
Dlineh = Dlinel+1 ; current DATA line high byte
Dptrl = $8F ; DATA pointer low byte
Dptrh = Dptrl+1 ; DATA pointer high byte
Rdptrl = $91 ; read pointer low byte
Rdptrh = Rdptrl+1 ; read pointer high byte
Varnm1 = $93 ; current var name 1st byte
Varnm2 = Varnm1+1 ; current var name 2nd byte
Cvaral = $95 ; current var address low byte
Cvarah = Cvaral+1 ; current var address high byte
Frnxtl = $97 ; var pointer for FOR/NEXT low byte
Frnxth = Frnxtl+1 ; var pointer for FOR/NEXT high byte
Tidx1 = Frnxtl ; temp line index
Lvarpl = Frnxtl ; let var pointer low byte
Lvarph = Frnxth ; let var pointer high byte
prstk = $99 ; precedence stacked flag
comp_f = $9B ; compare function flag, bits 0,1 and 2 used
; bit 2 set if >
; bit 1 set if =
; bit 0 set if <
func_l = $9C ; function pointer low byte
func_h = func_l+1 ; function pointer high byte
garb_l = func_l ; garbage collection working pointer low byte
garb_h = func_h ; garbage collection working pointer high byte
des_2l = $9E ; string descriptor_2 pointer low byte
des_2h = des_2l+1 ; string descriptor_2 pointer high byte
g_step = $A0 ; garbage collect step size
Fnxjmp = $A1 ; jump vector for functions
Fnxjpl = Fnxjmp+1 ; functions jump vector low byte
Fnxjph = Fnxjmp+2 ; functions jump vector high byte
g_indx = Fnxjpl ; garbage collect temp index
FAC2_r = $A3 ; FAC2 rounding byte
Adatal = $A4 ; array data pointer low byte
Adatah = Adatal+1 ; array data pointer high byte
Nbendl = Adatal ; new block end pointer low byte
Nbendh = Adatah ; new block end pointer high byte
Obendl = $A6 ; old block end pointer low byte
Obendh = Obendl+1 ; old block end pointer high byte
numexp = $A8 ; string to float number exponent count
expcnt = $A9 ; string to float exponent count
numbit = numexp ; bit count for array element calculations
numdpf = $AA ; string to float decimal point flag
expneg = $AB ; string to float eval exponent -ve flag
Astrtl = numdpf ; array start pointer low byte
Astrth = expneg ; array start pointer high byte
Histrl = numdpf ; highest string low byte
Histrh = expneg ; highest string high byte
Baslnl = numdpf ; BASIC search line pointer low byte
Baslnh = expneg ; BASIC search line pointer high byte
Fvar_l = numdpf ; find/found variable pointer low byte
Fvar_h = expneg ; find/found variable pointer high byte
Ostrtl = numdpf ; old block start pointer low byte
Ostrth = expneg ; old block start pointer high byte
Vrschl = numdpf ; variable search pointer low byte
Vrschh = expneg ; variable search pointer high byte
FAC1_e = $AC ; FAC1 exponent
FAC1_1 = FAC1_e+1 ; FAC1 mantissa1
FAC1_2 = FAC1_e+2 ; FAC1 mantissa2
FAC1_3 = FAC1_e+3 ; FAC1 mantissa3
FAC1_s = FAC1_e+4 ; FAC1 sign (b7)
str_ln = FAC1_e ; string length
str_pl = FAC1_1 ; string pointer low byte
str_ph = FAC1_2 ; string pointer high byte
des_pl = FAC1_2 ; string descriptor pointer low byte
des_ph = FAC1_3 ; string descriptor pointer high byte
mids_l = FAC1_3 ; MID$ string temp length byte
negnum = $B1 ; string to float eval -ve flag
numcon = $B1 ; series evaluation constant count
FAC1_o = $B2 ; FAC1 overflow byte
FAC2_e = $B3 ; FAC2 exponent
FAC2_1 = FAC2_e+1 ; FAC2 mantissa1
FAC2_2 = FAC2_e+2 ; FAC2 mantissa2
FAC2_3 = FAC2_e+3 ; FAC2 mantissa3
FAC2_s = FAC2_e+4 ; FAC2 sign (b7)
FAC_sc = $B8 ; FAC sign comparison, Acc#1 vs #2
FAC1_r = $B9 ; FAC1 rounding byte
ssptr_l = FAC_sc ; string start pointer low byte
ssptr_h = FAC1_r ; string start pointer high byte
sdescr = FAC_sc ; string descriptor pointer
csidx = $BA ; line crunch save index
Asptl = csidx ; array size/pointer low byte
Aspth = $BB ; array size/pointer high byte
Btmpl = Asptl ; BASIC pointer temp low byte
Btmph = Aspth ; BASIC pointer temp low byte
Cptrl = Asptl ; BASIC pointer temp low byte
Cptrh = Aspth ; BASIC pointer temp low byte
Sendl = Asptl ; BASIC pointer temp low byte
Sendh = Aspth ; BASIC pointer temp low byte
LAB_IGBY = $BC ; get next BASIC byte subroutine
LAB_GBYT = $C2 ; get current BASIC byte subroutine
Bpntrl = $C3 ; BASIC execute (get byte) pointer low byte
Bpntrh = Bpntrl+1 ; BASIC execute (get byte) pointer high byte
; = $D7 ; end of get BASIC char subroutine
Rbyte4 = $D8 ; extra PRNG byte
Rbyte1 = Rbyte4+1 ; most significant PRNG byte
Rbyte2 = Rbyte4+2 ; middle PRNG byte
Rbyte3 = Rbyte4+3 ; least significant PRNG byte
NmiBase = $DC ; NMI handler enabled/setup/triggered flags
; bit function
; === ========
; 7 interrupt enabled
; 6 interrupt setup
; 5 interrupt happened
; = $DD ; NMI handler addr low byte
; = $DE ; NMI handler addr high byte
IrqBase = $DF ; IRQ handler enabled/setup/triggered flags
; = $E0 ; IRQ handler addr low byte
; = $E1 ; IRQ handler addr high byte
; = $DE ; unused
; = $DF ; unused
; = $E0 ; unused
; = $E1 ; unused
; = $E2 ; unused
; = $E3 ; unused
; = $E4 ; unused
; = $E5 ; unused
; = $E6 ; unused
; = $E7 ; unused
; = $E8 ; unused
; = $E9 ; unused
; = $EA ; unused
; = $EB ; unused
; = $EC ; unused
; = $ED ; unused
; = $EE ; unused
Decss = $EF ; number to decimal string start
Decssp1 = Decss+1 ; number to decimal string start
; = $FF ; decimal string end
; token values needed for BASIC
; primary command tokens (can start a statement)
TK_END = $80 ; END token
TK_FOR = TK_END+1 ; FOR token
TK_NEXT = TK_FOR+1 ; NEXT token
TK_DATA = TK_NEXT+1 ; DATA token
TK_INPUT = TK_DATA+1 ; INPUT token
TK_DIM = TK_INPUT+1 ; DIM token
TK_READ = TK_DIM+1 ; READ token
TK_LET = TK_READ+1 ; LET token
TK_DEC = TK_LET+1 ; DEC token
TK_GOTO = TK_DEC+1 ; GOTO token
TK_RUN = TK_GOTO+1 ; RUN token
TK_IF = TK_RUN+1 ; IF token
TK_RESTORE = TK_IF+1 ; RESTORE token
TK_GOSUB = TK_RESTORE+1 ; GOSUB token
TK_RETIRQ = TK_GOSUB+1 ; RETIRQ token
TK_RETNMI = TK_RETIRQ+1 ; RETNMI token
TK_RETURN = TK_RETNMI+1 ; RETURN token
TK_REM = TK_RETURN+1 ; REM token
TK_STOP = TK_REM+1 ; STOP token
TK_ON = TK_STOP+1 ; ON token
TK_NULL = TK_ON+1 ; NULL token
TK_INC = TK_NULL+1 ; INC token
TK_WAIT = TK_INC+1 ; WAIT token
TK_LOAD = TK_WAIT+1 ; LOAD token
TK_SAVE = TK_LOAD+1 ; SAVE token
TK_DEF = TK_SAVE+1 ; DEF token
TK_POKE = TK_DEF+1 ; POKE token
TK_DOKE = TK_POKE+1 ; DOKE token
TK_CALL = TK_DOKE+1 ; CALL token
TK_DO = TK_CALL+1 ; DO token
TK_LOOP = TK_DO+1 ; LOOP token
TK_PRINT = TK_LOOP+1 ; PRINT token
TK_CONT = TK_PRINT+1 ; CONT token
TK_LIST = TK_CONT+1 ; LIST token
TK_CLEAR = TK_LIST+1 ; CLEAR token
TK_NEW = TK_CLEAR+1 ; NEW token
TK_WIDTH = TK_NEW+1 ; WIDTH token
TK_GET = TK_WIDTH+1 ; GET token
TK_SWAP = TK_GET+1 ; SWAP token
TK_BITSET = TK_SWAP+1 ; BITSET token
TK_BITCLR = TK_BITSET+1 ; BITCLR token
TK_IRQ = TK_BITCLR+1 ; IRQ token
TK_NMI = TK_IRQ+1 ; NMI token
; secondary command tokens, can't start a statement
TK_TAB = TK_NMI+1 ; TAB token
TK_ELSE = TK_TAB+1 ; ELSE token
TK_TO = TK_ELSE+1 ; TO token
TK_FN = TK_TO+1 ; FN token
TK_SPC = TK_FN+1 ; SPC token
TK_THEN = TK_SPC+1 ; THEN token
TK_NOT = TK_THEN+1 ; NOT token
TK_STEP = TK_NOT+1 ; STEP token
TK_UNTIL = TK_STEP+1 ; UNTIL token
TK_WHILE = TK_UNTIL+1 ; WHILE token
TK_OFF = TK_WHILE+1 ; OFF token
; opperator tokens
TK_PLUS = TK_OFF+1 ; + token
TK_MINUS = TK_PLUS+1 ; - token
TK_MUL = TK_MINUS+1 ; * token
TK_DIV = TK_MUL+1 ; / token
TK_POWER = TK_DIV+1 ; ^ token
TK_AND = TK_POWER+1 ; AND token
TK_EOR = TK_AND+1 ; EOR token
TK_OR = TK_EOR+1 ; OR token
TK_RSHIFT = TK_OR+1 ; RSHIFT token
TK_LSHIFT = TK_RSHIFT+1 ; LSHIFT token
TK_GT = TK_LSHIFT+1 ; > token
TK_EQUAL = TK_GT+1 ; = token
TK_LT = TK_EQUAL+1 ; < token
; functions tokens
TK_SGN = TK_LT+1 ; SGN token
TK_INT = TK_SGN+1 ; INT token
TK_ABS = TK_INT+1 ; ABS token
TK_USR = TK_ABS+1 ; USR token
TK_FRE = TK_USR+1 ; FRE token
TK_POS = TK_FRE+1 ; POS token
TK_SQR = TK_POS+1 ; SQR token
TK_RND = TK_SQR+1 ; RND token
TK_LOG = TK_RND+1 ; LOG token
TK_EXP = TK_LOG+1 ; EXP token
TK_COS = TK_EXP+1 ; COS token
TK_SIN = TK_COS+1 ; SIN token
TK_TAN = TK_SIN+1 ; TAN token
TK_ATN = TK_TAN+1 ; ATN token
TK_PEEK = TK_ATN+1 ; PEEK token
TK_DEEK = TK_PEEK+1 ; DEEK token
TK_SADD = TK_DEEK+1 ; SADD token
TK_LEN = TK_SADD+1 ; LEN token
TK_STRS = TK_LEN+1 ; STR$ token
TK_VAL = TK_STRS+1 ; VAL token
TK_ASC = TK_VAL+1 ; ASC token
TK_UCASES = TK_ASC+1 ; UCASE$ token
TK_LCASES = TK_UCASES+1 ; LCASE$ token
TK_CHRS = TK_LCASES+1 ; CHR$ token
TK_HEXS = TK_CHRS+1 ; HEX$ token
TK_BINS = TK_HEXS+1 ; BIN$ token
TK_BITTST = TK_BINS+1 ; BITTST token
TK_MAX = TK_BITTST+1 ; MAX token
TK_MIN = TK_MAX+1 ; MIN token
TK_PI = TK_MIN+1 ; PI token
TK_TWOPI = TK_PI+1 ; TWOPI token
TK_VPTR = TK_TWOPI+1 ; VARPTR token
TK_LEFTS = TK_VPTR+1 ; LEFT$ token
TK_RIGHTS = TK_LEFTS+1 ; RIGHT$ token
TK_MIDS = TK_RIGHTS+1 ; MID$ token
; offsets from a base of X or Y
PLUS_0 = $00 ; X or Y plus 0
PLUS_1 = $01 ; X or Y plus 1
PLUS_2 = $02 ; X or Y plus 2
PLUS_3 = $03 ; X or Y plus 3
LAB_STAK = $0100 ; stack bottom, no offset
LAB_SKFE = LAB_STAK+$FE
; flushed stack address
LAB_SKFF = LAB_STAK+$FF
; flushed stack address
ccflag = $0200 ; BASIC CTRL-C flag, 00 = enabled, 01 = dis
ccbyte = ccflag+1 ; BASIC CTRL-C byte
ccnull = ccbyte+1 ; BASIC CTRL-C byte timeout
VEC_CC = ccnull+1 ; ctrl c check vector
VEC_IN = VEC_CC+2 ; input vector
VEC_OUT = VEC_IN+2 ; output vector
VEC_LD = VEC_OUT+2 ; load vector
VEC_SV = VEC_LD+2 ; save vector
; Ibuffs can now be anywhere in RAM, ensure that the max length is < $80
IRQ_vec = VEC_SV+2
Ibuffs = IRQ_vec+$14 ; start of input buffer after IRQ/NMI code
Ibuffe = Ibuffs+$47 ; end of input buffer
.ORG $FFC0
; I/O routines for Michal Kowalski's 6502 emulator.
CHRIN
LDA $E004 ; Read from char IO address, non-blocking
BEQ ECHRIN ; if null, assume no character in buffer
CMP #'a' ; < 'a'?
BCC DCHRIN ; yes, done
CMP #'{' ; >= '{'?
BCS DCHRIN ; yes, done
AND #$5F ; no, convert to upper case
DCHRIN
SEC ; These is character waiting, set CARRY flag
RTS
ECHRIN
CLC ; no character in buffer, clear CARRY
RTS
CHROUT
STA $E001 ; write to char IO address
AND #$FF ; set flags
RTS
Ram_base = $0300 ; start of user RAM (set as needed, should be page aligned)
Ram_top = $C000 ; end of user RAM+1 (set as needed, should be page aligned)
; This start can be changed to suit your system
*= $C000
; BASIC cold start entry point
; new page 2 initialisation, copy block to ccflag on
LAB_COLD
CLD
LDY #PG2_TABE-PG2_TABS-1
; byte count-1
LAB_2D13
LDA PG2_TABS,Y ; get byte
STA ccflag,Y ; store in page 2
DEY ; decrement count
BPL LAB_2D13 ; loop if not done
LDX #$FF ; set byte
STX Ibuffs
STX Clineh ; set current line high byte (set immediate mode)
TXS ; reset stack pointer
LDA #$4C ; code for JMP
STA Fnxjmp ; save for jump vector for functions
; copy block from LAB_2CEE to $00BC - $00D3
LDX #StrTab-LAB_2CEE ; set byte count
LAB_2D4E
LDA LAB_2CEE-1,X ; get byte from table
STA LAB_IGBY-1,X ; save byte in page zero
DEX ; decrement count
BNE LAB_2D4E ; loop if not all done
; copy block from StrTab to $0000 - $0012
LAB_GMEM
LDX #EndTab-StrTab-1 ; set byte count-1
TabLoop
LDA StrTab,X ; get byte from table
STA PLUS_0,X ; save byte in page zero
DEX ; decrement count
BPL TabLoop ; loop if not all done
; set-up start values
LDA #$00 ; clear A
STA NmiBase ; clear NMI handler enabled flag
STA IrqBase ; clear IRQ handler enabled flag
STA FAC1_o ; clear FAC1 overflow byte
STA last_sh ; clear descriptor stack top item pointer high byte
LDA #$0E ; set default tab size
STA TabSiz ; save it
LDA #$03 ; set garbage collect step size for descriptor stack
STA g_step ; save it
LDX #des_sk ; descriptor stack start
STX next_s ; set descriptor stack pointer
JSR LAB_CRLF ; print CR/LF
LDA #<LAB_MSZM ; point to memory size message (low addr)
LDY #>LAB_MSZM ; point to memory size message (high addr)
JSR LAB_18C3 ; print null terminated string from memory
JSR LAB_INLN ; print "? " and get BASIC input
STX Bpntrl ; set BASIC execute pointer low byte
STY Bpntrh ; set BASIC execute pointer high byte
JSR LAB_GBYT ; get last byte back
BNE LAB_2DAA ; branch if not null (user typed something)
LDY #$00 ; else clear Y
; character was null so get memory size the hard way
; we get here with Y=0 and Itempl/h = Ram_base
LAB_2D93
INC Itempl ; increment temporary integer low byte
BNE LAB_2D99 ; branch if no overflow
INC Itemph ; increment temporary integer high byte
LDA Itemph ; get high byte
CMP #>Ram_top ; compare with top of RAM+1
BEQ LAB_2DB6 ; branch if match (end of user RAM)
LAB_2D99
LDA #$55 ; set test byte
STA (Itempl),Y ; save via temporary integer
CMP (Itempl),Y ; compare via temporary integer
BNE LAB_2DB6 ; branch if fail
ASL ; shift test byte left (now $AA)
STA (Itempl),Y ; save via temporary integer
CMP (Itempl),Y ; compare via temporary integer
BEQ LAB_2D93 ; if ok go do next byte
BNE LAB_2DB6 ; branch if fail
LAB_2DAA
JSR LAB_2887 ; get FAC1 from string
LDA FAC1_e ; get FAC1 exponent
CMP #$98 ; compare with exponent = 2^24
BCS LAB_GMEM ; if too large go try again
JSR LAB_F2FU ; save integer part of FAC1 in temporary integer
; (no range check)
LAB_2DB6
LDA Itempl ; get temporary integer low byte
LDY Itemph ; get temporary integer high byte
CPY #<Ram_base+1 ; compare with start of RAM+$100 high byte
BCC LAB_GMEM ; if too small go try again
; uncomment these lines if you want to check on the high limit of memory. Note if
; Ram_top is set too low then this will fail. default is ignore it and assume the
; users know what they're doing!
; CPY #>Ram_top ; compare with top of RAM high byte
; BCC MEM_OK ; branch if < RAM top
; BNE LAB_GMEM ; if too large go try again
; else was = so compare low bytes
; CMP #<Ram_top ; compare with top of RAM low byte
; BEQ MEM_OK ; branch if = RAM top
; BCS LAB_GMEM ; if too large go try again
;MEM_OK
STA Ememl ; set end of mem low byte
STY Ememh ; set end of mem high byte
STA Sstorl ; set bottom of string space low byte
STY Sstorh ; set bottom of string space high byte
LDY #<Ram_base ; set start addr low byte
LDX #>Ram_base ; set start addr high byte
STY Smeml ; save start of mem low byte
STX Smemh ; save start of mem high byte
; this line is only needed if Ram_base is not $xx00
; LDY #$00 ; clear Y
TYA ; clear A
STA (Smeml),Y ; clear first byte
INC Smeml ; increment start of mem low byte
; these two lines are only needed if Ram_base is $xxFF
; BNE LAB_2E05 ; branch if no rollover
; INC Smemh ; increment start of mem high byte
LAB_2E05
JSR LAB_CRLF ; print CR/LF
JSR LAB_1463 ; do "NEW" and "CLEAR"
LDA Ememl ; get end of mem low byte
SEC ; set carry for subtract
SBC Smeml ; subtract start of mem low byte
TAX ; copy to X
LDA Ememh ; get end of mem high byte
SBC Smemh ; subtract start of mem high byte
JSR LAB_295E ; print XA as unsigned integer (bytes free)
LDA #<LAB_SMSG ; point to sign-on message (low addr)
LDY #>LAB_SMSG ; point to sign-on message (high addr)
JSR LAB_18C3 ; print null terminated string from memory
LDA #<LAB_1274 ; warm start vector low byte
LDY #>LAB_1274 ; warm start vector high byte
STA Wrmjpl ; save warm start vector low byte
STY Wrmjph ; save warm start vector high byte
JMP (Wrmjpl) ; go do warm start
; open up space in memory
; move (Ostrtl)-(Obendl) to new block ending at (Nbendl)
; Nbendl,Nbendh - new block end address (A/Y)
; Obendl,Obendh - old block end address
; Ostrtl,Ostrth - old block start address
; returns with ..
; Nbendl,Nbendh - new block start address (high byte - $100)
; Obendl,Obendh - old block start address (high byte - $100)
; Ostrtl,Ostrth - old block start address (unchanged)
LAB_11CF
JSR LAB_121F ; check available memory, "Out of memory" error if no room
; addr to check is in AY (low/high)
STA Earryl ; save new array mem end low byte
STY Earryh ; save new array mem end high byte
; open up space in memory
; move (Ostrtl)-(Obendl) to new block ending at (Nbendl)
; don't set array end
LAB_11D6
SEC ; set carry for subtract
LDA Obendl ; get block end low byte
SBC Ostrtl ; subtract block start low byte
TAY ; copy MOD(block length/$100) byte to Y
LDA Obendh ; get block end high byte
SBC Ostrth ; subtract block start high byte
TAX ; copy block length high byte to X
INX ; +1 to allow for count=0 exit
TYA ; copy block length low byte to A
BEQ LAB_120A ; branch if length low byte=0
; block is (X-1)*256+Y bytes, do the Y bytes first
SEC ; set carry for add + 1, two's complement
EOR #$FF ; invert low byte for subtract
ADC Obendl ; add block end low byte
STA Obendl ; save corrected old block end low byte
BCS LAB_11F3 ; branch if no underflow
DEC Obendh ; else decrement block end high byte
SEC ; set carry for add + 1, two's complement
LAB_11F3
TYA ; get MOD(block length/$100) byte
EOR #$FF ; invert low byte for subtract
ADC Nbendl ; add destination end low byte
STA Nbendl ; save modified new block end low byte
BCS LAB_1203 ; branch if no underflow
DEC Nbendh ; else decrement block end high byte
BCC LAB_1203 ; branch always
LAB_11FF
LDA (Obendl),Y ; get byte from source
STA (Nbendl),Y ; copy byte to destination
LAB_1203
DEY ; decrement index
BNE LAB_11FF ; loop until Y=0
; now do Y=0 indexed byte
LDA (Obendl),Y ; get byte from source
STA (Nbendl),Y ; save byte to destination
LAB_120A
DEC Obendh ; decrement source pointer high byte
DEC Nbendh ; decrement destination pointer high byte
DEX ; decrement block count
BNE LAB_1203 ; loop until count = $0
RTS
; check room on stack for A bytes
; stack too deep? do OM error
LAB_1212
STA TempB ; save result in temp byte
TSX ; copy stack
CPX TempB ; compare new "limit" with stack
BCC LAB_OMER ; if stack < limit do "Out of memory" error then warm start
RTS
; check available memory, "Out of memory" error if no room
; addr to check is in AY (low/high)
LAB_121F
CPY Sstorh ; compare bottom of string mem high byte
BCC LAB_124B ; if less then exit (is ok)
BNE LAB_1229 ; skip next test if greater (tested <)
; high byte was =, now do low byte
CMP Sstorl ; compare with bottom of string mem low byte
BCC LAB_124B ; if less then exit (is ok)
; addr is > string storage ptr (oops!)
LAB_1229
PHA ; push addr low byte
LDX #$08 ; set index to save Adatal to expneg inclusive
TYA ; copy addr high byte (to push on stack)
; save misc numeric work area
LAB_122D
PHA ; push byte
LDA Adatal-1,X ; get byte from Adatal to expneg ( ,$00 not pushed)
DEX ; decrement index
BPL LAB_122D ; loop until all done
JSR LAB_GARB ; garbage collection routine
; restore misc numeric work area
LDX #$00 ; clear the index to restore bytes
LAB_1238
PLA ; pop byte
STA Adatal,X ; save byte to Adatal to expneg
INX ; increment index
CPX #$08 ; compare with end + 1
BMI LAB_1238 ; loop if more to do
PLA ; pop addr high byte
TAY ; copy back to Y
PLA ; pop addr low byte
CPY Sstorh ; compare bottom of string mem high byte
BCC LAB_124B ; if less then exit (is ok)
BNE LAB_OMER ; if greater do "Out of memory" error then warm start
; high byte was =, now do low byte
CMP Sstorl ; compare with bottom of string mem low byte
BCS LAB_OMER ; if >= do "Out of memory" error then warm start
; ok exit, carry clear
LAB_124B
RTS
; do "Out of memory" error then warm start
LAB_OMER
LDX #$0C ; error code $0C ("Out of memory" error)
; do error #X, then warm start
LAB_XERR
JSR LAB_CRLF ; print CR/LF
LDA LAB_BAER,X ; get error message pointer low byte
LDY LAB_BAER+1,X ; get error message pointer high byte
JSR LAB_18C3 ; print null terminated string from memory
JSR LAB_1491 ; flush stack and clear continue flag
LDA #<LAB_EMSG ; point to " Error" low addr
LDY #>LAB_EMSG ; point to " Error" high addr
LAB_1269
JSR LAB_18C3 ; print null terminated string from memory
LDY Clineh ; get current line high byte
INY ; increment it
BEQ LAB_1274 ; go do warm start (was immediate mode)
; else print line number
JSR LAB_2953 ; print " in line [LINE #]"
; BASIC warm start entry point
; wait for Basic command
LAB_1274
; clear ON IRQ/NMI bytes
LDA #$00 ; clear A
STA IrqBase ; clear enabled byte
STA NmiBase ; clear enabled byte
LDA #<LAB_RMSG ; point to "Ready" message low byte
LDY #>LAB_RMSG ; point to "Ready" message high byte
JSR LAB_18C3 ; go do print string
CLC
; wait for Basic command (no "Ready")
LAB_127D
JSR LAB_1357 ; call for BASIC input
LAB_1280
STX Bpntrl ; set BASIC execute pointer low byte
STY Bpntrh ; set BASIC execute pointer high byte
JSR LAB_GBYT ; scan memory
BEQ LAB_127D ; loop while null
; got to interpret input line now ..
LDX #$FF ; current line to null value
STX Clineh ; set current line high byte
BCC LAB_1295 ; branch if numeric character (handle new BASIC line)
; no line number .. immediate mode
JSR LAB_13A6 ; crunch keywords into Basic tokens
JMP LAB_15F6 ; go scan and interpret code
; handle new BASIC line
LAB_1295
JSR LAB_GFPN ; get fixed-point number into temp integer
JSR LAB_13A6 ; crunch keywords into Basic tokens
STY Ibptr ; save index pointer to end of crunched line
JSR LAB_SSLN ; search BASIC for temp integer line number
BCC LAB_12E6 ; branch if not found
; aroooogah! line # already exists! delete it
LDY #$01 ; set index to next line pointer high byte
LDA (Baslnl),Y ; get next line pointer high byte
STA ut1_ph ; save it
LDA Svarl ; get start of vars low byte
STA ut1_pl ; save it
LDA Baslnh ; get found line pointer high byte
STA ut2_ph ; save it
LDA Baslnl ; get found line pointer low byte
DEY ; decrement index
SBC (Baslnl),Y ; subtract next line pointer low byte
CLC ; clear carry for add
ADC Svarl ; add start of vars low byte
STA Svarl ; save new start of vars low byte
STA ut2_pl ; save destination pointer low byte
LDA Svarh ; get start of vars high byte
ADC #$FF ; -1 + carry
STA Svarh ; save start of vars high byte
SBC Baslnh ; subtract found line pointer high byte
TAX ; copy to block count
SEC ; set carry for subtract
LDA Baslnl ; get found line pointer low byte
SBC Svarl ; subtract start of vars low byte
TAY ; copy to bytes in first block count
BCS LAB_12D0 ; branch if overflow
INX ; increment block count (correct for =0 loop exit)
DEC ut2_ph ; decrement destination high byte
LAB_12D0
CLC ; clear carry for add
ADC ut1_pl ; add source pointer low byte
BCC LAB_12D8 ; branch if no overflow
DEC ut1_ph ; else decrement source pointer high byte
CLC ; clear carry
; close up memory to delete old line
LAB_12D8
LDA (ut1_pl),Y ; get byte from source
STA (ut2_pl),Y ; copy to destination
INY ; increment index
BNE LAB_12D8 ; while <> 0 do this block
INC ut1_ph ; increment source pointer high byte
INC ut2_ph ; increment destination pointer high byte
DEX ; decrement block count
BNE LAB_12D8 ; loop until all done
; got new line in buffer and no existing same #
LAB_12E6
LDA Ibuffs ; get byte from start of input buffer
BEQ LAB_1319 ; if null line just go flush stack/vars and exit
; got new line and it isn't empty line
LDA Ememl ; get end of mem low byte
LDY Ememh ; get end of mem high byte
STA Sstorl ; set bottom of string space low byte
STY Sstorh ; set bottom of string space high byte
LDA Svarl ; get start of vars low byte (end of BASIC)
STA Obendl ; save old block end low byte
LDY Svarh ; get start of vars high byte (end of BASIC)
STY Obendh ; save old block end high byte
ADC Ibptr ; add input buffer pointer (also buffer length)
BCC LAB_1301 ; branch if no overflow from add
INY ; else increment high byte
LAB_1301
STA Nbendl ; save new block end low byte (move to, low byte)
STY Nbendh ; save new block end high byte
JSR LAB_11CF ; open up space in memory
; old start pointer Ostrtl,Ostrth set by the find line call
LDA Earryl ; get array mem end low byte
LDY Earryh ; get array mem end high byte
STA Svarl ; save start of vars low byte
STY Svarh ; save start of vars high byte
LDY Ibptr ; get input buffer pointer (also buffer length)
DEY ; adjust for loop type
LAB_1311
LDA Ibuffs-4,Y ; get byte from crunched line
STA (Baslnl),Y ; save it to program memory
DEY ; decrement count
CPY #$03 ; compare with first byte-1
BNE LAB_1311 ; continue while count <> 3
LDA Itemph ; get line # high byte
STA (Baslnl),Y ; save it to program memory
DEY ; decrement count
LDA Itempl ; get line # low byte
STA (Baslnl),Y ; save it to program memory
DEY ; decrement count
LDA #$FF ; set byte to allow chain rebuild. if you didn't set this
; byte then a zero already here would stop the chain rebuild
; as it would think it was the [EOT] marker.
STA (Baslnl),Y ; save it to program memory
LAB_1319
JSR LAB_1477 ; reset execution to start, clear vars and flush stack
LDX Smeml ; get start of mem low byte
LDA Smemh ; get start of mem high byte
LDY #$01 ; index to high byte of next line pointer
LAB_1325
STX ut1_pl ; set line start pointer low byte
STA ut1_ph ; set line start pointer high byte
LDA (ut1_pl),Y ; get it
BEQ LAB_133E ; exit if end of program
; rebuild chaining of Basic lines
LDY #$04 ; point to first code byte of line
; there is always 1 byte + [EOL] as null entries are deleted
LAB_1330
INY ; next code byte
LDA (ut1_pl),Y ; get byte
BNE LAB_1330 ; loop if not [EOL]
SEC ; set carry for add + 1
TYA ; copy end index
ADC ut1_pl ; add to line start pointer low byte
TAX ; copy to X
LDY #$00 ; clear index, point to this line's next line pointer
STA (ut1_pl),Y ; set next line pointer low byte
TYA ; clear A
ADC ut1_ph ; add line start pointer high byte + carry
INY ; increment index to high byte
STA (ut1_pl),Y ; save next line pointer low byte
BCC LAB_1325 ; go do next line, branch always, carry clear
LAB_133E
JMP LAB_127D ; else we just wait for Basic command, no "Ready"
; print "? " and get BASIC input
LAB_INLN
JSR LAB_18E3 ; print "?" character
JSR LAB_18E0 ; print " "
BNE LAB_1357 ; call for BASIC input and return
; receive line from keyboard
; $08 as delete key (BACKSPACE on standard keyboard)
LAB_134B
JSR LAB_PRNA ; go print the character
DEX ; decrement the buffer counter (delete)
.byte $2C ; make LDX into BIT abs
; call for BASIC input (main entry point)
LAB_1357
LDX #$00 ; clear BASIC line buffer pointer
LAB_1359
JSR V_INPT ; call scan input device
BCC LAB_1359 ; loop if no byte
BEQ LAB_1359 ; loop until valid input (ignore NULLs)