-
Notifications
You must be signed in to change notification settings - Fork 2
/
scelbal-in-eprom.asm
4222 lines (4092 loc) · 298 KB
/
scelbal-in-eprom.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
PAGE 0 ; suppress page headings in AS listing file
;------------------------------------------------------------------------
;
; Scelbi BASIC Interpreter (SCELBAL) modified for ROM.
;
; serial I/O at 2400 bps, N-8-1
;
; SCELBAL interpreter downloaded from http://www.willegal.net/scelbi/scelbal.html modified
; to assemble with the AS Macro Assembler (http://john.ccac.rwth-aachen.de:8000/as/) by Hans-Åke.
;
; modified to run from a 2764 EPROM for my 8008 home-brew single board computer by Jim Loos.
;
; SCELBAL Commands:
;
; Immediate-mode only (referred to as "executive" mode in the documentation.):
; SCR, LIST, RUN, LOAD, SAVE
;
; Immediate or program mode:
; PRINT, INPUT, LET, IF...THEN, IF...GOTO, GOTO, GOSUB...RETURN, FOR...TO...STEP...NEXT, REM, END, DIM
;
; Functions:
; INT, SGN, ABS, SQR, RND, CHR, TAB, UDF
;
; the user defined function (UDF) is used to control the orange LEDs connected to port 09.
; X=UDF(255) turns all the orange LEDs on
; X=UDF(0) turns all the orange LEDs off
;
; If using Tera Term's 'Send File' function to download BASIC source code,
; set the transmit delay for 2ms/char, 500ms/line
;------------------------------------------------------------------------
include "bitfuncs.inc"
cpu 8008new ; use "new" 8008 mnemonics
radix 10 ; use base 10 for numbers
org 2000H ; beginning of EPROM
xra a ; clear A
out 09 ; turn off orange LEDs
mvi a,1
out 08 ; set serial output high (mark)
mvi h,hi(titletxt) ; print the title
mvi l,lo(titletxt)
call puts
; copy OLDPG1 constants and variables from EPROM at 3D00H to RAM at 0000H
mvi l,00H ; initialize L to start of page
mv_oldpg1: mvi h,hi(page1) ; source: OLDPG1 constants in EPROM at page 3DH
mov a,m ; retrieve the byte from EPROM
mvi h,hi(OLDPG1) ; destination: RAM at page 00H
mov m,a ; store the byte in RAM
inr l ; next address
jnz mv_oldpg1 ; go back if page not complete
; copy OLDPG26 constants and variables from EPROM at 3E00H to RAM at 0100H
mvi l,00H ; initialize L to start of page
mv_oldpg26: mvi h,hi(page26) ; source: OLDPG26 constants in EPROM at page 3EH
mov a,m ; retrieve the byte from EPROM
mvi h,hi(OLDPG26) ; destination: RAM at page 01H
mov m,a ; store the byte in RAM
inr l ; next address
jnz mv_oldpg26 ; go back if page not complete
; copy OLDPG27 constants and variables from EPROM at 3F00H to RAM at 0200H
mvi l,00H ; initialize L to start of page
mv_oldpg27: mvi h,hi(page27) ; source: OLDPG27 constants in EPROM at page 3FH
mov a,m ; retrieve the byte from EPROM
mvi h,hi(OLDPG27) ; destination: RAM at page 02H
mov m,a ; store the byte in RAM
inr l ; next address
jnz mv_oldpg27 ; go back if page not complete
jmp exec ; run the SCELBAL interpreter
;-----------------------------------------------------------------------------------------
; I/O routines for SCELBAL.
; According to the SCELBAL Manual: "Only CPU register B and the accumulator may be used by the I/O routines.
; All the other CPU registers must contain their original values when I/O operations have been completed."
; "... the I/O routines themselves may only utilize a maximum of two levels of nesting!"
; Although the manual doesn't mention it, SCELBAL also assumes that the CPRINT subroutine preserves
; the character in the accumulator.
;-----------------------------------------------------------------------------------------
INPORT equ 0 ; serial input port address
OUTPORT equ 08H ; serial output port address
;-----------------------------------------------------------------------------------------
; character input subroutine for SCELBAL
; wait for a character from the serial port.
; receives 1 start bit, 8 data bits and 1 stop bit at 2400 bps.
; echo each bit as it is received. return the received character in A.
; uses A and B.
;-----------------------------------------------------------------------------------------
CINP: in INPORT ; get input from serial port
rar ; rotate the received serial bit right into carry
jc CINP ; jump back if start bit was not detected (input was high)
; start bit detected. 1/2 bit time then send start bit
mvi b,0 ; initialize B
mvi b,0 ; timing adjustment
xra a ; clear the accumulator
out OUTPORT ; send the start bit
call delay1 ; timing adjustment
mvi b,0 ; timing adjustment
; receive and echo bits 0 through 7
call getbitecho ; receive/echo bit 0
call getbitecho ; receive/echo bit 1
call getbitecho ; receive/echo bit 2
call getbitecho ; receive/echo bit 3
call getbitecho ; receive/echo bit 4
call getbitecho ; receive/echo bit 5
call getbitecho ; receive/echo bit 6
call getbitecho ; receive/echo bit 7
; wait 1 bit time, then send the stop bit
mov a,b ; save the character from B to A
mvi b,0FEH ; timing adjustment
call delay ; timing adjustment
mov b,a ; restore the chararacter from A to B
mvi a,1 ; '1' for stop bit
out OUTPORT ; send the stop bit
; wait 1 bit time
mov a,b ; restore the character from B to A
mvi b,0FEH ; timing adjustment
call delay ; timing adjustment
; cpi 'a' ; is the input character below 'a'?
; jc $+10 ; skip the next three instructions if the character is already upper case
; cpi '{' ; is the input character '{' or above?
; jnc $+5 ; if so, skip the next instruction
; sui 20H ; else, convert to the character to upper case
ori 80H ; SCELBAL needs to have the most significant bit set
ret ; return to caller
getbitecho: mov a,b ; save the received bits from B to A
mvi b,0FFH ; timing adjustment
call delay ; timing adjustment
mov b,a ; restore the received bits from A to B
ana a ; timing adjustment
in INPORT ; get input from the serial port
out OUTPORT ; echo the received bit
rar ; rotate the received bit right into carry
mov a,b ; restore the previously received bits from B to A
rar ; rotate the newly received bit in carry right into the MSB of A
mov b,a ; save the received bits in B
ret
;------------------------------------------------------------------------
; character output subroutine for SCELBAL
; sends the character in A out from the serial port.
; transmits 1 start bit, 8 data bits and 1 stop at 2400 bps.
; uses A and B.
; returns with the original character in A
;------------------------------------------------------------------------
CPRINT: ani 7FH ; mask off the most significant bit of the character
mov b,a ; save the character from A to B
xra a ; clear A for the start bit
out OUTPORT ; send the start bit
mov a,b ; restore the character from B to A
mov a,b ; timing adjustment
mvi b,0FDH ; timing adjustment
mvi b,0FDH ; timing adjustment
call delay ; timing adjustment
; send bits 0 through 7
call putbit ; transmit bit 0
call putbit ; transmit bit 1
call putbit ; transmit bit 2
call putbit ; transmit bit 3
call putbit ; transmit bit 4
call putbit ; transmit bit 5
call putbit ; transmit bit 6
call putbit ; transmit bit 7
; send the stop bit
mov b,a ; save the character from A to B
mvi a,1 ; '1' for the stop bit
out OUTPORT ; send the stop bit
mov a,b ; restore the original character from B to A
ori 80H ; restore the most significant bit of the character
mvi b,0FCH ; timing adjustment
call delay ; timing adjustment
ret ; return to caller
putbit: out OUTPORT ; output the least significant bit of the character in A
mvi b,0FDH ; timing adjustment
mvi b,0FDH ; timing adjustment
call delay ; timing adjustment
rrc ; shift the character in A right
ret
;------------------------------------------------------------------------
; delay in microseconds = (((255-value in B)*16)+19) * 4 microseconds
;------------------------------------------------------------------------
delay: inr b
jnz delay
delay1: ret
;------------------------------------------------------------------------
; serially print the null terminated string whose address is in HL.
; uses A and B and HL
;------------------------------------------------------------------------
puts: mov a,m
ana a
rz ; return if end of string
call CPRINT
inr l ; next character
jnz puts
inr h
jmp puts
cpu 8008 ; use "old" mneumonics for SCELBAL
RADIX 8 ; use octal for numbers
;--------------------------------------------------------------------------------
;;; This is the Scelbi Basic Program from 1974 known as
;;; SCELBAL by Mark G. Arnold (MGA) and Nat Wadsworth
;;;
;;; Copyright 1975 Scelbi Computer Consulting, Inc.
;;; All rights reserved
;;;
;;; MGA gives permission to use SCELBAL for
;;; educational, historical, non-commercial purposes.
;;; Versions of this have been circulating on the web since
;;; about 2000; this version is authorized by MGA (Mar 2012)
;;; with the understanding no warranty is expressed or implied.
;;; As stated in the original, "no responsibility is assumed for
;;; for inaccuracies or for the success or failure of
;;; various applications to which the information herein
;;; may be applied."
;;;
;;; SCELBAL is the only open-source, floating-point
;;; high-level language ever implemented on Intel's first
;;; general-purpose microprocessor, the 8008. It was
;;; published in book form:
;;;
;;; SCELBAL: A Higher-Level Language for 8008/8080 Systems
;;;
;;; (Tiny BASIC only used 16-bit integers; the MCM\70
;;; was a closed system; calculators implemented with 8008
;;; were floating-point, but not high-level.)
;;;
;;; This version is modified to assemble with the
;;; as8 assembler (using the -octal option)
;;; for the Intel 8008 by Thomas E. Jones.
;;; This current form is made up non-relocatable so that
;;; locations of all code and data is identical to the
;;; original SCELBAL documents and patches. It should be
;;; reasonable after debugging code to convert this to a
;;; relocatable and ROMable code with variables in RAM.
;;; This code originates from a version made by
;;;
;;; Steve Loboyko in 2001.
;;;
;;; This version has all 3 patches for SCELBAL (the two
;;; pasted in the original manual, and a third which was
;;; written in SCELBAL UPDATE publication, as well as
;;; a couple changes to constants which didn't actually
;;; require a patch, just changes to bytes of data or
;;; arguments to an instruction--one of these (Tucker) was
;;; incorrect and restored to original by MGA March 2012).
;;;
;;; This comment must be incorporated with any version of SCELBAL
;;; downloaded, distributed, posted or disemenated.
;;;
;;; Here are labels originally attempting to make the code
;;; relocatable. These 4 pages contain variable data
;;; which needs to be relocated from ROM to RAM.
;;; I can't vouch for ALL references to these pages in
;;; the code being switched to these labels, but they
;;; seem to be.
OLDPG1 EQU 0000H ; originally at 0100H, now relocated to 0000H - jsl
OLDPG26 EQU 0100H ; originally at 1600H, now relocated to 0100H - jsl
OLDPG27 EQU 0200H ; originally at 1700H, now relocated to 0200H - jsl
OLDPG57 EQU 0300H ; originally at 2F00H, now relocated to 0300H - jsl
BGNPGRAM EQU 04H ; originally user program buffer began at 1B00H, now begins at 0400H - jsl
ENDPGRAM EQU 20H ; originally user program buffer ended at 2CFFH, now ends at 1FFFH - jsl
ORG 2100H
SYNTAX: CAL CLESYM ;Clear the SYMBOL BUFFER area
LLI 340 ;Set L to start of LINE NUMBER BUFFER
LHI OLDPG26/400 ;** Set H to page of LINE NUMBER BUFFER
LMI 000 ;Initialize line number buff by placing zero as (cc)
LLI 201 ;Change pointer to syntax counter/pointer storage loc.
LMI 001 ;Set pointer to first character (after cc) in line buffer
SYNTX1: LLI 201 ;Set pointer to syntax cntr/pntr storage location
CAL GETCHR ;Fetch the character pointed to by contents of syntax
JTZ SYNTX2 ;Cntr/pntr from the line input buffer. If character was
CPI 260 ;A space, ignore. Else, test to see if character was ASCII
JTS SYNTX3 ;Code for a decimal digit. If not a decimal digit, consider
CPI 272 ;Line number to have been processed by jumping
JFS SYNTX3 ;Over the remainder of this SYNTX1 section.
LLI 340 ;If have decimal digit, set pointer to start of LINE
CAL CONCT1 ;NUMBER BUFFER and append incoming digit there.
SYNTX2: LLI 201 ;Reset L to syntax cntr/pntr storage location. Call sub-
CAL LOOP ;Routine to advance pntr and test for end of inr)ut buffer
JFZ SYNTX1 ;If not end of input buffer, go back for next digit
LLI 203 ;If end of buffer, only had a line number in the line.
LMI 000 ;Set pntr to TOKEN storage location. Set TOKEN = 000.
RET ;Return to caller.
SYNTX3: LLI 201 ;Reset pointer to syntax cntr/pntr and fetch
LBM ;Position of next character after the line number
LLI 202 ;Change pntr to SCAN pntr storage location
LMB ;Store address when SCAN takes up after line number
SYNTX4: LLI 202 ;Set pntr to SCAN pntr stomge location
CAL GETCHR ;Fetch the character pointed to by contents of the SCAN
JTZ SYNTX6 ;Pointer storage location. If character was ASCII code
CPI 275 ;For space, ignore. Else, compare character with "=" sign
JTZ SYNTX7 ;If is an equal sign, go set TOKEN for IMPLIED LET.
CPI 250 ;Else, compare character with left parenthesis " ( "
JTZ SYNTX8 ;If left parenthesis, go set TOKEN for implied array LET
CAL CONCTS ;Otherwise, concatenate the character onto the string
; MGA 4/2012 begin "fast SYNTX5" patch:
; the following patch doubles the overall speed of execution.
; It is similar to the approach taken on 8080 SCELBAL II in 1978
; it adhears to the rules for patches in issue 1 of SCELBAL update
;SYNTX6: these four lines moved up w/o label
LLI 202 ;Set L to SCAN pointer storage location
; LHI OLDPG26/400 ;** Set H to page of SCAN pointer stomge location
;MGA 4/2012 except LHI needed at original place, not here
CAL LOOP ;Call routine to advance pntr & test for end of In buffer
JFZ SYNTX4 ;Go back and add another character to SYMBOL BUFF
SYNTX6: ; MGA 4/2012 label here
LLI 203 ;Being constructed in the SYMBOL BUFFER. Now set
LMI 001 ;Up TOKEN storage location to an initial value of 001.
LHI OLDPG27/400 ;** Set H to point to start of KEYWORD TABLE.
LLI 000 ;Set L to point to start of KEYWORD TABLE.
SYNTX5: LDI OLDPG26/400 ;** Set D to page of SYMBOL BUFFER
LEI 120 ;Set E to start of SYMBOL BUFFER
CAL STRCP ;Compare char string presently in SYMBOL BUFFER
RTZ ;With entry in KEYWORD TABLE. Exit if match.
CAL SWITCH ;TOKEN will be set to keyword found. Else, switch
SYNTXL: INL ;Pointers to get table address back and advance pntr to
LAM ;KEYWORD TABLE. Now look for start of next entry
NDI 300 ;In KEYWORD TABLE by looking for (cc) byte which
JFZ SYNTXL ;Will NOT have a one in the two most sig. bits. Advance
CAL SWITCH ;Pntr til next entry found. Then switch pointers apin so
LLI 203 ;Table pointer is in D&E. Put addr of TOKEN in L.
LHI OLDPG26/400 ;** And page of TOKEN in H. Fetch the value currently
LBM ;In TOKEN and advance it to account for going on to
INB ;The next entry in the KEYWORD TABLE.
LMB ;Restore the updated TOKEN value back to storage.
CAL SWITCH ;Restore the keyword table pointer back to H&L.
LAB ;Put TOKEN count in ACC.
CPI 015 ;See if have tested all entries in the keyword table.
JFZ SYNTX5 ;If not, continue checking the keyword table.
;MGA 4/2012 3 of 4 lines removed below (keep LHI)
LHI OLDPG26/400 ;** Set H to page of SCAN pointer stomge location
; MGA 4/2012 end of "fast SYNTX5" patch:
LLI 203 ;And search table for KEYWORD again. Unless reach
LMI 377 ;End of line input buffer. In which case set TOKEN=377
RET ;As an error indicator and exit to calling routine.
SYNTX7: LLI 203 ;Set pointer to TOKEN storage register. Set TOKEN
LMI 015 ;Equal to 015 when "=" sign found for IMPLIED LET.
RET ;Exit to calling routine.
SYNTX8: LLI 203 ;Set pointer to TOKEN storage register. Set TOKEN
LMI 016 ;Equal to 016 when "(" found for IMPLIED array LET.
RET ;Exit to calling routine.
;The following are subroutines used by SYNTAX and other routines in SCELBAL.
BIGERR: LAI 302 ;Load ASCII code for letters B and G to indicate BIG
LCI 307 ;ERROR (for when buffer, stack,etc., overflows).
ERROR: CAL ECHO ;Call user provided display routine to print ASCII code
LAC ;In accumulator. Transfer ASCII code from C to ACC
CAL ECHO ;And repeat to display error codes.
JMP FINERR ;Go cpmplete error message (AT LINE) as required.
GETCHR: LAM ;Get pointer from memory location pointed to by H&L
CPI 120 ;See if within range of line input buffer.
JFS BIGERR ;If not then have an overflow condition = error.
LLA ;Else can use it as addr of character to fetch from the
LHI OLDPG26/400 ;** LINE INPUT BUFFER by setting up H too.
LAM ;Fetch the character from the line input buffer.
CPI 240 ;See if it is ASCII code for space.
RET ;Return to caller with flags set according to comparison.
CLESYM: LLI 120 ;Set L to start of SYMBOL BUFFER.
LHI OLDPG26/400 ;** Set H to page of SYMBOL BUFFER.
LMI 000 ;Place a zero byte at start of SYMBOL BUFFER.
RET ;To effectively clear the buffer. Then exit to caller.
;Subroutine to concatenate (append) a character to the
;SYMBOL BUFFER. Character must be alphanumeric.
CONCTA: CPI 301 ;See if character code less than that for letter A.
JTS CONCTN ;If so, go see if it is numeric.
CPI 333 ;See if character code greater than that for letter Z.
JTS CONCTS ;If not, have valid alphabetical character.
CONCTN: CPI 260 ;Else, see if character in valid numeric range.
JTS CONCTE ;If not, have an error condition.
CPI 272 ;Continue to check for valid number.
JFS CONCTE ;If not, have an error condition.
CONCTS: LLI 120 ;If character alphanumeric, can concatenate. Set pointer
LHI OLDPG26/400 ;** To starting address of SYMBOL BUFFER.
CONCT1: LCM ;Fetch old character count in SYMBOL BUFFER.
INC ;Increment the value to account for adding new
LMC ;Character to the buffer. Restore updated (cc).
LBA ;Save character to be appended in register B.
CAL INDEXC ;Add (cc) to address in H & L to get new end of buffer
LMB ;Address and append the new character to buffer
LAI 000 ;Clear the accumulator
RET ;Exit to caller
CONCTE: JMP SYNERR ;If character to be appended not alphanumeric, ERROR!
;Subroutine to compare character strings pointed to by register pairs D & E and H & L.
STRCP: LAM ;Fetch (cc) of first string.
CAL SWITCH ;Switch pointers and fetch length of second string (cc)
LBM ;Into register B. Compare the lengths of the two strings.
CPB ;If they are not the same
RFZ ;Return to caller with flags set to non-zero condition
CAL SWITCH ;Else, exchange the pointers back to first string.
STRCPL: CAL ADV ;Advance the pointer to string number 1 and fetch a
LAM ;Character from that string into the accumulator.
CAL SWITCH ;Now switch the pointers to string number 2.
CAL ADV ;Advance the pointer in line number 2.
STRCPE: CPM ;Compare char in stxing 1 (ACC) to string 2 (memory)
RFZ ;If not equal, return to cauer with flags set to non-zero
CAL SWITCH ;Else, exchange pointers to restore pntr to string 1
DCB ;Decrement the string length counter in register B
JFZ STRCPL ;If not finiahed, continue testing entire string
RET ;If complete match, return with flag in zero condition
STRCPC: LAM ;Fetch character pointed to by pointer to string 1
CAL SWITCH ;Exchange pointer to examine string 2
JMP STRCPE ;Continue the string comparison loop
;Subroutine to advance the two byte value in CPU registers H and L.
ADV: INL ;Advance value in register L.
RFZ ;If new value not zero, return to caller.
INH ;Else must increment value in H
RET ;Before retuming to caller
;Subroutine to advance a buffer pointer and test to see if the end of the buffer has been reached.
LOOP: LBM ;Fetch memory location pointed to by H & L into B.
INB ;Increment the value.
LMB ;Restore it back to memory.
LLI 000 ;Change pointer to start of INPUT LINE BUFFER
LAM ;Fetch buffer length (cc) value into the accumulator
DCB ;Make value in B original value
CPB ;See if buffer length same as that in B
RET ;Return with flags yielding results of the comparison
;The following subroutine is used to input characters from the system's
;input device (such as a keyboard) into the LINE INPUT BUFFER. Routine has limited
;editing capability included. (Rubout = delete previous character(s) entered.)
STRIN: LCI 000 ;Initialize register C to zero.
STRIN1: CAL CINPUT ;Call user provided device input subroutine to fetch one
CPI 377 ;Character from the input device. Is it ASCII code for
JFZ NOTDEL ;Rubout? Skip to next section if not rubout.
LAI 334 ;Else, load ASCII code for backslash into ACC.
CAL ECHO ;Call user display driver to present backslash as a delete
DCC ;Indicator. Now decrement the input character counter.
JTS STRIN ;If at beginning of line do NOT decrement H and L.
CAL DEC ;Else, decrement H & L line pointer to erase previous
JMP STRIN1 ;Entry, then go back for a new input.
NOTDEL: CPI 203 ;See if character inputted was'CONTROL C'
JTZ CTRLC ;If so, stop inputting and go back to the EXECutive
CPI 215 ;If not, see if character was carriage-return
JTZ STRINF ;If so, have end of line of input
CPI 212 ;If not, see if character was line-feed
JTZ STRIN1 ;If so, ignore the input, get another character
CAL ADV ;If none of the above, advance contents of H & L
INC ;Increment the character counter
LMA ;Store the new character in the line input buffer
LAC ;Put new character count in the accumulator
CPI 120 ;Make sure maximum buffer size not exceeded
JFS BIGERR ;If buffer size exceeded, go display BG error message
JMP STRIN1 ;Else can go back to look for next input
STRINF: LBC ;Transfer character count from C to B
CAL SUBHL ;Subtract B from H & L to get starting address of
LMC ;The string and place the character count (cc) there
CAL CRLF ;Provide a line ending CR & LF combination on the
RET ;Display device. Then exit to caller.
;Subroutine to subtract contents of CPU register B from
;the two byte value in CPU registers H & L.
SUBHL: LAL ;Load contents of register L into the accumulator
SUB ;Subtract the contents of register B
LLA ;Restore the new value back to L
RFC ;If no carry, then no underflow. Exit to caller.
DCH ;Else must also decrement contents of H.
RET ;Before retuming to caller.
;Subroutine to display a character string on the system's display device.
TEXTC: LCM ;Fetch (cc) from the first location in the buffer (H & L
LAM ;Pointing there upon entry) into register B and ACC.
NDA ;Test the character count value.
RTZ ;No display if (cc) is zero.
TEXTCL: CAL ADV ;Advance pointer to next location in buffer
LAM ;Fetch a character from the buffer into ACC
CAL ECHO ;Call the user's display driver subroutine
DCC ;Decrement the (cc)
JFZ TEXTCL ;If character counter not zero, continue display
RET ;Exit to caller when (cc) is zero.
;Subroutine to provide carriage-return and line-feed combination to system's display device.
;Routine also initializes a column counter to zero. Column counter is used by selected output
;routines to count the number of characters that have been displayed on a line.
CRLF: LAI 215 ;Load ASCII code for carriage-return into ACC
CAL ECHO ;Call user provided display driver subroutine
LAI 212 ;Load ASCII code for line-feed into ACC
CAL ECHO ;Call user provided display driver subroutine
LLI 043 ;Set L to point to COLUMN COUNTER storage location
LHI OLDPG1/400 ;** Set H to page of COLUMN COUNTER
LMI 001 ;Initialize COLUMN COUNTER to a value of one
LHD ;Restore H from D (saved by ECHO subroutine)
LLE ;Restore L from E (saved by ECHO subroutine)
RET ;Then exit to calling routine
;Subroutine to decrement double-byte value in CPU registers H and L.
DEC: DCL ;Decrement contents of L
INL ;Now increment to exercise CPU flags
JFZ DECNO ;If L not presently zero, skip decrementing H
DCH ;Else decrement H
DECNO: DCL ;Do the actual decrement of L
RET ;Return to caller
;Subroutine to index the value in CPU registers H and L by the contents of CPU register B.
INDEXB: LAL ;Load L into the accumulator
ADB ;Add B to that value
LLA ;Restore the new value to L
RFC ;If no carry, return to caller
INH ;Else, increment value in H
RET ;Before returning to caller
;The following subroutine is used to display the ASCII encoded character in the ACC on the
;system's display device. This routine calls a routine labeled CINPUT which must be provided
;by the user to actually drive the system's output device. The subroutine below also increments
;an output column counter each time it is used.
ECHO: LDH ;Save entry value of H in register D
LEL ;And save entry value of L in register E
LLI 043 ;Set L to point to COLUMN COUNTER storage location
LHI OLDPG1/400 ;** Set H to page of COLUMN COUNTER
LBM ;Fetch the value in the COLUMN COUNTER
INB ;And increment it for each character displayed
LMB ;Restore the updated count in memory
CAL CPRINT ;tt Call the user's device driver subroutine
LHD ;Restore entry value of H from D
LLE ;Restore entry value of L from E
RET ;Return to calling routine
CINPUT: JMP CINP ;Reference to user defined input subroutine
EVAL: LLI 227 ;Load L with address of ARITHMETIC STACK pointer
LHI OLDPG1/400 ;** Set H to page of ARITHMETIC STACK pointer
LMI 224 ;Initialize ARITH STACK pointer value to addr minus 4
INL ;Advance memory pointer to FUN/ARRAY STACK pntr
LHI OLDPG26/400 ;** Set H to page of FUN/ARRAY STACK pointer
LMI 000 ;Initialize FUNIARRAY STACK pointer to start of stack
CAL CLESYM ;Initialize the SYMBOL BUFFER to empty condition
LLI 210 ;Load L with address of OPERATOR STACK pointer
LMI 000 ;Initialize OPERATOR STACK pointer value
LLI 276 ;Set L to address of EVAL pointer (start of expression)
LBM ;Fetch the EVAL pointer value into register B
LLI 200 ;Set up a working pointer register in this location
LMB ;And initialize EVAL CURRENT pointer
SCAN1: LLI 200 ;Load L with address of EVAL CURRENT pointer
CAL GETCHR ;Fetch a character in the expression being evaluated
JTZ SCAN10 ;If character is a space, jump out of this section
CPI 253 ;See if character is a "+" sign
JFZ SCAN2 ;If not, continue checking for an operator
LLI 176 ;If yes, set pointer to PARSER TOKEN storage location
LMI 001 ;Place TOKEN value for "+" sign in PARSER TOKEN
JMP SCANFN ;Go to PARSER subroutine entry point
SCAN2: CPI 255 ;See if character is a minus ("-") sign
JFZ SCAN4 ;If not, continue checking for an operator
LLI 120 ;If yes, check the length of the symbol stored in the
LAM ;SYMBOL BUFFER by fetching the (cc) byte
NDA ;And testing to see if (cc) is zero
JFZ SCAN3 ;If length not zero, then not a unary minus indicator
LLI 176 ;Else, check to see if last operator was a right parenthesi
LAM ;By fetching the value in the PARSER TOKEN storage
CPI 007 ;Location and seeing if it is token value for ")"
JTZ SCAN3 ;If last operator was I')" then do not have a unary minus
CPI 003 ;Check to see if last operator was C4*~2
JTZ SYNERR ;If yes, then have a syntax error
CPI 005 ;Check to see if last operator was exponentiation
JTZ SYNERR ;If yes, then have a syntax error
LLI 120 ;If none of the above, then minus sign is unary, put
LMI 001 ;Character string representing the
INL ;Value zero in the SYMBOL BUFFER in string format
LMI 260 ;(Character count (cc) followed by ASCII code for zero)
SCAN3: LLI 176 ;Set L to address of PARSER TOKEN storage location
LMI 002 ;Set PARSER TOKEN value for minus operator
SCANFN: CAL PARSER ;Call the PARSER subroutine to process current symbol
JMP SCAN10 ;And operator. Then jump to continue processing.
SCAN4: CPI 252 ;See if character fetched from expression is
JFZ SCAN5 ;If not, continue checking for an operator
LLI 176 ;If yes, set pointer to PARSER TOKEN storage location
LMI 003 ;Place TOKEN value for "*" (multiplication) operator in
JMP SCANFN ;PARSER TOKEN and go to PARSER subroutine entry
SCAN5: CPI 257 ;See if character fetched from expression is
JFZ SCAN6 ;If not, continue checking for an operator
LLI 176 ;If yes, set pointer to PARSER TOKEN storage location
LMI 004 ;Place TOKEN value for "/" (division) operator in
JMP SCANFN ;PARSER TOKEN and go to PARSER subroutine entry
SCAN6: CPI 250 ;See if character fetched from expression is
JFZ SCAN7 ;If not, continue checking for an operator
LLI 230 ;If yes, load L with address of FUN/ARRAY STACK
LBM ;Pointer. Fetch the value in the stack pointer. Increment
INB ;It to indicate number of "(" operators encountered.
LMB ;Restore the updated stack pointer back to memory
CAL FUNARR ;Call subroutine to process possible FUNCTION or
LLI 176 ;ARRAY variable subscript. Ihen set pointer to
LMI 006 ;PARSER TOKEN storage and set value for operator
JMP SCANFN ;Go to PARSER subroutine entry point.
SCAN7: CPI 251 ;See if character fetched from expression is
JFZ SCAN8 ;If not, continue checking for an operator
LLI 176 ;If yes, load L with address of PARSER TOKEN
LMI 007 ;Set PARSER TOKEN value to reflect ")"
CAL PARSER ;Call the PARSER subroutine to process current symbol
CAL PRIGHT ;Call subroutine to handle FUNCTION or ARRAY
LLI 230 ;Load L with address of FUN/ARRAY STACK pointer
LHI OLDPG26/400 ;** Set H to page of FUN/ARRAY STACK pointer
LBM ;Fetch the value in the stack pointer. Decrement it
DCB ;To account for left parenthesis just processed.
LMB ;Restore the updated value back to memory.
JMP SCAN10 ;Jump to continue processing expression.
SCAN8: CPI 336 ;See if character fetched from expression is " t
JFZ SCAN9 ;If not, continue checking for an operator
LLI 176 ;If yes, load L with address of PARSER TOKEN
LMI 005 ;Put in value for exponentiation
JMP SCANFN ;Go to PARSER subroutine entry point.
SCAN9: CPI 274 ;See if character fetched is the "less than" sign
JFZ SCAN11 ;If not, continue checking for an operator
LLI 200 ;If yes, set L to the EVAL CURRENT pointer
LBM ;Fetch the pointer
INB ;Increment it to point to the next character
LMB ;Restore the updated pointer value
CAL GETCHR ;Fetch the next character in the expression
CPI 275 ;Is the character the "= 9 $ sign?
JTZ SCAN13 ;If so, have 'less than or equal" combination
CPI 276 ;Is the character the "greater than" sign?
JTZ SCAN15 ;If so, have "less than or greater than" combination
LLI 200 ;Else character is not part of the operator. Set L back
LBM ;To the EVAL CURRENT pointer. Fetch the pointer
DCB ;Value and decriment it back one character in the
LMB ;Expression. Restore the original pointer value.
LLI 176 ;Have just the 'less than" operator. Set L to the
LMI 011 ;PARSER TOKEN storage location and set the value for
JMP SCANFN ;The 'less than" sign then go to PARSER entry point.
SCAN11: CPI 275 ;See if character fetched is the "= " sign
JFZ SCAN12 ;If not, continue checking for an operator
LLI 200 ;If yes, set L to the EVAL CURRENT pointer
LBM ;Fetch the pointer
INB ;Increment it to point to the next character
LMB ;Restore the updated pointer value
CAL GETCHR ;Fetch the next character in the expression
CPI 274 ;Is the character the "less than" sign?
JTZ SCAN13 ;If so, have "less than or equal" combination
CPI 276 ;Is the character the "greater than" sign?
JTZ SCAN14 ;If so, have "equal or greater than" combination
LLI 200 ;Else character is not part of the operator. Set L back
LBM ;To the EVAL CURRENT pointer. Fetch the pointer
DCB ;Value and decrement it back one character in the
LMB ;Expression. Restore the original pointer value.
LLI 176 ;Just have '~-- " operator. Set L to the PARSER TOKEN
LMI 012 ;Storage location and set the value for the sign.
JMP SCANFN ;Go to the PARSER entry point.
SCAN12: CPI 276 ;See if character fetched is the "greater than" sign
JFZ SCAN16 ;If not, go append the character to the SYMBOL BUFF
LLI 200 ;If so, set L to the EVAL CURRENT pointer
LBM ;Fetch the pointer
INB ;Increment it to point to the next character
LMB ;Restore the updated pointer value
CAL GETCHR ;Fetch the next character in the expression
CPI 274 ;Is the character the "less than" sign?
JTZ SCAN15 ;If so, have "less than or greater than" combination
CPI 275 ;Is the character the "= " sign?
JTZ SCAN14 ;If so, have the "equal to or greater than " combination
LLI 200 ;Else character is not part of the operator. Set L back
LBM ;To the EVAL CURRENT pointer. Fetch the pointer
DCB ;Value and decrement it back one character in the
LMB ;Expression. Restore the original pointer value.
LLI 176 ;Have just the "greater than" operator. Set L to the
LMI 013 ;PARSER TOKEN storage location and set the value for
JMP SCANFN ;The "greater than" sign then go to PARSER entry
SCAN13: LLI 176 ;When have 'less than or equal" combination set L to
LMI 014 ;PARSER TOKEN storage location and set the value.
JMP SCANFN ;Then go to the PARSER entry point.
SCAN14: LLI 176 ;When have "equal to or greater than" combination set L
LMI 015 ;To PARSER TOKEN storage location and set the value.
JMP SCANFN ;Then go to the PARSER entry point.
SCAN15: LLI 176 ;When have 'less than or greater than" combination set
LMI 016 ;L to PARSER TOKEN storage location and set value.
JMP SCANFN ;Then go to the PARSER entry point.
SCAN16: CAL CONCTS ;Concatenate the character to the SYMBOL BUFFER
SCAN10: LLI 200 ;Set L to the EVAL CURRENT pointer storage location
LHI OLDPG26/400 ;** Set H to page of EVAL CURRENT pointer
LBM ;Fetch the EVAL CURRENT pointer value into B
INB ;Increment the pointer value to point to next character
LMB ;In the expression and restore the updated value.
LLI 277 ;Set L to EVAL FINISH storage location.
LAM ;Fetch the EVAL FINISH value into the accumulator.
DCB ;Set B to last character processed in the expression.
CPB ;See if last character was at EVAL FINISH location.
JFZ SCAN1 ;If not, continue processing the expression. Else, jump
JMP PARSEP ;To final evaluation procedure and test. (Directs routine
HLT ;To a dislocated section.) Safety Halt in unused byte.
PARSER: LLI 120 ;Load L with starting address of SYMBOL BUFFER
LHI OLDPG26/400 ;** Load H with page of SYMBOL BUFFER
LAM ;Fetch the (cc) for contents of SYMBOL BUFFER
NDA ;Into the ACC and see if buffer is empty
JTZ PARSE ;If empty then no need to convert contents
INL ;If not empty, advance buffer pointer
LAM ;Fetch the first character in the buffer
CPI 256 ;See if it is ASCII code for decimal sign
JTZ PARNUM ;If yes, consider contents of buffer to be a number
CPI 260 ;If not decimal sign, see if first character represents
JTS LOOKUP ;A deciinal digit, if not, should have a variable
CPI 272 ;Continue to test for a decimal digit
JFS LOOKUP ;If not, go look up the variable nwne
PARNUM: DCL ;If SYMBOL BUFFER contains number, decrement
LAM ;Buffer pointer back to (cc) and fetch it to ACC
CPI 001 ;See if length of string in buffer is just one
JTZ NOEXPO ;If so, cannot have number with scientific notation
ADL ;If not, add length to buffer pointer to
LLA ;Point to last character in the buffer
LAM ;Fetch the last character in buffer and see if it
CPI 305 ;Represents letter E for Exponent
JFZ NOEXPO ;If not, cannot have number with scientific notation
LLI 200 ;If yes, have part of a scientific number, set pointer to
CAL GETCHR ;Get the operator that follows the E and append it to
JMP CONCTS ;The SYMBOL BUFFER and return to EVAL routine
NOEXPO: LLI 227 ;Load L with address of ARITHMETIC STACK pointer
LHI OLDPG1/400 ;** Load H with page of ARITHMETIC STACK pointer
LAM ;Fetch AS pointer value to ACC and add four to account
ADI 004 ;For the number of bytes required to store a number in
LMA ;Floating point format. Restore pointer to mernory.
LLA ;Then, change L to point to entry position in the AS
CAL FSTORE ;Place contents of the FPACC onto top of the AS
LLI 120 ;Change L to point to start of the SYMBOL BUFFER
LHI OLDPG26/400 ;** Set H to page of the SYMBOL BUFFER
CAL DINPUT ;Convert number in the buffer to floating point format
JMP PARSE ;In the FPACC then jump to check operator sign.
LOOKUP: LLI 370 ;Load L with address of LOOK-UP COUNTER
LHI OLDPG26/400 ;** Load H with page of the counter
LMI 000 ;Initialize the counter to zero
LLI 120 ;Load L with starting address of the SYMBOL BUFFER
LDI OLDPG27/400 ;** Load D with page of the VARIABLES TABLE
LEI 210 ;Load E with start of the VARLIABLES TABLE
LAM ;Fetch the (cc) for the string in the SYMBOL BUFFER
CPI 001 ;See if the name length is just one character. If not,
JFZ LOOKU1 ;Should be two so proceed to look-up routine. Else,
LLI 122 ;Change L to second character byte in the buffer and set
LMI 000 ;It to zero to provide compatibility with entries in table
LOOKU1: LLI 121 ;Load L with addr of first character in the SYMBOL
LHI OLDPG26/400 ;** BUFFER. Set H to page of the SYMBOL BUFFER.
CAL SWITCH ;Exchange contents of D&E with H&L so that can
LAM ;Fetch the first character of a name in the VARIABLES
INL ;TABLE. Advance the table pointer and save the
LBM ;Second byte of name in B. Then advance the pointer
INL ;Again to reach first bvte of floating point forrnatted
CAL SWITCH ;Number in table. Now exchange D&E with H&L and
CPM ;Compare first byte in table against first char in buffer
JFZ LOOKU2 ;If not the same, go try next entry in table. If same,
INL ;Advance pointer to next char in buffer. Transfer the
LAB ;Character in B (second byte in table entry) to the ACC
CPM ;Compare it against second character in the buffer.
JTZ LOOKU4 ;If match, have found the name in the VARIABLES tbl.
LOOKU2: CAL AD4DE ;Call subroutine to add four to the pointer in D&E to
LLI 370 ;Advance the table pointer over value bytes. Then set
LHI OLDPG26/400 ;** Up H and L to point to LOOK-UP COUNTER.
LBM ;Fetch counter value (counts number of entries tested
INB ;In the VARIABLES TABLE), increment it
LMB ;And restore it back to meynory
LLI 077 ;Load L with address of SYMBOL VARIABLES counter
LHI OLDPG27/400 ;** Do same for H. (Counts number of names in table.)
LAB ;Place LOOK-UP COUNTER value in the accumulator.
CPM ;Compare it with number of entries in the table.
JFZ LOOKU1 ;If have not reached end of table, keep looking for name.
LLI 077 ;If reach end of table without match, need to add name
LHI OLDPG27/400 ;** To table. First set H & L to the SYMBOL
LBM ;VARIABLES counter. Fetch the counter value and
INB ;Increment to account for new name being added to the
LMB ;Table. Restore the updated count to meinory. Also,
LAB ;Move the new counter value to the accumulator and
CPI 025 ;Check to see that table size is not exceeded. If try to
JFS BIGERR ;Go over 20 (decirnal) entries then have BIG error.
LLI 121 ;Else, set L to point to first character in the SYMBOL
LHI OLDPG26/400 ;** BUFFER and set H to proper page. Set the number
LBI 002 ;Of bytes to be transferred into register B as a counter.
CAL MOVEIT ;Move the symbol name from the buffer to the
LLE ;VARIABLES TABLE. Now set up H & L with value
LHD ;Contained in D & E after moving ops (points to first
XRA ;Byte of the value to be associated with the symbol
LMA ;Name.) Clear the accumulator and place zero in all four
INL ;Bytes associated with the variable name entered
LMA ;In the VARIABLES TABLE
INL ;In order to
LMA ;Assign an
INL ;Initial value
LMA ;To the variable narne
LAL ;Then transfer the address in L to the acc'umulator
SUI 004 ;Subtract four to reset the pointer to start of zeroing ops
LEA ;Restore the address in D & E to be in same state as if
LDH ;Name was found in the table in the LOOKUP routine
LOOKU4: CAL SAVEHL ;Save current address to VARIABLES TABLE
LLI 227 ;Load L with address of ARITHMETIC STACK pointer
LHI OLDPG1/400 ;** Load H with page of the pointer
LAM ;Fetch the AS pointer value to the accumulator
ADI 004 ;Add four to account for next floating point forrnatted
LMA ;Number to be stored in the stack. Restore the stack
LLA ;Pointer to memory and set it up in register L too.
CAL FSTORE ;Place the value in the FPACC on the top of the
CAL RESTHL ;ARITHMETIC STACK. Restore the VARIABLES
CAL SWITCH ;TABLE pointer to H&L and move it to D&E. Now load
CAL FLOAD ;The VARIABLE value from the table to the FPACC.
PARSE: CAL CLESYM ;Clear the SYMBOL BUFFER
LLI 176 ;Load L with address of PARSER TOKEN VALUE
LAM ;And fetch the token value into the accumulator
CPI 007 ;Is it token value for right parenthesis ")" ? If so, have
JTZ PARSE2 ;Special case where must perforin ops til find a "(" !
ADI 240 ;Else, fon-n address to HEIRARCHY IN table and
LLA ;Set L to point to HEIRARCHY IN VALUE in the table
LBM ;Fetch the heirarchy value from the table to register B
LLI 210 ;Set L to OPERATOR STACK pointer storage location
LCM ;Fetch the OS pointer into CPU register C
CAL INDEXC ;Add OS pointer to address of OS pointer storage loc
LAM ;Fetch the token value for the operator at top of the OS
ADI 257 ;And form address to HEIRARCHY OUT table
LLA ;Set L to point to HEIRARCHY OUT VALUE in the
LAB ;Table. Move the HEIRARCHY IN value to the ACC.
CPM ;Compare the HEIRARCHY IN with the HEIRARCHY
JTZ PARSE1 ;OUT value. If heirarchy of current operator equal to or
JTS PARSE1 ;Less than operator on top of OS stack, perfo
LLI 176 ;Operation indicated in top of OS stack. Else, fetch the
LBM ;Current operator token value into register B.
LLI 210 ;Load L with address of the OPERATOR STACK pntr
LCM ;Fetch the stack pointer value
INC ;Increment it to account for new entry on the stack
LMC ;Restore the stack pointer value to memory
CAL INDEXC ;For in pointer to next entry in OPERATOR STACK
LMB ;Place the current operator token value on top of the OS
RET ;Exit back to the EVAL routine.
PARSE1: LLI 210 ;Load L with address of the OPERATOR STACK pntr
LAM ;Fetch the stack pointer value to the accumulator
ADL ;Add in the value of the stack pointer address to form
LLA ;Address that points to top entry in the OS
LAM ;Fetch the token value at the top of the OS to the ACC
NDA ;Check to see if the token value is zero for end of stack
RTZ ;Exit back to the EVAL routine if stack empty
LLI 210 ;Else, reset L to the OS pointer storage location
LCM ;Fetch the pointer value
DCC ;Decrement it to account for operator rernoved from
LMC ;The OPERATOR STACK and restore the pointer value
CAL FPOPER ;Perform the operation obtained from the top of the OS
JMP PARSE ;Continue to compare current operator against top of OS
PARSE2: LLI 210 ;Load L with address of the OPERATOR STACK pntr
LHI OLDPG26/400 ;** Load H with page of the pointer
LAM ;Fetch the stack pointer value to the accumulator
ADL ;Add in the value of the stack pointer address to form
LLA ;Address that points to top entry in the OS
LAM ;Fetch the token value at the top of the 0 S to the ACC
NDA ;Check to see if the token value is zero for end of stack
JTZ PARNER ;If end of stack, then have a parenthesis error condx
LLI 210 ;Else, reset L to the OS pointer storage location
LCM ;Fetch the pointer value
DCC ;Decrement it to account for operator removed from
LMC ;The OPERATOR STACK and restore the pointer value
CPI 006 ;Check to see if token value is "(" to close parenthesis
RTZ ;If so, exit back to EVAL routine.
CAL FPOPER ;Else, perforin the op obtained from the top of the OS
JMP PARSE2 ;Continue to process data in parenthesis
FPOPER: LLI 371 ;Load L with address of TEMP OP storage location
LHI OLDPG26/400 ;** Load H with page of TEMP OP storage location
LMA ;Store OP (from top of OPERATOR STACK)
LLI 227 ;Change L to address of ARff HMETIC STACK pointer
LHI OLDPG1/400 ;** Load H with page of AS pointer
LAM ;Fetch AS pointer value into ACC
LLA ;Set L to top of ARITHMETIC STACK
CAL OPLOAD ;Transfer number from ARffHMETIC STACK to FPOP
LLI 227 ;Restore pointer to AS pointer
LAM ;Fetch the pointer value to the ACC and subtract four
SUI 004 ;To remove top value from the ARITHMETIC STACK
LMA ;Restore the updated AS pointer to memory
LLI 371 ;Set L to address of TEMP OP storage location
LHI OLDPG26/400 ;** Set H to page of TEMP OP storage location
LAM ;Fetch the operator token value to the ACC
CPI 001 ;Find out which kind of operation indicated
JTZ FPADD ;Perforn addition if have plus operator
CPI 002 ;If not plus, see if minus
JTZ FPSUB ;Perform subtraction if have minus operator
CPI 003 ;If not minus, see if multiplication
JTZ FPMULT ;Perform multiplication if have multiplication operator
CPI 004 ;If not multiplication, see if division
JTZ FPDIV ;Perform division if have division operator
CPI 005 ;If not division, see if exponentiation
JTZ INTEXP ;Perform exponentiation if have exponentiation operator
CPI 011 ;If not exponentiation, see if "less than" operator
JTZ LT ;Perform compaison for "less than" op if indicated
CPI 012 ;If not 'less than" see if have "equal" operator
JTZ EQ ;Perforin comparison for "equal" op if indicated
CPI 013 ;If not "equal" see if have "greater than" operator
JTZ GT ;Perform comparison for "greater than" op if indicated
CPI 014 ;If not "'greater than" see if have 'less than or equal" op
JTZ LE ;Perform comparison for the combination op if indicated
CPI 015 ;See if have "equal to or greater than" operator
JTZ GE ;Perform comparison for the combination op if indicated
CPI 016 ;See if have "less than or greater than" operator
JTZ NE ;Perform comparison for the combination op if indicated
PARNER: LLI 230 ;If cannot find operator, expression is not balanced
LHI OLDPG26/400 ;** Set H and L to address of F/A STACK pointer
LMI 000 ;Clear the F/A STACK pointer to re-initialize
LAI 311 ;Load ASCII code for letter I into the accumulator
LCI 250 ;And code for "(" character into register C
JMP ERROR ;Go display 1( for "Imbalanced Parenthesis") error msg
LT: CAL FPSUB ;Subtract contents of FPACC from FPOP to compare
LLI 126 ;Set L to point to the MSW of the FPACC (Contains
LAM ;Result of the subtraction.) Fetch the MSW of the
NDA ;FPACC to the accumulator and test to see if result is
JTS CTRUE ;Positive or negative. Set up the FPACC as a function
JMP CFALSE ;Of the result obtained.
EQ: CAL FPSUB ;Subtract contents of FPACC from FPOP to compare
LLI 126 ;Set L to point to the MSW of the FPACC (Contains
LAM ;Result of the subtraction.) Fetch the MSW of the
NDA ;FPACC to the accumulator and test to see if result is
JTZ CTRUE ;Equal. Set up the FPACC as a function
JMP CFALSE ;Of the result obtained.
GT: CAL FPSUB ;Subtract contents of FPACC from FPOP to compare
LLI 126 ;Set L to point to the MSW of the FPACC (Contains
LAM ;Result of the subtraction.) Fetch the MSW of the
NDA ;FPACC to the accumulator and test to see if result is
JTZ CFALSE ;Positive, Negative, or Equal. Set up the FPACC
JFS CTRUE ;As a function
JMP CFALSE ;Of the result obtained.
LE: CAL FPSUB ;Subtract contents of FPACC from FPOP to compare
LLI 126 ;Set L to point to the MSW of the FPACC (Contains
LAM ;Result of the subtraction.) Fetch the MSW of the
NDA ;FPACC to the accumulator and test to see if result is
JTZ CTRUE ;Positive, Negative, or Equal. Set up the FPACC
JTS CTRUE ;As a function
JMP CFALSE ;Of the result obtained
GE: CAL FPSUB ;Submit contents of FPACC from FPOP to compare
LLI 126 ;Set L to point to the MSW of the FPACC (Contains
LAM ;Result of the subtraction.) Fetch the MSW of the
NDA ;FPACC to the accumulator and test to see if result is
JFS CTRUE ;Positive or Negative. Set up the FPACC
JMP CFALSE ;As a function of the result obtained
NE: CAL FPSUB ;Subtract contents of FPACC from FPOP to compare
LLI 126 ;Set L to point to the MSW of the FPACC (Contains
LAM ;Result of the subtraction.) Fetch the MSW of the
NDA ;FPACC to the accumulator and test to see if result is
JTZ CFALSE ;Equal. Set up the FPACC as a function of the result.
CTRUE:
FPONE: LLI 004 ;Load L with address of floating point value +1.0
JMP FLOAD ;Load FPACC with value +1.0 and exit to caller
CFALSE: LLI 127 ;Load L with address of FPACC Exponent register
LMI 000 ;Set the FPACC Exponent to zero and then set the
JMP FPZERO ;Mantissa portion of the FPACC to zero. Exit to caller.
AD4DE: LAE ;Subroutine to add four to the value in register E.
ADI 004 ;Move contents of E to the ACC and add four.
LEA ;Restore the updated value back to register E.
RET ;Return to the calling routine.
INTEXP: LLI 126 ;Load L with address of WSW of FPACC (Floating Point
LHI OLDPG1/400 ;** ACCumulator). Load H with page of FPACC.
LAM ;Fetch MSW of the FPACC into the accumulator.
LLI 003 ;Load L with address of EXP TEMP storage location
LMA ;Store the FPACC MSW value in EXP TEMP location
NDA ;Test contents of the MSW of the FPACC. ff zero, then
JTZ FPONE ;Set FPACC equal to +1.0 (any nr to zero power = 1.0!)
CTS FPCOMP ;If MSW indicates negative number, complement
CAL FPFIX ;The FPACC. Then convert floating point number to
LLI 124 ;Fixed point. Load L with address of LSW of fixed nr
LBM ;Fetch the LSW into CPU register B.
LLI 013 ;Set L to address of EXPONENT COUNTER
LMB ;Place the fixed value in the EXP CNTR to indicate
LLI 134 ;Number of multiplications needed (power). Now set L
LEI 014 ;To LSW of FPOP and E to address of FP TEMP (LSW)
LHI OLDPG1/400 ;** Set H to floating point working area page.
LDH ;Set D to same page address.
LBI 004 ;Set transfer (precision) counter. Call subroutine to move
CAL MOVEIT ;Contents of FPOP into FP TEMP registers to save
CAL FPONE ;Original value of FPOP. Now set FPACC to +1.0.
LLI 003 ;Load L with pointer to original value of FPACC
LAM ;(Stored in FP TEMP) MSW and fetch contents to ACC.
NDA ;Test to see if raising to a negative power. If so, divide
JTS DVLOOP ;Instead of multiply!
MULOOP: LLI 014 ;Load L with address of LSW of FP TEMP (original
CAL FACXOP ;Value in FPOP). Move FP TEMP into FPOP.
CAL FPMULT ;Multiply FPACC by FPOP. Result left in FPACC.
LLI 013 ;Load L with address of EXPONENT COUNTER.
LBM ;Fetch the counter value
DCB ;Decrement it
LMB ;Restore it to memory
JFZ MULOOP ;If counter not zero, continue exponentiation process
RET ;When have raised to proper power, return to caller.
DVLOOP: LLI 014 ;Load L with address of LSW of FP TEMP (original
CAL FACXOP ;Value in FPOP). Move FP TEMP into FPOP.
CAL FPDIV ;Divide FPACC by FPOP. Result left in FPACC.
LLI 013 ;Load L with address of EXPONENT COUNTER
LBM ;Fetch the counter value
DCB ;Decrement it
LMB ;Restore to memory
JFZ DVLOOP ;If counter not zero, continue exponentiation process
RET ;When have raised to proper power, return to caller.
PRIGHT: LLI 230 ;Load L with address of F/A STACK pointer
LHI OLDPG26/400 ;** Load H with page of F/A STACK pointer