Log inRegister an accountBrowse CSDbHelp & documentationFacts & StatisticsThe forumsAvailable RSS-feeds on CSDbSupport CSDb Commodore 64 Scene Database
You are not logged in - nap
CSDb User Forums


Forums > CSDb Entries > Release id #171267 : Did you miss us?
2019-04-25 07:25
ChristopherJam

Registered: Aug 2004
Posts: 1238
Release id #171267 : Did you miss us?

OK, so I've had a few people ask how the split bitmap scroller works, and there's been a bit of water under the bridge now, so here goes.


Restrictions and Layout:

Source image is 40x22 chars in size, a standard multicolour bitmap aside from one restriction: every column of d800 needs to be uniform (at the split point there are sometimes four adjacent lines of pixels sourced from four rows of the original image, and no time for d800 updates).

Very nice work from iLKke, who was working without the benefit of an image converter and still managed to stay very close to the constraints I provided, long before I had running code.

The display routine uses one bitmap in each of the four banks. Every bank has the same layout, so $d018 is just set to $18 at the start of the frame, and $dd00 used to select which buffer is currently displayed. Bank 3 is used for the upper half, bank 0 for fixup at the join, and banks 1 & 2 are used to double buffer the rest of the lower half.


Upper Half:

Bank 3 is static, as the top half of the screen is scrolled using a combination of up to ten lines of linecrunch and up to 24 lines of FLD, to produce a range of scroll values from 0..88. I was originally going to use pure FLD, but then I'd need an interrupt every seven lines, and I wasn't sure I could afford the overhead. It also seemed like it'd be more hassle to set up, and I'm lazy.

So, the first 17 badline-capable rasterlines are dedicated to the hardware scrolling, the last line of which is sometimes used to display the first line of pixels (the upper display window runs from line $40 to line $97).


Lower Half:

Most of the lower half of the screen is updated with a high speed blitter, which needs to be able to write the lower image half to any of 23 row positions. It's optimised for the worst case, so always writes 11 image rows plus a blank row, and only loads the accumulator once per value per pointer offset. The stores are all indirect indexed, and the Y register increases from 0 to 63 as the blit proceeds. Whever possible I update the accumulator with a shift instead of a load immediate, to save a little code space. Before the stores start I initialise seven zero page pointers per row: one every 64 bytes of the bitmap, one for the first 24 bytes of the character row, and one for the last 16. The character split allows me to avoid any special case code for the buffer wrap from the linecrunch.

12969 bytes of speed code writes 4280 bytes (11 rows at 360 bytes per row, plus 320 bytes of zeros after the last row) in just 30,804 cycles (including the time to init the zero page pointers), or a mere 7.2 cycles per byte.


The Join:

A few raster lines of fixup are needed at the join. Line $98 is always a badline, and whenever the lower half of the image starts with a partial row, it fetches a rotated row from bank 0. Each frame I update that row from the buffer that's about to be displayed for the lower half. There's then another badline at the start of the first full row in the lower half to return to normal bitmap display.



Miscellany:

The lower half needs updating every time the difference between (upper half scroll)/8 and (lower half scroll)/8 changes. I didn't realise until a few days from release that that means I would have needed to triple buffer in the case of the two halves moving in opposite directions at different speeds (as occasionally the delta changes twice in two frames, and the blitter takes three or four frames to run). By then the memory layout was pretty much set in stone, so I ended up just mirroring the movements whenever top and bottom are both moving out or both moving in at the same time.

All the unrolled loop generation and data conversion was done in Python, with a bit of help from ca65's segment support for doing things like splitting the blitter code across three chunks of memory.

As a few people have noticed, the sine wave for the DYSP is a little squashed; I wanted to make sure I wasn't going too far off the bottom of anyone's monitor while still staying below the display area.

The "presents" screen is 192px wide pseudo-hires five colour image, using a half pixel offset multicolour sprite underlay.



tl;dr: linecruch for the top half, load minimised speedcode for the bottom half, and an extra badline at the join to fetch a software fine-scrolled partial row.
2019-04-25 16:09
Raistlin

Registered: Mar 2007
Posts: 402
Fantastic stuff.

I assume that the lack of replies to this is that everyone, like me, is still confuzzled about how on earth this works ;-)
2019-04-25 16:32
ChristopherJam

Registered: Aug 2004
Posts: 1238
Cheers, Raistlin. I might have to add a diagram at this rate…
2019-04-25 17:02
Golara

Registered: Jan 2018
Posts: 212
Very clever, thanks for the explanation.
2019-04-25 19:46
ChristopherJam

Registered: Aug 2004
Posts: 1238
np, golara.
2019-04-25 19:52
ChristopherJam

Registered: Aug 2004
Posts: 1238
If it helps anyone, here's an example of how the split point works:

Upper bitmap starts on row ten, in order that an FLD of 16 lines would push it down to starting on raster line $90 (ie, just off the bottom of the display window for the upper half).

If there are 10 lines of each of the upper and lower halves, then the lower part will be blitted to rows 1-11 of bank one, and the display around the middle 20 lines of the display area will go something like this:
 +------+-------+------+------+-----+-------+-------------+
 |raster| bank  | row  | line | DMA | source| copied from | 
 | line |       |      |      |     | line  |bank/row/line|
 +------+-------+------+------+-----+-------+-------------+
 |  $86 |   3   |  10  |  0   |  Y  |  $00  |             |
 |  $87 |   3   |  10  |  1   |     |  $01  |             |
 |  $88 |   3   |  10  |  2   |     |  $02  |             |
 |  $89 |   3   |  10  |  3   |     |  $03  |             |
 |  $8a |   3   |  10  |  4   |     |  $04  |             |
 |  $8b |   3   |  10  |  5   |     |  $05  |             |
 |  $8c |   3   |  10  |  6   |     |  $06  |             |
 |  $8d |   3   |  10  |  7   |     |  $07  |             |
 |  $8e |   3   |  11  |  0   |  Y  |  $08  |             |
 |  $8f |   3   |  11  |  1   |     |  $09  |             |
 +------+-------+------+------+-----+-------+-------------+ split is here
 |  $90 |   0   |  11  |  0   |  Y  |  $a6  |    1/10/6   |
 |  $91 |   0   |  11  |  1   |     |  $a7  |    1/10/7   |
 |  $92 |   1   |  11  |  0   |  Y  |  $a8  |             |
 |  $93 |   1   |  11  |  1   |     |  $a9  |             |
 |  $94 |   1   |  11  |  2   |     |  $aa  |             |
 |  $95 |   1   |  11  |  3   |     |  $ab  |             |
 |  $96 |   1   |  11  |  4   |     |  $ac  |             |
 |  $97 |   1   |  11  |  5   |     |  $ad  |             |
 |  $98 |   1   |  11  |  6   |     |  $ae  |             |
 |  $99 |   1   |  11  |  7   |     |  $af  |             |
 +------+-------+------+------+-----+-------+-------------+

Note that row 11 is fetched three times - once from bank 3 for the ninth and tenth lines of the source image, once from bank 0 for the ninth and tenth last lines of the source, then again from bank 1 for the last eight lines of the source.
RefreshSubscribe to this thread:

You need to be logged in to post in the forum.

Search the forum:
Search   for   in  
All times are CET.
Search CSDb
Advanced
Users Online
Didi/Laxity
cryptoboy
Guests online: 38
Top Demos
1 Coma Light 13  (9.6)
2 Edge of Disgrace  (9.6)
3 Bromance  (9.6)
4 Uncensored  (9.6)
5 E2IRA  (9.6)
6 Comaland 100%  (9.6)
7 Lunatico  (9.5)
8 Memento Mori  (9.5)
9 The World Is Not Eno..  (9.5)
10 Unboxed  (9.5)
Top onefile Demos
1 Copper Booze  (9.7)
2 Barry Boomer - Trapp..  (9.6)
3 Lovecats  (9.5)
4 Dawnfall V1.1  (9.5)
5 Daah, Those Acid Pil..  (9.5)
6 Offering  (9.5)
7 Onef1ler 2  (9.5)
8 Plasma Ninja  (9.5)
9 Someone Somewhere  (9.5)
10 Aurora Dreams - The ..  (9.5)
Top Groups
1 Booze Design  (9.4)
2 Crest  (9.3)
3 Oxyron  (9.3)
4 Censor Design  (9.3)
5 Maniacs of Noise  (9.3)
Top Coders
1 Axis  (9.8)
2 Graham  (9.8)
3 HCL  (9.8)
4 Crossbow  (9.8)
5 Jammer  (9.8)

Home - Disclaimer
Copyright © No Name 2001-2022
Page generated in: 0.059 sec.