| ;.lib "axm" | |
| ; | |
| ;begin | |
| ;title "A2232 serial board driver" | |
| ; | |
| ;set modules "2232" | |
| ;set executable "2232.bin" | |
| ; | |
| ;;;;set nolink | |
| ; | |
| ;set temporary directory "t:" | |
| ; | |
| ;set assembly options "-m6502 -l60:t:list" | |
| ;set link options "bin"; loadadr" | |
| ;;;bin2c 2232.bin msc6502.h msc6502code | |
| ;end | |
| ; | |
| ; | |
| ; ### Commodore A2232 serial board driver for NetBSD by JM v1.3 ### | |
| ; | |
| ; - Created 950501 by JM - | |
| ; | |
| ; | |
| ; Serial board driver software. | |
| ; | |
| ; | |
| % Copyright (c) 1995 Jukka Marin <jmarin@jmp.fi>. | |
| % All rights reserved. | |
| % | |
| % Redistribution and use in source and binary forms, with or without | |
| % modification, are permitted provided that the following conditions | |
| % are met: | |
| % 1. Redistributions of source code must retain the above copyright | |
| % notice, and the entire permission notice in its entirety, | |
| % including the disclaimer of warranties. | |
| % 2. Redistributions in binary form must reproduce the above copyright | |
| % notice, this list of conditions and the following disclaimer in the | |
| % documentation and/or other materials provided with the distribution. | |
| % 3. The name of the author may not be used to endorse or promote | |
| % products derived from this software without specific prior | |
| % written permission. | |
| % | |
| % ALTERNATIVELY, this product may be distributed under the terms of | |
| % the GNU General Public License, in which case the provisions of the | |
| % GPL are required INSTEAD OF the above restrictions. (This clause is | |
| % necessary due to a potential bad interaction between the GPL and | |
| % the restrictions contained in a BSD-style copyright.) | |
| % | |
| % THIS SOFTWARE IS PROVIDED `AS IS'' AND ANY EXPRESS OR IMPLIED | |
| % WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES | |
| % OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | |
| % DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, | |
| % INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | |
| % (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR | |
| % SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
| % HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, | |
| % STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | |
| % ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED | |
| % OF THE POSSIBILITY OF SUCH DAMAGE. | |
| ; | |
| ; | |
| ; Bugs: | |
| ; | |
| ; - Can't send a break yet | |
| ; | |
| ; | |
| ; | |
| ; Edited: | |
| ; | |
| ; - 950501 by JM -> v0.1 - Created this file. | |
| ; - 951029 by JM -> v1.3 - Carrier Detect events now queued in a separate | |
| ; queue. | |
| ; | |
| ; | |
| CODE equ $3800 ; start address for program code | |
| CTL_CHAR equ $00 ; byte in ibuf is a character | |
| CTL_EVENT equ $01 ; byte in ibuf is an event | |
| EVENT_BREAK equ $01 | |
| EVENT_CDON equ $02 | |
| EVENT_CDOFF equ $03 | |
| EVENT_SYNC equ $04 | |
| XON equ $11 | |
| XOFF equ $13 | |
| VARBASE macro *starting_address ; was VARINIT | |
| _varbase set \1 | |
| endm | |
| VARDEF macro *name space_needs | |
| \1 equ _varbase | |
| _varbase set _varbase+\2 | |
| endm | |
| stz macro * address | |
| db $64,\1 | |
| endm | |
| stzax macro * address | |
| db $9e,<\1,>\1 | |
| endm | |
| biti macro * immediate value | |
| db $89,\1 | |
| endm | |
| smb0 macro * address | |
| db $87,\1 | |
| endm | |
| smb1 macro * address | |
| db $97,\1 | |
| endm | |
| smb2 macro * address | |
| db $a7,\1 | |
| endm | |
| smb3 macro * address | |
| db $b7,\1 | |
| endm | |
| smb4 macro * address | |
| db $c7,\1 | |
| endm | |
| smb5 macro * address | |
| db $d7,\1 | |
| endm | |
| smb6 macro * address | |
| db $e7,\1 | |
| endm | |
| smb7 macro * address | |
| db $f7,\1 | |
| endm | |
| ;-----------------------------------------------------------------------; | |
| ; ; | |
| ; stuff common for all ports, non-critical (run once / loop) ; | |
| ; ; | |
| DO_SLOW macro * port_number ; | |
| .local ; ; | |
| lda CIA+C_PA ; check all CD inputs ; | |
| cmp CommonCDo ; changed from previous accptd? ; | |
| beq =over ; nope, do nothing else here ; | |
| ; ; | |
| cmp CommonCDb ; bouncing? ; | |
| beq =nobounce ; nope -> ; | |
| ; ; | |
| sta CommonCDb ; save current state ; | |
| lda #64 ; reinitialize counter ; | |
| sta CommonCDc ; ; | |
| jmp =over ; skip CD save ; | |
| ; ; | |
| =nobounce dec CommonCDc ; no, decrement bounce counter ; | |
| bpl =over ; not done yet, so skip CD save ; | |
| ; ; | |
| =saveCD ldx CDHead ; get write index ; | |
| sta cdbuf,x ; save status in buffer ; | |
| inx ; ; | |
| cpx CDTail ; buffer full? ; | |
| .if ne ; no: preserve status: ; | |
| stx CDHead ; update index in RAM ; | |
| sta CommonCDo ; save state for the next check ; | |
| .end ; ; | |
| =over .end local ; | |
| endm ; | |
| ; | |
| ;-----------------------------------------------------------------------; | |
| ; port specific stuff (no data transfer) | |
| DO_PORT macro * port_number | |
| .local ; ; | |
| lda SetUp\1 ; reconfiguration request? ; | |
| .if ne ; yes: ; | |
| lda SoftFlow\1 ; get XON/XOFF flag ; | |
| sta XonOff\1 ; save it ; | |
| lda Param\1 ; get parameter ; | |
| ora #%00010000 ; use baud generator for Rx ; | |
| sta ACIA\1+A_CTRL ; store in control register ; | |
| stz OutDisable\1 ; enable transmit output ; | |
| stz SetUp\1 ; no reconfiguration no more ; | |
| .end ; ; | |
| ; ; | |
| lda InHead\1 ; get write index ; | |
| sbc InTail\1 ; buffer full soon? ; | |
| cmp #200 ; 200 chars or more in buffer? ; | |
| lda Command\1 ; get Command reg value ; | |
| and #%11110011 ; turn RTS OFF by default ; | |
| .if cc ; still room in buffer: ; | |
| ora #%00001000 ; turn RTS ON ; | |
| .end ; ; | |
| sta ACIA\1+A_CMD ; set/clear RTS ; | |
| ; ; | |
| lda OutFlush\1 ; request to flush output buffer; | |
| .if ne ; yessh! ; | |
| lda OutHead\1 ; get head ; | |
| sta OutTail\1 ; save as tail ; | |
| stz OutDisable\1 ; enable transmit output ; | |
| stz OutFlush\1 ; clear request ; | |
| .end | |
| .end local | |
| endm | |
| DO_DATA macro * port number | |
| .local | |
| lda ACIA\1+A_SR ; read ACIA status register ; | |
| biti [1<<3] ; something received? ; | |
| .if ne ; yes: ; | |
| biti [1<<1] ; framing error? ; | |
| .if ne ; yes: ; | |
| lda ACIA\1+A_DATA ; read received character ; | |
| bne =SEND ; not break -> ignore it ; | |
| ldx InHead\1 ; get write pointer ; | |
| lda #CTL_EVENT ; get type of byte ; | |
| sta ictl\1,x ; save it in InCtl buffer ; | |
| lda #EVENT_BREAK ; event code ; | |
| sta ibuf\1,x ; save it as well ; | |
| inx ; ; | |
| cpx InTail\1 ; still room in buffer? ; | |
| .if ne ; absolutely: ; | |
| stx InHead\1 ; update index in memory ; | |
| .end ; ; | |
| jmp =SEND ; go check if anything to send ; | |
| .end ; ; | |
| ; normal char received: ; | |
| ldx InHead\1 ; get write index ; | |
| lda ACIA\1+A_DATA ; read received character ; | |
| sta ibuf\1,x ; save char in buffer ; | |
| stzax ictl\1 ; set type to CTL_CHAR ; | |
| inx ; ; | |
| cpx InTail\1 ; buffer full? ; | |
| .if ne ; no: preserve character: ; | |
| stx InHead\1 ; update index in RAM ; | |
| .end ; ; | |
| and #$7f ; mask off parity if any ; | |
| cmp #XOFF ; XOFF from remote host? ; | |
| .if eq ; yes: ; | |
| lda XonOff\1 ; if XON/XOFF handshaking.. ; | |
| sta OutDisable\1 ; ..disable transmitter ; | |
| .end ; ; | |
| .end ; ; | |
| ; ; | |
| ; BUFFER FULL CHECK WAS HERE ; | |
| ; ; | |
| =SEND lda ACIA\1+A_SR ; transmit register empty? ; | |
| and #[1<<4] ; ; | |
| .if ne ; yes: ; | |
| ldx OutCtrl\1 ; sending out XON/XOFF? ; | |
| .if ne ; yes: ; | |
| lda CIA+C_PB ; check CTS signal ; | |
| and #[1<<\1] ; (for this port only) ; | |
| bne =DONE ; not allowed to send -> done ; | |
| stx ACIA\1+A_DATA ; transmit control char ; | |
| stz OutCtrl\1 ; clear flag ; | |
| jmp =DONE ; and we're done ; | |
| .end ; ; | |
| ; ; | |
| ldx OutTail\1 ; anything to transmit? ; | |
| cpx OutHead\1 ; ; | |
| .if ne ; yes: ; | |
| lda OutDisable\1 ; allowed to transmit? ; | |
| .if eq ; yes: ; | |
| lda CIA+C_PB ; check CTS signal ; | |
| and #[1<<\1] ; (for this port only) ; | |
| bne =DONE ; not allowed to send -> done ; | |
| lda obuf\1,x ; get a char from buffer ; | |
| sta ACIA\1+A_DATA ; send it away ; | |
| inc OutTail\1 ; update read index ; | |
| .end ; ; | |
| .end ; ; | |
| .end ; ; | |
| =DONE .end local | |
| endm | |
| PORTVAR macro * port number | |
| VARDEF InHead\1 1 | |
| VARDEF InTail\1 1 | |
| VARDEF OutDisable\1 1 | |
| VARDEF OutHead\1 1 | |
| VARDEF OutTail\1 1 | |
| VARDEF OutCtrl\1 1 | |
| VARDEF OutFlush\1 1 | |
| VARDEF SetUp\1 1 | |
| VARDEF Param\1 1 | |
| VARDEF Command\1 1 | |
| VARDEF SoftFlow\1 1 | |
| ; private: | |
| VARDEF XonOff\1 1 | |
| endm | |
| VARBASE 0 ; start variables at address $0000 | |
| PORTVAR 0 ; define variables for port 0 | |
| PORTVAR 1 ; define variables for port 1 | |
| PORTVAR 2 ; define variables for port 2 | |
| PORTVAR 3 ; define variables for port 3 | |
| PORTVAR 4 ; define variables for port 4 | |
| PORTVAR 5 ; define variables for port 5 | |
| PORTVAR 6 ; define variables for port 6 | |
| VARDEF Crystal 1 ; 0 = unknown, 1 = normal, 2 = turbo | |
| VARDEF Pad_a 1 | |
| VARDEF TimerH 1 | |
| VARDEF TimerL 1 | |
| VARDEF CDHead 1 | |
| VARDEF CDTail 1 | |
| VARDEF CDStatus 1 | |
| VARDEF Pad_b 1 | |
| VARDEF CommonCDo 1 ; for carrier detect optimization | |
| VARDEF CommonCDc 1 ; for carrier detect debouncing | |
| VARDEF CommonCDb 1 ; for carrier detect debouncing | |
| VARBASE $0200 | |
| VARDEF obuf0 256 ; output data (characters only) | |
| VARDEF obuf1 256 | |
| VARDEF obuf2 256 | |
| VARDEF obuf3 256 | |
| VARDEF obuf4 256 | |
| VARDEF obuf5 256 | |
| VARDEF obuf6 256 | |
| VARDEF ibuf0 256 ; input data (characters, events etc - see ictl) | |
| VARDEF ibuf1 256 | |
| VARDEF ibuf2 256 | |
| VARDEF ibuf3 256 | |
| VARDEF ibuf4 256 | |
| VARDEF ibuf5 256 | |
| VARDEF ibuf6 256 | |
| VARDEF ictl0 256 ; input control information (type of data in ibuf) | |
| VARDEF ictl1 256 | |
| VARDEF ictl2 256 | |
| VARDEF ictl3 256 | |
| VARDEF ictl4 256 | |
| VARDEF ictl5 256 | |
| VARDEF ictl6 256 | |
| VARDEF cdbuf 256 ; CD event queue | |
| ACIA0 equ $4400 | |
| ACIA1 equ $4c00 | |
| ACIA2 equ $5400 | |
| ACIA3 equ $5c00 | |
| ACIA4 equ $6400 | |
| ACIA5 equ $6c00 | |
| ACIA6 equ $7400 | |
| A_DATA equ $00 | |
| A_SR equ $02 | |
| A_CMD equ $04 | |
| A_CTRL equ $06 | |
| ; 00 write transmit data read received data | |
| ; 02 reset ACIA read status register | |
| ; 04 write command register read command register | |
| ; 06 write control register read control register | |
| CIA equ $7c00 ; 8520 CIA | |
| C_PA equ $00 ; port A data register | |
| C_PB equ $02 ; port B data register | |
| C_DDRA equ $04 ; data direction register for port A | |
| C_DDRB equ $06 ; data direction register for port B | |
| C_TAL equ $08 ; timer A | |
| C_TAH equ $0a | |
| C_TBL equ $0c ; timer B | |
| C_TBH equ $0e | |
| C_TODL equ $10 ; TOD LSB | |
| C_TODM equ $12 ; TOD middle byte | |
| C_TODH equ $14 ; TOD MSB | |
| C_DATA equ $18 ; serial data register | |
| C_INTCTRL equ $1a ; interrupt control register | |
| C_CTRLA equ $1c ; control register A | |
| C_CTRLB equ $1e ; control register B | |
| section main,code,CODE-2 | |
| db >CODE,<CODE | |
| ;-----------------------------------------------------------------------; | |
| ; here's the initialization code: ; | |
| ; ; | |
| R_RESET ldx #$ff ; | |
| txs ; initialize stack pointer ; | |
| cld ; in case a 6502 is used... ; | |
| ldx #0 ; ; | |
| lda #0 ; ; | |
| ldy #Crystal ; this many bytes to clear ; | |
| clr_loop sta 0,x ; clear zero page variables ; | |
| inx ; ; | |
| dey ; ; | |
| bne clr_loop ; ; | |
| ; ; | |
| stz CommonCDo ; force CD test at boot ; | |
| stz CommonCDb ; ; | |
| stz CDHead ; clear queue ; | |
| stz CDTail ; ; | |
| ; ; | |
| lda #0 ; ; | |
| sta Pad_a ; ; | |
| lda #170 ; test cmp ; | |
| cmp #100 ; ; | |
| .if cs ; ; | |
| inc Pad_a ; C was set ; | |
| .end ; ; | |
| ; | |
| ;-----------------------------------------------------------------------; | |
| ; Speed check ; | |
| ;-----------------------------------------------------------------------; | |
| ; | |
| lda Crystal ; speed already set? ; | |
| beq DoSpeedy ; ; | |
| jmp LOOP ; yes, skip speed test ; | |
| ; ; | |
| DoSpeedy lda #%10011000 ; 8N1, 1200/2400 bps ; | |
| sta ACIA0+A_CTRL ; ; | |
| lda #%00001011 ; enable DTR ; | |
| sta ACIA0+A_CMD ; ; | |
| lda ACIA0+A_SR ; read status register ; | |
| ; ; | |
| lda #%10000000 ; disable all ints (unnecessary); | |
| sta CIA+C_INTCTRL ; ; | |
| lda #255 ; program the timer ; | |
| sta CIA+C_TAL ; ; | |
| sta CIA+C_TAH ; ; | |
| ; ; | |
| ldx #0 ; ; | |
| stx ACIA0+A_DATA ; transmit a zero ; | |
| nop ; ; | |
| nop ; ; | |
| lda ACIA0+A_SR ; read status ; | |
| nop ; ; | |
| nop ; ; | |
| stx ACIA0+A_DATA ; transmit a zero ; | |
| Speedy1 lda ACIA0+A_SR ; read status ; | |
| and #[1<<4] ; transmit data reg empty? ; | |
| beq Speedy1 ; not yet, wait more ; | |
| ; ; | |
| lda #%00010001 ; load & start the timer ; | |
| stx ACIA0+A_DATA ; transmit one more zero ; | |
| sta CIA+C_CTRLA ; ; | |
| Speedy2 lda ACIA0+A_SR ; read status ; | |
| and #[1<<4] ; transmit data reg empty? ; | |
| beq Speedy2 ; not yet, wait more ; | |
| stx CIA+C_CTRLA ; stop the timer ; | |
| ; ; | |
| lda CIA+C_TAL ; copy timer value for 68k ; | |
| sta TimerL ; ; | |
| lda CIA+C_TAH ; ; | |
| sta TimerH ; ; | |
| cmp #$d0 ; turbo or normal? ; | |
| .if cs ; ; | |
| lda #2 ; turbo! :-) ; | |
| .else ; ; | |
| lda #1 ; normal :-( ; | |
| .end ; ; | |
| sta Crystal ; ; | |
| lda #0 ; ; | |
| sta ACIA0+A_SR ; ; | |
| sta ACIA0+A_CTRL ; reset UART ; | |
| sta ACIA0+A_CMD ; ; | |
| ; | |
| jmp LOOP ; | |
| ; | |
| ; ; | |
| ;-----------------------------------------------------------------------; | |
| ; ; | |
| ; The Real Thing: ; | |
| ; ; | |
| LOOP DO_SLOW ; do non-critical things ; | |
| jsr do_input ; check for received data | |
| DO_PORT 0 | |
| jsr do_input | |
| DO_PORT 1 | |
| jsr do_input | |
| DO_PORT 2 | |
| jsr do_input | |
| DO_PORT 3 | |
| jsr do_input | |
| DO_PORT 4 | |
| jsr do_input | |
| DO_PORT 5 | |
| jsr do_input | |
| DO_PORT 6 | |
| jsr do_input | |
| jmp LOOP | |
| do_input DO_DATA 0 | |
| DO_DATA 1 | |
| DO_DATA 2 | |
| DO_DATA 3 | |
| DO_DATA 4 | |
| DO_DATA 5 | |
| DO_DATA 6 | |
| rts | |
| ;-----------------------------------------------------------------------; | |
| section vectors,data,$3ffa | |
| dw $d0d0 | |
| dw R_RESET | |
| dw $c0ce | |
| ;-----------------------------------------------------------------------; | |
| end | |