Changing Border during refresh

Page 1/2
| 2

By tvalenca

Paladin (728)

tvalenca's picture

25-08-2016, 17:37

Today I was wondering about a Spectrum game that I saw once, called "Aqualung" "Aquaplane". This game uses a trick to show 2-color borders on the screen to match the color on the middle of the screen (the top 1/3 of the screen border is light blue to perform the sky, and the bottom 2/3 is dark blue to perform the sea).

Here how it looks:

And here a broken version of this effect so you can understand what's happening:

I was wondering if this is doable on any VDP. Basically, looks like a Split Screen (wait a few cycles after interrupt then change some VDP registers) but is this doable, or the VDP will just freak out? And if it is doable, is there any easier/more MSX oriented way to do this than a busy loop during refresh?

Login or register to post comments

By NYYRIKKI

Enlighted (5541)

NYYRIKKI's picture

25-08-2016, 19:22

Practically busy loop is very bad idea because of 50Hz/60Hz difference + that you miss valuable time. In MSX2 this is trivial to do as there is line interrupt. On MSX1 it is better idea to use sprite collision flag or 5th sprite flag to poll the correct place. You still need to do some kind of busy loop, but you can more easily use the time for something useful (like playing music) as the code does not need to be cycle accurate.

By RetroTechie

Paragon (1563)

RetroTechie's picture

25-08-2016, 19:31

tvalenca wrote:

I was wondering if this is doable on any VDP.

Don't see why not. Producing screen output is a continuous process, and ultimately produced (border) colors have to come from somewhere. Read: from some VDP register.

Quote:

Basically, looks like a Split Screen (wait a few cycles after interrupt then change some VDP registers) but is this doable, or the VDP will just freak out?

Works fine.. change the relevant VDP register, and VDP will output some other color. Do it fast enough, and you have just a few screen lines between color changes. I used this sometimes to monitor tape input signal, very similar to how you can judge tape input on a ZX Spectrum by looking at border patterns. Tbh I never understood why this wasn't implemented as standard tape I/O feature on MSX. It's easy to implement, and very helpful especially with difficult-to-load tapes.

Quote:

And if it is doable, is there any easier/more MSX oriented way to do this than a busy loop during refresh?

On MSX2 and up you could use line interrupts, I think? Edit: argh, NYYRIKKI typed faster... LOL!

By NYYRIKKI

Enlighted (5541)

NYYRIKKI's picture

25-08-2016, 19:42

tvalenca wrote:

but is this doable, or the VDP will just freak out?

It is definitely doable and I consider this kind of changing colors as "Hello World" example to VDP programming, but maybe I've been talking too much with demo coders. Smile Usually programmers use this "trick" to measure time that their individual routines (like music player) takes... Think it as MSX version of Windows task manager's CPU meter. Smile

By DarkSchneider

Paladin (929)

DarkSchneider's picture

25-08-2016, 21:42

Very good that sprite flag trick.

By tvalenca

Paladin (728)

tvalenca's picture

30-08-2016, 20:09

Hi folks,

I have a first working example and a ton of questions... oO

This is my code: (the ASM syntax may be not accurate because I assembled it manually poking the opcodes on RAM)
(edit: I'll use the BlueMSX debugger to get the ASM listing)

9000:   ld     a,#01      
9002:   out    (#99),a    
9004:   ld     a,#8f      
9006:   nop               
9007:   nop               
9008:   out    (#99),a    
900A:   nop               
900B:   nop               
900C:   nop               
900D:   nop               
900E:   in     a,(#99)    
9010:   bit    0,a        
9012:   jr     z,#9020    
9014:   ld     a,#17      
9016:   out    (#99),a    
9018:   ld     a,#87      
901A:   nop               
901B:   nop               
901C:   out    (#99),a    
901E:   jr     #9028      
9020:   ld     a,#f4      
9022:   out    (#99),a    
9024:   ld     a,#87      
9026:   out    (#99),a    
9028:   ld     a,#00      
902A:   out    (#99),a    
902C:   ld     a,#8f      
902E:   nop               
902F:   nop               
9030:   out    (#99),a    
9032:   ret               
9033:   ret               
9034:   ret               
9035:   ret               
9036:   ret               

I used a few NOPs because openMSX complained about writting/reading too fast to the VDP, but the result is basically the same.

After poking this on RAM, I set the H.HEYI hook (&HFD9A) with call #9000 and then a ret. Once the hook is set up, I set VDP registers for line interrupt, first R#19 to line 40 (fifth character line on text mode) and finally set bit 4 on R#0 to activate the int signal generation.

Here's the video shot I made using OpenMSX, the emulated machine is a Panasonic FS-A1WX, and I used SETSCREEN to boot the computer to SCREEN 0:WIDTH 40

https://youtu.be/AdRgkHJtLt8

First thing is: the code takes a little more than 2 scanlines to change the screen color, but this is (almost) ok, I didn't expect the BASIC interrupt handler to dispatch a INT that fast, I don't mind setting the interrupt to fire 2 or 3 lines earlier at all. But I DO MIND with that flicker. when this happened the first time, I imediattely thought that was an issue with too fast VDP writes, and OpenMSX confirmed that I was poking the VDP port too fast, so I added a few NOPS (already on the ASM listing I provided) but it didn't stopped flickering. Is there any way to stop that flickering? or I just have to NOP it all way out of the screen?

Second thing: The video isn't showing but theres another color boundary right below the last text line of the screen. I suppose that there's another INT firing that moment and I don't have any idea where it is coming from, so I tried to place that routine under the H.TIMI hook (&HFD9F) so I could tell if the screen is redrawn before changing back the backdrop color register... but if I do such thing, OpenMSX tells me that it reached a DI; HALT and the emulation freezes. What's happening? I tried to reproduce the error on BlueMSX (because I don't have OpenMSX debugger set on none of my computers) and no matter what I do it doesn't hang (I used the Generic MSX2 machine configuration).

If I try to turn of the color-changing code the BASIC interpreter immediately stops working, no matter what I do. When I investigate this, apparently my code goes wild and start filling the RAM with garbage, which is an odd behaviour because I don't write to the RAM anywere, so I suppose that's an stack overflow. (or it jumped/returned to the middle of something that's make no sense, either code or data) No BIG deal here, but I don't think this should happen.

By tvalenca

Paladin (728)

tvalenca's picture

30-08-2016, 21:56

Doubled post. please delete.

By tvalenca

Paladin (728)

tvalenca's picture

30-08-2016, 22:01

Hi folks,

I have a first working example and a ton of questions... oO

This is my code: (the ASM syntax may be not accurate because I assembled it manually poking the opcodes on RAM)
(edit: I'll use the BlueMSX debugger to get the ASM listing)

9000:   ld     a,#01      
9002:   out    (#99),a    
9004:   ld     a,#8f      
9006:   nop               
9007:   nop               
9008:   out    (#99),a    
900A:   nop               
900B:   nop               
900C:   nop               
900D:   nop               
900E:   in     a,(#99)    
9010:   bit    0,a        
9012:   jr     z,#9020    
9014:   ld     a,#17      
9016:   out    (#99),a    
9018:   ld     a,#87      
901A:   nop               
901B:   nop               
901C:   out    (#99),a    
901E:   jr     #9028      
9020:   ld     a,#f4      
9022:   out    (#99),a    
9024:   ld     a,#87      
9026:   out    (#99),a    
9028:   ld     a,#00      
902A:   out    (#99),a    
902C:   ld     a,#8f      
902E:   nop               
902F:   nop               
9030:   out    (#99),a    
9032:   ret               
9033:   ret               
9034:   ret               
9035:   ret               
9036:   ret               

I used a few NOPs because openMSX complained about writting/reading too fast to the VDP, but the result is basically the same.

After poking this on RAM, I set the H.HEYI hook (&HFD9A) with call #9000 and then a ret. Once the hook is set up, I set VDP registers for line interrupt, first R#19 to line 40 (fifth character line on text mode) and finally set bit 4 on R#0 to activate the int signal generation.

Here's the video shot I made using OpenMSX, the emulated machine is a Panasonic FS-A1WX, and I used SETSCREEN to boot the computer to SCREEN 0:WIDTH 40

https://youtu.be/AdRgkHJtLt8

First thing is: the code takes a little more than 2 scanlines to change the screen color, but this is (almost) ok, I didn't expect the BASIC interrupt handler to dispatch a INT that fast, I don't mind setting the interrupt to fire 2 or 3 lines earlier at all. But I DO MIND with that flicker. when this happened the first time, I imediattely thought that was an issue with too fast VDP writes, and OpenMSX confirmed that I was poking the VDP port too fast, so I added a few NOPS (already on the ASM listing I provided) but it didn't stopped flickering. Is there any way to stop that flickering? or I just have to NOP it all way out of the screen?

Second thing: The video isn't showing but theres another color boundary right below the last text line of the screen. I suppose that there's another INT firing that moment and I don't have any idea where it is coming from, so I tried to place that routine under the H.TIMI hook (&HFD9F) so I could tell if the screen is redrawn before changing back the backdrop color register... but if I do such thing, OpenMSX tells me that it reached a DI; HALT and the emulation freezes. What's happening? I tried to reproduce the error on BlueMSX (because I don't have OpenMSX debugger set on none of my computers) and no matter what I do it doesn't hang (I used the Generic MSX2 machine configuration). EDIT: Just figured this out: I destroyed the contents of A register. Added a PUSH AF before my code and a POP AF at the end of my code and now it runs on H.TIMI without hanging, but now I know that this isn't the best approach for a routine that isn't tied to the 50/60Hz refresh interrupt. I do need a different code here to handle the "alternate color status"... maybe this would improve the original code as well since I won't need the "else case" anymore.

If I try to turn of the color-changing code the BASIC interpreter immediately stops working, no matter what I do. When I investigate this, apparently my code goes wild and start filling the RAM with garbage, which is an odd behaviour because I don't write to the RAM anywere, so I suppose that's an stack overflow. (or it jumped/returned to the middle of something that's make no sense, either code or data) No BIG deal here, but I don't think this should happen.

By Overflow

Resident (57)

Overflow's picture

31-08-2016, 17:12

It reminds me about my first steps on MSX1 two years ago, nice reading, thanks!

Your issue is not one. When the interruptions occurs, it halts the current code/program/whatever. But: before branching to interruption routine, cpu must wait for running opcode to end. The flicker you get depends on how many cpu-cycles were remaining on current/running opcode. On each frame, the opcode which is interrupted is different. So number of cpu-cycles to wait for is different. So you see flicker.

Easiest way to avoid this is: add a few NOPs or so. So that the flicker occurs right or left = in the border which is not seen. This is not a dedicated trick for you or MSX. This is the way it goes for years on other platforms too.

Note: now if you keep changing colors, i.e. only some OUTs in your code, you get some demo tricks such as this one (youtube video - starts at 1min36s).

Regards,
Olivier

By tvalenca

Paladin (728)

tvalenca's picture

31-08-2016, 18:55

Overflow wrote:

It reminds me about my first steps on MSX1 two years ago, nice reading, thanks!

You're very welcome!

Overflow wrote:

Your issue is not one. When the interruptions occurs, it halts the current code/program/whatever. But: before branching to interruption routine, cpu must wait for running opcode to end. The flicker you get depends on how many cpu-cycles were remaining on current/running opcode. On each frame, the opcode which is interrupted is different. So number of cpu-cycles to wait for is different. So you see flicker.

Aw crap! really?

Overflow wrote:

Easiest way to avoid this is: add a few NOPs or so. So that the flicker occurs right or left = in the border which is not seen. This is not a dedicated trick for you or MSX. This is the way it goes for years on other platforms too.

Sure will do it. Do anyone know how much time I have before the VDP begins to plot the next scanline?

Overflow wrote:

Note: now if you keep changing colors, i.e. only some OUTs in your code, you get some demo tricks such as this one (youtube video - starts at 1min36s).

Thanks. I'll have a look later.

Regards
Tiago

By ARTRAG

Enlighted (6368)

ARTRAG's picture

31-08-2016, 19:35

Tiago read also the links on C64 in the other thread about HW capabilities in 80's. The same jittering issue on c64 is solved in many ways.
Look for the sction "Stable Raster Interrupts"
http://z9.io/wp-content/uploads/2008/01/intro-to-programming...

"Double interrupts" seems feasible also on msx. ;)

Page 1/2
| 2