Page 1 of 1
Getting Address Of Last Jump
Posted: Sun Sep 08, 2013 12:35 am
by James_Parsons
Is there a way I can use the PC or stack to find the location of the address the last
or
instruction that was called
Re: Getting Address Of Last Jump
Posted: Sun Sep 08, 2013 12:55 am
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?"
Re: Getting Address Of Last Jump
Posted: Sun Sep 08, 2013 2:52 am
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.
Re: Getting Address Of Last Jump
Posted: Sun Sep 08, 2013 3:38 am
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?
Re: Getting Address Of Last Jump
Posted: Sun Sep 08, 2013 4:47 am
by Arlet
It would allow you to do this:
Code: Select all
JMP DISP_QUOTE
BYTE 19, "This is a tail call"
Re: Getting Address Of Last Jump
Posted: Sun Sep 08, 2013 2:25 pm
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
Re: Getting Address Of Last Jump
Posted: Sun Sep 08, 2013 3:42 pm
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).
Re: Getting Address Of Last Jump
Posted: Sun Sep 15, 2013 4:44 pm
by BigDumbDinosaur
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.
Re: Getting Address Of Last Jump
Posted: Sun Sep 15, 2013 5:19 pm
by Rob Finch
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.
Re: Getting Address Of Last Jump
Posted: Sun Sep 15, 2013 6:47 pm
by BigDumbDinosaur
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.
Re: Getting Address Of Last Jump
Posted: Sun Sep 15, 2013 8:06 pm
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.
Re: Getting Address Of Last Jump
Posted: Sun Sep 15, 2013 8:15 pm
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.
Re: Getting Address Of Last Jump
Posted: Mon Sep 16, 2013 4:39 am
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.
Re: Getting Address Of Last Jump
Posted: Mon Sep 16, 2013 5:52 am
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