refactor with source+header

This commit is contained in:
matthias@arch 2023-12-08 22:56:35 +01:00
parent 321759f70d
commit 9a1324a29a
28 changed files with 1032 additions and 913 deletions

5
.gitignore vendored
View File

@ -1,4 +1,5 @@
**.bin **.bin
**.o **.o
.build **.d
.dependencies *build*
labels

View File

@ -1,41 +1,54 @@
ROM = ../rom.bin ROM = ../rom.bin
BUILD_DIR = .build OBJ_DIR = build
SRC_DIRS = programs system SRC_DIRS = . programs system util
# VASM = ~/6502/vasm6502 # VASM = ~/6502/vasm6502
ASM = ca65 ASM = ca65
ASMFLAGS = -g --cpu 65C02 $(foreach srcdir, $(SRC_DIRS), -I $(srcdir)) ASMFLAGS = -g --cpu 65C02 $(foreach srcdir, $(SRC_DIRS), -I $(srcdir))
ASMDEPFLAGS = --create-dep .dependencies
LD = ld65 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)) # DEPENDS = $(shell $(VASM) -depend=make $(MAIN))
-include .dependencies -include $(DEP)
$(BUILD_DIR): .PHONY: default test clean print
mkdir $@
.PHONY: default test clean
.DEFAULT_GOAL = default .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 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 $@ $(LD) $(LDFLAGS) $< -o $@
../test.bin: $(BUILD_DIR)/test.o $(OBJ_DIR)/%.o: %.s65 | $(OBJ_DIRS)
# $(VASM) -dotdir -opt-branch -wdc02 -chklabels test.asm6502 @printf $(FMT_ASM) "$@" "$<"
$(LD) $(LDFLAGS) $(BUILD_DIR)/test.o -o ../test.bin $(ASM) $(ASMFLAGS) --create-dep $(patsubst %.o,%.d,$@) $< -o $@
$(BUILD_DIR)/%.o: %.s65 | $(BUILD_DIR)
$(ASM) $(ASMFLAGS) $(ASMDEPFLAGS) $< -o $@
clean: clean:
rm -r $(BUILD_DIR) rm -r $(OBJ_DIR)
rm $(ROM) rm $(ROM)

View File

@ -1,10 +1,11 @@
MEMORY { 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 = $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; SPI: start = $5000, size = $1000, type = rw, file = "spi.bin", fill = no;
VIA1: start = $6000, size = $600f, type = rw, file = "", fill = yes; VIA1: start = $6000, size = $000f, type = rw, file = "", fill = yes;
VIA2: start = $7000, size = $700f, 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; ROM: start = $8000, size = $8000, type = ro, file = %O, fill = yes;
} }
SEGMENTS { SEGMENTS {

View File

@ -1,4 +1,8 @@
.include "system/system.s65" .include "system/system.h65"
.export home
.import printer:absolute
.import spi_menu:absolute
.code .code
.macro DEBUG_LED_OFF nr .macro DEBUG_LED_OFF nr
@ -30,18 +34,17 @@
;******************************************************************************** ;********************************************************************************
; LCD ; LCD
; .include "utility.asm6502" ; .include "utility.asm6502"
LCD_IO = IO1 ; LCD_IO = IO1
.include "system/lcd.s65" .include "system/lcd.h65"
; Keypad Reading ; Keypad Reading
KP_IO = IO2 ; KP_IO = IO2
.include "system/keypad.s65" .include "system/keypad.h65"
; SPI ; SPI
SPI_IO = IO2 .include "system/spi.h65"
.include "system/spi.s65"
; Printer ; Printer
.include "programs/printer.s65" ; .include "programs/printer.s65"
.include "programs/print_slow.s65" .include "programs/print_slow.s65"
.include "programs/spi-menu.s65" ; .include "programs/spi-menu.s65"
; Digital Humidity and Temerature Sensor ; Digital Humidity and Temerature Sensor
; .include "dht.s65" ; .include "dht.s65"
@ -54,7 +57,7 @@ IRQ_VAR: .res 1
.code .code
nmi: nmi:
lda #'%' lda #'%'
jsr lcd_char jsr lcd::print_char
rti rti
irq: irq:
; read IRFs, while bit 7 ist set handle interrupts ; read IRFs, while bit 7 ist set handle interrupts
@ -69,7 +72,7 @@ irq:
bbs2 IRQ_VAR,@irq_spi_p ; check SR bbs2 IRQ_VAR,@irq_spi_p ; check SR
bbs1 IRQ_VAR,@irq_keypad ; check CA1 bbs1 IRQ_VAR,@irq_keypad ; check CA1
; this should never be reached ; this should never be reached
jsr lcd_clear jsr lcd::clear
Print str_irq_unknown Print str_irq_unknown
; force reset interrupt flags ; force reset interrupt flags
lda #$ff lda #$ff
@ -77,7 +80,7 @@ irq:
sta IO2 + IO::IFR sta IO2 + IO::IFR
bra @irq_return bra @irq_return
@irq_keypad: @irq_keypad:
jsr kp_read_on_irq jsr kp::read_irq
bra @irq_return bra @irq_return
@irq_spi_p: @irq_spi_p:
jsr spi_p::read jsr spi_p::read
@ -92,7 +95,7 @@ irq:
; Reset sequence ; Reset sequence
;******************************************************************************** ;********************************************************************************
reset: reset:
jsr lcd_init jsr lcd::init
; TODO debug stuff ; TODO debug stuff
stz IO2 + IO::DDRB stz IO2 + IO::DDRB
@ -102,7 +105,7 @@ reset:
DEBUG_LED_OFF 1 DEBUG_LED_OFF 1
jsr kp_init jsr kp::init
; ; INIT DHT ; ; INIT DHT
@ -124,17 +127,17 @@ reset:
Print message_menu Print message_menu
; jsr rb_keypad_read ; jsr rb_keypad_read
@loop: @loop:
lda _KP_DEBUG_VAL lda kp::_DEBUG_VAL
beq @loop beq @loop
; TODO debug ; TODO debug
sta 0 sta 0
stz _KP_DEBUG_VAL stz kp::_DEBUG_VAL
lda 0 lda 0
; beq home ; beq home
cmp #'A' cmp #'A'
jeq printer jeq printer
cmp #'B' cmp #'B'
jeq spi_menu::spi_menu jeq spi_menu
cmp #'C' cmp #'C'
jeq print_1 jeq print_1
cmp #'D' cmp #'D'
@ -166,23 +169,23 @@ reset:
DEBUG_LED_ON 1 DEBUG_LED_ON 1
jmp @loop jmp @loop
@print_rb: @print_rb:
jsr lcd_clear jsr lcd::clear
Print str_io2 Print str_io2
lda IO2 + IO::RB lda IO2 + IO::RB
jsr lcd_char jsr lcd::print_char
lda #''' lda #'''
jsr lcd_char jsr lcd::print_char
jmp @loop jmp @loop
.endproc .endproc
print_1: print_1:
jsr lcd_clear jsr lcd::clear
PrintSlow message_1,10 PrintSlow message_1,10
jmp home jmp home
print_2: print_2:
jsr lcd_clear jsr lcd::clear
PrintSlow message_2,10 PrintSlow message_2,10
jmp home jmp home

View File

@ -1,155 +1,155 @@
;******************************************************************************** ;;********************************************************************************
; @module SPI ;; @module SPI
; @type driver ;; @type driver
; @details ;; @details
; @depends IO-W65C22N ;; @depends IO-W65C22N
;******************************************************************************** ;;********************************************************************************
;TODO EVERYTHING ;;TODO EVERYTHING
DHT_REQUEST_L = $00 ;DHT_REQUEST_L = $00
DHT_REQUEST_H = %01010000 ; = 20480 PHI2 pulses = 20,5 ms at 1 MHz ;DHT_REQUEST_H = %01010000 ; = 20480 PHI2 pulses = 20,5 ms at 1 MHz
DHT_RECV_H = %10011100 ;DHT_RECV_H = %10011100
DHT_RECV_L = %01000000 ; = 40000 PHI2 = 40ms ;DHT_RECV_L = %01000000 ; = 40000 PHI2 = 40ms
; Status Variables, Used to determine what is sent by temp module ;; Status Variables, Used to determine what is sent by temp module
DHT_STATUS = $400 ;DHT_STATUS = $400
DHT_NONE = 0 ;DHT_NONE = 0
DHT_WAIT_REQ = 1 ;DHT_WAIT_REQ = 1
DHT_WAIT_RESP = 2 ;DHT_WAIT_RESP = 2
DHT_RECV = 3 ;DHT_RECV = 3
DHT_DONE = 4 ;DHT_DONE = 4
DHT_BIT = $401 ;DHT_BIT = $401
DHT_BIT_ROT = $402 ;DHT_BIT_ROT = $402
DHT_VALUES = $405 ; ;DHT_VALUES = $405 ;
DHT_OFFSET = $403 ;DHT_OFFSET = $403
DHT_OFF_RH_HIGH = 0 ; offsets to DHT_VALUES ;DHT_OFF_RH_HIGH = 0 ; offsets to DHT_VALUES
DHT_OFF_RH_LOW = 1 ;DHT_OFF_RH_LOW = 1
DHT_OFF_T_HIGH = 2 ;DHT_OFF_T_HIGH = 2
DHT_OFF_T_LOW = 3 ;DHT_OFF_T_LOW = 3
DHT_OFF_CHECKSUM = 4 ;DHT_OFF_CHECKSUM = 4
DHT_OFF_DONE = 5 ;DHT_OFF_DONE = 5
message_dht: .asciiz "DHT-Request gesendet." ;message_dht: .asciiz "DHT-Request gesendet."
dht_wait: ;dht_wait:
ldx #$00 ; ldx #$00
dht_wait_: ;dht_wait_:
lda message_dht,x ; lda message_dht,x
sta TO_PRINT,x ; sta TO_PRINT,x
inx ; inx
bne dht_wait_ ; bne dht_wait_
jsr lcd_print_clear ; jsr lcd_print_clear
dht_wait_loop: ; check after every interrpt if dht program is done and then return home ;dht_wait_loop: ; check after every interrpt if dht program is done and then return home
lda #'.' ; lda #'.'
jsr _lcd_char ; jsr _lcd::print_char
wai ; wai
lda DHT_STATUS ; lda DHT_STATUS
cmp #DHT_DONE ; cmp #DHT_DONE
bne dht_wait_loop ; bne dht_wait_loop
dht_exit: ;dht_exit:
jsr kb_read ; jsr kb_read
cmp #'*' ; cmp #'*'
jeq home ; jeq home
bra dht_exit ; bra dht_exit
jmp return_home ; jmp return_home
dht_request: ; send request to sensor ;dht_request: ; send request to sensor
sei ; sei
lda #%00000001 ; set PA1-0 to output 0 ; lda #%00000001 ; set PA1-0 to output 0
ora IO2 + IO_DDRA ; ora IO2 + IO_DDRA
sta IO2 + IO_DDRA ; sta IO2 + IO_DDRA
lda #(LCD_CLEAR | $00) ; lda #(LCD_CLEAR | $00)
sta IO2 + IO_RA ; sta IO2 + IO_RA
; start timer ; ; start timer
lda #DHT_REQUEST_L ; lda #DHT_REQUEST_L
sta IO2 + IO_T1CL ; sta IO2 + IO_T1CL
lda #DHT_REQUEST_H ; lda #DHT_REQUEST_H
sta IO2 + IO_T1CH ; sta IO2 + IO_T1CH
lda #DHT_WAIT_REQ ; lda #DHT_WAIT_REQ
sta DHT_STATUS ; sta DHT_STATUS
cli ; cli
jmp dht_wait ; jmp dht_wait
dht_request_end: ;dht_request_end:
lda #%10000010 ; lda #%10000010
sta IO2 + IO_IER ; enable Interrupt for CA1 ; sta IO2 + IO_IER ; enable Interrupt for CA1
lda #%11111110 ; lda #%11111110
and IO2 + IO_DDRA ; and IO2 + IO_DDRA
sta IO2 + IO_DDRA ; set PA1-0 to input ; sta IO2 + IO_DDRA ; set PA1-0 to input
lda #DHT_WAIT_RESP ; lda #DHT_WAIT_RESP
dht_response: ; receive response from sensor ;dht_response: ; receive response from sensor
lda #DHT_RECV ; lda #DHT_RECV
sta DHT_STATUS ; sta DHT_STATUS
stz DHT_OFFSET ; stz DHT_OFFSET
lda #7 ; lda #7
sta DHT_BIT ; sta DHT_BIT
dht_recv: ;dht_recv:
; start timer ; ; start timer
lda #DHT_RECV_L ; lda #DHT_RECV_L
sta IO2 + IO_T1CL ; sta IO2 + IO_T1CL
lda #DHT_RECV_H ; lda #DHT_RECV_H
sta IO2 + IO_T1CH ; sta IO2 + IO_T1CH
rts ; rts
dht_recv_read: ;dht_recv_read:
; read PA2 ; ; read PA2
lda IO2 + IO_RA ; lda IO2 + IO_RA
and #%00000001 ; and #%00000001
ldx DHT_BIT ; ldx DHT_BIT
beq dht_recv_end ; beq dht_recv_end
dht_recv_rot: ;dht_recv_rot:
rol ; rol
dex ; dex
bne dht_recv_rot ; bne dht_recv_rot
dht_recv_end: ;dht_recv_end:
ldy DHT_OFFSET ; ldy DHT_OFFSET
ora DHT_VALUES,y ; ora DHT_VALUES,y
sta DHT_VALUES,y ; sta DHT_VALUES,y
; determine if 8 bits are done ; ; determine if 8 bits are done
ldx DHT_BIT ; ldx DHT_BIT
beq dht_recv_next ; beq dht_recv_next
rts ; rts
dht_recv_next: ;dht_recv_next:
lda #7 ; lda #7
sta DHT_BIT ; sta DHT_BIT
inc DHT_OFFSET ; inc DHT_OFFSET
cmp DHT_OFF_DONE ; cmp DHT_OFF_DONE
beq dht_display ; beq dht_display
rts ; rts
dht_display: ;dht_display:
ldx #0 ; ldx #0
dht_display_: ;dht_display_:
lda DHT_VALUES,x ; lda DHT_VALUES,x
sta TO_PRINT,x ; sta TO_PRINT,x
inx ; inx
cpx #5 ; cpx #5
bne dht_display_ ; bne dht_display_
jsr lcd_print_clear ; jsr lcd_print_clear
rts ; rts
dht_irq: ;dht_irq:
lda DHT_STATUS ; lda DHT_STATUS
cmp #DHT_WAIT_REQ ; cmp #DHT_WAIT_REQ
beq dht_request_end ; beq dht_request_end
cmp #DHT_WAIT_RESP ; cmp #DHT_WAIT_RESP
beq dht_response ; beq dht_response
cmp #DHT_RECV ; cmp #DHT_RECV
beq dht_recv ; beq dht_recv
rts ; rts

View File

@ -1,7 +1,9 @@
.ifndef INCLUDE_MEMCOPY .ifndef INCLUDE_MEMCOPY
INCLUDE_MEMCOPY = 1 INCLUDE_MEMCOPY = 1
.include "system.h65"
.code
;******************************************************************************** ;********************************************************************************
; @function Copy a block of memory to a different address ; @function Copy a block of memory to a different address
; @param ARG0-1: Source address ; @param ARG0-1: Source address
@ -9,14 +11,15 @@ INCLUDE_MEMCOPY = 1
; @param y: Number of bytes to copy ; @param y: Number of bytes to copy
;******************************************************************************** ;********************************************************************************
.proc memcopy .proc memcopy
cpy cpy #0
loop: @loop:
beq @loop_end beq @loop_end
lda (ARG0),y lda (ARG0),y
sta (ARG2),y sta (ARG2),y
dey dey
bra @loop bra @loop
loop_end: @loop_end:
rts rts
.endproc
.endif ; guard .endif ; guard

View File

@ -1,11 +1,11 @@
.ifndef INCLUDE_PRINT_SLOW .ifndef INCLUDE_PRINT_SLOW
INCLUDE_PRINT_SLOW = 1 INCLUDE_PRINT_SLOW = 1
.include "programs/sleep.s65" .include "system.h65"
.include "system/lcd.s65" .include "sleep.s65"
.include "lcd.h65"
.code
;******************************************************************************** ;********************************************************************************
; @function Print a null-terminated string ; @function Print a null-terminated string
; @param ARG0-1: Address of the string to print ; @param ARG0-1: Address of the string to print
@ -19,7 +19,7 @@ INCLUDE_PRINT_SLOW = 1
phx phx
jsr sleep jsr sleep
plx plx
jsr lcd_char jsr lcd::print_char
iny iny
bra @print_loop bra @print_loop
@print_end: @print_end:
@ -32,7 +32,7 @@ INCLUDE_PRINT_SLOW = 1
; @param time_cs: time to sleep in centiseconds ; @param time_cs: time to sleep in centiseconds
;******************************************************************************** ;********************************************************************************
.macro PrintSlow message,time_cs .macro PrintSlow message,time_cs
jsr lcd_clear jsr lcd::clear
lda #<message lda #<message
sta ARG0 sta ARG0
lda #>message lda #>message

10
programs/printer.h65 Normal file
View File

@ -0,0 +1,10 @@
;********************************************************************************
; Printing Program
;********************************************************************************
.ifndef INCLUDE_PRINTER
INCLUDE_PRINTER = 1
.global printer
.import home:absolute
.endif ; guard

View File

@ -1,16 +1,15 @@
;******************************************************************************** .include "printer.h65"
; Printing Program .include "lcd.h65"
;******************************************************************************** .include "keypad.h65"
.ifndef INCLUDE_PRINTER
INCLUDE_PRINTER = 1
.code .code
printer: .proc printer
jsr lcd_clear jsr lcd::clear
@printer_loop: @printer_loop:
jsr rb_keypad_read jsr kp::read
beq @printer_loop beq @printer_loop
cmp #'*' cmp #'*'
jeq home jeq home
jsr lcd_char jsr lcd::print_char
bra @printer_loop bra @printer_loop
.endif ; guard .endproc

View File

@ -1,5 +1,6 @@
.ifndef INCLUDE_SLEEP .ifndef INCLUDE_SLEEP
INCLUDE_SLEEP = 1 INCLUDE_SLEEP = 1
.include "system.h65"
.code .code
;******************************************************************************** ;********************************************************************************
; @macro Sleep ; @macro Sleep
@ -20,10 +21,10 @@ INCLUDE_SLEEP = 1
; @details ; @details
; Interrupts might change the actual time to finish ; Interrupts might change the actual time to finish
; To be exact, time_cs is in units of 0.010244s ; To be exact, time_cs is in units of 0.010244s
; @modifies: ARG2 ; @modifies: ARG15
;******************************************************************************** ;********************************************************************************
.proc sleep .proc sleep
_VAR_1 = ARG2 _VAR_1 = ARG15
stz _VAR_1 stz _VAR_1
@loop: @loop:
.repeat 17 .repeat 17

View File

@ -1,9 +1,11 @@
.include "system/spi.s65" .include "spi.h65"
.include "util/string.s65" .include "string.h65"
.ifndef INCLUDE_SPI_MENU .include "keypad.h65"
INCLUDE_SPI_MENU = 1 .include "lcd.h65"
.import home:absolute
.import SPI_IO
.scope spi_menu .export spi_menu
.bss .bss
trans_bytes: .res 1 trans_bytes: .res 1
trans_pages: .res 1 trans_pages: .res 1
@ -17,12 +19,12 @@ status_str: .res 17 ; 16 + null
lda #'X' lda #'X'
sta status sta status
@print_menu: @print_menu:
jsr lcd_clear jsr lcd::clear
Print MENU Print MENU
@print_status: @print_status:
Strf FMT_STATUS,status_str,trans_pages,trans_bytes,status Strf FMT_STATUS,status_str,trans_pages,trans_bytes,status
lda #(LCD_CMD_SET_ADDRESS | LCD_LINE4) lda #(lcd::CMD_SET_ADDRESS | lcd::LINE4)
jsr _lcd_cmd jsr lcd::_cmd
Print status_str Print status_str
@loop: @loop:
; check if a byte has been transferred ; check if a byte has been transferred
@ -43,11 +45,11 @@ status_str: .res 17 ; 16 + null
bra @print_status bra @print_status
@read_keypad: @read_keypad:
lda _KP_DEBUG_VAL lda kp::_DEBUG_VAL
beq @loop beq @loop
; TODO debug ; TODO debug
sta 0 sta 0
stz _KP_DEBUG_VAL stz kp::_DEBUG_VAL
lda 0 lda 0
cmp #'*' cmp #'*'
beq @return_home beq @return_home
@ -70,9 +72,9 @@ status_str: .res 17 ; 16 + null
jmp @print_menu jmp @print_menu
@spi_jump: @spi_jump:
jsr spi_p::end jsr spi_p::end
jsr lcd_clear jsr lcd::clear
Print START Print START
jmp spi_p::SPI_CODE_START jmp spi_p::CODE_START
@return_home: @return_home:
jsr spi_p::end jsr spi_p::end
jmp home jmp home
@ -87,6 +89,3 @@ MENU:
FMT_STATUS: .asciiz "%x%xb Status:%x" FMT_STATUS: .asciiz "%x%xb Status:%x"
BEGIN: .asciiz "---BEGIN SPI---" BEGIN: .asciiz "---BEGIN SPI---"
START: .asciiz "---START SPI---" START: .asciiz "---START SPI---"
.endscope
.endif ; guard

149
spicode.s65 Normal file
View File

@ -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 ARG0
lda #>TEST_FMT
sta ARG1
lda #<TEST_OUT
sta ARG2
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"

View File

@ -77,7 +77,6 @@ RB_LENGTH = RBUF_MEM_END - RBUF_MEM_START - 2
; @param A: value to store ; @param A: value to store
; @modifies: X ; @modifies: X
;******************************************************************************** ;********************************************************************************
;TODO increment read when write reaches it
.ident(.concat(_RBUF_NAME, "_write")): .ident(.concat(_RBUF_NAME, "_write")):
.scope .scope
; lda kp_VALUES, x ; load the char in a ; lda kp_VALUES, x ; load the char in a

29
system/keypad.h65 Normal file
View File

@ -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

View File

@ -1,57 +1,45 @@
;******************************************************************************** .include "keypad.h65"
; @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
;********************************************************************************
Export kp, init, read_irq, read
.ifndef INCLUDE_KEYPAD ExportZp kp, _DEBUG_VAL
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
.zeropage .zeropage
_KP_COLUMN: .res 1 ; for storing stuff _COLUMN: .res 1 ; for storing stuff
_KP_DEBUG_VAL: .res 1 ; for storing the last char DEBUG _DEBUG_VAL: .res 1 ; for storing the last char DEBUG
.bss ; reserve space or ringbuffer .bss ; reserve space or ringbuffer
KP_BUF_SIZE = 10 RBUF_MEM_START: .res kp::BUF_SIZE
RBUF_MEM_START: .res KP_BUF_SIZE RBUF_MEM_END = RBUF_MEM_START + kp::BUF_SIZE - 1
RBUF_MEM_END = RBUF_MEM_START + KP_BUF_SIZE - 1
.define RBUF_NAME "keypad" .define RBUF_NAME "keypad"
.include "buffer.s65" .include "buffer.h65"
.code .code
.proc kp_init .proc init
; todo remove later and test ; todo remove later and test
lda #$ff lda #$ff
sta KP_IO+IO::DDRA sta kp::KP_IO+IO::DDRA
stz KP_IO+IO::RA stz kp::KP_IO+IO::RA
; INIT KEYPAD ; INIT KEYPAD
; todo: use masks ; todo: use masks
lda #%11110000; KP_IO+IO::RA 0-3 output lda #%11110000; kp::KP_IO+IO::RA 0-3 output
sta KP_IO+IO::DDRA sta kp::KP_IO+IO::DDRA
; output 0, key press will pull input pin low ; output 0, key press will pull input pin low
stz KP_IO+IO::RA stz kp::KP_IO+IO::RA
stz KP_IO+IO::ACR stz kp::KP_IO+IO::ACR
; lda #%00010000 ; set CA1 to interrupt on pos. edge ; lda #%00010000 ; set CA1 to interrupt on pos. edge
; todo: use masks ; todo: use masks
lda #IO::PCR::CA1_IP_AE lda #IO::PCR::CA1_IP_AE
sta KP_IO+IO::PCR sta kp::KP_IO+IO::PCR
jsr rb_keypad_init ; init keybuffer jsr rb_keypad_init ; init keybuffer
lda #(IO::IRQ::IRQ | IO::IRQ::CA1) ; enable interrupt for CA1 on KP_IO lda #(IO::IRQ::IRQ | IO::IRQ::CA1) ; enable interrupt for CA1 on kp::KP_IO
sta KP_IO+IO::IER sta kp::KP_IO+IO::IER
rts rts
.endproc .endproc
read = rb_keypad_read
;******************************************************************************** ;********************************************************************************
; @function Read which key is pressed on the keypad ; @function Read which key is pressed on the keypad
; @details ; @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 ; The value stored in the keybuffer is the offset which must be added to
; kp_VALUES to retrieve the key that was pressed ; 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 ; test each "row" and check which column is 1
; TODO dont check every column if the value has been found ; TODO dont check every column if the value has been found
lda #%11100000 lda #%11100000
@ -74,31 +62,31 @@ RBUF_MEM_END = RBUF_MEM_START + KP_BUF_SIZE - 1
lda #%01110000 lda #%01110000
ldx #$0c ldx #$0c
jsr @kp_read_column jsr @kp_read_column
stz KP_IO+IO::RA stz kp::KP_IO+IO::RA
lda KP_IO+IO::RA ; clear interrupt flag again beceause it might be set again through the above tests lda kp::KP_IO+IO::RA ; clear interrupt flag again beceause it might be set again through the above tests
rts rts
@kp_read_column: @kp_read_column:
sta KP_IO+IO::RA sta kp::KP_IO+IO::RA
lda KP_IO+IO::RA lda kp::KP_IO+IO::RA
sta _KP_COLUMN ; store result in zeropage so that bbr can be used sta _COLUMN ; store result in zeropage so that bbr can be used
bbr0 _KP_COLUMN,@kp_write ; row 1 bbr0 _COLUMN,@kp_write ; row 1
inx inx
bbr1 _KP_COLUMN,@kp_write ; row 3 bbr1 _COLUMN,@kp_write ; row 3
inx inx
bbr2 _KP_COLUMN,@kp_write ; row 2 bbr2 _COLUMN,@kp_write ; row 2
inx inx
bbr3 _KP_COLUMN,@kp_write ; row 4 bbr3 _COLUMN,@kp_write ; row 4
rts rts
@kp_write: @kp_write:
lda _KP_VALUES,x lda VALUES,x
; TODO use ringbuffer ; TODO use ringbuffer
sta _KP_DEBUG_VAL sta _DEBUG_VAL
jsr rb_keypad_write jsr rb_keypad_write
rts rts
.endproc .endproc
.rodata .rodata
_KP_VALUES: VALUES:
.byte "174*" .byte "174*"
.byte "2850" .byte "2850"
.byte "396#" .byte "396#"
@ -108,4 +96,3 @@ _KP_VALUES:
; row 2 = PA2 ; row 2 = PA2
; row 3 = PA1 ; row 3 = PA1
; row 4 = PA3 ; row 4 = PA3
.endif

60
system/lcd.h65 Normal file
View File

@ -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 ARG0
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

View File

@ -1,233 +1,214 @@
;******************************************************************************** .include "system/lcd.h65"
; @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
.ifndef LCD_IO .ifndef lcd::LCD_IO
.fatal "LCD_IO is not defined: set it to the base address of the IO chip of the LCD" .fatal "lcd::LCD_IO is not defined: set it to the base address of the IO chip of the LCD"
.endif .endif
.ifndef INCLUDE_IOW65C22
.error "IO-W65C22 module is not included"
.endif
.include "utility.h65"
Export lcd,init,clear,print,print_char,set_position
; RAM VARIABLES ; RAM VARIABLES
.ifndef LCD_MEM .bss
LCD_MEM = $300 charcount: .res 1
.endif
LCD_CHARCOUNT = LCD_MEM
; PIN MASKS .code
LCD_E = %10000000 ;;********************************************************************************
LCD_RW = %01000000 ;; @function Initialize the lcd module
LCD_RS = %00100000 ;; @details call before doing anything else
; .local LCD_E,LCD_RW,LCD_RS ;; @modifies A
;;********************************************************************************
; LCD Instructions (see datasheet for more) .proc init
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
; init IO ; init IO
lda #$ff ; RB 0-7 output 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) ; 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 lda #(lcd::RS | lcd::RW | lcd::E) ; RA 5-7 output
sta LCD_IO+IO::DDRA sta lcd::LCD_IO+IO::DDRA
; init lcd ; init lcd
lda #LCD_CMD_FUNCTION_SET lda #lcd::CMD_FUNCTION_SET
jsr _lcd_cmd jsr _cmd
lda #LCD_CMD_DISPLAY_ON lda #lcd::CMD_DISPLAY_ON
jsr _lcd_cmd jsr _cmd
lda #LCD_CMD_CLEAR lda #lcd::CMD_CLEAR
jsr _lcd_cmd jsr _cmd
lda #LCD_CMD_ENTRY_MODE lda #lcd::CMD_ENTRY_MODE
jsr _lcd_cmd jsr _cmd
stz LCD_CHARCOUNT stz charcount
rts rts
.endproc .endproc
;********************************************************************************
; PRINTING TO LCD
;********************************************************************************
;********************************************************************************
; @function Clear the display ;;********************************************************************************
; @see lcd_print ;; PRINTING TO LCD
;******************************************************************************** ;;********************************************************************************
.proc lcd_clear
stz LCD_CHARCOUNT ;;********************************************************************************
lda #LCD_CLEAR ;; @function Clear the display
jsr _lcd_cmd ;; @see lcd_print
lda #(LCD_CMD_SET_ADDRESS | LCD_LINE1) ;; @modifies A
jsr _lcd_cmd ;;********************************************************************************
.proc clear
stz charcount
lda #lcd::CLEAR
jsr _cmd
lda #(lcd::CMD_SET_ADDRESS | lcd::LINE1)
jsr _cmd
rts rts
.endproc .endproc
;******************************************************************************** ;;********************************************************************************
; @function Print a null-terminated string ;; @function Print a null-terminated string
; @param ARG0-1 Address of the string to print ;; @param ARG0-1 Address of the string to print
;******************************************************************************** ;; @modifies: A,Y
.proc lcd_print ;;********************************************************************************
.proc print
ldy #$00 ldy #$00
@lcd_print_loop: @lcd_print_loop:
lda (ARG0),y lda (ARG0),y
beq @lcd_print_end beq @lcd_print_end
jsr lcd_char jsr print_char
iny iny
bra @lcd_print_loop bra @lcd_print_loop
@lcd_print_end: @lcd_print_end:
rts rts
.endproc .endproc
;******************************************************************************** ;;********************************************************************************
; @macro Print a null-terminated string ;; @macro Print a single character
; @param message: Address of the message ;; @param A: Character to print
;******************************************************************************** ;;********************************************************************************
.macro Print message .proc print_char
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
pha pha
pha pha
; TODO use UT_update_with_mask? ; TODO use UT_update_with_mask?
jsr _lcd_wait_nbusy jsr _wait_nbusy
pla pla
sta LCD_IO + IO::RB sta lcd::LCD_IO + IO::RB
lda #LCD_RS lda #lcd::RS
sta LCD_IO + IO::RA sta lcd::LCD_IO + IO::RA
lda #(LCD_RS | LCD_E) lda #(lcd::RS | lcd::E)
sta LCD_IO + IO::RA sta lcd::LCD_IO + IO::RA
lda #LCD_RS lda #lcd::RS
sta LCD_IO + IO::RA sta lcd::LCD_IO + IO::RA
inc LCD_CHARCOUNT inc charcount
jsr _lcd_set_address jsr _break_line
pla ; put char back in a pla ; put char back in a
.endproc .endproc
;******************************************************************************** ;;********************************************************************************
; Internal LCD Commands ;; Internal LCD Commands
;******************************************************************************** ;;********************************************************************************
; read busy flag ; read busy flag
.proc _lcd_wait_nbusy .proc _wait_nbusy
stz LCD_IO + IO::DDRB ; set IO1-LCD_IO + IO::RB to input stz lcd::LCD_IO + IO::DDRB ; set IO1-IO + IO::RB to input
@lcd_wait_nbusy_loop: ; read the busy flag @lcd_wait_nbusy_loop: ; read the busy flag
lda #LCD_RW lda #lcd::RW
sta LCD_IO + IO::RA sta lcd::LCD_IO + IO::RA
lda #(LCD_RW | LCD_E) lda #(lcd::RW | lcd::E)
sta LCD_IO + IO::RA 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 and #%10000000 ; and updates zero flag, if not set retry
bne @lcd_wait_nbusy_loop bne @lcd_wait_nbusy_loop
lda #%00000000 ; TODO dont overwrite 0-4 lda #%00000000 ; TODO dont overwrite 0-4
sta LCD_IO + IO::RA sta lcd::LCD_IO + IO::RA
lda #%11111111 ; set IO1-LCD_IO + IO::RB to output lda #%11111111 ; set IO1-IO + IO::RB to output
sta LCD_IO + IO::DDRB sta lcd::LCD_IO + IO::DDRB
rts rts
.endproc .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 pha
jsr _lcd_wait_nbusy jsr _wait_nbusy
pla pla
; TODO use UT_update_with_mask? ; TODO use UT_update_with_mask?
sta LCD_IO + IO::RB sta lcd::LCD_IO + IO::RB
lda #LCD_CLEAR lda #lcd::CLEAR
sta LCD_IO + IO::RA sta lcd::LCD_IO + IO::RA
lda #LCD_E lda #lcd::E
sta LCD_IO + IO::RA sta lcd::LCD_IO + IO::RA
lda #LCD_CLEAR lda #lcd::CLEAR
sta LCD_IO + IO::RA sta lcd::LCD_IO + IO::RA
rts rts
.endproc .endproc
;******************************************************************************** ;;********************************************************************************
; Set the LCD DD-RAM Address so that text linebreaks after 16 chars ;; @function Set the cursor to a position
;******************************************************************************** ;; @param A: cursor position: `(lcd::LINEX + offset)`, where offset € [$0, $f]
.proc _lcd_set_address ;; @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 ; check if checks are necessary
lda LCD_CHARCOUNT lda charcount
beq @lcd_line1 beq @line1
and #%10001111 ; ($10 | $20 | $30 | $40) = %01110000 and #%10001111 ; ($10 | $20 | $30 | $40) = %01110000
bne @lcd_set_address_done bne @rts
; checks necessary ; checks necessary
lda LCD_CHARCOUNT lda charcount
beq @lcd_line1 beq @line1
cmp #$10 cmp #$10
beq @lcd_line2 beq @line2
cmp #$20 cmp #$20
beq @lcd_line3 beq @line3
cmp #$30 cmp #$30
beq @lcd_line4 beq @line4
cmp #$40 ; set to line1 when full ; set to line1 when full cmp #$40 ; set to line1 when full
beq @lcd_line1 bge @line1
@lcd_set_address_done: @rts:
rts rts
@lcd_line1: @line1:
stz LCD_CHARCOUNT stz charcount
lda #(LCD_CMD_SET_ADDRESS | LCD_LINE1) lda #(lcd::CMD_SET_ADDRESS | lcd::LINE1)
jsr _lcd_cmd jsr _cmd
rts rts
@lcd_line2: @line2:
lda #(LCD_CMD_SET_ADDRESS | LCD_LINE2) lda #(lcd::CMD_SET_ADDRESS | lcd::LINE2)
jsr _lcd_cmd jsr _cmd
rts rts
@lcd_line3: @line3:
lda #(LCD_CMD_SET_ADDRESS | LCD_LINE3) lda #(lcd::CMD_SET_ADDRESS | lcd::LINE3)
jsr _lcd_cmd jsr _cmd
rts rts
@lcd_line4: @line4:
lda #(LCD_CMD_SET_ADDRESS | LCD_LINE4) lda #(lcd::CMD_SET_ADDRESS | lcd::LINE4)
jsr _lcd_cmd jsr _cmd
rts rts
.endproc .endproc
.endif

View File

@ -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

18
system/spi.h65 Normal file
View File

@ -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

View File

@ -1,156 +1,17 @@
;******************************************************************************** .include "spi.h65"
; @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
Export spi_p, begin, end, read, pages_written, bytes_written
.zeropage .zeropage
code_page: .res 2 ; SPI_CODE_START + pages_written * 256 code_page: .res 2 ; CODE_START + pages_written * 256
.bss .bss
bytes_written: .res 1 bytes_written: .res 1
pages_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 ; spi-transferred code will be placed here
.segment "SPI"
SPI_CODE_START:
lda '$'
jsr lcd_char
lda #<TEST_FMT
sta ARG0
lda #>TEST_FMT
sta ARG1
lda #<TEST_OUT
sta ARG2
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 ; SPI_P = as peripheral
.code .code
.struct SPI_P_Pins .struct SPI_P_Pins
@ -178,9 +39,9 @@ TEST_OUT: .asciiz "TESTOUT"
stz pages_written stz pages_written
stz bytes_written stz bytes_written
; store address in zp ; store address in zp
lda #<SPI_CODE_START lda #<CODE_START
sta code_page sta code_page
lda #>SPI_CODE_START lda #>CODE_START
sta code_page + 1 sta code_page + 1
; todo USE MASKS ; todo USE MASKS
; set Shift register to shift in under external clock on CB1 ; set Shift register to shift in under external clock on CB1
@ -196,6 +57,7 @@ TEST_OUT: .asciiz "TESTOUT"
rts rts
.endproc .endproc
;******************************************************************************** ;********************************************************************************
; @function Stop listening for SPI transfers ; @function Stop listening for SPI transfers
; @details ; @details
@ -209,7 +71,6 @@ TEST_OUT: .asciiz "TESTOUT"
.endproc .endproc
;******************************************************************************** ;********************************************************************************
; @function Read a byte from SPI ; @function Read a byte from SPI
; @details ; @details
@ -218,7 +79,7 @@ TEST_OUT: .asciiz "TESTOUT"
.proc read .proc read
ldx bytes_written ldx bytes_written
lda SPI_IO + IO::SR lda SPI_IO + IO::SR
sta SPI_CODE_START,x sta CODE_START,x
inc bytes_written inc bytes_written
beq @new_page beq @new_page
rts rts
@ -249,9 +110,3 @@ TEST_OUT: .asciiz "TESTOUT"
;******************************************************************************** ;********************************************************************************
.proc send_data .proc send_data
.endproc .endproc
.endscope
.endif

55
system/system.h65 Normal file
View File

@ -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

View File

@ -1,82 +1,3 @@
;******************************************************************************** .zeropage
; @module system .org $10
; @type header .res 16
; @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

View File

@ -1,55 +1,55 @@
.include "system/system.h65" ;.include "system/system.h65"
.segment "CODE" ;.segment "CODE"
;******************************************************************************** ;;********************************************************************************
; Interrupts ;; Interrupts
;******************************************************************************** ;;********************************************************************************
nmi: ;nmi:
rti ; rti
irq: ;irq:
.repeat 20 ; .repeat 20
.endrepeat ; .endrepeat
rti ; rti
;******************************************************************************** ;;********************************************************************************
; Reset sequence ;; Reset sequence
;******************************************************************************** ;;********************************************************************************
reset: ;reset:
sei ; sei
; setup io2 bank a 1-3 ; ; setup io2 bank a 1-3
lda #%11111111 ; lda #%11111111
sta IO1 + IO_DDRA ; sta IO1 + IO_DDRA
sta IO1 + IO_DDRB ; sta IO1 + IO_DDRB
@loop: ;@loop:
lda #%00000000 ; lda #%00000000
sta IO1 + IO_RA ; sta IO1 + IO_RA
.repeat 3 ; .repeat 3
nop ; nop
.endrepeat ; .endrepeat
lda #%11111111 ; lda #%11111111
sta IO1 + IO_RA ; sta IO1 + IO_RA
.repeat 15 ; .repeat 15
nop ; nop
.endrepeat ; .endrepeat
lda #%00000000 ; lda #%00000000
sta IO1 + IO_RB ; sta IO1 + IO_RB
.repeat 5 ; .repeat 5
nop ; nop
.endrepeat ; .endrepeat
lda #%11111111 ; lda #%11111111
sta IO1 + IO_RB ; sta IO1 + IO_RB
.repeat 10 ; .repeat 10
nop ; nop
.endrepeat ; .endrepeat
bra @loop ; bra @loop
;******************************************************************************** ;;********************************************************************************
; reset vector ;; reset vector
;******************************************************************************** ;;********************************************************************************
.segment "RESET_VECTOR" ;.segment "RESET_VECTOR"
.word nmi ; .word nmi
.word reset ; .word reset
.word irq ; .word irq

107
util/math.h65 Normal file
View File

@ -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

View File

@ -1,106 +1 @@
;******************************************************************************** .code
; @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

66
util/string.h65 Normal file
View File

@ -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,#>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 ARG0
lda #>fmt
sta ARG1
lda #<out
sta ARG2
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

View File

@ -1,63 +1,8 @@
;******************************************************************************** .include "string.h65"
; @module string .include "math.h65"
; @type utility Export str, strf, int8_to_hex_str
; @details
; String utility
;********************************************************************************
.ifndef INCLUDE_STRING
INCLUDE_STRING = 1
.scope str
.code .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,#>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 ARG0
lda #>fmt
sta ARG1
lda #<out
sta ARG2
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 ; @function Format a string
; @details ; @details
@ -73,6 +18,8 @@ out_idx = $31
; @returns ; @returns
; @modifies: A, X, Y ; @modifies: A, X, Y
;******************************************************************************** ;********************************************************************************
out_idx := str::out_idx
fmt_idx := str::fmt_idx
.proc strf .proc strf
stz out_idx stz out_idx
stz fmt_idx stz fmt_idx
@ -156,8 +103,3 @@ out_idx = $31
.rodata .rodata
HEX_CHARS_UPPER: .byte "0123456789ABCDEF" HEX_CHARS_UPPER: .byte "0123456789ABCDEF"
HEX_CHARS_LOWER: .byte "0123456789abcdef" HEX_CHARS_LOWER: .byte "0123456789abcdef"
.export strf
.endscope
.endif ; guard

View File

@ -2,6 +2,7 @@
INCLUDE_UTILITY = 1 INCLUDE_UTILITY = 1
.macpack longbranch ; jeq, jge... .macpack longbranch ; jeq, jge...
.macpack generic ; bge, add, sub
;******************************************************************************** ;********************************************************************************
; @macro Update a byte in memory using a mask ; @macro Update a byte in memory using a mask
@ -31,4 +32,59 @@ INCLUDE_UTILITY = 1
; _n_genlabel .set _n_genlabel + 1 ; _n_genlabel .set _n_genlabel + 1
;.endmacro ;.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 .endif