; Serial port helper function ; Serial is handled by the 65c51n (this thing has a few bugs) .export serial_setup, serial_recv_char, serial_print_char, serial_baud_19200, serial_baud_9600 .include "hardware.inc" ; ----------------------------- ; Active wait loop calculations ; ----------------------------- INNER_LOOP = 9 ; Inner loop count (sets granularity of the waiting period) ; cycles per outer pass: ldx(2) + innerLoop(5*INNER_LOOP-1) + dey(2) + bne(3) PASS_CYC = INNER_LOOP * 5 + 6 ; passes for each 10bit frame (8N1), rounded up PASSES_19200 = (10 * CPU_HZ/19200 + PASS_CYC - 1) / PASS_CYC PASSES_9600 = (10 * CPU_HZ/9600 + PASS_CYC - 1) / PASS_CYC .assert PASSES_9600 < 256, error, "CPU clock too fast for this delay; raise INNER_LOOP" ; ACIA control register presets: internal BAUD, 8N1 SERIAL_CTRL_19200 = %00011111 SERIAL_CTRL_9600 = %00011110 ; ||||````- 19200/9600 baud ; |||`----- Receiver clock is baud rate ; |``------ 8bit word ; `-------- 1 stop bit ; ----------------------------- ; ----------------------------- .zeropage tx_passes: .res 1 ; Variable to store outer loop passes .code serial_setup: ; 65c51n has a few bugs. check http://forum.6502.org/viewtopic.php?f=4&t=2543&start=30#p29795 lda #$00 sta SERIAL_STATUS ; Write to the status register for program reset lda #$0b ; %0000 1011 sta SERIAL_COMMAND ; || |||`- Data terminal ready (DTRB low) ; || ||`-- IRQB disabled ; || ``--- RTSB low, transmit interrupt disabled ; |`------ Receiver normal mode ; `------- Parity disabled jsr serial_baud_19200 rts serial_baud_19200: lda #SERIAL_CTRL_19200 sta SERIAL_CONTROL lda #PASSES_19200 sta tx_passes rts serial_baud_9600: lda #SERIAL_CTRL_9600 sta SERIAL_CONTROL lda #PASSES_9600 sta tx_passes rts serial_recv_char: lda SERIAL_STATUS ; read status and #$08 ; mask receive status flag beq serial_recv_char; if buffer is empty, loop lda SERIAL_DATA ; get byte rts serial_print_char: sta SERIAL_DATA ; send character ;fall through to the delay routine serial_delay: phy ; save y reg phx ; save x register ldy tx_passes ; outer passes @ydelay: ldx #INNER_LOOP ; Init x register @xdelay: ; loop time was calculated above by the assembler dex ; decrement low index bne @xdelay ; loop back until x is 0 dey ; decrement high bne @ydelay ; loop until y is 0 @delay_done: plx ; return x ply ; return y rts