How to implement bareback interrupts?

All aspects of programming on the Commander X16.
Stefan
Posts: 456
Joined: Thu Aug 20, 2020 8:59 am

Re: How to implement bareback interrupts?

Post by Stefan »

I can try to fix if you upload the complete source code file here + the ca65 config file
Stefan
Posts: 456
Joined: Thu Aug 20, 2020 8:59 am

Re: How to implement bareback interrupts?

Post by Stefan »

I have a minimal example that works in the emulator.

File: cart.cfg

Code: Select all

MEMORY {
    ZP:             file = "", start = $0022, size = $0080 - $0022, define = yes;
    CARTRAM:        start = $1000, size = $8f00, define = yes;
    CARTROM:        start = $c000, size = $3fff, fill = yes, fillval = $aa;
}
SEGMENTS {
    SETUP: load = CARTROM, type = rw, define = yes;
    CODE: load = CARTROM,  run = CARTRAM, type=rw, define=yes;
}
File: main.asm

Code: Select all

; Build with: cl65 -o cart.bin -t cx16 -C cart.cfg main.asm

.import __CODE_LOAD__
.import __CODE_SIZE__
.import __CODE_RUN__

IRQVec = $0314

.segment "SETUP"

; Magic cartridge string at $c000
.byt "cx16"

; Copy code to RAM
init:
    lda #<__CODE_LOAD__
    sta $22
    lda #>__CODE_LOAD__
    sta $23

    lda #<__CODE_RUN__
    sta $24
    lda #>__CODE_RUN__
    sta $25

    lda #<__CODE_SIZE__
    sta $26
    lda #>__CODE_SIZE__
    sta $27

loop:
    lda ($22)
    sta ($24)

    inc $22
    bne :+
    inc $23

:   inc $24
    bne :+
    inc $25

:   lda $26
    bne :+
    dec $27
:   dec $26

    lda $26
    ora $27
    bne loop 

    ; Jump to RAM code
    jmp __CODE_RUN__

.CODE

hello:
    ; Select Kernal ROM bank
    stz $01

    ; Print hello
    ldx #0
:   lda msg,x
    beq _setup_irq
    jsr $ffd2
    inx
    bra :-

msg:
    .byt "hello",0

; Your code...

_setup_irq:
    ;nop
    ;php
    sei
    lda #<loop_irq
    sta IRQVec
    lda #>loop_irq
    sta IRQVec+1
    cli
    ;plp
    
    ;lda #1
    ;sta $9F27   
    ;rts
wait:
    bra wait
    
loop_irq:
    jsr handle_clock
    jsr handle_joystick
    jsr handle_keyboard
    jsr show_life
    
    lda #1
    sta $9F27   ; ISR, bit 0=VSYNC

  	ply
	plx
	pla
    
    rti

handle_clock:
    ;inc $22
    rts

handle_joystick:
    rts
    
handle_keyboard:
    rts

show_life:
    inc $22
    bne :+
    lda #'.'
    jsr $ffd2
:   rts
Run with: ./x16emu -cartbin cart.bin
Stefan
Posts: 456
Joined: Thu Aug 20, 2020 8:59 am

Re: How to implement bareback interrupts?

Post by Stefan »

Looking at this code that you posted earlier, one thing that stands out is the PLP at the end of _setup_irq. This will disable interrupts, if interrupts were disabled at the beginning of the function, effectively overwriting the CLI.

Code: Select all

_setup_irq:
    nop
    php
    sei
    
    stz ClockLo
    stz ClockHi

    lda #<loop_irq
    sta IRQVec
    lda #>loop_irq
    sta IRQVec+1
    
    ; Setup first VBLANK
    lda #$1
    sta VERA::IRQ_EN

    cli
    plp
    rts
    
loop_irq:
    jsr handle_clock
    jsr handle_joystick
    jsr handle_keyboard
    
    ; Sign IRQ
    lda #$1
    sta VERA::IRQ_FLAGS

    ; Cleanup
  	ply
	plx
	pla
    
    rti
User avatar
kliepatsch
Posts: 247
Joined: Thu Oct 08, 2020 9:54 pm

Re: How to implement bareback interrupts?

Post by kliepatsch »

This is starting to smell like a bug in the emulator. Maybe the fact that a cartridge is inserted changes its behavior? I think that ISR with a cartridge has so far been rather niche and maybe not been tested very well.

Edit: from skimming through the emulator source I can't find anything suspicious. It seems to be exactly as Stefan explained.
User avatar
kliepatsch
Posts: 247
Joined: Thu Oct 08, 2020 9:54 pm

Re: How to implement bareback interrupts?

Post by kliepatsch »

Ah yes, good find Stefan. Didn't see your posts before posting mine
SunSailor
Posts: 12
Joined: Mon Apr 03, 2023 10:50 pm

Re: How to implement bareback interrupts?

Post by SunSailor »

Boah, thanks guys, you rock! Stefan, you're right, that's the issue. Would never found that, although I still don't understand, why everyting worked fine on the vanilla boot then. I was so focused on the VERA flag set, that I totally forgot about the CPUs one.

For the sake of anybody ever searching for something like this, this is the working code on my side now:

Code: Select all

_setup_irq:
    nop
    php
    sei
    
    lda #<_loop_irq
    sta IRQVec
    lda #>_loop_irq
    sta IRQVec+1
    
    ; Setup first VBLANK
    lda VERA::IRQ_EN
    ora #$1
    sta VERA::IRQ_EN

    plp
    cli

    rts
    
_loop_irq:
    ; Sign IRQ
    lda #$1
    sta VERA::IRQ_FLAGS
    
    ; Cleanup
  	ply
	plx
	pla
    
    rti
Stefan
Posts: 456
Joined: Thu Aug 20, 2020 8:59 am

Re: How to implement bareback interrupts?

Post by Stefan »

Without digging deeper it's hard to be sure, but I have at least a theory why it first worked, and not in the cartridge ROM.

When the boot_cartridge function is called during Kernal init from within the start function in kernal/cbm/init.s, interrupts have been disabled with a SEI instructions. When you in the cartridge setup function preserved and restored the status register, you kept interrupts disabled.

If the same setup function is called from BASIC, where interrupts are enabled, you are not hit by this.
Stefan
Posts: 456
Joined: Thu Aug 20, 2020 8:59 am

Re: How to implement bareback interrupts?

Post by Stefan »

As a side note:

Code: Select all

php
sei
<do some work>
plp
is a common pattern in 6502 assembly when you need to disable interrupts but want to preserve the original state of the interrupt flag.
SunSailor
Posts: 12
Joined: Mon Apr 03, 2023 10:50 pm

Re: How to implement bareback interrupts?

Post by SunSailor »

Ah, that makes totally sense! Thank you, for pointing this out!
Post Reply