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
; 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.VduGrafL
;
; ARTHUR OPERATING SYSTEM - Vdu Drivers
; =======================
;
; Vdu driver code - Sprite stuff
;
; Author T M Dobson
; Date 22-Sep-87
;
; *****************************************************************************
;
; ReadSaveAreaSize - Read size of a VDU context save area
;
; in: R0 = SpriteReason_ReadSaveAreaSize
; R1 -> sprite area
; R2 -> sprite (0 => screen (possibly))
;
; out: R3 = size of an area suitable for this sprite
;
ReadSaveAreaSize ROUT
MOV R3, #MainSize ; I was kidding about it depending
STR R3, [WsPtr, #RetnReg3] ; on the sprite!
MOV PC, R14
; *****************************************************************************
;
; SwitchOutputToSprite - Make VDU(graphics) output go to a sprite
;
; External routine
;
; in: R0 = SpriteReason_SwitchOutputTo <Sprite or Mask>
; R1 -> sprite area
; R2 -> sprite (0 => screen)
; R3 -> save area for VDU variables relating to sprite
; 0 => no save area, initialise variables from mode number of sprite
; or display mode number
; 1 => use MOS's save area
;
; First word of save area = 0 => uninitialised save area
; "VOTS" => initialised save area
; else error
;
; From Medusa onwards, things are further complicated here by the fact that
; the sprite may have a new sprite mode word rather than a mode number. When
; the former case occurs calling pushmodeinfoanymonitor doesn't really help
; very much. Instead, when a sprite mode word is given, it will derive or
; fudge all the variables that it is really interested from the sprite mode
; word directly.
SwitchOutputToSprite ROUT
SwitchOutputToMask ROUT
CMP R3, #1 ; check for values 0 and 1
MOVCC R4, #0 ; R3=0 => no save area, so not inited
ADDEQ R5, WsPtr, #VduSaveArea ; R3=1 => MOS's area
MOVHI R5, R3 ; else user area
LDRCS R4, [R5, #InitFlag] ; if is an area, load R4 with init flag
LDR R5, VOTS ; compare with initialised identifier
TEQ R4, R5 ; if not initialised
TEQNE R4, #0 ; and not uninitialised
BNE InvalidSaveArea
; no more errors can be generated, so update returned registers
ADD R5, WsPtr, #VduOutputCurrentState
LDMIA R5, {R6-R9}
ADD R5, WsPtr, #RetnReg0
STMIA R5, {R6-R9}
Push "R0-R4,R14"
ASSERT SpriteMaskSelect = VduOutputCurrentState +0
ASSERT VduSpriteArea = VduOutputCurrentState + 4
ASSERT VduSprite = VduOutputCurrentState + 8
ORR R0, R0, #RangeC ; make R0 into &2nn
ADD R5, WsPtr, #VduOutputCurrentState
STMIA R5, {R0-R2}
BL PreWrchCursor ; remove cursor
BL PackVars ; save away current vars into save area
; (if any)
Pull "R0-R4"
STR R3, [WsPtr, #VduSaveAreaPtr] ; save new save area ptr
TEQ R2, #0 ; if switching to screen
LDREQ R9, [WsPtr, #DisplayScreenStart] ; then load up new ScreenStart
LDREQ R11, [WsPtr, #DisplayModeNo] ; and mode number
BEQ %FT20 ; and skip sprite stuff
; do stuff for switching to sprite
Push R0
BL RemoveLeftHandWastage ; then remove LH wastage from sprite
Pull R0 ; (spLBit := 0)
ASSERT spHeight = spWidth +4
ASSERT spLBit = spWidth +8
ASSERT spRBit = spWidth +12
ASSERT spImage = spWidth +16
ASSERT spTrans = spWidth +20
ASSERT spMode = spWidth +24
ADD R5, R2, #spWidth ; R5=width:R6=height:R7=LBit(=0)
LDMIA R5, {R5-R11} ; R8=RBit:R9=Image:R10=Trans:R11=Mode
TEQ R0, #SpriteReason_SwitchOutputToMask
BNE %FT23
MOV R9, R10 ; point at mask instead of image
MOVS R0, R11, LSR #27
BEQ %FT23 ; check for old format masks
BL GetMaskspWidth ; adjust R5 and R8 to mask dimensions
AND R10, R11, #15<<27
TEQ R10, #SpriteType_RISCOS5<<27
BEQ %FT21
TST R11, #&80000000
BIC R11, R11, #&F8000000 ; wipe existing sprite type
ORREQ R11, R11, #SpriteType_New1bpp<<27 ; force to 1bpp
ORRNE R11, R11, #SpriteType_New8bpp<<27 ; force to 8bpp
B %FT23
21
TST R11, #&80000000
AND R11, R11, #&F0 ; preserve DPI fields, modeflags + original type must go
ORR R11, R11, #1+(SpriteType_RISCOS5<<27) ; mark as RO5 format
ORREQ R11, R11, #SpriteType_New1bpp<<20 ; force to 1bpp
ORRNE R11, R11, #SpriteType_New8bpp<<20 ; force to 8bpp
23
ADD R9, R9, R2 ; R9 -> sprite data or mask
20
MOV R10, R11
BL PushModeInfoAnyMonitor
STRVS R0, [WsPtr, #RetnReg0]
Pull "PC", VS
STR R9, [WsPtr, #ScreenStart]
STR R11, [WsPtr, #ModeNo] ; new mode number
MOV R11, R13
; If we're switching output to screen, either find our values from the
; pushed mode info or from the saved DisplayXXX values.
; DisplayXXX is needed for any values which might differ from one
; display driver to another, but care is needed because ModeChangeSub
; actually calls us during the mode change to set up some of the
; variables (so need to make sure that any DisplayXXX values are set
; before we get called).
; Also note that we can't replace the above PushModeInfoAnyMonitor call
; with PushModeInfo (to get accurate values for the current display
; driver) because ScreenModes might not be running with the same MDF
; as when the original call was made.
TEQ R2, #0
LDREQ R5, [R12, #DisplayLineLength]
LDREQ R6, [R11, #wkYWindLimit]
LDREQ R7, [R11, #wkXWindLimit]
LDREQ R8, [R11, #wkScrRCol]
LDREQ R10, [R11, #wkScrBRow]
BEQ %FT30
; OK, we're switching to a sprite, so calculate the above values from
; the sprite header
ADD R5, R5, #1
MOV R5, R5, LSL #2 ; R5 = width in bytes
ADD R7, R8, R5, LSL #3 ; R7 = LineLength*8 + spRBit
SUB R7, R7, #31 ; R7=active area width in bits
LDR R8, [R11, #wkLog2BPC]
MOV R7, R7, LSR R8 ; R7 = width in pixels
MOV R8, R7, LSR #3 ; R8 = width in text columns
SUB R7, R7, #1 ; R7 = max value of GWRCol
SUB R8, R8, #1 ; R8 = max column number
ADD R10, R6, #1 ; R10 = no. of pixel rows
MOV R10, R10, LSR #3 ; R10 = number of char rows
SUB R10, R10, #1 ; R4 = maximum row number
30
STR R5, [WsPtr, #LineLength]
STR R6, [WsPtr, #YWindLimit]
STR R7, [WsPtr, #XWindLimit]
STR R8, [WsPtr, #ScrRCol]
STR R10, [WsPtr, #ScrBRow]
LDR R0,[R11, #wkNColour]
STR R0,[WsPtr, #NColour] ; copy number of colours -1
ADD R11, R11, #wkmiddle
MOV R0, #wkmidend-wkmiddle ; number of bytes to do
ADD R1, WsPtr, #YShftFactor ; first mode variable that we do
40
LDR R5, [R11], #4 ; copy byte from mode table
STR R5, [R1], #4 ; into word variable
SUBS R0, R0, #4 ; decrement count
BNE %BT40 ; loop until finished
ADD R13, R13, #PushedInfoSize ; junked stacked info
; now create other variables from simple ones
LDR R0, [WsPtr, #Log2BPP]
LDR R1, [WsPtr, #Log2BPC]
LDR R5, [WsPtr, #XEigFactor]
LDR R6, [WsPtr, #ModeFlags]
TEQ R2, #0
ORRNE R6, R6, #ModeFlag_HardScrollDisabled ; if sprite then disable hard scroll
STR R6, [WsPtr, #ModeFlags]
;if switching to a sprite, check for full palette 8bpp, and set modeflags and
;NColour to suit.
TEQ R2, #0
BEQ %FT65 ; switching to a sprite ?
ADD R7, R2, #spImage ; point R7 at the image/mask start pair
LDMIA R7, {R7, LR} ; fetch them
CMP R7, LR ; which is lower
MOVGT R7, LR ; use the lowest
SUB R7, R7, #spPalette ; get the size of the palette
CMP R0, #3
BNE %FT51 ; which is 8bpp ?
CMP R7, #&800 ; full 8bpp palette ?
BNE %FT51
ORR R6, R6, #ModeFlag_FullPalette
STR R6, [WsPtr, #ModeFlags] ; set the full palette flag
MOV LR, #255
STR LR, [WsPtr, #NColour] ; and set the number of colours
51
LDRB LR, [WsPtr, #SpriteMaskSelect]
TEQ LR, #SpriteReason_SwitchOutputToSprite
BEQ %FT52
LDR LR, [R2, #spMode]
TST LR, #&80000000
ORRNE R6, R6, #ModeFlag_GreyscalePalette+ModeFlag_FullPalette ; alpha masks are 256 greyscale
STRNE R6, [WsPtr, #ModeFlags]
MOVNE LR, #255
STRNE LR, [WsPtr, #NColour]
B %FT65
52
; Redirecting to sprite image, check for greyscale palette
CMP R0, #3
BHI %FT65
TSTEQ R6, #ModeFlag_FullPalette ; 63 colour can't be greyscale
TEQNE R7, #0 ; If no palette then (probably) also not greyscale
BEQ %FT65
ADD R8, R2, #spPalette
53
LDR LR, [R8], #4
EOR LR, LR, LR, LSL #8
CMP LR, #&10000
BHS %FT65
SUBS R7, R7, #4
BGT %BT53
ORR R6, R6, #ModeFlag_GreyscalePalette
STR R6, [WsPtr, #ModeFlags]
65
TST R6, #ModeFlag_DoubleVertical
ADREQL R7, WrchNbitTab ; point to correct table
ADRNEL R7, WrchNbitDoubleTab
LDR R8, [R7, R1, LSL #2] ; get offset to correct code
ADD R8, R8, R7 ; convert to absolute address
STR R8, [WsPtr, #WrchNbit]
ADRL R7, CursorNbitTab
LDR R8, [R7, R1, LSL #2]
ADD R8, R8, R7
TST R6, #ModeFlag_Teletext
ADRNEL R8, CursorTeletext
STR R8, [WsPtr, #CursorNbit]
TST R6, #ModeFlag_NonGraphic
MOVEQ R7, #32 ; if graphic mode
MOVEQ R7, R7, LSR R1 ; then = (32 >> lbpc)-1
SUBEQ R7, R7, #1
MOVNE R7, #0 ; else = 0 ;;; NOT REALLY SAFE BET ANYMORE!!!
STR R7, [WsPtr, #NPix]
RSB R7, R1, #5 ; XShftFactor = 5-log2bpc
STR R7, [WsPtr, #XShftFactor]
LDR R7, [WsPtr, #YEigFactor]
SUBS R7, R5, R7 ; XEigFactor-YEigFactor
MOVLT R7, #2 ; X<Y => 2 (vert rect)
MOVGT R7, #1 ; X>Y => 1 (horz rect)
; else X=Y => 0 (square)
STR R7, [WsPtr, #AspectRatio]
MOV R8, #1
MOV R7, R8, LSL R0 ; bpp = 1 << lbpp
STR R7, [WsPtr, #BitsPerPix]
MOV R7, R8, LSL R1 ; bpc = 1 << lbpc
STR R7, [WsPtr, #BytesPerChar]
[ HiResTTX
TST R6, #ModeFlag_Teletext ; in teletext mode
MOVNE R7, R7, LSL #1 ; characters are 16 pixels, not 8
]
STR R7, [WsPtr, #CharWidth]
TST R6, #ModeFlag_BBCGapMode ; is it a BBC gap mode ?
MOVNE R7, #&55 ; yes, then use colour 1
BNE %FT70
TEQ R0, #2 ; if (1<<2=4) bits per pixel
MOVEQ R7, #&77 ; then use colour 7 for cursor
MOVNE R7, #&FF ; else use colour 15
[ HiResTTX
TST R6, #ModeFlag_Teletext ; unless it's 256 colour teletext
BEQ %FT70
TEQ R0, #3
MOVEQ R7, #&07 ; in which case still use colour 7
]
70
ORR R7, R7, R7, LSL #8 ; fill out to whole word
ORR R7, R7, R7, LSL #16
STR R7, [WsPtr, #CursorFill]
TST R6, #ModeFlag_DoubleVertical
MOVEQ R7, #8 ; if single vertical then 8 pixels
MOVNE R7, #16 ; if double vertical then 16 pixels
STR R7, [WsPtr, #TCharSizeY]
TST R6, #ModeFlag_GapMode
ADDNE R7, R7, R7, LSR #2 ; make 10 or 20 if gap mode
STR R7, [WsPtr, #RowMult]
STR R7, [WsPtr, #TCharSpaceY]
MOV R8, #8
[ HiResTTX
TST R6, #ModeFlag_Teletext
MOVNE R8, #16
]
STR R8, [WsPtr, #TCharSizeX]
STR R8, [WsPtr, #TCharSpaceX]
LDR R8, [WsPtr, #LineLength]
MUL R7, R8, R7
STR R7, [WsPtr, #RowLength]
ANDS R14, R6, #ModeFlag_Teletext
BEQ %FT71
; Calculate TextOffset necessary to center the text window
; First, Y offset
LDR R7, [WsPtr, #RowMult]
LDR R14, [WsPtr, #ScrBRow]
ADD R14, R14, #1
MUL R14, R7, R14 ; text window height, pixels
LDR R7, [WsPtr, #YWindLimit]
ADD R7, R7, #1
SUB R14, R7, R14 ; spare rows on screen
MOV R14, R14, LSR #1
MUL R14, R8, R14 ; byte offset to start at correct row
; Now, X offset
LDR R7, [WsPtr, #TCharSpaceX]
LDR R8, [WsPtr, #ScrRCol]
ADD R8, R8, #1
MUL R8, R7, R8 ; text window width, pixels
LDR R7, [WsPtr, #XWindLimit]
ADD R7, R7, #1
SUB R8, R7, R8 ; spare columns on screen
MOV R8, R8, LSR #1
LDR R7, [WsPtr, #Log2BPP]
MOV R8, R8, LSL R7 ; spare bits on row
ADD R14, R14, R8, LSR #3 ; combine with vertical offset
BIC R14, R14, #3 ; TTX assumes word alignment
71
STR R14, [WsPtr, #TextOffset]
; finished doing other variables
SWI XColourTrans_InvalidateCache ; let ColourTrans know we've changed mode
; so that colours get set up correctly
TEQ R4, #0 ; initialising from a save area ?
BEQ %FT80 ; no, then set to defaults
BL UnpackVars
BL AddressCursors
BL ValidateVars
BL PlainBit
BL SetColour
LDR R6, [WsPtr, #CursorFlags]
ORR R6, R6, #TEUpdate ; TextExpand needs updating
STR R6, [WsPtr, #CursorFlags]
B %FT90
80
; *****Change made by DJS
; Original code was:
; MOV R0, #0
; STR R0, [WsPtr, #ECFShift]
; STR R0, [WsPtr, #ECFYOffset]
; This needed to be changed to make the bottom left of the screen (rather
; than the top left) be the default ECF origin.
LDR R0, [WsPtr, #YWindLimit]
ADD R0, R0, #1
AND R0, R0, #7
STR R0, [WsPtr, #ECFYOffset]
MOV R0, #0
STR R0, [WsPtr, #ECFShift]
; *****End of change made by DJS
STR R0, [WsPtr, #ClipBoxEnable]
[ ZeroPage <> 0
LDR R0, =ZeroPage
ASSERT (ZeroPage :AND: 255) = 0
]
STRB R0, [R0, #OsbyteVars + :INDEX: VDUqueueItems]
MOV R0, #8
STR R0, [WsPtr, #GCharSizeX] ; chars are 8x8 by default
STR R0, [WsPtr, #GCharSizeY]
STR R0, [WsPtr, #GCharSpaceX] ; and with 8x8 spacing
STR R0, [WsPtr, #GCharSpaceY]
LDR R1, [WsPtr, #ModeFlags]
LDR R0, [WsPtr, #CursorFlags]
BIC R0, R0, #(ActualState :OR: Vdu5Bit)
BIC R0, R0, #(CursorsSplit :OR: PageMode :OR: TeletextMode :OR: ClipBoxEnableBit)
TST R1, #ModeFlag_Teletext ; is it teletext ?
ORRNE R0, R0, #TeletextMode ; yes, then set bit
STR R0, [WsPtr, #CursorFlags]
ADRNE LR, %FT85
BNE TeletextInit ; (re-)initialise TTX if appropriate
; Not teletext mode. If we're switching output to screen, then we might
; be in the middle of a mode change from TTX to regular, so free any
; old TTX workspace.
LDR R2, [WsPtr, #VduSprite]
TEQ R2, #0
BLEQ TeletextFinalise
85
BL InitCursor ; initialise cursor after
; cursorflags
BL PlainBit ; also sets up RAMMaskTb
BL DefaultColours ; N.B. SetColour is called by both
BL DefaultEcfPattern ; of these.
BL DefaultLineStyle
BL DefaultWindows
BL Home
90
; If we've just switched back to the screen, make sure the greyscale palette flag is accurate. Easiest way is to copy DisplayModeFlags into ModeFlags.
LDR R2, [WsPtr, #VduSprite]
TEQ R2, #0
LDREQ R2, [WsPtr, #DisplayModeFlags]
STREQ R2, [WsPtr, #ModeFlags]
BL PostWrchCursor
MOV R1, #Service_SwitchingOutputToSprite ; call Ran's service
ADD R2, WsPtr, #VduOutputCurrentState
LDMIA R2, {R2-R5} ; load the registers that were in R0-R3 on entry
IssueService
Pull R14
RETURNVC
InvalidSaveArea
ADRL R0, SpriteErr_InvalidSaveArea
[ International
Push "lr"
BL TranslateError
Pull "lr"
]
STR R0, [WsPtr, #RetnReg0]
RETURNVS
VOTS = "VOTS"
; *****************************************************************************
; Specially saved items
^ 0
InitFlag # 4 ; 0 => uninit, "VOTS" => init
SavedSpoolFileH # 1 ; an OSBYTE variable
SavedWrchDest # 1 ; --------""--------
SavedVDUqueueItems # 1 ; --------""--------
# 1 ; padding to word align it
SavedDataOffset # 0 ; start of compressed data
GBLA FirstOffset
GBLA NextOffset
GBLA CompressedSize
MACRO
CompStart
FirstOffset SETA -1
NextOffset SETA -1
CompressedSize SETA 0
MEND
MACRO
Compress $v0, $v1, $v2, $v3, $v4, $v5, $v6, $v7
[ "$v0"<>""
Compo $v0
]
[ "$v1"<>""
Compo $v1
]
[ "$v2"<>""
Compo $v2
]
[ "$v3"<>""
Compo $v3
]
[ "$v4"<>""
Compo $v4
]
[ "$v5"<>""
Compo $v5
]
[ "$v6"<>""
Compo $v6
]
[ "$v7"<>""
Compo $v7
]
MEND
MACRO
Compo $var
[ FirstOffset <> -1
[ $var = NextOffset
NextOffset SETA ($var)+4
|
DCW FirstOffset
DCW NextOffset
CompressedSize SETA CompressedSize + (NextOffset-FirstOffset)
FirstOffset SETA $var
NextOffset SETA ($var)+4
]
|
FirstOffset SETA $var
NextOffset SETA ($var)+4
]
MEND
MACRO
CompMult $start, $size
[ FirstOffset <> -1
[ $start = NextOffset
NextOffset SETA $start + $size
|
DCW FirstOffset
DCW NextOffset
CompressedSize SETA CompressedSize + (NextOffset-FirstOffset)
FirstOffset SETA $start
NextOffset SETA $start + $size
]
|
FirstOffset SETA $start
NextOffset SETA $start + $size
]
MEND
MACRO
CompRange $start, $end
CompMult $start, ($end+4-$start)
MEND
MACRO
CompEnd
[ FirstOffset <> -1
DCW FirstOffset
DCW NextOffset
CompressedSize SETA CompressedSize + (NextOffset-FirstOffset)
]
& -1
MEND
CompressionTable
CompStart
; CompMult FgEcf, 8*4 ; recreated from GCOLs + ecfs by
; CompMult BgEcf, 8*4 ; call to SetColour
Compress GPLFMD, GPLBMD, GFCOL, GBCOL, GWLCol, GWBRow, GWRCol, GWTRow
CompRange qqqPad, JVec
; Compress ScreenStart ; worked out from sprite address each time
Compress TWLCol, TWBRow, TWRCol, TWTRow
CompRange OrgX, NewPtY
Compress TForeCol, TBackCol, CursorX, CursorY
; Compress CursorAddr, InputCursorAddr - computed from (Input)CursorX,Y
Compress InputCursorX, InputCursorY
Compress VduStatus
Compress CursorDesiredState, CursorStartOffset, CursorEndOffset
Compress CursorCounter, CursorSpeed, Reg10Copy
; Compress CursorFill, CursorNbit - computed from mode variables
; Compress DriverBankAddr - refers to screen always
CompRange Ecf1, Ecf4+4
CompMult DotLineStyle, 8
; Compress ModeNo - stored in sprite itself
Compress TFTint, TBTint, GFTint, GBTint
; Compress TotalScreenSize, MaxMode, ScreenEndAddr - refer to screen always
Compress CursorFlags, CursorStack
Compress ECFShift, ECFYOffset
Compress GCharSizeX, GCharSizeY, GCharSpaceX, GCharSpaceY
; Compress TCharSizeX, TCharSizeY ; recomputed from mode number
; Compress TCharSpaceX, TCharSpaceY ; each time
; CompMult FgEcfOraEor, 64 ; recreated from GCOLs and ecfs
; CompMult BgEcfOraEor, 64 ; by call to SetColour
; CompMult BgEcfStore, 64 ;
Compress LineDotCnt, LineDotPatLSW, LineDotPatMSW, DotLineLength
Compress BBCcompatibleECFs
; Compress WrchNbit - computed from mode number
CompRange ClipBoxEnable, ClipBoxTRow
CompMult FgPattern, 4*8
CompMult BgPattern, 4*8
Compress TextFgColour
Compress TextBgColour
CompEnd
CompressionTableEnd
MainSize * CompressedSize + SavedDataOffset
; N.B. teletext state is not saved
ASSERT MainSize <= SaveAreaSize
! 0, "Space free in VDU save area = ":CC::STR:(SaveAreaSize-MainSize)
; *****************************************************************************
;
; PackVars - Pack variables into save area
;
PackVars ROUT
CLC ; clear carry - indicate packing
PackOrUnpack
Push "R0-R4,R14"
LDR R0, [WsPtr, #VduSaveAreaPtr]
TEQ R0, #0
Pull "R0-R4,PC", EQ ; ptr=0 => no area
TEQ R0, #1
ADDEQ R0, WsPtr, #VduSaveArea ; ptr=1 => use MOS's save area
BL DoSpecialVars ; process special vars
ADD R0, R0, #SavedDataOffset ; move on to compressed data
ADR R1, CompressionTable
10
LDR R2, [R1], #4
MVNS R3, R2 ; set Z if it was -1 (end of table)
Pull "R0-R4,PC", EQ ; (preserves C)
ADD R3, WsPtr, R2, LSR #16 ; R3 = end pointer
MOV R2, R2, LSL #16
ADD R2, WsPtr, R2, LSR #16 ; R2 = start pointer
20
LDRCC R4, [R2], #4 ; load a word from vars
LDRCS R4, [R0], #4 ; or from save area
STRCC R4, [R0], #4 ; store into save area
STRCS R4, [R2], #4 ; or into vars
TEQ R2, R3 ; end of this block ?
BNE %BT20 ; [no, so loop]
B %BT10 ; go back for another block
; *****************************************************************************
;
; UnpackVars - Unpack variables from save area
;
UnpackVars ROUT
SEC ; set carry - indicate unpacking
B PackOrUnpack
; *****************************************************************************
;
; DoSpecialVars - Pack/unpack special vars: CursorAddr, InputCursorAddr,
; (stored relative to ScreenStart); SpoolFileH, WrchDest, VDUqueueItems
;
; in: R0 -> save area
;
; out: R0 preserved
; R1-R2 corrupted
; Flags preserved
;
DoSpecialVars ROUT
BYTEWS R1
BCS %FT10
LDRB R2, [R1, #:INDEX: SpoolFileH]
STRB R2, [R0, #SavedSpoolFileH]
LDRB R2, [R1, #:INDEX: WrchDest]
STRB R2, [R0, #SavedWrchDest]
LDRB R2, [R1, #:INDEX: VDUqueueItems]
STRB R2, [R0, #SavedVDUqueueItems]
LDR R1, VOTS ; initialised save area identifier
STR R1, [R0, #InitFlag]
MOV PC, R14
; unpack special vars (R1 -> ByteWS)
10
LDRB R2, [R0, #SavedSpoolFileH]
STRB R2, [R1, #:INDEX: SpoolFileH]
LDRB R2, [R0, #SavedWrchDest]
STRB R2, [R1, #:INDEX: WrchDest]
LDRB R2, [R0, #SavedVDUqueueItems]
STRB R2, [R1, #:INDEX: VDUqueueItems]
MOV PC, R14
; *****************************************************************************
;
; ValidateVars - Validate unpacked variables (windows, cursor posns)
;
ValidateVars ROUT
Push R14
ASSERT ScrBRow = ScrRCol + 4
ADD R4, WsPtr, #ScrRCol
LDMIA R4, {R4, R5} ; R4 = ScrRCol; R5 = ScrBRow
ADD R6, WsPtr, #TWLCol ; R0 = TWLCol; R1 = TWBRow
LDMIA R6, {R0-R3} ; R2 = TWRCol; R3 = TWTRow
MOV R7, #0
MOV R8, R5
MOV R9, R4
MOV R10, #0
STMIA R6, {R7-R10} ; set up default window
BL FSRegs ; and attempt to define text window
ASSERT YWindLimit = XWindLimit + 4
ADD R0, WsPtr, #XWindLimit
LDMIA R0, {R2, R3} ; R2 = XWindLimit; R3 = YWindLimit
ADD R8, WsPtr, #GWLCol ; R4 = GWLCol; R5 = GWBRow
LDMIA R8, {R4-R7} ; R6 = GWRCol; R7 = GWTRow
CMP R6, R2 ; if GWRCol > XWindLimit
CMPLS R7, R3 ; or GWTRow > YWindLimit
MOVHI R0, #0
MOVHI R1, #0
STMHIIA R8, {R0-R3} ; then set default graphics window
Pull PC
END