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