User Tools

Site Tools


base:stable_raster_routine

STABLE RASTER ROUTINE

A Raster Stabbing routine using the double IRQ principle. Insert this code after you have pushed your registers onto the stack inside your IRQ code. The routine doesen't care what the actual $d012 value is so it is flexible.

Other Interrupts, $d012 = #$ff, Sprites, Badline and Badline-1 = fuckup.

If you have the KERNAL banked in, you need to modify the IRQ-Vectors.

Kickassembler format

//«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»
// Raster Stabilizing Code
//«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»
    // A Raster Compare IRQ is triggered on cycle 0 on the current $d012 line
    // The MPU needs to finish it's current OP code before starting the Interrupt Handler,
    // meaning a 0 -> 7 cycles delay depending on OP code.
    // Then a 7 cycle delay is spendt invoking the Interrupt Handler (Push SR/PC to stack++)
    // Then 13 cycles for storing registers (pha, txa, pha, tya, pha)

    // CYCLECOUNT: [20 -> 27] cycles after Raster IRQ occurred.

    // Set up Wedge IRQ vector
    lda #<WedgeIRQ
    sta $fffe
    lda #>WedgeIRQ
    sta $ffff

    // Set the Raster IRQ to trigger on the next Raster line
    inc $d012

    // Acknowlege current Raster IRQ
    lda #$01
    sta $d019

    // Store current Stack Pointer (will be messed up when the next IRQ occurs)
    tsx

    // Allow IRQ to happen (Remeber the Interupt flag is set by the Interrupt Handler).
    cli

    // Execute NOPs untill the raster line changes and the Raster IRQ triggers
    NOP
    NOP
    NOP
    NOP
    NOP
    NOP
    NOP
    NOP
    // Add one extra nop for 65 cycle NTSC machines

    // CYCLECOUNT: [64 -> 71]

WedgeIRQ:
    // At this point the next Raster Compare IRQ has triggered and the jitter is max 1 cycle.
    // CYCLECOUNT: [7 -> 8] (7 cycles for the interrupt handler + [0 -> 1] cycle Jitter for the NOP)

    // Restore previous Stack Pointer (ignore the last Stack Manipulation by the IRQ)
    txs

    // PAL-63  // NTSC-64    // NTSC-65
    //---------//------------//-----------
    ldx #$08   // ldx #$08   // ldx #$09
    dex        // dex        // dex
    bne *-1    // bne *-1    // bne *-1
    bit $00    // nop
               // nop

    // Check if $d012 is incremented and rectify with an aditional cycle if neccessary
    lda $d012
    cmp $d012  // <- critical instruction (ZERO-Flag will indicate if Jitter = 0 or 1)

    // CYCLECOUNT: [61 -> 62] <- Will not work if this timing is wrong

    // cmp $d012 is originally a 5 cycle instruction but due to piplining tech. the
    // 5th cycle responsible for calculating the result is executed simultaniously
    // with the next OP fetch cycle (first cycle of beq *+2).

    // Add one cycle if $d012 wasn't incremented (Jitter / ZERO-Flag = 0)
    beq *+2

    // Stable code    
    

Don't forget to set up the next IRQ-Vector before exiting the IRQ.

If you want to make it more simple, you could store this as a pseudo or macro (STABILIZE) and just:

IRQ_Begin:
    pha
    txa
    pha
    tya
    pha
    :STABILIZE
    
    //..xxXX[Stable Code]XXxx..
    
    lda #<Next_IRQ
    sta $fffe
    lda #>Next_IRQ
    sta $ffff
    lda #$01
    sta $d019
    pla
    tay
    pla
    tax
    pla
    rti

TWW/Creators

base/stable_raster_routine.txt · Last modified: 2015-04-17 04:34 (external edit)