ca65 V2.15 - Git f7cdfbf
Main file   : acia.s65
Current file: acia.s65

000000r 1                                 .setcpu "6502"
000000r 1                                 .include "zeropage.inc65"
000000r 2               .importzp RES
000000r 2               .importzp R0
000000r 2               .importzp R1
000000r 2               .importzp TMP0
000000r 2               .importzp TMP1
000000r 2               .importzp TMP_STACK
000000r 2               
000000r 1                                 .include "io.inc65"
000000r 2               ; CPU frequency
000000r 2               
000000r 2               F_CPU = 1000000
000000r 2               
000000r 2               ; ACIA registers
000000r 2               
000000r 2               ACIA_BASE    = $8200
000000r 2               ACIA_DATA    = ACIA_BASE
000000r 2               ACIA_STATUS  = ACIA_BASE + 1
000000r 2               ACIA_COMMAND = ACIA_BASE + 2
000000r 2               ACIA_CONTROL = ACIA_BASE + 3
000000r 2               
000000r 2               ; ACIA control register bit values
000000r 2               
000000r 2               ACIA_STOP_BITS_1 = %00000000
000000r 2               ACIA_STOP_BITS_2 = %10000000
000000r 2               ACIA_DATA_BITS_8 = %00000000
000000r 2               ACIA_DATA_BITS_7 = %00100000
000000r 2               ACIA_DATA_BITS_6 = %01000000
000000r 2               ACIA_DATA_BITS_5 = %01100000
000000r 2               ACIA_CLOCK_EXT   = %00000000
000000r 2               ACIA_CLOCK_INT   = %00010000
000000r 2               ACIA_BAUD_16XEXT = %00000000
000000r 2               ACIA_BAUD_50     = %00000001
000000r 2               ACIA_BAUD_75     = %00000010
000000r 2               ACIA_BAUD_109    = %00000011
000000r 2               ACIA_BAUD_134    = %00000100
000000r 2               ACIA_BAUD_150    = %00000101
000000r 2               ACIA_BAUD_300    = %00000110
000000r 2               ACIA_BAUD_600    = %00000111
000000r 2               ACIA_BAUD_1200   = %00001000
000000r 2               ACIA_BAUD_1800   = %00001001
000000r 2               ACIA_BAUD_2400   = %00001010
000000r 2               ACIA_BAUD_3600   = %00001011
000000r 2               ACIA_BAUD_4800   = %00001100
000000r 2               ACIA_BAUD_7200   = %00001101
000000r 2               ACIA_BAUD_9600   = %00001110
000000r 2               ACIA_BAUD_19200  = %00001111
000000r 2               
000000r 2               ; ACIA command register bit values
000000r 2               
000000r 2               ACIA_PARITY_ODD              = %00000000
000000r 2               ACIA_PARITY_EVEN             = %01000000
000000r 2               ACIA_PARITY_MARK             = %10000000
000000r 2               ACIA_PARITY_SPACE            = %11000000
000000r 2               ACIA_PARITY_DISABLE          = %00000000
000000r 2               ACIA_PARITY_ENABLE           = %00100000
000000r 2               ACIA_ECHO_DISABLE            = %00000000
000000r 2               ACIA_ECHO_ENABLE             = %00010000
000000r 2               ACIA_TX_INT_DISABLE_RTS_HIGH = %00000000
000000r 2               ACIA_TX_INT_ENABLE_RTS_LOW   = %00000100
000000r 2               ACIA_TX_INT_DISABLE_RTS_LOW  = %00001000
000000r 2               ACIA_TX_INT_DISABLE_BREAK    = %00001100
000000r 2               ACIA_RX_INT_ENABLE           = %00000000
000000r 2               ACIA_RX_INT_DISABLE          = %00000010
000000r 2               ACIA_DTR_HIGH                = %00000000
000000r 2               ACIA_DTR_LOW                 = %00000001
000000r 2               
000000r 2               ; ACIA status register bit masks
000000r 2               
000000r 2               ACIA_STATUS_IRQ        = 1 << 7
000000r 2               ACIA_STATUS_DSR        = 1 << 6
000000r 2               ACIA_STATUS_DCD        = 1 << 5
000000r 2               ACIA_STATUS_TX_EMPTY   = 1 << 4
000000r 2               ACIA_STATUS_RX_FULL    = 1 << 3
000000r 2               ACIA_STATUS_OVERRUN    = 1 << 2
000000r 2               ACIA_STATUS_FRAME_ERR  = 1 << 1
000000r 2               ACIA_STATUS_PARITY_ERR = 1 << 0
000000r 2               
000000r 2               ; VIA registers
000000r 2               
000000r 2               VIA1_BASE   = $8000
000000r 2               VIA1_ORB    = VIA1_BASE
000000r 2               VIA1_IRB    = VIA1_BASE
000000r 2               VIA1_ORA    = VIA1_BASE + 1
000000r 2               VIA1_IRA    = VIA1_BASE + 1
000000r 2               VIA1_DDRB   = VIA1_BASE + 2
000000r 2               VIA1_DDRA   = VIA1_BASE + 3
000000r 2               VIA1_T1C_L  = VIA1_BASE + 4
000000r 2               VIA1_T1C_H  = VIA1_BASE + 5
000000r 2               VIA1_T1L_L  = VIA1_BASE + 6
000000r 2               VIA1_T1L_H  = VIA1_BASE + 7
000000r 2               VIA1_T2C_L  = VIA1_BASE + 8
000000r 2               VIA1_T2C_H  = VIA1_BASE + 9
000000r 2               VIA1_SR     = VIA1_BASE + 10
000000r 2               VIA1_ACR    = VIA1_BASE + 11
000000r 2               VIA1_PCR    = VIA1_BASE + 12
000000r 2               VIA1_IFR    = VIA1_BASE + 13
000000r 2               VIA1_IER    = VIA1_BASE + 14
000000r 2               VIA1_ORA_NH = VIA1_BASE + 15
000000r 2               VIA1_IRA_NH = VIA1_BASE + 15
000000r 2               
000000r 2               VIA2_BASE   = $8100
000000r 2               VIA2_ORB    = VIA2_BASE
000000r 2               VIA2_IRB    = VIA2_BASE
000000r 2               VIA2_ORA    = VIA2_BASE + 1
000000r 2               VIA2_IRA    = VIA2_BASE + 1
000000r 2               VIA2_DDRB   = VIA2_BASE + 2
000000r 2               VIA2_DDRA   = VIA2_BASE + 3
000000r 2               VIA2_T1C_L  = VIA2_BASE + 4
000000r 2               VIA2_T1C_H  = VIA2_BASE + 5
000000r 2               VIA2_T1L_L  = VIA2_BASE + 6
000000r 2               VIA2_T1L_H  = VIA2_BASE + 7
000000r 2               VIA2_T2C_L  = VIA2_BASE + 8
000000r 2               VIA2_T2C_H  = VIA2_BASE + 9
000000r 2               VIA2_SR     = VIA2_BASE + 10
000000r 2               VIA2_ACR    = VIA2_BASE + 11
000000r 2               VIA2_PCR    = VIA2_BASE + 12
000000r 2               VIA2_IFR    = VIA2_BASE + 13
000000r 2               VIA2_IER    = VIA2_BASE + 14
000000r 2               VIA2_ORA_NH = VIA2_BASE + 15
000000r 2               VIA2_IRA_NH = VIA2_BASE + 15
000000r 2               
000000r 2               ; Port bits
000000r 2               
000000r 2               VIA_PA0 = (1 << 0)
000000r 2               VIA_PA1 = (1 << 1)
000000r 2               VIA_PA2 = (1 << 2)
000000r 2               VIA_PA3 = (1 << 3)
000000r 2               VIA_PA4 = (1 << 4)
000000r 2               VIA_PA5 = (1 << 5)
000000r 2               VIA_PA6 = (1 << 6)
000000r 2               VIA_PA7 = (1 << 7)
000000r 2               
000000r 2               ; Port bits
000000r 2               
000000r 2               VIA_PB0 = 1 << 0
000000r 2               VIA_PB1 = 1 << 1
000000r 2               VIA_PB2 = 1 << 2
000000r 2               VIA_PB3 = 1 << 3
000000r 2               VIA_PB4 = 1 << 4
000000r 2               VIA_PB5 = 1 << 5
000000r 2               VIA_PB6 = 1 << 6
000000r 2               VIA_PB7 = 1 << 7
000000r 2               
000000r 2               ; SID registers
000000r 2               
000000r 2               SID_BASE = $8300
000000r 2               SID_VOICE1_FREQ_L = SID_BASE
000000r 2               SID_VOICE1_FREQ_H = SID_BASE + 1
000000r 2               SID_VOICE1_PW_L   = SID_BASE + 2
000000r 2               SID_VOICE1_PW_H   = SID_BASE + 3
000000r 2               SID_VOICE1_CTRL   = SID_BASE + 4
000000r 2               SID_VOICE1_AD     = SID_BASE + 5
000000r 2               SID_VOICE1_SR     = SID_BASE + 6
000000r 2               SID_VOICE2_FREQ_L = SID_BASE + 7
000000r 2               SID_VOICE2_FREQ_H = SID_BASE + 8
000000r 2               SID_VOICE2_PW_L   = SID_BASE + 9
000000r 2               SID_VOICE2_PW_H   = SID_BASE + 10
000000r 2               SID_VOICE2_CTRL   = SID_BASE + 11
000000r 2               SID_VOICE2_AD     = SID_BASE + 12
000000r 2               SID_VOICE2_SR     = SID_BASE + 13
000000r 2               SID_VOICE3_FREQ_L = SID_BASE + 14
000000r 2               SID_VOICE3_FREQ_H = SID_BASE + 15
000000r 2               SID_VOICE3_PW_L   = SID_BASE + 16
000000r 2               SID_VOICE3_PW_H   = SID_BASE + 17
000000r 2               SID_VOICE3_CTRL   = SID_BASE + 18
000000r 2               SID_VOICE3_AD     = SID_BASE + 19
000000r 2               SID_VOICE3_SR     = SID_BASE + 20
000000r 2               SID_FC_L          = SID_BASE + 21
000000r 2               SID_FC_H          = SID_BASE + 22
000000r 2               SID_RES_FILT      = SID_BASE + 23
000000r 2               SID_MODE_VOLUME   = SID_BASE + 24
000000r 2               SID_POTX          = SID_BASE + 25
000000r 2               SID_POTY          = SID_BASE + 26
000000r 2               SID_OSC3        = SID_BASE + 27
000000r 2               SID_ENV3          = SID_BASE + 28
000000r 2               
000000r 2               ; LED
000000r 2               
000000r 2               LED_DDR = VIA1_DDRA
000000r 2               LED_OUT = VIA1_ORA
000000r 2               LED     = VIA_PA7
000000r 2               
000000r 1                                 .include "macros.inc65"
000000r 2               ; Push X
000000r 2               .macro phx
000000r 2                 sta TMP_STACK
000000r 2                 txa
000000r 2                 pha
000000r 2                 lda TMP_STACK
000000r 2               .endmacro
000000r 2               
000000r 2               ; Push Y
000000r 2               .macro phy
000000r 2                 sta TMP_STACK
000000r 2                 tya
000000r 2                 pha
000000r 2                 lda TMP_STACK
000000r 2               .endmacro
000000r 2               
000000r 2               ; Push X and Y
000000r 2               .macro phxy
000000r 2                 sta TMP_STACK
000000r 2                 txa
000000r 2                 pha
000000r 2                 tya
000000r 2                 pha
000000r 2                 lda TMP_STACK
000000r 2               .endmacro
000000r 2               
000000r 2               ; Push A and X
000000r 2               .macro phax
000000r 2                 sta TMP_STACK
000000r 2                 pha
000000r 2                 txa
000000r 2                 pha
000000r 2                 lda TMP_STACK
000000r 2               .endmacro
000000r 2               
000000r 2               ; Push A and Y
000000r 2               .macro phay
000000r 2                 sta TMP_STACK
000000r 2                 pha
000000r 2                 tya
000000r 2                 pha
000000r 2                 lda TMP_STACK
000000r 2               .endmacro
000000r 2               
000000r 2               ; Push A, X and Y
000000r 2               .macro phaxy
000000r 2                 sta TMP_STACK
000000r 2                 pha
000000r 2                 txa
000000r 2                 pha
000000r 2                 tya
000000r 2                 pha
000000r 2                 lda TMP_STACK
000000r 2               .endmacro
000000r 2               
000000r 2               ; Pull X
000000r 2               .macro plx
000000r 2                 sta TMP_STACK
000000r 2                 pla
000000r 2                 tax
000000r 2                 lda TMP_STACK
000000r 2               .endmacro
000000r 2               
000000r 2               ; Pull Y
000000r 2               .macro ply
000000r 2                 sta TMP_STACK
000000r 2                 pla
000000r 2                 tay
000000r 2                 lda TMP_STACK
000000r 2               .endmacro
000000r 2               
000000r 2               ; Pull X and Y
000000r 2               .macro plxy
000000r 2                 sta TMP_STACK
000000r 2                 pla
000000r 2                 tay
000000r 2                 pla
000000r 2                 tax
000000r 2                 lda TMP_STACK
000000r 2               .endmacro
000000r 2               
000000r 2               ; Pull A and X
000000r 2               .macro plax
000000r 2                 pla
000000r 2                 tax
000000r 2                 pla
000000r 2               .endmacro
000000r 2               
000000r 2               ; Pull A and Y
000000r 2               .macro play
000000r 2                 pla
000000r 2                 tay
000000r 2                 pla
000000r 2               .endmacro
000000r 2               
000000r 2               ; Pull A, X and Y
000000r 2               .macro plaxy
000000r 2                 pla
000000r 2                 tay
000000r 2                 pla
000000r 2                 tax
000000r 2                 pla
000000r 2               .endmacro
000000r 2               
000000r 2               ; Load zero page register reg/reg+1 with the 16-bit value, destroys A
000000r 2               .macro ld16 reg, value
000000r 2                 lda #<(value)
000000r 2                 sta reg
000000r 2                 lda #>(value)
000000r 2                 sta reg + 1
000000r 2               .endmacro
000000r 2               
000000r 1               
000000r 1                                 ACIA_BUFFER_LENGTH = 10
000000r 1               
000000r 1                                 .export acia_init
000000r 1                                 .export acia_getc
000000r 1                                 .export acia_gets
000000r 1                                 .export acia_gets_buffer
000000r 1                                 .export acia_putc
000000r 1                                 .export acia_puts
000000r 1                                 .export acia_put_newline
000000r 1               
000000r 1                                 .bss
000000r 1               
000000r 1  00 00 00 00  acia_gets_buffer: .res ACIA_BUFFER_LENGTH + 1, 0
000004r 1  00 00 00 00  
000008r 1  00 00 00     
00000Br 1               
00000Br 1                                 .code
000000r 1               
000000r 1               ; Initialize the ACIA
000000r 1  48           acia_init:        pha
000001r 1  A9 0B                          lda #(ACIA_PARITY_DISABLE | ACIA_ECHO_DISABLE | ACIA_TX_INT_DISABLE_RTS_LOW | ACIA_RX_INT_DISABLE | ACIA_DTR_LOW)
000003r 1  8D 02 82                       sta ACIA_COMMAND
000006r 1  A9 1F                          lda #(ACIA_STOP_BITS_1 | ACIA_DATA_BITS_8 | ACIA_CLOCK_INT | ACIA_BAUD_19200)
000008r 1  8D 03 82                       sta ACIA_CONTROL
00000Br 1  68                             pla
00000Cr 1  60                             rts
00000Dr 1               
00000Dr 1               ; Send the character in A
00000Dr 1  48           acia_putc:        pha
00000Er 1  AD 01 82     wait_txd_empty:   lda ACIA_STATUS
000011r 1  29 10                          and #ACIA_STATUS_TX_EMPTY
000013r 1  F0 F9                          beq wait_txd_empty
000015r 1  68                             pla
000016r 1  8D 00 82                       sta ACIA_DATA
000019r 1  60                             rts
00001Ar 1               
00001Ar 1               ; Send the zero terminated string pointed to by R0
00001Ar 1  85 rr 48 98  acia_puts:        phay
00001Er 1  48 A5 rr     
000021r 1  A0 FF                          ldy #$ff
000023r 1  C8           next_char:        iny
000024r 1  B1 rr                          lda (R0),y
000026r 1  20 rr rr                       jsr acia_putc
000029r 1  D0 F8                          bne next_char
00002Br 1  68 A8 68                       play
00002Er 1  60                             rts
00002Fr 1               
00002Fr 1               ; Wait until a character was reveiced and return it in A
00002Fr 1               acia_getc:
00002Fr 1  AD 01 82     wait_rxd_full:    lda ACIA_STATUS
000032r 1  29 08                          and #ACIA_STATUS_RX_FULL
000034r 1  F0 F9                          beq wait_rxd_full
000036r 1  AD 00 82                       lda ACIA_DATA
000039r 1  60                             rts
00003Ar 1               
00003Ar 1               ; Wait until a \n terminated string was received and store it at (R0)
00003Ar 1               ; The accu contains the size of the buffer
00003Ar 1               ; The \n is removed and the string is zero terminated
00003Ar 1               ; After receiving buffer size - 1 characters, any following characters are discarded
00003Ar 1  85 rr        acia_gets:        sta TMP0
00003Cr 1  85 rr 48 98                    phay
000040r 1  48 A5 rr     
000043r 1  A0 00                          ldy #0
000045r 1  20 rr rr     gets_next_char:   jsr acia_getc
000048r 1  20 rr rr                       jsr acia_putc ;echo back to screen
00004Br 1  C9 0A                          cmp #$0a ;is it end of line?
00004Dr 1  F0 25                          beq gets_eos
00004Fr 1  C9 08                          cmp #$08 ;is it a backspace?
000051r 1  F0 0A                          beq gets_backspace
000053r 1  C4 rr        gets_buff_test:   cpy TMP0 ;is buffer full?
000055r 1  F0 EE                          beq gets_next_char
000057r 1  91 rr                          sta (R0),y
000059r 1  C8                             iny
00005Ar 1  4C rr rr                       jmp gets_next_char
00005Dr 1  88           gets_backspace:   dey ;decrement y
00005Er 1  30 0F                          bmi gets_reinit ;beyond start of line, reinitialize
000060r 1  A9 20                          lda #$20 ;replace backspace with space
000062r 1  91 rr                          sta (R0),y ;store space in buffer
000064r 1  20 rr rr                       jsr acia_putc ;blank out existing char on screen
000067r 1  A9 08                          lda #$08  ;backspace again to get correct position
000069r 1  20 rr rr                       jsr acia_putc
00006Cr 1  4C rr rr                       jmp gets_next_char
00006Fr 1  A5 rr        gets_reinit:      lda TMP0 ;restore a
000071r 1  4C rr rr                       jmp acia_gets ;start over
000074r 1  A9 00        gets_eos:         lda #0
000076r 1  91 rr                          sta (R0),y
000078r 1  68 A8 68                       play
00007Br 1  60                             rts
00007Cr 1               
00007Cr 1               ; Send a newline character
00007Cr 1  A9 0A        acia_put_newline: lda #$0a ;lf
00007Er 1  4C rr rr                       jmp acia_putc
00007Er 1               
