-
Notifications
You must be signed in to change notification settings - Fork 4
/
Copy pathSUB1.MAC
584 lines (512 loc) · 16.7 KB
/
SUB1.MAC
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
; SUB1.MAC 12-Feb-83
; Globals defined:
.globl IDLE,RANDOM,TTinr,DECPRT,INMASK,CLEAR,DECIN
.globl RNGNRM,LOCPRT,LOCIN,CRLF,CURMES,TEST,INLMES,ADRMES
.globl DELAY,SPACE,TTin,SAVACS,DIV10,LOCDOT,TABBER,BCKSPC
.iif ne,EIS .globl .MUL,.DIV
.mcall .regdef,.ttyin,.ttinr
.globl SEEDHI,SEEDLO,STACK,PLYR,ROUND,CURSOR,SETCUR
.globl idle,TTout,TTinr,IROWCO,BELL
;;;;;;;;;;;;;;;;;;;;;;;;;;;
; SPACE & TABBER & BCKSPC
; Purpose: Type a space, tab, backspace respectively
; Use:
; call SPACE
;
SPACE: .imes < >
rts PC
TABBER: jsr R1,INLMES ;note that cursor pos gets screwed up
.byte TAB,0
rts PC
BCKSPC: jsr R1,INLMES
.byte BS,0
rts PC
;;;;;;;;;;;;;;;;;;;;;;;;;;
; Save and restore R0-R5.
; Use:
; call SUBR ;use PC as linkage reg
;
; SUBR: jsr R0,SAVACS
; code of subr....
; rts PC ;return to RESACS, then to caller of SUBR
;
SAVACS: ;R0 already pushed
push <R1,R2,R3,R4,R5>
push #resacs ;caller return addr
push R0 ;SAVACS ret addr
mov 14(SP),R0 ;restore R0
rts PC ;return to caller
resacs: ;caller returns to here
pop <R5,R4,R3,R2,R1,R0>
rts PC ;ret to caller of caller
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Delay for approx N/3 seconds.
; Use:
; jsr R5,DELAY
; .word N
;
DELAY: push R0
push (R5)+ ;push N
beq 1$ ;if no delay
3$: clr R0 ;control count
2$: sob R0,2$ ;loop 2**16 times
dec (SP) ;dec N
bne 3$ ;till 0
1$: pop ;pop N
pop R0
rts R5
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; IDLE
; Purpose: Switch stacks and variables between to programs, such
; that they seem to run simultaneously.
; Use:
; call IDLE ;R5 must be set up beforehand
;
; Condition codes destroyed.
;
IDLE: push <R0,R1,R2,R3,R4> ;save regs on old stack
mov SP,STACK(R5) ;save old stack pointer
mov R5,R4 ;keep old var pntr
mov PLYR(R5),R5 ;get new variable pointer
mov ROUND(R4),R0 ;get old turn #
add #10,R0
if R0 his ROUND(R5), 1$ ;ROUND(old)+10 >= ROUND(new)?
mov R4,R5 ;don't switch players
1$: mov STACK(R5),SP ;get new stack pointer
pop <R4,R3,R2,R1,R0> ;restore new regs
rts PC ;return to new program
;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Return a value in R0 that is between 0 and (max-1).
; Inputs:
; Requires SEEDHI and SEEDLO globals.
; R0 = max
; Output:
; R0 = random #
; Z = set if R0=0
; Algorithm:
; if (SEEDHI,SEEDLO) = 0 then Xn+1 = 2**16 + 3
; else Xn+1 = (2**16 + 3) Xn mod 2**32
; where Xn=(SEEDHI,SEEDLO) ;a 32 bit quantitiy
;
RANDOM: push <R3,R2,R1,R0> ;push R0 last
mov SEEDLO,R3
mov SEEDHI,R2 ;put Xn in (R2,R3)
bne 1$
tst R3
bne 1$ ;if Xn<>0 goto 1$
mov #3,R3
mov #1,R2 ;Xn = 2**16 + 3
1$: mov R3,R0
clr R1 ;(R0,R1)= 2**16 * (R2,R3)
add R3,R1 ;(R0,R1)= (R0,R1)+3*(R2,R3) (add in 3 times)
adc R0
add R2,R0
add R3,R1
adc R0
add R2,R0
add R3,R1
adc R0
add R2,R0
mov R1,SEEDLO
mov R0,SEEDHI ;store Xn+1 for next time
mov R0,R1 ;R0 is our 16-bit random number
clr R0 ;calculate R0=R0 mod max
mov #16,R2
3$: rol R1
rol R0
if (SP) hi R0, 4$ ;if max>R0
sub (SP),R0 ;R0=R0-max
4$: sob R2,3$ ;loop 16 times
tst (SP)+ ;pop max
pop <R1,R2,R3>
tst R0 ;set Z
rts PC
;;;;;;;;;;;;;;;;;;;;;;;
; Get char from terminal and return in R0.
; Do not pass LFs as they are a nuisance.
TTin: .ttyin
ifb R0 eq #LF, TTin ;swallow LFs
rts PC
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Same as TTin except if no characters are available keep calling
; IDLE.
TTinr: br 1$
2$: push CURSOR ;remember cursor position
call IDLE ;call IDLE while we wait
pop R0 ;get cursor
call SETCUR ;make sure cursor is there
1$: .ttinr
bcs 2$ ;call IDLE if no character
ifb R0 eq #LF, 1$ ;swallow LFs
rts PC
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Convert lower case ascii in R0 to upper case
LCtoUC: ifb R0 lo #'a, 1$
ifb R0 hi #'z, 1$
bicb #^O40,R0 ;convert to upper case
1$: rts PC
;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Divide by 10
; Input:
; R1 = 16 bit #
; Output:
; R0 = R1 / 10
; R1 = R1 mod 10
; Z = 1 if (R1=0)
DIV10:
.if eq,EIS ;EIS machine?
.ift
clr R0 ;high 16 bits of R1
div #10,R0 ;R0=(R0,R1)/10, remainder in R1
.iff
mov #10,R0
call .DIV
.endc
tst R1 ;test remainder
rts PC
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Print the number in R0 in decimal, including sign
DECPRT: .savacs
mov R0,R1 ;need it in R0 for DIV
bpl 1$ ;if R1>=0
.imes <->
neg R1 ;R1 is now positive
1$: clr R2 ;R2 is number of digits to be typed
2$: call DIV10 ;R0=R1/10, remainder in R1
push R1 ;push digit to be printed
inc R2 ;number of digits
mov R0,R1 ;put quotient in R1
bne 2$ ;till nothing left
3$: pop R0 ;get dig to be printed
add #'0,R0 ;convert to ASCII
call TTout ;type it
sob R2,3$ ;loop till no more digits
rts PC
.if ne,EIS ;only if not an EIS machine
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Provide a substitute for DIV instructions for non-EIS machines.
; Unsigned, divide by 0 check.
; Input:
; R0,R1 16 bit #s
; Output:
; R0 = R1 / R0
; R1 = R1 mod R0
.DIV: push <R2,R3>
;first left-justify dividend in R0, put # of shifts in R2
mov #1,R2 ;initialize number of shifts
tst R0 ;test for sign
beq div0 ;whoops! divide by 0
bmi 1$ ;already left-justified
2$: inc R2 ;number of shifts
asl R0 ;shift left
bpl 2$ ;until left-justified
1$: mov #-1,R3 ;R3 will hold result
4$: sub R0,R1 ;see if we can subtract it
bcc 3$ ;yes! we have a 1 in the quotient
add R0,R1 ;nope, add it back in, C is set
3$: rol R3 ;C becomes rightmost bit
clc ;make sure we shift in a 0
ror R0 ;0 is shifted into leftmost bit
sob R2,4$ ;loop till no more shifts
mov R3,R0 ;put quotient in R0
com R0 ;we ROLed in the complement
retd: pop <R3,R2>
rts PC
div0: .imes <Div 0>
br retd
.endc
.if ne,EIS ;only if not an EIS machine
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Substitute for MUL instruction, tho not exactly. R1=R0*R1
; Input:
; R0,R1 factors
; Output:
; R0 = 0
; R1 = R0 * R1
.MUL: push <R2,R3>
mov #16,R2 ;control count
clr R3 ;result
2$: ror R1 ;shift into carry
bcc 1$ ;if 0
add R0,R3 ;if 1, add to result
1$: asl R0 ;multiply factor by 2
sob R2,2$ ;loop thru all the bits
mov R3,R1 ;put result in R1
pop <R3,R2>
rts PC
.endc
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Determine if bit is set in a 32 bit mask.
; Inputs:
; R1: Bit number (0-31)
; mask: 32 bit quantity, 0 is leftmost bit, 31 is rightmost
; Use:
; mov bitnum,R1
; jsr R5,INMASK
; .word maskhi ;bits 0-15
; .word masklo ;bits 16-31
;
; Output:
; R1: Preserved
; C: 1 if bit is set, else 0
;
INMASK:
.if eq,EIS ;EIS machine?
.ift
push <R2,R3>
mov (R5)+,R2 ;put maskhi in R2
mov (R5)+,R3 ;masklo in R3
inc R1 ;set to 1-32
ashc R2,R1 ;shift left R1 times into C
dec R1 ;restore R1
pop <R3,R2>
.iff
push R1
push R2
push R3
mov (R5)+,R2 ;get maskhi
mov (R5)+,R3 ;get masklo
inc R1 ;for SOB
1$: asl R3 ;masklo
rol R2 ;32 bit shift into C
sob R1,1$ ;R1 times
pop R3
pop R2
pop R1
.endc
rts R5
;*****************************
; CLEAR
; Purpose: Clear numbytes of memory starting at addr.
; Use:
; jsr R5,CLEAR
; .word addr ;starting addr
; .word addr+numbytes ;# of bytes to clear
;
CLEAR: push R0
mov (R5)+,R0 ;get start addr
1$: clrb (R0)+ ;clear a byte
cmp R0,(R5) ;done?
bne 1$ ;no
tst (R5)+ ;point to ret addr
pop R0
rts R5
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; DECIN
; Purpose: Get a number from the terminal in decimal, return it in R0.
; Use:
; jsr R5,DECIN
; .word delim ;character to recognize end of input
DECIN:
push R1
push R2
clr R1 ;running total
clr R2 ;set if result is to be negative
2$: call TTinr ;get digit
ifb R0 lo #'0, 3$ ;not a digit
ifb R0 hi #'9, 3$ ;not a digit
call TTout ;echo character
sub #'0,R0 ;convert to number
.if eq,EIS
.ift
mul #10,R1
add R0,R1 ;R1=R1*10+R0
.iff
push R0
mov #10,R0
call .MUL
add (SP)+,R1
.endc
br 2$ ;get more digits
3$: cmp (R5),R0 ;see if it's the delimiter
beq 4$ ;yes
cmpb #'-,R0 ;see if it's negative
bne 1$
tst R2 ;see if already negative
bmi 1$ ;yes
tst R1 ;no imbedded -
bne 1$
call TTout ;echo it
com R2 ;set to indicate result is to be negative
br 2$
1$: call BELL ;angrilly ring bell
br 2$ ;get more digits
4$: call TTout ;echo delimiter
tst R2 ;see if negative
bpl 5$
neg R1 ;if so, R1 is negative
5$: mov R1,R0
pop R2
pop R1
tst (R5)+ ;add 2 to R5
rts R5
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; RNGNRM
; Purpose: Given a byte value in R0, round it off until it fits inside the
; range given. Return with C set if any change in R0 is done. The
; byte in R0 is assumed to be signed.
; Use:
; mov value,R0
; jsr R5,RNGNRM
; .byte minval,maxval ;max and min values for R0, respectively
;
RNGNRM:
ifb R0 ge (R5)+, 1$ ;if R0>=minval
movb -1(R5),R0 ;R0=minval
2$: sec
3$: inc R5 ;set R5 to ret addr
rts R5
1$: ifb R0 le (R5), 4$ ;if R0<=maxval
movb (R5),R0 ;R0=maxval
br 2$
4$: clc
br 3$
;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Print a location in R0 in row,column format.
; Input:
; R0 = location
LOCPRT: .savacs
call IROWCO ;separate into row and column
call DECPRT ;print row
.imes <,>
mov R1,R0
jmp DECPRT ;print column
;;;;;;;;;;;;;;;;;;;;;;;
; LOCIN
; Purpose: Get a location from terminal in row,column format.
; Return in R0.
; Use:
; call LOCIN
;
LOCIN: jsr R5,DECIN ;get row
.word ', ;comma terminates
swab R0 ;put row in left half
push R0
jsr R5,DECIN
.word ESC ;get column
bis (SP)+,R0 ;OR in row
rts PC
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; CRLF
; Purpose: Send a <CR><LF> to the terminal.
; Use:
; call CRLF
;
CRLF: jsr R1,INLMES
.byte CR,LF,0,0
rts PC
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; ADRMES
; Purpose: Type a string of characters.
; Use:
; push addr ;address of start of string
; call ADRMES
;
ADRMES:
push R1
mov 4(SP),R1 ;get pointer to start of string
call typstr
pop R1
mov (SP),2(SP) ;copy down ret addr
pop ;adjust SP
rts PC
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Type a string of characters on the terminal.
; Use:
; jsr R1,INLMES ;use R1 as linkage pointer
; .asciz /text/ ;string to be typed
; .even
;
; INLMES will return to the instruction following the asciz string.
INLMES:
call typstr
inc R1
bic #1,R1 ;point to next word
rts R1 ;which we return to
;;;;;;;;;;;;;;;;;;;
; Type a string, R1 points to start of string. The string is
; terminated by:
; 0: do nothing
; ^O200: do a CRLF
; eol: erase to end of line
; eold: eol, then DELAY(4)
; Input:
; R1 -> string
; Output:
; R1 -> just past string
;
typstr: push R0
br 1$
4$: call TTout ;type char
1$: movb (R1)+,R0 ;get next char from string
beq 2$ ;done
cmpb #^O200,R0 ;is it a 200 byte?
bne 3$ ;no
pop R0
br CRLF ;do a CRLF
3$: bcc 4$ ;br if R0<^O200
jsr R1,TTfunc
.word 0 ;erase to end of line
cmpb R0,#eold ;is it eold?
bne 2$ ;no
jsr R5,DELAY
.word 4 ;delay for 4/3 sec
2$: pop R0
rts PC
;***************************************
; Combine TTcurs and INLMES to save code.
; Use:
; jsr R1,CURMES
; .byte row,col ;where you want the cursor
; .asciz /message/ ;the message
; .even
;
CURMES:
mov (R1)+,1$ ;set up args for TTcurs
jsr R1,TTcurs ;position cursor
1$: .blkw 1
jmp INLMES ;R1 is already set up for INLMES
;;;;;;;;;;;;;;;;;;;;;;;;;
; Print loc in R0, then '.', then erase to eol.
; Use:
; mov loc,R0
; call LOCDOT
LOCDOT:
call LOCPRT
.imes <.>,eol
rts PC
;;;;;;;;;;;;;;;;;;;;;;;;
; Provide a test point, type out regs.
; Use:
; jsr R5,TEST
; .word num ;test point #
;
TEST: mfps -(SP) ;push PS
push R0
.imes <Test pnt: >
mov (R5)+,R0 ;get arg
call DECPRT ;type it
.imes < R0: >
mov (SP),R0 ;restore R0
call LOCPRT
.imes < R1: >
mov R1,R0
call DECPRT
.imes < R2: >
mov R2,R0
call DECPRT
.imes < R3: >
mov R3,R0
call DECPRT
.imes < R4: >
mov R4,R0
call DECPRT
.imes < R5: >,eol
mov 4(SP),R0
call DECPRT
pop R0
call CRLF
mtps (SP)+ ;pop PS
rts R5
.end
.