diff --git a/details.md b/details.md index 14c68e2..b0f7bed 100644 --- a/details.md +++ b/details.md @@ -15,5 +15,5 @@ leading underscors `_` indicate a "private" label/variable, that is meant for in ### Labels - **scopes**: snake case - **subroutines** and **variables**: snake case (`scope::(_)fname_snake_case` or `scope::(_)varname_2`) -- **macros**: camel case (`(_)GoodMacroname`) +- **macros**: camel case (`(_)GoodMacroname` or `scope_GoodMacroname`) - **constants** (eg. in ROM): upper case (`scope::(_)NICE_SYMBOLNAME`) diff --git a/main.s65 b/main.s65 index f52414d..20e5eaa 100644 --- a/main.s65 +++ b/main.s65 @@ -1,5 +1,5 @@ .include "system/system.h65" -.export home +.export home,homeloop .import printer:absolute .import spi_menu:absolute @@ -36,6 +36,7 @@ ; .include "utility.asm6502" ; LCD_IO = IO1 .include "system/lcd.h65" + .include "chars.h65" ; Keypad Reading ; KP_IO = IO2 .include "system/keypad.h65" @@ -43,7 +44,7 @@ .include "system/spi.h65" ; Printer ; .include "programs/printer.s65" - .include "programs/print_slow.s65" + .include "programs/print_slow.h65" ; .include "programs/spi-menu.s65" ; Digital Humidity and Temerature Sensor ; .include "dht.s65" @@ -107,6 +108,10 @@ reset: jsr kp::init + SetCustomChar chars::CAT,0 + SetCustomChar chars::SMILEY,1 + SetCustomChar chars::SMILEY_XD,2 + ; ; INIT DHT ; lda #%11000010 ; enable interrupt for Timer 1 and CA1 on IO2 @@ -126,6 +131,9 @@ reset: .proc home Print message_menu ; jsr rb_keypad_read + bra homeloop +.endproc +.proc homeloop @loop: lda kp::_DEBUG_VAL beq @loop diff --git a/programs/print_slow.h65 b/programs/print_slow.h65 new file mode 100644 index 0000000..b0a2aae --- /dev/null +++ b/programs/print_slow.h65 @@ -0,0 +1,25 @@ +.ifndef INCLUDE_PRINT_SLOW +INCLUDE_PRINT_SLOW = 1 + +.import print_slow + +;******************************************************************************** +; @macro Print a null-terminated string +; @param message: Address of the message +; @param time_cs: time to sleep in centiseconds +;******************************************************************************** +.macro PrintSlow message,time_cs + jsr lcd::clear + lda #message + sta ARG1 + phx + ldx #time_cs + jsr print_slow + plx +.endmacro + +.endif ; guard + + diff --git a/programs/print_slow.s65 b/programs/print_slow.s65 index cdc51f9..a552bcd 100644 --- a/programs/print_slow.s65 +++ b/programs/print_slow.s65 @@ -1,10 +1,9 @@ -.ifndef INCLUDE_PRINT_SLOW -INCLUDE_PRINT_SLOW = 1 - .include "system.h65" -.include "sleep.s65" +.include "sleep.h65" .include "lcd.h65" +.export print_slow + .code ;******************************************************************************** ; @function Print a null-terminated string @@ -25,22 +24,3 @@ INCLUDE_PRINT_SLOW = 1 @print_end: rts .endproc - -;******************************************************************************** -; @macro Print a null-terminated string -; @param message: Address of the message -; @param time_cs: time to sleep in centiseconds -;******************************************************************************** -.macro PrintSlow message,time_cs - jsr lcd::clear - lda #message - sta ARG1 - phx - ldx #time_cs - jsr print_slow - plx -.endmacro - -.endif ; guard diff --git a/programs/sleep.h65 b/programs/sleep.h65 new file mode 100644 index 0000000..d138b9f --- /dev/null +++ b/programs/sleep.h65 @@ -0,0 +1,20 @@ +.ifndef INCLUDE_SLEEP +INCLUDE_SLEEP = 1 + +.import sleep + +.code +;******************************************************************************** +; @macro Sleep +; @param time_cs: Time to sleep in centiseconds (10^-2s = 10ms) +; @details +; Interrupts might change the actual time to finish +;******************************************************************************** +.macro Sleep time_cs + phx + ldx #time_cs + jsr sleep + plx +.endmacro + +.endif ; guard diff --git a/programs/sleep.s65 b/programs/sleep.s65 index fb13ba2..dda9979 100644 --- a/programs/sleep.s65 +++ b/programs/sleep.s65 @@ -1,20 +1,8 @@ -.ifndef INCLUDE_SLEEP -INCLUDE_SLEEP = 1 .include "system.h65" -.code -;******************************************************************************** -; @macro Sleep -; @param time_cs: Time to sleep in centiseconds (10^-2s = 10ms) -; @details -; Interrupts might change the actual time to finish -;******************************************************************************** -.macro Sleep time_cs - phx - ldx #time_cs - jsr sleep - plx -.endmacro +.export sleep + +.code ;******************************************************************************** ; @function sleep ; @param x: Time to sleep in centiseconds (10^-2s = 10ms) @@ -41,4 +29,3 @@ _VAR_1 = ARG15 rts ; so T = N * 0,010 244 s - (1(last bne) + 4(jsr) + 6(rts)) * (1/1MHz) .endproc -.endif ; guard diff --git a/programs/spi-menu.s65 b/programs/spi-menu.s65 index f2d2d9f..cd467db 100644 --- a/programs/spi-menu.s65 +++ b/programs/spi-menu.s65 @@ -2,6 +2,7 @@ .include "string.h65" .include "keypad.h65" .include "lcd.h65" +.include "chars.h65" .import home:absolute .import SPI_IO @@ -22,10 +23,10 @@ status_str: .res 17 ; 16 + null jsr lcd::clear Print MENU @print_status: - Strf FMT_STATUS,status_str,trans_pages,trans_bytes,status lda #lcd::LINE4 jsr lcd::set_position - Print status_str + Strf FMT_STATUS,status_str,trans_pages,trans_bytes,status + PrintNC status_str @loop: ; check if a byte has been transferred @check_byte: @@ -82,7 +83,7 @@ status_str: .res 17 ; 16 + null .rodata MENU: - .byte "A> Beg. Transfer" + .byte chars::DOT, "A Beg. Transfer" .byte "B> Stop Transfer" .asciiz "C> Jump Home <*" ; .asciiz "0b0p Status: X" diff --git a/spicode.s65 b/spicode.s65 index 138407b..d226f5a 100644 --- a/spicode.s65 +++ b/spicode.s65 @@ -1,282 +1,154 @@ .include "system.h65" +.include "string.h65" .include "lcd.h65" .include "math.h65" .include "keypad.h65" +.include "chars.h65" +.import homeloop:absolute .import home:absolute .segment "SPI" .export CODE_START CODE_START: .assert * = $5000, error, "SPI Code not at $5000" - lda '$' + jsr lcd::clear + lda #'>' jsr lcd::print_char - lda #TEST_FMT - sta ARG1 - lda #TEST_OUT - sta ARG3 - lda #$a9 - sta ARG4 - lda #$3c - sta ARG5 - lda #$10 - sta ARG6 - jsr strf - Print TEST_OUT + jsr rb_test_init stz kp::_DEBUG_VAL + ldy #0 @loop: lda kp::_DEBUG_VAL - jeq home + pha + stz kp::_DEBUG_VAL + pla + beq @loop + cmp #'*' + jeq homeloop + cmp #'#' + beq @print + tya + pha + iny + jsr rb_test_write + pla + ora #$30 + jsr lcd::print_char + bra @loop -fmt_idx = $30 -out_idx = $31 -fmt_digit = $32 -.proc strf - stz out_idx - stz fmt_idx - stz fmt_digit - ldx #0 ; index of format args -@loop: - ldy fmt_idx - lda (ARG0),y - beq @null - cmp #'%' - beq @percent -@normal_char: ; store A in output string - ldy out_idx - sta (ARG2),y - inc fmt_idx - inc out_idx - beq @out_overflow - bra @loop -@percent: ; check for format in next position - iny - sty fmt_idx - lda (ARG0),y ; next char - beq @null - ; formats - cmp #'9' - ble @percent_number ; numbers < letters - cmp #'x' - beq @format_hex1 - bra @normal_char -@percent_number: - cmp #'1' - blt @normal_char ; NaN or zero - ; todo covert from char - jsr hex_char_to_int ; only 0-9 supported - ; A is now number of digits to convert - sta fmt_digit - iny - sty fmt_idx - lda (ARG0),y ; next char - beq @null - cmp #'x' - beq @format_hexN - bra @normal_char -@format_hexN: - lda fmt_digit - jsr int_to_hex_str - bra @format_return +@print: +@printloop: + lda #'r' + jsr lcd::print_char + jsr @print_state -@format_hex1: ; 1 byte hex -> 2 chars - lda ARG4,x - phx - jsr int8_to_hex_str - ldy out_idx - sta (ARG2),y ; most sig digit - iny - beq @out_overflow - txa - sta (ARG2),y ; least sig digit - iny - beq @out_overflow - sty out_idx - plx - inx ; 1 byte of args handeled - ; bra @format_return -@format_return: ; increment fmt_idx to swallow the formating char - inc fmt_idx - bra @loop -@out_overflow: ; store 0 in last position - ldy #$ff - sty out_idx -@store_null: - lda #0 -@null: ; store and return - ldy out_idx - sta (ARG2),y -@rts: + jsr rb_test_read + beq @empty + ora #$30 + jsr lcd::print_char + + lda #';' + jsr lcd::print_char + + bra @printloop +@empty: + lda #'E' + jsr lcd::print_char + lda #';' + jsr lcd::print_char + bra @loop +@print_state: + lda #'(' + jsr lcd::print_char + lda RB_READ + ora #$30 + jsr lcd::print_char + lda RB_WRITE + ora #$30 + jsr lcd::print_char + lda #')' + jsr lcd::print_char rts -.endproc - - -;******************************************************************************** -; @function Convert a 1 byte number into two hex characters -; @param A: Number to convert -; @returns A: Most significant digit -; @returns X: Least significant digit -; @modifies A,X,Y -;******************************************************************************** -.proc int8_to_hex_str - pha - and #%00001111 - tay - ldx HEX_CHARS_UPPER,y - pla - div A,16 - and #%00001111 - tay - lda HEX_CHARS_UPPER,y - rts -.endproc - -;******************************************************************************** -; @function Convert any int into hex -; @param ARG2-3: Address of output string -; @param Y: Offset onto output string -; @param A: Number of digits to convert -; @param X: Offset onto ARG4 = start of int (big endian) -; @returns Y: New offset onto output string -; @returns A: 0 -; @returns X: Offset onto ARG4 = past the end of number -; @modifies X,Y,A -;******************************************************************************** -.proc int_to_hex_str - bit - beq @rts ; check done -@loop: - ; load next byte - pha - lda ARG4,x - inx - phx - pha ; copy byte - div A,16 ; get first 4 bits = first digit - and #%00001111 - phy - tay - lda HEX_CHARS_LOWER,y - ply - sta (ARG2),y - iny - pla ; get copy - and #%00001111 ; lower 4 bits = second digit - phy - tay - lda HEX_CHARS_LOWER,y - ply - sta (ARG2),y - iny - plx - pla - dec - bne @loop -@rts: - rts -.endproc - - - -;******************************************************************************** -; @function Convert a hex char into a binary number -; @details -; The char must be one of [0-9,a-f,A-F]. -; All results are only valid if N == 0. -; @param A: Char to convert -; @returns N: 0 == success, 1 == invalid char -; @returns A: The converted number -;******************************************************************************** -.proc hex_char_to_int - sec - sbc #'0' - bmi @invalid ; char was in [0, '0') - cmp #10 - bcc @rts ; A in [0, 10) - ; char higher than '9' - sbc #('A' - '0') - bmi @invalid ; char was in ('0', 'A') - cmp #7 - bcc @hex_char ; A in [0, 6] - ; char higher than 'F' - sbc #('a' - 'A') - bmi @invalid ; char was in ('F', 'a') - cmp #17 - bcc @hex_char ; A in [0, 6] - ; char was in ('f', $ff] -@invalid: - lda #$ff ; sets N flag - rts -@hex_char: - ; carry is not set - adc #10 -@rts: - rts -.endproc - - -;******************************************************************************** -; @function Convert a number encoded as hexadecimal string to a binary number -; @details -; The string must only consist of [0-9,a-f,A-F]. -; All results are only valid if N == 0. -; @param ARG0-1: Address of string -; @param A: Number of chars to convert -; @param Y: Offset onto string so that first char = (ARG0) + Y -; @returns N: 0 => success, 1 => invalid string -; @returns A: 0 -; @returns X: Size of the number in bytes -; @returns Y: Offset onto string, past the end of the number -; @modifies X,Y,A -;******************************************************************************** -.proc hex_to_int - bit #%11111111 ; check if accumulator is zero - beq @rts - ldx #0 - bit #%00000001 ; check if accumulator is even - beq @loop ; even - ; not even - stz ARG2 - pha - bra @less_sig_char -@loop: - pha - ; more significant char - lda (ARG0),y ; load next char - iny - jsr hex_char_to_int - bmi @invalid - rol - rol - rol - rol - sta ARG2,x -@less_sig_char: - ; less significant char - lda (ARG0),y ; load next char - iny - jsr hex_char_to_int - bmi @invalid - ora ARG2,x - sta ARG2,x - inx - pla - dec - bne @loop -@invalid: -@rts: - rts - -.endproc -TEST_FMT: .asciiz "%x -> %x -> %x:)" -TEST_OUT: .asciiz "TESTOUT" -HEX_CHARS_UPPER: .byte "0123456789ABCDEF" -HEX_CHARS_LOWER: .byte "0123456789abcdef" + +TEST_MEMSIZE = $A + +RBUF_MEM_START: + .res TEST_MEMSIZE +RBUF_MEM_END: + + +.define RBUF_NAME "test" +.define _RBUF_NAME .concat("rb_", RBUF_NAME) +RB_WRITE = RBUF_MEM_START ; write pointer, relative to RB_WRITE +RB_READ = RBUF_MEM_START + 1 ; read ponter, relative to RB_START +RB_START = RBUF_MEM_START + 2 +RB_LENGTH = RBUF_MEM_END - RBUF_MEM_START - 2 + +.if RB_LENGTH < 1 + .fatal "buffer size too small, must be at least 1" +.endif +.if RB_LENGTH > $ff + .fatal "buffer size too large, must be <= $ff" +.endif + +; .out .sprintf("Buffer: %x -> %x (len=%x)", RBUF_MEM_START, RBUF_MEM_END, RB_LENGTH) + + +.proc rb_test_init + stz RB_WRITE + stz RB_READ + rts +.endproc + +.proc rb_test_read + ldx RB_READ + cpx RB_WRITE + beq @rb_read_rts ; if buffer empty + lda RB_START,x + inx ; increment RB_READ pointer, not using macro bec. of unknown Pz + cpx #RB_LENGTH + beq @read_wrap + stx RB_READ +@rb_read_rts: + rts +@read_wrap: ; ptr == RB_LENGTH -> ptr = 0 + stz RB_READ + ; make sure Pz is not set + ldx #$01 + rts +.endproc + +.proc rb_test_write + ; lda kp_VALUES, x ; load the char in a + ldx RB_WRITE + sta RB_START,x + inx ; increment write pointer + cpx #RB_LENGTH + beq @write_wrap + stx RB_WRITE +@check_buf_full: ; increment read if buffer is full + cpx RB_READ + beq @read_inc + rts +@write_wrap: ; ptr == RB_LENGTH -> ptr = 0 + stz RB_WRITE + ldx #0 + bra @check_buf_full +@read_inc: + ldx RB_READ + inx + cpx #RB_LENGTH + beq @read_wrap + stx RB_READ + rts +@read_wrap: ; ptr == RB_LENGTH -> ptr = 0 + stz RB_READ + rts +.endproc + + diff --git a/system/lcd.h65 b/system/lcd.h65 index 816a653..392baba 100644 --- a/system/lcd.h65 +++ b/system/lcd.h65 @@ -10,7 +10,6 @@ ; - IO.RA7 -> LCD.E enable ; ; @requires IO: Base Address of IO Chip -; @optparam MEM: Memory address for a runtime variable. Default = $300 ; @depends IO-W65C22N ;******************************************************************************** .ifndef INCLUDE_LCD @@ -20,14 +19,28 @@ INCLUDE_LCD = 1 .scope lcd LCD_IO = IO1 -Import lcd,init,clear,print,print_char,set_position +Import lcd,init,clear,print,print_char,set_position,set_custom_char +Import lcd,_cmd,_wait_nbusy,_write_ram,_read_ram + +;******************************************************************************** +; @macro Clear the screen and print a null-terminated string +; @param message: Address of the message +;******************************************************************************** +.macro Print message + jsr lcd::clear + lda #message + sta ARG1 + jsr lcd::print +.endmacro + ;******************************************************************************** ; @macro Print a null-terminated string ; @param message: Address of the message ;******************************************************************************** -.macro Print message - jsr lcd::clear +.macro PrintNC message lda #message @@ -40,11 +53,18 @@ E = %10000000 RW = %01000000 RS = %00100000 +RA_MASK = %11100000 + ; LCD Instructions (see datasheet for more) CMD_CLEAR = %00000001 ; clear display CMD_ENTRY_MODE = %00000110 ; auto-shift cursor CMD_DISPLAY_ON = %00001111 ; everything on, with blinking cursor +CMD_SHIFT_CUR_LEFT = %00101000 ; shift the display to the left +CMD_SHIFT_DIS_LEFT = %00111000 ; shift the display to the left +CMD_SHIFT_DIS_RIGHT = %00110000 ; shift the display to the right +CMD_SHIFT_CUR_RIGHT = %00100000 ; shift the display to the right CMD_FUNCTION_SET = %00111000 ; 8-bit, 4 lines, 5x7 font +CMD_SET_CG_ADDRESS = %01000000 ; or with the address CMD_SET_ADDRESS = %10000000 ; or with the address ; LCD Constants LINE1 = $00 @@ -52,9 +72,5 @@ LINE2 = $40 LINE3 = $10 LINE4 = $50 -CLEAR = %00000000 - -.ifndef KEEPSCOPE .endscope -.endif .endif ; guard diff --git a/system/lcd.s65 b/system/lcd.s65 index 90015df..7e19bbc 100644 --- a/system/lcd.s65 +++ b/system/lcd.s65 @@ -4,12 +4,13 @@ .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 - +Export lcd,init,clear,print,print_char,set_position,set_custom_char +Export lcd,_cmd,_wait_nbusy,_write_ram,_read_ram ; 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 @@ -21,9 +22,9 @@ charcount: .res 1 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 + MaskedWrite lcd::LCD_IO+IO::DDRA, (lcd::RS | lcd::RW | lcd::E), lcd::RA_MASK + ; lda #(lcd::RS | lcd::RW | lcd::E) ; RA 5-7 output + ; sta lcd::LCD_IO+IO::DDRA ; init lcd lda #lcd::CMD_FUNCTION_SET @@ -40,115 +41,11 @@ charcount: .res 1 .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 +;; If the position is too large, it will be set to char 4 in line 2 ;; @returns A: the cursor position ;;******************************************************************************** .proc set_position @@ -176,16 +73,209 @@ charcount: .res 1 @set: sta charcount pla + pha ora #lcd::CMD_SET_ADDRESS jsr _cmd - and #(<~lcd::CMD_SET_ADDRESS) ; return original argument + ; and #(<~lcd::CMD_SET_ADDRESS) ; return original argument + pla rts @invalid: - lda $14 + pla ; otherwise stack corruption + lda #$13 sta charcount - lda #(lcd::CMD_SET_ADDRESS | (lcd::LINE2 + 4)) + lda #(lcd::CMD_SET_ADDRESS | (lcd::LINE2 + 3)) jsr _cmd - lda #(lcd::LINE2 + 4) + 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 +@lcd_wait_nbusy_loop: ; read the busy flag + ; TODO use update_with_mask + 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 + bmi @lcd_wait_nbusy_loop ; msb set + ; 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 + pla + rts +.endproc + + +;;******************************************************************************** +;; @function Send a 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 @@ -197,11 +287,11 @@ charcount: .res 1 ; check if checks are necessary lda charcount beq @line1 - and #%10001111 ; ($10 | $20 | $30 | $40) = %01110000 - bne @rts + bit #%10001111 ; ($10 | $20 | $30 | $40) = %01110000 + beq @check + rts +@check: ; checks necessary - lda charcount - beq @line1 cmp #$10 beq @line2 cmp #$20 @@ -210,7 +300,6 @@ charcount: .res 1 beq @line4 cmp #$40 ; set to line1 when full bge @line1 -@rts: rts @line1: stz charcount @@ -230,4 +319,3 @@ charcount: .res 1 jsr _cmd rts .endproc - diff --git a/system/system.h65 b/system/system.h65 index 5ff42d7..058d860 100644 --- a/system/system.h65 +++ b/system/system.h65 @@ -32,6 +32,7 @@ ARG4 = $14 ARG5 = $15 ARG6 = $16 ARG7 = $17 +ARG8 = $18 ARG9 = $19 ARG10 = $1a ARG11 = $1b diff --git a/util/string.h65 b/util/string.h65 index 82bf9aa..c5da36e 100644 --- a/util/string.h65 +++ b/util/string.h65 @@ -11,7 +11,8 @@ INCLUDE_STRING = 1 .scope str -Import str, strf, int8_to_hex_str +Import str, strf +Import str, hex_char_to_uint8, hex_str_to_uint, uint8_to_hex_str .macro _StrfStoreArg arg diff --git a/util/string.s65 b/util/string.s65 index 34bc86c..b886d18 100644 --- a/util/string.s65 +++ b/util/string.s65 @@ -1,6 +1,5 @@ .include "string.h65" -.include "math.h65" -Export str, strf, int8_to_hex_str +Export str, strf .code ;******************************************************************************** @@ -50,7 +49,7 @@ fmt_idx := str::fmt_idx @format_hex1: ; 1 byte hex -> 2 chars lda ARG4,x phx - jsr int8_to_hex_str + jsr str::uint8_to_hex_str ldy out_idx sta (ARG2),y ; most sig digit iny @@ -79,27 +78,3 @@ fmt_idx := str::fmt_idx .endproc -;******************************************************************************** -; @function Convert a 1 byte number into two hex characters -; @param A: Number to convert -; @returns A: Most significant digit -; @returns X: Least significant digit -; @modifies A,X,Y -;******************************************************************************** -.proc int8_to_hex_str - pha - and #%00001111 - tay - ldx HEX_CHARS_UPPER,y - pla - div A,16 - and #%00001111 - tay - lda HEX_CHARS_UPPER,y - rts -.endproc - - -.rodata -HEX_CHARS_UPPER: .byte "0123456789ABCDEF" -HEX_CHARS_LOWER: .byte "0123456789abcdef" diff --git a/utility.h65 b/utility.h65 index 1a1d82d..ad66569 100644 --- a/utility.h65 +++ b/utility.h65 @@ -4,22 +4,26 @@ INCLUDE_UTILITY = 1 .macpack longbranch ; jeq, jge... .macpack generic ; bge, add, sub +.feature string_escapes +.feature underline_in_numbers + + ;******************************************************************************** ; @macro Update a byte in memory using a mask -; @param orignal Address of the byte to update -; @param new New value +; @param addr Address of the byte to update +; @param value New value ; @param mask Mask of the bits to affect by the new value ; @details -; xor new with original -> only bits that need to flip are 1 -; and result with mask -> only selected bits that need to flip stay 1 -; xor result with original -> flips selected bits +; xor #value with addr -> only bits that need to flip are 1 +; and result with #mask -> only selected bits that need to flip stay 1 +; xor result with addr -> flips selected bits ;******************************************************************************** -.macro UT_update_with_mask original,new,mask - lda #new - eor original +.macro MaskedWrite addr,value,mask + lda #value + eor addr and #mask - eor original - sta original + eor addr + sta addr .endmacro @@ -27,7 +31,7 @@ INCLUDE_UTILITY = 1 ;;******************************************************************************** ;; @macro Generate a unique label ;;******************************************************************************** -.macro genlabel +.macro GenLabel .ident(.sprintf("generated_label%04X", _n_genlabel)) _n_genlabel .set _n_genlabel + 1 .endmacro