From 9a1324a29a64b0afe8f64dbd29949b5aab8e4581 Mon Sep 17 00:00:00 2001 From: "matthias@arch" Date: Fri, 8 Dec 2023 22:56:35 +0100 Subject: [PATCH] refactor with source+header --- .gitignore | 5 +- Makefile | 51 +++-- linker.conf | 9 +- main.s65 | 47 ++--- programs/dht.s65 | 260 ++++++++++++------------ programs/memcopy.s65 | 9 +- programs/print_slow.s65 | 12 +- programs/printer.h65 | 10 + programs/printer.s65 | 19 +- programs/sleep.s65 | 5 +- programs/spi-menu.s65 | 29 ++- spicode.s65 | 149 ++++++++++++++ system/{buffer.s65 => buffer.h65} | 1 - system/keypad.h65 | 29 +++ system/keypad.s65 | 79 ++++---- system/lcd.h65 | 60 ++++++ system/lcd.s65 | 315 ++++++++++++++---------------- system/ram.s65 | 31 --- system/spi.h65 | 18 ++ system/spi.s65 | 165 +--------------- system/system.h65 | 55 ++++++ system/system.s65 | 85 +------- test.s65 | 98 +++++----- util/math.h65 | 107 ++++++++++ util/math.s65 | 107 +--------- util/string.h65 | 66 +++++++ util/string.s65 | 68 +------ utility.h65 | 56 ++++++ 28 files changed, 1032 insertions(+), 913 deletions(-) create mode 100644 programs/printer.h65 create mode 100644 spicode.s65 rename system/{buffer.s65 => buffer.h65} (98%) create mode 100644 system/keypad.h65 create mode 100644 system/lcd.h65 delete mode 100644 system/ram.s65 create mode 100644 system/spi.h65 create mode 100644 system/system.h65 create mode 100644 util/math.h65 create mode 100644 util/string.h65 diff --git a/.gitignore b/.gitignore index 23b7684..10a7c0c 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ **.bin **.o -.build -.dependencies +**.d +*build* +labels diff --git a/Makefile b/Makefile index 622aa81..84e3b7a 100644 --- a/Makefile +++ b/Makefile @@ -1,41 +1,54 @@ ROM = ../rom.bin -BUILD_DIR = .build +OBJ_DIR = build -SRC_DIRS = programs system +SRC_DIRS = . programs system util # VASM = ~/6502/vasm6502 ASM = ca65 ASMFLAGS = -g --cpu 65C02 $(foreach srcdir, $(SRC_DIRS), -I $(srcdir)) -ASMDEPFLAGS = --create-dep .dependencies LD = ld65 -LDFLAGS = -C linker.conf +LDFLAGS = -C linker.conf --obj-path $(OBJ_DIR) -Ln labels + +SRC = $(wildcard *.s65) $(wildcard */*.s65) +OBJ = $($(notdir SRC):%.s65=$(OBJ_DIR)/%.o) +OBJ_DIRS = $(OBJ_DIR) $(foreach dir_,$(SRC_DIRS),$(OBJ_DIR)/$(dir_)) +DEP = $(wildcard $(OBJ_DIR)/*/*.d) # DEPENDS = $(shell $(VASM) -depend=make $(MAIN)) --include .dependencies +-include $(DEP) -$(BUILD_DIR): - mkdir $@ - -.PHONY: default test clean +.PHONY: default test clean print .DEFAULT_GOAL = default -default: $(ROM) + +FMT_MESSAGE="\e[1;34m%s\e[0m %s\n" +FMT_ASM="\e[1;34mAssembling\e[0m: \e[34m%s\e[39m from %s\e[0m\n" +FMT_VAR="\e[1;35m%s\e[0m: %s\n" + test: ../test.bin +print: + @printf $(FMT_VAR) "ASMFLAGS" "$(ASMFLAGS)" + @printf $(FMT_VAR) "LDFLAGS" "$(LDFLAGS)" + @printf $(FMT_VAR) "SRC" "$(SRC)" + @printf $(FMT_VAR) "OBJ" "$(OBJ)" +default: $(ROM) +$(OBJ_DIRS): + mkdir -p $@ -$(ROM): $(BUILD_DIR)/main.o +$(ROM): $(OBJ) + @printf $(FMT_MESSAGE) "Linking" "$@" + $(LD) $(LDFLAGS) $(OBJ) -o $@ + +../test.bin: $(OBJ_DIR)/test.o $(LD) $(LDFLAGS) $< -o $@ -../test.bin: $(BUILD_DIR)/test.o - # $(VASM) -dotdir -opt-branch -wdc02 -chklabels test.asm6502 - $(LD) $(LDFLAGS) $(BUILD_DIR)/test.o -o ../test.bin - -$(BUILD_DIR)/%.o: %.s65 | $(BUILD_DIR) - $(ASM) $(ASMFLAGS) $(ASMDEPFLAGS) $< -o $@ - +$(OBJ_DIR)/%.o: %.s65 | $(OBJ_DIRS) + @printf $(FMT_ASM) "$@" "$<" + $(ASM) $(ASMFLAGS) --create-dep $(patsubst %.o,%.d,$@) $< -o $@ clean: - rm -r $(BUILD_DIR) + rm -r $(OBJ_DIR) rm $(ROM) diff --git a/linker.conf b/linker.conf index 492555a..3ccb861 100644 --- a/linker.conf +++ b/linker.conf @@ -1,10 +1,11 @@ MEMORY { - RAM_ZP: start = $0000, size = $100, type = rw, file = "", fill = yes; + RAM_ZP: start = $0000, size = $0100, type = rw, file = "", fill = yes; # RAM: start = $0100, size = $5eff, type = rw, file = "", fill = yes; - RAM: start = $0100, size = $4eff, type = rw, file = "", fill = yes; + STACK: start = $0100, size = $0100, type = rw, file = "", fill = yes; + RAM: start = $0200, size = $4e00, type = rw, file = "", fill = yes; SPI: start = $5000, size = $1000, type = rw, file = "spi.bin", fill = no; - VIA1: start = $6000, size = $600f, type = rw, file = "", fill = yes; - VIA2: start = $7000, size = $700f, type = rw, file = "", fill = yes; + VIA1: start = $6000, size = $000f, type = rw, file = "", fill = yes; + VIA2: start = $7000, size = $000f, type = rw, file = "", fill = yes; ROM: start = $8000, size = $8000, type = ro, file = %O, fill = yes; } SEGMENTS { diff --git a/main.s65 b/main.s65 index 5430746..f52414d 100644 --- a/main.s65 +++ b/main.s65 @@ -1,4 +1,8 @@ -.include "system/system.s65" +.include "system/system.h65" +.export home +.import printer:absolute +.import spi_menu:absolute + .code .macro DEBUG_LED_OFF nr @@ -30,18 +34,17 @@ ;******************************************************************************** ; LCD ; .include "utility.asm6502" -LCD_IO = IO1 - .include "system/lcd.s65" +; LCD_IO = IO1 + .include "system/lcd.h65" ; Keypad Reading -KP_IO = IO2 - .include "system/keypad.s65" +; KP_IO = IO2 + .include "system/keypad.h65" ; SPI -SPI_IO = IO2 - .include "system/spi.s65" + .include "system/spi.h65" ; Printer - .include "programs/printer.s65" + ; .include "programs/printer.s65" .include "programs/print_slow.s65" - .include "programs/spi-menu.s65" + ; .include "programs/spi-menu.s65" ; Digital Humidity and Temerature Sensor ; .include "dht.s65" @@ -54,7 +57,7 @@ IRQ_VAR: .res 1 .code nmi: lda #'%' - jsr lcd_char + jsr lcd::print_char rti irq: ; read IRFs, while bit 7 ist set handle interrupts @@ -69,7 +72,7 @@ irq: bbs2 IRQ_VAR,@irq_spi_p ; check SR bbs1 IRQ_VAR,@irq_keypad ; check CA1 ; this should never be reached - jsr lcd_clear + jsr lcd::clear Print str_irq_unknown ; force reset interrupt flags lda #$ff @@ -77,7 +80,7 @@ irq: sta IO2 + IO::IFR bra @irq_return @irq_keypad: - jsr kp_read_on_irq + jsr kp::read_irq bra @irq_return @irq_spi_p: jsr spi_p::read @@ -92,7 +95,7 @@ irq: ; Reset sequence ;******************************************************************************** reset: - jsr lcd_init + jsr lcd::init ; TODO debug stuff stz IO2 + IO::DDRB @@ -102,7 +105,7 @@ reset: DEBUG_LED_OFF 1 - jsr kp_init + jsr kp::init ; ; INIT DHT @@ -124,17 +127,17 @@ reset: Print message_menu ; jsr rb_keypad_read @loop: - lda _KP_DEBUG_VAL + lda kp::_DEBUG_VAL beq @loop ; TODO debug sta 0 - stz _KP_DEBUG_VAL + stz kp::_DEBUG_VAL lda 0 ; beq home cmp #'A' jeq printer cmp #'B' - jeq spi_menu::spi_menu + jeq spi_menu cmp #'C' jeq print_1 cmp #'D' @@ -166,23 +169,23 @@ reset: DEBUG_LED_ON 1 jmp @loop @print_rb: - jsr lcd_clear + jsr lcd::clear Print str_io2 lda IO2 + IO::RB - jsr lcd_char + jsr lcd::print_char lda #''' - jsr lcd_char + jsr lcd::print_char jmp @loop .endproc print_1: - jsr lcd_clear + jsr lcd::clear PrintSlow message_1,10 jmp home print_2: - jsr lcd_clear + jsr lcd::clear PrintSlow message_2,10 jmp home diff --git a/programs/dht.s65 b/programs/dht.s65 index 301d549..fa10256 100644 --- a/programs/dht.s65 +++ b/programs/dht.s65 @@ -1,155 +1,155 @@ -;******************************************************************************** -; @module SPI -; @type driver -; @details -; @depends IO-W65C22N -;******************************************************************************** +;;******************************************************************************** +;; @module SPI +;; @type driver +;; @details +;; @depends IO-W65C22N +;;******************************************************************************** -;TODO EVERYTHING -DHT_REQUEST_L = $00 -DHT_REQUEST_H = %01010000 ; = 20480 PHI2 pulses = 20,5 ms at 1 MHz +;;TODO EVERYTHING +;DHT_REQUEST_L = $00 +;DHT_REQUEST_H = %01010000 ; = 20480 PHI2 pulses = 20,5 ms at 1 MHz -DHT_RECV_H = %10011100 -DHT_RECV_L = %01000000 ; = 40000 PHI2 = 40ms +;DHT_RECV_H = %10011100 +;DHT_RECV_L = %01000000 ; = 40000 PHI2 = 40ms -; Status Variables, Used to determine what is sent by temp module -DHT_STATUS = $400 -DHT_NONE = 0 -DHT_WAIT_REQ = 1 -DHT_WAIT_RESP = 2 -DHT_RECV = 3 -DHT_DONE = 4 +;; Status Variables, Used to determine what is sent by temp module +;DHT_STATUS = $400 +;DHT_NONE = 0 +;DHT_WAIT_REQ = 1 +;DHT_WAIT_RESP = 2 +;DHT_RECV = 3 +;DHT_DONE = 4 -DHT_BIT = $401 -DHT_BIT_ROT = $402 +;DHT_BIT = $401 +;DHT_BIT_ROT = $402 -DHT_VALUES = $405 ; -DHT_OFFSET = $403 -DHT_OFF_RH_HIGH = 0 ; offsets to DHT_VALUES -DHT_OFF_RH_LOW = 1 -DHT_OFF_T_HIGH = 2 -DHT_OFF_T_LOW = 3 -DHT_OFF_CHECKSUM = 4 -DHT_OFF_DONE = 5 +;DHT_VALUES = $405 ; +;DHT_OFFSET = $403 +;DHT_OFF_RH_HIGH = 0 ; offsets to DHT_VALUES +;DHT_OFF_RH_LOW = 1 +;DHT_OFF_T_HIGH = 2 +;DHT_OFF_T_LOW = 3 +;DHT_OFF_CHECKSUM = 4 +;DHT_OFF_DONE = 5 -message_dht: .asciiz "DHT-Request gesendet." -dht_wait: - ldx #$00 -dht_wait_: - lda message_dht,x - sta TO_PRINT,x - inx - bne dht_wait_ - jsr lcd_print_clear -dht_wait_loop: ; check after every interrpt if dht program is done and then return home - lda #'.' - jsr _lcd_char - wai - lda DHT_STATUS - cmp #DHT_DONE - bne dht_wait_loop +;message_dht: .asciiz "DHT-Request gesendet." +;dht_wait: +; ldx #$00 +;dht_wait_: +; lda message_dht,x +; sta TO_PRINT,x +; inx +; bne dht_wait_ +; jsr lcd_print_clear +;dht_wait_loop: ; check after every interrpt if dht program is done and then return home +; lda #'.' +; jsr _lcd::print_char +; wai +; lda DHT_STATUS +; cmp #DHT_DONE +; bne dht_wait_loop -dht_exit: - jsr kb_read - cmp #'*' - jeq home - bra dht_exit - jmp return_home +;dht_exit: +; jsr kb_read +; cmp #'*' +; jeq home +; bra dht_exit +; jmp return_home -dht_request: ; send request to sensor - sei +;dht_request: ; send request to sensor +; sei - lda #%00000001 ; set PA1-0 to output 0 - ora IO2 + IO_DDRA - sta IO2 + IO_DDRA - lda #(LCD_CLEAR | $00) - sta IO2 + IO_RA +; lda #%00000001 ; set PA1-0 to output 0 +; ora IO2 + IO_DDRA +; sta IO2 + IO_DDRA +; lda #(LCD_CLEAR | $00) +; sta IO2 + IO_RA - ; start timer - lda #DHT_REQUEST_L - sta IO2 + IO_T1CL - lda #DHT_REQUEST_H - sta IO2 + IO_T1CH +; ; start timer +; lda #DHT_REQUEST_L +; sta IO2 + IO_T1CL +; lda #DHT_REQUEST_H +; sta IO2 + IO_T1CH - lda #DHT_WAIT_REQ - sta DHT_STATUS +; lda #DHT_WAIT_REQ +; sta DHT_STATUS - cli - jmp dht_wait +; cli +; jmp dht_wait -dht_request_end: - lda #%10000010 - sta IO2 + IO_IER ; enable Interrupt for CA1 - lda #%11111110 - and IO2 + IO_DDRA - sta IO2 + IO_DDRA ; set PA1-0 to input +;dht_request_end: +; lda #%10000010 +; sta IO2 + IO_IER ; enable Interrupt for CA1 +; lda #%11111110 +; and IO2 + IO_DDRA +; sta IO2 + IO_DDRA ; set PA1-0 to input - lda #DHT_WAIT_RESP +; lda #DHT_WAIT_RESP -dht_response: ; receive response from sensor - lda #DHT_RECV - sta DHT_STATUS - stz DHT_OFFSET - lda #7 - sta DHT_BIT +;dht_response: ; receive response from sensor +; lda #DHT_RECV +; sta DHT_STATUS +; stz DHT_OFFSET +; lda #7 +; sta DHT_BIT -dht_recv: - ; start timer - lda #DHT_RECV_L - sta IO2 + IO_T1CL - lda #DHT_RECV_H - sta IO2 + IO_T1CH - rts +;dht_recv: +; ; start timer +; lda #DHT_RECV_L +; sta IO2 + IO_T1CL +; lda #DHT_RECV_H +; sta IO2 + IO_T1CH +; rts -dht_recv_read: - ; read PA2 - lda IO2 + IO_RA - and #%00000001 - ldx DHT_BIT - beq dht_recv_end -dht_recv_rot: - rol - dex - bne dht_recv_rot -dht_recv_end: - ldy DHT_OFFSET - ora DHT_VALUES,y - sta DHT_VALUES,y - ; determine if 8 bits are done - ldx DHT_BIT - beq dht_recv_next - rts -dht_recv_next: - lda #7 - sta DHT_BIT - inc DHT_OFFSET - cmp DHT_OFF_DONE - beq dht_display - rts +;dht_recv_read: +; ; read PA2 +; lda IO2 + IO_RA +; and #%00000001 +; ldx DHT_BIT +; beq dht_recv_end +;dht_recv_rot: +; rol +; dex +; bne dht_recv_rot +;dht_recv_end: +; ldy DHT_OFFSET +; ora DHT_VALUES,y +; sta DHT_VALUES,y +; ; determine if 8 bits are done +; ldx DHT_BIT +; beq dht_recv_next +; rts +;dht_recv_next: +; lda #7 +; sta DHT_BIT +; inc DHT_OFFSET +; cmp DHT_OFF_DONE +; beq dht_display +; rts -dht_display: - ldx #0 -dht_display_: - lda DHT_VALUES,x - sta TO_PRINT,x - inx - cpx #5 - bne dht_display_ - jsr lcd_print_clear - rts +;dht_display: +; ldx #0 +;dht_display_: +; lda DHT_VALUES,x +; sta TO_PRINT,x +; inx +; cpx #5 +; bne dht_display_ +; jsr lcd_print_clear +; rts -dht_irq: - lda DHT_STATUS - cmp #DHT_WAIT_REQ - beq dht_request_end - cmp #DHT_WAIT_RESP - beq dht_response - cmp #DHT_RECV - beq dht_recv - rts +;dht_irq: +; lda DHT_STATUS +; cmp #DHT_WAIT_REQ +; beq dht_request_end +; cmp #DHT_WAIT_RESP +; beq dht_response +; cmp #DHT_RECV +; beq dht_recv +; rts diff --git a/programs/memcopy.s65 b/programs/memcopy.s65 index 01f8a6b..b8c20ca 100644 --- a/programs/memcopy.s65 +++ b/programs/memcopy.s65 @@ -1,7 +1,9 @@ .ifndef INCLUDE_MEMCOPY INCLUDE_MEMCOPY = 1 +.include "system.h65" +.code ;******************************************************************************** ; @function Copy a block of memory to a different address ; @param ARG0-1: Source address @@ -9,14 +11,15 @@ INCLUDE_MEMCOPY = 1 ; @param y: Number of bytes to copy ;******************************************************************************** .proc memcopy - cpy -loop: + cpy #0 +@loop: beq @loop_end lda (ARG0),y sta (ARG2),y dey bra @loop -loop_end: +@loop_end: rts +.endproc .endif ; guard diff --git a/programs/print_slow.s65 b/programs/print_slow.s65 index 5edd508..cdc51f9 100644 --- a/programs/print_slow.s65 +++ b/programs/print_slow.s65 @@ -1,11 +1,11 @@ - .ifndef INCLUDE_PRINT_SLOW INCLUDE_PRINT_SLOW = 1 -.include "programs/sleep.s65" -.include "system/lcd.s65" - +.include "system.h65" +.include "sleep.s65" +.include "lcd.h65" +.code ;******************************************************************************** ; @function Print a null-terminated string ; @param ARG0-1: Address of the string to print @@ -19,7 +19,7 @@ INCLUDE_PRINT_SLOW = 1 phx jsr sleep plx - jsr lcd_char + jsr lcd::print_char iny bra @print_loop @print_end: @@ -32,7 +32,7 @@ INCLUDE_PRINT_SLOW = 1 ; @param time_cs: time to sleep in centiseconds ;******************************************************************************** .macro PrintSlow message,time_cs - jsr lcd_clear + jsr lcd::clear lda #message diff --git a/programs/printer.h65 b/programs/printer.h65 new file mode 100644 index 0000000..7404dcd --- /dev/null +++ b/programs/printer.h65 @@ -0,0 +1,10 @@ +;******************************************************************************** +; Printing Program +;******************************************************************************** +.ifndef INCLUDE_PRINTER +INCLUDE_PRINTER = 1 + +.global printer +.import home:absolute + +.endif ; guard diff --git a/programs/printer.s65 b/programs/printer.s65 index b4198fa..335ab10 100644 --- a/programs/printer.s65 +++ b/programs/printer.s65 @@ -1,16 +1,15 @@ -;******************************************************************************** -; Printing Program -;******************************************************************************** -.ifndef INCLUDE_PRINTER -INCLUDE_PRINTER = 1 +.include "printer.h65" +.include "lcd.h65" +.include "keypad.h65" + .code -printer: - jsr lcd_clear +.proc printer + jsr lcd::clear @printer_loop: - jsr rb_keypad_read + jsr kp::read beq @printer_loop cmp #'*' jeq home - jsr lcd_char + jsr lcd::print_char bra @printer_loop -.endif ; guard +.endproc diff --git a/programs/sleep.s65 b/programs/sleep.s65 index f274ac6..fb13ba2 100644 --- a/programs/sleep.s65 +++ b/programs/sleep.s65 @@ -1,5 +1,6 @@ .ifndef INCLUDE_SLEEP INCLUDE_SLEEP = 1 +.include "system.h65" .code ;******************************************************************************** ; @macro Sleep @@ -20,10 +21,10 @@ INCLUDE_SLEEP = 1 ; @details ; Interrupts might change the actual time to finish ; To be exact, time_cs is in units of 0.010244s -; @modifies: ARG2 +; @modifies: ARG15 ;******************************************************************************** .proc sleep -_VAR_1 = ARG2 +_VAR_1 = ARG15 stz _VAR_1 @loop: .repeat 17 diff --git a/programs/spi-menu.s65 b/programs/spi-menu.s65 index 0f97439..19d7a61 100644 --- a/programs/spi-menu.s65 +++ b/programs/spi-menu.s65 @@ -1,9 +1,11 @@ -.include "system/spi.s65" -.include "util/string.s65" -.ifndef INCLUDE_SPI_MENU -INCLUDE_SPI_MENU = 1 +.include "spi.h65" +.include "string.h65" +.include "keypad.h65" +.include "lcd.h65" +.import home:absolute +.import SPI_IO -.scope spi_menu +.export spi_menu .bss trans_bytes: .res 1 trans_pages: .res 1 @@ -17,12 +19,12 @@ status_str: .res 17 ; 16 + null lda #'X' sta status @print_menu: - jsr lcd_clear + jsr lcd::clear Print MENU @print_status: Strf FMT_STATUS,status_str,trans_pages,trans_bytes,status - lda #(LCD_CMD_SET_ADDRESS | LCD_LINE4) - jsr _lcd_cmd + lda #(lcd::CMD_SET_ADDRESS | lcd::LINE4) + jsr lcd::_cmd Print status_str @loop: ; check if a byte has been transferred @@ -43,11 +45,11 @@ status_str: .res 17 ; 16 + null bra @print_status @read_keypad: - lda _KP_DEBUG_VAL + lda kp::_DEBUG_VAL beq @loop ; TODO debug sta 0 - stz _KP_DEBUG_VAL + stz kp::_DEBUG_VAL lda 0 cmp #'*' beq @return_home @@ -70,9 +72,9 @@ status_str: .res 17 ; 16 + null jmp @print_menu @spi_jump: jsr spi_p::end - jsr lcd_clear + jsr lcd::clear Print START - jmp spi_p::SPI_CODE_START + jmp spi_p::CODE_START @return_home: jsr spi_p::end jmp home @@ -87,6 +89,3 @@ MENU: FMT_STATUS: .asciiz "%x%xb Status:%x" BEGIN: .asciiz "---BEGIN SPI---" START: .asciiz "---START SPI---" - -.endscope -.endif ; guard diff --git a/spicode.s65 b/spicode.s65 new file mode 100644 index 0000000..c1b54f9 --- /dev/null +++ b/spicode.s65 @@ -0,0 +1,149 @@ +.include "system.h65" +.include "lcd.h65" +.include "math.h65" +.import home:absolute +.segment "SPI" +.export CODE_START + +Export +CODE_START: + 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 +@spiloop: + bbs4 ASDA,dasdZQ + lda IO1 + IO::RA + lda IO2 + IO::RA + jeq @spiloop + bge @spiloop + nop + bra @spiloop + bro @spiloop + jmp home + lda €asdaasd + lda €$ff + lds €asda + + lds #($ff | asd) + lda #'c' + lda #(jk:) + + +; TODO allocate zp memory +fmt_idx = $30 +out_idx = $31 +;******************************************************************************** +; @function Format a string +; @details +; If there is no value to be read, the Pz will be set +; Formats: +; - u: unsigned decimal integer (1 byte) +; - U: unsigned decimal integer (2 bytes) +; @param ARG0-1: Format string address +; @param ARG2-3: Output string address +; @param ARG4+: Additional parameters +; @returns +; @modifies: A, Y +;******************************************************************************** +.proc strf + stz out_idx + stz fmt_idx + ldy #0 ; position in string + 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 + beq @null + ; formats + cmp #'x' + beq @format_hex1 + bra @normal_char +@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: + 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 X,Y,A +;******************************************************************************** +.proc int8_to_hex_str + pha + and #%00001111 + tay + ldx HEX_CHARS,y + pla + div A,16 + and #%00001111 + tay + lda HEX_CHARS,y + rts +.endproc + + + + +HEX_CHARS: .byte "0123456789ABCDEF" + +TEST_FMT: .asciiz "%x -> %x -> %x:)" +TEST_OUT: .asciiz "TESTOUT" + diff --git a/system/buffer.s65 b/system/buffer.h65 similarity index 98% rename from system/buffer.s65 rename to system/buffer.h65 index 68468e2..5cccb5c 100644 --- a/system/buffer.s65 +++ b/system/buffer.h65 @@ -77,7 +77,6 @@ RB_LENGTH = RBUF_MEM_END - RBUF_MEM_START - 2 ; @param A: value to store ; @modifies: X ;******************************************************************************** -;TODO increment read when write reaches it .ident(.concat(_RBUF_NAME, "_write")): .scope ; lda kp_VALUES, x ; load the char in a diff --git a/system/keypad.h65 b/system/keypad.h65 new file mode 100644 index 0000000..29bca1b --- /dev/null +++ b/system/keypad.h65 @@ -0,0 +1,29 @@ +;******************************************************************************** +; @module keypad4x4 +; @type driver +; @device 4x4 Matrix Keypad +; @details +; The LCD must be connected to a W65C22N Interface Chip: +; - IO.RA0-7 -> +; @requires KP_IO: Base Address of IO Chip +; @depends IO-W65C22N +;******************************************************************************** +.ifndef INCLUDE_KEYPAD +INCLUDE_KEYPAD = 1 +.include "system.h65" + +.scope kp +KP_IO = IO2 +; .import KP_IO +; .ifndef KP_IO +; .fatal "KP_IO is not defined: set it to the base address of the IO chip of the Keypad" +; .endif + +Import kp, init, read_irq, read +ImportZp kp,_DEBUG_VAL + +BUF_SIZE = 10 + +.endscope +.endif ; guard + diff --git a/system/keypad.s65 b/system/keypad.s65 index dec4e0f..0ef8676 100644 --- a/system/keypad.s65 +++ b/system/keypad.s65 @@ -1,57 +1,45 @@ -;******************************************************************************** -; @module keypad4x4 -; @type driver -; @device 4x4 Matrix Keypad -; @details -; The LCD must be connected to a W65C22N Interface Chip: -; - IO.RA0-7 -> -; @requires KP_IO: Base Address of IO Chip -; @depends IO-W65C22N -;******************************************************************************** +.include "keypad.h65" - -.ifndef INCLUDE_KEYPAD -INCLUDE_KEYPAD = 1 -.ifndef KP_IO - .fatal "KP_IO is not defined: set it to the base address of the IO chip of the Keypad" -.endif +Export kp, init, read_irq, read +ExportZp kp, _DEBUG_VAL .zeropage -_KP_COLUMN: .res 1 ; for storing stuff -_KP_DEBUG_VAL: .res 1 ; for storing the last char DEBUG +_COLUMN: .res 1 ; for storing stuff +_DEBUG_VAL: .res 1 ; for storing the last char DEBUG .bss ; reserve space or ringbuffer -KP_BUF_SIZE = 10 -RBUF_MEM_START: .res KP_BUF_SIZE -RBUF_MEM_END = RBUF_MEM_START + KP_BUF_SIZE - 1 +RBUF_MEM_START: .res kp::BUF_SIZE +RBUF_MEM_END = RBUF_MEM_START + kp::BUF_SIZE - 1 .define RBUF_NAME "keypad" -.include "buffer.s65" +.include "buffer.h65" .code -.proc kp_init +.proc init ; todo remove later and test lda #$ff - sta KP_IO+IO::DDRA - stz KP_IO+IO::RA + sta kp::KP_IO+IO::DDRA + stz kp::KP_IO+IO::RA ; INIT KEYPAD ; todo: use masks - lda #%11110000; KP_IO+IO::RA 0-3 output - sta KP_IO+IO::DDRA + lda #%11110000; kp::KP_IO+IO::RA 0-3 output + sta kp::KP_IO+IO::DDRA ; output 0, key press will pull input pin low - stz KP_IO+IO::RA - stz KP_IO+IO::ACR + stz kp::KP_IO+IO::RA + stz kp::KP_IO+IO::ACR ; lda #%00010000 ; set CA1 to interrupt on pos. edge ; todo: use masks lda #IO::PCR::CA1_IP_AE - sta KP_IO+IO::PCR + sta kp::KP_IO+IO::PCR jsr rb_keypad_init ; init keybuffer - lda #(IO::IRQ::IRQ | IO::IRQ::CA1) ; enable interrupt for CA1 on KP_IO - sta KP_IO+IO::IER + lda #(IO::IRQ::IRQ | IO::IRQ::CA1) ; enable interrupt for CA1 on kp::KP_IO + sta kp::KP_IO+IO::IER rts .endproc +read = rb_keypad_read + ;******************************************************************************** ; @function Read which key is pressed on the keypad ; @details @@ -59,7 +47,7 @@ RBUF_MEM_END = RBUF_MEM_START + KP_BUF_SIZE - 1 ; The value stored in the keybuffer is the offset which must be added to ; kp_VALUES to retrieve the key that was pressed ;******************************************************************************** -.proc kp_read_on_irq +.proc read_irq ; test each "row" and check which column is 1 ; TODO dont check every column if the value has been found lda #%11100000 @@ -74,31 +62,31 @@ RBUF_MEM_END = RBUF_MEM_START + KP_BUF_SIZE - 1 lda #%01110000 ldx #$0c jsr @kp_read_column - stz KP_IO+IO::RA - lda KP_IO+IO::RA ; clear interrupt flag again beceause it might be set again through the above tests + stz kp::KP_IO+IO::RA + lda kp::KP_IO+IO::RA ; clear interrupt flag again beceause it might be set again through the above tests rts @kp_read_column: - sta KP_IO+IO::RA - lda KP_IO+IO::RA - sta _KP_COLUMN ; store result in zeropage so that bbr can be used - bbr0 _KP_COLUMN,@kp_write ; row 1 + sta kp::KP_IO+IO::RA + lda kp::KP_IO+IO::RA + sta _COLUMN ; store result in zeropage so that bbr can be used + bbr0 _COLUMN,@kp_write ; row 1 inx - bbr1 _KP_COLUMN,@kp_write ; row 3 + bbr1 _COLUMN,@kp_write ; row 3 inx - bbr2 _KP_COLUMN,@kp_write ; row 2 + bbr2 _COLUMN,@kp_write ; row 2 inx - bbr3 _KP_COLUMN,@kp_write ; row 4 + bbr3 _COLUMN,@kp_write ; row 4 rts @kp_write: - lda _KP_VALUES,x + lda VALUES,x ; TODO use ringbuffer - sta _KP_DEBUG_VAL + sta _DEBUG_VAL jsr rb_keypad_write rts .endproc .rodata -_KP_VALUES: +VALUES: .byte "174*" .byte "2850" .byte "396#" @@ -108,4 +96,3 @@ _KP_VALUES: ; row 2 = PA2 ; row 3 = PA1 ; row 4 = PA3 -.endif diff --git a/system/lcd.h65 b/system/lcd.h65 new file mode 100644 index 0000000..0afe340 --- /dev/null +++ b/system/lcd.h65 @@ -0,0 +1,60 @@ +;******************************************************************************** +; @module LCD-W164B +; @type driver +; @device ELECTRONIC ASSEMBLY - W164B-NLW +; @details +; The LCD must be connected to a W65C22N Interface Chip: +; - IO.RB0-7 -> LCD.D0-7 data lines +; - IO.RA5 -> LCD.RS register select +; - IO.RA6 -> LCD.R/W read/write +; - 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 +INCLUDE_LCD = 1 + +.include "system/system.h65" + +.scope lcd +LCD_IO = IO1 +Import lcd,init,clear,print,print_char,_cmd + +;******************************************************************************** +; @macro 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 + +; PIN MASKS +E = %10000000 +RW = %01000000 +RS = %00100000 + +; 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_FUNCTION_SET = %00111000 ; 8-bit, 4 lines, 5x7 font +CMD_SET_ADDRESS = %10000000 ; or with the address +; LCD Constants +LINE1 = $00 +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 6343606..b6a63b5 100644 --- a/system/lcd.s65 +++ b/system/lcd.s65 @@ -1,233 +1,214 @@ -;******************************************************************************** -; @module LCD-W164B -; @type driver -; @device ELECTRONIC ASSEMBLY - W164B-NLW -; @details -; The LCD must be connected to a W65C22N Interface Chip: -; - IO.RB0-7 -> LCD.D0-7 data lines -; - IO.RA5 -> LCD.RS register select -; - IO.RA6 -> LCD.R/W read/write -; - IO.RA7 -> LCD.E enable -; -; @requires LCD_IO: Base Address of IO Chip -; @optparam LCD_MEM: Memory address for a runtime variable. Default = $300 -; @depends IO-W65C22N -;******************************************************************************** -.ifndef INCLUDE_LCD -INCLUDE_LCD = 1 +.include "system/lcd.h65" - .ifndef LCD_IO - .fatal "LCD_IO is not defined: set it to the base address of the IO chip of the LCD" - .endif - - .ifndef INCLUDE_IOW65C22 - .error "IO-W65C22 module is not included" - .endif - - .include "utility.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 - .ifndef LCD_MEM -LCD_MEM = $300 - .endif -LCD_CHARCOUNT = LCD_MEM +.bss +charcount: .res 1 -; PIN MASKS -LCD_E = %10000000 -LCD_RW = %01000000 -LCD_RS = %00100000 - ; .local LCD_E,LCD_RW,LCD_RS - -; LCD Instructions (see datasheet for more) -LCD_CMD_CLEAR = %00000001 ; clear display -LCD_CMD_ENTRY_MODE = %00000110 ; auto-shift cursor -LCD_CMD_DISPLAY_ON = %00001111 ; everything on, with blinking cursor -LCD_CMD_FUNCTION_SET = %00111000 ; 8-bit, 4 lines, 5x7 font -LCD_CMD_SET_ADDRESS = %10000000 ; or with the address -; LCD Constants -LCD_LINE1 = $00 -LCD_LINE2 = $40 -LCD_LINE3 = $10 -LCD_LINE4 = $50 - -LCD_CLEAR = %00000000 - - -;******************************************************************************** -; @function Initialize the lcd module -; @details call before doing anything else -;******************************************************************************** -.proc lcd_init +.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_IO+IO::DDRB + sta lcd::LCD_IO+IO::DDRB - ; UT_update_with_mask LCD_IO + IO::DDRA, (LCD_RS | LCD_RW | LCD_E), (LCD_RS | LCD_RW | LCD_E) - lda #(LCD_RS | LCD_RW | LCD_E) ; RA 5-7 output - sta LCD_IO+IO::DDRA + ; 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 _lcd_cmd - lda #LCD_CMD_DISPLAY_ON - jsr _lcd_cmd - lda #LCD_CMD_CLEAR - jsr _lcd_cmd - lda #LCD_CMD_ENTRY_MODE - jsr _lcd_cmd + 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 LCD_CHARCOUNT + stz charcount rts .endproc -;******************************************************************************** -; PRINTING TO LCD -;******************************************************************************** -;******************************************************************************** -; @function Clear the display -; @see lcd_print -;******************************************************************************** -.proc lcd_clear - stz LCD_CHARCOUNT - lda #LCD_CLEAR - jsr _lcd_cmd - lda #(LCD_CMD_SET_ADDRESS | LCD_LINE1) - jsr _lcd_cmd + +;;******************************************************************************** +;; 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 -;******************************************************************************** -.proc lcd_print +;;******************************************************************************** +;; @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 lcd_char + jsr print_char iny bra @lcd_print_loop @lcd_print_end: rts .endproc -;******************************************************************************** -; @macro Print a null-terminated string -; @param message: Address of the message -;******************************************************************************** -.macro Print message - jsr lcd_clear - lda #.LOBYTE(message) - sta ARG0 - lda #.HIBYTE(message) - sta ARG1 - jsr lcd_print -.endmacro - -;******************************************************************************** -; @macro Print a single character -; @param A: Character to print -;******************************************************************************** -.proc lcd_char +;;******************************************************************************** +;; @macro Print a single character +;; @param A: Character to print +;;******************************************************************************** +.proc print_char pha pha ; TODO use UT_update_with_mask? - jsr _lcd_wait_nbusy + jsr _wait_nbusy pla - sta LCD_IO + IO::RB - lda #LCD_RS - sta LCD_IO + IO::RA - lda #(LCD_RS | LCD_E) - sta LCD_IO + IO::RA - lda #LCD_RS - sta LCD_IO + IO::RA - inc LCD_CHARCOUNT - jsr _lcd_set_address + 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 -;******************************************************************************** +;;******************************************************************************** +;; Internal LCD Commands +;;******************************************************************************** ; read busy flag -.proc _lcd_wait_nbusy - stz LCD_IO + IO::DDRB ; set IO1-LCD_IO + IO::RB to input +.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_IO + IO::RA - lda #(LCD_RW | LCD_E) - sta LCD_IO + IO::RA + lda #lcd::RW + sta lcd::LCD_IO + IO::RA + lda #(lcd::RW | lcd::E) + sta lcd::LCD_IO + IO::RA - lda LCD_IO + IO::RB + 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_IO + IO::RA - lda #%11111111 ; set IO1-LCD_IO + IO::RB to output - sta LCD_IO + IO::DDRB + sta lcd::LCD_IO + IO::RA + lda #%11111111 ; set IO1-IO + IO::RB to output + sta lcd::LCD_IO + IO::DDRB rts .endproc -.proc _lcd_cmd ; send cmd in acc +;;******************************************************************************** +;; @function Send a command to the lcd +;; @param A: command +;; @modifies A +;;******************************************************************************** +.proc _cmd ; send cmd in acc pha - jsr _lcd_wait_nbusy + jsr _wait_nbusy pla ; TODO use UT_update_with_mask? - sta LCD_IO + IO::RB - lda #LCD_CLEAR - sta LCD_IO + IO::RA - lda #LCD_E - sta LCD_IO + IO::RA - lda #LCD_CLEAR - sta LCD_IO + IO::RA + 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 -;******************************************************************************** -; Set the LCD DD-RAM Address so that text linebreaks after 16 chars -;******************************************************************************** -.proc _lcd_set_address +;;******************************************************************************** +;; @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 LCD_CHARCOUNT - beq @lcd_line1 + lda charcount + beq @line1 and #%10001111 ; ($10 | $20 | $30 | $40) = %01110000 - bne @lcd_set_address_done + bne @rts ; checks necessary - lda LCD_CHARCOUNT - beq @lcd_line1 + lda charcount + beq @line1 cmp #$10 - beq @lcd_line2 + beq @line2 cmp #$20 - beq @lcd_line3 + beq @line3 cmp #$30 - beq @lcd_line4 - cmp #$40 ; set to line1 when full ; set to line1 when full - beq @lcd_line1 -@lcd_set_address_done: + beq @line4 + cmp #$40 ; set to line1 when full + bge @line1 +@rts: rts -@lcd_line1: - stz LCD_CHARCOUNT - lda #(LCD_CMD_SET_ADDRESS | LCD_LINE1) - jsr _lcd_cmd +@line1: + stz charcount + lda #(lcd::CMD_SET_ADDRESS | lcd::LINE1) + jsr _cmd rts -@lcd_line2: - lda #(LCD_CMD_SET_ADDRESS | LCD_LINE2) - jsr _lcd_cmd +@line2: + lda #(lcd::CMD_SET_ADDRESS | lcd::LINE2) + jsr _cmd rts -@lcd_line3: - lda #(LCD_CMD_SET_ADDRESS | LCD_LINE3) - jsr _lcd_cmd +@line3: + lda #(lcd::CMD_SET_ADDRESS | lcd::LINE3) + jsr _cmd rts -@lcd_line4: - lda #(LCD_CMD_SET_ADDRESS | LCD_LINE4) - jsr _lcd_cmd +@line4: + lda #(lcd::CMD_SET_ADDRESS | lcd::LINE4) + jsr _cmd rts .endproc -.endif + diff --git a/system/ram.s65 b/system/ram.s65 deleted file mode 100644 index 39f9a19..0000000 --- a/system/ram.s65 +++ /dev/null @@ -1,31 +0,0 @@ - - -.segment "ZP" - .org 0 - .byte NULL - .org $10 - .byte ARG0 - .byte ARG1 - .byte ARG2 - .byte ARG3 - .byte ARG4 - .byte ARG5 - .byte ARG6 - .byte ARG7 - .byte ARG8 - .byte ARG9 - .byte ARG10 - .byte ARG11 - .byte ARG12 - .byte ARG13 - .byte ARG14 - .byte ARG15 - - - -.segment "RAM" - -.segment "SPI" - .byte SPI_BYTES_WRITTEN - .byte SPI_PAGES_WRITTEN - .byte diff --git a/system/spi.h65 b/system/spi.h65 new file mode 100644 index 0000000..62f8544 --- /dev/null +++ b/system/spi.h65 @@ -0,0 +1,18 @@ +;******************************************************************************** +; @module SPI +; @type driver +; @details +; @depends IO-W65C22N +;******************************************************************************** +.ifndef INCLUDE_SPI +INCLUDE_SPI = 1 + +.include "system/system.h65" + +.scope spi_p +SPI_IO = IO2 +.import CODE_START:absolute +Import spi_p, begin, end, read, pages_written, bytes_written + +.endscope +.endif ; guard diff --git a/system/spi.s65 b/system/spi.s65 index 00b57c5..18cc7ef 100644 --- a/system/spi.s65 +++ b/system/spi.s65 @@ -1,156 +1,17 @@ -;******************************************************************************** -; @module SPI -; @type driver -; @details -; @depends IO-W65C22N -;******************************************************************************** - -.include "system/system.s65" -.include "programs/print_slow.s65" - -.ifndef INCLUDE_SPI -INCLUDE_SPI = 1 -.scope spi_p +.include "spi.h65" +Export spi_p, begin, end, read, pages_written, bytes_written .zeropage -code_page: .res 2 ; SPI_CODE_START + pages_written * 256 +code_page: .res 2 ; CODE_START + pages_written * 256 .bss bytes_written: .res 1 pages_written: .res 1 -.include "util/math.s65" +SPI_IO := spi_p::SPI_IO +CODE_START := spi_p::CODE_START + ; spi-transferred code will be placed here -.segment "SPI" -SPI_CODE_START: - lda '$' - jsr lcd_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 -@spiloop: - lda IO1 + IO::RA - lda IO2 + IO::RA - nop - bra @spiloop - jmp home - -; TODO allocate zp memory -fmt_idx = $30 -out_idx = $31 -;******************************************************************************** -; @function Format a string -; @details -; If there is no value to be read, the Pz will be set -; Formats: -; - u: unsigned decimal integer (1 byte) -; - U: unsigned decimal integer (2 bytes) -; @param ARG0-1: Format string address -; @param ARG2-3: Output string address -; @param ARG4+: Additional parameters -; @returns -; @modifies: A, Y -;******************************************************************************** -.proc strf - stz out_idx - stz fmt_idx - ldy #0 ; position in string - 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 - beq @null - ; formats - cmp #'x' - beq @format_hex1 - bra @normal_char -@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: - 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 X,Y,A -;******************************************************************************** -.proc int8_to_hex_str - pha - and #%00001111 - tay - ldx HEX_CHARS,y - pla - div A,16 - and #%00001111 - tay - lda HEX_CHARS,y - rts -.endproc - - - - -HEX_CHARS: .byte "0123456789ABCDEF" - -TEST_FMT: .asciiz "%x -> %x -> %x:)" -TEST_OUT: .asciiz "TESTOUT" - ; SPI_P = as peripheral .code .struct SPI_P_Pins @@ -178,9 +39,9 @@ TEST_OUT: .asciiz "TESTOUT" stz pages_written stz bytes_written ; store address in zp - lda #SPI_CODE_START + lda #>CODE_START sta code_page + 1 ; todo USE MASKS ; set Shift register to shift in under external clock on CB1 @@ -196,6 +57,7 @@ TEST_OUT: .asciiz "TESTOUT" rts .endproc + ;******************************************************************************** ; @function Stop listening for SPI transfers ; @details @@ -207,7 +69,6 @@ TEST_OUT: .asciiz "TESTOUT" sta SPI_IO + IO::IER rts .endproc - ;******************************************************************************** @@ -218,7 +79,7 @@ TEST_OUT: .asciiz "TESTOUT" .proc read ldx bytes_written lda SPI_IO + IO::SR - sta SPI_CODE_START,x + sta CODE_START,x inc bytes_written beq @new_page rts @@ -249,9 +110,3 @@ TEST_OUT: .asciiz "TESTOUT" ;******************************************************************************** .proc send_data .endproc - -.endscope - - - -.endif diff --git a/system/system.h65 b/system/system.h65 new file mode 100644 index 0000000..5ff42d7 --- /dev/null +++ b/system/system.h65 @@ -0,0 +1,55 @@ +;******************************************************************************** +; @module system +; @type header +; @details +; Variable definitions for the current hardware setup +;******************************************************************************** + +.ifndef INCLUDE_SYSTEM +INCLUDE_SYSTEM = 1 +; reserved RAM addresses +; 00-0f - free +; 10-1f - arguments / return values +; 20-ff - free +; 0100 - 01FF Stack +; 0200,0201 keybuffer write/read pointer +; 0202-02ff keybuffer +; 0300 lcd character counter +; 0400, 0401, 0402 dht status, dht bit, dht_bit_rot +; 0403 value offset +; 0405-04a0 rh high/low, temp high/low, checksum + +.include "io_W65C22.h65" +.include "utility.h65" + +; ARGUMENTS +; a,x,y can also be used +ARG0 = $10 +ARG1 = $11 +ARG2 = $12 +ARG3 = $13 +ARG4 = $14 +ARG5 = $15 +ARG6 = $16 +ARG7 = $17 +ARG9 = $19 +ARG10 = $1a +ARG11 = $1b +ARG12 = $1c +ARG13 = $1d +ARG14 = $1e +ARG15 = $1f + + +; RETURN VALUE +; in a + +.segment "VIA1" +; IO1: .res 16 +IO1 = $6000 + +.segment "VIA2" +; IO2: .res 16 +IO2 = $7000 + +.endif ; include guard diff --git a/system/system.s65 b/system/system.s65 index 2d6f3fd..4d8db89 100644 --- a/system/system.s65 +++ b/system/system.s65 @@ -1,82 +1,3 @@ -;******************************************************************************** -; @module system -; @type header -; @details -; Variable definitions for the current hardware setup -;******************************************************************************** - -.ifndef INCLUDE_SYSTEM -INCLUDE_SYSTEM = 1 -; reserved RAM addresses -; 00-0f - free -; 10-1f - arguments / return values -; 20-ff - free -; 0100 - 01FF Stack -; 0200,0201 keybuffer write/read pointer -; 0202-02ff keybuffer -; 0300 lcd character counter -; 0400, 0401, 0402 dht status, dht bit, dht_bit_rot -; 0403 value offset -; 0405-04a0 rh high/low, temp high/low, checksum - -.include "io_W65C22.h65" -.include "utility.h65" - -; ARGUMENTS -; a,x,y can also be used -.segment "ZEROPAGE" -ARG0: .res 1 -ARG1: .res 1 -ARG2: .res 1 -ARG3: .res 1 -ARG4: .res 1 -ARG5: .res 1 -ARG6: .res 1 -ARG7: .res 1 -ARG9: .res 1 -ARG10: .res 1 -ARG11: .res 1 -ARG12: .res 1 -ARG13: .res 1 -ARG14: .res 1 -ARG15: .res 1 - - -; RETURN VALUE -; in a - -.segment "VIA1" -; IO1: .res 16 -IO1 = $6000 - -.segment "VIA2" -; IO2: .res 16 -IO2 = $7000 - -; struct method - ; .org $6000 -; VIA1: .tag VIA_Pins - ; .org $7000 -; VIA2: .tag VIA_Pins - -; ; IO-1 -; PB1 = $6000 -; PA1 = $6001 -; DDRB1 = $6002 -; DDRA1 = $6003 -; T1L1 = $6004 -; T1H1 = $6005 -; ; IO-2 -; PB2 = $7000 -; PA2 = $7001 -; DDRB2 = $7002 -; DDRA2 = $7003 -; T1L2 = $7004 -; T1H2 = $7005 -; ACR2 = $700b -; PCR2 = $700c -; IFR2 = $700d -; IER2 = $700e - - -.endif ; include guard +.zeropage +.org $10 +.res 16 diff --git a/test.s65 b/test.s65 index ce4b8f1..da4faae 100644 --- a/test.s65 +++ b/test.s65 @@ -1,55 +1,55 @@ -.include "system/system.h65" -.segment "CODE" +;.include "system/system.h65" +;.segment "CODE" -;******************************************************************************** -; Interrupts -;******************************************************************************** -nmi: - rti -irq: - .repeat 20 - .endrepeat - rti +;;******************************************************************************** +;; Interrupts +;;******************************************************************************** +;nmi: +; rti +;irq: +; .repeat 20 +; .endrepeat +; rti -;******************************************************************************** -; Reset sequence -;******************************************************************************** -reset: - sei - ; setup io2 bank a 1-3 - lda #%11111111 - sta IO1 + IO_DDRA - sta IO1 + IO_DDRB +;;******************************************************************************** +;; Reset sequence +;;******************************************************************************** +;reset: +; sei +; ; setup io2 bank a 1-3 +; lda #%11111111 +; sta IO1 + IO_DDRA +; sta IO1 + IO_DDRB -@loop: - lda #%00000000 - sta IO1 + IO_RA - .repeat 3 - nop - .endrepeat - lda #%11111111 - sta IO1 + IO_RA - .repeat 15 - nop - .endrepeat +;@loop: +; lda #%00000000 +; sta IO1 + IO_RA +; .repeat 3 +; nop +; .endrepeat +; lda #%11111111 +; sta IO1 + IO_RA +; .repeat 15 +; nop +; .endrepeat - lda #%00000000 - sta IO1 + IO_RB - .repeat 5 - nop - .endrepeat - lda #%11111111 - sta IO1 + IO_RB - .repeat 10 - nop - .endrepeat - bra @loop +; lda #%00000000 +; sta IO1 + IO_RB +; .repeat 5 +; nop +; .endrepeat +; lda #%11111111 +; sta IO1 + IO_RB +; .repeat 10 +; nop +; .endrepeat +; bra @loop -;******************************************************************************** -; reset vector -;******************************************************************************** -.segment "RESET_VECTOR" - .word nmi - .word reset - .word irq +;;******************************************************************************** +;; reset vector +;;******************************************************************************** +;.segment "RESET_VECTOR" +; .word nmi +; .word reset +; .word irq diff --git a/util/math.h65 b/util/math.h65 new file mode 100644 index 0000000..03b26d1 --- /dev/null +++ b/util/math.h65 @@ -0,0 +1,107 @@ +;******************************************************************************** +; @module math +; @type utility +; @details +; Math library +;******************************************************************************** +.ifndef INCLUDE_MATH +INCLUDE_MATH = 1 + +.scope math + +;******************************************************************************** +; @macro Divide a num (or A) by a factor +; @param num: Memory or A +; @param divider: must be power of 2 +;******************************************************************************** +.macro div num,divider +.if divider = 2 + lsr num +.elseif divider = 4 + lsr num + lsr num +.elseif divider = 8 + lsr num + lsr num + lsr num +.elseif divider = 16 + .repeat 4 + lsr num + .endrepeat +.elseif divider = 32 + .repeat 5 + lsr num + .endrepeat +.elseif divider = 64 + .repeat 6 + lsr num + .endrepeat +.elseif divider = 128 + .repeat 7 + lsr num + .endrepeat +.else + .error "div macro: divider % 2 != 0" +.endif +.endmacro + +; .macro Amult1 factor +; phx +; ldx factor +; AmultX +; plx +; .endmacro + +; https://www.llx.com/Neil/a2/mult.html +; .macro mult num1,num2,result +; lda #0 +; ldx #8 +; L1: +; lsr num2 +; bcc L2 +; clc +; adc num1 +; L2: +; ror +; ror result +; dex +; bne L1 +; sta result+1 +; .endmacro + +; 00110101 +; 10010011 +; -------^ +; =00110101 +; 00110101 +; 01001001 +; -------^ +; =00110101 +; 00110101 +; 00100100 +; -------^ +; =00000000 +; 00110101 +; 00010010 +; -------^ +; =00000000 +; 00110101 +; 00001001 +; -------^ +; 00110101 +; 00110101 +; 00000100 +; -------^ +; =00000000 +; 00110101 +; 00000010 +; -------^ +; =00000000 +; 00110101 +; 00000001 +; 00110101 + + +.endscope +.endif ; guard + diff --git a/util/math.s65 b/util/math.s65 index 3a7d2be..bd22ffc 100644 --- a/util/math.s65 +++ b/util/math.s65 @@ -1,106 +1 @@ -;******************************************************************************** -; @module math -; @type utility -; @details -; Math library -;******************************************************************************** -.ifndef INCLUDE_MATH -INCLUDE_MATH = 1 - -.scope math - -;******************************************************************************** -; @macro Divide a num (or A) by a factor -; @param num: Memory or A -; @param divider: must be power of 2 -;******************************************************************************** -.macro div num,divider -.if divider = 2 - lsr num -.elseif divider = 4 - lsr num - lsr num -.elseif divider = 8 - lsr num - lsr num - lsr num -.elseif divider = 16 - .repeat 4 - lsr num - .endrepeat -.elseif divider = 32 - .repeat 5 - lsr num - .endrepeat -.elseif divider = 64 - .repeat 6 - lsr num - .endrepeat -.elseif divider = 128 - .repeat 7 - lsr num - .endrepeat -.else - .error "div macro: divider % 2 != 0" -.endif -.endmacro - -; .macro Amult1 factor -; phx -; ldx factor -; AmultX -; plx -; .endmacro - -; https://www.llx.com/Neil/a2/mult.html -; .macro mult num1,num2,result -; lda #0 -; ldx #8 -; L1: -; lsr num2 -; bcc L2 -; clc -; adc num1 -; L2: -; ror -; ror result -; dex -; bne L1 -; sta result+1 -; .endmacro - -; 00110101 -; 10010011 -; -------^ -; =00110101 -; 00110101 -; 01001001 -; -------^ -; =00110101 -; 00110101 -; 00100100 -; -------^ -; =00000000 -; 00110101 -; 00010010 -; -------^ -; =00000000 -; 00110101 -; 00001001 -; -------^ -; 00110101 -; 00110101 -; 00000100 -; -------^ -; =00000000 -; 00110101 -; 00000010 -; -------^ -; =00000000 -; 00110101 -; 00000001 -; 00110101 - - -.endscope -.endif ; guard +.code diff --git a/util/string.h65 b/util/string.h65 new file mode 100644 index 0000000..82bf9aa --- /dev/null +++ b/util/string.h65 @@ -0,0 +1,66 @@ +;******************************************************************************** +; @module string +; @type utility +; @details +; String utility +;******************************************************************************** +.ifndef INCLUDE_STRING +INCLUDE_STRING = 1 + +.include "system/system.h65" + + +.scope str +Import str, strf, int8_to_hex_str + + +.macro _StrfStoreArg arg +.if (.not .blank(arg)) + .if .match(arg, x) + stx ARG4 + @N_ARGS + .elseif .match(arg, y) + sty ARG4 + @N_ARGS + .else + lda arg + sta ARG4 + @N_ARGS + .endif + @N_ARGS .set (@N_ARGS + 1) +.endif +.endmacro + +;******************************************************************************** +; @function Macro for passing arguments to strf +; @param fmt: Format string address +; @param out: Output string address +; @param x0-x9: Additional parameters +; @warning Addresses as additional paramteres must be passed like this `#addr` +; @modifies: A, X, Y +; @see strf +;******************************************************************************** +.macro Strf fmt,out,x0,x1,x2,x3,x4,x5,x6,x7,x8,x9 + @N_ARGS .set 0 ; @ so that it doesnt break cheap labels + lda #fmt + sta ARG1 + lda #out + sta ARG3 + _StrfStoreArg x0 + _StrfStoreArg x1 + _StrfStoreArg x2 + _StrfStoreArg x3 + _StrfStoreArg x4 + _StrfStoreArg x5 + _StrfStoreArg x6 + _StrfStoreArg x7 + jsr str::strf + .out .sprintf("info: Strf: called with %d arguments", @N_ARGS) +.endmacro + +; TODO allocate zp memory +fmt_idx = $30 +out_idx = $31 +.endscope +.endif ; guard diff --git a/util/string.s65 b/util/string.s65 index 9b6cb28..34bc86c 100644 --- a/util/string.s65 +++ b/util/string.s65 @@ -1,63 +1,8 @@ -;******************************************************************************** -; @module string -; @type utility -; @details -; String utility -;******************************************************************************** -.ifndef INCLUDE_STRING -INCLUDE_STRING = 1 - -.scope str +.include "string.h65" +.include "math.h65" +Export str, strf, int8_to_hex_str .code -.macro _StrfStoreArg arg -.if (.not .blank(arg)) - .if .match(arg, x) - stx ARG4 + @N_ARGS - .elseif .match(arg, y) - sty ARG4 + @N_ARGS - .else - lda arg - sta ARG4 + @N_ARGS - .endif - @N_ARGS .set (@N_ARGS + 1) -.endif -.endmacro - -;******************************************************************************** -; @function Macro for passing arguments to strf -; @param fmt: Format string address -; @param out: Output string address -; @param x0-x9: Additional parameters -; @warning Addresses as additional paramteres must be passed like this `#addr` -; @modifies: A, X, Y -; @see strf -;******************************************************************************** -.macro Strf fmt,out,x0,x1,x2,x3,x4,x5,x6,x7,x8,x9 - @N_ARGS .set 0 ; @ so that it doesnt break cheap labels - lda #fmt - sta ARG1 - lda #out - sta ARG3 - _StrfStoreArg x0 - _StrfStoreArg x1 - _StrfStoreArg x2 - _StrfStoreArg x3 - _StrfStoreArg x4 - _StrfStoreArg x5 - _StrfStoreArg x6 - _StrfStoreArg x7 - jsr strf - .out .sprintf("info: Strf: called with %d arguments", @N_ARGS) -.endmacro - -; TODO allocate zp memory -fmt_idx = $30 -out_idx = $31 ;******************************************************************************** ; @function Format a string ; @details @@ -73,6 +18,8 @@ out_idx = $31 ; @returns ; @modifies: A, X, Y ;******************************************************************************** +out_idx := str::out_idx +fmt_idx := str::fmt_idx .proc strf stz out_idx stz fmt_idx @@ -156,8 +103,3 @@ out_idx = $31 .rodata HEX_CHARS_UPPER: .byte "0123456789ABCDEF" HEX_CHARS_LOWER: .byte "0123456789abcdef" - -.export strf - -.endscope -.endif ; guard diff --git a/utility.h65 b/utility.h65 index 6a65530..377e6c9 100644 --- a/utility.h65 +++ b/utility.h65 @@ -2,6 +2,7 @@ INCLUDE_UTILITY = 1 .macpack longbranch ; jeq, jge... +.macpack generic ; bge, add, sub ;******************************************************************************** ; @macro Update a byte in memory using a mask @@ -31,4 +32,59 @@ INCLUDE_UTILITY = 1 ; _n_genlabel .set _n_genlabel + 1 ;.endmacro +;;******************************************************************************** +;; @macro Export labels with a prefix +;; @details +;; Equivalent to: +;; .export prefix_l1:=l1 +;; .export prefix_l2:=l2 +;; ... +;;******************************************************************************** +.macro Export prefix,l1,l2,l3,l4,l5,l6,l7,l8 + .if .blank(l1) + .exitmacro + .endif + ; .out .sprintf("Exporting %s as %s_%s", .string(l1), .string(prefix), .string(l1)) + .export .ident(.sprintf("%s_%s", .string(prefix), .string(l1))):=l1 + Export prefix,l2,l3,l4,l5,l6,l7,l8 +.endmacro +.macro ExportZp prefix,l1,l2,l3,l4,l5,l6,l7,l8 + .if .blank(l1) + .exitmacro + .endif + ; .out .sprintf("Exporting (zp) %s as %s_%s", .string(l1), .string(prefix), .string(l1)) + .exportzp .ident(.sprintf("%s_%s", .string(prefix), .string(l1))):=l1 + ExportZp prefix,l2,l3,l4,l5,l6,l7,l8 +.endmacro + +;;******************************************************************************** +;; @macro Import labels and remove prefix +;; @details +;; Equivalent to: +;; .import prefix_l1 +;; .import prefix_l2 +;; ... +;; l1 = prefix_l1 +;; l2 = prefix_l2 +;; ... +;; Use in a scope to have the lX available as scope::lX +;;******************************************************************************** +.macro Import prefix,l1,l2,l3,l4,l5,l6,l7,l8 + .if .blank(l1) + .exitmacro + .endif + ; .out .sprintf("Importing %s_%s as %s", .string(prefix), .string(l1), .string(l1)) + .import .ident(.sprintf("%s_%s", .string(prefix), .string(l1))):absolute + .ident(.sprintf("%s", .string(l1))) = .ident(.sprintf("%s_%s", .string(prefix), .string(l1))) + Import prefix,l2,l3,l4,l5,l6,l7,l8 +.endmacro +.macro ImportZp prefix,l1,l2,l3,l4,l5,l6,l7,l8 + .if .blank(l1) + .exitmacro + .endif + ; .out .sprintf("Importing (zp) %s_%s as %s", .string(prefix), .string(l1), .string(l1)) + .importzp .ident(.sprintf("%s_%s", .string(prefix), .string(l1))):zeropage + .ident(.sprintf("%s", .string(l1))) = .ident(.sprintf("%s_%s", .string(prefix), .string(l1))) + ImportZp prefix,l2,l3,l4,l5,l6,l7,l8 +.endmacro .endif