-
Notifications
You must be signed in to change notification settings - Fork 33
/
pdp11.zip
2806 lines (2577 loc) · 75.8 KB
/
pdp11.zip
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
.TITLE ZIP Z-language Interpreter Program
.IDENT /ZIP.15/
ZMVERS= 3 ;Z-MACHINE VERSION NUMBER
.ENABL LC
; Proprietary documentation of:
;
; Infocom, Inc.
; 55 Wheeler St.
; Cambridge, MA 02138
;
; Copyright (C) 1982, 1983 Infocom, Inc. All rights reserved.
;
;This listing is furnished for a specific purpose under an
;agreement that it will not be copied in any form or made
;available to any other party. Neither will the information
;contained herein be disclosed. When the purpose for which
;this listing has been furnished is completed, the listing
;will be returned to Infocom. This listing will at all times
;remain the property of Infocom.
.SBTTL DEFINE PROGRAM SECTIONS AND ATTRIBUTES
.PSECT PARAM,D ;PARAMETERS, MUST BE FIRST
.PSECT DATA,D ;MOST MODIFIABLE DATA
.PSECT STRING,RO,D ;STRING SPACE, READ ONLY
.PSECT CODE,RO ;INSTRUCTIONS, READ ONLY
.PSECT BUFFER,D ;EXPANDABLE DATA AREA AT END OF PROGRAM
.SBTTL PROGRAMMING CONVENTIONS
;PROGRAM SECTIONS:
; CODE READ ONLY, CONTAINS ALL CODE AND SOME CONSTANT DATA
; DATA CONTAINS MOST DATA INCLUDING EVERYTHING MODIFIABLE
; STRING CONTAINS STRING DATA, MOSTLY FROM STRING MACROS
; BUFFER POINTS TO DYNAMICALLY ALLOCATED MEMORY ABOVE PROGRAM
; PARAM SET UP PARAMETERS PATCHED IN BY USER (HOPEFULLY)
;EACH SUBROUTINE IS OFFSET FROM THE NEXT BY A BLANK LINE. EACH BEGINS
;WITH A SHORT DESCRIPTION INCLUDING REGISTERS USED - BOTH ARGUMENTS
;AND RETURNED VALUES.
;GENERALLY, A SINGLE ARGUMENT IS PASSED IN R0. A SINGLE VALUE WILL
;LIKEWISE BE RETURNED IN R0. IN ANY CASE, R0 IS A SCRATCH REGISTER
;AND NEED NOT BE PRESERVED. ALL OTHER REGISTERS, EXCEPT WHERE OTHER-
;WISE SPECIFIED, MUST BE PRESERVED ACROSS EACH SUBROUTINE CALL. NOTE
;THAT TOP-LEVEL ROUTINES, OPx ROUTINES, ARE EXCLUDED FROM THIS
;RESTRICTION.
;SUBROUTINES ARE NORMALLY CALLED VIA JSR PC. THOSE THAT SKIP RETURN
;OR TAKE FOLLOWING ARGUMENTS, AS SPECIFIED IN THE INDIVIDUAL DESCRIPTION,
;ARE CALLED VIA JSR R5. SINCE R5 IS ALSO USED AS THE ZSTACK-POINTER,
;SUCH SUBROUTINES CANNOT USE THE ZSTACK.
.SBTTL CONFIGURATION FLAGS
SOBINS= 0 ;HAS NO HARDWARE SOB
EIS= 0 ;HAS NO HARDWARE EIS
NEW11= 0 ;HAS NO SXT, XOR, MARK, RTT, SOB, OR EIS
RT11= 1 ;USE RT-11 MONITOR CALLS
.SBTTL GENERAL MACROS
;PUSH REGISTERS ONTO STACK
.MACRO SAVE REGS
.IRPC REGNUM,REGS
MOV R'REGNUM,-(SP)
.ENDM
.ENDM SAVE
;POP REGISTERS FROM STACK
.MACRO RESTOR REGS
.IRPC REGNUM,REGS
MOV (SP)+,R'REGNUM
.ENDM
.ENDM RESTOR
;PRINT A STRING STORED IN STRING AREA AND THEN DIE
.MACRO FATAL STR
.PSECT STRING
$$$=.
.ASCIZ \STR\
.PSECT CODE
JSR R5,FATALR
.WORD $$$
.ENDM FATAL
;PRINT A STRING STORED IN STRING AREA WITH INFORMATIONAL HEADER
.MACRO INFORM STR
.PSECT STRING
$$$=.
.ASCIZ \STR\
.PSECT CODE
JSR R5,INFRMR
.WORD $$$
.ENDM INFORM
;PRINT A STRING STORED IN STRING AREA WITH NO NEWLINE
.MACRO PRIN1 STR
.PSECT STRING
$$$=.
.ASCII \STR\<200>
.PSECT CODE
MOV #$$$,R0
JSR PC,OUTSTR
.ENDM PRIN1
;DEFINE A VARIABLE IN DATA SECTION
.MACRO DEFVAR NAM,VAL
.PSECT DATA
.IF NB ^\VAL\
NAM:: VAL
.IFF
NAM:: 0
.ENDC
.PSECT CODE
.ENDM DEFVAR
;IF NO NEW 11 INSTRUCTIONS, REPLACE WITH OTHER INSTRUCTIONS
.IF EQ NEW11
SOBINS= 0 ;CAN'T HAVE THESE, EITHER
EIS= 0
;SIGN EXTEND
.MACRO SXT ARG,?NEGLOC,?ENDLOC
BMI NEGLOC ;WAS OTHER WORD NEGATIVE?
CLR ARG ;NO, MAKE THIS WORD ZERO (NON-NEGATIVE),
BR ENDLOC ;& SKIP TO END
NEGLOC: MOV #-1,ARG ;YES, MAKE THIS WORD ALL ONES (NEGATIVE)
ENDLOC:
.ENDM SXT
;EXCLUSIVE OR
.MACRO XOR REG,ARG
.ERROR ;XOR NOT IMPLEMENTED
.ENDM XOR
;MARK STACK
.MACRO MARK LOC
.ERROR ;MARK NOT IMPLEMENTED
.ENDM MARK
;RETURN FROM TRAP WITH T-BIT TRAP INHIBITED
.MACRO RTT
.ERROR ;RTT NOT IMPLEMENTED
.ENDM RTT
.ENDC
;IF NO SOB, REPLACE WITH OTHER INSTRUCTIONS
.IF EQ SOBINS
.MACRO SOB REG,LOC
DEC REG
BNE LOC
.ENDM SOB
.ENDC
;IF NO EIS INSTRUCTIONS, REPLACE WITH SIMULATION ROUTINES
.IF EQ EIS
;ARITHMETIC SHIFT (SINGLE WORD)
.MACRO ASH NUM,REG
MOV REG,-(SP)
MOV NUM,-(SP)
JSR PC,ASHSIM
MOV (SP)+,REG
.ENDM ASH
;ARITHMETIC SHIFT (DOUBLE WORD)
.MACRO ASHC NUM,REG
.ERROR ;ASHC NOT IMPLEMENTED
.ENDM ASHC
;MULTIPLY (SINGLE WORD ONLY)
.MACRO MUL NUM,REG
.IF DIF REG,R1
.IF DIF REG,R3
.IF DIF REG,R5
.ERROR ;DOUBLE WORD MULTIPLY NOT IMPLEMENTED
.ENDC
.ENDC
.ENDC
MOV REG,-(SP)
MOV NUM,-(SP)
JSR PC,MULSIM
MOV (SP)+,REG
.ENDM MUL
;DIVIDE (DOUBLE WORD)
.MACRO DIV NUM,REG
MOV REG,-(SP)
MOV REG+1,-(SP)
MOV NUM,-(SP)
JSR PC,DIVSIM
MOV (SP)+,REG+1
MOV (SP)+,REG
.ENDM DIV
.ENDC
.SBTTL ARITHMETIC OPERATIONS
.PSECT CODE
;ADD
OPADD:: ADD R1,R0 ;ADD OPR1 AND OPR2
JMP PUTVAL ;RETURN THE VALUE
;SUB
OPSUB:: SUB R1,R0 ;SUBTRACT OPR2 FROM OPR1
JMP PUTVAL ;RETURN THE VALUE
;MUL
OPMUL:: MUL R0,R1 ;MULTIPLY OPR1 BY OPR2
MOV R1,R0 ;IGNORING OVERFLOW
JMP PUTVAL ;RETURN THE VALUE
;DIV
OPDIV:: MOV R1,R2 ;REARRANGE OPERANDS FOR DIVIDE
MOV R0,R1
SXT R0
DIV R2,R0 ;DIVIDE OPR1 BY OPR2
JMP PUTVAL ;RETURN THE VALUE
;MOD
OPMOD:: MOV R1,R2 ;REARRANGE OPERANDS FOR DIVIDE
MOV R0,R1
SXT R0
DIV R2,R0 ;DIVIDE OPR1 BY OPR2
MOV R1,R0 ;WE WANT REMAINDER
JMP PUTVAL ;RETURN THE VALUE
;RANDOM
DEFVAR RSEED ;SEED FOR RANDOM NUMBERS
OPRAND::MOV RSEED,R1 ;GET THE SEED
MUL #257.,R1 ;TRANSFORM IT
ADD #13,R1
MOV R0,R2
MOV R1,RSEED ;SAVE NEW VALUE
CLR R0 ;TRIM IT TO PROPER SIZE
BIC #100000,R1 ;CLEAR BIT TO PREVENT POSSIBLE OVERFLOW
DIV R2,R0
MOV R1,R0
INC R0 ;MUST BE BETWEEN 1 AND N, INCLUSIVE
JMP PUTVAL ;RETURN THE VALUE
;LESS?
OPQLES::CMP R0,R1 ;IS OPR1 LESS THAN OPR2?
BLT JPT ;YES, PREDICATE TRUE
JPF: JMP PFALSE ;NO, PREDICATE FALSE
JPT: JMP PTRUE
;GRTR?
OPQGRT::CMP R0,R1 ;IS OPR1 GREATER THAN OPR2?
BGT JPT ;YES, PREDICATE TRUE
BR JPF ;NO, PREDICATE FALSE
.SBTTL LOGICAL OPERATIONS
;BTST
OPBTST::BIC R0,R1 ;TURN OFF ALL BITS IN OPR2 THAT ARE ON IN OPR1
BEQ JPT ;SUCCESS IF OPR2 COMPLETELY CLEARED
BR JPF
;BOR
OPBOR:: BIS R1,R0 ;LOGICAL OR
JMP PUTVAL ;RETURN THE VALUE
;BCOM
OPBCOM::COM R0 ;LOGICAL COMPLEMENT
JMP PUTVAL ;RETURN THE VALUE
;BAND
OPBAND::COM R1 ;LOGICAL AND
BIC R1,R0
JMP PUTVAL ;RETURN THE VALUE
.SBTTL GENERAL PREDICATES
;EQUAL?
OPQEQU::NOP ;TELL CALLER TO USE ARGUMENT BLOCK
CMP 2(R0),4(R0) ;IS OPR1 EQUAL TO OPR2?
BEQ 1$ ;YES
CMP (R0),#3 ;NO, IS THERE A THIRD OPERAND?
BLT 2$ ;NO
CMP 2(R0),6(R0) ;YES, IS IT EQUAL TO OPR1?
BEQ 1$ ;YES
CMP (R0),#4 ;NO, IS THERE A FOURTH?
BLT 2$ ;NO
CMP 2(R0),10(R0) ;YES, IS IT EQUAL TO OPR1?
BNE 2$ ;NO
1$: JMP PTRUE ;PREDICATE TRUE IF EQUAL
2$: JMP PFALSE ;PREDICATE FALSE IF NOT
;ZERO?
OPQZER::TST R0 ;IS OPR ZERO?
BNE 1$ ;NO, PREDICATE FALSE
JMP PTRUE ;YES, PREDICATE TRUE
1$: JMP PFALSE
.SBTTL OBJECT OPERATIONS
;MOVE (OBJ1 INTO OBJ2)
OPMOVE::SAVE 01 ;PROTECT OPRS FROM REMOVE CALL
JSR PC,OPREMO ;REMOVE OBJ1 FROM WHEREVER IT IS
MOV (SP),R0 ;OBJ2
JSR PC,OBJLOC ;FIND ITS LOCATION
MOV R0,R2 ;SAVE FOR LATER
MOV 2(SP),R0 ;OBJ1
JSR PC,OBJLOC ;FIND ITS LOCATION
RESTOR 1 ;OBJ2
MOVB R1,4(R0) ;PUT OBJ2 INTO OBJ1'S LOC SLOT
MOVB 6(R2),R3 ;GET CONTENTS OF OBJ2'S FIRST SLOT
RESTOR 1 ;OBJ1
MOVB R1,6(R2) ;MAKE OBJ1 FIRST CONTENT OF OBJ2
TST R3 ;WERE THERE ANY OTHER CONTENTS?
BEQ 1$ ;NO
MOVB R3,5(R0) ;YES, CHAIN ONTO OBJ1'S SIBLING SLOT
1$: RTS PC
;REMOVE (OBJ FROM ITS PARENT)
OPREMO::MOV R0,R2 ;SAVE OBJ FOR LATER
JSR PC,OBJLOC ;FIND ITS LOCATION
MOV R0,R1 ;SAVE THAT
MOVB 4(R1),R0 ;GET ITS PARENT
BEQ 3$ ;IF NO PARENT, WE'RE DONE
JSR PC,OBJLOC ;FIND PARENT'S LOCATION
MOVB 6(R0),R3 ;GET PARENT'S FIRST CONTENT
CMPB R3,R2 ;IS IT OBJ?
BNE 1$ ;NO
MOVB 5(R1),6(R0) ;YES, CHANGE SLOT TO OBJ'S SIBLING
BR 2$ ;AND RETURN
1$: MOV R3,R0 ;CURRENT SIBLING
JSR PC,OBJLOC ;FIND ITS LOCATION
MOVB 5(R0),R3 ;GET NEXT SIBLING IN CHAIN
CMPB R3,R2 ;IS IT OBJ?
BNE 1$ ;NO, CONTINUE LOOP
MOVB 5(R1),5(R0) ;YES, CHANGE IT TO OBJ'S SIBLING
2$: CLRB 4(R1) ;OBJ NOW HAS NO PARENT
CLRB 5(R1) ;OR SIBLING
3$: RTS PC
;FSET? (IS FLAG SET IN OBJ?)
OPQFSE::JSR PC,OBJLOC ;FIND OBJ'S LOCATION
CMP R1,#20 ;SECOND WORD FLAG?
BLT 1$ ;NO
SUB #20,R1 ;YES, SUBTRACT 16 FROM FLAG NUMBER
ADD #2,R0 ;AND USE SECOND FLAG WORD
1$: JSR PC,GTAWRD ;GET THE FLAG WORD
SUB #17,R1 ;SHIFT A BIT TO PROPER POSITION
NEG R1
MOV #1,R2
ASH R1,R2
BIT R2,R0 ;IS THIS BIT SET IN FLAG WORD?
BEQ 2$ ;NO, PREDICATE FALSE
JMP PTRUE ;YES, PREDICATE TRUE
2$: JMP PFALSE
;FSET (SET A FLAG IN OBJ)
OPFSET::JSR PC,OBJLOC ;FIND OBJ'S LOCATION
CMP R1,#20 ;SECOND WORD FLAG?
BLT 1$ ;NO
SUB #20,R1 ;YES, SUBTRACT 16 FROM FLAG NUMBER
ADD #2,R0 ;AND USE SECOND FLAG WORD
1$: MOV R0,R3 ;REMEMBER THIS LOCATION
JSR PC,GTAWRD ;GET THE FLAG WORD
SUB #17,R1 ;SHIFT A BIT TO PROPER POSITION
NEG R1
MOV #1,R2
ASH R1,R2
BIS R2,R0 ;SET THIS BIT IN FLAG WORD
MOV R0,R1
MOV R3,R0
JMP PTAWRD ;STORE THE NEW FLAG WORD
;FCLEAR (CLEAR A FLAG IN OBJ)
OPFCLE::JSR PC,OBJLOC ;FIND OBJ'S LOCATION
CMP R1,#20 ;SECOND WORD FLAG?
BLT 1$ ;NO
SUB #20,R1 ;YES, SUBTRACT 16 FROM FLAG NUMBER
ADD #2,R0 ;AND USE SECOND FLAG WORD
1$: MOV R0,R3 ;REMEMBER THIS LOCATION
JSR PC,GTAWRD ;GET THE FLAG WORD
SUB #17,R1 ;SHIFT A BIT TO PROPER POSITION
NEG R1
MOV #1,R2
ASH R1,R2
BIC R2,R0 ;CLEAR THIS BIT IN FLAG WORD
MOV R0,R1
MOV R3,R0
JMP PTAWRD ;STORE THE NEW FLAG WORD
;LOC (RETURN CONTAINER OF OBJ)
OPLOC:: JSR PC,OBJLOC ;FIND OBJ'S LOCATION
MOVB 4(R0),R0 ;GET LOC SLOT
JMP BYTVAL ;RETURN THE BYTE VALUE
;FIRST? (RETURN FIRST SLOT OF OBJ, FAIL IF NONE)
OPQFIR::JSR PC,OBJLOC ;FIND OBJ'S LOCATION
MOVB 6(R0),R0 ;GET FIRST SLOT
SAVE 0
JSR PC,BYTVAL ;RETURN THE BYTE VALUE
RESTOR 0 ;WAS IT ZERO?
BEQ JPF1 ;YES, PREDICATE FALSE
JPT1: JMP PTRUE ;NO, PREDICATE TRUE
JPF1: JMP PFALSE
;NEXT? (RETURN THE NEXT (SIBLING) SLOT OF OBJ, FAIL IF NONE)
OPQNEX::JSR PC,OBJLOC ;FIND OBJ'S LOCATION
MOVB 5(R0),R0 ;GET SIBLING SLOT
SAVE 0
JSR PC,BYTVAL ;RETURN THE BYTE VALUE
RESTOR 0 ;WAS IT ZERO?
BEQ JPF1 ;YES, PREDICATE FALSE
BR JPT1 ;NO, PREDICATE TRUE
;IN? (IS OBJ1 CONTAINED IN OBJ2?)
OPQIN:: JSR PC,OBJLOC ;FIND OBJ1'S LOCATION
CMPB 4(R0),R1 ;IS OBJ1'S PARENT OBJ2?
BEQ JPT1 ;YES, PREDICATE TRUE
BR JPF1 ;NO, PREDICATE FALSE
;GETP (GET SPECIFIED PROPERTY OF OBJ, DEFAULT IF NONE)
OPGETP::JSR PC,OBJLOC ;FIND OBJ'S LOCATION
ADD #7,R0 ;POINT TO PROPERTY TABLE SLOT
JSR PC,GTAWRD ;GET ITS LOCATION
ADD #BUFFER,R0 ;ABSOLUTIZE IT
MOVB (R0),R2 ;LENGTH OF SHORT DESCRIPTION IN WORDS
BIC #^C377,R2 ;CLEAN OFF ANY HIGH-ORDER BYTE
ASL R2 ;CONVERT TO BYTES
ADD R2,R0 ;ADJUST POINTER TO SKIP IT
INC R0 ;ALSO SKIP LENGTH BYTE
BR 2$ ;SKIP NEXT LINE FIRST TIME THROUGH LOOP
1$: JSR PC,NXTPRP ;POINT TO NEXT PROPERTY
2$: MOVB (R0),R2 ;GET PROPERTY IDENTIFIER
BIC #^C37,R2 ;CLEAN OFF LENGTH BITS
CMP R2,R1 ;COMPARE PROPERTY NUMBER WITH DESIRED ONE
BGT 1$ ;IF GREATER, LOOP (TABLE SORTED IN REVERSE)
BLT 3$ ;IF LESS, NO SUCH PROPERTY HERE
MOVB (R0),R2 ;GOT IT, NOW FIND LENGTH OF PROPERTY
INC R0 ;POINT TO PROPERTY VALUE
ASH #-5,R2 ;GET LENGTH BITS
BIC #^C7,R2
BNE 4$ ;ZERO MEANS BYTE VALUE
MOVB (R0),R0 ;GET THE BYTE
JMP BYTVAL ;AND RETURN IT
3$: DEC R1 ;POINT INTO DEFAULT PROPERTY TABLE
ASL R1
ADD OBJTAB,R1
MOV R1,R0
4$: JSR PC,GTAWRD ;GET THE WORD
JMP PUTVAL ;AND RETURN IT
;PUTP (CHANGE VALUE OF A PROPERTY, ERROR IF BAD NUMBER)
.ENABL LSB
OPPUTP::JSR PC,OBJLOC ;FIND OBJ'S LOCATION
ADD #7,R0 ;POINT TO PROPERTY TABLE SLOT
JSR PC,GTAWRD ;GET ITS LOCATION
ADD #BUFFER,R0 ;ABSOLUTIZE IT
MOVB (R0),R3 ;LENGTH OF SHORT DESCRIPTION IN WORDS
BIC #^C377,R3 ;CLEAN OFF ANY HIGH-ORDER BYTE
ASL R3 ;CONVERT TO BYTES
ADD R3,R0 ;ADJUST POINTER TO SKIP IT
INC R0 ;ALSO SKIP LENGTH BYTE
BR 2$ ;SKIP NEXT LINE FIRST TIME THROUGH LOOP
1$: JSR PC,NXTPRP ;POINT TO NEXT PROPERTY
2$: MOVB (R0),R3 ;GET PROPERTY IDENTIFIER
BIC #^C37,R3 ;CLEAN OFF LENGTH BITS
CMP R3,R1 ;COMPARE PROPERTY NUMBER WITH DESIRED ONE
BEQ 3$ ;IF EQUAL, GOT IT
BGT 1$ ;IF GREATER, LOOP (TABLE SORTED IN REVERSE)
FATAL <No such property> ;OTHERWISE, FATAL ERROR
3$: MOVB (R0),R3 ;NOW FIND LENGTH OF PROPERTY
INC R0 ;POINT TO PROPERTY VALUE
ASH #-5,R3 ;GET LENGTH BITS
BIC #^C7,R3
BNE 4$ ;ZERO MEANS BYTE VALUE
MOVB R2,(R0) ;STORE THE NEW BYTE
RTS PC ;AND RETURN
4$: MOV R2,R1 ;STORE THE NEW WORD VALUE
JMP PTAWRD
.DSABL LSB
;NEXTP (RETURN NUMBER OF NEXT PROP FOLLOWING GIVEN PROB IN OBJ)
.ENABL LSB
OPNEXT::JSR PC,OBJLOC ;FIND OBJ'S LOCATION
ADD #7,R0 ;POINT TO PROPERTY TABLE SLOT
JSR PC,GTAWRD ;GET ITS LOCATION
ADD #BUFFER,R0 ;ABSOLUTIZE IT
MOVB (R0),R3 ;LENGTH OF SHORT DESCRIPTION IN WORDS
BIC #^C377,R3 ;CLEAN OFF ANY HIGH-ORDER BYTE
ASL R3 ;CONVERT TO BYTES
ADD R3,R0 ;ADJUST POINTER TO SKIP IT
INC R0 ;ALSO SKIP LENGTH BYTE
TST R1 ;WERE WE GIVEN ZERO AS PROP?
BEQ 4$ ;YES, GO RETURN FIRST PROPERTY NUMBER
BR 2$ ;NO, SKIP NEXT LINE FIRST TIME THROUGH LOOP
1$: JSR PC,NXTPRP ;POINT TO NEXT PROPERTY
2$: MOVB (R0),R3 ;GET PROPERTY IDENTIFIER
BIC #^C37,R3 ;CLEAN OFF LENGTH BITS
CMP R3,R1 ;COMPARE PROPERTY NUMBER WITH DESIRED ONE
BEQ 3$ ;IF EQUAL, GOT IT
BGT 1$ ;IF GREATER, LOOP (TABLE SORTED IN REVERSE)
FATAL <No such property> ;OTHERWISE, FATAL ERROR
3$: JSR PC,NXTPRP ;POINT TO NEXT PROPERTY
4$: MOVB (R0),R0 ;GET PROPERTY IDENTIFIER
BIC #^C37,R0 ;EXTRACT PROPERTY NUMBER
JMP PUTVAL ;AND RETURN IT
.DSABL LSB
.SBTTL TABLE OPERATIONS
;GET (GET THE ITEM'TH WORD FROM TABLE)
OPGET:: ASL R1 ;CONVERT ITEM TO BYTE COUNT
ADD R1,R0 ;INDEX INTO TABLE
JSR PC,BSPLTB ;SPLIT THE POINTER
JSR PC,GETWRD ;GET THE WORD
MOV R2,R0
JMP PUTVAL ;AND RETURN IT
;GETB (GET THE ITEM'TH BYTE FROM TABLE)
OPGETB::ADD R1,R0 ;INDEX INTO TABLE
JSR PC,BSPLTB ;SPLIT THE POINTER
JSR PC,GETBYT ;GET THE BYTE
MOV R2,R0
JMP BYTVAL ;AND RETURN IT
;PUT (REPLACE THE ITEM'TH WORD IN TABLE)
OPPUT:: ASL R1 ;CONVERT ITEM TO BYTE COUNT
ADD R1,R0 ;INDEX INTO TABLE
ADD #BUFFER,R0 ;ABSOLUTIZE POINTER
MOV R2,R1
JMP PTAWRD ;STORE THE WORD
;PUTB (REPLACE ITEM'TH BYTE IN TABLE)
OPPUTB::ADD R1,R0 ;INDEX INTO TABLE
MOVB R2,BUFFER(R0) ;STORE BYTE
RTS PC
;GETPT (GET POINTER TO PROPERTY TABLE FOR GIVEN PROP)
OPGTPT::JSR PC,OBJLOC ;FIND OBJ'S LOCATION
ADD #7,R0 ;POINT TO PROPERTY TABLE SLOT
JSR PC,GTAWRD ;GET ITS LOCATION
ADD #BUFFER,R0 ;ABSOLUTIZE IT
MOVB (R0),R2 ;LENGTH OF SHORT DESCRIPTION IN WORDS
BIC #^C377,R2 ;CLEAN OFF ANY HIGH-ORDER BYTE
ASL R2 ;CONVERT TO BYTES
ADD R2,R0 ;ADJUST POINTER TO SKIP IT
INC R0 ;ALSO SKIP LENGTH BYTE
BR 2$ ;SKIP NEXT LINE FIRST TIME THROUGH LOOP
1$: JSR PC,NXTPRP ;POINT TO NEXT PROPERTY
2$: MOVB (R0),R2 ;GET PROPERTY IDENTIFIER
BIC #^C37,R2 ;CLEAN OFF LENGTH BITS
CMP R2,R1 ;COMPARE PROPERTY NUMBER WITH DESIRED ONE
BGT 1$ ;IF GREATER, LOOP (TABLE SORTED IN REVERSE)
BEQ 3$ ;FOUND THE PROPERTY
CLR R0 ;RETURN ZERO FOR NO SUCH PROPERTY
BR 4$
3$: SUB #BUFFER-1,R0 ;POINT TO PROPERTY VALUE & RE-RELATIVIZE IT
4$: JMP PUTVAL ;AND RETURN IT
;PTSIZE (RETURN SIZE OF PROPERTY TABLE)
OPPTSI::MOVB BUFFER-1(R0),R0 ;GET PROPERTY IDENTIFIER
ASH #-5,R0 ;EXTRACT LENGTH BITS
BIC #^C7,R0
INC R0 ;ADJUST TO ACTUAL LENGTH
JMP PUTVAL ;RETURN IT
.SBTTL VARIABLE OPERATIONS
;VALUE (GET VALUE OF VAR)
OPVALU::JSR PC,GETVAR ;GET THE VALUE
JMP PUTVAL ;AND RETURN IT
;SET (VAR TO VALUE)
OPSET:: JMP PUTVAR ;STORE THE VALUE
;PUSH (A VALUE ONTO THE STACK)
OPPUSH::MOV R0,-(R5) ;PUSH THE VALUE
RTS PC
;POP (A VALUE OFF THE STACK INTO VAR)
OPPOP:: MOV (R5)+,R1 ;POP A VALUE
JMP PUTVAR ;AND STORE IT
;INC (INCREMENT VAR)
OPINC:: SAVE 0
JSR PC,GETVAR ;GET VAR'S VALUE
INC R0 ;INCREMENT IT
OPINC1: MOV R0,R1
RESTOR 0
JSR PC,PUTVAR ;STORE NEW VALUE
RTS PC
;DEC (DECREMENT VAR)
OPDEC:: SAVE 0
JSR PC,GETVAR ;GET VAR'S VALUE
DEC R0 ;DECREMENT IT
BR OPINC1 ;STORE NEW VALUE
;IGRTR? (INCREMENT VAR & TEST IF GREATER THAN VAL)
OPQIGR::SAVE 0
JSR PC,GETVAR ;GET VAR'S VALUE
INC R0 ;INCREMENT IT
CLR R2 ;SET FLAG FALSE
CMP R0,R1 ;NEW VALUE GREATER THAN VAL?
BLE OPQIG1 ;NO
OPQIG0: INC R2 ;YES, CHANGE FLAG TO TRUE
OPQIG1: MOV R0,R1
RESTOR 0
JSR PC,PUTVAR ;STORE NEW VALUE
TST R2 ;TEST FLAG
BEQ 1$ ;FALSE, PREDICATE FALSE
JMP PTRUE ;ELSE, PREDICATE TRUE
1$: JMP PFALSE
;DLESS? (DECREMENT VAR & TEST IF LESS THAN VAL)
OPQDLE::SAVE 0
JSR PC,GETVAR ;GET VAR'S VALUE
DEC R0 ;DECREMENT IT
CLR R2 ;SET FLAG FALSE
CMP R0,R1 ;NEW VALUE LESS THAN VAL?
BGE OPQIG1 ;NO, PREDICATE FALSE
BR OPQIG0 ;YES, PREDICATE TRUE
.SBTTL I/O OPERATIONS
EOLCHR= 12 ;LINE-FEED IS END-OF-LINE CHARACTER
MOVVAR= 22 ;NUMBER-OF-MOVES GLOBAL
SCRVAR= 21 ;SCORE VARIABLE
RMVAR= 20 ;CURRENT ROOM VARIABLE
;USL (UPDATE STATUS LINE)
DEFVAR OLDCHS ;OLD NUMBER OF CHARACTERS PRINTED IN NUMBERS
DEFVAR OLDRM ;OLD ROOM
.ENABL LSB
OPUSL:: TST P$TERM ;STATUS LINE REQUESTED?
BNE 1$ ;YES
RTS PC ;NO, DO NOTHING
1$: CLR R3 ;COUNT NUMBER CHARACTERS HERE
MOV SAVPOS,R0 ;SAVE OLD POSITION & SET ATTRIBUTES
JSR PC,OUTSTR
TST TIMEMD ;IN TIME MODE?
BNE 2$ ;YES
MOV SCRPOS,R0 ;NO, MOVE TO SCORE POSITION
JSR PC,OUTSTR
MOV #SCRVAR,R0 ;GET SCORE
JSR PC,GETVAR
JSR PC,OUTNUM ;PRINT IT
ADD R0,R3
MOV #'/,R0 ;SEPARATOR
JSR PC,OUTCHR
MOV #MOVVAR,R0 ;GET NUMBER-OF-MOVES
JSR PC,GETVAR
JSR PC,OUTNUM ;PRINT NUMBER OF MOVES
ADD R0,R3
BR 6$
2$: MOV TIMPOS,R0 ;MOVE TO TIME POSITION
JSR PC,OUTSTR
MOV #SCRVAR,R0 ;GET HOUR
JSR PC,GETVAR
MOV #'a,R2 ;ASSUME AM
CMP R0,#12. ;PM?
BLT 4$ ;NO
BEQ 3$ ;YES, BUT 12PM IS SPECIAL
SUB #12.,R0 ;CONVERT TO 12-HOUR TIME
3$: MOV #'p,R2 ;MODIFY EARLIER ASSUMPTION
4$: TST R0 ;00 IS REALLY 12 AM
BNE 5$
MOV #12.,R0
5$: JSR PC,OUTNUM ;PRINT HOUR
ADD R0,R3
MOV #':,R0 ;SEPARATOR
JSR PC,OUTCHR
MOV #MOVVAR,R0 ;GET MINUTES
JSR PC,GETVAR
MOV R0,R1 ;OUTPUT MINUTES IN TWO DIGITS
CLR R0
DIV #10.,R0 ;SEPARATE DIGITS
ADD #'0,R0 ;PRINT FIRST ONE
JSR PC,OUTCHR
MOV R1,R0 ;PRINT OTHER DIGIT
ADD #'0,R0
JSR PC,OUTCHR
MOV #40,R0 ;SPACE
JSR PC,OUTCHR
MOV R2,R0 ;AM OR PM
JSR PC,OUTCHR
MOV #'m,R0
JSR PC,OUTCHR
6$: MOV #RMVAR,R0 ;GET CURRENT ROOM
JSR PC,GETVAR
CMP R0,OLDRM ;HAS IT CHANGED?
BNE 7$ ;YES
CMP R3,OLDCHS ;NO, BUT HAS SIZE OF NUMBERS CHANGED?
BNE 7$ ;YES
CMP P$TERM,#1 ;NO, BUT IS THIS A VT100?
BEQ 8$ ;OK, GIVE UP
7$: MOV R0,OLDRM ;SAVE NEW ROOM
MOV R3,OLDCHS ;AND NUMBER OF CHARACTERS
MOV LOCPOS,R0 ;MOVE TO ROOM POSITION
JSR PC,OUTSTR
MOV #OUTCHR,CHRFUN ;CHANGE CHARACTER FUNCTION TO DIRECT OUTPUT
MOV OLDRM,R0
JSR PC,OPPRND ;PRINT ROOM DESCRIPTION
MOV #PUTCHR,CHRFUN ;RESET CHARACTER FUNCTION
MOV CLRROL,R0 ;CLEAR REST OF LINE
JSR PC,OUTSTR
8$: MOV RETPOS,R0 ;RETURN TO OLD POSITION, RESET ATTRIBUTES,
JMP OUTSTR ;& RETURN
.DSABL LSB
;READ (A LINE OF INPUT & PARSE IT, LINE BUF IN R0, RETURN BUF IN R1)
.ENABL LSB
OPREAD::SAVE 01
JSR PC,OPUSL ;UPDATE STATUS LINE
RESTOR 1
JSR PC,TSTSCR ;TEST FOR SCRIPTING & UPDATE FLAGS ACCORDINGLY
MOVB #200,@CHRPTR ;DON'T END OUTPUT, IF ANY, WITH NEW LINE
1$: JSR PC,BUFOUT ;FORCE OUT ANY QUEUED TEXT
CLRB @CHRPTR ;RESTORE CRLF CHARACTER
MOV OUTBUF,CHRPTR ;RESET CHARACTER POINTER
RESTOR 2 ;INPUT BUFFER POINTER
ADD #BUFFER,R2 ;ABSOLUTIZE IT
MOV R2,R4
MOVB (R2)+,R3 ;MAX NUMBER OF CHARACTERS TO GET
2$: JSR PC,GETCHR ;INPUT A CHARACTER
CMP R0,#EOLCHR ;END OF THE LINE?
BEQ 5$ ;YES
CMP R0,#'A ;NO, UPPERCASE?
BLT 3$ ;NO
CMP R0,#'Z
BGT 3$ ;NO
ADD #40,R0 ;YES, LOWERCASIFY IT
3$: MOVB R0,(R2)+ ;SAVE IN LINE BUFFER
SOB R3,2$ ;LOOP UNTIL EOL OR BUFFER FULL
JSR PC,GETCHR ;BUFFER FULL, LAST CHANCE FOR EOL
CMP R0,#EOLCHR ;IS IT?
BEQ 5$ ;YES, WIN
SAVE 0 ;NO, INFORM LOSER
PRIN1 <Input line too long, flushing: >
RESTOR 0
4$: JSR PC,OUTCHR ;AND FLUSH REST OF LINE
JSR PC,GETCHR
CMP R0,#EOLCHR
BNE 4$
JSR PC,OUTCHR
5$: CMPB 1(R4),#'@ ;IS THIS A REQUEST FOR A COMMAND FILE?
BNE 7$ ;NO
TST CMDBUF ;YES, ALREADY HAVE A COMMAND FILE OPEN?
BNE 6$ ;YES, IGNORE THIS LINE & GET ANOTHER
JSR PC,OPNCFL ;NO, OPEN THE COMMAND FILE
6$: SUB #BUFFER,R4 ;RERELATIVIZE INPUT BUFFER POINTER,
SAVE 4 ;PUT ONTO STACK,
BR 1$ ;AND READ ANOTHER LINE
7$: DEFVAR RDWSTR,<.BLKW 4> ;WORD STRING BUFFER FOR ZWORD
DEFVAR RDBOS ;BEGINNING OF STRING POINTER
DEFVAR RDEOS ;END OF STRING POINTER
DEFVAR RDRET ;RETURN TABLE POINTER
DEFVAR RDNWDS ;NUMBER OF WORDS READ
SAVE 5
MOV R4,RDBOS ;INITIALIZE RDBOS
MOV R2,RDEOS ;AND RDEOS
ADD #BUFFER,R1 ;ABSOLUTIZE RET POINTER
MOV R1,RDRET ;AND STORE IT
CLR RDNWDS ;NO WORDS SO FAR
INC R4 ;SKIP LENGTH BYTE
MOV R1,R5 ;THIS WILL BE WORD ENTRY POINTER
ADD #2,R5 ;SKIP MAX WORDS & NWORDS BYTES
8$: MOV #RDWSTR,R3 ;HERE FOR NEXT WORD, POINT TO WORD STRING
MOV R4,R1 ;AND SAVE BEGINNING OF WORD POINTER
9$: CMP R4,RDEOS ;END OF STRING?
BNE 10$ ;NO
CMP R3,#RDWSTR ;YES, WAS A WORD FOUND?
BEQ 23$ ;NO, WE'RE DONE
BR 15$ ;YES, WE STILL HAVE TO LOOKUP WORD
10$: MOVB (R4)+,R0 ;GET NEXT CHARACTER FROM BUFFER
MOV RBRKS,R2 ;LIST OF READ BREAK CHARACTERS
11$: CMPB R0,(R2)+ ;SEARCH LIST FOR THIS ONE
BEQ 12$ ;FOUND IT
TSTB (R2) ;END OF LIST?
BNE 11$ ;NO, CONTINUE SEARCH
CMP R3,#RDWSTR+6 ;YES, NOT A BREAK, WORD STRING FULL?
BEQ 9$ ;YES, LOOP UNTIL END OF WORD
MOVB R0,(R3)+ ;NO, TACK THIS CHARACTER ONTO STRING
BR 9$ ;AND LOOP
12$: CMP R3,#RDWSTR ;WORD READ BEFORE THIS BREAK?
BNE 14$ ;YES
CMP R2,ESIBKS ;NO, BUT IS IT A SELF-INSERTING BREAK?
BLOS 13$ ;YES
INC R1 ;NO, UPDATE BEGINNING OF WORD TO SKIP BREAK
BR 9$ ;AND RETURN TO LOOP TO FIND A WORD
13$: MOVB R0,(R3)+ ;STORE THE BREAK IN WORD STRING
BR 15$ ;AND GO FOR THE WORD
14$: DEC R4 ;UNREAD TERMINATING BREAK IN CASE IT WAS SI
15$: INC RDNWDS ;INCREMENT FOUND WORD COUNT
CMPB RDNWDS,@RDRET ;GREATER THAN MAX ALLOWED?
BLE 16$ ;NO
PRIN1 <Too many words typed, flushing: > ;YES, INFORM LOSER
MOV R1,R0 ;BEGINNING OF THIS WORD
MOVB @RDEOS,R1 ;SAVE BYTE AFTER EOS
CLRB @RDEOS ;ZERO IT TO MAKE STRING ASCIZ
JSR PC,OUTSTR ;PRINT IT
MOVB R1,@RDEOS ;AND RESTORE OLD BYTE
DEC RDNWDS ;REMEMBER THAT WE FLUSHED THIS WORD
BR 23$ ;AND WE'RE DONE
16$: MOV R1,R0 ;CALCULATE NUMBER OF CHARACTERS IN WORD
NEG R0
ADD R4,R0
MOVB R0,2(R5) ;SAVE THE NUMBER IN RET TABLE
SUB RDBOS,R1 ;BYTE OFFSET FOR BEGINNING OF WORD
MOVB R1,3(R5) ;STORE IT, TOO
CLRB (R3) ;MAKE WORD STRING ASCIZ
MOV #RDWSTR,R0 ;POINT TO IT
JSR PC,ZWORD ;AND CONVERT TO (2-WORD) ZWORD
SAVE 45 ;SAVE CHAR & WORD ENTRY POINTERS
MOV R0,R4 ;FIRST ZWORD WORD
MOV R1,R5 ;SECOND ZWORD WORD
MOV VWORDS,R2 ;NUMBER OF VOCABULARY WORDS
MOV R2,R3
DEC R3 ;WE WANT TO POINT TO LAST WORD
MUL VWLEN,R3 ;MULTIPLY BY WORD LENGTH IN BYTES
ADD VOCBEG,R3 ;ADD POINTER TO BEGINNING TO FIND LAST WORD
MOV VWLEN,R1 ;CALCULATE INITIAL OFFSET FOR BINARY SEARCH
ASR R2
17$: ASL R1
ASR R2
BNE 17$
MOV VOCBEG,R2 ;BEGINNING OF WORD TABLE
ADD R1,R2 ;ADD CURRENT OFFSET (HALF OF POWER-OF-2 TABLE)
SUB VWLEN,R2 ;AVOID FENCE-POST BUG FOR EXACT POWER-OF-2 TBL
18$: ASR R1 ;NEXT OFFSET WILL BE HALF OF PREVIOUS ONE
MOV R2,R0 ;GET FIRST HALF OF CURRENT ZWORD
JSR PC,GTAWRD
CMP R4,R0 ;COMPARE DESIRED ONE TO IT
BHI 19$ ;GREATER, WE'LL HAVE TO MOVE UP
BLO 20$ ;LESS, WE'LL HAVE TO MOVE DOWN
MOV R2,R0 ;SAME, GET SECOND HALF
ADD #2,R0
JSR PC,GTAWRD
CMP R5,R0 ;COMPARE DESIRED WORD WITH IT
BHI 19$ ;GREATER, WE'LL HAVE TO MOVE UP
BLO 20$ ;LESS, WE'LL HAVE TO MOVE DOWN
SUB #BUFFER,R2 ;SAME, WE'VE FOUND IT, RELATIVIZE POINTER
BR 22$ ;AND RETURN IT
19$: ADD R1,R2 ;TO MOVE UP, ADD CURRENT OFFSET
CMP R2,R3 ;HAVE WE MOVED PAST END OF TABLE?
BLOS 21$ ;NO
MOV R3,R2 ;YES, POINT TO END OF TABLE INSTEAD
BR 21$
20$: SUB R1,R2 ;TO MOVE DOWN, SIMPLY SUBTRACT OFFSET
21$: CMP R1,VWLEN ;IS OFFSET RESOLUTION BELOW ONE WORD?
BGE 18$ ;NO, CONTINUE LOOP
CLR R2 ;YES, WORD NOT FOUND, RETURN ZERO
22$: RESTOR 54 ;RESTORE WORD ENTRY AND CHAR POINTERS
MOV R5,R0 ;POINTER TO WORD FOUND GOES HERE
MOV R2,R1 ;THE POINTER
JSR PC,PTAWRD ;STORE IT
ADD #4,R5 ;UPDATE POINTER FOR NEXT WORD ENTRY
JMP 8$ ;GO FOR IT
23$: INC RDRET ;DONE, STORE NUMBER OF WORDS FOUND
MOVB RDNWDS,@RDRET
RESTOR 5 ;RESTORE USER STACK POINTER
RTS PC ;AND RETURN
.DSABL LSB
;PRINTC (PRINT CHAR WHOSE ASCII VALUE IS GIVEN)
OPPRNC::JMP PUTCHR ;QUEUE THE CHARACTER FOR PRINTING
;PRINTN (PRINT A NUMBER)
OPPRNN::MOV R0,R1 ;NUMBER TO PRINT
BNE 1$ ;NON-ZERO
MOV #'0,R0 ;SPECIAL CASE ZERO
JMP PUTCHR
1$: BGT 2$ ;POSITIVE?
MOV #'-,R0 ;NO, PRINT MINUS SIGN
JSR PC,PUTCHR
NEG R1 ;AND MAKE IT POSITIVE
2$: CLR R2 ;COUNT OF DIGITS ON STACK
BR 4$ ;START WITH GREATER-THAN-10 TEST
3$: CLR R0 ;EXTRACT A DIGIT
DIV #10.,R0
MOV R1,-(SP) ;PUSH IT
INC R2 ;BUMP COUNT
MOV R0,R1 ;GET QUOTIENT
4$: CMP R1,#10. ;MORE DIGITS TO EXTRACT?
BGE 3$ ;YES, GO LOOP
MOV R1,R0 ;NO, GET LAST (FIRST) DIGIT
BR 6$ ;ALREADY IN PLACE
5$: MOV (SP)+,R0 ;POP NEXT DIGIT
6$: ADD #'0,R0 ;ASCIIZE IT
JSR PC,PUTCHR ;QUEUE IT
DEC R2 ;REDUCE DIGIT COUNT
BGE 5$ ;LOOP IF SOME LEFT
RTS PC ;ELSE, RETURN
;PRINT (THE STRING POINTED TO)
OPPRIN::JSR PC,BSPLIT ;SPLIT THE BLOCK & WORD NUMBERS
JMP PUTSTR ;PRINT THE STRING
;PRINTB (PRINT THE STRING POINTED TO BY THE BYTE-POINTER)
OPPRNB::JSR PC,BSPLTB ;SPLIT THE BLOCK & BYTE NUMBERS
JMP PUTSTR ;PRINT THE STRING
;PRINTD (PRINT OBJ'S SHORT DESCRIPTION)
OPPRND::JSR PC,OBJLOC ;FIND OBJ'S LOCATION
ADD #7,R0 ;PROPERTY TABLE POINTER
JSR PC,GTAWRD ;GET IT
INC R0 ;POINT TO STRING
JSR PC,BSPLTB ;SPLIT POINTER
JMP PUTSTR ;AND PRINT THE STRING
;PRINTI (PRINT THE STRING FOLLOWING THIS INSTRUCTION)
OPPRNI::MOV ZPC1,R0 ;GET POINTER TO STRING
MOV ZPC2,R1
JSR PC,PUTSTR ;AND PRINT IT
MOV R0,ZPC1 ;UPDATE ZPC
MOV R1,ZPC2
JMP NEWZPC
;PRINTR (PRINTI FOLLOWED BY RTRUE)
OPPRNR::JSR PC,OPPRNI ;DO A PRINTI
JSR PC,OPCRLF ;A CRLF
JMP OPRTRU ;AND AN RTRUE
;CRLF (DO A NEWLINE)
OPCRLF::JMP NEWLIN ;DO A NEWLINE
.SBTTL CONTROL OPERATIONS
;CALL (A FUNCTION WITH OPTIONAL ARGUMENTS)
OPCALL::NOP ;TELL CALLER TO USE ARGUMENT BLOCK
MOV R0,R2 ;ARGUMENT BLOCK POINTER
MOV 2(R2),R0 ;FUNCTION TO CALL
BNE 1$ ;ZERO?
CLR R0 ;YES, SIMPLY RETURN A ZERO
JMP PUTVAL
1$: MOV ZPC1,-(R5) ;OTHERWISE, SAVE OLD ZPC
MOV ZPC2,-(R5)
MOV ZLOCS,-(R5) ;AND OLD LOCAL POINTER
SUB STKBOT,(R5) ;BUT RELATIVIZE IT IN CASE OF SAVE
JSR PC,BSPLIT ;SPLIT FUNCTION POINTER
MOV R0,ZPC1 ;MAKE IT THE NEW ZPC
MOV R1,ZPC2
JSR PC,NEWZPC ;UPDATE ZPC STUFF
MOV R5,ZLOCS ;LOCALS WILL START AT NEXT STACK SLOT
SUB #2,ZLOCS
JSR PC,NXTBYT ;NUMBER OF LOCALS
MOV R0,R1
MOV (R2),R3 ;NUMBER OF ARGUMENTS TO CALL
ADD #4,R2 ;POINT TO FIRST OPTIONAL ARG
2$: DEC R1 ;ANY MORE LOCALS?
BLT 4$ ;NO, WE'RE DONE
JSR PC,NXTWRD ;YES, GET THE NEXT LOCAL DEFAULT VALUE
DEC R3 ;ANY MORE OPTIONALS GIVEN?
BLE 3$ ;NO
MOV (R2)+,-(R5) ;YES, USE ITS VALUE
BR 2$ ;AND CONTINUE LOOP
3$: MOV R0,-(R5) ;OTHERWISE, USE DEFAULT
BR 2$ ;AND LOOP
4$: RTS PC
;RETURN (FROM CURRENT FUNCTION CALL)
OPRETU::MOV ZLOCS,R5 ;RESTORE OLD TOP OF STACK
TST (R5)+
MOV (R5)+,ZLOCS ;AND OTHER VALUES
ADD STKBOT,ZLOCS ;RE-ABSOLUTIZE THIS ONE
MOV (R5)+,ZPC2
MOV (R5)+,ZPC1
SAVE 0 ;VALUE TO RETURN
JSR PC,NEWZPC ;UPDATE ZPC STUFF
RESTOR 0
JMP PUTVAL ;RETURN THE VALUE
;RTRUE
OPRTRU::MOV #1,R0 ;RETURN A 1
BR OPRETU
;RFALSE
OPRFAL::CLR R0 ;RETURN A 0
BR OPRETU
;JUMP (TO A NEW LOCATION)
OPJUMP::ADD R0,ZPC2 ;ADD OFFSET TO CURRENT ZPC
SUB #2,ZPC2 ;ADJUST IT
JMP NEWZPC ;NORMALIZE IT & UPDATE ZPC STUFF
;RSTACK (RETURN STACK)
OPRSTA::MOV (R5)+,R0 ;POP A VALUE
BR OPRETU ;AND RETURN IT
;FSTACK (FLUSH A VALUE OFF THE STACK)