home *** CD-ROM | disk | FTP | other *** search
/ ARM Club 3 / TheARMClub_PDCD3.iso / hensa / documentation / documents / a252scrl < prev    next >
Internet Message Format  |  1999-04-27  |  30KB

  1. From: ee@datcon.co.uk (Eddie Edwards)
  2. Subject: Article: Hardware Scrolling
  3. Summary: Hardware Scrolling using VIDC and MEMC 
  4. Keywords: VIDC MEMC Acorn Archimedes Games Scrolling Sad
  5. Date: Thu, 3 Feb 1994 18:50:50 GMT
  6.  
  7.  
  8. Hardware Scrolling using VIDC and MEMC
  9.  
  10. Author : Eddie Edwards (ee@datcon.co.uk)
  11.  
  12. Version: 0.1
  13.  
  14. Date   : 03/02/94
  15.  
  16. It is possible, on a system which uses the VIDC and MEMC chips, to perform
  17. scrolling in hardware in all four directions (and combinations thereof). This
  18. is possible to single pixel resolution in the vertical direction and double
  19. pixel resolution in the horizontal direction. This article attempts to explain
  20. the method, give all the technical detail required, and includes a limited
  21. implementation as a scrolltext demo.
  22.  
  23. [-----------------------------------------------------------------------------]
  24.  
  25. THE VIDEO DISPLAY
  26.  
  27. There are four parameters which we are concerned with for the video display,
  28. horizontal border start, horizontal border width, horizontal display start
  29. and horizontal display width.  The meaning of these is explained below by
  30. means of a diagram:
  31.  
  32.      HSYNC (leading edge)                                       HSYNC
  33.        :                                                          :
  34.        :                                                          :
  35.        :  |----------------------------------------------------|  :
  36.        :  |''''''''''''''''''''''''''''''''''''''''''''''''''''|  :
  37.        :  |''''''''''''''''''''''''''''''''''''''''''''''''''''|  :
  38.        :  |''''''''''''''''''''''''''''''''''''''''''''''''''''|  :
  39.        :  |''''X------------------------------------------|''''|  :
  40.        :  |''''|                                          |''''|  :
  41.        :  |''''|                                          |''''|  :
  42.        :  |''''|                                          |''''|  :
  43.        :  |''''|                                          |''''|  :
  44.        :  |''''|                                          |''''|  :
  45.        :  |''''|                                          |''''|  :
  46.        :  |''''|                                          |''''|  :
  47.        :  |''''|                                          |''''|  :
  48.        :  |''''|                                          |''''|  :
  49.        :  |''''|                                          |''''|  :
  50.        :  |''''|                                          |''''|  :
  51.        :  |''''|                                          |''''|  :
  52.        :  |''''|                                          |''''|  :
  53.        :  |''''|                                          |''''|  :
  54.        :  |''''|                                          |''''|  :
  55.        :  |''''|------------------------------------------|''''|  :
  56.        :  |'''':'''''''''''''''''''''''''''''''''''''''''':''''|  :
  57.        :  |'''':'''''''''''''''''''''''''''''''''''''''''':''''|  :
  58.        :  |'''':'''''''''''''''''''''''''''''''''''''''''':''''|  :
  59.        :  |----:------------------------------------------:----|  :
  60.        :  :    :                                          :    :  :
  61.        :  :    :                                          :    :  :
  62.     1  <-->    :                                          :    :
  63.     2  <------------------------------------------------------->
  64.     3  <------->                                          :
  65.     4  <-------------------------------------------------->
  66.  
  67. 1 - Horizontal border start  (VIDC register &88)
  68. 2 - Horizontal border end    (VIDC register &94)
  69. 3 - Horizontal display start (VIDC register &8C)
  70. 4 - Horizontal display end   (VIDC register &90)
  71.  
  72. These four parameters (together with two which define the width of the HSYNC
  73. pulse and the distance between HSYNC pulses) define the appearance of the
  74. screen in the horizontal direction. The parameters are in units of 2 pixels,
  75. that is if you increase horizontal display start by 1, the display becomes
  76. 2 pixels wider.
  77.  
  78. [HSYNC is the Horizontal SYNC pulse, which occurs when the electron beam of
  79. the monitor has traced far enough to the right, and tells it to return to the
  80. left of the monitor. Thus, we can imagine that the HSYNC line above is a point
  81. on the extreme left of the monitor, usually hidden behind the case. Then the
  82. registers above are thought of in terms of how many pixels there are between
  83. this point and the point on the display where the border starts, etc.]
  84.  
  85. Usually parameters 1-4 are set up to give a display as above, with a border
  86. and a display embedded within the border.
  87.  
  88. One further point to note: the number of bytes read in per line (i.e. 320
  89. for mode 13) is the number of pixels between horizontal display start and end.
  90. Therefore these always have to be a fixed number apart.
  91.  
  92. [-----------------------------------------------------------------------------]
  93.  
  94. SCREEN MEMORY
  95.  
  96. We are also interested in one parameter in the MEMC, the screen base address
  97. (called Vinit in the VLSI manual). This is different to the screen memory
  98. base address, which is fixed by the amount of screen memory you have. The
  99. screen base address is the point X on the diagram above, and is the address
  100. on the first byte to be output - i.e. the address of the pixel in the top
  101. left-hand corner of the display.
  102.  
  103. [-----------------------------------------------------------------------------]
  104.  
  105. HARDWARE SCROLLING THE EASY WAY
  106.  
  107. If we could set Vinit (X on the diagram) to whatever pixel we wanted, we'd
  108. have no problem scrolling the screen. However, because of the way the MEMC
  109. works (DMA accesses are done 16 bytes at a time into the VIDC, and these
  110. 16 bytes have to be on an address &xxxxxx0) Vinit can only be set to multiples
  111. of 16 bytes.
  112.  
  113. What this does mean, though, is that vertical scrolling is easy. Merely add
  114. or subtract the width of a line (e.g. 320 bytes in mode 13) to the current
  115. Vinit. Obviously, we update the register just after a VSYNC, or OS_Byte 19,
  116. so the screen doesn't flicker, and we must make sure beforehand that the
  117. bottom/top line of the screen (the one which will come into view) is set up
  118. with whatever graphics we want to display.
  119.  
  120. [-----------------------------------------------------------------------------]
  121.  
  122. HARDWARE SCROLLING THE HARD WAY
  123.  
  124. The climax of the article - how do we do horizontal scrolling?
  125.  
  126. Well, if we want to scroll 16 bytes at a time, we can do that in the same way
  127. as above. But we probably want a finer granularity than that. To achieve this,
  128. we cheat. Say we want to scroll the screen left by two pixels at a time (and
  129. as will be apparent from the method, the screen can only be scrolled two
  130. pixels at a time horizontally).
  131.  
  132. What we do is move the horizontal display start and horizontal display end
  133. registers left by two pixels (i.e. subtract 1 from both registers). This
  134. makes the part of the screen we are looking at move left, i.e. the screen
  135. scrolls left ... or at least it would, except it looks like it's just moved.
  136. When we have moved the display left by 14 pixels and want to scroll again,
  137. NOW we can update Vinit in the MEMC, and put the display back at offset 0.
  138. To turn this into the illusion of scrolling, we start playing with the
  139. border start and end registers.
  140.  
  141. The thing is, before the border starts only blackness is displayed. After the
  142. border starts but before the display starts, the border colour is shown,
  143. and after the display and border have started the display is shown.
  144.  
  145. However, until the border has started, nothing is EVER displayed. So if we
  146. start the border after we start the display, we lose the border, but we get
  147. to chop off the bit of the display we don't want. So we set the border start
  148. register to the normal display start (i.e. the right-most point that display
  149. start ever touches) and set the border end register to the normal display
  150. end - 14 pixels (i.e. the left-most point that display end ever touches). This
  151. means that we get blackness, then the part of the display we want to show,
  152. then blackness. It also means that we have a method for horizontal scrolling
  153. in hardware.
  154.  
  155. The apparent screen size, however, is 14 pixels less than the actual screen
  156. size. If we want an apparent screen size of 320 pixels, we just define a screen
  157. 334 pixels wide. Simple! The extra 14 bytes per line are used before scrolling
  158. to insert what we're scrolling onto the screen.
  159.  
  160. [-----------------------------------------------------------------------------]
  161.  
  162. PROGRAMMING THE VIDC
  163.  
  164. The VIDC is programmed by writing words, which contain the register to be
  165. programmed and the value in one word, to the VIDC chip, at address &3400000.
  166. The top byte of the word is the register number, the bottom three bytes
  167. contain the value, in a position which changes for each register. The four
  168. registers which concern us are shown below:
  169.  
  170. ===============================================================================
  171.  
  172. Horizontal Border Start (&88)
  173.  
  174. If M pixels are required between the start of the HSYNC pulse and the start
  175. of the border, program (M-1)/2 into this register. (M is odd).
  176.  
  177. The value of the word to be written is then
  178.  
  179. &88000000 + (v<<14) where v is the value calculated
  180.  
  181. ===============================================================================
  182.  
  183. Horizontal Display Start (&8C)
  184.  
  185. If M pixels are required between the start of the HSYNC pulse and the start
  186. of the display, program (M-5)/2 for 256-colour modes, (M-7)/2 for 16 colour
  187. modes, (M-11)/2 for 4 colour modes and (M-19)/2 for 2 colour modes. (M is odd).
  188.  
  189. The value of the word to be written is then
  190.  
  191. &8C000000 + (v<<14) where v is the value calculated
  192.  
  193. ===============================================================================
  194.  
  195. Horizontal Display End (&90)
  196.  
  197. If M pixels are required between the start of the HSYNC pulse and the end
  198. of the display, program (M-5)/2 for 256-colour modes, (M-7)/2 for 16 colour
  199. modes, (M-11)/2 for 4 colour modes and (M-19)/2 for 2 colour modes. (M is odd).
  200.  
  201. The value of the word to be written is then
  202.  
  203. &90000000 + (v<<14) where v is the value calculated
  204.  
  205. ===============================================================================
  206.  
  207. Horizontal Border End (&94)
  208.  
  209. If M pixels are required between the start of the HSYNC pulse and the end
  210. of the border, program (M-1)/2 into this register. (M is odd).
  211.  
  212. The value of the word to be written is then
  213.  
  214. &94000000 + (v<<14) where v is the value calculated
  215.  
  216. ===============================================================================
  217.  
  218. To set up the mode required initially, change to a normal mode with similar
  219. characteristics and merely change the registers above. Note that you cannot
  220. rely on an OS plotting calls working.
  221.  
  222. Note further that you can only write to the VIDC and MEMC in SUPERVISOR mode.
  223. I.E. call OS_EnterOS before starting all this scrolling stuff.
  224.  
  225. [-----------------------------------------------------------------------------]
  226.  
  227. PROGRAMMING THE MEMC
  228.  
  229. The MEMC is programmed by writing anything to certain addresses, which are at
  230. the extreme top of the memory map.
  231.  
  232. (Note that writing to anywhere between &3400000 and &35FFFFF activates the
  233. VIDC, which reads data off the bus, so this is "where" the VIDC resides for
  234. any MEMC-based system)
  235.  
  236. The MEMC handles all DMA accesses within the system, which can only be in the
  237. bottom 512K of RAM. This PHYSICALLY resides at addresses &2000000 onwards,
  238. but the LOGICAL addresses are laid out (by RISC-OS) so that however much
  239. video memory is allocated, it LOGICALLY ends at &20000000 and starts at
  240. &20000000 - (size of video buffer). This means that a Supervisor mode program
  241. can do circular WRITES of the video buffer, by starting in logical RAM and
  242. crossing the boundary into the physical RAM. Most useful.
  243.  
  244. The key thing to remember, though, is that all numbers used in the MEMC are
  245. offsets from the start of video memory.
  246.  
  247. What happens when a screen is drawn is that after a VSYNC, the video pointer
  248. is set to Vinit. There are two other registers which define the buffer -
  249. Vstart and Vend. If Vptr ever increases past Vend, it is automatically
  250. initialised to Vstart.
  251.  
  252. Typically, Vstart will be 0 and Vend will be the size of video memory you
  253. have allocated, although there is no reason why you shouldn't change this.
  254.  
  255. Vinit is the start of the screen, as explained above.
  256.  
  257. All three registers can only be programmed to multiples of 16 bytes.
  258.  
  259. To calculate the address to write to,
  260.  
  261. Vinit  = &3600000+(val>>4)<<2
  262. Vstart = &3620000+(val>>4)<<2
  263. Vend   = &3640000+(val>>4)<<2
  264.  
  265. Then you merely do a STR Rx,[address] to set the register to that value.
  266.  
  267. Note, however, that OS_Word 22 will set Vinit for you, and OS_UpdateMEMC
  268. allows you to change the control register (the interesting bit in that is
  269. the one which turns video DMA on and off - turning it off speeds the program
  270. up and gives a completely black screen). These calls are used by the demo
  271. below.
  272.  
  273. (BTW: The address in the scrolltext is no longer my residence ... oddly :-)
  274.  
  275. [-----------------------------------------------------------------------------]
  276.  
  277. Thanks to:
  278.  
  279. Paul Dellar, for outlining the algorithm,
  280. The VLSI Manual, for being there :-)
  281. &c &c &c
  282.  
  283. Any corrections, suggestions etc. to ee@datcon.co.uk
  284.  
  285. Hope this is useful,
  286.  
  287. Happy scrolling!
  288.  
  289. Eddie xxx
  290.  
  291. [-----------------------------------------------------------------------------]
  292.  
  293.    10 REM >Isometric4
  294.    20 DIM code% 65536*2
  295.    30 FOR i%=0 TO 2 STEP 2
  296.    40 P%=code%
  297.    50 [OPT i%
  298.    60 FNlocdeloc(i%,demo,&1FEC000)
  299.    70 .generate
  300.    80 ADR R1,block:MOV R0,#10:SWI "OS_Word"
  301.    90 LDR R0,buffad2:ADD R1,R0,#3456:LDR R2,buffad:ADD R3,R2,#3456
  302.   100 STR R0,buffad:STR R2,buffad2
  303.   110 MOV R4,#0:MOV R5,#0
  304.   120 MOV R8,#0:MOV R9,#0
  305.   130 MVN R6,#0:MVN R7,#0
  306.   140 MVN R10,#0:MVN R11,#0
  307.   150 MOV R12,#3456
  308.   160 .loopgen1
  309.   170 STMIA R0!,{R4-R5,R8-R9}:STMIA R1!,{R6-R7,R10-R11}
  310.   180 STMIA R0!,{R4-R5,R8-R9}:STMIA R1!,{R6-R7,R10-R11}
  311.   190 STMIA R0!,{R4-R5,R8-R9}:STMIA R1!,{R6-R7,R10-R11}
  312.   200 STMIA R0!,{R4-R5,R8-R9}:STMIA R1!,{R6-R7,R10-R11}
  313.   210 STMIA R0!,{R4-R5,R8-R9}:STMIA R1!,{R6-R7,R10-R11}
  314.   220 STMIA R0!,{R4-R5,R8-R9}:STMIA R1!,{R6-R7,R10-R11}
  315.   230 STMIA R0!,{R4-R5,R8-R9}:STMIA R1!,{R6-R7,R10-R11}
  316.   240 STMIA R0!,{R4-R5,R8-R9}:STMIA R1!,{R6-R7,R10-R11}
  317.   250 SUBS R12,R12,#128:BNE loopgen1
  318.   260 STMFD R13!,{R14}
  319.   270 LDR R0,buffad:ADD R0,R0,#1536+48*4+32
  320.   280 ADR R1,char+4
  321.   290 MOV R6,#8
  322.   300 LDR R7,thick
  323.   310 .loopgen2
  324.   320 MOV R2,#1
  325.   330 MOV R5,R0
  326.   340 MOV R3,#8
  327.   350 LDRB R4,[R1],#-1
  328.   360 .loopgen3
  329.   370 TST R4,R2:BEQ nodraw
  330.   380 BL putblk
  331.   390 ADD R0,R0,#100
  332.   400 CMP R7,#2
  333.   410 BLEQ putblk
  334.   420 SUB R0,R0,#100
  335.   430 .nodraw
  336.   440 ADD R0,R0,#92
  337.   450 MOV R2,R2,ASL #1
  338.   460 SUBS R3,R3,#1:BNE loopgen3
  339.   470 MOV R0,R5
  340.   480 SUB R0,R0,#48*5
  341.   490 SUBS R6,R6,#1
  342.   500 BNE loopgen2
  343.   510 LDMFD R13!,{PC}
  344.   520 .thick EQUD 2
  345.   530 .gen_part2
  346.   540 LDR R2,buffad:LDR R0,buffad2:ADD R0,R0,#32:ADD R2,R2,#48*16
  347.   550 ADD R1,R0,#3456
  348.   560 MOV R4,#56
  349.   570 .loopgen4
  350.   580 LDMIA R2,{R5-R8}
  351.   590 LDMIA R1,{R9-R12}
  352.   600 AND R5,R5,R9:AND R6,R6,R10
  353.   610 AND R7,R7,R11:AND R8,R8,R12
  354.   620 LDMIA R0,{R9-R12}
  355.   630 ORR R5,R5,R9:ORR R6,R6,R10
  356.   640 ORR R7,R7,R11:ORR R8,R8,R12
  357.   650 STMIA R2,{R5-R8}
  358.   660 ADD R0,R0,#48:ADD R2,R2,#48:ADD R1,R1,#48
  359.   670 SUBS R4,R4,#1:BNE loopgen4
  360.   680 MOV PC,R14
  361.   690 .thick1 MOV R0,#1:STR R0,thick:B nextchr
  362.   700 .thick2 MOV R0,#2:STR R0,thick:B nextchr
  363.   710 .putblk ADR R8,grafix:MOV R9,#10:MOV R10,R0
  364.   720 .loopPB1
  365.   730 LDR R11,[R10,#3456]:LDR R12,[R8,#8]:AND R11,R11,R12:STR R11,[R10,#3456]
  366.   740 LDR R11,[R10]:LDR R12,[R8,#8]:AND R11,R11,R12:LDR R12,[R8],#4:ORR R11,R11,R12:STR R11,[R10],#4
  367.   750 LDR R11,[R10,#3456]:LDR R12,[R8,#8]:AND R11,R11,R12:STR R11,[R10,#3456]
  368.   760 LDR R11,[R10]:LDR R12,[R8,#8]:AND R11,R11,R12:LDR R12,[R8],#12:ORR R11,R11,R12:STR R11,[R10],#44
  369.   770 SUBS R9,R9,#1:BNE loopPB1
  370.   780 MOV PC,R14
  371.   790 .trans
  372.   800 ADR R0,grafixO
  373.   810 ADR R5,grafix
  374.   820 LDR R1,conv
  375.   830 MOV R2,#160
  376.   840 .loopT
  377.   850 LDRB R3,[R0],#1
  378.   860 CMP R3,#255:MOVEQ R3,#4
  379.   870 LDRB R4,[R1,R3]
  380.   880 STRB R4,[R5],#1
  381.   890 SUBS R2,R2,#1
  382.   900 BNE loopT
  383.   910 MOV PC,R14
  384.   920 .conv EQUD conv1
  385.   930 .conv1 EQUB 0
  386.   940 EQUB &13
  387.   950 EQUB &07
  388.   960 EQUB &77
  389.   970 EQUB &FF
  390.   980 ALIGN
  391.   990 .conv2 EQUB 0
  392.  1000 EQUB &13
  393.  1010 EQUB &07
  394.  1020 EQUB &63
  395.  1030 EQUB &FF
  396.  1040 ALIGN
  397.  1050 .conv3 EQUB 0
  398.  1060 EQUB &13
  399.  1070 EQUB &07
  400.  1080 EQUB &8B
  401.  1090 EQUB &FF
  402.  1100 ALIGN
  403.  1110 .conv4 EQUB 0
  404.  1120 EQUB &13
  405.  1130 EQUB &07
  406.  1140 EQUB &2F
  407.  1150 EQUB &FF
  408.  1160 ALIGN
  409.  1170 .conv5 EQUB 0
  410.  1180 EQUB &13
  411.  1190 EQUB &07
  412.  1200 EQUB &FF
  413.  1210 EQUB &FF
  414.  1220 ALIGN
  415.  1230 .conv9 EQUB 0
  416.  1240 EQUB &13
  417.  1250 EQUB &07
  418.  1260 EQUB &17
  419.  1270 EQUB &FF
  420.  1280 ALIGN
  421.  1290 .comm1 ADR R1,conv1:STR R1,conv:BL trans:B nextchr
  422.  1300 .comm2 ADR R1,conv2:STR R1,conv:BL trans:B nextchr
  423.  1310 .comm3 ADR R1,conv3:STR R1,conv:BL trans:B nextchr
  424.  1320 .comm4 ADR R1,conv4:STR R1,conv:BL trans:B nextchr
  425.  1330 .comm5 ADR R1,conv5:STR R1,conv:BL trans:B nextchr
  426.  1340 .comm9 ADR R1,conv9:STR R1,conv:BL trans:B nextchr
  427.  1350 .grafix
  428.  1360 EQUD &01000000:EQUD &00000001:EQUD &00FFFFFF:EQUD &FFFFFF00
  429.  1370 EQUD &01010100:EQUD &00010101:EQUD &000000FF:EQUD &FF000000
  430.  1380 EQUD &01010101:EQUD &01010101:EQUD &00000000:EQUD &00000000
  431.  1390 EQUD &01010102:EQUD &03010101:EQUD &00000000:EQUD &00000000
  432.  1400 EQUD &01020202:EQUD &03030301:EQUD &00000000:EQUD &00000000
  433.  1410 EQUD &02020202:EQUD &03030303:EQUD &00000000:EQUD &00000000
  434.  1420 EQUD &02020202:EQUD &03030303:EQUD &00000000:EQUD &00000000
  435.  1430 EQUD &02020202:EQUD &03030303:EQUD &00000000:EQUD &00000000
  436.  1440 EQUD &02020200:EQUD &00030303:EQUD &000000FF:EQUD &FF000000
  437.  1450 EQUD &02000000:EQUD &00000003:EQUD &00FFFFFF:EQUD &FFFFFF00
  438.  1460 .grafixO
  439.  1470 EQUD &01000000:EQUD &00000001:EQUD &00FFFFFF:EQUD &FFFFFF00
  440.  1480 EQUD &01010100:EQUD &00010101:EQUD &000000FF:EQUD &FF000000
  441.  1490 EQUD &01010101:EQUD &01010101:EQUD &00000000:EQUD &00000000
  442.  1500 EQUD &01010102:EQUD &03010101:EQUD &00000000:EQUD &00000000
  443.  1510 EQUD &01020202:EQUD &03030301:EQUD &00000000:EQUD &00000000
  444.  1520 EQUD &02020202:EQUD &03030303:EQUD &00000000:EQUD &00000000
  445.  1530 EQUD &02020202:EQUD &03030303:EQUD &00000000:EQUD &00000000
  446.  1540 EQUD &02020202:EQUD &03030303:EQUD &00000000:EQUD &00000000
  447.  1550 EQUD &02020200:EQUD &00030303:EQUD &000000FF:EQUD &FF000000
  448.  1560 EQUD &02000000:EQUD &00000003:EQUD &00FFFFFF:EQUD &FFFFFF00
  449.  1570 .block EQUD 69
  450.  1580 .char EQUD 0:EQUD 0
  451.  1590 .count EQUD 0
  452.  1600 .countapply EQUD buffer
  453.  1610 .buffad EQUD buffer
  454.  1620 .buffad2 EQUD buffer+6912
  455.  1630 EQUB 0:EQUB 0:EQUB 0
  456.  1640 .parablock EQUB 3
  457.  1650 .screenoff EQUD 0
  458.  1660 .screenstartabs EQUD &1FEC000
  459.  1670 .screenstart EQUD &1FEC000
  460.  1680
  461.  1681 ; main scroll routine - only scrolls left and down for the minute
  462.  1690
  463.  1700 .scrollLEFTword
  464.  1710 MOV R0,#19:SWI "OS_Byte"                      ; VSYNC
  465.  1720 SWI 22                                        ; OS_EnterOS - need
  466.  1730 MOVNV R0,R0                                   ; Supervisor mode for this!
  467.  1740 LDR R11,screenstartabs:RSB R11,R11,#&2000000  ; R11 = screen buf size
  468.  1750 LDR R0,screenstart:ADD R0,R0,#4               ; move screenstart 4 right
  469.  1760 SUB R0,R0,#640                                ; and 2 up
  470.  1770 CMP R0,#&2000000:SUBHS R0,R0,R11              ; make sure it's in the
  471.  1771                                               ; screen buffer
  472.  1780 LDR R1,screenstartabs                         ; make sure it's in the
  473.  1790 CMP R0,R1:ADDLO R0,R0,R11                     ; screen buffer
  474.  1800 STR R0,screenstart                            ; and update variable
  475.  1810 MOV R2,R0,LSR #1:AND R2,R2,#6                 ; get pixels/2 across
  476.  1811                                               ; from window
  477.  1812                                               ; (shift of 0-7)
  478.  1820 RSB R2,R2,#66                                 ; calc. timing from left
  479.  1821                                               ; HSYNC
  480.  1830 MOV R2,R2,ASL #14                             ; shift into VIDC format
  481.  1840 ORR R2,R2,#&8C000000:MOV R1,#&03400000        ; get VIDC reg no,
  482.  1850 STR R2,[R1]                                   ; store!
  483.  1860 ADD R2,R2,#&04000000                          ; get right side reg
  484.  1870 ADD R2,R2,#&00280000:STR R2,[R1]              ; add size of screen &
  485.  1871                                               ; store
  486.  1880 MOV R2,#(68<<14):ORR R2,R2,#&88000000:STR R2,[R1]  ; border offset L ...
  487.  1890 ADD R2,R2,#(320-12)<<13:ADD R2,R2,#&0C000000:STR R2,[R1] ; and right
  488.  1900 LDR R1,screenoff                              ; get screen offset
  489.  1910 TST R0,#15                                    ; if screenstart is 0 MOD 16
  490.  1920 ADDEQ R1,R1,#16                               ; then add 16 to screen off
  491.  1930 SUBS R1,R1,#640:ADDMI R1,R1,R11               ; sub 640 (2 lines) and
  492.  1931                                               ; realign if overflow off
  493.  1932                                               ; screen base
  494.  1940 CMP R1,R11:SUBHS R1,R1,R11:STR R1,screenoff   ; then update variable
  495.  1950 MOV R0,#22:ADR R1,parablock:SWI "OS_Word"     ; update MEMC screen addr
  496.  1960 LDR R0,screenstart                            ; get screenstart
  497.  1970 SUB R0,R0,#4                                  ; sub 4
  498.  1980 LDR R1,screenstartabs                         ; get top of screen mem
  499.  1990 CMP R0,R1:ADDLO R0,R0,R11                     ; align screenstart
  500.  2000 STMFD R13!,{R0}                               ; save
  501.  2010 LDR R9,offsetr                                ; rest is scrolling code
  502.  2020 LDR R8,count:MOV R8,R8,LSR #1:ADD R8,R8,R9    ; to print the invisible
  503.  2030 MOV R11,R8                                    ; line for the next time
  504.  2040 MOV R1,#0                                     ; around ....
  505.  2050 .loopP1
  506.  2060 STR R1,[R0],#320:SUBS R8,R8,#1:BNE loopP1
  507.  2070 LDR R8,count:LDR R9,countapply:ADD R9,R9,R8:ADD R10,R9,#3456
  508.  2080 MOV R12,#72
  509.  2090 .loopP2
  510.  2100 LDR R1,[R9],#48:STR R1,[R0],#320
  511.  2110 LDR R1,[R9],#48:STR R1,[R0],#320
  512.  2120 LDR R1,[R9],#48:STR R1,[R0],#320
  513.  2130 LDR R1,[R9],#48:STR R1,[R0],#320
  514.  2140 LDR R1,[R9],#48:STR R1,[R0],#320
  515.  2150 LDR R1,[R9],#48:STR R1,[R0],#320
  516.  2160 LDR R1,[R9],#48:STR R1,[R0],#320
  517.  2170 LDR R1,[R9],#48:STR R1,[R0],#320
  518.  2180 SUBS R12,R12,#8:BNE loopP2
  519.  2190 ADD R11,R11,#72
  520.  2200 MOV R1,#0
  521.  2210 .loopP3
  522.  2220 STR R1,[R0],#320:ADD R11,R11,#1:CMP R11,#128:BNE loopP3
  523.  2230 LDR R1,col1:LDR R2,adder:LDMFD R13!,{R8}
  524.  2240 MOV R3,#0:MOV R4,#0:MOV R5,#0:MOV R6,#0
  525.  2250 ADD R8,R8,#320
  526.  2260 STMIA R8!,{R3-R6}:STMIA R8!,{R3-R6}
  527.  2270 STMIA R8!,{R3-R6}:STMIA R8!,{R3-R6}
  528.  2280 SUB R8,R8,#384
  529.  2290 STMIA R8!,{R3-R6}:STMIA R8!,{R3-R6}
  530.  2300 STMIA R8!,{R3-R6}:STMIA R8!,{R3-R6}
  531.  2310 .loopP4
  532.  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
  533.  2330 MOV R1,R1,ASL #16:MOV R1,R1,LSR #16:STR R1,[R0]:STR R1,[R8,#316]
  534.  2340 TEQP PC,#0:MOVNV R0,R0
  535.  2350 MOV PC,R14
  536.  2360 .col1 EQUD &01010000
  537.  2370 .adder EQUD &01010101
  538.  2380 .const1 EQUD 320*72
  539.  2390 .minispace MOV R0,#8:STR R0,nextcount:B nextchr
  540.  2400 .nextcount EQUD 40
  541.  2410 .notpending CMP R0,#32
  542.  2420 MOVNE PC,R14
  543.  2430 STMFD R13!,{R14}
  544.  2440 BL gen_part2
  545.  2450 MOV R0,#0:STR R0,count
  546.  2460 LDR R0,buffad:STR R0,countapply
  547.  2470 LDR R0,nextoffsetr:STR R0,offsetr
  548.  2480 LDMFD R13!,{PC}
  549.  2490 .scroll LDR R0,count:ADD R0,R0,#4
  550.  2500 LDR R1,nextcount:CMP R0,R1:MOVEQ R0,#28
  551.  2510 STR R0,count
  552.  2520 CMP R0,#28:BNE notpending
  553.  2530 MOV R1,#40:STR R1,nextcount
  554.  2540 STMFD R13!,{R14}
  555.  2550 .nextchr
  556.  2560 LDR R0,textptr:LDRB R1,[R0],#1:STR R0,textptr
  557.  2570 CMP R1,#32:BLO command
  558.  2580 STR R1,block
  559.  2590 BL generate
  560.  2600 LDMFD R13!,{PC}
  561.  2610 .command CMP R1,#12:BHI nextchr
  562.  2620 ADD PC,PC,R1,ASL #2
  563.  2630 B nextchr
  564.  2640 B resettext
  565.  2650 B comm1
  566.  2660 B comm2
  567.  2670 B comm3
  568.  2680 B comm4
  569.  2690 B comm5
  570.  2700 B thick1
  571.  2710 B thick2
  572.  2720 B offset
  573.  2730 B comm9
  574.  2740 B minispace
  575.  2750 B slow
  576.  2760 B fast
  577.  2770 .offset LDR R0,textptr:LDRB R1,[R0],#1:STR R0,textptr
  578.  2780 STR R1,nextoffsetr
  579.  2790 B nextchr
  580.  2800 .offsetr EQUD 20
  581.  2810 .nextoffsetr EQUD 20
  582.  2820 .resettext
  583.  2830 LDR R0,textinit:STR R0,textptr:B nextchr
  584.  2840 .demo
  585.  2850 STMFD R13!,{R14}
  586.  2860 SWI &116:SWI &10D:SWI "OS_RemoveCursors"
  587.  2870 MOV R0,#0:MOV R1,#1024:SWI "OS_UpdateMEMC"  ; screen off
  588.  2880 MOV R0,#100
  589.  2890 .loopdemo1
  590.  2900 STMFD R13!,{R0}
  591.  2910 BL scrollLEFTword+8                         ; scroll without waiting
  592.  2920 BL scrollLEFTword+8                         ; for VSYNC - this fills
  593.  2930 BL scrollLEFTword+8                         ; the screen with the
  594.  2940 BL scrollLEFTword+8                         ; background
  595.  2950 LDMFD R13!,{R0}
  596.  2960 SUBS R0,R0,#4:BNE loopdemo1
  597.  2970 MOV R0,#19:SWI "OS_Byte"                    ; wait a little while
  598.  2980 MOV R0,#19:SWI "OS_Byte"
  599.  2990 MOV R0,#19:SWI "OS_Byte"
  600.  3000 MOV R0,#19:SWI "OS_Byte"
  601.  3010 MOV R0,#19:SWI "OS_Byte"
  602.  3020 MOV R0,#19:SWI "OS_Byte"
  603.  3030 MOV R0,#19:SWI "OS_Byte"
  604.  3040 MOV R0,#19:SWI "OS_Byte"
  605.  3050 MOV R0,#19:SWI "OS_Byte"
  606.  3060 MOV R0,#19:SWI "OS_Byte"
  607.  3070 MOV R0,#1024:MOV R1,#1024:SWI "OS_UpdateMEMC" ; screen on
  608.  3080 BL music                                      ; (music on)
  609.  3090 .loopdemo
  610.  3100 BL scroll                                     ; calc
  611.  3110 BL scrollLEFTword                             ; scroll
  612.  3120 LDR R0,speed:CMP R0,#2:BNE notfast
  613.  3130 BL scroll                                     ; calc some more
  614.  3140 BL scrollLEFTword+8                           ; scroll without VSYNC
  615.  3150 .notfast
  616.  3160 BL music+4                                    ; update music
  617.  3170 MOV R0,#129:MOV R1,#0:MOV R2,#0:SWI "OS_Byte" ; get ESCAPE
  618.  3180 CMP R2,#27:BNE loopdemo                       ; if not, loop
  619.  3190 BL music+8                                    ; kill music
  620.  3200 LDMFD R13!,{PC}                               ; die
  621.  3210 .slow MOV R0,#1:STR R0,speed:B nextchr
  622.  3220 .fast MOV R0,#2:STR R0,speed:B nextchr
  623.  3230 .speed EQUD 1
  624.  3240 .textptr EQUD text
  625.  3250 .textinit EQUD realtext
  626.  3260 .text
  627.  3270 EQUS "          "
  628.  3280 .realtext
  629.  3290 EQUB 1:EQUB 7:EQUB 8:EQUB 20
  630.  3300 EQUS "Welcome to ........ "
  631.  3310 EQUB 5:EQUS "Crap Demo #3":EQUB 1:EQUS " !!!!! "
  632.  3320 EQUS "Written by "
  633.  3330 EQUB 6:EQUB 2:EQUS "Mike Edwards":EQUB 7:EQUB 1
  634.  3340 EQUS ", for a "
  635.  3350 EQUB 9
  636.  3360 EQUB 8:EQUB 20:EQUS "L":EQUB 10:EQUB 32
  637.  3370 EQUB 8:EQUB 4:EQUS "A":EQUB 10:EQUB 32
  638.  3380 EQUB 8:EQUB 20:EQUS "U":EQUB 10:EQUB 32
  639.  3390 EQUB 8:EQUB 36:EQUS "G":EQUB 10:EQUB 32
  640.  3400 EQUB 8:EQUB 20:EQUS "H":EQUB 10:EQUB 32
  641.  3410 EQUB 1
  642.  3420 EQUS " on the 27th of December "
  643.  3430 EQUS "1990, using lots of dodgy programming techniques, etc. "
  644.  3440 EQUS "Every 50th of a second, the screen is scrolling in this direction "
  645.  3450 EQUS "and a strip of letter is added onto the right-hand end. These "
  646.  3460 EQUS "strips are calculated letter by letter, behind the previous letter "
  647.  3470 EQUS "and then plotted. The big letters are not kept in memory (a full "
  648.  3480 EQUS "character set would take 576K!!!) but calculated from the system "
  649.  3490 EQUS "font. Hence, to change this font all you have to do is change the "
  650.  3500 EQUS "system font!!! Also, I'm not using any "
  651.  3510 EQUB 4:EQUS "shadow":EQUB 1
  652.  3520 EQUS " screens. At the end of this scrolltext, I'll print all 224 "
  653.  3530 EQUS "characters, just to prove that I'm not storing them (this would "
  654.  3540 EQUS "take 1344K!). The calculation is split up into two halves, one "
  655.  3550 EQUS "just before a character is needed and one when it is "
  656.  3560 EQUS "needed (the complete calculation takes too long, and there's all "
  657.  3570 EQUS "this time going spare between letters! Anyway, I'd better be "
  658.  3580 EQUS "going as it's now the 28th of December (i.e. past bedtime!) and "
  659.  3590 EQUS "I'm bored of writing this scrolltext. Write to : "
  660.  3600 EQUB 5:EQUS "Mike ":EQUB 9:EQUS """Eddie""":EQUB 5
  661.  3610 EQUS " Edwards, Christ's College, Cambridge ":EQUB 1
  662.  3620 EQUS "  Lots of love and kisses, Eddie xxx    Now here's the entire "
  663.  3630 EQUS "character set (as promised):           "
  664.  3640 EQUB 3:EQUB 12:EQUB 6
  665.  3650 .chrsetentire
  666.  3660 ]
  667.  3670 P%+=224
  668.  3680 [OPT i%
  669.  3690 EQUS "            "
  670.  3700 EQUB 11:EQUB 7
  671.  3710 EQUB 1
  672.  3720 EQUS "   Time to replay ... "
  673.  3730 EQUB 0
  674.  3740 ALIGN
  675.  3750 .buffer
  676.  3760 ]
  677.  3770 P%+=3456*4
  678.  3780 [OPT i%
  679.  3790 .music
  680.  3800 MOV PC,R14
  681.  3810 MOV PC,R14
  682.  3820 MOV PC,R14
  683.  3830 ]
  684.  3840 NEXT
  685.  3850 FOR i%=0 TO 3455 STEP 4
  686.  3860 buffer!i%=0:buffer!(i%+3456)=-1
  687.  3870 NEXT
  688.  3880 FOR i%=0 TO 223:chrsetentire?i%=i%+32:NEXT
  689.  3890 CALL delocate
  690.  3900 OSCLI("Save CrapDemo3 "+STR$~code%+" "+STR$~P%)
  691.  3910 OSCLI("Settype CrapDemo3 Absolute")
  692.  3920 CALL locate
  693.  3930 CALL demo
  694.  3940 END
  695.  3950 REM >%.Assemprims.LocDeloc
  696.  3960 DEF FNlocdeloc(opt%,maincode%,video%)
  697.  3970 [OPT opt%
  698.  3980 .top
  699.  3990 SWI "OS_GetEnv"
  700.  4000 MOV R13,R1
  701.  4010 BL locate
  702.  4020 BL maincode%
  703.  4030 BL delocate
  704.  4040 SWI "OS_Exit"
  705.  4050 .locate
  706.  4060 SWI &116:SWI &100:SWI "OS_RemoveCursors"
  707.  4070 ADR R0,list:ADR R1,vdu
  708.  4080 SWI "OS_ReadVduVariables"
  709.  4090 ADR R0,top:ADR R1,vidlist:LDR R2,vdu
  710.  4100 .loopL1
  711.  4110 LDR R3,[R1],#4:CMP R3,#0:BEQ nextbitL
  712.  4120 ADD R3,R3,R0:LDR R4,[R3]:ADD R4,R4,R2:STR R4,[R3]
  713.  4130 B loopL1
  714.  4140 .nextbitL
  715.  4150 ADR R1,EQUDlist
  716.  4160 .loopL2
  717.  4170 LDR R3,[R1],#4:CMP R3,#0:MOVEQ PC,R14
  718.  4180 ADD R3,R3,R0:LDR R4,[R3]:ADD R4,R4,R0:STR R4,[R3]
  719.  4190 B loopL2
  720.  4200 .list EQUD 149:EQUD -1
  721.  4210 .vdu EQUD video%
  722.  4220 .delocate
  723.  4230 ADR R0,top:ADR R1,vidlist:LDR R2,vdu
  724.  4240 .loopDL1
  725.  4250 LDR R3,[R1],#4:CMP R3,#0:BEQ nextbitDL
  726.  4260 ADD R3,R3,R0:LDR R4,[R3]:SUB R4,R4,R2:STR R4,[R3]
  727.  4270 B loopDL1
  728.  4280 .nextbitDL
  729.  4290 ADR R1,EQUDlist
  730.  4300 .loopDL2
  731.  4310 LDR R3,[R1],#4:CMP R3,#0:MOVEQ PC,R14
  732.  4320 ADD R3,R3,R0:LDR R4,[R3]:SUB R4,R4,R0:STR R4,[R3]
  733.  4330 B loopDL2
  734.  4340 .vidlist
  735.  4350 EQUD screenstartabs-top
  736.  4360 EQUD screenstart-top
  737.  4370 EQUD 0
  738.  4380 .EQUDlist
  739.  4390 EQUD conv-top
  740.  4400 EQUD countapply-top
  741.  4410 EQUD buffad-top
  742.  4420 EQUD buffad2-top
  743.  4430 EQUD textptr-top
  744.  4440 EQUD textinit-top
  745.  4450 EQUD 0
  746.  4460 ]
  747.  4470 =0
  748.  
  749.