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
; Copyright 1996 Acorn Computers Ltd
;
; Licensed under the Apache License, Version 2.0 (the "License");
; you may not use this file except in compliance with the License.
; You may obtain a copy of the License at
;
; http://www.apache.org/licenses/LICENSE-2.0
;
; Unless required by applicable law or agreed to in writing, software
; distributed under the License is distributed on an "AS IS" BASIS,
; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
; See the License for the specific language governing permissions and
; limitations under the License.
;
; > $.Source.Vdu5
; *****************************************************************************
;
; Print a character in VDU 5 mode
;
; *****This file has been extensively modified by DJS
; Alter these at your peril !
cxl RN 0
scr RN 0
ecfptr RN 1
cword0 RN 1
cyb RN 2
cyt2 RN 2
scrend RN 2
cword1 RN 2
cxr RN 3
cyb2 RN 3
ormask RN 3
cxl2 RN 4
eormask RN 4
cyb3 RN 5
charmsk RN 5
cword2 RN 5
cyt RN 6
llength RN 6
chartmp RN 6
sizex RN 7
charptr RN 7
sizey RN 8
invcharshf RN 8
charbyte RN 9
cxr2 RN 10
charshf RN 10
lgBPC RN 11
Vdu5Wrch
Push R14
BL Vdu5DoChar
Pull R14
B PostCharMove
; Vdu23_18
; LDR R0, [WsPtr, #QQ+1]
Vdu5DoChar
ADD ecfptr, WsPtr, #FgEcfOraEor ;Base address of OR/EOR pairs
Vdu5DoChar10
Push "R14"
MOV charbyte, R0 ;Put character out of harm's
; way
ASSERT cxl < cyt
ASSERT GCsIY = GCsIX +4
ADD cxl, WsPtr, #GCsIX
LDMIA cxl, {cxl, cyt} ; cxl=where left pixel would be
; cyt=where top pixel would be
ASSERT sizex < sizey
ADD sizex, WsPtr, #GCharSizes
LDMIA sizex, {sizex, sizey}
CMP sizey, #16 ; if SizeY=8 or SizeY=16
TEQNE sizey, #8 ; (leaving CS <=> SizeY=16)
TEQEQ sizex, #8 ; and SizeX=8, then do it fast
BNE SlowVdu5 ; else do by scaled char
TEQ charbyte, #127 ; Which font do we use?
ADDNE charptr, WsPtr, #(Font-32*8) ; Soft if character not DELETE
ADREQL charptr, HardFont-32*8 ; Hard if character is DELETE
ADD charptr, charptr, charbyte, LSL #3 ;Point at char def
MOVCS charptr, charptr, ASL #1 ; Double address if SizeY = 16
SUBCS charptr, charptr, #1 ; (tricky code, originally
; designed by TMD)
SUB cyb, cyt, sizey
ADD cyb, cyb, #1 ; where bottom pixel would be
ADD cxr, cxl, #7 ; where right pixel would be
ASSERT GWBRow = GWLCol+4
ASSERT GWRCol = GWLCol+8
ASSERT GWTRow = GWLCol+12
ASSERT cyb3 > cxl2
ASSERT cxr2 > cyb3
ASSERT R14 > cxr2
ADD cxl2, WsPtr, #GWLCol
LDMIA cxl2, {cxl2, cyb3, cxr2, R14}
Greatest cxl2, cxl2, cxl ; cxl2 := windowed left
; (2 instructions)
Least cxr2, cxr2, cxr ; cxr2 := windowed right
; (2 instructions)
Greatest cyb2, cyb3, cyb ; cyb2 := windowed bottom
; (3 instructions)
Least cyt2, R14, cyt ; cyt2 := windowed top
; (3 instructions)
SUBS cyb2, cyt2, cyb2 ; top >= bottom ?
CMPGE cxr2, cxl2 ; and right >= left ?
Pull "PC", LT ; Exit if not. Otherwise cyb2
; has become clipped height
LDR R14, [WsPtr, #CursorFlags] ; update changed box, if wanted
TST R14, #ClipBoxEnableBit
BLNE ClipVdu5
ADD charptr, charptr, cyt ; adjust charptr to point at
SUB charptr, charptr, cyt2 ; first used row of character
MOV charmsk, #&FF ; Produce mask to do left/right
SUB R14, cxl2, cxl ; clipping
MOV charmsk, charmsk, LSR R14
SUB R14, cxr2, cxl2
ADD R14, R14, #1
BIC charmsk, charmsk, charmsk, LSR R14
TEQ sizey, #16 ; If double height, signal this
ORREQ charmsk, charmsk, #1:SHL:31 ; by making charmsk negative
ASSERT llength > scr
ASSERT LineLength = YWindLimit+4
LDR lgBPC, [WsPtr, #Log2BPC] ; Address point at (cxl, cyt2),
MOV charshf, cxl, LSL lgBPC ; putting address in scr, bit
ADD scr, WsPtr, #YWindLimit ; offset in charshf and
LDMIA scr, {scr, llength} ; adjusting ecfptr
SUB scr, scr, cyt2
AND R14, scr, #7
ADD ecfptr, ecfptr, R14, LSL #3
LDR R14, [WsPtr, #ScreenStart]
MLA scr, llength, scr, R14
MOV R14, charshf, ASR #5
ADD scr, scr, R14, LSL #2
AND charshf, charshf, #31
MLA scrend, llength, cyb2, scr ;Calculate terminating address
RSB invcharshf, charshf, #32 ;And inverse shift
Vdu5NextLine
ASSERT eormask > ormask
LDMIA ecfptr!, {ormask, eormask} ;Pick up ecf info and advance
TST ecfptr, #63 ; ecf pointer, wrapping if
SUBEQ ecfptr, ecfptr, #64 ; necessary
ASSERT HardFont < &40000000 :LOR: HardFont >= &C0000000
ASSERT WsPtr < &40000000 :LOR: WsPtr >= &C0000000
TEQ charmsk, #0 ; Double height? (MI=yes)
LDRMIB charbyte, [charptr, -charptr, ASR #1] ; Use ASR, as font will be at
LDRPLB charbyte, [charptr] ; top or bottom of memory (zero page,
ADD charptr, charptr, #1 ; system heap or ROM)
ANDS charbyte, charbyte, charmsk ;Clip left & right; skip loop
BEQ Vdu5TryNextLine ; body if nothing to plot
Push "ecfptr,scrend,charmsk,llength,charptr"
LDR R14, [WsPtr, #TextExpandArea] ;Address correct expansion
ADD charptr, charbyte, #&100 ; table entry, assuming that
ADD charptr, R14, charptr, LSL lgBPC ; this is not mode 10 or greater
CMP lgBPC, #1 ;Pick up this entry:
LDRLSB cword0, [charptr, #0] ; 1 byte if lgBPC = 0
LDREQB R14, [charptr, #1] ; 2 bytes if lgBPC = 1
ORREQ cword0, cword0, R14, LSL #8
MOV cword1, #0
BLS Vdu5DoOneWord
CMP lgBPC, #3
LDRLO cword0, [charptr, #0] ; 1 word if lgBPC = 2
BLO Vdu5DoOneWord
BHI Vdu5Mode10 ; 4 words if lgBPC = 4
LDMIA charptr, {cword0, cword1} ; 2 words if lgBPC = 3
MOVS cword2, cword1, LSR invcharshf
MACRO
$l DoVdu5Word $c, $reg, $off
$l
LDR$c chartmp, [scr, #$off]
AND$c R14, ormask, $reg
ORR$c chartmp, chartmp, R14
AND$c R14, eormask, $reg
EOR$c chartmp, chartmp, R14
STR$c chartmp, [scr, #$off]
MEND
Vdu5DoTwoWords
DoVdu5Word NE, cword2, 8
MOV cword1, cword1, LSL charshf
Vdu5DoOneWord
ORRS cword1, cword1, cword0, LSR invcharshf
DoVdu5Word NE, cword1, 4
MOVS cword0, cword0, LSL charshf
DoVdu5Word NE, cword0, 0
Vdu5LinePainted
Pull "ecfptr,scrend,charmsk,llength,charptr"
Vdu5TryNextLine
TEQ scr, scrend
ADDNE scr, scr, llength
BNE Vdu5NextLine
Pull "PC"
; This is mode 10 (or similar) - we must do bit expansion on the fly
Vdu5Mode10
CMP lgBPC, #5 ; is this a 32 bit per pixel mode, if so then ignore the
BEQ Vdu5Mode32 ; existing code and use a newer function
ADRL charptr, C16BTab
AND R14, charbyte, #&0F
ADD R14, charptr, R14, LSL #3
LDMIA R14, {cword0, cword1}
MOVS cword2, cword1, LSR invcharshf
DoVdu5Word NE, cword2, 16
MOV cword1, cword1, LSL charshf
ORRS cword1, cword1, cword0, LSR invcharshf
DoVdu5Word NE, cword1, 12
MOVS cword2, cword0, LSL charshf
AND R14, charbyte, #&F0
ADD R14, charptr, R14, LSR #1
LDMIA R14, {cword0, cword1}
ORRS cword2, cword2, cword1, LSR invcharshf
B Vdu5DoTwoWords
; Expand the character data out to 32 bit per pixel (mode 48 or similar)
MACRO
$l PixMunge32 $reg, $mask, $offset
$l
TST $reg, #$mask
LDRNE chartmp, [scr, #$offset]
ORRNE chartmp, chartmp, ormask
EORNE chartmp, chartmp, eormask
STRNE chartmp, [scr, #$offset]
MEND
MACRO
$l PixSolid32 $reg, $mask, $offset
$l
TST $reg, #$mask
STRNE chartmp, [scr, #$offset]
MEND
; Perform bit expansion on the fly, this is a word based operation, no need to
; extract sub-pixels from the ORR / EOR masks, simply perform the bit test and
; then write the character data to the screen!
Vdu5Mode32
[ AvoidScreenReads
CMP ormask, #&FFFFFFFF
BNE Vdu5Mode32_NotSolid
MVN chartmp, eormask
PixSolid32 charbyte, 1<<7, 0
PixSolid32 charbyte, 1<<6, 4
PixSolid32 charbyte, 1<<5, 8
PixSolid32 charbyte, 1<<4, 12
PixSolid32 charbyte, 1<<3, 16
PixSolid32 charbyte, 1<<2, 20
PixSolid32 charbyte, 1<<1, 24
PixSolid32 charbyte, 1<<0, 28
B Vdu5LinePainted
Vdu5Mode32_NotSolid
]
PixMunge32 charbyte, 1<<7, 0
PixMunge32 charbyte, 1<<6, 4
PixMunge32 charbyte, 1<<5, 8
PixMunge32 charbyte, 1<<4, 12
PixMunge32 charbyte, 1<<3, 16
PixMunge32 charbyte, 1<<2, 20
PixMunge32 charbyte, 1<<1, 24
PixMunge32 charbyte, 1<<0, 28
B Vdu5LinePainted ; flow down and try the next line
; *****************************************************************************
;
; Slow VDU 5 - Print char by scaled method (in SprExtend)
;
; in: R1 (ecfptr) = pointer to ecf pattern
; R7 (sizex) = SizeX
; R8 (sizey) = SizeY
; R9 (charbyte) = character to plot
;
; Stack: Return address
;
ASSERT ecfptr = R1
ASSERT sizex = R7
ASSERT sizey = R8
ASSERT charbyte = R9
SlowVdu5 ROUT
MOV R10, R1 ; R10 := ecfptr
; now save current GCOL on stack if necessary
ADD R11, WsPtr, #FgEcfOraEor
TEQ R10, R11 ; if going to use this one
BEQ %FT20 ; then skip
MOV R0, #64 ; 64 bytes
10
LDMIA R11, {R3-R6} ; copy old GCOL into stack
Push "R3-R6" ; frame, reversing order of
; 16 byte chunks
LDMIA R10!, {R3-R6} ; copy new colour
STMIA R11!, {R3-R6} ; into GCOL
SUBS R0, R0, #16
BNE %BT10
20
MOV R4, #8
MOV R5, #8
Push "R4,R5"
Push "R7,R8"
MOV R6, R13 ; R6 -> scaling block
SUB R1, R8, #1 ; SizeY-1
LDR R5, [WsPtr, #YEigFactor]
ADD R3, WsPtr, #GCsX
LDMIA R3, {R3, R4} ; R3 = ext X; R4 = ext Y (top)
SUB R4, R4, R1, LSL R5 ; R4 = ext Y (bottom)
MOV R1, R9 ; R1 = char
MOV R0, #SpriteReason_PaintCharScaled
SWI XOS_SpriteOp
ADD R13, R13, #4*4 ; junk scaling block
TEQ R10, R11 ; if we didn't copy GCOLs
Pull "PC", EQ ; then return, else copy back
MOV R0, #64
30
Pull "R3-R6" ; Reverse order of 16 byte
STMDB R11!, {R3-R6} ; chunks during copy again
SUBS R0, R0, #16
BNE %BT30
Pull PC
; *****************************************************************************
;
; VDU 5 - Start printing text at graphics cursor
ENQ
GraphicsMode R0
MOVNE PC, R14
MOV R1, #0
BSR CursorOnOff ; turn cursor off without
; saving to copy
LDR R6, [WsPtr, #CursorFlags]
ORR R6, R6, #Vdu5Bit
B R6toCursorFlags
; *****************************************************************************
;
; VDU 4 - Return to printing text at text cursor
EOT
GraphicsMode R0
MOVNE PC,LR
MOV R1, #1
BSR CursorOnOff ; restore cursor from copy
LDR R6, [WsPtr, #CursorFlags]
BIC R6, R6, #Vdu5Bit
B R6toCursorFlags
; *****************************************************************************
;
; Vdu5HT - Move cursor "right" when in VDU 5 mode
;
; in: R6 = CursorFlags
Vdu5HT
Push R14
BL GCursorMove ; try to move in +ve X direction
BCC EndVdu5HT ; if successful, finish
BL GCursorB0 ; else move cursor to -ve X boundary
Vdu5HT10
EOR R6, R6, #8 ; change to +ve Y direction
BL GCursorMove ; try to move in that direction
BLCS GCursorB0 ; if unsuccessful, move to -ve Y bdy
EndVdu5HT
Pull R14
B IEG
; *****************************************************************************
;
; Vdu5BS - Move cursor "left" when in VDU 5 mode
;
; in: R6 = CursorFlags
Vdu5BS
EOR R6, R6, #6 ; go to -ve X direction
B Vdu5HT ; dead easy, huh ?
; *****************************************************************************
;
; Vdu5LF - Move cursor "down" when in VDU 5 mode
;
; in: R6 = CursorFlags
Vdu5LF
Push R14
B Vdu5HT10
; *****************************************************************************
;
; Vdu5VT - Move cursor "up" when in VDU 5 mode
;
; in: R6 = CursorFlags
Vdu5VT
EOR R6, R6, #6 ; go to -ve Y direction (eventually)
B Vdu5LF
; *****************************************************************************
;
; Vdu5CR - Carriage return in VDU 5 mode
;
; in: R6 = CursorFlags
Vdu5CR
BSR GCursorB0
B IEG
; *****************************************************************************
;
; Vdu5FF - Clear screen in VDU 5 mode
;
; in: R6 = CursorFlags
Vdu5FF
BSR Home
B CLG
; *****************************************************************************
;
; Vdu5TAB - TAB(X,Y) in VDU 5 mode
;
; in: R0 = X, R1 = Y, R6 = CursorFlags
Vdu5TAB
BSR GCursorBdy
EOR R6, R6, #8
MOV R0, R1
BSR GCursorBdy
B IEG
; *****************************************************************************
;
; Vdu5Delete - Delete in VDU 5 mode (already done backspace)
;
; in: R6 = CursorFlags
Vdu5Delete
ADD ecfptr, WsPtr, #BgEcfStore ; STORE background colour/ecf
MOV R0, #127 ; uses hard font for this char
B Vdu5DoChar10
; *****************************************************************************
;
; GCursorMove - Move graphics cursor in direction specified by R6
; (0,4 = right; 2,6 = left; 8,10 = down; 12,14 = up)
; R6 is preserved
GCursorMove
ADD R0, WsPtr, #GCsIX
LDMIA R0, {R0, R1} ; R0 = GCsIX; R1 = GCsIY
ADD R2, WsPtr, #GCharSpacing+8 ; +8 needed to address it
LDMDB R2, {R2, R3} ; R2=GCharSpaceX;R3=GCharSpaceY
WINDow R0, R1, R8,R9,R10,R11 ; return LT if outside window
ADR R7, GCMVTab
B DoJumpTable
GCMVTab
& GMoveRight-GCMVTab
& GMoveLeft-GCMVTab
& GMoveRight-GCMVTab
& GMoveLeft-GCMVTab
& GMoveDown-GCMVTab
& GMoveDown-GCMVTab
& GMoveUp-GCMVTab
& GMoveUp-GCMVTab
; Move graphics cursor right if possible - on exit C=0 iff OK to move
GMoveRight
ADD R0, R0, R2 ; add on GCharSpaceX
GMove10
STR R0, [WsPtr, #GCsIX]
GMove15
BLT GMoveOK ; if we were outside already
TST R6, #&40 ; or we are in nowrap mode
BNE GMoveOK ; then we were OK to move
WINDow R0, R1, R8,R9,R10,R11
BGE GMoveOK ; if inside now, then OK
SEC
MOV PC, R14
GMoveOK
CLC
MOV PC, R14
; Move graphics cursor left if possible - on exit C=0 iff OK to move
GMoveLeft
SUB R0, R0, R2 ; subtract off GCharSpaceX
B GMove10
; Move graphics cursor down if possible - on exit C=0 iff OK to move
GMoveDown
SUB R1, R1, R3 ; subtract off GCharSpaceY
GMove20
STR R1, [WsPtr, #GCsIY]
B GMove15
; Move graphics cursor up if possible - on exit C=0 iff OK to move
GMoveUp
ADD R1, R1, R3 ; add on GCharSpaceY
B GMove20
; *****************************************************************************
;
; Move graphics cursor to boundary indicated by value of R6 in bits 1-3
; (0 or 4 = left, 2 or 6 = right, 8 or 10 = up, 12 or 14 = down)
; + R0 character positions in
;
GCursorB0
MOV R0, #0
GCursorBdy
ADR R7, GCBDYTab
B DoJumpTable
GCBDYTab
& GCursorLBdy-GCBDYTab
& GCursorRBdy-GCBDYTab
& GCursorLBdy-GCBDYTab
& GCursorRBdy-GCBDYTab
& GCursorUBdy-GCBDYTab
& GCursorUBdy-GCBDYTab
& GCursorDBdy-GCBDYTab
& GCursorDBdy-GCBDYTab
; Move graphics cursor to left boundary + R0 characters in
GCursorLBdy
LDR R7, [WsPtr, #GWLCol]
LDR R2, [WsPtr, #GCharSpaceX]
MLA R0, R2, R0, R7 ; GCsIX := GWLCol + (X*SpaceX)
STR R0, [WsPtr, #GCsIX]
MOV PC, R14
; Move graphics cursor to right boundary + R0 characters in
; (adjust for character size)
GCursorRBdy
LDR R7, [WsPtr, #GWRCol]
LDR R2, [WsPtr, #GCharSizeX]
SUB R7, R2, R7 ; R7 = SizeX-GWRCol
LDR R2, [WsPtr, #GCharSpaceX]
MLA R0, R2, R0, R7 ; R0 = SizeX-GWRCol+X*SpaceX
RSB R0, R0, #1 ; GWRCol-X*SpaceX-(SizeX-1)
STR R0, [WsPtr, #GCsIX]
MOV PC, R14
; Move graphics cursor to up boundary + R0 characters in
GCursorUBdy
LDR R7, [WsPtr, #GWTRow]
LDR R2, [WsPtr, #GCharSpaceY]
RSB R2, R2, #0 ; -SizeY
MLA R0, R2, R0, R7 ; GWTRow-Y*SizeY
STR R0, [WsPtr, #GCsIY]
MOV PC, R14
; Move graphics cursor to down boundary + R0 characters in
; (adjust for character size)
GCursorDBdy
LDR R7, [WsPtr, #GWBRow]
LDR R2, [WsPtr, #GCharSpaceY]
MLA R0, R2, R0, R7 ; GWBRow+Y*SpaceY
LDR R2, [WsPtr, #GCharSizeY]
ADD R0, R0, R2
SUB R0, R0, #1 ; GWBRow+Y*SpaceY+(SizeY-1)
STR R0, [WsPtr, #GCsIY]
MOV PC, R14
; *****************************************************************************
;
; ClipVdu5 - Add a VDU 5 char to clip box
;
; in: cxl2 = left
; cyb2 = top-bottom
; cxr2 = right
; cyt2 = top
;
; out: All registers preserved
;
ASSERT (cxl2=R4) :LAND: (cyb2=R3) :LAND: (cxr2=R10) :LAND: (cyt2=R2)
ClipVdu5 ROUT
Push "R0-R3, R4, R10, R14"
MOV R0, cxl2
SUB R1, cyt2, cyb2 ; top-(top-bottom) = bottom
MOV R3, cyt2
MOV R2, cxr2
BL MergeClipBox
Pull "R0-R3, R4, R10, PC"
END