URL
                    https://opencores.org/ocsvn/rf6809/rf6809/trunk
                
            Subversion Repositories rf6809
[/] [rf6809/] [trunk/] [software/] [boot/] [serial.asm] - Rev 21
Compare with Previous | Blame | View Log
; ============================================================================; __; \\__/ o\ (C) 2022 Robert Finch, Waterloo; \ __ / All rights reserved.; \/_// robfinch<remove>@opencores.org; ||;;; Serial port routines for a WDC6551 compatible circuit.;; This source file is free software: you can redistribute it and/or modify; it under the terms of the GNU Lesser General Public License as published; by the Free Software Foundation, either version 3 of the License, or; (at your option) any later version.;; This source file is distributed in the hope that it will be useful,; but WITHOUT ANY WARRANTY; without even the implied warranty of; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the; GNU General Public License for more details.;; You should have received a copy of the GNU General Public License; along with this program. If not, see <http://www.gnu.org/licenses/>.;; ============================================================================;;------------------------------------------------------------------------------; Initialize serial port.;; Clear buffer indexes. Two bytes are used for the buffer index even though; only a single byte is needed. This is for convenience in calculating the; number of characters in the buffer, done later. The upper byte remains at; zero.; The port is initialized for 9600 baud, 1 stop bit and 8 bits data sent.; The internal baud rate generator is used.;; Parameters:; none; Modifies:; d; Returns:; none;------------------------------------------------------------------------------setdp $FFCInitSerial:SerialInit:pshs dprlda #$FFCtfr a,dprclraclrbclr SerHeadRcvclr SerTailRcvclr SerHeadXmitclr SerTailXmitclr SerRcvXonclr SerRcvXofflda COREIDsini1:cmpa IOFocusIDbne sini1ldb #$0B ; dtr,rts active, rxint enabled (bit 1=0), no paritystb ACIA+ACIA_CMDldb #$1E ; baud 9600, 1 stop bit, 8 bit, internal baud genstb ACIA+ACIA_CTRLldb #$0AC ; disable fifos (bit zero, one), reset fifosstb ACIA+ACIA_CTRL2puls dpr,pc;------------------------------------------------------------------------------; SerialGetChar;; Check the serial port buffer to see if there's a char available. If there's; a char available then return it. If the buffer is almost empty then send an; XON.;; Stack Space:; 3 words; Parameters:; none; Modifies:; none; Returns:; d = character or -1;------------------------------------------------------------------------------SerialGetChar:pshs ccr,x,y,dprlda #$FFCtfr a,dprsei ; disable interruptsbsr SerialRcvCount ; check number of chars in receive buffercmpb #8 ; less than 8?bhi sgc2ldb SerRcvXon ; skip sending XON if already sentbne sgc2 ; XON already sent?ldb #XON ; if <8 send an XONclr SerRcvXoff ; clear XOFF statusstb SerRcvXon ; flag so we don't send it multiple timesbsr SerialPutCharsgc2:ldb SerHeadRcv ; check if anything is in buffercmpb SerTailRcvbeq sgcNoChars ; no?leax SerRcvBuf ; x = buffer addressclraldb b,x ; get byte from bufferinc SerHeadRcv ; 4k wrap aroundbra sgcXitsgcNoChars:ldd #-1sgcXit:puls ccr,x,y,dpr,pc;------------------------------------------------------------------------------; SerialPeekChar;; Check the serial port buffer to see if there's a char available. If there's; a char available then return it. But don't update the buffer indexes. No need; to send an XON here.;; Stack Space:; 2 words; Parameters:; none; Modifies:; none; Returns:; d = character or -1;------------------------------------------------------------------------------SerialPeekChar:pshs x,ccr,dprlda #$FFCtfr a,dprseildb SerHeadRcv ; check if anything is in buffercmpb SerTailRcvbeq spcNoChars ; no?leax SerRcvBufclraldb b,x ; get byte from bufferbra spcXitspcNoChars:ldd #-1spcXit:puls x,ccr,dpr,pc;------------------------------------------------------------------------------; SerialPeekChar; Get a character directly from the I/O port. This bypasses the input; buffer.;; Stack Space:; 0 words; Parameters:; none; Modifies:; d; Returns:; d = character or -1;------------------------------------------------------------------------------SerialPeekCharDirect:pshs ccr,dprlda #$FFCtfr a,dprlda COREID ; Ensure we have the IO Focuscmpa IOFocusIDbne spcd0001; Disallow interrupts between status read and rx read.seildb ACIA+ACIA_STATbitb #8 ; look for Rx not emptybeq spcd0001clraldb ACIA+ACIA_RXpuls ccr,dpr,pcspcd0001:ldd #-1puls ccr,dpr,pc;------------------------------------------------------------------------------; SerialPutChar; Put a character to the serial transmitter. This routine blocks until the; transmitter is empty.;; Stack Space; 0 words; Parameters:; b = character to put; Modifies:; none;------------------------------------------------------------------------------SerialPutChar:pshs a,ccr,dprlda #$FFCtfr a,dprspc0001:lda COREID ; Ensure we have the IO Focuscmpa IOFocusIDbne spc0001cli ; provide a window for an interrupt to occursei; Between the status read and the transmit do not allow an; intervening interrupt.lda ACIA+ACIA_STAT ; wait until the uart indicates tx emptybita #16 ; bit #4 of the status regbeq spc0001 ; branch if transmitter is not emptystb ACIA+ACIA_TX ; send the bytepuls a,ccr,dpr,pc;------------------------------------------------------------------------------; Calculate number of character in input buffer. Direct page must be set; already.;; Parameters:; none; Returns:; d = number of bytes in buffer.;------------------------------------------------------------------------------SerialRcvCount:clraldb SerTailRcvsubb SerHeadRcvbge srcXitldd #$1000subd SerHeadRcvaddd SerTailRcvsrcXit:rts;------------------------------------------------------------------------------; Serial IRQ routine;; Keeps looping as long as it finds characters in the ACIA recieve buffer/fifo.; Received characters are buffered. If the buffer becomes full, new characters; will be lost.;; Parameters:; none; Modifies:; d,x; Returns:; none;------------------------------------------------------------------------------SerialIRQ:pshs dpr ; set direct page register to boot variableslda #$FFCtfr a,dprlda PIC+$D3 ; Serial active interrupt flagbeq notSerIntsirqNxtByte:ldb ACIA+ACIA_IRQS ; look for IRQsbpl notSerInt ; quick test for any irqsldb ACIA+ACIA_STAT ; check the statusbitb #$08 ; bit 3 = rx full (not empty)beq notRxInt1ldb ACIA+ACIA_RX ; get data from Rx buffer to clear interruptlda SerTailRcv ; check if recieve buffer fullincacmpa SerHeadRcvbeq sirqRxFullsta SerTailRcv ; update tail pointerdeca ; backupexg a,bleax SerRcvBuf ; x = buffer addresssta b,x ; store recieved byte in buffertst SerRcvXoff ; check if xoff already sentbne sirqNxtBytebsr SerialRcvCount ; if more than 4070 chars in buffercmpb #4070blo sirqNxtByteldb #XOFF ; send an XOFFclr SerRcvXon ; clear XON statusstb SerRcvXoff ; set XOFF statusstb ACIA+ACIA_TXbra sirqNxtByte ; check the status for another byte; Process other serial IRQsnotRxInt1:puls dpr,pcsirqRxFull:notRxInt:notSerInt:puls dpr,pcnmeSerial:fcb "Serial",0;------------------------------------------------------------------------------; Put a string to the serial port.;; Parameters:; d = pointer to string; Modifies:; none; Returns:; none;------------------------------------------------------------------------------SerialPutString:pshs d,xtfr d,xsps2:ldb ,xbeq spsXitinxbsr SerialPutCharbra sps2spsXit:puls d,x,pc;------------------------------------------------------------------------------; A little routine to test serial output.;; Parameters:; none; Modifies:; none; Returns:; none;------------------------------------------------------------------------------SerialOutputTest:pshs dldd #msgSerialTestlbsr DisplayStringbsr SerialInitsotst1:ldb #XONbsr SerialPutCharbsr SerialPutCharbsr SerialPutCharldd #msgSerialTestbsr SerialPutStringlbsr INCHcmpb #CTRLCbne sotst1puls d,pcmsgSerialTest:fcb "Serial port test",CR,LF,0setdp $000

