Guessing game for 6502 computer
;; guess the secret number
;; version 28 Oct 2024
PORTB = $6000 ; 8 bits on the right
PORTA = $6001 ; 3 bit last 3 on the left
DDRB = $6002
DDRA = $6003
counter = $0200 ; interrupt counter
hidden = $0201 ; random generated
guess = $0202 ; user's guessed number
endz = $0203 ; holds string ends
sign = $0204 ; switch for add/subtract
turn = $0205 ; number of guesses
fspace = $0206 ; first space in cstr
cstr = $0207 ; from bin to string
E = %10000000 ; enable pin
RW = %01000000 ; r/w pin
RS = %00100000 ; data vs cmd pin
.org $8000
reset:
ldx #$ff
txs ; init stack pointer in page1 $01xx
lda #%11111111 ; all outputs
sta DDRB
lda #%11100000 ; 3 pins output
sta DDRA
lda #%00111000 ; 8-bit mode, 2-lines, 5x8 font
jsr lcd_instruction
lda #%00001100 ; display on, blink off, cursor off
jsr lcd_instruction
lda #%00000110 ; increment and shift cursor, no shift display
jsr lcd_instruction
lda #%00000001 ; clear screen
jsr lcd_instruction
init:
lda #$0
sta guess ; guess=0
sta sign ; sign=0 add, sign=1 subtract
sta turn
sta counter
lda #%00000001 ; clear screen
jsr lcd_instruction
lda #%11000000 ; cursor 2,1
jsr lcd_instruction
ldx #$0
ldy #$b ; "press start"
sty endz
jsr print_msg
cli ; clear disable interrupt bit
start:
jsr delay
lda counter
beq start ; counter = zero
lda #%11000000 ; cursor 2,1
jsr lcd_instruction
ldx #$4c
ldy #$57 ; " "
sty endz
jsr print_msg
lda #%10000000 ; cursor 1,1
jsr lcd_instruction
ldx #$48
ldy #$4b ; " 0"
sty endz
jsr print_msg
lda #%10000110 ; cursor 1,6
jsr lcd_instruction
ldx #$c
ldy #$17 ; "Add"
sty endz
jsr print_msg
lda counter
sta hidden
sei ; set disable interrupt bit
keypress: ; label
lda PORTA ; input pins
; and #$1e ; xxx1 111x and 0001 1110 = 0001 1110
and #$0f ; xxxx 1111 and 0000 1111 = 0000 1111
cmp #$0f ; check button press
beq keypress ; zero = no press, loop back
jsr delay ; debounce delay
lda PORTA ; check again
and #$08 ; 0000 1000
beq press4 ; add or subtract
lda PORTA ; check again
and #$04 ; 0100
beq press3 ; +1/-1
lda PORTA ; check again
and #$02 ; 0010
beq but2 ; +10/-10
lda PORTA ; check again
and #$01 ; 0001
beq but1 ; submit/compare
jmp keypress ; safety jump
but2: ; branch destination out of range, max 128 bytes
jmp press2 ;
but1: ; branch destination out of range, max 128 bytes
jmp press1 ;
press4: ; label
lda sign ; 0=add 1=subtract
bne change ; sign = 1
lda #$1 ; make sign=1
sta sign
lda #%10000110 ; cursor 1,6
jsr lcd_instruction
ldx #$18
ldy #$23 ; "Subtract"
sty endz
jsr print_msg
jsr clrl2 ; clear line2
jmp nokeypress
change: ; label
lda #$0
sta sign ; make sign=0
lda #%10000110 ; cursor 1,6
jsr lcd_instruction
ldx #$c
ldy #$17 ; "Add "
sty endz
jsr print_msg
jsr clrl2 ; clear line2
nokeypress:
lda PORTA ; key press xxx0 xxxx
and #$1e ; & 0001 1110
beq nokeypress ; no key pressed
jsr delay
jmp keypress
press3: ; label
lda sign ; 0=add 1=subtract
bne minus
inc guess ; guess+1
lda guess
jsr bin_to_str
lda #%10000000 ; cursor 1,1
jsr lcd_instruction
ldx #$0
jsr print_str
jsr clrl2 ; clear line2
jmp nokeypress
minus:
dec guess ; guess-1
lda guess
jsr bin_to_str
lda #%10000000 ; cursor 1,1
jsr lcd_instruction
ldx #$0
jsr print_str
jsr clrl2 ; clear line2
jmp nokeypress
press2: ; label
lda sign ; 0=add 1=subtract
bne min10
lda guess
adc #$a ; guess+10
sta guess
lda guess
jsr bin_to_str
lda #%10000000 ; cursor 1,1
jsr lcd_instruction
ldx #$0
jsr print_str
jsr clrl2 ; clear line2
jmp nokeypress
min10:
lda guess
sec ; set carry flag
sbc #$a ; guess-10
sta guess
lda guess
jsr bin_to_str
lda #%10000000 ; cursor 1,1
jsr lcd_instruction
ldx #$0
jsr print_str
jsr clrl2 ; clear line2
jmp nokeypress
;; check guess = hidden
press1: ; label
lda guess
cmp hidden
beq gotit ; A=Mem
bcs toobig ; A > M
inc turn ; add 1 to turn
lda #%11000000 ; cursor 2,1
jsr lcd_instruction
ldx #$30 ; print "Too low"
ldy #$3b
sty endz
jsr print_msg
jmp nokeypress
gotit: ; label
inc turn ; add 1 to turn
lda #%11000000 ; cursor 2,1
jsr lcd_instruction
ldx #$3c ; print "Correct in "
ldy #$47
sty endz
jsr print_msg
lda turn
jsr bin_to_str
lda #%11001011 ; cursor 2,12 line2 0-15
jsr lcd_instruction
ldx #$0
jsr print_str
wait:
jmp wait ; wait for reset
toobig: ; label
inc turn ; add 1 to turn
lda #%11000000 ; cursor 2,1
jsr lcd_instruction
ldx #$24 ; print "Too high"
ldy #$2f
sty endz
jsr print_msg
jmp nokeypress
; 0-b/c-17/18-23/24-2f/30-3b/3c-47/48-4b/4c-57
msg: .byte "Press start Add Subtract Too high Too low Correct in 0 "
print_msg: ; subroutine
lda msg,x
jsr print_char
inx
cpx endz
bne print_msg
rts
print_str: ; subroutine
lda cstr,x
jsr print_char
inx
cpx #$3
bne print_str
rts
clrl2:
lda #%11000000 ; cursor 2,1
jsr lcd_instruction
ldx #$4c
ldy #$57 ; " "
sty endz
jsr print_msg
rts
bin_to_str: ; subroutine needs lda value
ldx #0
ldy #0
stx fspace
up100:
cmp #$64 ; carry flag a >= 100
bcc end100
sbc #$64 ; subtract 100
inx
jmp up100
end100:
pha ; push a on stack 228-200 = 28
txa ; x -> a 0,1,2 a=2
beq space ; a=0
adc #$30 ; +48 dec a=50
jmp over
space:
adc #$20 ; +32 dec
inc fspace ; =1
over:
sta cstr,y ; 50 -> cstr
iny ; =1
ldx #0 ; x =0
pla ; a =28
up10:
cmp #$0a ; carry flag a >= 10
bcc end10
sbc #$0a ; subtract 10
inx
jmp up10
end10:
pha ; push a on stack 28-20=8
lda fspace ;
bne space1 ; fspace = 1 (space), check sec digit
txa ; x to a a=0,1,2
adc #$30 ; +48 dec
sta cstr,y
jmp over1
space1:
txa ; x to a
beq space2; first=space, sec=space
adc #$30 ; +48 dec
sta cstr,y
jmp over1
space2:
adc #$20 ; +32 dec
sta cstr,y
over1:
iny ; =2
ldx #0
pla ; a=8
adc #$30
sta cstr,y ; 8+48 = 56
rts
busy_wait: ; subroutine
pha
lda #%00000000 ; portb inputs
sta DDRB
busy_loop:
lda #RW
sta PORTA
lda #(RW | E)
sta PORTA
lda PORTB
and #%10000000
bne busy_loop
lda #RW
sta PORTA
lda #%11111111 ; portb outputs
sta DDRB ; address $6002
pla
rts
delay: ; subroutine
ldx #$ff
ldy #$2f
delay_loop:
dex ; (2 cycles)
bne delay_loop ; (3 cycles in loop, 2 cycles at end)
dey
bne delay_loop
rts
lcd_instruction: ; subroutine
jsr busy_wait
sta PORTB
lda #0 ; Clear RS/RW/E bits
sta PORTA
lda #E ; Set E bit to send instruction
sta PORTA
lda #0 ; Clear RS/RW/E bits
sta PORTA
rts
print_char: ; subroutine
jsr busy_wait
sta PORTB
lda #RS ; set RS, clear E
sta PORTA
lda #(RS | E) ; set RS, set E
sta PORTA
lda #RS ; set RS, clear E
sta PORTA
rts
nmi: ; interrupt routines
irq:
inc counter
rti
.org $fffa
.word nmi
.word reset
.word irq