Skip to content

Commit

Permalink
Forth: differentiate *LOOP and *+LOOP
Browse files Browse the repository at this point in the history
  • Loading branch information
adumont committed Feb 27, 2022
1 parent 72a889a commit 429f3b4
Showing 1 changed file with 61 additions and 27 deletions.
88 changes: 61 additions & 27 deletions forth.s
Original file line number Diff line number Diff line change
Expand Up @@ -1320,8 +1320,8 @@ noheader "STAR_SKIP_DO"
defword "PLUS_LOOP","+LOOP",IMMEDIATE_FLAG
; : +LOOP LIT, *LOOP , ; IMMEDIATE " ;
JMP do_COLON
.ADDR do_COMPILE, do_STAR_PLUS_LOOP
call_from_do_LOOP:
.ADDR do_COMPILE, do_STAR_LOOP
.ADDR do_COMMA

; support for ?DO
Expand Down Expand Up @@ -1948,48 +1948,43 @@ noheader "STAR_DO"
defword "LOOP",,IMMEDIATE_FLAG
; : LOOP LIT, 1 LIT, *LOOP , ; IMMEDIATE
JMP do_COLON
.ADDR do_COMPILE, do_PUSH1
.ADDR do_JUMP, call_from_do_LOOP ; we fallback into +LOOP
; it's a small penalty at compile time, but code is more compact in ROM
.ADDR do_BREAK
.ADDR do_COMPILE, do_STAR_LOOP
.ADDR do_JUMP, call_from_do_LOOP

noheader "STAR_LOOP"
; ( INC -- )
; Used by LOOP, +LOOP, takes the increment on the stack
; Used by LOOP, takes NO arguments on the stack (we know the increment is 1)

; Previously, *LOOP and *+LOOP were the same. LOOP was just inserting a PUSH1 before calling *LOOP. Now I have differentiated both. In a normal LOOP, we don't need to PUSH1 , so we save 2 bytes in the dictionary (and it's a bit faster), also *LOOP already knows that the increment it 1.

; *LOOP should be followed by [ADDR], so IP points to ADDR
; where ADDR is the word after DO
; *LOOP will either run it (ie. jump back to DO) or bypass it (ie. leaving the DO LOOP)

; Copy INC (on ToS) to G1
LDA 2,X
STA G1
LDA 3,X
STA G1+1

; Drop INC from ToS
INX
INX
; Save X to G2
; Save X in Y
TXA
STA G2
TAY

; Transfer SP to X
TSX
; END and I (of DO/LOOP) are on the 6502 stack, after transfering S to X
; we can now address them like that:
; $104,X $103,X [ END ]
; $102,X $101,X [ I ]

; Add INC to I: I+INC -> I
; I++
CLC
LDA G1
ADC $101,X
LDA $101,X
ADC #1
STA $101,X
LDA G1+1
ADC $102,X
STA $102,X
BCC @skip
INC $102,X
@skip:

from_STAR_PLUS_LOOP:
; Compare I to END
; LDA $102,X ; HI I ; we can skip that line, as $102,X is in A already!
LDA $102,X ; HI I ; we can skip that line, as $102,X is in A already!
CMP $104,X ; HI END
BNE :+
LDA $101,X ; LO I
Expand All @@ -2003,8 +1998,8 @@ noheader "STAR_LOOP"
INX
INX
TXS
; Restore X from G2
LDA G2
; Restore X from Y
TYA
TAX

; Skip over the [ADDR]
Expand All @@ -2018,14 +2013,53 @@ noheader "STAR_LOOP"
: JMP NEXT

@loop_again:
; Restore X from G2
LDA G2
; Restore X from Y
TYA
TAX

; IP just happen to point to [ADDR]!
; now we call JUMP
JMP do_JUMP

noheader "STAR_PLUS_LOOP"
; ( INC -- )
; Used by LOOP, +LOOP, takes the increment on the stack

; *+LOOP should be followed by [ADDR], so IP points to ADDR
; where ADDR is the word after DO
; *+LOOP will either run it (ie. jump back to DO) or bypass it (ie. leaving the DO LOOP)

; Copy INC (on ToS) to G1
LDA 2,X
STA G1
LDA 3,X
STA G1+1

; Drop INC from ToS
INX
INX
; Save X in Y
TXA
TAY

TSX
; END and I (of DO/LOOP) are on the 6502 stack, after transfering S to X
; we can now address them like that:
; $104,X $103,X [ END ]
; $102,X $101,X [ I ]

; Add INC to I: I+INC -> I
CLC
LDA G1
ADC $101,X
STA $101,X
LDA G1+1
ADC $102,X
STA $102,X

; the end is ine STAR_LOOP (it was the same code, so I branch to it)
BRA from_STAR_PLUS_LOOP

defword "ROT",,
; ( x y z -- y z x )
; X, stack 2 -> W
Expand Down

0 comments on commit 429f3b4

Please sign in to comment.