Jump to content
The 8-Bit Guy

Beware of using the VERA inside IRQ

Recommended Posts

During my conversion of Petscii Robots over to the X16, it was relatively smooth until I added sound support.   So, I thought I'd talk about the one big issue I ran into, which I wasn't expecting due to my previous experience coding for Commodore machines.

Because the Vera has it's own video RAM, you have to set the VERA_L, VERA_M, and VERA_H every time you are about to write something to video RAM.  It's a little more cumbersome than the way things are done on other Commodore computers, but not terribly so.  In fact, in about 25% of cases, I found it easier to use this than the C64, depending on what I was trying to modify on the screen.

So, In my sound/music routine, I'm using the VERA's built-in PSG.  Which means my sound routine is changing VERA_L, VERA_M, and VERA_H every time the IRQ routine runs.   And the IRQ can run right in the middle of your writes to VRAM.  And unless you want to add an SEI and CLI before and after every routine that writes data to VRAM, you'll need to backup the VERA address registers in your IRQ routine.  So, I did this:

LDA VERA_H
PHA
LDA VERA_M
PHA
LDA VERA_L
PHA

***insert IRQ code here ***

PLA
STA VERA_L
PLA
STA VERA_M
PLA
STA VERA_H

Now, while this may sound obvious to some people, I wasn't accustomed to dealing with this sort of thing when writing to sound registers in the SID or VIC-20 or whatever, since they were their own separate registers.   Anyway, hopefully this piece of advice will help somebody else not pull their hair out in the future.

 

  • Like 9
  • Thanks 4

Share this post


Link to post
Share on other sites

You could possibly set your code up in such a way that VRAM access uses port 1 and sound register access uses port 2.

  • Like 3

Share this post


Link to post
Share on other sites

Funny... I was just thinking about this yesterday, as well... but from a different perspective. Someone was talking about using conio commands in C, and it occurred to me that ISRs (interrupt service routine) might write to VERA while you're in the middle of another process. 

So I guess it's doubly important to make sure interrupt handlers always back up the VERA registers before making any changes - not just for their own use, but to protect running software and protect the transparency of ISRs. 

 

Share this post


Link to post
Share on other sites
47 minutes ago, Guybrush said:

You could possibly set your code up in such a way that VRAM access uses port 1 and sound register access uses port 2.

This is what I decided to do, although I'm not sure this would completely solve it in all cases. It's solved it for me - so far anyway. Of note, VERA PSG does require a lot of CPU support to make chippy sounds (due to software envelopes) so I can see communicating with VERA to be a very common occurrence as a result.

Share this post


Link to post
Share on other sites
1 hour ago, Guybrush said:

You could possibly set your code up in such a way that VRAM access uses port 1 and sound register access uses port 2.

Excellent idea.  I hadn't considered this.  It would still require changing the data port before and after the IRQ runs, but that's probably less code and CPU cycles than backing up the registers.  

  • Like 1

Share this post


Link to post
Share on other sites
17 minutes ago, The 8-Bit Guy said:

Excellent idea.  I hadn't considered this.  It would still require changing the data port before and after the IRQ runs, but that's probably less code and CPU cycles than backing up the registers.  

It would only require changing the CTRL register's ADDRSEL bit to set the active port while reloading the address registers but that's just one register instead of three.

If you don't use any of the KERNAL's graphics functions then you have complete control of the VERA and you can be sure that nothing else is touching the address registers and the CTRL register. Then you can simply do LDA #$01, ORA $9f29 when you enter the interrupt handler and LDA #$FE, AND $9f29 before exiting. That's just 12 cycles  instead of 15 when using the stack.😛 I know that's not that important on Commander X16 compared to C64, but I just can't help myself 😆.

Share this post


Link to post
Share on other sites
48 minutes ago, Guybrush said:

It would only require changing the CTRL register's ADDRSEL bit to set the active port while reloading the address registers, but that's just one register instead of three.

If you don't use any of the KERNAL's graphics functions, then you have complete control of the VERA, and you can be sure that nothing else is touching the address registers and the CTRL register. Then, you can simply do LDA #$01, ORA $9f29 when you enter the interrupt handler, and LDA #$FE, AND $9f29 before exiting. That's just 12 cycles instead of 15 when using the stack.😛 I know that's not that important on Commander X16 compared to C64, but I just can't help myself 😆.

You don't need even that much.  Just do "inc $9F25" when starting the ISR.  And, "stz $9F25" when leaving the ISR.  (The DCSEL bit is irrelevant.)

  • Like 1

Share this post


Link to post
Share on other sites

Yup had the same problem when I wrote music library for BASIC programs. Of course I had to back up registers because I had to allow the default IRQ handler to take over after I was done playing with PSG (pun intended 🙂 ) and of course BASIC programs print, draw, scroll, etc.

Share this post


Link to post
Share on other sites
18 hours ago, The 8-Bit Guy said:

And the IRQ can run right in the middle of your writes to VRAM.

Ah - this is why the sound effects in Invaderz sometimes drop out or chip in some way... I can now fix this, thanks a lot!

  • Like 2

Share this post


Link to post
Share on other sites

My solution to this was to generally run all of my logic in the IRQ, starting with screen draws, while the non-interrupt code essentially spins on a tight loop checking on a single memory address. This way I don't have to worry about any of my routines being interrupted. An additional up-side to this is that I effectively have a thread that's not doing anything, and I'm thinking it would be ideal to place my streaming I/O logic into there, essentially spinning through banks and loading files as needed into them.

In particular, I really like the VERA's dual access channels and auto-increment settings, and how they make it really easy to write columns and rows of 16-bit tile data.

Share this post


Link to post
Share on other sites

Might be quicker to semaphore it, so when your code isn't updating Vera you don't have to execute the code if it hasn't claimed the semaphore. Really depends :)

There's an argument that you shouldn't update in IRQ anyway, but have a Model-View design, so you update your model if you want in the interrupt routine, just using the IRQ as a timer.

 

Share this post


Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.


×
×
  • Create New...

Important Information

Please review our Terms of Use