.from: http://nesdev.parodius.com/the%20%27B%27%20flag%20&%20BRK%20instruction.txt
6502 'B' flag & BRK opcode
Brad Taylor
The B flag
----------
No actual "B" flag exists inside the 6502's processor status register. The B
flag only exists in the status flag byte pushed to the stack. Naturally,
when the flags are restored (via PLP or RTI), the B bit is discarded.
Depending on the means, the B status flag will be pushed to the stack as
either 0 or 1.
software instructions BRK & PHP will push the B flag as being 1.
hardware interrupts IRQ & NMI will push the B flag as being 0.
A note on the BRK opcode
------------------------
Regardless of what ANY 6502 documentation says, BRK is a 2 byte opcode. The
first is #$00, and the second is a padding byte. This explains why interrupt
routines called by BRK always return 2 bytes after the actual BRK opcode,
and not just 1.
6502 coded breakpoint handlers that treat BRK as a 1-byte opcode have to
manually decrement the return address stored on the stack before executing a
RTI:
tsx; get stack pointer into index register
sec; ensure carry is set before subtracting
;decrement low byte of rtn address
lda $0102,x
sbc #$01
sta $0102,x
;decrement high byte of rtn address (if no carry)
lda $0103,x
sbc #$00
sta $0103,x
rti; return to byte after BRK opcode
Of course, none of this code (except "rti") is neccessary if BRK is
assembled as a 2-byte opcode.
BRK in detail
-------------
In the 7 clock cycles it takes BRK to execute, the padding byte is actually
fetched, but the CPU does nothing with it. The diagram below will show the
bus operations that take place during the execution of BRK:
cc addr data
-- ---- ----
1 PC 00 ;BRK opcode
2 PC+1 ?? ;the padding byte, ignored by the CPU
3 S PCH ;high byte of PC
4 S-1 PCL ;low byte of PC
5 S-2 P ;status flags with B flag set
6 FFFE ?? ;low byte of target address
7 FFFF ?? ;high byte of target address
making use of the padding byte
------------------------------
With some external hardware, it is possible to take advantage of the padding
byte. For example, a good use for this byte would be to index an interrupt
vector to swap into addresses $FFFE & $FFFF, so that a 256 software
interrupt scheme could be implemented.
On regular 6502's, BRK could be detected with an 8-input "OR" gate (tied to
the data bus), gated with "SYNC". The padding byte would then appear on the
data bus one clock cycle after detecting BRK.
There is no SYNC signal available on the NES's 2A03, so obtaining the
padding byte is a little trickier, but still possible. The first step is to
have an 8-bit latch that is loaded with the contents of the data bus on
every clock cycle _except_ during write cycles. Next, hardware must be
implemented to detect 3 consecutive write cycles to the stack (only
interrupts can do 3 writes in a row), plus make sure that bit 4 during the
3rd stack write is set (1) (this 3rd write contains the B flag, which will
be set if the interrupt was caused by BRK). Finally, if all these tests
pass, this means the BRK instruction is in progress, and the latch register
contains the valid padding byte. The latched value can now be used to swap
in the values to use for the next 2 clock cycles (the BRK vector fetch).
Note that since all of this won't happen unless BRK is executed, IRQ & BRK
routines will effectively be seperate from each other (i.e., IRQ will still
use the vector at $FFFE, but BRK will now use a 512-byte jump table at e.g.,
$8000).
EOF
No comments:
Post a Comment