Compare commits

...

5 Commits

Author SHA1 Message Date
Matthias@Dell
25d0fcfb90 use indirect spi handler 2023-12-23 14:19:15 +01:00
Matthias@Dell
eb02613837 fmt 2023-12-23 14:18:48 +01:00
Matthias@Dell
9e9978669a fmt 2023-12-23 14:18:32 +01:00
Matthias@Dell
7b97ca096d fmt 2023-12-23 14:18:15 +01:00
Matthias@Dell
2d06c9700b use size, add write 2023-12-23 14:17:49 +01:00
8 changed files with 328 additions and 183 deletions

View File

@ -74,7 +74,6 @@ irq:
bbr7 irq_via_ifr,@irq_return ; skip bbr7 irq_via_ifr,@irq_return ; skip
bbs2 irq_via_ifr,@irq_spi_p ; check SR bbs2 irq_via_ifr,@irq_spi_p ; check SR
bbs1 irq_via_ifr,@irq_keypad ; check CA1 bbs1 irq_via_ifr,@irq_keypad ; check CA1
; this SHOULD never be reached ; this SHOULD never be reached
jsr lcd::clear jsr lcd::clear
Print "Unknown IRQ" Print "Unknown IRQ"
@ -85,8 +84,11 @@ irq:
rti rti
; bra @irq_return ; bra @irq_return
@irq_keypad: @irq_keypad:
jsr kp::read_irq lda #<@irq_return
bra @irq_return pha
lda #>@irq_return
pha
jmp (spi_p::irq_handler)
@irq_spi_p: @irq_spi_p:
jsr spi_p::read jsr spi_p::read
bra @irq_return bra @irq_return

View File

@ -118,56 +118,57 @@ CODE_START:
bra @loop bra @loop
kbinit: ; .proc kbinit
lda #'[' ; lda #'['
jsr lcd::print_char
; - use the shift register interrupts to read the first 8 bits
; set shift register to shift in under external clock on CB1
; - configure timer for timing the read of the last 3 bits
; timer 2 one shot mode is sufficient, leaves T1 available
lda #(IO::ACR::SR_SIN_PHIE | IO::ACR::T2_IRQ_LOAD)
tsb kb::KB_IO + IO::ACR
; the 3 last bits take about 230us, at @1MHz => wait 230 cycles and then the shift register
lda #230
sta kb::KB_IO + IO::T2CL
stz key_read
stz key_read+1
; enable SR interrupts
lda #(IO::IRQ::IRQ | IO::IRQ::SR)
sta kb::KB_IO + IO::IER
; load SR to reset
lda kb::KB_IO + IO::SR
lda #']'
jsr lcd::print_char
rts
;; @details
;; IO::SR has to be read before the next bit is shifted in, which happens ~75us after the irq
;; at 1MHz, handlings this interrupt takes about 50us (without any additional debug code), so it should work
irq_on_shift_reg:
; lda #'{'
; jsr lcd::print_char ; jsr lcd::print_char
lda kb::KB_IO + IO::SR ; ; - use the shift register interrupts to read the first 8 bits
sta key_read ; ; set shift register to shift in under external clock on CB1
stz kb::KB_IO + IO::SR ; ; - configure timer for timing the read of the last 3 bits
; ; timer 2 one shot mode is sufficient, leaves T1 available
; disable SR interrupts ; lda #(IO::ACR::SR_SIN_PHIE | IO::ACR::T2_IRQ_LOAD)
lda #IO::IRQ::SR ; tsb kb::KB_IO + IO::ACR
sta kb::KB_IO + IO::IER ; ; the 3 last bits take about 230us, at @1MHz => wait 230 cycles and then the shift register
; enable timer interrupts ; lda #230
lda #(IO::IRQ::IRQ | IO::IRQ::T2) ; sta kb::KB_IO + IO::T2CL
sta kb::KB_IO + IO::IER ; stz key_read
; start timer ; stz key_read+1
lda #1 ; ; enable SR interrupts
sta kb::KB_IO + IO::T2CH ; lda #(IO::IRQ::IRQ | IO::IRQ::SR)
; lda #'}' ; sta kb::KB_IO + IO::IER
; ; load SR to reset
; lda kb::KB_IO + IO::SR
; lda #']'
; jsr lcd::print_char ; jsr lcd::print_char
rts ; rts
; .endproc
irq_on_timer: ; ;; @details
; ;; IO::SR has to be read before the next bit is shifted in, which happens ~75us after the irq
; ;; at 1MHz, handlings this interrupt takes about 50us (without any additional debug code), so it should work
; .proc irq_on_shift_reg
; ; lda #'{'
; ; jsr lcd::print_char
; lda kb::KB_IO + IO::SR
; sta key_read
; stz kb::KB_IO + IO::SR
; ; disable SR interrupts
; lda #IO::IRQ::SR
; sta kb::KB_IO + IO::IER
; ; enable timer interrupts
; lda #(IO::IRQ::IRQ | IO::IRQ::T2)
; sta kb::KB_IO + IO::IER
; ; start timer
; lda #1
; sta kb::KB_IO + IO::T2CH
; ; lda #'}'
; ; jsr lcd::print_char
; rts
; .endproc
.proc irq_on_timer
; lda #'<' ; lda #'<'
; jsr lcd::print_char ; jsr lcd::print_char
lda kb::KB_IO + IO::SR lda kb::KB_IO + IO::SR
@ -201,13 +202,14 @@ irq_on_timer:
stz key_read+1 stz key_read+1
rts rts
.endproc
key_read: .res 2 ; key_read: .res 2
keycode: .res 1 ; keycode: .res 1
kb_irq1: kb_irq1:
; lda #'!' ; lda #'!'
; jsr lcd::print_char ; jsr lcd::print_char
jsr irq_on_shift_reg jsr kb::on_shift_reg_irq
; lda #':' ; lda #':'
; jsr lcd::print_char ; jsr lcd::print_char
rts rts
@ -215,6 +217,7 @@ kb_irq1:
kb_irq2: kb_irq2:
; lda #'?' ; lda #'?'
; jsr lcd::print_char ; jsr lcd::print_char
; jsr kb::on_timer_irq
jsr irq_on_timer jsr irq_on_timer
; lda #';' ; lda #';'
; jsr lcd::print_char ; jsr lcd::print_char

View File

@ -1,9 +1,9 @@
;******************************************************************************** ;;********************************************************************************
; @module IO-W65C22 ;; @module IO-W65C22
; @type utility ;; @type utility
; @device Western Design - W65C22N Versatile Interface Adapter ;; @device Western Design - W65C22N Versatile Interface Adapter
; @details ;; @details
;******************************************************************************** ;;********************************************************************************
.ifndef INCLUDE_IOW65C22 .ifndef INCLUDE_IOW65C22
INCLUDE_IOW65C22 = 1 INCLUDE_IOW65C22 = 1

View File

@ -1,17 +1,17 @@
;******************************************************************************** ;;********************************************************************************
; @module LCD-W164B ;; @module LCD-W164B
; @type driver ;; @type driver
; @device ELECTRONIC ASSEMBLY - W164B-NLW ;; @device ELECTRONIC ASSEMBLY - W164B-NLW
; @details ;; @details
; The LCD must be connected to a W65C22N Interface Chip: ;; The LCD must be connected to a W65C22N Interface Chip:
; - IO.RB0-7 -> LCD.D0-7 data lines ;; - IO.RB0-7 -> LCD.D0-7 data lines
; - IO.RA5 -> LCD.RS register select ;; - IO.RA5 -> LCD.RS register select
; - IO.RA6 -> LCD.R/W read/write ;; - IO.RA6 -> LCD.R/W read/write
; - IO.RA7 -> LCD.E enable ;; - IO.RA7 -> LCD.E enable
; ;;
; @requires IO: Base Address of IO Chip ;; @requires IO: Base Address of IO Chip
; @depends IO-W65C22N ;; @depends IO-W65C22N
;******************************************************************************** ;;********************************************************************************
.ifndef INCLUDE_LCD .ifndef INCLUDE_LCD
INCLUDE_LCD = 1 INCLUDE_LCD = 1

View File

@ -1,9 +1,10 @@
;******************************************************************************** ;;********************************************************************************
; @module SPI ;; @module SPI-P
; @type driver ;; @type driver
; @details ;; @details
; @depends IO-W65C22N ;; Support being a peripheral SPI device.
;******************************************************************************** ;; @depends IO-W65C22N
;;********************************************************************************
.ifndef INCLUDE_SPI .ifndef INCLUDE_SPI
INCLUDE_SPI = 1 INCLUDE_SPI = 1
@ -11,8 +12,15 @@ INCLUDE_SPI = 1
.scope spi_p .scope spi_p
SPI_IO = IO2 SPI_IO = IO2
.import CODE_START:absolute Import spi_p, begin_read, irq_read_byte, begin_write, irq_write_byte, end, recv_bytes, sent_bytes, status
Import spi_p, begin, end, read, pages_written, bytes_written
.enum STATUS
XFER_SIZEL = %10000000
XFER_SIZEH = %01000000
XFER = %00000001
DONE = %00000000
ERROR = %11111111
.endenum
.endscope .endscope
.endif ; guard .endif ; guard

View File

@ -1,69 +1,90 @@
.include "spi.h65" .include "spi.h65"
Export spi_p, begin, end, read, pages_written, bytes_written Export spi_p, begin_read, irq_read_byte, begin_write, irq_write_byte, end, recv_bytes, sent_bytes, status, spi_irq
.zeropage .zeropage
code_page: .res 2 ; CODE_START + pages_written * 256 buffer_start: .res 2
.bss .bss
bytes_written: .res 1 recv_bytes:
pages_written: .res 1 sent_bytes: .res 2
status: .res 1
buffer_size: .res 2
irq_handler: .res 2
SPI_IO := spi_p::SPI_IO 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
; SPI_P = as peripheral ; SPI_P = as peripheral
.code .code
.struct SPI_P_Pins ; .struct SPI_P_Pins
; VIA addresses ; ; VIA addresses
DDR_a .word ; address of the data direction register ; DDR_a .word ; address of the data direction register
R_a .word ; address of the register ; R_a .word ; address of the register
; pin mask ; ; pin mask
SCLK_p .byte ; Serial Clock ; SCLK_p .byte ; Serial Clock
POCI_p .byte ; Peripheral Out / Controller In ; POCI_p .byte ; Peripheral Out / Controller In
PICO_p .byte ; Peripheral In / Controller Out ; PICO_p .byte ; Peripheral In / Controller Out
CSB_p .byte ; Chip Select ; CSB_p .byte ; Chip Select
; settings ; ; settings
CPOL .byte ; Clock Polarity ; CPOL .byte ; Clock Polarity
CPHA .byte ; Clock Phase ; CPHA .byte ; Clock Phase
.endstruct ; .endstruct
;;********************************************************************************
;; @function Begin listening for SPI transfers
;; @details
;; The transfer must be: <SIZE, >SIZE, data (SIZE bytes)
;;
;; - initialize variables
;; - configure shift register to shift in under external clock
;; - enable shift register interrupts
;; @param ARG0-1: Start address of the buffer
;; @param ARG2-3: Size of the buffer
;; @todo: Use irq register handler
;; @note: The buffer must be large enough for the received data.
;;********************************************************************************
.proc begin_read
stz recv_bytes
stz recv_bytes+1
lda #%spi_p::STATUS::XFER_SIZEL
sta status
;********************************************************************************
; @function Begin listening for SPI transfers
; @details
; - initialize variables
; - configure shift register to shift in under external clock
; - enable shift register interrupts
;********************************************************************************
.proc begin
stz pages_written
stz bytes_written
; store address in zp ; store address in zp
lda #<CODE_START lda #<ARG0
sta code_page sta buffer_start
lda #>CODE_START lda #>ARG1
sta code_page + 1 sta buffer_start+1
; todo USE MASKS
; set Shift register to shift in under external clock on CB1
lda #IO::ACR::SR_SIN_PHIE
sta SPI_IO + IO::ACR
; load irq handler
lda #<irq_read_byte
sta irq_handler
lda #>irq_read_byte
sta irq_handler+1
; temporarily store the low byte in buffer, will be checked later
lda #<ARG2
sta (buffer_start)
lda #>ARG3
sta buffer_size+1
; set Shift register to shift in under external clock on CB1
MaskedWrite SPI_IO+IO::ACR, #IO::ACR::SR_SIN_PHIE, #IO::ACR_MASK::SR
; enable SR interrupts ; enable SR interrupts
lda #(IO::IRQ::IRQ | IO::IRQ::SR) lda #(IO::IRQ::IRQ | IO::IRQ::SR)
sta SPI_IO + IO::IER sta SPI_IO + IO::IER
; load SR to reset ; load SR to reset
lda SPI_IO + IO::SR lda SPI_IO + IO::SR
rts rts
.endproc .endproc
;******************************************************************************** ;;********************************************************************************
; @function Stop listening for SPI transfers ;; @function Stop reading/writing from/to SPI
; @details ;; @details
; Disables shift register interrupts ;; Disables shift register interrupts
; @modifies A ;; @modifies A
;******************************************************************************** ;;********************************************************************************
.proc end .proc end
; disable SR interrupts ; disable SR interrupts
lda #IO::IRQ::SR lda #IO::IRQ::SR
@ -72,43 +93,154 @@ CODE_START := spi_p::CODE_START
.endproc .endproc
;******************************************************************************** ;;********************************************************************************
; @function Read a byte from SPI ;; @function Read a byte from SPI
; @details ;; @details
; Reads a byte from the shift register and stores it in the SPI code buffer ;; Reads a byte from the shift register and stores it in the SPI code buffer
; @modifies A,Y ;; The first two bytes must be the size of the incumong data (LE).
;******************************************************************************** ;; The spi_p:status is updated according to the current stage of the transfer.
.proc read ;; If the buffer size given in begin_read is too small too fit the incoming data,
ldy bytes_written ;; the status is set to ERROR and spi (shift register) interrupts are disabled before
;; the first real byte is read.
;; @modifies A,Y
;;********************************************************************************
.proc irq_read_byte
lda SPI_IO + IO::SR lda SPI_IO + IO::SR
sta (code_page),y bit status
inc bytes_written bmi @read_size1
bvs @read_size2
ldy recv_bytes
sta (buffer_start),y
inc recv_bytes
beq @new_page beq @new_page
rts rts
@new_page: @new_page:
inc pages_written inc recv_bytes+1
inc code_page + 1 inc buffer_start+1
rts
@read_size1:
sta buffer_size
lda #spi_p::STATUS::XFER_SIZEH
sta status
rts
@read_size2:
; todo: check if the buffer is large enough:
; low byte of buffer size in (buffer_start), high byte in buffer_size+1
; low byte of recv buffer size in buffer_size, high byte in A
cmp buffer_size+1
beq @hieq
sta buffer_size+1
bcs @enough ; buffer larger
bra @not_enough
@hieq: ; high bytes are equal, check lo
lda (buffer_start)
cmp buffer_size
bcs @enough
@not_enough:
lda #spi_p::STATUS::ERROR
sta status
; disable SR interrupts
lda #IO::IRQ::SR
sta SPI_IO + IO::IER
rts
@enough:
lda #spi_p::STATUS::XFER
sta status
rts rts
.endproc .endproc
;******************************************************************************** ;;********************************************************************************
; @function Initialize the IO Adapter for SPI ;; @function Begin writing to spi
; @param ARG0-1 Address of the SPI_Pins struct ;; @details
;******************************************************************************** ;; - initialize variables
;******************************************************************************** ;; - configure shift register to shift in under external clock
; @function Read bytes ;; - enable shift register interrupts
; @param X Number of bytes to send ;; @param ARG0-1: Start address of the buffer
; @param ARG0-1 Address of the SPI_Pins struct ;; @param ARG2-3: Size of the buffer
; @param ARG2-3 Address of the first byte ;; @todo: Use irq register handler
;******************************************************************************** ;;********************************************************************************
.proc recv_data .proc begin_write
stz recv_bytes
stz recv_bytes+1
; store address in zp
lda #<ARG0
sta buffer_start
lda #>ARG1
sta buffer_start+1
; store size
lda #<ARG2
sta buffer_size
lda #>ARG3
sta buffer_size+1
; load irq handler
lda #<irq_read_byte
sta irq_handler
lda #>irq_read_byte
sta irq_handler+1
; set Shift register to shift out under external clock on CB1
MaskedWrite SPI_IO+IO::ACR, #IO::ACR::SR_SOUT_PHIE, #IO::ACR_MASK::SR
; enable SR interrupts
lda #(IO::IRQ::IRQ | IO::IRQ::SR)
sta SPI_IO + IO::IER
; write the first byte
@write_size1:
lda buffer_size
sta SPI_IO+IO_SR
lda #spi_p::STATUS::XFER_SIZEH
sta status
rts
rts
.endproc .endproc
;********************************************************************************
; @function Send bytes ;;;********************************************************************************
; @param X Number of bytes to send ;;; @function Write a byte
; @param ARG0-1 Address of the SPI_Pins struct ;;; @details
; @param ARG2-3 Address of the first byte ;;; Write a byte to the spi shift reister
;******************************************************************************** ;;; @modifies A,Y
.proc send_data ;;;********************************************************************************
;.proc irq_write_byte
; ldy sent_bytes
; lda (buffer_start),y
; sta SPI_IO + IO::SR
; inc sent_bytes
; beq @new_page
; rts
;@new_page:
; inc sent_bytes+1
; inc buffer_start+1
; rts
;.endproc
;;********************************************************************************
;; @function Write a byte to SPI
;; @details
;; Write a byte from the buffer to the (spi) shift register.
;; The first two bytes are the size of the data (LE).
;; The spi_p:status is updated according to the current stage of the transfer.
;; @modifies A,Y
;;********************************************************************************
.proc irq_write_byte
bit status
bvs @write_size2 ; bit 6 set -> XFER_SIZEH
ldy sent_bytes
lda (buffer_start),y
sta SPI_IO + IO::SR
inc sent_bytes
beq @new_page
rts
@new_page:
inc sent_bytes+1
inc buffer_start+1
rts
@write_size2:
lda buffer_size+1
sta SPI_IO+IO_SR
lda #spi_p::STATUS::XFER
sta status
rts
.endproc
.endproc .endproc

View File

@ -1,9 +1,9 @@
;******************************************************************************** ;;********************************************************************************
; @module string ;; @module string
; @type utility ;; @type utility
; @details ;; @details
; String utility ;; String utility
;******************************************************************************** ;;********************************************************************************
.ifndef INCLUDE_STRING .ifndef INCLUDE_STRING
INCLUDE_STRING = 1 INCLUDE_STRING = 1
@ -29,15 +29,15 @@ Import str, hex_char_to_uint8, hex_str_to_uint, uint8_to_hex_str
.endif .endif
.endmacro .endmacro
;******************************************************************************** ;;********************************************************************************
; @function Macro for passing arguments to strf ;; @function Macro for passing arguments to strf
; @param fmt: Format string address or string literal ;; @param fmt: Format string address or string literal
; @param out: Output string address ;; @param out: Output string address
; @param x0-x9: Additional parameters ;; @param x0-x9: Additional parameters
; @warning Addresses as additional paramters must be passed like this `#<addr,#>addr` ;; @warning Addresses as additional paramters must be passed like this `#<addr,#>addr`
; @modifies: A, X, Y ;; @modifies: A, X, Y
; @see strf ;; @see strf
;******************************************************************************** ;;********************************************************************************
.macro Strf fmt,out,x0,x1,x2,x3,x4,x5,x6,x7,x8,x9 .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 @N_ARGS .set 0 ; @ so that it doesnt break cheap labels
.if .match(fmt, "") ; fmt is a string literal -> store in rodata .if .match(fmt, "") ; fmt is a string literal -> store in rodata

View File

@ -2,21 +2,21 @@
Export str, strf Export str, strf
.code .code
;******************************************************************************** ;;********************************************************************************
; @function Format a string ;; @function Format a string
; @details ;; @details
; If there is no value to be read, the Pz will be set ;; If there is no value to be read, the Pz will be set
; Formats: ;; Formats:
; - x: unsigned hex integer (1 byte) -> 2 chars ;; - x: unsigned hex integer (1 byte) -> 2 chars
; - X: unsigned hex integer (2 byte) -> 4 chars TODO ;; - X: unsigned hex integer (2 byte) -> 4 chars TODO
; - u: unsigned decimal integer (1 byte) TODO ;; - u: unsigned decimal integer (1 byte) TODO
; - U: unsigned decimal integer (2 bytes) TODO ;; - U: unsigned decimal integer (2 bytes) TODO
; @param ARG0-1: Format string address ;; @param ARG0-1: Format string address
; @param ARG2-3: Output string address ;; @param ARG2-3: Output string address
; @param ARG4+: Additional parameters ;; @param ARG4+: Additional parameters
; @returns ;; @returns
; @modifies: A, X, Y ;; @modifies: A, X, Y
;******************************************************************************** ;;********************************************************************************
out_idx := str::out_idx out_idx := str::out_idx
fmt_idx := str::fmt_idx fmt_idx := str::fmt_idx
.proc strf .proc strf