easy6502
easy6502 copied to clipboard
simple cursor
I'm just getting used to the built-in 6502 emulator. I'm having problems trying a code even a simple cursor. All I want is a single dot that could move up, down, left, and right by my command. What could I do to accomplish this?
Maybe take a look at the snake game: if you cut the snake down to one cell, and stop it moving, it's pretty close to a cursor, perhaps.
I have a similar problem.
You can't stop something moving, because $ff only contains the last key pressed, A released key can't be detected with $ff. I have tried to simulate a released key by writiting #$00 to $ff before reading the value once more from it, but it always stays at $00 after that.
Ah, that's a bit of a problem. Here in the JavaScript we see
$(document).keypress(memory.storeKeypress);
which detects keypresses. But there's nothing to detect key releases. It wouldn't be too hard to add a handler for $(document).keyup(memory.clearKeypress) which could set $ff back to $00. Would that be a good idea? Would it demand that the Snake demo be rewritten?
(Just to note: with this simple change, typing say 'L' would give you keypress for shift, keypress for L, and then two key-up events, the first of which would clear $ff.)
Interesting. I hope @skilldrick takes a look and considers a patch.
Try this - it has the right effect I think, but it does mean that the Snake demo (and anything else) can now easily miss a short keypress. Previously keys were sticky. http://biged.github.io/easy6502/#snake
But hang on, your approach of writing $00 to $ff should have worked. It seems to work with this demo:
go:
LDA $ff
BEQ go
STA $f8
LDA #0
STA $ff
jmp go
Okay that works.
But not this:
start:
LDX #0
STX $0200
LDA $ff
BEQ start
LDX #05
STX $0200
LDA #0
STA $FF
JMP start
Basically, the pixel in the upper left should be visible when I press a key and disappear when I release the key. I guess it is a timing thing... Not enough time to recognize the pressed key. But I am not that great 6502 assembler programmer (yet)... I don't know.
Would be cool to have a robust code snippet that works.
I had a look, and it doesn't quite do that: $ff isn't a register which holds the code for the currently-pressed key, like a keyboard interface might do, instead it's a register which holds the code of the last key pressed. So, if you read it and set it to zero, you see each keypress just once. If you don't set it to zero, you keep seeing the same key, even if released.
(If the key is held down, then after a short delay the keyboard will start auto-repeating, and that will appear as a succession of keypresses.)
You can see this with this program:
LDX #0
waitforkey:
LDA $ff
BEQ waitforkey
LDA #05
STA $0200,x
INX
LDA #0
STA $ff
JMP waitforkey
The code in my fork is presently different: it will clear the register when the key is released. That opens the possibility of missing the key, whereas the presently published code in the main fork can't miss a keypress. (It has no rollover: if two keys were pressed in quick succession, you'd only see the second.)
Ahh I see. But your example works quite well for many use cases I guess. A cursor should be possible now
Here's a simple cursor routine: a bit of a spoiler so encoded with rot13
; Hfvat K nybar gb vaqrk vagb gur fperra
; jr whfg trg 32k8 nern gb cynl va
YQK #$90 ; zvqqyr bs gur rnfl-gb-ernpu nern
cybg:
FGK $sp ; sbe qroht
YQN #05
FGN $0200,k
WZC jnvgsbexrl
jnvgsbexrl:
YQN $ss
ORD jnvgsbexrl
FGN $s8
YQN #0
FGN $ss ; pyrne gur xrlcerff sbe arkg gvzr
FGN $200,K ; pyrne gur pheerag cvkry
YQN $s8
; JNFQ ner $77 $61 $73 $64
PZC #$70
OPF hcqbja
yrsgevtug:
PZC #$62
OPF evtug
yrsg:
QRK ; bss gur rqtr? jub pnerf!
WZC cybg
evtug:
VAK
WZC cybg
hcqbja:
PZC #$74
OPF hc
qbja:
GKN
PYP
NQP #32
GNK
WZC cybg
hc:
GKN
FRP
FOP #32
GNK
WZC cybg
Wait, I got it! This is the code:
define ascii $ff
define upMove $77
define downMove $73
define rightMove $64
define leftMove $61
define CursorPosition $200
CursorStart:
ldx #$f1
stx $02
lda #$01
sta CursorPosition,x
keyFinder:
lda $ff
cmp #upMove
beq moveUp
cmp #downMove
beq moveDown
cmp #rightMove
beq moveRight
cmp #leftMove
beq moveLeft
jmp keyFinder
moveUp:
lda #$00
sta ascii
lda #$00
sta CursorPosition,x
ldy #$00
sty $03
toTwenty:
dex
iny
sty $03
ldy $03
cpy #$20
beq newUp
jmp toTwenty
newUp:
lda #$01
sta CursorPosition,x
jmp keyFinder
moveDown:
lda #$00
sta ascii
lda #$00
sta CursorPosition,x
ldy #$00
sty $03
toTwentytoo:
inx
iny
sty $03
ldy $03
cpy #$20
beq newDown
jmp toTwentytoo
newDown:
lda #$01
sta CursorPosition,x
jmp keyFinder
moveLeft:
lda #$00
sta ascii
sta CursorPosition,x
dex
lda #$01
sta CursorPosition,x
jmp keyFinder
moveRight:
lda #$00
sta ascii
sta CursorPosition,x
inx
lda #$01
sta CursorPosition,x
jmp keyFinder
The only trouble that's left is how I can make the dot go further down. Also, the dot glitches a bit when moving vertically.
I finally got this to work, don't use absolute addressing mode for the reason that it only wraps around the last 2 bytes. Use indexed indirect because then you will be able to update both the high and low bytes.
Edit: I did not define at all, sorry, I am putting in comments to make it easier to read.
;up is #$77 ;left is #$61 ;down is #$73 ;right is #$64 ;$06 is like a counter that skips 20 bytes for up and down
LDA #$02 ;$XX00 High STA $04
LDA #$00 ;$00XX low STA $03
JMP UPLEFT ;follow the comments to loop UPLEFT
MINUS: ;and finally at this loop I refresh the screen and finish the $06 counter for up and down LDA #$00 ; so that $03 will contain the same left and right position for the next move down STA ($03,X) DEC $03 INC $06 LDA $06 CMP #$1f BNE MINUS LDA #$00 STA ($03,X) DEC $04 ;I then decrement $04 so that it does not just wrap around at $03. LDA #$01 STA ($03,X) JMP DONE ;jump to done
OVERFLOWUPLEFT: LDA $ff ;I then check the inputs, again because I don't know which direction is warping CMP #$61 ;around. For instance, When it is up that is warping around it branches to MINUS ^ BEQ DONE LDA $03 CMP #$00 BEQ MINUS
DONE: LDA #$00 ;I then zero out the input and jump to RESET STA $ff JMP RESET
PLUS: LDA #$00 STA ($03,X) INC $03 INC $06 LDA $06 CMP #$1f BNE PLUS LDA #$00 STA ($03,X) INC $04 LDA #$01 STA ($03,X) JMP DONE2
OVERFLOWDOWNRIGHT: LDA $ff CMP #$64 BEQ DONE2 LDA $03 CMP #$ff BEQ PLUS
DONE2: LDA #$00 STA $ff JMP RESET
RESET: ;in here I refresh the screen and then I check each input, I need to fix this part, it is
LDA #$00 ; a bit awkward
STA ($03,X)
LDA #$01
STA ($03,X)
LDA $ff
CMP #$77
BEQ OVERFLOWUPLEFT ;these loops that check the overflow are here because the wraparound
CMP #$61 ;so when it does...^ go up to OVERFLOWLEFT
BEQ OVERFLOWUPLEFT
CMP #$73
BEQ OVERFLOWDOWNRIGHT
CMP #$64
BEQ OVERFLOWDOWNRIGHT
LDA #$00
STA $ff
LDA $06
CMP #$00
BEQ UPLEFT
DEC $06
JMP RESET
UPLEFT:
LDA $ff ;at first I was just trying to get the inputs from $ff a better and faster way, but I basically
CMP #$77 ;ended up doing the same thing I did before in the reset loop.
BEQ UPIF ;so it basically looks for #$77 and if it is then it jumps to upif
CMP #$61
BNE DOWNRIGHT
;NOW inc for LEFT or up
LDA #$00
STA ($03,X)
DEC $03 ;this part is for left, so it just decrements once, not that complicated.
JMP RESET UPIF: ;when it jumps here, I make $06 the counter and it is pretty self explanatory. LDA #$00 STA ($03,X) DEC $03 LDA $03 CMP #$00 ;I am comparing the low bytes in $03 to #$00 because when you DEC and it is already BEQ RESET ; #$00 then it basically wraps around to #$ff and that is annoying, so I go to RESET INC $06 LDA $06 CMP #$20 BNE UPIF
JMP RESET
DOWNRIGHT: LDA $ff CMP #$73 BEQ DOWNIF CMP #$64 BNE UPLEFT ;NOW inc for right or DOWN LDA #$00 STA ($03,X) INC $03
JMP RESET DOWNIF: LDA #$00 STA ($03,X) INC $03 LDA $03 CMP #$ff BEQ RESET INC $06 LDA $06 CMP #$20 BNE DOWNIF JMP RESET