📄 ser_a2232fw.ax
字号:
;.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 codeCTL_CHAR equ $00 ; byte in ibuf is a characterCTL_EVENT equ $01 ; byte in ibuf is an eventEVENT_BREAK equ $01EVENT_CDON equ $02EVENT_CDOFF equ $03EVENT_SYNC equ $04XON equ $11XOFF equ $13VARBASE macro *starting_address ; was VARINIT_varbase set \1 endmVARDEF macro *name space_needs\1 equ _varbase_varbase set _varbase+\2 endmstz macro * address db $64,\1 endmstzax macro * address db $9e,<\1,>\1 endmbiti macro * immediate value db $89,\1 endmsmb0 macro * address db $87,\1 endmsmb1 macro * address db $97,\1 endmsmb2 macro * address db $a7,\1 endmsmb3 macro * address db $b7,\1 endmsmb4 macro * address db $c7,\1 endmsmb5 macro * address db $d7,\1 endmsmb6 macro * address db $e7,\1 endmsmb7 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 endmDO_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 endmPORTVAR 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 queueACIA0 equ $4400ACIA1 equ $4c00ACIA2 equ $5400ACIA3 equ $5c00ACIA4 equ $6400ACIA5 equ $6c00ACIA6 equ $7400A_DATA equ $00A_SR equ $02A_CMD equ $04A_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 registerCIA equ $7c00 ; 8520 CIAC_PA equ $00 ; port A data registerC_PB equ $02 ; port B data registerC_DDRA equ $04 ; data direction register for port AC_DDRB equ $06 ; data direction register for port BC_TAL equ $08 ; timer AC_TAH equ $0aC_TBL equ $0c ; timer BC_TBH equ $0eC_TODL equ $10 ; TOD LSBC_TODM equ $12 ; TOD middle byteC_TODH equ $14 ; TOD MSBC_DATA equ $18 ; serial data registerC_INTCTRL equ $1a ; interrupt control registerC_CTRLA equ $1c ; control register AC_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 LOOPdo_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
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -