mirror of https://gitee.com/openkylin/linux.git
530 lines
13 KiB
Plaintext
530 lines
13 KiB
Plaintext
;.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
|
|
|
|
|
|
|