summaryrefslogtreecommitdiff
path: root/doc
diff options
context:
space:
mode:
authorAndreas Baumann <mail@andreasbaumann.cc>2020-11-19 10:59:32 +0100
committerAndreas Baumann <mail@andreasbaumann.cc>2020-11-19 10:59:32 +0100
commit4c167d48f0f972ff9a5f0e10247aab71c50a141b (patch)
tree2956f0f591bf79c6cb265c1e828a702ffb46b018 /doc
parent055ca03ed8ebadaafea285bf79f7e85529663bab (diff)
download6502-4c167d48f0f972ff9a5f0e10247aab71c50a141b.tar.gz
6502-4c167d48f0f972ff9a5f0e10247aab71c50a141b.tar.bz2
added some docu and links
Diffstat (limited to 'doc')
-rw-r--r--doc/www_webmail_supervisord_org_tutorials_register_preservation.txt188
1 files changed, 188 insertions, 0 deletions
diff --git a/doc/www_webmail_supervisord_org_tutorials_register_preservation.txt b/doc/www_webmail_supervisord_org_tutorials_register_preservation.txt
new file mode 100644
index 0000000..b8833ff
--- /dev/null
+++ b/doc/www_webmail_supervisord_org_tutorials_register_preservation.txt
@@ -0,0 +1,188 @@
+ Register Preservation Using The Stack (and a BRK handler)
+
+ by Bruce Clark, 7 Jun 2004
+ __________________________________________________________________
+
+ On the 65C02, a subroutine can save the A, X, and Y registers without
+ altering them by using:
+PHA
+PHX
+PHY
+
+ The subroutine then restores A, X, and Y by exiting with:
+PLY
+PLX
+PLA
+RTS
+
+ The PHX/PLX and PHY/PLY instructions are not available on the 6502. On
+ the 6502, A, X, and Y are often saved using:
+PHA
+TXA
+PHA
+TYA
+PHA
+
+ which preserves X and Y, but overwrites A. The subroutine then restores
+ A, X, and Y by exiting with:
+PLA
+TAY
+PLA
+TAX
+PLA
+RTS
+
+ One way to preserve A (to allow it to be passed as a parameter to the
+ subroutine) -- as well as X and Y -- is to use:
+STA TEMP
+PHA
+TXA
+PHA
+TYA
+PHA
+LDA TEMP
+
+ which takes 4 additional bytes and 6 additional cycles if TEMP is a
+ zero page location, and 6 additional bytes and 8 additional cycles if
+ TEMP is an absolute memory location.
+
+ This is usually sufficient, but if, for example, the subroutine is used
+ by the main program and by an interrupt routine, interrupts must be
+ disabled so that TEMP will not be in use when the interrupt occurs.
+
+ An alternative is to use:
+PHA
+TXA
+TSX
+PHA
+TYA
+PHA
+INX
+LDA $100,X ; get A from the stack
+
+ which takes 5 additional bytes and 8 additional cycles (as compared to
+ the the first 6502 example, not the previous example) but interrupts
+ need not be disabled since it gets A from the stack rather than
+ requiring a special memory location. This could be used in a subroutine
+ called by an NMI (since an NMI can't be disabled). Remember, NMIs are
+ dangerous, and should be used with extreme caution if at all.
+
+ Notice that the idea is to get the stack pointer into X as soon as
+ possible so that the number INX instructions needed can be minimized.
+
+ The code above works correctly regardless of the value of the stack
+ pointer. As long as the stack pointer is not $FF, the last two
+ instructions could be replaced with a LDA $101,X instruction, which
+ would save 1 byte and two cycles. Ordinarily, this is not a problem
+ since the stack pointer is usually initialized to $FF (and will
+ therefore be less than $FF after the PHA). It goes without saying that
+ the software should be fully debugged before even considering the LDA
+ $101,X change.
+
+ The code above preserves A, but overwrites X. To preserve A, X, and Y,
+ use:
+PHA
+TXA
+TSX
+PHA
+TYA
+PHA
+INX
+LDA $100,X ; get A from the stack
+PHA
+DEX
+LDA $100,X ; get X from the stack
+TAX
+PLA
+
+ which is 7 bytes and 15 cycles longer than the previous example. This
+ may be more trouble than it is worth, but it could come in handy for
+ subroutines that are used for debugging (where the idea is to be as
+ independent as possible and to stay as far out of the way of the main
+ program as possible).
+
+ The preceding techniques can also be applied to the BRK/IRQ interrupt
+ handler. For example, on the 6502,
+PHA
+TXA
+TSX
+PHA
+INX
+INX
+LDA $100,X ; get the status register from the stack
+AND #$10 ; mask B flag
+BNE BREAK
+BEQ IRQ
+
+ can be used to determine whether the interrupt was caused by a BRK
+ instruction or an IRQ. Ordinarily, of course, the code would simply
+ fall through to the IRQ handler, eliminating the BEQ instruction. The
+ BRK and IRQ handlers would then exit with:
+PLA
+TAX
+PLA
+RTI
+
+ Alternatively, A and X could be restored immediately after branching
+ (or falling through) to the BRK or IRQ interrupt handler.
+
+ On the 65C02, with PHX and PLX available,
+PHX
+TSX
+PHA
+INX
+INX
+LDA $100,X ; get the status register from the stack
+AND #$10 ; mask B flag
+BNE BREAK
+BEQ IRQ
+
+ can be used, which takes 1 fewer byte and 2 fewer cycles than the 6502
+ example. The BRK and IRQ handlers would then exit with:
+PLA
+PLX
+RTI
+
+ which also takes 1 fewer byte and 2 fewer cycles than the 6502 example.
+
+ Note that A and X are saved in the opposite order that they were in the
+ 6502 example!
+
+ The B (Break) flag, bit 4 of the P (Processor status) register, is a
+ frequent source of confusion on the 6502. The sole purpose of this flag
+ is to distinguish a BRK from a IRQ. However, the behavior of BRK and
+ IRQ (and how to distinguish between the two) can be described without
+ even mentioning the B flag.
+
+ After the return address has been pushed onto the stack, a BRK
+ instruction pushes the value of the P register ORed with $10, then
+ transfers control to the BRK/IRQ interrupt handler.
+
+ After the return address has been pushed onto the stack, an IRQ
+ interrupt pushes the value of the P register ANDed with $EF, then
+ transfers control to the BRK/IRQ interrupt handler.
+
+ This means that the value of the P register that was pushed onto the
+ stack must be used to distinguish a BRK from a IRQ, not the value of
+ the P register upon entry to the BRK/IRQ interrupt handler.
+ Specifically,
+PHA
+PHP
+PLA
+AND #$10 ; mask B flag
+BNE BREAK
+BEQ IRQ
+
+ does NOT properly distinguish a BRK from an IRQ!
+
+ Chelly adds: At the end proper checking of the B flag is discussed. My
+ feedback is that it would be simpler to explain that there is no B flag
+ in the processor status register; that bit is simply unused. When
+ pushing the status register on the stack, that bit is set to a fixed
+ value based on the instruction/event (set for PHP and BRK, clear for
+ NMI). This is much simpler to explain and leads to no incorrect
+ assumption that there is a B flag in the status register that can be
+ checked.
+ __________________________________________________________________
+
+ Last page update: November 11, 2006.