6502.org Forum  Projects  Code  Documents  Tools  Forum
It is currently Thu Sep 19, 2024 11:17 pm

All times are UTC




Post new topic Reply to topic  [ 14 posts ] 
Author Message
PostPosted: Sun Sep 08, 2013 12:35 am 
Offline
User avatar

Joined: Wed Jul 10, 2013 3:13 pm
Posts: 67
Is there a way I can use the PC or stack to find the location of the address the last
Code:
JMP
or
Code:
JSR
instruction that was called

_________________
JMP $FFD2


Top
 Profile  
Reply with quote  
PostPosted: Sun Sep 08, 2013 12:55 am 
Offline

Joined: Sun Jul 28, 2013 12:59 am
Posts: 235
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?"


Top
 Profile  
Reply with quote  
PostPosted: Sun Sep 08, 2013 2:52 am 
Offline
User avatar

Joined: Fri Aug 30, 2002 1:09 am
Posts: 8509
Location: Southern California
Getting the address of the last JSR is quite useful for things like DISPlaying IMmediate embedded data, for example:
Code:
        JSR   DISP_QUOTE
        BYTE  25, "Press CONTINUE when ready"

or, if you make it a macro,
Code:
        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?


Top
 Profile  
Reply with quote  
PostPosted: Sun Sep 08, 2013 3:38 am 
Offline

Joined: Sun Jul 28, 2013 12:59 am
Posts: 235
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?


Top
 Profile  
Reply with quote  
PostPosted: Sun Sep 08, 2013 4:47 am 
Offline
User avatar

Joined: Tue Nov 16, 2010 8:00 am
Posts: 2353
Location: Gouda, The Netherlands
It would allow you to do this:
Code:
JMP   DISP_QUOTE
BYTE  19, "This is a tail call"


Top
 Profile  
Reply with quote  
PostPosted: Sun Sep 08, 2013 2:25 pm 
Offline
User avatar

Joined: Mon Apr 23, 2012 12:28 am
Posts: 760
Location: Huntsville, AL
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:
            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.


Top
 Profile  
Reply with quote  
PostPosted: Sun Sep 08, 2013 3:42 pm 
Offline
User avatar

Joined: Sat Sep 29, 2012 10:15 pm
Posts: 899
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


Top
 Profile  
Reply with quote  
PostPosted: Sun Sep 15, 2013 4:44 pm 
Offline
User avatar

Joined: Thu May 28, 2009 9:46 pm
Posts: 8387
Location: Midwestern USA
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!


Top
 Profile  
Reply with quote  
PostPosted: Sun Sep 15, 2013 5:19 pm 
Offline
User avatar

Joined: Sun Dec 29, 2002 8:56 pm
Posts: 452
Location: Canada
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.

_________________
http://www.finitron.ca


Top
 Profile  
Reply with quote  
PostPosted: Sun Sep 15, 2013 6:47 pm 
Offline
User avatar

Joined: Thu May 28, 2009 9:46 pm
Posts: 8387
Location: Midwestern USA
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!


Top
 Profile  
Reply with quote  
PostPosted: Sun Sep 15, 2013 8:06 pm 
Offline
User avatar

Joined: Fri Aug 30, 2002 1:09 am
Posts: 8509
Location: Southern California
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?


Top
 Profile  
Reply with quote  
PostPosted: Sun Sep 15, 2013 8:15 pm 
Offline

Joined: Sun Jul 28, 2013 12:59 am
Posts: 235
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.


Top
 Profile  
Reply with quote  
PostPosted: Mon Sep 16, 2013 4:39 am 
Offline

Joined: Sun Nov 08, 2009 1:56 am
Posts: 395
Location: Minnesota
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.


Top
 Profile  
Reply with quote  
PostPosted: Mon Sep 16, 2013 5:52 am 
Offline
User avatar

Joined: Sun Jun 30, 2013 10:26 pm
Posts: 1948
Location: Sacramento, CA, USA
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


Top
 Profile  
Reply with quote  
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 14 posts ] 

All times are UTC


Who is online

Users browsing this forum: No registered users and 20 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: