| |
Krill
Registered: Apr 2002 Posts: 2980 |
C-64 coding cargo cults
The most-discussed coding cargo cult on the C-64 is probably SEI/CLI around interrupt setup code.
Here's another one: acknowledging VIC raster interrupts.
According to the datasheet http://archive.6502.org/datasheets/mos_6567_vic_ii_preliminary... an active VIC interrupt is acknowledged by writing a "1" to the corresponding bit in $d019.
The usual way to achieve this seems to be "DEC $D019" and to a lesser extent other read-modify-write instructions, saving a few bytes and/or cycles compared to "LDA $D019 : STA $D019" or "LDA #$xF : STA $D019".
This works because RMW instructions on 6502/6510 read a value (here, the pending interrupts) and write the same value again (clearing the interrupt latches) before writing the modified value.
This is also why this technique does not work on SuperCPU's 65816 in native mode, as its RMW instructions lack the dummy-write of the unmodified value.
Now, the cargo cult bit is this: For raster interrupts, it suffices to write any value with bit 0 set (likewise for other VIC interrupts). Clearing all VIC interrupts can be achieved by writing any value with bits 0..3 set.
So, you can save 2 cycles by simply recycling any register value that happens to have bit 0 set, writing that one to $d019 to acknowledge a VIC raster interrupt.
Please post other coding cargo cults here. =) |
|
| |
JackAsser
Registered: Jun 2002 Posts: 2014 |
When you want to ack a timer interrupt and exit the ISR you normally read $ddxd and the do RTI.
This takes 4+6 cycles.
But by instead place the RTI on $ddxc and do a jmp $ddxc you exploit the fact that the 6502 ALWAYS reads at least two bytes even if an instruction is just one byte. So, the read from $ddxd is implicitly done by the CPU while fetching the RTI.
This takes 3+6 cycles. |
| |
Krill
Registered: Apr 2002 Posts: 2980 |
Okay, then let's extend this thread to clever hacks as well and not just somewhat superfluous boilerplate code typed in unthinkingly. =) |
| |
JackAsser
Registered: Jun 2002 Posts: 2014 |
Quote: Okay, then let's extend this thread to clever hacks as well and not just somewhat superfluous boilerplate code typed in unthinkingly. =)
Ahh ok, now I know the difference! |
| |
oziphantom
Registered: Oct 2014 Posts: 490 |
interrupts must always do
pha
txa
pha
tya
pha
pla
....
is another good one.
lda vic reg
and value
ora value
sta vic reg
there are cases where this is needed, and it should be taught this way to hammer the point of setting a bit. But 99.8% of the time you can just do lda sta
also inc $d019 don't think I've ever seen dec |
| |
Oswald
Registered: Apr 2002 Posts: 5094 |
I use lsr d019.
Remember flaming on sei/cli. What happens without them if you only changed half of the jump vector? |
| |
Krill
Registered: Apr 2002 Posts: 2980 |
Quoting OswaldRemember flaming on sei/cli. What happens without them if you only changed half of the jump vector? The point is that you do not need SEI/CLI for regular interrupt setup when starting from BASIC.
There is only one possible interrupt, the CIA1 timer interrupt, which you would disable with LDA #$7F : STA $DC0D. Note that there is no need to acknowledge any pending interrupt by reading $dc0d either.
After that, no interrupts will be triggered, and you can set up a raster interrupt without worrying for a race-condition (interrupt triggering between setting interrupt vector lo- and hi-bytes). Once everything is done you would enable raster interrupts via LDA #$01 : STA $D01A. |
| |
Oswald
Registered: Apr 2002 Posts: 5094 |
ok, but honestly thats rather a good practise than a cargo cult. you need to be sure of your enviroment, and then decide if to use sei/cli. not for the faint hearted :)
btw if anyone reads this make sure do also this:
lda #$7f
sta dc0d
sta dd0d
lda $dc0d
lda $dd0d
this will stop all timer irqs, and acknowledge any pending ones. many times have I wondered why my raster irq doesnt work after decades of coding, and it was a missing lda $dc0d often the case.
edit: I missed your note regarding dc0d, but frankly as above written many times I needed to add it in to make raster irq happen from basic! |
| |
JackAsser
Registered: Jun 2002 Posts: 2014 |
Quote: ok, but honestly thats rather a good practise than a cargo cult. you need to be sure of your enviroment, and then decide if to use sei/cli. not for the faint hearted :)
btw if anyone reads this make sure do also this:
lda #$7f
sta dc0d
sta dd0d
lda $dc0d
lda $dd0d
this will stop all timer irqs, and acknowledge any pending ones. many times have I wondered why my raster irq doesnt work after decades of coding, and it was a missing lda $dc0d often the case.
edit: I missed your note regarding dc0d, but frankly as above written many times I needed to add it in to make raster irq happen from basic!
especially when linking with other parts. Don't assume anything setup properly by the previous part. Assume crap in all registers imo. But for the initial kernel-takeover, fine no need to sei/cli etc. |
| |
Golara Account closed
Registered: Jan 2018 Posts: 212 |
I use sei/cli when changing irq only in demo parts, for one files I don't think I ever had a situation where I wanted to change the irq when (or where when thinking raster position) an irq could fire (i.e I'm on a way different line)
btw. I do inc $d019, just muscle memory. But that trick with writing anything with bit 0 set is good, i'll remember that.
Here's my little tip, though only about the assembler itself. Kickasm supports labels even in the middle of opcode. For example
lda var1:#$00
var1 points to the $00 itself, it's the same as
var1 = *+1
lda #$00
It's awesome for labeling your registers, it's almost like having variables in C (especially that you can have local labels between {}) My typical irq handler hence looks like this:
irq1:
{
sta rega
stx regx
sty regy
...
inc $d019
lda rega:#$00
ldx regx:#$00
ldy regy:#$00
rti
} |
| |
JackAsser
Registered: Jun 2002 Posts: 2014 |
Quote: I use sei/cli when changing irq only in demo parts, for one files I don't think I ever had a situation where I wanted to change the irq when (or where when thinking raster position) an irq could fire (i.e I'm on a way different line)
btw. I do inc $d019, just muscle memory. But that trick with writing anything with bit 0 set is good, i'll remember that.
Here's my little tip, though only about the assembler itself. Kickasm supports labels even in the middle of opcode. For example
lda var1:#$00
var1 points to the $00 itself, it's the same as
var1 = *+1
lda #$00
It's awesome for labeling your registers, it's almost like having variables in C (especially that you can have local labels between {}) My typical irq handler hence looks like this:
irq1:
{
sta rega
stx regx
sty regy
...
inc $d019
lda rega:#$00
ldx regx:#$00
ldy regy:#$00
rti
}
Just beware that such handler is not re-entrant itself, not will it handle background-loading over I/O. At least, have that in mind when linking if "random" stuff occurs. |
... 31 posts hidden. Click here to view all posts.... |
Previous - 1 | 2 | 3 | 4 | 5 - Next |