Modified 6502 Interrupt Returns

353 Views Asked by At

I am trying to switch normal program flow while an interrupt returns:

START
    SEI
    LDX #<IRQ
    LDY #>IRQ
    STX $FFFE
    STY $FFFF
    CLI

LOOP1
    INC $D020
    JMP LOOP1

LOOP2
    INC $D021
    JMP LOOP2

IRQ
    STA SAVEA+1
    STX SAVEX+1
    STY SAVEY+1

    // Some Routines

    LDA #$00
    PHA
    LDA #<LOOP2
    PHA
    LDA #>LOOP2
    PHA

SAVEA   
    LDA #$00
SAVEX   
    LDX #$00
SAVEY   
    LDY #$00
    RTI

I wrote this code accourding to that source: http://6502.org/tutorials/interrupts.html#1.3

enter image description here

But PHA's cause crash, how to switch normal flow LOOP1 to LOOP2 in an interrupt?

3

There are 3 best solutions below

2
On BEST ANSWER

Simple way is:

TSX
LDA #$00
STA $0101,X   // Processor Status
LDA #<LOOP2
STA $0102,X   // Task Low Address
LDA #>LOOP2
STA $0103,X   // Task High Address

But for more complex task management, we have to save A,X,Y registers for each task:

START
    SEI
    LDX #<IRQ
    LDY #>IRQ
    STX $FFFE
    STY $FFFF
    CLI

LOOP1
    INC $D020
    JMP LOOP1

LOOP2
    INC $D021
    JMP LOOP2

IRQ
    STA $FF
    STX $FE
    STY $FD
    LDX TASK+1
    CPX TASK
    BEQ CONT
    LDY TASKI,X
    TSX
    LDA $0101,X
    STA TASKS+0,Y
    LDA $0102,X
    STA TASKS+1,Y
    LDA $0103,X
    STA TASKS+2,Y
    LDA $FF
    STA TASKS+3,Y
    LDA $FE
    STA TASKS+4,Y
    LDA $FD
    STA TASKS+5,Y
    LDA TASK
    STA TASK+1
CONT

    // Change Task
    LDA TASK
    CLC
    ADC #$01
    AND #$01
    STA TASK


    LDX TASK
    CPX TASK+1
    BEQ CONT2
    STX TASK+1
    LDY TASKI,X
    TSX
    LDA TASKS+0,Y
    STA $0101,X
    LDA TASKS+1,Y
    STA $0102,X
    LDA TASKS+2,Y
    STA $0103,X
    LDA TASKS+3,Y
    STA $FF
    LDA TASKS+4,Y
    STA $FE
    LDA TASKS+5,Y
    STA $FD
CONT2
    LDA $FF
    LDX $FE
    LDY $FD
    RTI

TASK
    .BYTE 0,0
TASKI
    .BYTE 0,6,12,18,24,30,36
TASKS
    .BYTE 0,<LOOP1,>LOOP1,0,0,0
    .BYTE 0,<LOOP2,>LOOP2,0,0,0
0
On

I'm not sure exactly what you're trying to do, but it looks to me as though you want to change the background colors on a Commodore 64 in rapid succession. If you want to change what you're doing, there's actually a much easier way:

START
    SEI
    LDX #<IRQ
    LDY #>IRQ
    STX $FFFE
    STY $FFFF
    CLI

LOOP1
    INC $D020   ;the interrupt will switch this to $D021 and back every time it happens.
    JMP LOOP1

IRQ
    PHA
       LDA #$01
       EOR LOOP1+1  ;the value at this address is the "20" in "INC $D020"
       STA LOOP1+1  ;toggle between "INC $D020" and "INC $D021" each IRQ
    PLA
    RTI

This has a lot less overhead than setting a flag and branching based on that flag. Presumably your goal is to update the border color/background color as quickly as possible and this greatly reduces the amount of time spent checking conditions.

3
On

The simplest thing is probably to have two stack areas -- one for every task. $100-$17f and $180-$1ff, for example. Then, you would have your interrupt task switching code like this:

  pha
  txa
  pha
  tya
  pha ;saving task's registers on its stack,
      ;where flags and PC are already saved
      ;by entering the interrupt

  tsx
  stx ... ;save task's stack position

  ... ;select new task to run/etc.

  ldx ...
  txs ;load other task's stack position

  pla
  tay
  pla
  tax
  pla ;restore other task's registers

  rti ;and finally continue other task