Aha, a non-cheating version.
Critical design change:
The special key row does not go to d4, but rather to d6, for detection by BIT key
[
Edit: except scroll down, I was totally wrong about this being needed for this approach to work.

It works just fine with "non-key" reading out as $00, "hex keys" reading out as $8x, and "special keys" reading out as $90-$93 -- albeit having "non-keys" read as $80, hex as their hex value, $0x, and "special keys" read out as $10-$13 would save two bytes.]
Non-critical design change:
"no-key" sets d7, "key" resets d7, so the d7 bit doesn't have to be cleaned up when a hex value as the new low nybble is being "or"ed with the new high nybble (not doing this leaves the requirement for an "AND #$7F" in place.
Design specification: this can work with various allocations of special keys, but I put the review key, "<-" in column 0, the go key, "->", in column 1, and the CR key in column 3.
Instead of trying to make it possible to set an address, this version accepts that there is a single starting address and GO will jump to that address ... and uses restarting the whole thing, including the original setting of the address, to go back for the review run.
The key to making the <- function fit in was the realization that it doesn't have to be prevented from auto-repeating ... because multiple repeated executions of setting W:W+1 to $00:$02 for a single press of the <- (or "review") key gives the same result as a single "<-" keypress. So just going to the start where the base address is originally set should work.
Putting the tac switch (or whatever button) for that on the 0 column is partly so that the review key, at least, shouldn't glitch the LED display ... if still pressed, it will run through one full column cycle of unpressed keys until hitting the 0 column and redo the restart at that point. But it is also an aesthetic choice, since if the ReView key is a silkscreened as a left "<-" arrow, then the GO switch next to it can be silkscreened as a right "->" arrow if desired.
Or a more mundane, though likely more mnemonic, "RV" (for review or reverse, take your pick), "GO" and "CR". (Also noting that "GB" for Go Back and "GA" for "Go Ahead" would be both mundane and also excessively obscure.)
Rather than comparing to each command key, this one distinguishes between hex keys and command keys (which involves a slight hardware change), and then a comparison with the index state for the middle (GO) key distinguishes between that key (BEQ), the one to it's left (BMI), and then by implication the one to its right.
Code: Select all
VERSION = $00 ; alpha
REVISION = $01 ; first revision
; 125 total
; main: 80
; to_leds: 25
; vectors: 4
; table: 16
; Note:
; the special key row goes to d6
; d7 is !(row0 # row1 # row2 # row3 # row4)
; so no need to clean up hex key before "or" op.
; For branching to work, need to know where keys are:
; Column 0 = "<-", Reverse key (restart)
; Column 1 = "->", Go key (execute routine)
; Column 3 = "CR", CR key, next address
; Paleolithic
led_addr = ????
keys = ????
addr0 = $0200
; Neolithic
;led_addr = $0880
;keys = $0886
;addr0 = $1000
W = $00
leds = $02
KEY_RV = %11000000
RV_INDEX = 0
KEY_GO = %11000001
GO_INDEX = 1
KEY_CR = %11000011
CR_INDEX = 3
code
org $ff80
LED_PATTERNS db 0b00111111 ;0
db 0b00000110 ;1
db 0b01011011 ;2
db 0b01001111 ;3
db 0b01100110 ;4
db 0b01101101 ;5
db 0b01111101 ;6
db 0b00000111 ;7
db 0b01111111 ;8
db 0b01101111 ;9
db 0b01011111 ;a
db 0b00111100 ;b
db 0b00101000 ;c
db 0b01011110 ;d
db 0b01111101 ;e
db 0b01110001 ;f
exec: jmp addr0 ; +3
; +6
start: ; Set base address, this is also "review"
lda #>addr0
sta W+1
stz W ; start address addr0, page aligned
loop_main: ; +2
; Initialize the display count
; we have eight leds but we only drive six (5..0)
; to save code space (we don't need to clear them)
ldy #5
loop_digit: ; +17
; current state to leds
; put W and (W) into leds
; [x][x][x][x][x][x][ ][ ]
; (also provides a short delay for the LED multiplex)
ldx #0
lda W+1
jsr to_leds
lda W
jsr to_leds
lda (W)
jsr to_leds
; +10
; for each LED digit (right to left)...
lda leds,y
sta led_addr,y ; display bit pattern
bit keys
bmi loop_99 ; no key pressed
; +8
; do stuff to sort out which key
; a hex key if V clear (bit6=0)
bvc loop_hex ; enter hex value
; sort out the command key by index
cpy #GO_INDEX
beq exec ; execute on Go key
bmi start ; return addr0 to review
; +8
; remaining special key is return
inc W
bne loop_90
inc W+1
bra loop_90
loop_hex: ; +17
; else shuffle key value into (W)
lda keys
pha
lda (W)
asl a
asl a
asl a
asl a
sta (W)
pla
ora (W)
sta (W)
loop_90: ; +4
; wait for key to be released
; this will cause display glitch, but...
lda keys
bmi loop_90
loop_99: ; +5
dey
bpl loop_digit
bra loop_main
to_leds:
; unpack byte into two adjacent LED patterns
; x has character position
phy
pha
and #$0f ; low nibble
tay
lda LED_PATTERNS,y ; index into the patterns
sta leds+1,x ; and output into the LED array
pla
lsr a
lsr a
lsr a
lsr a ; high nibble
tay
lda LED_PATTERNS,y
sta leds,x ; this byte goes on the left
inx
inx
ply
rts
org $fffc
dw start
db VERSION,REVISION