Hex, dec, binary converter for 4 bit LCD
; latest 6502 board
;
PORTB = $6000 ; 8 bits PB0-PB7
PORTA = $6001 ; 8 bits PA0-PA7
DDRB = $6002 ; data direction B bits
DDRA = $6003 ; data direction A bits
E = %00001000 ; PB3 connected
RW = %00000100 ; PB2 connected
RS = %00000010 ; PB1 connected
value = $20 ; from input str to 1 byte value
Hx = $21 ; store hex result
Cx = $22 ; store hunderds
Xx = $23 ; store tens
Rx = $24 ; store ones
keep = $25 ; zero page, store A in lcd_instruction
endz = $0201 ; end of string
numeral = $0202 ; hex,dec,bin = 0,1,2
xmax = $0203 ; maximum xpos = 2,3,8
xpos = $0206 ; position cursor
ypos = $0207 ; 0-7 (8 bytes max)
ymax = $020f ; 16,10,2 (h,d,b)
binstr = $0212 ; store binary string (8 bytes)
.org $8000
setup: ; setup io reset
ldx #$ff
txs ; init stack pointer
lda #%11111110 ; 7 outputs PB1 -PB7, PB0 free
sta DDRB
lda #%00000001 ; 7 pins input, 1 output (PA0 led)
sta DDRA
lda #%00000001
sta PORTA ; turn off led (sink)
lda #%00000010 ; 4-bit mode
jsr lcd_instruction
lda #%00101000 ; 4-bit mode, 2-lines, 5x8 font
jsr lcd_instruction
lda #%00001110 ; display on, blink on, cursor off
jsr lcd_instruction
jsr short_delay
lda #%00000110 ; increment and shift cursor, no shift display
jsr lcd_instruction
init:
lda #%00000001 ; clear screen
jsr lcd_instruction
jsr short_delay ; necessary delay for lcd
lda #%10000000 ; cursor (0,0) line 1, pos 1
jsr lcd_instruction
jsr short_delay
; init variables
lda #$0
sta keep ; keep = 0
sta xpos ; xpos = 0
sta numeral ; numeral = 0
sta Hx
sta Cx
sta Xx
sta Rx
ldx #$0 ; index
lda #$2
sta xmax,x ; xmax[0] = 2
lda #$10
sta ymax,x ; ymax[0] = 16
inx
lda #$3
sta xmax,x ; xmax[1] = 3
lda #$0a
sta ymax,x ; ymax[1] = 10
inx
lda #$8
sta xmax,x ; xmax[2] = 8
lda #$2
sta ymax,x ; ymax[2] = 2
ldx #$0
lda #$0
lp0: ; ypos[0-7]=0
sta ypos,x
inx
cpx #$8
bne lp0
start:
; print "Press Up"
lda #$0c ; cursor off
jsr lcd_instruction
lda #$80 ; cursor 0,0
jsr lcd_instruction
ldx #$0 ; start of msg
ldy #$8
sty endz ; end point of msg + 1
jsr print_msg
jsr short_delay
key_up_enter: ; to select input hex,dec,bin
lda PORTA ; 1111 111x
and #$fe ; 1111 1110
cmp #$fe ; 1111 1110
beq key_up_enter ; zero = no press, loop back
jsr short_delay ; debounce delay
lda PORTA ; 1111 110x
and #$02 ; 0000 0010
beq choice ; up pressed
lda PORTA
and #$20 ; 0010 0000
beq stage1 ; enter pressed
jmp key_up_enter
choice: ; print hex,dec or bin
jsr blink_off
ldx numeral ; read numeral 0
inx ; x+1
stx numeral ; store 1
cpx #$3 ; x==3
beq set_b ; set back 0
cpx #$2
beq set_2
cpx #$1
beq set_1
cpx #$0
beq set_0
jmp key_up_enter
set_b:
ldx #$0
stx numeral
jmp set_0
set_2:
lda #$80 ; cursor 0,0
jsr lcd_instruction
ldx #$1b ; start string
ldy #$23 ; end string
sty endz
jsr print_msg
jmp key_up_enter
set_1:
lda #$80 ; cursor 0,0
jsr lcd_instruction
ldx #$12 ; start string
ldy #$1a ; end string
sty endz
jsr print_msg
jmp key_up_enter
set_0:
lda #$80 ; cursor 0,0
jsr lcd_instruction
ldx #$9 ; start string
ldy #$11 ; end string
sty endz
jsr print_msg
jmp key_up_enter
stage1: ; hex 00 dec 000 bin 00000000
jsr blink_on
lda #$0e ; cursor on
jsr lcd_instruction
lda #$84 ; cursor 0,4
jsr lcd_instruction
ldx numeral ; read numeral 0
cpx #$2
beq print_8
cpx #$1
beq print_3
cpx #$0
beq print_2
jmp stage1 ; just in case
print_8:
ldx #$24 ; start string
ldy #$2c ; end string
sty endz
jsr print_msg
lda #$84 ; cursor 0,4
jsr lcd_instruction
jmp keypress
print_3:
ldx #$24 ; start string
ldy #$27 ; end string
sty endz
jsr print_msg
lda #$84 ; cursor 0,4
jsr lcd_instruction
jmp keypress
print_2:
ldx #$24 ; start string
ldy #$26 ; end string
sty endz
jsr print_msg
lda #$84 ; cursor 0,4
jsr lcd_instruction
keypress: ; up,down,left,right,enter or clear
lda PORTA ; 1111 111x
and #$fe ; 1111 1110
cmp #$fe ; 1111 1110
beq keypress ; zero = no press, loop back
jsr short_delay ; debounce delay
lda PORTA ; 1111 110x
and #$02 ; 0000 0010
beq b_up
lda PORTA ; 1111 101x
and #$04 ; 0000 0100
beq b_down
lda PORTA ; 1111 011x
and #$08 ; 0000 1000
beq b_left
lda PORTA ; 1110 111x
and #$10 ; 0001 0000
beq b_right
lda PORTA ; 1101 111x
and #$20 ; 0010 0000
beq b_enter
lda PORTA ; 1011 111x
and #$40 ; 0100 0000
beq b_clear
jmp keypress
b_up:
jmp jmp_up ; not necessary but consistent
b_down:
jmp jmp_down
b_left: ; branch can jump max 128 bytes
jmp jmp_left
b_right:
jmp jmp_right
b_enter:
jmp jmp_enter
b_clear:
jmp jmp_clear
clearpress: ; only clear button to start again
lda PORTA ; 1011 111x
and #$40 ; 0100 0000
beq b_clear
jmp clearpress
jmp_up: ; get numeral (h,d,b); get xpos; get ypos,xpos;
; incr ypos; > #$0; print char
ldx xpos ; relative cursor postion
lda ypos,x ; index number of y in relation to xpos
adc #$1 ; ypos + 1= 1
sta ypos,x ; store ypos
ldx numeral ; check maximum allowed for numeral
cmp ymax,x ; ymax,0 = 16
beq zero_ypos ; make ypos zero
b_up_back:
tax ; copy a to x
lda str,x ; get print char using value of ypos,x
jsr print_char
lda xpos ; set cursor back
clc
adc #$84 ; add $84 to set cursor position
jsr lcd_instruction
jmp keypress
zero_ypos: ; ypos reached max+1
clc
lda #$0
ldx xpos
sta ypos,x ; store ypos, either +1 or 0
jmp b_up_back
jmp_down: ; get numeral (h,d,b); get xpos; get ypos,xpos;
;dec ypos; print char
ldx xpos ; relative cursor postion
lda ypos,x ; index number of y in relation to xpos
sec ; clear borrow
sbc #$1 ; ypos - 1
bcc max_ypos ; borrow set (carry clear)
ldx xpos
sta ypos,x ; store ypos
b_down_back:
tax ; copy a to x 15,9,1
lda str,x ; get print char using value of ypos,x
jsr print_char
lda xpos ; set cursor back
clc
adc #$84 ; add $84 to set cursor position
jsr lcd_instruction
jmp keypress
max_ypos: ; ypos reached -1 set back to maximum -1
ldx numeral ; 0,1,2
lda ymax,x ; 16,10,2
sec ; clear borrow
sbc #$1 ; 15,9,1
ldx xpos
sta ypos,x ; store ypos, 15,9,1
jmp b_down_back
jmp_left:
sec ; clear borrow
lda xpos ; 0
sbc #$1 ; xpos-1
bcc max_xpos
b_left_back:
clc
sta xpos
adc #$84 ; def location
jsr lcd_instruction
jmp keypress
max_xpos:
ldx numeral
sec
lda xmax,x
sbc #$1
jmp b_left_back
jmp_right:
clc ; clear carry
lda xpos ; 0
adc #$1 ; xpos+1
ldx numeral ; check xmax
cmp xmax,x ; xmax[numeral]
beq zero_xpos
b_right_back:
sta xpos
clc
lda xpos ; 0
adc #$84 ; def location
jsr lcd_instruction
jmp keypress
zero_xpos:
lda #$0
jmp b_right_back
jmp_enter:
lda #$0c ; cursor off
jsr lcd_instruction
; if dec check input
lda numeral ; 0=hex
cmp #$0
beq hex_ok
cmp #$1
beq check_dec
cmp #$2
beq bin_ok
jmp jmp_enter ; not necessary
check_dec: ; check input > 255
ldx #$0
lda ypos,x
cmp #$3 ; a>=3?
bcs error
cmp #$2 ; a>=2
bcs check2
jmp dec_ok
check2:
inx
lda ypos,x
clc
cmp #$6 ; a >= 6
bcs error
cmp #$5 ; a >= 5
bcs check3
jmp dec_ok
check3:
inx
lda ypos,x
clc
cmp #$6 ; a >= 6
bcs error
jmp dec_ok
error:
jmp stage1 ; back to enter values
bin_ok: ; start of binary conversion
lda #$c0 ; set cursor line 2,1 1100 0000
jsr lcd_instruction
jsr bin_to_val
jsr val_to_hex
lda #$c4 ; set cursor line 2,5 1100 0100
jsr lcd_instruction
jsr val_to_dec
jsr short_delay
jmp clearpress ; clear as only option
hex_ok: ; start of hex conversion
lda #$c0 ; set cursor line 2,1 1100 0000
jsr lcd_instruction
jsr hex_to_val
jsr val_to_dec
lda #$c4 ; set cursor line 2,5 1100 0100
jsr lcd_instruction
jsr val_to_bin
jsr short_delay
jmp clearpress ; clear as only option
dec_ok: ; start of decimal conversion
lda #$c0 ; set cursor line 2,1 1100 0000
jsr lcd_instruction
jsr dec_to_val
jsr val_to_hex
lda #$c4 ; set cursor line 2,5 1100 0100
jsr lcd_instruction
jsr val_to_bin
jsr short_delay
jmp clearpress ; clear as only option
jmp_clear:
jmp init
;-----------------------------
bin_to_val: ; binary input to hex output
ldx #$0
stx value
bv_loop:
lda ypos,x ; ypos[0]
ora value ; 0000 0000
inx
cpx #$8
beq bv_done
asl
sta value
jmp bv_loop
bv_done:
sta value
rts
;-------------------------------
dec_to_val:
lda #$0
sta value ; value=0
dv_100:
ldx #$0
lda ypos,x ; 0,1 or 2
cmp #$01 ; >= 1?
bcs dv_hunderd ; carry set
dv_10:
ldx #$1
lda ypos,x
cmp #$01 ; >= 1?
bcs dv_ten
; add the one position
lda value
ldx #$02
adc ypos,x
sta value
rts
dv_ten:
sbc #$01 ; a-1
ldx #$1
sta ypos,x ; ypos-1
lda value
clc
adc #$0a ; 10
sta value ; store Hx+10
jmp dv_10
dv_hunderd:
sbc #$01 ; minus 1
ldx #$0
sta ypos,x ; ypos-1
lda value ; get value
clc
adc #$64 ; 100
sta value ; store value+100
jmp dv_100
;-------------------------------
hex_to_val:
ldx #$0
stx value ; value=0
lda ypos,x ; number first xpos
asl
asl
asl
asl ; 4x shift left xxxx 0000
inx
adc ypos,x ; add number second xpos
sta value
rts
;-------------------------------
val_to_hex:
lda value ; D7 1101 0111
lsr ; high nibble -> low
lsr
lsr
lsr ; 0000 1101
tax ; copy number a->x
lda str,x ; get char from str, 15=F
jsr print_char
lda value ; 1101 0111
and #$0f ; 0000 1111 = 0111
tax
lda str,x
jsr print_char
rts
;-------------------------------
val_to_dec:
lda value
vd_100:
cmp #$64 ; >=100 ?
bcs vd_hunderd ; c=1, no borrow
vd_10:
cmp #$0a ; >=10 ?
bcs vd_ten
vd_ones:
sta Rx
ldx Cx
lda str,x
jsr print_char
ldx Xx
lda str,x
jsr print_char
ldx Rx
lda str,x
jsr print_char
rts
vd_hunderd:
sec
sbc #$64 ; subtract 100
ldx Cx
inx
stx Cx ; Cx+1
jmp vd_100
vd_ten:
sec
sbc #$0a ; subtract 10
ldx Xx
inx
stx Xx ; Xx + 1
jmp vd_10
;-------------------------------
val_to_bin:
ldx #$0
lda #$30 ; letter "0"
vb_loop1: ; init binstr
sta binstr,x ; "0"->binstr[0-7]
inx
cpx #$8
bne vb_loop1
ldx #$7 ; from 7 to 0
vb_loop2:
lda value ; 0101 0101 &
and #$1 ; 0000 0001
beq vb_zero ; and results in 0
lda #$31 ; not zero
sta binstr,x ; order 7->0
lsr value ; shift right to check next bit
dex ; x-1
cpx #$ff ; (x)0-1
beq vb_done
jmp vb_loop2
vb_zero:
lsr value ; shift right -> 0010 1010
dex ; x-1
cpx #$ff
beq vb_done
jmp vb_loop2
vb_done: ; print binstr
ldx #$0
vb_loop3:
lda binstr,x ; 0->7
jsr print_char
inx
cpx #$8
bne vb_loop3
rts
;-------------------------------
print_msg:
lda msg,x
jsr print_char
inx
cpx endz
bne print_msg
rts
; 0-8/9-11/12-1a/1b-23/24-2c/
msg: .byte "Press up hex dec bin 00000000 "
str: .byte "0123456789ABCDEF"
short_delay:
ldx #$ff ; (2 cycles)
ldy #$3f ; (2 cycles)
short_loop:
dex ; (2 cycles)
bne short_loop ; (3 cycles in loop, 2 cycles at end)
dey
bne short_loop
rts
delay: ; delay for 1MHz
ldx #$ff ; (2 cycles)
ldy #$ff ; (2 cycles)
lda #$02
delay_loop:
nop
dex ; (2 cycles)
bne delay_loop ; (3 cycles in loop, 2 cycles at end)
nop
dey
bne delay_loop
nop
sbc #$1
bne delay_loop
rts
lcd_instruction: ; 1. remove low nibble ; 2. move lnibble to high bit
sta keep ; save A in keep
and #$F0 ; lda & 1111 0000
sta PORTB
; Clear RS/RW/E bits no necessary
; Set E bit to send instruction
ora #E ; lda or E xxxx 0000 or 0000 1000
sta PORTB
; Clear RS/RW/E bits
and #$F0 ; lda & 1111 0000
sta PORTB
lda keep ; load lda from memory
asl ; shift left 4x 0000 xxxx -> xxxx 0000
asl
asl
asl
sta PORTB
; Set E bit to send instruction
ora #E ; lda or E xxxx 0000 or 0000 1000
sta PORTB
; Clear RS/RW/E bits
and #$F0 ; lda & 1111 0000
sta PORTB
rts
print_char:
pha ; push A on stack
and #$F0 ; lda & 1111 0000
sta PORTB
; clear E, set RS
and #$f0 ; lda & 1111 0000
ora #RS ; lda or 0000 0010
sta PORTB
; set E, set RS
ora #E ; lda or 0000 1000
ora #RS ; lda or 0000 0010
sta PORTB
; clear E, set RS
and #$f0 ; lda & 1111 0000
ora #RS ; lda or 0000 0010
sta PORTB
pla ; pull A from stack
asl ; shift left 4x
asl
asl
asl
sta PORTB
; clear E, set RS
and #$f0 ; lda & 1111 0000
ora #RS ; lda or 0000 0010
sta PORTB
; set E, set RS
ora #E ; lda or 0000 1000
ora #RS ; lda or 0000 0010
sta PORTB
; clear E, set RS
and #$f0 ; lda & 1111 0000
ora #RS ; lda or 0000 0010
sta PORTB
rts
blink_on: ; sink=on
ldy #$0
sty PORTA
rts
blink_off: ; source=off
ldy #$1
sty PORTA
rts
.org $fffc
.word setup
.word $0000