See Also: part 1, part 2, part 3, part 4, part 5 and more to come…
Version 2 of this code added support for moving the cursor UP, DOWN, LEFT and RIGHT. BUT, it was processing these special characters at all times, including when you typed them in. This was confusing to me, so I wanted to add some way to make them only process when the program is PRINTing them, not when you are just typing them from a command line.
I was unsure how to approach this but ended up looking at CURLIN. This is what line number BASIC is processing or &HFFFF if in “direct mode” (where you type in program lines).
From checking the disassembly, I should be able to add a quick check when deciding to process the special characters and only do that if CURLIN was &HFFFF. The code I added looked like this:
newcode
...snip...
* Do this only if NOT in Direct mode. Problem: After a BREAK, CURLIN
* has not been updated yet, so the very first line you type will be
* processing the special characters. Lines after that will not. Trying
* to find a different way to detect this.
pshs a save A
lda CURLIN GET CURRENT LINE NUMBER (CURLIN)
inca TEST FOR DIRECT MODE
puls a restore A
beq continue if 0, in direct mode.
...snip...
I was unsure what registers I could use, so I saved A and used it, then restored it. If you look at the ROM code, you will see sometimes it will load the bull 16-bit value and check against FFFF, and other times it just loads the first byte and checks that. I decided to do it that way.
This code loads the first byte then increments it. If it was FF, then it should increment/wrap around back to 0, which will set the zero bit (I think) and match a BEQ (branch if equal). I expect there is a better way to do this, but this is what I came up with.
Now, typing the lowercase “u”, “d”, “l” and “r” do not move the cursor around the screen, but PRINTing them in a program will. The downside is if you try to type a PRINT from the command line, it will not be processed — only the PRINTs from the program when it is RUNning.
Is this good enough?
Ah, but there was still a problem. When BASIC returns from running a program, I found it would still process those characters! Then it would stop. I eventually figured out it would process the FIRST line after returning to direct mode, then would behave as I wanted it after that.
I found this code in the ROM:
* THIS IS THE MAIN LOOP OF BASIC WHEN IN DIRECT MODE
LAC73 JSR LB95C MOVE CURSOR TO START OF LINE
LDX #LABE1-1 POINT X TO ‘OK’, CR MESSAGE
JSR LB99C PRINT ‘OK’, CR
LAC7C JSR LA390 GO GET AN INPUT LINE
LDU #FFFF THE LINE NUMBER FOR DIRECT MODE IS $FFFF
STU CURLIN SAVE IT IN CURLIN
For “some reason”, the routine first jumps (JSR) to the code to read a line, THEN it sets the direct mode line number to FFFF. This means the first line you type still has CURLIN set to the last line the program executed. I am sure there is reason for this, but that explains the problem.
I now present the full version of the code, but will show a way William Astle suggested I make it more better in the next installment:
* lwasm consmove3.asm -fbasic -oconsmove3.bas --map
* Allow embedded characters to move the cursor in a PRINT.
UP equ 'u character for up
DOWN equ 'd character for down
LEFT equ 'l character for left
RIGHT equ 'r character for right
CURLIN equ $68 *PV CURRENT LINE # OF BASIC PROGRAM, $FFFF = DIRECT
DEVNUM equ $6f device number being used for I/O
CURPOS equ $88 location of cursor position in RAM
RVEC3 equ $167 console out RAM hook
VIDRAM equ $400 VIDEO DISPLAY AREA
org $7f00
init
lda RVEC3 get op code
sta savedrvec save it
ldx RVEC3+1 get address
stx savedrvec+1 save it
lda #$7e op code for JMP
sta RVEC3 store it in RAM hook
ldx #newcode address of new code
stx RVEC3+1 store it in RAM hook
rts done
uninstall
* TODO
newcode
* Do this only if DEVNUM is 0 (console)
tst DEVNUM is DEVNUM 0?
bne continue not device #0 (console)
* Do this only if NOT in Direct mode. Problem: After a BREAK, CURLIN
* has not been updated yet, so the very first line you type will be
* processing the special characters. Lines after that will not. Trying
* to find a different way to detect this.
pshs a save A
lda CURLIN GET CURRENT LINE NUMBER (CURLIN)
inca TEST FOR DIRECT MODE
puls a restore A
beq continue if 0, in direct mode.
leas 2,s remove PC from stack since we won't be returning there.
* Now this is the start of what Color BASIC ROM does for PUTCHR:
* PUT A CHARACTER ON THE SCREEN
LA30A
PSHS X,B,A SAVE REGISTERS
LDX CURPOS POINT X TO CURRENT CHARACTER POSITION
checkup
cmpa #UP
bne checkdown
CMPX #VIDRAM+32 second line or lower?
blt goLA35D disallow if on top line.
leax -32,x move up one line
bra done
checkdown
cmpa #DOWN
bne checkleft
cmpx #VIDRAM+512-32
bge goLA35D disallow if on bottom line.
leax 32,X move down one line
bra done
checkleft
cmpa #LEFT
bne checkright
cmpx #VIDRAM top left of screen?
beq goLA35D
leax -1,X move left one character
bra done
checkright
cmpa #RIGHT
bne goLA30E
cmpx #VIDRAM+511 bottom right of screen
beq goLA35D
leax 1,x increment X, skipping that location.
bra done
goLA30E
jmp $A30E jump back into Color BASIC ROM code.
done
stx CURPOS update cursor position
goLA35D
jmp $A35D jump back into Color BASIC ROM code.
continue
savedrvec rmb 3 call regular RAM hook
rts just in case...
end
And here is a BASIC loaded:
5 CLEAR 200,&H7F00
10 READ A,B
20 IF A=-1 THEN 70
30 FOR C = A TO B
40 READ D:POKE C,D
50 NEXT C
60 GOTO 10
70 END
80 DATA 32512,32616,182,1,103,183,127,105,190,1,104,191,127,106,134,126,183,1,103,142,127,24,191,1,104,57,13,111,38,77,52,2,150,104,76,53,2,39,68,50,98,52,22,158,136,129,117,38,10,140,4,32,45,50,48,136,224,32,43,129,100,38,10,140,5,224,44,36
90 DATA 48,136,32,32,29,129,108,38,9,140,4,0,39,22,48,31,32,16,129,114,38,9,140,5,255,39,9,48,1,32,3,126,163,14,159,136,126,163,93,32620,32620,57,-1,-1
To be continued…
