home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
ARM Club 3
/
TheARMClub_PDCD3.iso
/
hensa
/
documentation
/
documents
/
a252scrl
< prev
next >
Wrap
Internet Message Format
|
1999-04-27
|
30KB
From: ee@datcon.co.uk (Eddie Edwards)
Subject: Article: Hardware Scrolling
Summary: Hardware Scrolling using VIDC and MEMC
Keywords: VIDC MEMC Acorn Archimedes Games Scrolling Sad
Date: Thu, 3 Feb 1994 18:50:50 GMT
Hardware Scrolling using VIDC and MEMC
Author : Eddie Edwards (ee@datcon.co.uk)
Version: 0.1
Date : 03/02/94
It is possible, on a system which uses the VIDC and MEMC chips, to perform
scrolling in hardware in all four directions (and combinations thereof). This
is possible to single pixel resolution in the vertical direction and double
pixel resolution in the horizontal direction. This article attempts to explain
the method, give all the technical detail required, and includes a limited
implementation as a scrolltext demo.
[-----------------------------------------------------------------------------]
THE VIDEO DISPLAY
There are four parameters which we are concerned with for the video display,
horizontal border start, horizontal border width, horizontal display start
and horizontal display width. The meaning of these is explained below by
means of a diagram:
HSYNC (leading edge) HSYNC
: :
: :
: |----------------------------------------------------| :
: |''''''''''''''''''''''''''''''''''''''''''''''''''''| :
: |''''''''''''''''''''''''''''''''''''''''''''''''''''| :
: |''''''''''''''''''''''''''''''''''''''''''''''''''''| :
: |''''X------------------------------------------|''''| :
: |''''| |''''| :
: |''''| |''''| :
: |''''| |''''| :
: |''''| |''''| :
: |''''| |''''| :
: |''''| |''''| :
: |''''| |''''| :
: |''''| |''''| :
: |''''| |''''| :
: |''''| |''''| :
: |''''| |''''| :
: |''''| |''''| :
: |''''| |''''| :
: |''''| |''''| :
: |''''| |''''| :
: |''''|------------------------------------------|''''| :
: |'''':'''''''''''''''''''''''''''''''''''''''''':''''| :
: |'''':'''''''''''''''''''''''''''''''''''''''''':''''| :
: |'''':'''''''''''''''''''''''''''''''''''''''''':''''| :
: |----:------------------------------------------:----| :
: : : : : :
: : : : : :
1 <--> : : :
2 <------------------------------------------------------->
3 <-------> :
4 <-------------------------------------------------->
1 - Horizontal border start (VIDC register &88)
2 - Horizontal border end (VIDC register &94)
3 - Horizontal display start (VIDC register &8C)
4 - Horizontal display end (VIDC register &90)
These four parameters (together with two which define the width of the HSYNC
pulse and the distance between HSYNC pulses) define the appearance of the
screen in the horizontal direction. The parameters are in units of 2 pixels,
that is if you increase horizontal display start by 1, the display becomes
2 pixels wider.
[HSYNC is the Horizontal SYNC pulse, which occurs when the electron beam of
the monitor has traced far enough to the right, and tells it to return to the
left of the monitor. Thus, we can imagine that the HSYNC line above is a point
on the extreme left of the monitor, usually hidden behind the case. Then the
registers above are thought of in terms of how many pixels there are between
this point and the point on the display where the border starts, etc.]
Usually parameters 1-4 are set up to give a display as above, with a border
and a display embedded within the border.
One further point to note: the number of bytes read in per line (i.e. 320
for mode 13) is the number of pixels between horizontal display start and end.
Therefore these always have to be a fixed number apart.
[-----------------------------------------------------------------------------]
SCREEN MEMORY
We are also interested in one parameter in the MEMC, the screen base address
(called Vinit in the VLSI manual). This is different to the screen memory
base address, which is fixed by the amount of screen memory you have. The
screen base address is the point X on the diagram above, and is the address
on the first byte to be output - i.e. the address of the pixel in the top
left-hand corner of the display.
[-----------------------------------------------------------------------------]
HARDWARE SCROLLING THE EASY WAY
If we could set Vinit (X on the diagram) to whatever pixel we wanted, we'd
have no problem scrolling the screen. However, because of the way the MEMC
works (DMA accesses are done 16 bytes at a time into the VIDC, and these
16 bytes have to be on an address &xxxxxx0) Vinit can only be set to multiples
of 16 bytes.
What this does mean, though, is that vertical scrolling is easy. Merely add
or subtract the width of a line (e.g. 320 bytes in mode 13) to the current
Vinit. Obviously, we update the register just after a VSYNC, or OS_Byte 19,
so the screen doesn't flicker, and we must make sure beforehand that the
bottom/top line of the screen (the one which will come into view) is set up
with whatever graphics we want to display.
[-----------------------------------------------------------------------------]
HARDWARE SCROLLING THE HARD WAY
The climax of the article - how do we do horizontal scrolling?
Well, if we want to scroll 16 bytes at a time, we can do that in the same way
as above. But we probably want a finer granularity than that. To achieve this,
we cheat. Say we want to scroll the screen left by two pixels at a time (and
as will be apparent from the method, the screen can only be scrolled two
pixels at a time horizontally).
What we do is move the horizontal display start and horizontal display end
registers left by two pixels (i.e. subtract 1 from both registers). This
makes the part of the screen we are looking at move left, i.e. the screen
scrolls left ... or at least it would, except it looks like it's just moved.
When we have moved the display left by 14 pixels and want to scroll again,
NOW we can update Vinit in the MEMC, and put the display back at offset 0.
To turn this into the illusion of scrolling, we start playing with the
border start and end registers.
The thing is, before the border starts only blackness is displayed. After the
border starts but before the display starts, the border colour is shown,
and after the display and border have started the display is shown.
However, until the border has started, nothing is EVER displayed. So if we
start the border after we start the display, we lose the border, but we get
to chop off the bit of the display we don't want. So we set the border start
register to the normal display start (i.e. the right-most point that display
start ever touches) and set the border end register to the normal display
end - 14 pixels (i.e. the left-most point that display end ever touches). This
means that we get blackness, then the part of the display we want to show,
then blackness. It also means that we have a method for horizontal scrolling
in hardware.
The apparent screen size, however, is 14 pixels less than the actual screen
size. If we want an apparent screen size of 320 pixels, we just define a screen
334 pixels wide. Simple! The extra 14 bytes per line are used before scrolling
to insert what we're scrolling onto the screen.
[-----------------------------------------------------------------------------]
PROGRAMMING THE VIDC
The VIDC is programmed by writing words, which contain the register to be
programmed and the value in one word, to the VIDC chip, at address &3400000.
The top byte of the word is the register number, the bottom three bytes
contain the value, in a position which changes for each register. The four
registers which concern us are shown below:
===============================================================================
Horizontal Border Start (&88)
If M pixels are required between the start of the HSYNC pulse and the start
of the border, program (M-1)/2 into this register. (M is odd).
The value of the word to be written is then
&88000000 + (v<<14) where v is the value calculated
===============================================================================
Horizontal Display Start (&8C)
If M pixels are required between the start of the HSYNC pulse and the start
of the display, program (M-5)/2 for 256-colour modes, (M-7)/2 for 16 colour
modes, (M-11)/2 for 4 colour modes and (M-19)/2 for 2 colour modes. (M is odd).
The value of the word to be written is then
&8C000000 + (v<<14) where v is the value calculated
===============================================================================
Horizontal Display End (&90)
If M pixels are required between the start of the HSYNC pulse and the end
of the display, program (M-5)/2 for 256-colour modes, (M-7)/2 for 16 colour
modes, (M-11)/2 for 4 colour modes and (M-19)/2 for 2 colour modes. (M is odd).
The value of the word to be written is then
&90000000 + (v<<14) where v is the value calculated
===============================================================================
Horizontal Border End (&94)
If M pixels are required between the start of the HSYNC pulse and the end
of the border, program (M-1)/2 into this register. (M is odd).
The value of the word to be written is then
&94000000 + (v<<14) where v is the value calculated
===============================================================================
To set up the mode required initially, change to a normal mode with similar
characteristics and merely change the registers above. Note that you cannot
rely on an OS plotting calls working.
Note further that you can only write to the VIDC and MEMC in SUPERVISOR mode.
I.E. call OS_EnterOS before starting all this scrolling stuff.
[-----------------------------------------------------------------------------]
PROGRAMMING THE MEMC
The MEMC is programmed by writing anything to certain addresses, which are at
the extreme top of the memory map.
(Note that writing to anywhere between &3400000 and &35FFFFF activates the
VIDC, which reads data off the bus, so this is "where" the VIDC resides for
any MEMC-based system)
The MEMC handles all DMA accesses within the system, which can only be in the
bottom 512K of RAM. This PHYSICALLY resides at addresses &2000000 onwards,
but the LOGICAL addresses are laid out (by RISC-OS) so that however much
video memory is allocated, it LOGICALLY ends at &20000000 and starts at
&20000000 - (size of video buffer). This means that a Supervisor mode program
can do circular WRITES of the video buffer, by starting in logical RAM and
crossing the boundary into the physical RAM. Most useful.
The key thing to remember, though, is that all numbers used in the MEMC are
offsets from the start of video memory.
What happens when a screen is drawn is that after a VSYNC, the video pointer
is set to Vinit. There are two other registers which define the buffer -
Vstart and Vend. If Vptr ever increases past Vend, it is automatically
initialised to Vstart.
Typically, Vstart will be 0 and Vend will be the size of video memory you
have allocated, although there is no reason why you shouldn't change this.
Vinit is the start of the screen, as explained above.
All three registers can only be programmed to multiples of 16 bytes.
To calculate the address to write to,
Vinit = &3600000+(val>>4)<<2
Vstart = &3620000+(val>>4)<<2
Vend = &3640000+(val>>4)<<2
Then you merely do a STR Rx,[address] to set the register to that value.
Note, however, that OS_Word 22 will set Vinit for you, and OS_UpdateMEMC
allows you to change the control register (the interesting bit in that is
the one which turns video DMA on and off - turning it off speeds the program
up and gives a completely black screen). These calls are used by the demo
below.
(BTW: The address in the scrolltext is no longer my residence ... oddly :-)
[-----------------------------------------------------------------------------]
Thanks to:
Paul Dellar, for outlining the algorithm,
The VLSI Manual, for being there :-)
&c &c &c
Any corrections, suggestions etc. to ee@datcon.co.uk
Hope this is useful,
Happy scrolling!
Eddie xxx
[-----------------------------------------------------------------------------]
10 REM >Isometric4
20 DIM code% 65536*2
30 FOR i%=0 TO 2 STEP 2
40 P%=code%
50 [OPT i%
60 FNlocdeloc(i%,demo,&1FEC000)
70 .generate
80 ADR R1,block:MOV R0,#10:SWI "OS_Word"
90 LDR R0,buffad2:ADD R1,R0,#3456:LDR R2,buffad:ADD R3,R2,#3456
100 STR R0,buffad:STR R2,buffad2
110 MOV R4,#0:MOV R5,#0
120 MOV R8,#0:MOV R9,#0
130 MVN R6,#0:MVN R7,#0
140 MVN R10,#0:MVN R11,#0
150 MOV R12,#3456
160 .loopgen1
170 STMIA R0!,{R4-R5,R8-R9}:STMIA R1!,{R6-R7,R10-R11}
180 STMIA R0!,{R4-R5,R8-R9}:STMIA R1!,{R6-R7,R10-R11}
190 STMIA R0!,{R4-R5,R8-R9}:STMIA R1!,{R6-R7,R10-R11}
200 STMIA R0!,{R4-R5,R8-R9}:STMIA R1!,{R6-R7,R10-R11}
210 STMIA R0!,{R4-R5,R8-R9}:STMIA R1!,{R6-R7,R10-R11}
220 STMIA R0!,{R4-R5,R8-R9}:STMIA R1!,{R6-R7,R10-R11}
230 STMIA R0!,{R4-R5,R8-R9}:STMIA R1!,{R6-R7,R10-R11}
240 STMIA R0!,{R4-R5,R8-R9}:STMIA R1!,{R6-R7,R10-R11}
250 SUBS R12,R12,#128:BNE loopgen1
260 STMFD R13!,{R14}
270 LDR R0,buffad:ADD R0,R0,#1536+48*4+32
280 ADR R1,char+4
290 MOV R6,#8
300 LDR R7,thick
310 .loopgen2
320 MOV R2,#1
330 MOV R5,R0
340 MOV R3,#8
350 LDRB R4,[R1],#-1
360 .loopgen3
370 TST R4,R2:BEQ nodraw
380 BL putblk
390 ADD R0,R0,#100
400 CMP R7,#2
410 BLEQ putblk
420 SUB R0,R0,#100
430 .nodraw
440 ADD R0,R0,#92
450 MOV R2,R2,ASL #1
460 SUBS R3,R3,#1:BNE loopgen3
470 MOV R0,R5
480 SUB R0,R0,#48*5
490 SUBS R6,R6,#1
500 BNE loopgen2
510 LDMFD R13!,{PC}
520 .thick EQUD 2
530 .gen_part2
540 LDR R2,buffad:LDR R0,buffad2:ADD R0,R0,#32:ADD R2,R2,#48*16
550 ADD R1,R0,#3456
560 MOV R4,#56
570 .loopgen4
580 LDMIA R2,{R5-R8}
590 LDMIA R1,{R9-R12}
600 AND R5,R5,R9:AND R6,R6,R10
610 AND R7,R7,R11:AND R8,R8,R12
620 LDMIA R0,{R9-R12}
630 ORR R5,R5,R9:ORR R6,R6,R10
640 ORR R7,R7,R11:ORR R8,R8,R12
650 STMIA R2,{R5-R8}
660 ADD R0,R0,#48:ADD R2,R2,#48:ADD R1,R1,#48
670 SUBS R4,R4,#1:BNE loopgen4
680 MOV PC,R14
690 .thick1 MOV R0,#1:STR R0,thick:B nextchr
700 .thick2 MOV R0,#2:STR R0,thick:B nextchr
710 .putblk ADR R8,grafix:MOV R9,#10:MOV R10,R0
720 .loopPB1
730 LDR R11,[R10,#3456]:LDR R12,[R8,#8]:AND R11,R11,R12:STR R11,[R10,#3456]
740 LDR R11,[R10]:LDR R12,[R8,#8]:AND R11,R11,R12:LDR R12,[R8],#4:ORR R11,R11,R12:STR R11,[R10],#4
750 LDR R11,[R10,#3456]:LDR R12,[R8,#8]:AND R11,R11,R12:STR R11,[R10,#3456]
760 LDR R11,[R10]:LDR R12,[R8,#8]:AND R11,R11,R12:LDR R12,[R8],#12:ORR R11,R11,R12:STR R11,[R10],#44
770 SUBS R9,R9,#1:BNE loopPB1
780 MOV PC,R14
790 .trans
800 ADR R0,grafixO
810 ADR R5,grafix
820 LDR R1,conv
830 MOV R2,#160
840 .loopT
850 LDRB R3,[R0],#1
860 CMP R3,#255:MOVEQ R3,#4
870 LDRB R4,[R1,R3]
880 STRB R4,[R5],#1
890 SUBS R2,R2,#1
900 BNE loopT
910 MOV PC,R14
920 .conv EQUD conv1
930 .conv1 EQUB 0
940 EQUB &13
950 EQUB &07
960 EQUB &77
970 EQUB &FF
980 ALIGN
990 .conv2 EQUB 0
1000 EQUB &13
1010 EQUB &07
1020 EQUB &63
1030 EQUB &FF
1040 ALIGN
1050 .conv3 EQUB 0
1060 EQUB &13
1070 EQUB &07
1080 EQUB &8B
1090 EQUB &FF
1100 ALIGN
1110 .conv4 EQUB 0
1120 EQUB &13
1130 EQUB &07
1140 EQUB &2F
1150 EQUB &FF
1160 ALIGN
1170 .conv5 EQUB 0
1180 EQUB &13
1190 EQUB &07
1200 EQUB &FF
1210 EQUB &FF
1220 ALIGN
1230 .conv9 EQUB 0
1240 EQUB &13
1250 EQUB &07
1260 EQUB &17
1270 EQUB &FF
1280 ALIGN
1290 .comm1 ADR R1,conv1:STR R1,conv:BL trans:B nextchr
1300 .comm2 ADR R1,conv2:STR R1,conv:BL trans:B nextchr
1310 .comm3 ADR R1,conv3:STR R1,conv:BL trans:B nextchr
1320 .comm4 ADR R1,conv4:STR R1,conv:BL trans:B nextchr
1330 .comm5 ADR R1,conv5:STR R1,conv:BL trans:B nextchr
1340 .comm9 ADR R1,conv9:STR R1,conv:BL trans:B nextchr
1350 .grafix
1360 EQUD &01000000:EQUD &00000001:EQUD &00FFFFFF:EQUD &FFFFFF00
1370 EQUD &01010100:EQUD &00010101:EQUD &000000FF:EQUD &FF000000
1380 EQUD &01010101:EQUD &01010101:EQUD &00000000:EQUD &00000000
1390 EQUD &01010102:EQUD &03010101:EQUD &00000000:EQUD &00000000
1400 EQUD &01020202:EQUD &03030301:EQUD &00000000:EQUD &00000000
1410 EQUD &02020202:EQUD &03030303:EQUD &00000000:EQUD &00000000
1420 EQUD &02020202:EQUD &03030303:EQUD &00000000:EQUD &00000000
1430 EQUD &02020202:EQUD &03030303:EQUD &00000000:EQUD &00000000
1440 EQUD &02020200:EQUD &00030303:EQUD &000000FF:EQUD &FF000000
1450 EQUD &02000000:EQUD &00000003:EQUD &00FFFFFF:EQUD &FFFFFF00
1460 .grafixO
1470 EQUD &01000000:EQUD &00000001:EQUD &00FFFFFF:EQUD &FFFFFF00
1480 EQUD &01010100:EQUD &00010101:EQUD &000000FF:EQUD &FF000000
1490 EQUD &01010101:EQUD &01010101:EQUD &00000000:EQUD &00000000
1500 EQUD &01010102:EQUD &03010101:EQUD &00000000:EQUD &00000000
1510 EQUD &01020202:EQUD &03030301:EQUD &00000000:EQUD &00000000
1520 EQUD &02020202:EQUD &03030303:EQUD &00000000:EQUD &00000000
1530 EQUD &02020202:EQUD &03030303:EQUD &00000000:EQUD &00000000
1540 EQUD &02020202:EQUD &03030303:EQUD &00000000:EQUD &00000000
1550 EQUD &02020200:EQUD &00030303:EQUD &000000FF:EQUD &FF000000
1560 EQUD &02000000:EQUD &00000003:EQUD &00FFFFFF:EQUD &FFFFFF00
1570 .block EQUD 69
1580 .char EQUD 0:EQUD 0
1590 .count EQUD 0
1600 .countapply EQUD buffer
1610 .buffad EQUD buffer
1620 .buffad2 EQUD buffer+6912
1630 EQUB 0:EQUB 0:EQUB 0
1640 .parablock EQUB 3
1650 .screenoff EQUD 0
1660 .screenstartabs EQUD &1FEC000
1670 .screenstart EQUD &1FEC000
1680
1681 ; main scroll routine - only scrolls left and down for the minute
1690
1700 .scrollLEFTword
1710 MOV R0,#19:SWI "OS_Byte" ; VSYNC
1720 SWI 22 ; OS_EnterOS - need
1730 MOVNV R0,R0 ; Supervisor mode for this!
1740 LDR R11,screenstartabs:RSB R11,R11,#&2000000 ; R11 = screen buf size
1750 LDR R0,screenstart:ADD R0,R0,#4 ; move screenstart 4 right
1760 SUB R0,R0,#640 ; and 2 up
1770 CMP R0,#&2000000:SUBHS R0,R0,R11 ; make sure it's in the
1771 ; screen buffer
1780 LDR R1,screenstartabs ; make sure it's in the
1790 CMP R0,R1:ADDLO R0,R0,R11 ; screen buffer
1800 STR R0,screenstart ; and update variable
1810 MOV R2,R0,LSR #1:AND R2,R2,#6 ; get pixels/2 across
1811 ; from window
1812 ; (shift of 0-7)
1820 RSB R2,R2,#66 ; calc. timing from left
1821 ; HSYNC
1830 MOV R2,R2,ASL #14 ; shift into VIDC format
1840 ORR R2,R2,#&8C000000:MOV R1,#&03400000 ; get VIDC reg no,
1850 STR R2,[R1] ; store!
1860 ADD R2,R2,#&04000000 ; get right side reg
1870 ADD R2,R2,#&00280000:STR R2,[R1] ; add size of screen &
1871 ; store
1880 MOV R2,#(68<<14):ORR R2,R2,#&88000000:STR R2,[R1] ; border offset L ...
1890 ADD R2,R2,#(320-12)<<13:ADD R2,R2,#&0C000000:STR R2,[R1] ; and right
1900 LDR R1,screenoff ; get screen offset
1910 TST R0,#15 ; if screenstart is 0 MOD 16
1920 ADDEQ R1,R1,#16 ; then add 16 to screen off
1930 SUBS R1,R1,#640:ADDMI R1,R1,R11 ; sub 640 (2 lines) and
1931 ; realign if overflow off
1932 ; screen base
1940 CMP R1,R11:SUBHS R1,R1,R11:STR R1,screenoff ; then update variable
1950 MOV R0,#22:ADR R1,parablock:SWI "OS_Word" ; update MEMC screen addr
1960 LDR R0,screenstart ; get screenstart
1970 SUB R0,R0,#4 ; sub 4
1980 LDR R1,screenstartabs ; get top of screen mem
1990 CMP R0,R1:ADDLO R0,R0,R11 ; align screenstart
2000 STMFD R13!,{R0} ; save
2010 LDR R9,offsetr ; rest is scrolling code
2020 LDR R8,count:MOV R8,R8,LSR #1:ADD R8,R8,R9 ; to print the invisible
2030 MOV R11,R8 ; line for the next time
2040 MOV R1,#0 ; around ....
2050 .loopP1
2060 STR R1,[R0],#320:SUBS R8,R8,#1:BNE loopP1
2070 LDR R8,count:LDR R9,countapply:ADD R9,R9,R8:ADD R10,R9,#3456
2080 MOV R12,#72
2090 .loopP2
2100 LDR R1,[R9],#48:STR R1,[R0],#320
2110 LDR R1,[R9],#48:STR R1,[R0],#320
2120 LDR R1,[R9],#48:STR R1,[R0],#320
2130 LDR R1,[R9],#48:STR R1,[R0],#320
2140 LDR R1,[R9],#48:STR R1,[R0],#320
2150 LDR R1,[R9],#48:STR R1,[R0],#320
2160 LDR R1,[R9],#48:STR R1,[R0],#320
2170 LDR R1,[R9],#48:STR R1,[R0],#320
2180 SUBS R12,R12,#8:BNE loopP2
2190 ADD R11,R11,#72
2200 MOV R1,#0
2210 .loopP3
2220 STR R1,[R0],#320:ADD R11,R11,#1:CMP R11,#128:BNE loopP3
2230 LDR R1,col1:LDR R2,adder:LDMFD R13!,{R8}
2240 MOV R3,#0:MOV R4,#0:MOV R5,#0:MOV R6,#0
2250 ADD R8,R8,#320
2260 STMIA R8!,{R3-R6}:STMIA R8!,{R3-R6}
2270 STMIA R8!,{R3-R6}:STMIA R8!,{R3-R6}
2280 SUB R8,R8,#384
2290 STMIA R8!,{R3-R6}:STMIA R8!,{R3-R6}
2300 STMIA R8!,{R3-R6}:STMIA R8!,{R3-R6}
2310 .loopP4
2320 STR R1,[R0],#320:TST R11,#1:STRNE R1,[R8,#316]:STREQ R1,[R8],#4:ADD R1,R1,R2:ADD R11,R11,#1:CMP R11,#255:BNE loopP4
2330 MOV R1,R1,ASL #16:MOV R1,R1,LSR #16:STR R1,[R0]:STR R1,[R8,#316]
2340 TEQP PC,#0:MOVNV R0,R0
2350 MOV PC,R14
2360 .col1 EQUD &01010000
2370 .adder EQUD &01010101
2380 .const1 EQUD 320*72
2390 .minispace MOV R0,#8:STR R0,nextcount:B nextchr
2400 .nextcount EQUD 40
2410 .notpending CMP R0,#32
2420 MOVNE PC,R14
2430 STMFD R13!,{R14}
2440 BL gen_part2
2450 MOV R0,#0:STR R0,count
2460 LDR R0,buffad:STR R0,countapply
2470 LDR R0,nextoffsetr:STR R0,offsetr
2480 LDMFD R13!,{PC}
2490 .scroll LDR R0,count:ADD R0,R0,#4
2500 LDR R1,nextcount:CMP R0,R1:MOVEQ R0,#28
2510 STR R0,count
2520 CMP R0,#28:BNE notpending
2530 MOV R1,#40:STR R1,nextcount
2540 STMFD R13!,{R14}
2550 .nextchr
2560 LDR R0,textptr:LDRB R1,[R0],#1:STR R0,textptr
2570 CMP R1,#32:BLO command
2580 STR R1,block
2590 BL generate
2600 LDMFD R13!,{PC}
2610 .command CMP R1,#12:BHI nextchr
2620 ADD PC,PC,R1,ASL #2
2630 B nextchr
2640 B resettext
2650 B comm1
2660 B comm2
2670 B comm3
2680 B comm4
2690 B comm5
2700 B thick1
2710 B thick2
2720 B offset
2730 B comm9
2740 B minispace
2750 B slow
2760 B fast
2770 .offset LDR R0,textptr:LDRB R1,[R0],#1:STR R0,textptr
2780 STR R1,nextoffsetr
2790 B nextchr
2800 .offsetr EQUD 20
2810 .nextoffsetr EQUD 20
2820 .resettext
2830 LDR R0,textinit:STR R0,textptr:B nextchr
2840 .demo
2850 STMFD R13!,{R14}
2860 SWI &116:SWI &10D:SWI "OS_RemoveCursors"
2870 MOV R0,#0:MOV R1,#1024:SWI "OS_UpdateMEMC" ; screen off
2880 MOV R0,#100
2890 .loopdemo1
2900 STMFD R13!,{R0}
2910 BL scrollLEFTword+8 ; scroll without waiting
2920 BL scrollLEFTword+8 ; for VSYNC - this fills
2930 BL scrollLEFTword+8 ; the screen with the
2940 BL scrollLEFTword+8 ; background
2950 LDMFD R13!,{R0}
2960 SUBS R0,R0,#4:BNE loopdemo1
2970 MOV R0,#19:SWI "OS_Byte" ; wait a little while
2980 MOV R0,#19:SWI "OS_Byte"
2990 MOV R0,#19:SWI "OS_Byte"
3000 MOV R0,#19:SWI "OS_Byte"
3010 MOV R0,#19:SWI "OS_Byte"
3020 MOV R0,#19:SWI "OS_Byte"
3030 MOV R0,#19:SWI "OS_Byte"
3040 MOV R0,#19:SWI "OS_Byte"
3050 MOV R0,#19:SWI "OS_Byte"
3060 MOV R0,#19:SWI "OS_Byte"
3070 MOV R0,#1024:MOV R1,#1024:SWI "OS_UpdateMEMC" ; screen on
3080 BL music ; (music on)
3090 .loopdemo
3100 BL scroll ; calc
3110 BL scrollLEFTword ; scroll
3120 LDR R0,speed:CMP R0,#2:BNE notfast
3130 BL scroll ; calc some more
3140 BL scrollLEFTword+8 ; scroll without VSYNC
3150 .notfast
3160 BL music+4 ; update music
3170 MOV R0,#129:MOV R1,#0:MOV R2,#0:SWI "OS_Byte" ; get ESCAPE
3180 CMP R2,#27:BNE loopdemo ; if not, loop
3190 BL music+8 ; kill music
3200 LDMFD R13!,{PC} ; die
3210 .slow MOV R0,#1:STR R0,speed:B nextchr
3220 .fast MOV R0,#2:STR R0,speed:B nextchr
3230 .speed EQUD 1
3240 .textptr EQUD text
3250 .textinit EQUD realtext
3260 .text
3270 EQUS " "
3280 .realtext
3290 EQUB 1:EQUB 7:EQUB 8:EQUB 20
3300 EQUS "Welcome to ........ "
3310 EQUB 5:EQUS "Crap Demo #3":EQUB 1:EQUS " !!!!! "
3320 EQUS "Written by "
3330 EQUB 6:EQUB 2:EQUS "Mike Edwards":EQUB 7:EQUB 1
3340 EQUS ", for a "
3350 EQUB 9
3360 EQUB 8:EQUB 20:EQUS "L":EQUB 10:EQUB 32
3370 EQUB 8:EQUB 4:EQUS "A":EQUB 10:EQUB 32
3380 EQUB 8:EQUB 20:EQUS "U":EQUB 10:EQUB 32
3390 EQUB 8:EQUB 36:EQUS "G":EQUB 10:EQUB 32
3400 EQUB 8:EQUB 20:EQUS "H":EQUB 10:EQUB 32
3410 EQUB 1
3420 EQUS " on the 27th of December "
3430 EQUS "1990, using lots of dodgy programming techniques, etc. "
3440 EQUS "Every 50th of a second, the screen is scrolling in this direction "
3450 EQUS "and a strip of letter is added onto the right-hand end. These "
3460 EQUS "strips are calculated letter by letter, behind the previous letter "
3470 EQUS "and then plotted. The big letters are not kept in memory (a full "
3480 EQUS "character set would take 576K!!!) but calculated from the system "
3490 EQUS "font. Hence, to change this font all you have to do is change the "
3500 EQUS "system font!!! Also, I'm not using any "
3510 EQUB 4:EQUS "shadow":EQUB 1
3520 EQUS " screens. At the end of this scrolltext, I'll print all 224 "
3530 EQUS "characters, just to prove that I'm not storing them (this would "
3540 EQUS "take 1344K!). The calculation is split up into two halves, one "
3550 EQUS "just before a character is needed and one when it is "
3560 EQUS "needed (the complete calculation takes too long, and there's all "
3570 EQUS "this time going spare between letters! Anyway, I'd better be "
3580 EQUS "going as it's now the 28th of December (i.e. past bedtime!) and "
3590 EQUS "I'm bored of writing this scrolltext. Write to : "
3600 EQUB 5:EQUS "Mike ":EQUB 9:EQUS """Eddie""":EQUB 5
3610 EQUS " Edwards, Christ's College, Cambridge ":EQUB 1
3620 EQUS " Lots of love and kisses, Eddie xxx Now here's the entire "
3630 EQUS "character set (as promised): "
3640 EQUB 3:EQUB 12:EQUB 6
3650 .chrsetentire
3660 ]
3670 P%+=224
3680 [OPT i%
3690 EQUS " "
3700 EQUB 11:EQUB 7
3710 EQUB 1
3720 EQUS " Time to replay ... "
3730 EQUB 0
3740 ALIGN
3750 .buffer
3760 ]
3770 P%+=3456*4
3780 [OPT i%
3790 .music
3800 MOV PC,R14
3810 MOV PC,R14
3820 MOV PC,R14
3830 ]
3840 NEXT
3850 FOR i%=0 TO 3455 STEP 4
3860 buffer!i%=0:buffer!(i%+3456)=-1
3870 NEXT
3880 FOR i%=0 TO 223:chrsetentire?i%=i%+32:NEXT
3890 CALL delocate
3900 OSCLI("Save CrapDemo3 "+STR$~code%+" "+STR$~P%)
3910 OSCLI("Settype CrapDemo3 Absolute")
3920 CALL locate
3930 CALL demo
3940 END
3950 REM >%.Assemprims.LocDeloc
3960 DEF FNlocdeloc(opt%,maincode%,video%)
3970 [OPT opt%
3980 .top
3990 SWI "OS_GetEnv"
4000 MOV R13,R1
4010 BL locate
4020 BL maincode%
4030 BL delocate
4040 SWI "OS_Exit"
4050 .locate
4060 SWI &116:SWI &100:SWI "OS_RemoveCursors"
4070 ADR R0,list:ADR R1,vdu
4080 SWI "OS_ReadVduVariables"
4090 ADR R0,top:ADR R1,vidlist:LDR R2,vdu
4100 .loopL1
4110 LDR R3,[R1],#4:CMP R3,#0:BEQ nextbitL
4120 ADD R3,R3,R0:LDR R4,[R3]:ADD R4,R4,R2:STR R4,[R3]
4130 B loopL1
4140 .nextbitL
4150 ADR R1,EQUDlist
4160 .loopL2
4170 LDR R3,[R1],#4:CMP R3,#0:MOVEQ PC,R14
4180 ADD R3,R3,R0:LDR R4,[R3]:ADD R4,R4,R0:STR R4,[R3]
4190 B loopL2
4200 .list EQUD 149:EQUD -1
4210 .vdu EQUD video%
4220 .delocate
4230 ADR R0,top:ADR R1,vidlist:LDR R2,vdu
4240 .loopDL1
4250 LDR R3,[R1],#4:CMP R3,#0:BEQ nextbitDL
4260 ADD R3,R3,R0:LDR R4,[R3]:SUB R4,R4,R2:STR R4,[R3]
4270 B loopDL1
4280 .nextbitDL
4290 ADR R1,EQUDlist
4300 .loopDL2
4310 LDR R3,[R1],#4:CMP R3,#0:MOVEQ PC,R14
4320 ADD R3,R3,R0:LDR R4,[R3]:SUB R4,R4,R0:STR R4,[R3]
4330 B loopDL2
4340 .vidlist
4350 EQUD screenstartabs-top
4360 EQUD screenstart-top
4370 EQUD 0
4380 .EQUDlist
4390 EQUD conv-top
4400 EQUD countapply-top
4410 EQUD buffad-top
4420 EQUD buffad2-top
4430 EQUD textptr-top
4440 EQUD textinit-top
4450 EQUD 0
4460 ]
4470 =0