home *** CD-ROM | disk | FTP | other *** search
- 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
-
-