Page 1 of 1

JMP(nn) - indirect JMP question

Posted: Sat Jan 13, 2024 5:35 am
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?

Re: JMP(nn) - indirect JMP question

Posted: Sat Jan 13, 2024 6:18 am
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.

Re: JMP(nn) - indirect JMP question

Posted: Sat Jan 13, 2024 6:51 am
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.

Re: JMP(nn) - indirect JMP question

Posted: Sat Jan 13, 2024 7:21 am
by GARTHWILSON
That exact thing is addressed in the middle of the page I linked to.

Re: JMP(nn) - indirect JMP question

Posted: Sat Jan 13, 2024 7:43 am
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.

Re: JMP(nn) - indirect JMP question

Posted: Sat Jan 13, 2024 4:30 pm
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)

Re: JMP(nn) - indirect JMP question

Posted: Sat Jan 13, 2024 5:30 pm
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.

Re: JMP(nn) - indirect JMP question

Posted: Sat Jan 13, 2024 7:59 pm
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..

Re: JMP(nn) - indirect JMP question

Posted: Sat Jan 13, 2024 8:06 pm
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.

Re: JMP(nn) - indirect JMP question

Posted: Sat Jan 13, 2024 8:09 pm
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/ .

Re: JMP(nn) - indirect JMP question

Posted: Sat Jan 13, 2024 8:40 pm
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
;

Re: JMP(nn) - indirect JMP question

Posted: Sun Jan 14, 2024 3:33 am
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.

Re: JMP(nn) - indirect JMP question

Posted: Sun Jan 14, 2024 3:09 pm
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)

Re: JMP(nn) - indirect JMP question

Posted: Sun Jan 14, 2024 9:05 pm
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 :)

Re: JMP(nn) - indirect JMP question

Posted: Sun Jan 14, 2024 9:13 pm
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?