JMP(nn) - indirect JMP question

Programming the 6502 microprocessor and its relatives in assembly and other languages.
Post Reply
glockr
Posts: 7
Joined: 26 Apr 2012

JMP(nn) - indirect JMP question

Post by glockr »

Hoping someone will explain what I'm missing in understanding how indirect JMPs work. For example:

Code: Select all

target     =$85

.org $200

LDA #0
STA target
LDA #10
STA target+1
...
JMP (target)
...
$1000 .WORD real_destination     ; say real_destination is located at $2500
...
real_destination: ...
The way I read the 6502 programming books, what should happen when the

Code: Select all

JMP (target)
is
executed is the CPU looks to where target is pointed (real_destination), and JMPs to real_destination. When
I run that code in the simulator though, it JMPs to target, i.e. $1000 and tries to execute whatever is there,
which crashes the program b/c it's an address, not valid machine code.

However, if I put a $6C (indirect JMP opcode) in front of target and change

Code: Select all

JMP (target)
to

Code: Select all

JMP target-1
it works the way I understand it should - the address JMPed to is real_destination.
What am I getting wrong?
User avatar
GARTHWILSON
Forum Moderator
Posts: 8773
Joined: 30 Aug 2002
Location: Southern California
Contact:

Re: JMP(nn) - indirect JMP question

Post by GARTHWILSON »

I think what you're looking for is a double indirect.  There's no native instruction to give you that; but you can use self-modifying code to efficiently get things like double indirects and double indexing.
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?
glockr
Posts: 7
Joined: 26 Apr 2012

Re: JMP(nn) - indirect JMP question

Post by glockr »

I'm trying to figure out how to get rid of the need for W in a FORTH system without using JSR to get into DOCOL or making it completely subroutine threaded. Thinking about your answer, I realize double indirection is what I'm looking for - just didn't know what it's called. I also understand now why fig-FORTH puts a $6C right in front of W and then NEXT does a JMP W-1 instead of just doing a JMP (W). Hmmm... if I put NEXT in zp I might not need double indirection.
User avatar
GARTHWILSON
Forum Moderator
Posts: 8773
Joined: 30 Aug 2002
Location: Southern California
Contact:

Re: JMP(nn) - indirect JMP question

Post by GARTHWILSON »

That exact thing is addressed in the middle of the page I linked to.
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?
IamRob
Posts: 357
Joined: 26 Apr 2020

Re: JMP(nn) - indirect JMP question

Post by IamRob »

glockr wrote:
Hoping someone will explain what I'm missing in understanding how indirect JMPs work. For example:

Code: Select all

target     =$85

.org $200

LDA #0
STA target
LDA #10
STA target+1
...
JMP (target)
...
$1000 .WORD real_destination     ; say real_destination is located at $2500
...
real_destination: ...
The way I read the 6502 programming books, what should happen when the

Code: Select all

JMP (target)
is
executed is the CPU looks to where target is pointed (real_destination), and JMPs to real_destination. When
I run that code in the simulator though, it JMPs to target, i.e. $1000 and tries to execute whatever is there,
which crashes the program b/c it's an address, not valid machine code.

However, if I put a $6C (indirect JMP opcode) in front of target and change

Code: Select all

JMP (target)
to

Code: Select all

JMP target-1
it works the way I understand it should - the address JMPed to is real_destination.
What am I getting wrong?
I think you are making the mistake in assuming that TARGET is the actual subroutine. In ITC Forth, TARGET is also an indirect address.
maurice6502
Posts: 21
Joined: 28 Dec 2023

Re: JMP(nn) - indirect JMP question

Post by maurice6502 »

Hi,
to make double indirect jump the simplest way should be :

- call your code that calculate final address
- push computed final address into stack (in just order..)
- RTS (that return to pointed address)
User avatar
lightbeing
Posts: 11
Joined: 15 Oct 2023
Location: Paris (France)

Re: JMP(nn) - indirect JMP question

Post by lightbeing »

Not sure that I understand your issue but there's a "bug" with the indirect JMP.

It works properly only if the low/high bytes of the pointing adress are on the same page.

JMP ($C0FF) will not fetch the effective jumping adress from $C100 but from $C000.
maurice6502
Posts: 21
Joined: 28 Dec 2023

Re: JMP(nn) - indirect JMP question

Post by maurice6502 »

lightbeing wrote:
Not sure that I understand your issue but there's a "bug" with the indirect JMP.

It works properly only if the low/high bytes of the pointing adress are on the same page.

JMP ($C0FF) will not fetch the effective jumping adress from $C100 but from $C000.
Correct, simple use it on zero page.. but is only indirect ..

But what do you are searching for?
JMP indirect outside zpage?
JMP double indirect?

Anyway with direct use of stack you can JSR or JMP to any location..
User avatar
GARTHWILSON
Forum Moderator
Posts: 8773
Joined: 30 Aug 2002
Location: Southern California
Contact:

Re: JMP(nn) - indirect JMP question

Post by GARTHWILSON »

maurice6502 wrote:
Hi,
to make double indirect jump the simplest way should be :

- call your code that calculate final address
- push computed final address into stack (in just order..)
- RTS (that return to pointed address)
Be careful:  If you do it that way, you need to use the target address minus 1, because RTS increments it before execution begins at the new address.
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?
User avatar
GARTHWILSON
Forum Moderator
Posts: 8773
Joined: 30 Aug 2002
Location: Southern California
Contact:

Re: JMP(nn) - indirect JMP question

Post by GARTHWILSON »

lightbeing wrote:
Not sure that I understand your issue but there's a "bug" with the indirect JMP.

It works properly only if the low/high bytes of the pointing adress are on the same page.

JMP ($C0FF) will not fetch the effective jumping adress from $C100 but from $C000.
That bug exists in the original NMOS versions of the 6502.  This bug, and all others, were fixed with the 65c02 (ie, CMOS), and does not exist in any of the CMOS versions.  See all the differences at http://wilsonminesco.com/NMOS-CMOSdif/ .
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?
glockr
Posts: 7
Joined: 26 Apr 2012

Re: JMP(nn) - indirect JMP question

Post by glockr »

I'm going to try this later (when I finish the honey-do list my wife just gave me). I'll have to change DOCOL too, but I think SEMIS can stay the same. Don't really want to use a JSR then pop and adjust the return pointer :)

Code: Select all

;
;$95	NEXT:		LDA IP
;$97				CLC
;$98				ADC #2
;$9A				BCC NNINC
;$9C				INC IP+1
;$9E	NNINC		STA IP
;$A0				JMP (**)
;$A1	IP			$adL $adH
;
BruceRMcF
Posts: 388
Joined: 21 Aug 2019

Re: JMP(nn) - indirect JMP question

Post by BruceRMcF »

glockr wrote:
Hoping someone will explain what I'm missing in understanding how indirect JMPs work. For example:

Code: Select all

target     =$85

.org $200

LDA #0
STA target
LDA #10
STA target+1
...
JMP (target)
...
$1000 .WORD real_destination     ; say real_destination is located at $2500
...
real_destination: ...
The way I read the 6502 programming books, what should happen when the

Code: Select all

JMP (target)
is executed is the CPU looks to where target is pointed (real_destination), and JMPs to real_destination.
The direct jump loads the two byte address operand and it becomes the new execution address. The indirect jump loads the two byte vector operand and then loads the two byte address located where the vector is pointing.

So if you have a set of 16 indirect vectors at $0300-$0332, you can "JMP ($0306)" to jump to the address that is stored as the third vector in that list.

Now, if you have a direct threaded Forth, you can have the instruction pointer "IP" as the vector for the indirect jump, and still use it as a zero page pointer for words like "LIT", by putting the indirect JMP opcode in front of the IP vector and jumping to it:

Code: Select all

JMPIP = <base address in ZP>
IP = JMPIP+1
IPH = IP+1

SETUPIP: LDA #$6C
        STA JMPIP
        LDA #$FF
        STA IP
        LDA #$FC
        RTS
...

NEXT:
        INC IP
        BEQ +
        INC IP
        BEQ ++
        JMP JMPIP
+       INC IP
++      INC IPH
        JMP JMPIP
... 
Quote:
When I run that code in the simulator though, it JMPs to target, i.e. $1000 and tries to execute whatever is there, which crashes the program b/c it's an address, not valid machine code.
Exactly. You have the address of "target", which is $0084, as the operand. Rather than jumping to $0084, it loads what is contained AT $0084, the address $1000, and jumps there instead.

What you seemed to have wanted is a DOUBLY indirect jump, that loads the operand, loads the vector that it points to, and uses THAT to load the address to jump to, and the 65C02 doesn't have one.
Quote:
However, if I put a $6C (indirect JMP opcode) in front of target and change

Code: Select all

JMP (target)
to

Code: Select all

JMP target-1
it works the way I understand it should - the address JMPed to is real_destination.

What am I getting wrong?
Nothing is wrong: if you put a $6C in front of target, then the indirect jump loads the following operand address as the location that holds the address to jump to, so $1000 is used as a vector, with the contents as the address. If you had put $20 in front of target, then the direct jump would have simply jumped to the address at target, as the indirect JMP (target) had done before.
User avatar
BB8
Posts: 57
Joined: 01 Nov 2020
Location: Tatooine

Re: JMP(nn) - indirect JMP question

Post by BB8 »

When executing a JMP (nn) the cpu goes to the address nn and nn+1, takes the two bytes there and puts them on the PC (in other words nn and nn+1 contain the address of the next instruction to be executed).

Possibly what you want to do is simply:

Code: Select all

JMP ($1000)
or alternatively:

Code: Select all

lda $1000
sta target
lda $1000+1
sta target+1
...
jmp (target)
glockr
Posts: 7
Joined: 26 Apr 2012

Re: JMP(nn) - indirect JMP question

Post by glockr »

BB8 wrote:
When executing a JMP (nn) the cpu goes to the address nn and nn+1, takes the two bytes there and puts them on the PC (in other words nn and nn+1 contain the address of the next instruction to be executed).

Possibly what you want to do is simply:

Code: Select all

JMP ($1000)
or alternatively:

Code: Select all

lda $1000
sta target
lda $1000+1
sta target+1
...
jmp (target)
That's what I wanted. My mistake was confusing names and addresses. So when I wrote

Code: Select all

target     =$AE
...
LDA #$12
STA target
LDA #$1F
STA target+1
JMP(target)
the intention was a JMP to whatever address target pointed at, 6C 1F 12 but I should have realized
it was assembling (as it should) to 6C AE 00. I understand it now thanks to the explanations here :)
6502inside
Posts: 101
Joined: 03 Jan 2007
Location: Sunny So Cal
Contact:

Re: JMP(nn) - indirect JMP question

Post by 6502inside »

glockr wrote:
Hoping someone will explain what I'm missing in understanding how indirect JMPs work. For example:

Code: Select all

target     =$85

.org $200

LDA #0
STA target
LDA #10
STA target+1
...
JMP (target)
...
$1000 .WORD real_destination     ; say real_destination is located at $2500
...
real_destination: ...
Gonna ask a stupid question: did you mean #10 or #$10?
Post Reply