Using the WAI instruction correctly

All aspects of programming on the Commander X16.
grml
Posts: 60
Joined: Sat Aug 13, 2022 8:31 pm

Using the WAI instruction correctly

Post by grml »

I have this code (64tass) and I would expect it to print
ABABABABAB...
, but it only prints
A
once and nothing else happens.

Not installing the irq_handler and letting the default CINV routine run gives the desired result. What is wrong with my irq_handler, or what is wrong with my understanding of the WAI instruction?

Code: Select all

.cpu 'w65c02'

CHROUT = $ffd2
CINV = $0314

* = $0801
		.word  (+)
		.text  0, 0, $9e, format("%d", hello), 0
	+	.word  0

	hello .proc
			sei
			
			; removing this makes it work
			lda <#irq_handler
			sta CINV
			lda >#irq_handler
			sta CINV+1

		_loop:
			lda #'A'
			jsr CHROUT

			cli ; allow irqs
			wai ; wait for irq to happen
			; we continue to execute here after the next RTI
			sei ; don't allow irqs

			lda #'B'
			jsr CHROUT

			bra _loop
	.pend

	irq_handler .proc
			ply
			plx
			pla
			rti
	.pend
DragWx
Posts: 363
Joined: Tue Mar 07, 2023 9:07 pm

Re: Using the WAI instruction correctly

Post by DragWx »

You need to tell the VERA that you've acknowledged its interrupt, or else it'll just continually trigger that same IRQ over and over (i.e., running your irq handler in an endless loop), preventing your main code from ever advancing.

The kernal enables only the VSYNC interrupt by default, so try acknowledging it by writing #$01 to $9F27 in your IRQ handler.
grml
Posts: 60
Joined: Sat Aug 13, 2022 8:31 pm

Re: Using the WAI instruction correctly

Post by grml »

Yep, that's it. Thanks!
grml
Posts: 60
Joined: Sat Aug 13, 2022 8:31 pm

Re: Using the WAI instruction correctly

Post by grml »

And just to make sure I didn't miss something: CINV is the only way hook into interrupts; the vector at $fffe can't be changed because it's always in ROM. If you want to use interrupts, you must make sure $314/$315 contains a valid function pointer. These are hardcoded, constant addresses.

Is that correct? (ignoring NMI completely, only IRQ is relevant)
DragWx
Posts: 363
Joined: Tue Mar 07, 2023 9:07 pm

Re: Using the WAI instruction correctly

Post by DragWx »

Yes, modifying the CINV vector is the only way to supply your own IRQ handler (and there's no way to bypass the short "preamble" baked into the kernal rom), so always make sure it points to a valid IRQ handler or else Fun Stuff™ happens. :P

Also of note, the CINV vector's memory address is part of the C64's original API, so I think it's safe to always count on it being the same between kernal revisions.
User avatar
StephenHorn
Posts: 565
Joined: Tue Apr 28, 2020 12:00 am
Contact:

Re: Using the WAI instruction correctly

Post by StephenHorn »

DragWx wrote: Mon Mar 20, 2023 7:33 pm Yes, modifying the CINV vector is the only way to supply your own IRQ handler (and there's no way to bypass the short "preamble" baked into the kernal rom), so always make sure it points to a valid IRQ handler or else Fun Stuff™ happens. :P

Also of note, the CINV vector's memory address is part of the C64's original API, so I think it's safe to always count on it being the same between kernal revisions.
This is mostly true, and likely to be completely true as of hardware revision 2.
tl;dr: If you want the all the ugly details, keep reading, otherwise just assume that CINV is the only way to implement IRQs, and that CINV will be always invoked with the ROM bank set to 0.

At present, the kernal and BASIC ROM banks (0 and 4, respectively) have handlers for IRQs baked into them, but not all ROM banks have the interrupt vectors or logic. If other ROM banks are selected, this means allowing an IRQ to occur may result in a system crash.

If you explore cartridges, their memory uses the same address region as ROM banks, and as a result they can currently implement their own IRQ handling logic, even bypassing the kernal's default preamble. Simply make sure the appropriate cartridge bank is selected when the IRQ occurs. But be aware that this behavior is likely to change in the future.

That having been said, and looking towards the future, Wavicle seems likely to take over the hardware design of the X16 for the gen-2 hardware, and he strongly wants to add a feature that would force the X16 to always reference bank 0 for interrupts. There are good technical reasons for this, particularly when it comes to interrupts that may happen early in the boot process and create race conditions. As far as the kernal is concerned, we're confident enough that this hardware change will occur to have already changed the kernal preamble to account for this change. If/when this change occurs, it would also mean that cartridges could no longer implement their own whole-cloth interrupt handlers, requiring them to go through CINV, and CINV would always execute with the current ROM bank set to 0.
Developer for Box16, the other X16 emulator. (Box16 on GitHub)
I also accept pull requests for x16emu, the official X16 emulator. (x16-emulator on GitHub)
grml
Posts: 60
Joined: Sat Aug 13, 2022 8:31 pm

Re: Using the WAI instruction correctly

Post by grml »

"We're adding one RAM bank to the ROM space so you can do whatever the hell you want" would have made me happier.
User avatar
StephenHorn
Posts: 565
Joined: Tue Apr 28, 2020 12:00 am
Contact:

Re: Using the WAI instruction correctly

Post by StephenHorn »

grml wrote: Tue Mar 21, 2023 5:29 pm "We're adding one RAM bank to the ROM space so you can do whatever the hell you want" would have made me happier.
Well, the cartridge feature in the emulator will let you do exactly that right now, if that's your wish. Author a cartridge with makecart and load it with -cart, or make an empty 3.5MB file and load it with -cartbin. Proceed to enjoy your memory.

Nevertheless, Gen-2 is likely to change the IRQ behavior as described.
Developer for Box16, the other X16 emulator. (Box16 on GitHub)
I also accept pull requests for x16emu, the official X16 emulator. (x16-emulator on GitHub)
BruceRMcF
Posts: 224
Joined: Sat Jan 07, 2023 10:33 pm

Re: Using the WAI instruction correctly

Post by BruceRMcF »

StephenHorn wrote: Tue Mar 21, 2023 5:10 pm ... Wavicle seems likely to take over the hardware design of the X16 for the gen-2 hardware, and he strongly wants to add a feature that would force the X16 to always reference bank 0 for interrupts. There are good technical reasons for this, particularly when it comes to interrupts that may happen early in the boot process and create race conditions. ...
I would very much like this for any ROM based Forth system, as my approach for defining and combining modules for additional ROM banks is looking toward a "smallest power of two" package with manual fitting together of pieces -- 2^(7+index) where index runs from 0 to 6 for RAM segment modules, 0 to 7 for ROM segment modules ... 128, 256, 512, 1KB, 2KB, 4KB, 8KB, [16KB, ROM only] ... and not having to fit IRQ support into the top page of the ROM segment would substantially simplify module packaging.
User avatar
Yazwho
Posts: 172
Joined: Fri Feb 19, 2021 2:59 pm
Contact:

Re: Using the WAI instruction correctly

Post by Yazwho »

Wavicle seems likely to take over the hardware design of the X16 for the gen-2 hardware, and he strongly wants to add a feature that would force the X16 to always reference bank 0 for interrupts.
Thats really disappointing. Having the ability to remove the kernel completely and construct your own is one of the most exciting features of the 'cartridge'.

Constricting devs to whatever happens in the Kernel's handler feels awful. It hamstrings projects from the get go. If you're writing things for a cartridge you should understand how the system works, so what is needed is better documentation and tooling. Then we don't need to coddle developers.
Post Reply