6502-OS/system/lcd.s65

371 lines
9.8 KiB
Plaintext
Raw Normal View History

2023-12-08 22:56:35 +01:00
.include "system/lcd.h65"
2023-10-26 19:51:20 +02:00
2023-12-08 22:56:35 +01:00
.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
2023-12-16 02:41:19 +01:00
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
2023-10-26 19:51:20 +02:00
; RAM VARIABLES
2023-12-08 22:56:35 +01:00
.bss
2024-01-15 09:19:05 +01:00
_charcount: .res 1
2023-12-08 22:56:35 +01:00
2024-08-08 20:15:50 +02:00
; @TODO when clockspeeds are more than 1MHz, _cmd, _write_ram and _read_ram might need to be adjusted
2023-12-08 22:56:35 +01:00
.code
;;********************************************************************************
;; @function Initialize the lcd module
;; @details call before doing anything else
;; @modifies A
;;********************************************************************************
.proc init
2023-10-26 19:51:20 +02:00
; init IO
lda #$ff ; RB 0-7 output
2023-12-08 22:56:35 +01:00
sta lcd::LCD_IO+IO::DDRB
2023-10-26 19:51:20 +02:00
2023-12-31 01:56:42 +01:00
lda lcd::LCD_IO+IO::DDRA
ora #(lcd::RS | lcd::RW | lcd::E)
sta lcd::LCD_IO+IO::DDRA
2023-10-26 19:51:20 +02:00
; init lcd
lda #lcd::CMD::FUNCTION_SET
2023-12-08 22:56:35 +01:00
jsr _cmd
lda #lcd::CMD::DISPLAY_ON
2023-12-08 22:56:35 +01:00
jsr _cmd
lda #lcd::CMD::CLEAR
2023-12-08 22:56:35 +01:00
jsr _cmd
lda #lcd::CMD::ENTRY_MODE
2023-12-08 22:56:35 +01:00
jsr _cmd
2024-01-15 09:19:05 +01:00
stz _charcount
2023-10-26 19:51:20 +02:00
rts
.endproc
2023-12-08 22:56:35 +01:00
2023-12-16 02:41:19 +01:00
;;********************************************************************************
;; @function Set the cursor to a position
;; @param A: cursor position: `(lcd::LINEX + offset)`, where offset € [$0, $f]
2024-08-08 20:39:25 +02:00
;; @details
2023-12-16 02:41:19 +01:00
;; 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
2024-01-15 09:19:05 +01:00
; @line1: ; starts at $00, _charcount at $00
@line2: ; starts at $40, _charcount at $10
2023-12-16 02:41:19 +01:00
sbc #$30 ; carry is already set
bra @set
2024-01-15 09:19:05 +01:00
@line3: ; starts at $10, _charcount at $20
2023-12-16 02:41:19 +01:00
add #$10
bra @set
2024-01-15 09:19:05 +01:00
@line4: ; starts at $50, _charcount at $30
2023-12-16 02:41:19 +01:00
sbc #$20
@set:
2024-01-15 09:19:05 +01:00
sta _charcount
2023-12-16 02:41:19 +01:00
pla
pha
ora #lcd::CMD::SET_ADDRESS
2023-12-16 02:41:19 +01:00
jsr _cmd
; and #(<~lcd::CMD::SET_ADDRESS) ; return original argument
2023-12-16 02:41:19 +01:00
pla
rts
@invalid:
pla ; otherwise stack corruption
lda #$13
2024-01-15 09:19:05 +01:00
sta _charcount
lda #(lcd::CMD::SET_ADDRESS | (lcd::LINE2 + 3))
2023-12-16 02:41:19 +01:00
jsr _cmd
lda #(lcd::LINE2 + 3)
rts
.endproc
2023-12-08 22:56:35 +01:00
;********************************************************************************
; PRINTING TO LCD
;********************************************************************************
2023-12-08 22:56:35 +01:00
;;********************************************************************************
;; @function Clear the display
;; @see lcd_print
;; @modifies A
;;********************************************************************************
.proc clear
2024-01-15 09:19:05 +01:00
stz _charcount
lda #lcd::CMD::CLEAR
2023-12-08 22:56:35 +01:00
jsr _cmd
2023-10-28 03:48:27 +02:00
rts
.endproc
2023-10-26 19:51:20 +02:00
2023-12-08 22:56:35 +01:00
;;********************************************************************************
;; @function Print a null-terminated string
;; @param ARG0-1 Address of the string to print
2024-08-08 20:39:25 +02:00
;; @modifies A,Y
2023-12-16 02:41:19 +01:00
;; @returns Y: Length of the string
2023-12-08 22:56:35 +01:00
;;********************************************************************************
.proc print
2023-10-28 03:48:27 +02:00
ldy #$00
@lcd_print_loop:
2023-10-30 22:14:08 +01:00
lda (ARG0),y
2023-10-28 03:48:27 +02:00
beq @lcd_print_end
2023-12-08 22:56:35 +01:00
jsr print_char
2023-10-28 03:48:27 +02:00
iny
bra @lcd_print_loop
@lcd_print_end:
2023-10-26 19:51:20 +02:00
rts
2023-10-28 03:48:27 +02:00
.endproc
2023-12-16 02:41:19 +01:00
2023-12-08 22:56:35 +01:00
;;********************************************************************************
2023-12-16 02:41:19 +01:00
;; @function Print a single character
2023-12-08 22:56:35 +01:00
;; @param A: Character to print
;;********************************************************************************
.proc print_char
2023-11-01 13:13:23 +01:00
pha
2023-12-16 02:41:19 +01:00
jsr _write_ram
2024-01-15 09:19:05 +01:00
inc _charcount
2023-12-08 22:56:35 +01:00
jsr _break_line
2023-11-01 13:13:23 +01:00
pla ; put char back in a
.endproc
2023-12-16 02:41:19 +01:00
;;********************************************************************************
;; @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
2024-08-08 20:39:25 +02:00
;; @modifies A,Y
2023-12-16 02:41:19 +01:00
;;********************************************************************************
.proc set_custom_char
cmp #8
bcs @rts ; >= 8
rol ; address is bytes 3-5
rol
rol
ora #lcd::CMD::SET_CG_ADDRESS
2023-12-16 02:41:19 +01:00
jsr lcd::_cmd
ldy #0
@loop:
lda (ARG0),y
jsr lcd::_write_ram
iny
cpy #8
bne @loop
clc
@rts:
rts
.endproc
2023-12-08 22:56:35 +01:00
;;********************************************************************************
;; Internal LCD Commands
;;********************************************************************************
2023-12-16 02:41:19 +01:00
;; @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
;;********************************************************************************
2023-12-08 22:56:35 +01:00
.proc _wait_nbusy
2023-12-16 02:41:19 +01:00
pha
2023-12-08 22:56:35 +01:00
stz lcd::LCD_IO + IO::DDRB ; set IO1-IO + IO::RB to input
2023-12-31 01:56:42 +01:00
lda lcd::LCD_IO + IO::RA
and #<~lcd::RA_MASK
ora #lcd::RW
sta lcd::LCD_IO + IO::RA
2023-10-26 19:51:20 +02:00
@lcd_wait_nbusy_loop: ; read the busy flag
2023-12-31 01:56:42 +01:00
; set E low, then high
lda lcd::LCD_IO + IO::RA
and #<~lcd::E
2023-12-08 22:56:35 +01:00
sta lcd::LCD_IO + IO::RA
2023-12-31 01:56:42 +01:00
ora #lcd::E
2023-12-08 22:56:35 +01:00
sta lcd::LCD_IO + IO::RA
2023-10-26 19:51:20 +02:00
2023-12-08 22:56:35 +01:00
lda lcd::LCD_IO + IO::RB
2023-12-16 02:41:19 +01:00
bmi @lcd_wait_nbusy_loop ; msb set
2023-10-26 19:51:20 +02:00
2023-12-31 01:56:42 +01:00
lda lcd::LCD_IO + IO::RA
and #<~lcd::RA_MASK
2023-12-08 22:56:35 +01:00
sta lcd::LCD_IO + IO::RA
lda #%11111111 ; set IO1-IO + IO::RB to output
sta lcd::LCD_IO + IO::DDRB
2023-12-16 02:41:19 +01:00
pla
2023-10-26 19:51:20 +02:00
rts
2023-11-01 13:13:23 +01:00
.endproc
2023-12-31 01:56:42 +01:00
2023-12-16 02:41:19 +01:00
2023-12-08 22:56:35 +01:00
;;********************************************************************************
;; @function Send a @ref lcd::CMD "command" to the lcd
2023-12-08 22:56:35 +01:00
;; @param A: command
;; @modifies A
;;********************************************************************************
2023-12-16 02:41:19 +01:00
.proc _cmd
2023-12-08 22:56:35 +01:00
jsr _wait_nbusy
2023-10-26 19:51:20 +02:00
2023-12-08 22:56:35 +01:00
sta lcd::LCD_IO + IO::RB
2023-12-16 02:41:19 +01:00
; while preserve bits 0-4: unset E, set RS
; unset E, RW and RS
lda lcd::LCD_IO + IO::RA
and #(<~lcd::RA_MASK)
2023-12-08 22:56:35 +01:00
sta lcd::LCD_IO + IO::RA
2023-12-16 02:41:19 +01:00
; set E
ora #lcd::E
2023-12-08 22:56:35 +01:00
sta lcd::LCD_IO + IO::RA
2023-12-16 02:41:19 +01:00
; unset E
eor #lcd::E
2023-12-08 22:56:35 +01:00
sta lcd::LCD_IO + IO::RA
2023-10-26 19:51:20 +02:00
rts
2023-10-28 03:48:27 +02:00
.endproc
2023-10-26 19:51:20 +02:00
2023-12-08 22:56:35 +01:00
;;********************************************************************************
2023-12-16 02:41:19 +01:00
;; @function Write a byte to the lcd
;; @details
;; Set the CG or DD address first
;; @param A: data
;; @modifies A
2023-12-08 22:56:35 +01:00
;;********************************************************************************
2023-12-16 02:41:19 +01:00
.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
2023-12-09 23:33:15 +01:00
pha
2023-12-16 02:41:19 +01:00
; 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
2023-12-09 23:33:15 +01:00
pla
rts
2023-12-08 22:56:35 +01:00
.endproc
;;********************************************************************************
2024-01-15 09:19:05 +01:00
;; @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
2024-01-15 09:19:05 +01:00
;;********************************************************************************
.proc _set_dd_ram_addr_from_charcount
2024-01-15 09:19:05 +01:00
cmp #$40 ; set to line1 when full
bcs @wrap_to_line1 ; a € [$40, $ff]
2024-01-15 09:19:05 +01:00
cmp #$10
bcc @line1 ; a € [$00, $0f]
2024-01-15 09:19:05 +01:00
cmp #$20
bcc @line2 ; a € [$10, $1f]
cmp #$30
bcc @line3 ; a € [$20, $2f]
; bra @line4; a € [$30, $3f]
2024-01-15 09:19:05 +01:00
@line4:
clc
adc #$20 ; _charcount $30-$3f -> $50 - $5f
bra @set_address
@wrap_to_line1:
and #%00111111
2024-01-15 09:19:05 +01:00
; 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
2024-01-15 09:19:05 +01:00
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
2023-12-08 22:56:35 +01:00
;;********************************************************************************
.proc _break_line
2023-10-26 19:51:20 +02:00
; check if checks are necessary
2024-01-15 09:19:05 +01:00
lda _charcount
2023-12-08 22:56:35 +01:00
beq @line1
2023-12-16 02:41:19 +01:00
bit #%10001111 ; ($10 | $20 | $30 | $40) = %01110000
beq @check
rts
@check:
2023-10-26 19:51:20 +02:00
; checks necessary
cmp #$10
2023-12-08 22:56:35 +01:00
beq @line2
2023-10-26 19:51:20 +02:00
cmp #$20
2023-12-08 22:56:35 +01:00
beq @line3
2023-10-26 19:51:20 +02:00
cmp #$30
2023-12-08 22:56:35 +01:00
beq @line4
cmp #$40 ; set to line1 when full
bge @line1
2023-10-26 19:51:20 +02:00
rts
2023-12-08 22:56:35 +01:00
@line1:
2024-01-15 09:19:05 +01:00
stz _charcount
lda #(lcd::CMD::SET_ADDRESS | lcd::LINE1)
2023-12-08 22:56:35 +01:00
jsr _cmd
2023-10-26 19:51:20 +02:00
rts
2023-12-08 22:56:35 +01:00
@line2:
lda #(lcd::CMD::SET_ADDRESS | lcd::LINE2)
2023-12-08 22:56:35 +01:00
jsr _cmd
2023-10-26 19:51:20 +02:00
rts
2023-12-08 22:56:35 +01:00
@line3:
lda #(lcd::CMD::SET_ADDRESS | lcd::LINE3)
2023-12-08 22:56:35 +01:00
jsr _cmd
2023-10-26 19:51:20 +02:00
rts
2023-12-08 22:56:35 +01:00
@line4:
lda #(lcd::CMD::SET_ADDRESS | lcd::LINE4)
2023-12-08 22:56:35 +01:00
jsr _cmd
2023-10-26 19:51:20 +02:00
rts
2023-10-28 03:48:27 +02:00
.endproc