Getting Address Of Last Jump

Programming the 6502 microprocessor and its relatives in assembly and other languages.
Post Reply
User avatar
James_Parsons
Posts: 67
Joined: 10 Jul 2013

Getting Address Of Last Jump

Post by James_Parsons »

Is there a way I can use the PC or stack to find the location of the address the last

Code: Select all

JMP
or

Code: Select all

JSR
instruction that was called
JMP $FFD2
nyef
Posts: 235
Joined: 28 Jul 2013

Re: Getting Address Of Last Jump

Post by nyef »

JMP? Not unless you know your program's control-flow graph, and at that point it gets a little silly.

JSR? Well, as long as you haven't executed an RTS, and know what's been pushed to the stack since, it's two bytes before the return address on the stack. Otherwise, you're SOL.

And what on earth are you contemplating doing that requires such a thing?

"Are you pondering what I'm pondering, Pinky?" "I think so, Brain, but how do we find the address of the last JMP instruction that was executed?"
User avatar
GARTHWILSON
Forum Moderator
Posts: 8773
Joined: 30 Aug 2002
Location: Southern California
Contact:

Re: Getting Address Of Last Jump

Post by GARTHWILSON »

Getting the address of the last JSR is quite useful for things like DISPlaying IMmediate embedded data, for example:

Code: Select all

        JSR   DISP_QUOTE
        BYTE  25, "Press CONTINUE when ready"
or, if you make it a macro,

Code: Select all

        DISP_IM  "Press CONTINUE when ready"
where the DISP_QUOTE subroutine looks at the return address on the stack (without removing it) to know where to get the string to display, and uses the length byte (or alternately a 00 byte at the end) both to know how many bytes to display and what to adjust the return address to so the RTS doesn't take it back to try to execute data. These probably wreak havok with disassemblers but I've never concerned myself with that. In the subroutine, do a TSX then the low byte is at 101,X and the high byte at 102,X.
http://WilsonMinesCo.com/ lots of 6502 resources
The "second front page" is http://wilsonminesco.com/links.html .
What's an additional VIA among friends, anyhow?
nyef
Posts: 235
Joined: 28 Jul 2013

Re: Getting Address Of Last Jump

Post by nyef »

Okay, I'll concede the point for JSR, as that's an absolutely classic technique that I've run into (and used) before. But JMP?
User avatar
Arlet
Posts: 2353
Joined: 16 Nov 2010
Location: Gouda, The Netherlands
Contact:

Re: Getting Address Of Last Jump

Post by Arlet »

It would allow you to do this:

Code: Select all

JMP   DISP_QUOTE
BYTE  19, "This is a tail call"
User avatar
MichaelM
Posts: 761
Joined: 23 Apr 2012
Location: Huntsville, AL

Re: Getting Address Of Last Jump

Post by MichaelM »

James:

I don't think that we've addressed your question. The answer is that there is no way to know the address of the last JMP. The address of the last JSR is on the processor stack with an offset. I expect the offset to the actual opcode to be the return address on the stack -3. For JSR, the return address points to the first byte of the instruction following the JSR instruction. Since the JSR is a three byte instruction, the return address is the address of the JSR opcode + 3.

Accessing the value of the return address of a JSR instruction on the stack is pretty straight forward. There are several elements of the technique used to access that return address. First, the stack pointer, S, is always pointing to the first free location on the stack. Second, is to use pre-indexed absolute addressing mode, i.e. abs,X. Since S is an 8-bit register, any addition using S to calculate an address will be performed modulo 256. In other words, it will stay within the stack page.

Thus, the first step is to capture the stack pointer in the X index register. The second is to determine how many bytes relative to the current stack pointer (which points to first free location on the stack) is the value in which you are you are interested. For example, if you have not pushed any values onto the stack on entry into the DISP_QUOTE subroutine Garth gave in in his example, the low byte of the return address is 1 byte above the current stack pointer, and the high byte of the return address is 2 bytes above the current return address. If any registers have been pushed on the stack, then you'll have to take that into account.

To pull the return address from the stack and move it to a zero page location you do something like the following: (The following code assembles without errors, but has not been tested. Use only as an example of the technique for accessing values on the processor stack.)

Code: Select all

            org     $0
            ds      254            
pString     ds      2           ; Zero page location holds return address 
                                ;   which is a pointer to the string to display

            org     $0200       ; Beginning of RAM

Start:      jsr     Disp_Quote
            db      25, "Press CONTINUE when ready"
            
Next:       brk
           
            align   8
            
;   On entry all registers preserved on stack
;
;   Stack lays out as follows
;
;   S+1     A
;   S+2     X
;   S+3     Y 
;   S+4     P 
;   S+5     Return Lo 
;   S+6     Return Hi
;
;   Assume S = $80 and that its value is captured in X using tsx, then the 
;   address $105,x will yield $0185, which is S+5 in the stack page
;
;   At completion of this routine, return address on stack should point to Next
            
Disp_Quote: php                 ; Save all registers
            phy
            phx
            pha
            
            tsx                 ; Capture current stack pointer in X
            
            lda     $105,x      ; Read return address low from the stack
            sta     pString     ; Store in low byte of zp pointer
            lda     $106,x      ; Read return address high from the stack
            sta     pString+1   ; Store in high byte of zp pointer
            
            lda     (pString)   ; load count into X
            tax
            
            ldy     #$01        ; load index to first character in string
            
Disp_Lp:    lda     (pString),y ; load character into address
            jsr     put_ch      ; output character
            iny                 ; increment character index
            dex                 ; decrement character counter
            bne     Disp_Lp     ; loop until all characters sent to output
            
            tsx                 ; capture S in X
            
            clc                 ; prepare to offset the return address
            lda     (pString)   ; load string length into A
            adc     $105,x      ; add offset to low byte of return address
            sta     $105,x      ; store adjusted low byte of return address
            lda     #0          ; prepare to adjust high byte of return address
            adc     $106,x      ; add carry out of low byte adjustment
            sta     $106,x      ; store adjuste high byte of return address
            
            pla                 ; restore registers
            plx
            ply
            plp 
            
            rts                 ; return from Disp_Quote routine
            
;   Example output routine

put_ch:     sta     $F400       ;
            rts
Michael A.
User avatar
enso
Posts: 904
Joined: 29 Sep 2012

Re: Getting Address Of Last Jump

Post by enso »

James, to summarize:

JMP forces the processor to abandon the current location and transfer execution elsewhere;
JSR preserves the return address (just after the JSR xxx instruction) on the stack and transfers execution.

The return address is available on the stack and is used by RTS to return, or may be used by your code to determine where the call came from. The address may be used to pass data immediately following the JSR (you will have to adjust the return address on the stack to skip the data before returning).
In theory, there is no difference between theory and practice. In practice, there is. ...Jan van de Snepscheut
User avatar
BigDumbDinosaur
Posts: 9425
Joined: 28 May 2009
Location: Midwestern USA (JB Pritzker’s dystopia)
Contact:

Re: Getting Address Of Last Jump

Post by BigDumbDinosaur »

MichaelM wrote:
The address of the last JSR is on the processor stack with an offset. I expect the offset to the actual opcode to be the return address on the stack -3. For JSR, the return address points to the first byte of the instruction following the JSR instruction. Since the JSR is a three byte instruction, the return address is the address of the JSR opcode + 3.

RTS increments the address on the stack before loading it into the program counter. So the saved address points to the second operand byte of the JSR instruction. SAVED_ADDRESS - 2 gives you the address of the JSR opcode.
x86?  We ain't got no x86.  We don't NEED no stinking x86!
User avatar
Rob Finch
Posts: 465
Joined: 29 Dec 2002
Location: Canada
Contact:

Re: Getting Address Of Last Jump

Post by Rob Finch »

Quote:
Is there a way I can use the PC or stack to find the location of the address the last
Could you use a high speed interrupt like a single step interrupt to the processor, then look at the next instruction to see if it is a JMP/JSR and stuff the address of the instruction in a variable somewhere.

It''s possible to get the address with hardware by recording the jump triggered on the sync signal.
User avatar
BigDumbDinosaur
Posts: 9425
Joined: 28 May 2009
Location: Midwestern USA (JB Pritzker’s dystopia)
Contact:

Re: Getting Address Of Last Jump

Post by BigDumbDinosaur »

Rob Finch wrote:
Quote:
Is there a way I can use the PC or stack to find the location of the address the last
Could you use a high speed interrupt like a single step interrupt to the processor, then look at the next instruction to see if it is a JMP/JSR and stuff the address of the instruction in a variable somewhere.

It''s possible to get the address with hardware by recording the jump triggered on the sync signal.

Probably, but I would think performance would take a severe hit.
x86?  We ain't got no x86.  We don't NEED no stinking x86!
User avatar
GARTHWILSON
Forum Moderator
Posts: 8773
Joined: 30 Aug 2002
Location: Southern California
Contact:

Re: Getting Address Of Last Jump

Post by GARTHWILSON »

I seem to remember that that's how the AIM-65's we used in school in 1982 did single-stepping-- by using sync to generate an interrupt.
http://WilsonMinesCo.com/ lots of 6502 resources
The "second front page" is http://wilsonminesco.com/links.html .
What's an additional VIA among friends, anyhow?
nyef
Posts: 235
Joined: 28 Jul 2013

Re: Getting Address Of Last Jump

Post by nyef »

Well, if you're going that way, how about monitoring the CPU SYNC signal and the data bus for a $4C or $20 with SYNC high and using that combination of events to latch the contents of the address bus somewhere that you can read later? Should just require a tiny bit of programmable logic (or a handful of discrete logic) and a couple of 8-bit latches. Might even be able to do it with two 22V10 chips and no external latches. Your interrupt handlers might need to be cleverly designed so as to not corrupt the latch contents, but you should be able to run the system at full speed this way.
teamtempest
Posts: 443
Joined: 08 Nov 2009
Location: Minnesota
Contact:

Re: Getting Address Of Last Jump

Post by teamtempest »

You could pre-scan the program, either at load time or while it's still on mass storage, and replace every JSR and JMP with a BRK. Then the BRK handler could examine at run time what the destination is before letting execution of them happen (it'd have to be done in a way that preserved the BRK for next time, of course).

But if you can do that, you can find out the destinations of every JSR and every absolute JMP beforehand, so this would only make a real difference for indirect JMPs which can change at run time. Mmm, and perhaps for programs which can be relocated at load time, as well.
User avatar
barrym95838
Posts: 2056
Joined: 30 Jun 2013
Location: Sacramento, CA, USA

Re: Getting Address Of Last Jump

Post by barrym95838 »

I think that we might be approaching the concept of Intercal's COME FROM instruction, with all of it's amusing and ridiculous idiosyncrasies. It's doable in theory, but so is hammering a nail into my skull.

Mike
Post Reply