42bs Posted July 22, 2019 Share Posted July 22, 2019 (edited) Hi, diving into the 65C02 docs, I found out "CLD" is not needed in the interrupt handler. After all these year, I did also re-work the interrupt code to save some cycles. ; Timer 7 => 3+2+4+3+2+12 = 26 ; Timer 6 => 3+2+4+2+3+12 = 28 ; UART => 3+2+4+3+6 = 18 ; pre = 19 ; Timer 5 => 19+4*(2+2)+12 = 47 ; Timer 3 => 19+3*(2+2)+(2+3)+12 = 48 ; Timer 2 => 19+2*(2+2)+(2+3)+12 = 44 ; Timer 1 => 19+1*(2+2)+(2+3)+12 = 40 ; Timer 0 => 19+(2+3)+12 = 36 ; Timer 0 => HBL ; Timer 2 => VBL irq:: pha ; 3 lda #$10 ; 2 bit $fd81 ; 4 bne _4 ; 2,3 bmi _7 ; 2,3 bvs _6 ; 2,3 lda $fd81 ; 4 IFD BRKuser beq dummy_irq ENDIF lsr ; 2 bcs _0 ; 2,3 lsr ; 2 bcs _1 ; 2,3 lsr ; 2 bcs _2 ; 2,3 lsr ; 2 bcs _3 ; 2,3 _5: lda #$20 ; 2 sta $fd80 ; 4 jmp (irq_vecs+5*2) ;6 _4: jmp (irq_vecs+4*2) ; 6 _3: lda #$08 sta $fd80 jmp (irq_vecs+3*2) _2: lda #$04 sta $fd80 jmp (irq_vecs+2*2) _1: lda #$2 sta $fd80 jmp (irq_vecs+2*2) _0: lda #$1 sta $fd80 jmp (irq_vecs+0*2) _6: lda #$40 sta $fd80 jmp (irq_vecs+6*2) _7: lda #$80 sta $fd80 jmp (irq_vecs+7*2) dummy_irq END_IRQ Compared to the old one, the worst case cycles are heavily reduced: ;--------------- ;- Interrupt-Handler ;--------------- ; pre = 17 , post = 14 ; Timer 0 => 17+4+2+2+14 = 39 ; Timer 1 => 17+4+2+3+2+2+14 = 44 ; Timer 2 => 17+4+2+2*(3+2)+2+14 = 49 ; Timer 3 => 17+4+2+3*(3+2)+2+14 = 54 ; UART => 22 ; Timer 5 => 17+4+2+5*(3+2)+2+14 = 64 ; Timer 6 => 17+4+2+6*(3+2)+2+14 = 69 ; Timer 7 => 17+4+2+7*(3+2)+2+14 = 74 Edited July 22, 2019 by 42bs 1 Link to comment Share on other sites More sharing options...
+karri Posted July 29, 2019 Share Posted July 29, 2019 The BLL IRQ handling is more efficient than cc65. I would like to use this technique instead of having the comparison in every IRQ handler. Link to comment Share on other sites More sharing options...
42bs Posted July 29, 2019 Author Share Posted July 29, 2019 22 minutes ago, karri said: The BLL IRQ handling is more efficient than cc65. I would like to use this technique instead of having the comparison in every IRQ handler. I thought the cc65 irq code was derived from the original BLL code. But yes, this code is ugly. Where is "callirq"? Link to comment Share on other sites More sharing options...
+karri Posted July 29, 2019 Share Posted July 29, 2019 1 hour ago, 42bs said: I thought the cc65 irq code was derived from the original BLL code. But yes, this code is ugly. Where is "callirq"? At cc65/libsrc/runtime/callirq.s They had some great idea to hide the interrupts from confusing programmers. So now we need to use .interruptor everywhere. Fortunately there is a possibility to add higher levels to interrupts. Example: .interruptor _HandyMusic_Main .interruptor _HandyMusic_PCMMain,15 Normal HandyMusic just ticks on while PSC samples are served at highest priority. This was a must to get the correct pitch for the samples. HandyMusic_PCMMain: lda INTSET and #TIMER3_INTERRUPT beq @L0 jsr PCMSample_IRQ sec rts @L0: clc rts As you can see setting CARRY bit tells the IRQ handler that there are no more IRQ handlers to be called for this interrupt. The CLC is the normal flag that lets you hook more handlers to this IRQ. A typical example would be to use VBL for the screen and system time. .interruptor update_clock update_clock: lda INTSET and #%00000100 beq @NotVBlank ; Not vertical-blank interrupt inc clock_count bne @L1 inc clock_count+1 bne @L1 inc clock_count+2 @L1: ;clc ; General interrupt was not reset @NotVBlank: rts Link to comment Share on other sites More sharing options...
42bs Posted July 29, 2019 Author Share Posted July 29, 2019 5 minutes ago, karri said: At cc65/libsrc/runtime/callirq.s They had some great idea to hide the interrupts from confusing programmers. So now we need to use .interruptor everywhere. Fortunately there is a possibility to add higher levels to interrupts. Example: .interruptor _HandyMusic_Main .interruptor _HandyMusic_PCMMain,15 Normal HandyMusic just ticks on while PSC samples are served at highest priority. This was a must to get the correct pitch for the samples. HandyMusic_PCMMain: lda INTSET and #TIMER3_INTERRUPT beq @L0 jsr PCMSample_IRQ sec rts @L0: clc rts Ok, w/o changing too much: irq.s: pha phx phy lda INTSET sta INTSET_ZP jsr callirq ply plx pla rti ... HandyMusic_PCMMain: bbs3 INTSET_ZP, sample_irq clc rts sample_irq: lda #$8 sta INTCLR jsr PCMSample_IRQ sec rts 1 Link to comment Share on other sites More sharing options...
+karri Posted July 29, 2019 Share Posted July 29, 2019 I had no idea that there is a bbs3 instruction available. Oliver's cc65 has already changed a lot by removing IRQ's from all drivers and changing the joypad syntax. So speeding up the IRQ's a little would not hurt further cc65 use for me... It would be nice to change the CPU directive to use all the special op-codes available for Lynx. /* CPUs */ typedef enum { CPU_UNKNOWN = -1, /* Not specified or invalid target */ CPU_NONE, /* No CPU - for assembler */ CPU_6502, CPU_6502X, /* "Extended", that is: with illegal opcodes */ CPU_65SC02, CPU_65C02, CPU_65816, CPU_SUNPLUS, /* Not in the freeware version - sorry */ CPU_SWEET16, CPU_HUC6280, /* Used in PC engine */ CPU_M740, /* Mitsubishi 740 series MCUs */ CPU_COUNT /* Number of different CPUs */ } cpu_t; Perhaps creating a new CPU type 65SC02X /* All Lynx op-codes plus usable illegal op-codes */ Then we could create cute mnemonics for SKIP1 opcode and who knows what else. The da65 disassembler seems to give mnemonics to 256 different opcodes when you choose 6502X as the CPU type. Link to comment Share on other sites More sharing options...
42bs Posted July 29, 2019 Author Share Posted July 29, 2019 Besides STP and WAI it seems to be a plain vanilla 65C02, so no need for a special CPU. The multi-byte NOPs are in 65C02. Link to comment Share on other sites More sharing options...
42bs Posted July 29, 2019 Author Share Posted July 29, 2019 (edited) 2 hours ago, karri said: At cc65/libsrc/runtime/callirq.s grep did not find it?!! Anyway, from what I see, there is no problem to use my routine and skip callirq.s completely. Of course, one has to pay attention that currently only A is saved. If cycle count matters Edited July 29, 2019 by 42bs Link to comment Share on other sites More sharing options...
42bs Posted July 29, 2019 Author Share Posted July 29, 2019 2 hours ago, karri said: A typical example would be to use VBL for the screen and system time. .interruptor update_clock update_clock: lda INTSET and #%00000100 beq @NotVBlank ; Not vertical-blank interrupt inc clock_count bne @L1 inc clock_count+1 bne @L1 inc clock_count+2 @L1: ;clc ; General interrupt was not reset @NotVBlank: rts .interruptor update_clock update_clock: lda INTSET and #%00000100 beq @NotVBlank ; Not vertical-blank interrupt inc clock_count beq @l1 rts @l1: inc clock_count+1 beq @l2 rts @l2 inc clock_count+2 ;clc ; General interrupt was not reset @NotVBlank: rts Little optimization: It is more likely that Z is not set (only once all 256 VBLs) Link to comment Share on other sites More sharing options...
+karri Posted July 30, 2019 Share Posted July 30, 2019 Thanks! Link to comment Share on other sites More sharing options...
Recommended Posts