Double buffering on the Spectrum
Re: Double buffering on the Spectrum
Hi Giorgio! Welcome to the forums!
This discussion about floating bus is certainly very interesting.
I would have one advice to beginner programmers however. Don't mess with with floating bus It's a rather advanced trick. Joffa games were generally a piece of quite sophisticated code.
A "normal", typical game did it this way:
1) It keeps a screen buffer somewhere in memory
2) It draws to this buffer as fast as it can but usually longer than one frame
3) When it's ready it copies the buffer to screen by series of LDI commands without any synchronisation with screen refresh
Copying buffer to screen may alone take more than one frame so some artifacts on screen may happen. And the final framerate was around 12.5 fls or so.
It all may sound very rough and crude but in practice it worked and the result was acceptable.
This discussion about floating bus is certainly very interesting.
I would have one advice to beginner programmers however. Don't mess with with floating bus It's a rather advanced trick. Joffa games were generally a piece of quite sophisticated code.
A "normal", typical game did it this way:
1) It keeps a screen buffer somewhere in memory
2) It draws to this buffer as fast as it can but usually longer than one frame
3) When it's ready it copies the buffer to screen by series of LDI commands without any synchronisation with screen refresh
Copying buffer to screen may alone take more than one frame so some artifacts on screen may happen. And the final framerate was around 12.5 fls or so.
It all may sound very rough and crude but in practice it worked and the result was acceptable.
Re: Double buffering on the Spectrum
Did Joffa Smith ever talk about or write on how he wrote his games?
Re: Double buffering on the Spectrum
He made some comments here and there but not very detailed.Did Joffa Smith ever talk about or write on how he wrote his games?
In my opinion he was generally a very modest man. He would probably say you that all his tricks were nothing special and not worth to get excited about.
Re: Double buffering on the Spectrum
Kind of like an anti Ian Weatherburn then (personality wise).
One of the most frustrating things trying to find out about N.O.M.A.D was the main developer had left nothing behind about how he wrote the game. It was weird that for a guy that was so sure of his own genius that he didn't talk about his process more before he became An Hero after Canvas folded.
One of the most frustrating things trying to find out about N.O.M.A.D was the main developer had left nothing behind about how he wrote the game. It was weird that for a guy that was so sure of his own genius that he didn't talk about his process more before he became An Hero after Canvas folded.
- Ast A. Moore
- Rick Dangerous
- Posts: 2641
- Joined: Mon Nov 13, 2017 3:16 pm
Re: Double buffering on the Spectrum
Okay, a write-up on the subject of the floating bus, as promised.
Every man should plant a tree, build a house, and write a ZX Spectrum game.
Author of A Yankee in Iraq, a 50 fps shoot-’em-up—the first game to utilize the floating bus on the +2A/+3,
and zasm Z80 Assembler syntax highlighter.
Author of A Yankee in Iraq, a 50 fps shoot-’em-up—the first game to utilize the floating bus on the +2A/+3,
and zasm Z80 Assembler syntax highlighter.
Re: Double buffering on the Spectrum
Was Steve Wetherill also able to figure out the trick for SideWize?
Re: Double buffering on the Spectrum
Joffa did give some loose notes on how he did his scrolling, but they were such that you'd only really understand it if you tried to program it yourself. I had a few private exchanges with him and here are the basics that I gleaned. I didn't actually get anything from him about the floating bus, so I don't know when or where he used it. Much of what I understood was simply down to timing of the program code.
His general approach was for a 25fps update rate, which worked as follows:
1. Wait for an interrupt.
2. Do some pre-processing of various stuff. This is a delay whilst the raster reaches the first line of the screen, so could be using the floating bus. This may involve sorting the sprites into vertical order.
3. Redraw the scrolling level scenery line-by-line from the top down, just behind the raster. Any sprites are erased by this scenery wipe. This is inevitably slower than the raster so by the time it finishes, the raster will be well into the lower scoreboard, if not the lower border or even the next TV frame.
4. Draw the sprites as fast as possible, hopefully before the raster catches up with their positions - hence the vertical sorting earlier. Fully expect the next frame interrupt to occur while this is going on, if it hasn't already.
5. Make sound effects. Rig the system so the next interrupt breaks out of the sound routine and loops back to 2.
Sprites were generally only placeable at 2-pixel positions (4 pre-shifted frames horizontally, data stored in a left-right/right-left zig-zag form with masks and drawn two rows at a time). There were enough black-attribute columns either side for the screen to mask off sprites that went outside the scenery area.
For games, specifically:
Green Beret -
Used an 8-character high buffered strip that was pixel-scrolled horizontally, filled in at the edge from scenery data, and copied to the screen. Don't know if the scroll and copy were done simultaneously or if the scroll was done, then POP+PUSH used to copy it. The top third of the screen is simply erased. The rockets are made to protrude slightly higher into the empty sky by adding sprites to their tips.
Hysteria
Like Green Beret, used an 8-character high strip pixel-scrolled horizontally and copied to the screen. But some of the extra space was filled in by parallax patterns at the bottom of the screen. These are simply 16-bit values repeatedly PUSHed across the screen. Note how the sprites that are supposed to be sat on the background judder slightly as they move in 2-pixel resolution compared to the scenery's 1-pixel movement. Note also you can grab items off the background, though you're actually running along the strip of ground in front that's moving in 2-pixel steps.
Cobra
This one is more complicated - there is no background buffer; the scenery is redrawn from scratch each frame. There are a very limited number of scenic blocks, but it's actually quicker than a scroll+copy. Note also that the scenery now scrolls in 2-pixel steps.
The pre-shifted scenery blocks are loaded into the registers AF, BC, DE and HL then the scenery is drawn by a series of PUSHes, PUSHing the relevant pattern onto the screen at that point. It's wasteful as a scrolling pattern may be half-in and half-out of a character position. So the patterns for solid platforms might be:
AF = empty space
BC = start of platform
DE = continuous platform
HL = end of platform
But before this happens, the program must first re-write the list of PUSH instructions to match the level data. The PUSH list for each row of scenery blocks is re-used to draw all 16 pixel rows. It only has to POP four registers to fetch the scenery patterns for an entire pixel row, so it's quicker that using POP+PUSH to copy a row of data (just as many PUSHes, but fewer POPs).
The scroll can also draw things one-character over, so it only needs scenery pre-shifted to 4 positions (to cover each pattern moving across 8 pixels, not 16). The blacked-off borders either side of the screen are uneven; there's an extra character on one side to hide the scenery redraw moving about, as well as any sprite overlap.
It can have a different set of patterns on each row of the screen, and because of the character-position adjustment it can have either:
- one pattern that can be repeated to any length (e.g. platforms which need 3 pre-shifted patterns to start, repeat and end)
- or 3 separate patterns of a narrow upright object (e.g. pipes up to 10 pixels wide, which always just fit within one 16 pixel wide pre-shifted block)
- or one platform that must start and end within 24 pixels and one narrow upright object.
Finally, there's a faster parallax bit at the bottom of the screen drawn by just PUSHing a 16-bit wide pattern right across the screen. This is programmed to occur twice per game cycle. The result is that this part scrolls at 50fps, making everything seem a bit smoother.
His general approach was for a 25fps update rate, which worked as follows:
1. Wait for an interrupt.
2. Do some pre-processing of various stuff. This is a delay whilst the raster reaches the first line of the screen, so could be using the floating bus. This may involve sorting the sprites into vertical order.
3. Redraw the scrolling level scenery line-by-line from the top down, just behind the raster. Any sprites are erased by this scenery wipe. This is inevitably slower than the raster so by the time it finishes, the raster will be well into the lower scoreboard, if not the lower border or even the next TV frame.
4. Draw the sprites as fast as possible, hopefully before the raster catches up with their positions - hence the vertical sorting earlier. Fully expect the next frame interrupt to occur while this is going on, if it hasn't already.
5. Make sound effects. Rig the system so the next interrupt breaks out of the sound routine and loops back to 2.
Sprites were generally only placeable at 2-pixel positions (4 pre-shifted frames horizontally, data stored in a left-right/right-left zig-zag form with masks and drawn two rows at a time). There were enough black-attribute columns either side for the screen to mask off sprites that went outside the scenery area.
For games, specifically:
Green Beret -
Used an 8-character high buffered strip that was pixel-scrolled horizontally, filled in at the edge from scenery data, and copied to the screen. Don't know if the scroll and copy were done simultaneously or if the scroll was done, then POP+PUSH used to copy it. The top third of the screen is simply erased. The rockets are made to protrude slightly higher into the empty sky by adding sprites to their tips.
Hysteria
Like Green Beret, used an 8-character high strip pixel-scrolled horizontally and copied to the screen. But some of the extra space was filled in by parallax patterns at the bottom of the screen. These are simply 16-bit values repeatedly PUSHed across the screen. Note how the sprites that are supposed to be sat on the background judder slightly as they move in 2-pixel resolution compared to the scenery's 1-pixel movement. Note also you can grab items off the background, though you're actually running along the strip of ground in front that's moving in 2-pixel steps.
Cobra
This one is more complicated - there is no background buffer; the scenery is redrawn from scratch each frame. There are a very limited number of scenic blocks, but it's actually quicker than a scroll+copy. Note also that the scenery now scrolls in 2-pixel steps.
The pre-shifted scenery blocks are loaded into the registers AF, BC, DE and HL then the scenery is drawn by a series of PUSHes, PUSHing the relevant pattern onto the screen at that point. It's wasteful as a scrolling pattern may be half-in and half-out of a character position. So the patterns for solid platforms might be:
AF = empty space
BC = start of platform
DE = continuous platform
HL = end of platform
But before this happens, the program must first re-write the list of PUSH instructions to match the level data. The PUSH list for each row of scenery blocks is re-used to draw all 16 pixel rows. It only has to POP four registers to fetch the scenery patterns for an entire pixel row, so it's quicker that using POP+PUSH to copy a row of data (just as many PUSHes, but fewer POPs).
The scroll can also draw things one-character over, so it only needs scenery pre-shifted to 4 positions (to cover each pattern moving across 8 pixels, not 16). The blacked-off borders either side of the screen are uneven; there's an extra character on one side to hide the scenery redraw moving about, as well as any sprite overlap.
It can have a different set of patterns on each row of the screen, and because of the character-position adjustment it can have either:
- one pattern that can be repeated to any length (e.g. platforms which need 3 pre-shifted patterns to start, repeat and end)
- or 3 separate patterns of a narrow upright object (e.g. pipes up to 10 pixels wide, which always just fit within one 16 pixel wide pre-shifted block)
- or one platform that must start and end within 24 pixels and one narrow upright object.
Finally, there's a faster parallax bit at the bottom of the screen drawn by just PUSHing a 16-bit wide pattern right across the screen. This is programmed to occur twice per game cycle. The result is that this part scrolls at 50fps, making everything seem a bit smoother.
- Ast A. Moore
- Rick Dangerous
- Posts: 2641
- Joined: Mon Nov 13, 2017 3:16 pm
Re: Double buffering on the Spectrum
I think he only used it in Cobra and Terra Cresta. Both use the same code:
Code: Select all
ld bc,$3f28 ;Cobra
1$ ld a,c
in a,($ff)
cp b
jr nc,1$
ld c,$28 ;Terra Cresta
ld b,$3f
1$ ld a,c
in a,($ff)
cp b
jr nc,1$
Yes, he was. Sidewize was never re-released, though. So it hangs on a +2A. Steve’s code is as follows:
Code: Select all
ld bc,$40ff
ld e,$40 ;BRIGHT BLACK INK on BLACK PAPER
sync ld a,r ;padding instruction
in a,(c)
cp e
jp nz,sync
Every man should plant a tree, build a house, and write a ZX Spectrum game.
Author of A Yankee in Iraq, a 50 fps shoot-’em-up—the first game to utilize the floating bus on the +2A/+3,
and zasm Z80 Assembler syntax highlighter.
Author of A Yankee in Iraq, a 50 fps shoot-’em-up—the first game to utilize the floating bus on the +2A/+3,
and zasm Z80 Assembler syntax highlighter.
Re: Double buffering on the Spectrum
I didn't fully appreciate that Sidewize / Crosswize run at 50fps.
That's a lot of scenery and sprites being redrawn. I can see that Sidewize uses a block of scenery that repeats several times across the screen, and I know Crosswize multi-loads, so it's probably not being super-efficient with memory, but nevertheless 50fps is quite an achievement!
That's a lot of scenery and sprites being redrawn. I can see that Sidewize uses a block of scenery that repeats several times across the screen, and I know Crosswize multi-loads, so it's probably not being super-efficient with memory, but nevertheless 50fps is quite an achievement!
- Ast A. Moore
- Rick Dangerous
- Posts: 2641
- Joined: Mon Nov 13, 2017 3:16 pm
Re: Double buffering on the Spectrum
Yes, Sidewize was pretty impressive from a technical standpoint. Incidentally, I only learned about it a couple of years ago. It'd somehow slipped under my radar back in the day.Joefish wrote: ↑Tue Apr 17, 2018 7:07 pm I didn't fully appreciate that Sidewize / Crosswize run at 50fps.
That's a lot of scenery and sprites being redrawn. I can see that Sidewize uses a block of scenery that repeats several times across the screen, and I know Crosswize multi-loads, so it's probably not being super-efficient with memory, but nevertheless 50fps is quite an achievement!
What I miss the most in Spectrum games today are ducks. Joffa really knew how to cook ’em.
Every man should plant a tree, build a house, and write a ZX Spectrum game.
Author of A Yankee in Iraq, a 50 fps shoot-’em-up—the first game to utilize the floating bus on the +2A/+3,
and zasm Z80 Assembler syntax highlighter.
Author of A Yankee in Iraq, a 50 fps shoot-’em-up—the first game to utilize the floating bus on the +2A/+3,
and zasm Z80 Assembler syntax highlighter.
Re: Double buffering on the Spectrum
Seems he was using a bright 1 black attribute as delimiter. That's clever:
Me either, but when I've learned about EmuZWin's real FPS indicator, I started to test games, and I loaded Sidewize because I can, and I got instantly blown again about how well it performs.I didn't fully appreciate that Sidewize / Crosswize run at 50fps.
I now notice the flickering, EmuZWin seems not to be doing a great job emulating this.
-
- Drutt
- Posts: 21
- Joined: Thu Jun 13, 2019 11:52 pm
- Location: York, UK
- Contact:
Re: Double buffering on the Spectrum
This is great information, what about when a row changed graphics, how did this work (see image attached)Joefish wrote: ↑Tue Apr 17, 2018 5:15 pm
Cobra
This one is more complicated - there is no background buffer; the scenery is redrawn from scratch each frame. There are a very limited number of scenic blocks, but it's actually quicker than a scroll+copy. Note also that the scenery now scrolls in 2-pixel steps.
The pre-shifted scenery blocks are loaded into the registers AF, BC, DE and HL then the scenery is drawn by a series of PUSHes, PUSHing the relevant pattern onto the screen at that point. It's wasteful as a scrolling pattern may be half-in and half-out of a character position. So the patterns for solid platforms might be:
AF = empty space
BC = start of platform
DE = continuous platform
HL = end of platform
But before this happens, the program must first re-write the list of PUSH instructions to match the level data. The PUSH list for each row of scenery blocks is re-used to draw all 16 pixel rows. It only has to POP four registers to fetch the scenery patterns for an entire pixel row, so it's quicker that using POP+PUSH to copy a row of data (just as many PUSHes, but fewer POPs).
The scroll can also draw things one-character over, so it only needs scenery pre-shifted to 4 positions (to cover each pattern moving across 8 pixels, not 16). The blacked-off borders either side of the screen are uneven; there's an extra character on one side to hide the scenery redraw moving about, as well as any sprite overlap.
It can have a different set of patterns on each row of the screen, and because of the character-position adjustment it can have either:
- one pattern that can be repeated to any length (e.g. platforms which need 3 pre-shifted patterns to start, repeat and end)
- or 3 separate patterns of a narrow upright object (e.g. pipes up to 10 pixels wide, which always just fit within one 16 pixel wide pre-shifted block)
- or one platform that must start and end within 24 pixels and one narrow upright object.
Finally, there's a faster parallax bit at the bottom of the screen drawn by just PUSHing a 16-bit wide pattern right across the screen. This is programmed to occur twice per game cycle. The result is that this part scrolls at 50fps, making everything seem a bit smoother.
Re: Double buffering on the Spectrum
By loading values in the middle of line.robpearmain wrote: ↑Fri Jun 14, 2019 12:07 am
This is great information, what about when a row changed graphics, how did this work (see image attached)
Code: Select all
push bc ; 89d2 c5 $0bts
push af ; 89d3 f5 $0bts
push de ; 89d4 d5 $0bts
push bc ; 89d5 c5 $0bts
push hl ; 89d6 e5 $0bts
push hl ; 89d7 e5 $0bts
push hl ; 89d8 e5 $0bts
ld ($8bf0), sp ; 89d9 ed 73 f0 8b $14ts
ld sp, ix ; 89dd dd f9 $0ats
pop bc ; 89df c1 $0ats
pop de ; 89e0 d1 $0ats
pop af ; 89e1 f1 $0ats
ld sp, ($8bf0) ; 89e2 ed 7b f0 8b $14ts
push af ; 89e6 f5 $0bts
push de ; 89e7 d5 $0bts
push de ; 89e8 d5 $0bts
push de ; 89e9 d5 $0bts
push de ; 89ea d5 $0bts
push de ; 89eb d5 $0bts
push de ; 89ec d5 $0bts
jp $9ced ; 89ed c3 ed 9c $0at
Proud owner of Didaktik M
Re: Double buffering on the Spectrum
Could it really do that?
OK, my 50Hz scrolling demo couldn't, but then there was no 'slack time' in it. I tried to keep mine running at a constant speed, whereas with all its sprites, Cobra varies a lot in execution time. Mine used the alternate registers for an alternate set of platforms, but could only swap them between rows, not columns. I just assumed Cobra did the same.
I did develop some code that used the alternate BC/DE/HL registers (or just as easily AF'/IX/IY) for an extra platform type within a row, but it takes longer to execute.
OK, my 50Hz scrolling demo couldn't, but then there was no 'slack time' in it. I tried to keep mine running at a constant speed, whereas with all its sprites, Cobra varies a lot in execution time. Mine used the alternate registers for an alternate set of platforms, but could only swap them between rows, not columns. I just assumed Cobra did the same.
I did develop some code that used the alternate BC/DE/HL registers (or just as easily AF'/IX/IY) for an extra platform type within a row, but it takes longer to execute.
Re: Double buffering on the Spectrum
maybe not related to topic, but I used another tricks for AY Mehademo 3
http://g0blinish.ucoz.ru/forblog2/mudademo.rar
(sources inside,compile with sjasm)
http://g0blinish.ucoz.ru/forblog2/mudademo.rar
(sources inside,compile with sjasm)
Re: Double buffering on the Spectrum
sorry for necroposting, but i happened to stumble upon Joffa's name here, and simply couldn't stop myself. i reversed Firefly engine around 10 years ago (man, i'm old now!), extracted map blitting parts from it, and even made a simple editor. i intended to use that in my game, but never wrote it. it works mostly like Cobra, using low part of the screen for the status bar, and for floating bus vsyncing. the map is 32x32 tiles of 16x16 pixels, with wraparound.
if anybody's interested, i can try to reverse-engineer my code (i lost most of my notes and such, and my asm source is not really well commented ;-), and publish it here. actually, the code is quite easy to follow (i think ;-), so i may throw in more comments, and turn it into some kind of simple example/tutorial. i think Joffa would be happy to see others learning from his tricks...
if anybody's interested, i can try to reverse-engineer my code (i lost most of my notes and such, and my asm source is not really well commented ;-), and publish it here. actually, the code is quite easy to follow (i think ;-), so i may throw in more comments, and turn it into some kind of simple example/tutorial. i think Joffa would be happy to see others learning from his tricks...
- Ast A. Moore
- Rick Dangerous
- Posts: 2641
- Joined: Mon Nov 13, 2017 3:16 pm
Re: Double buffering on the Spectrum
Curious. I haven’t noticed any floating bus polling in Firefly. Besides, the game runs just fine on a +2A/+3. Do you think you could share the relevant part of Firefly’s code with us?
Every man should plant a tree, build a house, and write a ZX Spectrum game.
Author of A Yankee in Iraq, a 50 fps shoot-’em-up—the first game to utilize the floating bus on the +2A/+3,
and zasm Z80 Assembler syntax highlighter.
Author of A Yankee in Iraq, a 50 fps shoot-’em-up—the first game to utilize the floating bus on the +2A/+3,
and zasm Z80 Assembler syntax highlighter.
Re: Double buffering on the Spectrum
yeah, that may be added by me to have some more time to do things, it is hard to tell now. as i said, i lost most of my notes and oridinal disassemblies, there's only the "final" extracted engine left. if i'll find my original notes, i'll double-check. the blitter itself doesn't really need that, you can simply "chase the beam", of course.
but tbh, i don't keep hight hopes here. i think i used the mix of IDA and my own tools, and i don't have neither IDA, nor those tools anymore.
yeah, judging from git history (which is very short ;-), floating bus vsync was added by me. so sorry for misinformation. still, "builder" and "blitter" code is almost unmodified (and it seems i introduced small bug there...).
when i'll find some more time, i will properly comment it, and will make a post. i think it will be interesting to see how exactly Joffa did his magic. and if i'll find any my old notes, i'll add them.
p.s.: ah, another thing i remember about Firefly is that it is using two types of compression for maps. i don't remember exact algos, but i think that one was your usual RLE, and another one was kind of LZ coding (but somewhat twisted). or maybe just RLE with another counter size.
p.p.s.: yeah, Firefly is one of my favorite Speccy games. i remember seeing its fantastic 8-way smooth scrolling for the first time and dropped my jaw. so dissecting Firefly was a natural choice. ;-)
but tbh, i don't keep hight hopes here. i think i used the mix of IDA and my own tools, and i don't have neither IDA, nor those tools anymore.
yeah, judging from git history (which is very short ;-), floating bus vsync was added by me. so sorry for misinformation. still, "builder" and "blitter" code is almost unmodified (and it seems i introduced small bug there...).
when i'll find some more time, i will properly comment it, and will make a post. i think it will be interesting to see how exactly Joffa did his magic. and if i'll find any my old notes, i'll add them.
p.s.: ah, another thing i remember about Firefly is that it is using two types of compression for maps. i don't remember exact algos, but i think that one was your usual RLE, and another one was kind of LZ coding (but somewhat twisted). or maybe just RLE with another counter size.
p.p.s.: yeah, Firefly is one of my favorite Speccy games. i remember seeing its fantastic 8-way smooth scrolling for the first time and dropped my jaw. so dissecting Firefly was a natural choice. ;-)
- Ast A. Moore
- Rick Dangerous
- Posts: 2641
- Joined: Mon Nov 13, 2017 3:16 pm
Re: Double buffering on the Spectrum
Firefly is by far my favorite Joffa’s game. Pretty brilliant concept and implementation.
Every man should plant a tree, build a house, and write a ZX Spectrum game.
Author of A Yankee in Iraq, a 50 fps shoot-’em-up—the first game to utilize the floating bus on the +2A/+3,
and zasm Z80 Assembler syntax highlighter.
Author of A Yankee in Iraq, a 50 fps shoot-’em-up—the first game to utilize the floating bus on the +2A/+3,
and zasm Z80 Assembler syntax highlighter.
Re: Double buffering on the Spectrum
yeah, i absolutely agree. and it aged very well: it still looks fantastic, and insanely addictive. i never really liked Cobra or Green Beret (excellent technical implementation, but the gameplay is not my cup of tea). but i must confess that i am still playing Firefly from time to time, and it is still as good as it was the first time.Ast A. Moore wrote: ↑Wed Jun 17, 2020 2:53 pm Firefly is by far my favorite Joffa’s game. Pretty brilliant concept and implementation.
randomized world map is a brilliant touch too: it always looks like there are more unexplored maps there, even if you know that there are not so many of them. and each game feels like a fresh one.
eh, i can keep praizing Firefly the whole day... ;-)
Re: Double buffering on the Spectrum
i almost reversed my old code (and put alot more comments in it). there's still one bug left (i have to double-check if it is mine, or i did something the original code wasn't designed for). i'll fix it (i hope ;-), and then i will try to write a post about it all, with code samples and some explanations.
Re: Double buffering on the Spectrum
sorry for bumping, but i want to say that i'm still working on that post/article. it is somewhat hard to split my time between various things, and i want to explain the code and the idea behind it instead of simply dumping it on you, so it require some more time. basically, i'm going through the code line-by-line, adding explanations where i think they're needed, and creating a small sample game to show how one can connect all the pieces together to get something interesting.
it looks like in becomes more a kind of Yet Another Game Programming Tutorial, this time for people who know the asm, and want to do some advanced stuff. dunno if the world needs another one of those, but at least creating it is fun.
it looks like in becomes more a kind of Yet Another Game Programming Tutorial, this time for people who know the asm, and want to do some advanced stuff. dunno if the world needs another one of those, but at least creating it is fun.
Re: Double buffering on the Spectrum
I try to speed up my game, which draws to a memory buffer and then it copies it to the screen. It buffers the entire 6912 screen bytes, so I can use a simple ldir, but I also try the push/pop way. I wrote the following routine and it works, but the screen is a bit corrupted - two columns are doubled on the screen and if I move in the game, the screen is more and more corrupted. I admit that I don't really understand how exactly the stack works (I read some explanations, but it's still not clear). Is anything wrong with my routine and should it be faster than ldir?
Code: Select all
di ; disable interrupt
ld (stack),sp ; save stack address
ld ix,buffer ; start of buffer
ld iy,16384+15 ; start of screen + 15
ld a,216 ; loop counter, 216*32=6912
scrcopy ld i,a ; counter to i
ld sp,ix ; stack is on ix in buffer
pop af ; 16 bytes from buffer to registers
pop bc
pop de
pop hl
exx
pop af
pop bc
pop de
pop hl
exx
ld sp,iy ; stack is on iy in screen
exx
push hl ; 16 bytes from registers to screen in reverse order
push de
push bc
push af
exx
push hl
push de
push bc
push af
ld bc,16
add ix,bc ; increase buffer address by 16
add iy,bc ; increase screen address by 16
ld sp,ix ; stack is on ix in buffer
pop af ; 16 bytes from buffer to registers
pop bc
pop de
pop hl
exx
pop af
pop bc
pop de
pop hl
exx
ld sp,iy ; stack is on iy in screen
exx
push hl ; 16 bytes from registers to screen in reverse order
push de
push bc
push af
exx
push hl
push de
push bc
push af
ld bc,16
add ix,bc ; increase buffer address by 16
add iy,bc ; increase screen address by 16
ld a,i ; counter to a
dec a ; decrease counter by 1
jr nz,scrcopy ; if counter is not 0, copy next 32 bytes
ld sp,(stack) ; restore stack address
ei ; enable interrupt
ret
Re: Double buffering on the Spectrum
Hi, Art.
The EXX instruction swaps BC, DE, HL pairs only. AF can swapped by special instruction EX AF,AF'.
What you do is that you load AF register twice from two different locations without swapping and that is why screen get corrupted.
The EXX instruction swaps BC, DE, HL pairs only. AF can swapped by special instruction EX AF,AF'.
What you do is that you load AF register twice from two different locations without swapping and that is why screen get corrupted.
Proud owner of Didaktik M