6502.org Forum  Projects  Code  Documents  Tools  Forum
It is currently Fri Sep 20, 2024 4:48 pm

All times are UTC




Post new topic Reply to topic  [ 16 posts ]  Go to page 1, 2  Next
Author Message
PostPosted: Tue Jan 22, 2019 4:22 pm 
Offline

Joined: Wed Jul 18, 2018 12:12 pm
Posts: 96
I posted an update on my CNC-64 project to YouTube yesterday and got a very interesting tip from Stephen White. One tip he provided was to store the A, X, Y registers in zero page instead of the traditional pha, tya, etc. Since my NMI ISR runs at a 1kHz rate on a 1mHz 6510 (C64) every cycle in the ISR counts. Indeed this saved a precious 9 cycles in entry and 10 on exit of the ISR!

His other tip had to do with some redundant bits in my buffer read macro and the ISR, removing those saved another 5 cycles. So another 24,000 cycles are available every second!

Just thought I would pass this along as I did not find it just now when searching the forum.

WAS
Code:
        php                     ; (3) push status register to stack
        pha                     ; (3) save A register on stack
        tya                      ; (3) transfer Y to A to push to stack
        pha                     ; (3) save Y register on stack
        txa                      ; (3) transfer Xto A to push to stack
        pha                     ; (3) save X register on stack
                                  ; (18 cycles total)


NOW
Code:
        php                     ; (3) push status register to stack
        sta zpA                 ; (3) save A register to zero page
        stx zpX                 ; (3) save X register to zero page
        ;stY zpY                 ; (3) save X register to zero page
                                ; (9 cycles total, saved 9)


Top
 Profile  
Reply with quote  
PostPosted: Tue Jan 22, 2019 6:38 pm 
Offline
User avatar

Joined: Tue Mar 02, 2004 8:55 am
Posts: 996
Location: Berkshire, UK
If this code is at the start of an interrupt routine then the PHP is redundant, it's pushed automatically by the processor.

_________________
Andrew Jacobs
6502 & PIC Stuff - http://www.obelisk.me.uk/
Cross-Platform 6502/65C02/65816 Macro Assembler - http://www.obelisk.me.uk/dev65/
Open Source Projects - https://github.com/andrew-jacobs


Top
 Profile  
Reply with quote  
PostPosted: Tue Jan 22, 2019 7:35 pm 
Offline

Joined: Wed Jul 18, 2018 12:12 pm
Posts: 96
I did not think the PHP was done automatically for NMIs?

EDIT:
Don't know how I got that idea into my head, just found this: http://6502.org/tutorials/interrupts.html which says of course, just as you said the PHP is not needed. So, two more cycles saved!

EDIT #2, that is actually 7 cycles save, 3 for PHP and 4 for PLP!

Thanks


Top
 Profile  
Reply with quote  
PostPosted: Tue Jan 22, 2019 7:43 pm 
Offline
User avatar

Joined: Tue Mar 02, 2004 8:55 am
Posts: 996
Location: Berkshire, UK
IRQ, BRK and NMI all push the PC and status register. A power on reset goes through the same internal operations BUT does not enable the memory writes - If you connect a logic analyser you can see the stack addresses being generated.

https://en.wikipedia.org/wiki/Interrupts_in_65xx_processors

_________________
Andrew Jacobs
6502 & PIC Stuff - http://www.obelisk.me.uk/
Cross-Platform 6502/65C02/65816 Macro Assembler - http://www.obelisk.me.uk/dev65/
Open Source Projects - https://github.com/andrew-jacobs


Top
 Profile  
Reply with quote  
PostPosted: Tue Jan 22, 2019 7:53 pm 
Offline
User avatar

Joined: Tue Mar 02, 2004 8:55 am
Posts: 996
Location: Berkshire, UK
If you are using memory to save registers in interrupts and using both IRQ/BRK and NMI then they must save to different areas as your IRQ/BRK code could be interrupted by an NMI.

Many systems try to minimise the foot print of the firmware to leave as much as possible for the users application. Pushing to the stack is normally a reasonable thing to do but in your case saving to memory may be better if timing is very tight.

_________________
Andrew Jacobs
6502 & PIC Stuff - http://www.obelisk.me.uk/
Cross-Platform 6502/65C02/65816 Macro Assembler - http://www.obelisk.me.uk/dev65/
Open Source Projects - https://github.com/andrew-jacobs


Top
 Profile  
Reply with quote  
PostPosted: Tue Jan 22, 2019 8:00 pm 
Offline

Joined: Thu Jan 21, 2016 7:33 pm
Posts: 275
Location: Placerville, CA
Overall good idea, but I'm not sure why you bother saving A to ZP - it wastes a byte in the code, a byte in ZP, and saves you no cycles.


Top
 Profile  
Reply with quote  
PostPosted: Tue Jan 22, 2019 8:15 pm 
Offline

Joined: Wed Jul 18, 2018 12:12 pm
Posts: 96
commodorejohn wrote:
Overall good idea, but I'm not sure why you bother saving A to ZP - it wastes a byte in the code, a byte in ZP, and saves you no cycles.


It saves 1 cycled on exit. A lda from zero page is 3 cycles, a pla is 4 cycles...


Top
 Profile  
Reply with quote  
PostPosted: Tue Jan 22, 2019 11:48 pm 
Offline

Joined: Thu Jan 21, 2016 7:33 pm
Posts: 275
Location: Placerville, CA
Ah.


Top
 Profile  
Reply with quote  
PostPosted: Wed Jan 23, 2019 9:51 pm 
Offline

Joined: Fri May 05, 2017 9:27 pm
Posts: 890
Did you switch out the C64's kernel ROM after setting up your own interupt and reset vectors ( and any other routines needed) or did you hook into the C64's NMI handler at $318-$319?


Top
 Profile  
Reply with quote  
PostPosted: Thu Jan 24, 2019 12:42 am 
Offline

Joined: Wed Jul 18, 2018 12:12 pm
Posts: 96
I overwrote the NMI handler address at $0318-$0319 which has drawbacks but is simpler for now. I do not pass through to the kernel handler.


Top
 Profile  
Reply with quote  
PostPosted: Thu Jan 24, 2019 11:09 am 
Offline

Joined: Sat Jul 28, 2012 11:41 am
Posts: 442
Location: Wiesbaden, Germany
Just a note on your initial post: TXA, TAX, TYA & TAY take only 2 cycles and you are comparing saving Y to not saving Y. So the saving is just 2 cycles and on restore probably just 4 cycles.

_________________
6502 sources on GitHub: https://github.com/Klaus2m5


Top
 Profile  
Reply with quote  
PostPosted: Thu Jan 24, 2019 1:19 pm 
Offline

Joined: Wed Jul 18, 2018 12:12 pm
Posts: 96
Klaus2m5 wrote:
Just a note on your initial post: TXA, TAX, TYA & TAY take only 2 cycles and you are comparing saving Y to not saving Y. So the saving is just 2 cycles and on restore probably just 4 cycles.


Good catch! I was able to get rid of the php as well so now my entry and exit code is below.

@JimBoyd mentioned the kernel's NMI functionality and looking at it this morning this is the code that the NMI vector at $FFFA points to:

Code:
                *** NMI vector
.,FE43 78             SEI                  disable the interrupts
.,FE44 6C 18 03   JMP ($0318)     do NMI vector


So it seems that since I am hijacking the NMI after the indirect jump I should be adding a CLI upon exit though I don't see this in the kernel disassembly, it just ends with RTI.

my entry:
Code:
        sta zpA                 ; (3) save A register to zero page
        stx zpX                 ; (3) save X register to zero page
        ;stY zpY                 ; (3) save X register to zero page (not using)
                                ; (6 cycles total)


and exit:

Code:
        ;ldy zpY                 ; (3) grab old Y val from zero page (not used)
        ldx zpX                 ; (3) grab old X val from zero page
        lda zpA                 ; (3) grab old A val from zero page
        rti                     ; (6) all done
                                ; (12 cycles total)


Top
 Profile  
Reply with quote  
PostPosted: Thu Jan 24, 2019 2:16 pm 
Offline

Joined: Sat Jul 28, 2012 11:41 am
Posts: 442
Location: Wiesbaden, Germany
Jeff_Birt wrote:
So it seems that since I am hijacking the NMI after the indirect jump I should be adding a CLI upon exit though I don't see this in the kernel disassembly, it just ends with RTI.
Since RTI includes PLP a CLI is not required.

_________________
6502 sources on GitHub: https://github.com/Klaus2m5


Top
 Profile  
Reply with quote  
PostPosted: Thu Jan 24, 2019 3:07 pm 
Offline

Joined: Wed Jul 18, 2018 12:12 pm
Posts: 96
Klaus2m5 wrote:
Jeff_Birt wrote:
So it seems that since I am hijacking the NMI after the indirect jump I should be adding a CLI upon exit though I don't see this in the kernel disassembly, it just ends with RTI.
Since RTI includes PLP a CLI is not required.


Ah, OK. That had not occured to me before but makes sense. Thanks!


Top
 Profile  
Reply with quote  
PostPosted: Thu Jan 24, 2019 3:15 pm 
Offline
User avatar

Joined: Thu May 28, 2009 9:46 pm
Posts: 8389
Location: Midwestern USA
Klaus2m5 wrote:
Jeff_Birt wrote:
So it seems that since I am hijacking the NMI after the indirect jump I should be adding a CLI upon exit though I don't see this in the kernel disassembly, it just ends with RTI.
Since RTI includes PLP a CLI is not required.

Also, the SEI that the Commodore kernel inserts into the beginning of the NMI handler is unnecessary. IRQs are automatically disabled as part of the response to any interrupt.

_________________
x86?  We ain't got no x86.  We don't NEED no stinking x86!


Top
 Profile  
Reply with quote  
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 16 posts ]  Go to page 1, 2  Next

All times are UTC


Who is online

Users browsing this forum: No registered users and 41 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to: