Porting FIG Forth 6502 to ca65 and UK101

Topics relating to various Forth models on the 6502, 65816, and related microprocessors and microcontrollers.
Post Reply
v6ops
Posts: 3
Joined: 24 Mar 2026

Porting FIG Forth 6502 to ca65 and UK101

Post by v6ops »

I recently bought a single board clone of a UK101 (I owned an original OSI C1E which was the donor for the clone).

I've ported what I believe to be an original listing of FIG Forth v1.1 (bugs and all) to ca65.

Code is here:https://github.com/v6ops/FIG-Forth-UK101/tree/UK101

This works as far as I can tell on the hardware UK101, but not on the run6502 simulator library. I'm probably doing something wrong there. It prompts and echos the line, but doesn't seem to exec (CR/LF issues??).

Q1. I had to add an extra line to BRAN: to get that working, because the branch offsets weren't being calculated correctly.
Was anyone else impacted by this?

L89 .BYTE $86,'BRANC',$C8
.WORD L75 ; link to EXCECUTE
BRAN .WORD *+2
; Y reg looks undefined. Assume Bug.
LDY #0 ; set offset to IP to 0. Doesn't change C bit.
; end

CLC
LDA (IP),Y
ADC IP
PHA
INY
LDA (IP),Y
ADC IP+1
STA IP+1
PLA
STA IP
JMP NEXT +2
;

Q2. Any idea why the hardware code runs, but the emulated code doesn't? I' normally expect the other way on.

Thanks
User avatar
Dr Jefyll
Posts: 3525
Joined: 11 Dec 2009
Location: Ontario, Canada
Contact:

Re: Porting FIG Forth 6502 to ca65 and UK101

Post by Dr Jefyll »

Hello, v6ops, and (belated) welcome. :)
Quote:
Q1. I had to add an extra line to BRAN: to get that working, because the branch offsets weren't being calculated correctly.
Firstly, allow me to suggest you use the Code tags for better clarity (see below).

As for the incorrect the branch offsets, adding the LDY #0 should not have made any difference.

[Edit: remove ill-considered theory]
Quote:
Y reg looks undefined. Assume Bug.
Y is left equal to zero by NEXT. So, Y isn't undefined if BRANCH executes immediately subsequent to NEXT (as is often the case). But BRANCH's code can also get jumped into from 0BRANCH and others, so perhaps one of those has somehow left Y non-zero.

I wonder if the problem may result from corruption in your copy of the FIG assembly source. In support of this idea, I notice the mis-spelled word "EXCECUTE" in one of the comments in the source code you posted. This mis-spelling doesn't appear in my own (ancient, dog-eared :) ) copy of the the FIG assembly source. So, perhaps your copy also includes *other* errors.
Quote:
Q2. Any idea why the hardware code runs, but the emulated code doesn't?
Interesting! But firstly let's answer Q1. Then perhaps we'll be better informed when it comes to Q2.

-- Jeff

Code: Select all

L89 .BYTE $86,'BRANC',$C8
.WORD L75 ; link to EXCECUTE
BRAN .WORD *+2
; Y reg looks undefined. Assume Bug.
LDY #0 ; set offset to IP to 0. Doesn't change C bit.
; end
CLC
LDA (IP),Y
ADC IP
PHA
INY
LDA (IP),Y
ADC IP+1
STA IP+1
PLA
STA IP
JMP NEXT +2
;
In 1988 my 65C02 got six new registers and 44 new full-speed instructions!
https://laughtonelectronics.com/Arcana/ ... mmary.html
v6ops
Posts: 3
Joined: 24 Mar 2026

Re: Porting FIG Forth 6502 to ca65 and UK101

Post by v6ops »

Thanks Jeff.

The tip you gave makes a lot of sense. I do see NEXT setting Y to 0. I was unaware that Y had to remain 0 as that's not in any comments, but that also makes sense.

Odd that X (the Forth stack pointer) is protected before calling these routines, but Y isn't.

Code: Select all

; original FIG Forth
XKEY:     STX XSAVE
          JSR INCH       ; might otherwise clobber it while
          LDX XSAVE      ; inputting a char to accumulator
          JMP PUSHOA
;
;         XQTER leaves a boolean representing terminal break
It's simple enough to preserve Y using exactly the same method as X.

I've tried quite a lot of debug but I haven't yet found anything conclusive to feed back.

regards,
Ray
User avatar
Dr Jefyll
Posts: 3525
Joined: 11 Dec 2009
Location: Ontario, Canada
Contact:

Re: Porting FIG Forth 6502 to ca65 and UK101

Post by Dr Jefyll »

v6ops wrote:
I was unaware that Y had to remain 0 as that's not in any comments
Apologies, Ray... If you look again you'll see I edited my post. This was promptly after I submitted the erroneous content, but unfortunately you'd already seen it, it seems.

To be clear, Y does not have to remain equal to zero. It is only assumed to be zero initially... that is, immediately following NEXT and thus upon entry to a primitive. It's handy being able to rely on that assumption because it relieves the need for some primitives, including BRANCH, to initialize Y upon entry. But it's OK for Y to be trashed when execution eventually jumps back to NEXT because NEXT makes no assumption; it explicitly reloads Y.

This leaves us with the question of why your system seemingly benefits when you insert a LDY #0 at the entry point for BRANCH. And BRANCH is a joker in the deck because, as I noted upthread, its entry point can be reached not only via NEXT but also by a few other paths: ie, conditional jumps directly from 0BRANCH and 1 or 2 others. Regarding these special cases, Y does needs to be zero when the primitive's exit jump occurs... it's not same as when the primitive exits by jumping to NEXT. So, there could be a problem with 0BRANCH, for example, failing to have Y=0 when it jumps into BRANCH.

But I suggest we set that line of thinking aside and take a wider view. It seems your version of the source code may be problematic, so IMO it's better to consider that overall aspect (rather than worrying about Y this or BRANCH that). How is it possible that the word "EXECUTE" would get transformed into "EXCECUTE"? What other glitches may your assembler have ingested?

Hope this helps,

Jeff
In 1988 my 65C02 got six new registers and 44 new full-speed instructions!
https://laughtonelectronics.com/Arcana/ ... mmary.html
Post Reply