6502-OS/system/lcd.s65

215 lines
5.4 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
; RAM VARIABLES
.bss
charcount: .res 1
.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
; UT_update_with_mask IO + IO::DDRA, (RS | LCD_RW | LCD_E), (LCD_RS | LCD_RW | LCD_E)
lda #(lcd::RS | lcd::RW | lcd::E) ; RA 5-7 output
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
;;********************************************************************************
;; PRINTING TO LCD
;;********************************************************************************
;;********************************************************************************
;; @function Clear the display
;; @see lcd_print
;; @modifies A
;;********************************************************************************
.proc clear
stz charcount
lda #lcd::CLEAR
jsr _cmd
lda #(lcd::CMD_SET_ADDRESS | lcd::LINE1)
jsr _cmd
rts
.endproc
;;********************************************************************************
;; @function Print a null-terminated string
;; @param ARG0-1 Address of the string to print
;; @modifies: A,Y
;;********************************************************************************
.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
;;********************************************************************************
;; @macro Print a single character
;; @param A: Character to print
;;********************************************************************************
.proc print_char
pha
pha
; TODO use UT_update_with_mask?
jsr _wait_nbusy
pla
sta lcd::LCD_IO + IO::RB
lda #lcd::RS
sta lcd::LCD_IO + IO::RA
lda #(lcd::RS | lcd::E)
sta lcd::LCD_IO + IO::RA
lda #lcd::RS
sta lcd::LCD_IO + IO::RA
inc charcount
jsr _break_line
pla ; put char back in a
.endproc
;;********************************************************************************
;; Internal LCD Commands
;;********************************************************************************
; read busy flag
.proc _wait_nbusy
stz lcd::LCD_IO + IO::DDRB ; set IO1-IO + IO::RB to input
@lcd_wait_nbusy_loop: ; read the busy flag
lda #lcd::RW
sta lcd::LCD_IO + IO::RA
lda #(lcd::RW | lcd::E)
sta lcd::LCD_IO + IO::RA
lda lcd::LCD_IO + IO::RB
and #%10000000 ; and updates zero flag, if not set retry
bne @lcd_wait_nbusy_loop
lda #%00000000 ; TODO dont overwrite 0-4
sta lcd::LCD_IO + IO::RA
lda #%11111111 ; set IO1-IO + IO::RB to output
sta lcd::LCD_IO + IO::DDRB
rts
.endproc
;;********************************************************************************
;; @function Send a command to the lcd
;; @param A: command
;; @modifies A
;;********************************************************************************
.proc _cmd ; send cmd in acc
pha
jsr _wait_nbusy
pla
; TODO use UT_update_with_mask?
sta lcd::LCD_IO + IO::RB
lda #lcd::CLEAR
sta lcd::LCD_IO + IO::RA
lda #lcd::E
sta lcd::LCD_IO + IO::RA
lda #lcd::CLEAR
sta lcd::LCD_IO + IO::RA
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 5 in line 2
;; @returns A: the cursor position
;;********************************************************************************
.proc set_position
cmp #$40
bge @invalid
sta charcount
pha
ora #lcd::CMD_SET_ADDRESS
jsr _cmd
pla
@rts:
rts
@invalid:
lda $14
sta charcount
lda #(lcd::CMD_SET_ADDRESS | (lcd::LINE2 + 4))
jsr _cmd
lda #(lcd::LINE2 + 4)
bra @rts
.endproc
;;********************************************************************************
;; @function Set the LCD DD-RAM Address so that text linebreaks after 16 chars
;;********************************************************************************
.proc _break_line
; check if checks are necessary
lda charcount
beq @line1
and #%10001111 ; ($10 | $20 | $30 | $40) = %01110000
bne @rts
; checks necessary
lda charcount
beq @line1
cmp #$10
beq @line2
cmp #$20
beq @line3
cmp #$30
beq @line4
cmp #$40 ; set to line1 when full
bge @line1
@rts:
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