371 lines
9.8 KiB
Plaintext
371 lines
9.8 KiB
Plaintext
.include "system/lcd.h65"
|
|
|
|
.ifndef lcd::LCD_IO
|
|
.fatal "lcd::LCD_IO is not defined: set it to the base address of the IO chip of the LCD"
|
|
.endif
|
|
|
|
Export lcd,init,clear,print,print_char,set_position,set_custom_char
|
|
Export lcd,_cmd,_wait_nbusy,_write_ram,_read_ram,_set_dd_ram_addr_from_charcount
|
|
Export lcd,_charcount
|
|
; RAM VARIABLES
|
|
.bss
|
|
_charcount: .res 1
|
|
|
|
; @TODO when clockspeeds are more than 1MHz, _cmd, _write_ram and _read_ram might need to be adjusted
|
|
.code
|
|
;;********************************************************************************
|
|
;; @function Initialize the lcd module
|
|
;; @details call before doing anything else
|
|
;; @modifies A
|
|
;;********************************************************************************
|
|
.proc init
|
|
; init IO
|
|
lda #$ff ; RB 0-7 output
|
|
sta lcd::LCD_IO+IO::DDRB
|
|
|
|
lda lcd::LCD_IO+IO::DDRA
|
|
ora #(lcd::RS | lcd::RW | lcd::E)
|
|
sta lcd::LCD_IO+IO::DDRA
|
|
|
|
; init lcd
|
|
lda #lcd::CMD::FUNCTION_SET
|
|
jsr _cmd
|
|
lda #lcd::CMD::DISPLAY_ON
|
|
jsr _cmd
|
|
lda #lcd::CMD::CLEAR
|
|
jsr _cmd
|
|
lda #lcd::CMD::ENTRY_MODE
|
|
jsr _cmd
|
|
|
|
stz _charcount
|
|
rts
|
|
.endproc
|
|
|
|
|
|
;;********************************************************************************
|
|
;; @function Set the cursor to a position
|
|
;; @param A: cursor position: `(lcd::LINEX + offset)`, where offset € [$0, $f]
|
|
;; @details
|
|
;; If the position is too large, it will be set to char 4 in line 2
|
|
;; @returns A: the cursor position
|
|
;;********************************************************************************
|
|
.proc set_position
|
|
pha
|
|
cmp #$60
|
|
bge @invalid
|
|
cmp #$50
|
|
bge @line4
|
|
cmp #$40
|
|
bge @line2
|
|
cmp #$20
|
|
bge @invalid
|
|
cmp #$10
|
|
bge @line3
|
|
bra @set
|
|
; @line1: ; starts at $00, _charcount at $00
|
|
@line2: ; starts at $40, _charcount at $10
|
|
sbc #$30 ; carry is already set
|
|
bra @set
|
|
@line3: ; starts at $10, _charcount at $20
|
|
add #$10
|
|
bra @set
|
|
@line4: ; starts at $50, _charcount at $30
|
|
sbc #$20
|
|
@set:
|
|
sta _charcount
|
|
pla
|
|
pha
|
|
ora #lcd::CMD::SET_ADDRESS
|
|
jsr _cmd
|
|
; and #(<~lcd::CMD::SET_ADDRESS) ; return original argument
|
|
pla
|
|
rts
|
|
@invalid:
|
|
pla ; otherwise stack corruption
|
|
lda #$13
|
|
sta _charcount
|
|
lda #(lcd::CMD::SET_ADDRESS | (lcd::LINE2 + 3))
|
|
jsr _cmd
|
|
lda #(lcd::LINE2 + 3)
|
|
rts
|
|
.endproc
|
|
|
|
;********************************************************************************
|
|
; PRINTING TO LCD
|
|
;********************************************************************************
|
|
|
|
;;********************************************************************************
|
|
;; @function Clear the display
|
|
;; @see lcd_print
|
|
;; @modifies A
|
|
;;********************************************************************************
|
|
.proc clear
|
|
stz _charcount
|
|
lda #lcd::CMD::CLEAR
|
|
jsr _cmd
|
|
rts
|
|
.endproc
|
|
|
|
;;********************************************************************************
|
|
;; @function Print a null-terminated string
|
|
;; @param ARG0-1 Address of the string to print
|
|
;; @modifies A,Y
|
|
;; @returns Y: Length of the string
|
|
;;********************************************************************************
|
|
.proc print
|
|
ldy #$00
|
|
@lcd_print_loop:
|
|
lda (ARG0),y
|
|
beq @lcd_print_end
|
|
jsr print_char
|
|
iny
|
|
bra @lcd_print_loop
|
|
@lcd_print_end:
|
|
rts
|
|
.endproc
|
|
|
|
|
|
;;********************************************************************************
|
|
;; @function Print a single character
|
|
;; @param A: Character to print
|
|
;;********************************************************************************
|
|
.proc print_char
|
|
pha
|
|
jsr _write_ram
|
|
inc _charcount
|
|
jsr _break_line
|
|
pla ; put char back in a
|
|
.endproc
|
|
|
|
|
|
;;********************************************************************************
|
|
;; @function Write a custom character to the lcds CharacterGenerator (CG) RAM
|
|
;; @param A: The ASCII code: 0-7
|
|
;; @param ARG0-1: Start address of the 8 bytes describing the character
|
|
;; @returns: C: 0 => success, 1 => invalid argument
|
|
;; @modifies A,Y
|
|
;;********************************************************************************
|
|
.proc set_custom_char
|
|
cmp #8
|
|
bcs @rts ; >= 8
|
|
rol ; address is bytes 3-5
|
|
rol
|
|
rol
|
|
ora #lcd::CMD::SET_CG_ADDRESS
|
|
jsr lcd::_cmd
|
|
ldy #0
|
|
@loop:
|
|
lda (ARG0),y
|
|
jsr lcd::_write_ram
|
|
iny
|
|
cpy #8
|
|
bne @loop
|
|
clc
|
|
@rts:
|
|
rts
|
|
.endproc
|
|
|
|
|
|
;;********************************************************************************
|
|
;; Internal LCD Commands
|
|
;;********************************************************************************
|
|
;; @function Wait until the lcd is no longer busy
|
|
;; @details
|
|
;; Reads from the address until the busy flag is no longer set.
|
|
;; After reading, the VIA will be set to output mode again
|
|
;;********************************************************************************
|
|
.proc _wait_nbusy
|
|
pha
|
|
stz lcd::LCD_IO + IO::DDRB ; set IO1-IO + IO::RB to input
|
|
lda lcd::LCD_IO + IO::RA
|
|
and #<~lcd::RA_MASK
|
|
ora #lcd::RW
|
|
sta lcd::LCD_IO + IO::RA
|
|
|
|
@lcd_wait_nbusy_loop: ; read the busy flag
|
|
; set E low, then high
|
|
lda lcd::LCD_IO + IO::RA
|
|
and #<~lcd::E
|
|
sta lcd::LCD_IO + IO::RA
|
|
ora #lcd::E
|
|
sta lcd::LCD_IO + IO::RA
|
|
|
|
lda lcd::LCD_IO + IO::RB
|
|
bmi @lcd_wait_nbusy_loop ; msb set
|
|
|
|
lda lcd::LCD_IO + IO::RA
|
|
and #<~lcd::RA_MASK
|
|
sta lcd::LCD_IO + IO::RA
|
|
lda #%11111111 ; set IO1-IO + IO::RB to output
|
|
sta lcd::LCD_IO + IO::DDRB
|
|
pla
|
|
rts
|
|
.endproc
|
|
|
|
|
|
;;********************************************************************************
|
|
;; @function Send a @ref lcd::CMD "command" to the lcd
|
|
;; @param A: command
|
|
;; @modifies A
|
|
;;********************************************************************************
|
|
.proc _cmd
|
|
jsr _wait_nbusy
|
|
|
|
sta lcd::LCD_IO + IO::RB
|
|
|
|
; while preserve bits 0-4: unset E, set RS
|
|
; unset E, RW and RS
|
|
lda lcd::LCD_IO + IO::RA
|
|
and #(<~lcd::RA_MASK)
|
|
sta lcd::LCD_IO + IO::RA
|
|
; set E
|
|
ora #lcd::E
|
|
sta lcd::LCD_IO + IO::RA
|
|
; unset E
|
|
eor #lcd::E
|
|
sta lcd::LCD_IO + IO::RA
|
|
rts
|
|
.endproc
|
|
|
|
|
|
;;********************************************************************************
|
|
;; @function Write a byte to the lcd
|
|
;; @details
|
|
;; Set the CG or DD address first
|
|
;; @param A: data
|
|
;; @modifies A
|
|
;;********************************************************************************
|
|
.proc _write_ram
|
|
jsr _wait_nbusy
|
|
sta lcd::LCD_IO + IO::RB
|
|
; while preserve bits 0-4: unset E and RW, set RS
|
|
lda lcd::LCD_IO + IO::RA
|
|
and #(<~lcd::RA_MASK)
|
|
ora #lcd::RS
|
|
sta lcd::LCD_IO + IO::RA
|
|
; set E
|
|
ora #lcd::E
|
|
sta lcd::LCD_IO + IO::RA
|
|
; unsert E
|
|
eor #lcd::E
|
|
sta lcd::LCD_IO + IO::RA
|
|
rts
|
|
.endproc
|
|
|
|
|
|
;;********************************************************************************
|
|
;; @function Read a byte from the lcd
|
|
;; @details
|
|
;; Set the CG or DD address first
|
|
;; @returns A: byte
|
|
;;********************************************************************************
|
|
.proc _read_ram
|
|
jsr _wait_nbusy
|
|
; set IO1-IO + IO::RB to input
|
|
stz lcd::LCD_IO + IO::DDRB
|
|
; while preserve bits 0-4: unset E, set RW and RS
|
|
lda lcd::LCD_IO + IO::RA
|
|
and #(<~lcd::RA_MASK)
|
|
ora #(lcd::RW | lcd::RS)
|
|
sta lcd::LCD_IO + IO::RA
|
|
; set E
|
|
ora #lcd::E
|
|
sta lcd::LCD_IO + IO::RA
|
|
; load the byte
|
|
lda lcd::LCD_IO + IO::RB
|
|
pha
|
|
; unset E
|
|
lda lcd::LCD_IO + IO::RA
|
|
eor #lcd::E
|
|
sta lcd::LCD_IO + IO::RA
|
|
; set IO1-IO + IO::RB to output
|
|
lda #$ff
|
|
sta lcd::LCD_IO + IO::DDRB
|
|
pla
|
|
rts
|
|
.endproc
|
|
|
|
|
|
;;********************************************************************************
|
|
;; @function Set the LCD DD-RAM Address from the character count
|
|
;; @details
|
|
;; Sets the DD-RAM Address so that a line break occurs after 16 characters
|
|
;; If _charcount is more than $40, the position will be set to _charcount % $40
|
|
;;********************************************************************************
|
|
.proc _set_dd_ram_addr_from_charcount
|
|
cmp #$40 ; set to line1 when full
|
|
bcs @wrap_to_line1 ; a € [$40, $ff]
|
|
cmp #$10
|
|
bcc @line1 ; a € [$00, $0f]
|
|
cmp #$20
|
|
bcc @line2 ; a € [$10, $1f]
|
|
cmp #$30
|
|
bcc @line3 ; a € [$20, $2f]
|
|
; bra @line4; a € [$30, $3f]
|
|
@line4:
|
|
clc
|
|
adc #$20 ; _charcount $30-$3f -> $50 - $5f
|
|
bra @set_address
|
|
@wrap_to_line1:
|
|
and #%00111111
|
|
; now every _charcount is mapped between 0 and $3f
|
|
bra @set_address
|
|
@line2:
|
|
adc #$30 ; _charcount $10-$1f -> $40 - $4f
|
|
bra @set_address
|
|
@line3:
|
|
sec
|
|
sbc #$10 ; _charcount $20-$2f -> $10 - $1f
|
|
bra @set_address
|
|
@line1: ; _charcount $00-$1f -> $00 - $0f - nothing to do
|
|
@set_address:
|
|
ora #lcd::CMD::SET_ADDRESS
|
|
jsr _cmd
|
|
rts
|
|
.endproc
|
|
|
|
;;********************************************************************************
|
|
;; @function Set the LCD DD-RAM Address to te next line if the end of the line was reached
|
|
;; @details
|
|
;; If the cursor is past the end of a line, the DD-RAM Address is set to the next line.
|
|
;; If _charcount is more than $40, the position will be set to line 1.
|
|
;; This function is intended to be used with to set the correct address when
|
|
;; auto-shift is enabled
|
|
;;********************************************************************************
|
|
.proc _break_line
|
|
; check if checks are necessary
|
|
lda _charcount
|
|
beq @line1
|
|
bit #%10001111 ; ($10 | $20 | $30 | $40) = %01110000
|
|
beq @check
|
|
rts
|
|
@check:
|
|
; checks necessary
|
|
cmp #$10
|
|
beq @line2
|
|
cmp #$20
|
|
beq @line3
|
|
cmp #$30
|
|
beq @line4
|
|
cmp #$40 ; set to line1 when full
|
|
bge @line1
|
|
rts
|
|
@line1:
|
|
stz _charcount
|
|
lda #(lcd::CMD::SET_ADDRESS | lcd::LINE1)
|
|
jsr _cmd
|
|
rts
|
|
@line2:
|
|
lda #(lcd::CMD::SET_ADDRESS | lcd::LINE2)
|
|
jsr _cmd
|
|
rts
|
|
@line3:
|
|
lda #(lcd::CMD::SET_ADDRESS | lcd::LINE3)
|
|
jsr _cmd
|
|
rts
|
|
@line4:
|
|
lda #(lcd::CMD::SET_ADDRESS | lcd::LINE4)
|
|
jsr _cmd
|
|
rts
|
|
.endproc
|