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
**.o
.build
.dependencies
**.d
*build*
labels

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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
sta ARG0
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 @@
;********************************************************************************
; 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

View File

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

View File

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

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
; @modifies: X
;********************************************************************************
;TODO increment read when write reaches it
.ident(.concat(_RBUF_NAME, "_write")):
.scope
; 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 @@
;********************************************************************************
; @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

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

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 @@
;********************************************************************************
; @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 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
.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
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

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

View File

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

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

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 @@
;********************************************************************************
; @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,#>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
; @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

View File

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