Vera Layers in Assembly

Jestin

New Member
Jan 25, 2020
16
13
3
I've been trying to use the vera's two layers from assembly. I've been able to write data to veradat2 just as easily as veradat1, however they seem to behave differently. Namely, I cannot seem to set the address properly on layer 2, despite selecting it with veractrl. Running the same code on layer 1 vs layer 2 produces the following results:

1581241208022.png

Layer one appears just fine (the petscii x16 in the center), but layer 2 draws from 0,0, and also ignores my code that should take it to the next line. I was ready to assume that there was a bug in my code, and I'm simply not setting things right, when I decided to compare what I was doing to the BASIC layer demo code the x16-demo repo. I know that I've ran this just find sometime in the past, however now I get the following result:

layer_demo_error.gif

This looks suspiciously like what I'm seeing in my own code, making me suspect that the problem is with the current version of the emulator or rom. I'm using r36 for the rom and r36 for the emulator, which otherwise seems to work. Without knowing if the bug is in my own code, I don't want to spend too much time trying to find it.

Am I alone in seeing this error in the layer demo?
 
  • Like
Reactions: JustinBaldock

Jestin

New Member
Jan 25, 2020
16
13
3
After getting some sleep, I decided to wake up and see if I could find the version of the rom/emulator where the layer demo works. At r33 for both projects, things seem to work:

layer_demo_r33.gif

During these tests, I left the x16-demo repo checked out to the latest master (commit b5c4717). There are only 3 commits to the layer demo in the repository, and the most recent was was fix on October 2nd. Meanwhile, r33 of the rom and emulator came out on October 12th, so the layer demo hasn't been updated since r32 was the latest. It looks like something broke during r34. I'm going to keep looking into this, as I'd really like to understand the vera's layers.
 
  • Like
Reactions: JustinBaldock

StephenH

New Member
Feb 4, 2020
6
7
3
The last breaking change I can recall in the emulator was the addition of the VSYNC interrupt, but that shouldn't impact a program written in BASIC, and from a first-glance I'm not immediately seeing what broke it. I can't make "promises", but I'm trying to dive back into X16 programming so maybe I can check this more carefully over the weekend.

If the unofficial VERA documentation I wrote has fallen out-of-date (other than emulator release number), maybe I'll even be motivated to fix it. :p
 
  • Like
Reactions: Jestin

SlithyMatt

New Member
Sep 14, 2019
9
9
3
It sounds like you are confusing the VERA graphics layers with the memory channels. There are two of each, but there is no correlation. You can read and write from either layer with either channel.
 

StephenH

New Member
Feb 4, 2020
6
7
3
Well, as for the layer demo in BASIC, the problem seems to be the call to SYS $9000, and REM'ing it out seemed to make the demo work for me. I'm not sure why, because BASIC's not my jam. I'm about the 6502 assembly. But my guess is that SYS $9000 is attempting to execute kernal code that has been moved or otherwise doesn't exist anymore (or doesn't exist there).

Edit: In short, make the following change:
440 SYS $9000
440 REM SYS $9000
 

Jestin

New Member
Jan 25, 2020
16
13
3
@SlithyMatt, yep, I was confusing that. This explains how the FB_move_pixels function in the kernal is using veradat2. I was referencing that because it was one of the only examples of use I could find. I'll have to re-read those docs with fresh eyes, now that I realize they are talking about different things. Thanks for the tip!
 

Jestin

New Member
Jan 25, 2020
16
13
3
@StephenH , I finally got a chance to sit back down and take a look at this, I think you might find it interesting what that `SYS $9000` is doing.

If you look at the memory map, you'll see that $9000 is within "Basic program/variables; available to the user". This got me looking at what could be there at the time of execution, and after inspecting the code, it became obvious. The final section of the BASIC layer demo is a series of DATA statements that is labeled as `MACHINE CODE FOR QUICK SCREEN FILL`. It's some in-line assembly for filling 64 rows and 128 columns! If you look back to where the call to $9000 is, a couple lines above is a line of commented out code...that writes 2 bytes to the data port 64x128 times. This was the original BASIC code for filling the screen with a character that was later replaced by a call to in-line assembly!

I've played around with not only removing the call, but also putting back the REM'd out line. It works...but takes a while to fill the screen. I understand why the code was replaced with some assembly. I'm guessing that somehow, the value $9000 became the wrong place to call when loaded by later versions of the ROM, and demo simply jumps somewhere unexpected.
 

Jestin

New Member
Jan 25, 2020
16
13
3
After looking a little more closely, I think there's actually two things that have broken this demo between r33 and the current revision.

First, is the quick screen fill I mentioned above. Removing the call to the quick screen fill in-line assembly works because I found a bug in the assembly code. If you notice on lines 11090 and 11110 of the BASIC code, the address `$FC` on the zero page is used to store a value that gets decremented during the loop. This may have been fine when the code was written, but since then zero page addresses from $80 through $FF are reserved for KERNAL and BASIC. I found that changing this value to something in the user zero page range ($00-$7F) works just the same as not making the call to $9000 in the first place. The program was crashing before the electricity starts to scroll because it was using a memory address that was no longer safe to use.

Second, something is wrong with layers in general. Whether I use the assembly quick screen fill or the BASIC screen fill, layer 0 always shows up as all black. In both cases the electricity being drawn on layer 1 works perfectly, but unlike in r33, there is no longer any tiles filling the layer below (or at least not with correct color values set). I suspect that this may be due to not explicitly setting the layer 0 registers the way we are explicitly setting layer 1. I've written a small assembly program that is showing the same results. If I initialize layer 1, I no longer see layer 0. If I run the same code in r33, I see layer 0.

I'm going to keep experimenting, and see if there's something simple I'm missing. I'll post here with whatever I find.
 

StephenH

New Member
Feb 4, 2020
6
7
3
@Jestin Yup, that sounds like a promising path. I was updating my old Matrix-like screen crawl demo and re-discovered another change that happened somewhere along the way, which is that the kernal no longer leaves layer 1 disabled.

Being fair, best programming practices at this point would definitely be to fully initialize both layers and all sprites (and the mouse if you plan to enable Sprite 0 for any reason). Otherwise, even if the Vera interfaces themselves don't change, you're still depending on kernal behavior that might change in the future.
 
  • Like
Reactions: Jestin

Jestin

New Member
Jan 25, 2020
16
13
3
Another mystery solved.

I've been trying to figure out why in r33 and prior the layer demo draws the electricity on top of the default text screen (in the example I removed the character fill):

layer_demo_no_bg_fill_r33.gif

but on r34 and greater, it simply draws over a black screen:

layer_demo_no_bg_fill.gif

After some experimentation, the answer became clear. In r34 and later, the default screen draws to layer 1 instead of layer 0. When the demo initializes layer 1, it is overwriting the addresses pointing to the tiles and map of the default. The demo is now incorrect, as it assumes that the default character screen is writing to layer 0, even though it now goes to layer 1.

By writing a simple program to shift the hscroll and vscroll of layer 1, you can see that the default screen uses layer 1:

Code:
verareg = $9f20
veralo = verareg+0
veramid = verareg+1
verahi = verareg+2
veradat = verareg+3
veractl = verareg+5

*=$1000

    ; hscroll layer 1
    lda #$06
    sta veralo
    lda #$30
    sta veramid
    lda #$0f
    sta verahi
    lda #10
    sta veradat

    ; vscroll layer 1
    lda #$08
    sta veralo
    lda #$30
    sta veramid
    lda #$0f
    sta verahi
    lda #10
    sta veradat
    
    rts
1582491118984.png

I think @StephenH is correct, and that there should be no assumptions about layer initialization going forward.
 

Jestin

New Member
Jan 25, 2020
16
13
3
Final update.

By adding a simple one-line for loop, I was able to get the layer-demo.bas program working at its r33 level of functionality:

Code:
13 FOR I=0 TO 9 : A = VPEEK($F,$3000+I) : VPOKE $F,$2000+I,A : NEXT I
Before anything else occurs, this will copy all the layer 1 registers to the layer 0 registers, effectively making the default screen render to layer 0. Now layer 1 can be initialized and used as an overlay, as it currently is in the demo. I've submitted a pull request to the x16-demo project (https://github.com/commanderx16/x16-demo/pull/98) so that the demo can continue to work with recent revisions of the rom and emulator.

Thanks to everyone here for pointing me in the right direction, and correcting my blatent oversights. I'm glad to have a great community like this to learn and explore this crazy new machine!
 
Last edited:
  • Like
Reactions: JustinBaldock