URL
https://opencores.org/ocsvn/rf6809/rf6809/trunk
Subversion Repositories rf6809
[/] [rf6809/] [trunk/] [software/] [boot/] [xmodem.asm] - Rev 21
Compare with Previous | Blame | View Log
; ============================================================================; __; \\__/ o\ (C) 2022 Robert Finch, Waterloo; \ __ / All rights reserved.; \/_// robfinch<remove>@opencores.org; ||;;; BSD 3-Clause License; 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, this; list of conditions and the following disclaimer.;; 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. Neither the name of the copyright holder nor the names of its; contributors may be used to endorse or promote products derived from; this software without specific prior written permission.;; THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT HOLDER OR CONTRIBUTORS 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.;; ============================================================================;; Xmodem variables;xm_timer EQU $FFC020xm_protocol EQU $9F5xm_flag EQU $9F6xm_checksum EQU $9F7xm_tmp2 EQU $9F8xm_packetnum EQU $9FAxm_tmp EQU $9FCxm_crc EQU $9FExm_ibuf EQU $A00 ; to $A7Fxm_obuf EQU $A80 ; to $AFF; ------------------------------------------------------------------------------; Send data using XModem.; ------------------------------------------------------------------------------xm_SendStart:lbsr GetRangeldx mon_r1+2 ; x = buffer addresstfr x,uldb #1 ; packet numbers start at onestb xm_packetnum+1; Wait for receiver to send a NAKxm_send:ldd #-1 ; select blocking inputswifcb MF_INCHcmpb #NAK ; should have got a NAKbeq xm_send5cmpb #'C' ; or a 'C'bne xm_sendxm_send5:stb xm_protocolxm_send4:ldb #SOH ; send startswifcb OUTCHldb xm_packetnum+1 ; send packet numberswifcb MF_OUTCHcomb ; one's complementswifcb MF_OUTCH ; send packet number complementclra ; acca = byte counttfr x,u ; u = buffer addressxm_send1:ldb ,u+ ; grab a byte from the bufferswifcb MF_OUTCH ; send it outincacmpa #128 ; number of bytes in payloadblo xm_send1ldb xm_protocolcmpb #'C' ; CRC protocol?bne xm_send2bsr xm_calc_crc ; compute CRCldd xm_crc ; get crclsra ; transfer high eight bits first, sororb ; right shift D by eightlsrarorblsrarorblsrarorblsrarorblsrarorblsrarorblsrarorbswifcb MF_OUTCH ; send out the byteldd xm_crc ; get back CRCswifcb MF_OUTCH ; and send out low bytebra xm_send3xm_send2:bsr xm_calc_checksumldb xm_checksumswifcb MF_OUTCHxm_send3:swildd #-1 ; block until input is presentfcb MF_INCHcmpb #ACKbne xm_send4 ; not an ACK then resend the recordinc xm_packetnum ; increment packet numberleax 128,x ; advance buffer pointercmpx mon_r2+2blo xm_send4 ; go send next recordldb #EOT ; send end of transmissionswifcb MF_OUTCHswifcb MF_OUTCHswifcb MF_OUTCHrts; ------------------------------------------------------------------------------; Get a byte, checking for a receive timeout.;; Returns:; accb = byte (0 to 255) or -1 if timed out; ------------------------------------------------------------------------------xm_getbyte:xm_gb1:tst xm_timer ; check the timeout - 2048 ticks (3 seconds approx.)bmi xm_gb2clra ; non-blockingclrbswifcb MF_INCH ; try and get a characterbmi xm_gb1 ; if no character, try againbsr xm_outbyteAsHexrtsxm_gb2:ldb #-1rts; ------------------------------------------------------------------------------; XModem Receive;; Parameters:; none; Modifies:; All; Returns:; none; ------------------------------------------------------------------------------xm_ReceiveStart:lbsr Delay3s ; give a little bit of time for senderlbsr Delay3slbsr Delay3slbsr GetNumber ; Get the transfer addresststb ; Make sure we got a valuelbeq Monitorldx mon_numwka+2 ; X = transfer addressclr xm_packetnum ; initializelda #'C' ; try for CRC firststa xm_protocolxm_receive:lda #2 ; number of times to retry -1xm_rcv5:ldb xm_protocol ; indicate we want a transfer (send protocol byte)swifcb MF_SerialPutcharxm_rcv4:clr xm_timer ; clear the timeoutxm_rcv1:bsr xm_getbytetstbbmi xm_retry1 ; timeout on protocol id?cmpb #SOH ; it should be start of a transferbeq xm_SOHcmpb #EOTbeq xm_EOT ; or end of transfer (EOT)cmpb #CANbeq xm_receive ; might be a cancelcmpb #ETBbeq xm_EOTxm_rcv_nak: ; wasn't a valid start soldb #NAK ; send a NAKswifcb MF_SerialPutchar ; and try againbra xm_rcv4xm_SOH:bsr xm_getbyte ; get packet numberbmi xm_rcv_to1stb xm_packetnum+1pshs b ; save itbsr xm_getbyte ; get complement of packet numberbmi xm_rcv_to2addb ,s ; add the two valuesandb #$FF ; the sum should be $FFsubb #$FFstb xm_flag ; should be storing a zero if there is no errorldy #0 ; y = payload byte countertfr x,uxm_rcv2:bsr xm_getbytebmi xm_rcv_to1stb ,u+ ; store the byte to memoryinycmpy #128 ; 128 bytes per payloadblo xm_rcv2bsr xm_getbyte ; get checksum or CRC bytebmi xm_rcv_to1stb xm_tmp ; stuff checksum/CRC byteldb xm_protocolcmpb #'C'bne xm_rcv_chksumbsr xm_getbyte ; get low order CRC bytebmi xm_rcv_to1lda xm_tmp ; get the high byteaslb ; prepare to combine high and low orderaslbaslbaslblsra ; shift low nybble of acca into accbrorblsrarorblsrarorblsrarorbanda #$00F ; mask off any extra bitsstd xm_tmp2bsr xm_calc_crc ; compute the CRC-16 for the received dataldd xm_crc ; and compare to received valuecmpd xm_tmp2bra xm_rcv3xm_rcv_chksum:bsr xm_calc_checksumldb xm_checksumcmpb xm_tmp ; where we stuffed the bytexm_rcv3:bne xm_rcv_nak ; if not the same, NAKtst xm_flagbne xm_rcv_nak ; bad packet number?ldb #ACK ; packet recieved okay, send back an ACKswifcb MF_SerialPutcharldb xm_packetnum+1 ; did we receive the same packetcmpb xm_packetnumbeq xm_rcv4 ; same packet received, dont update buffer pointerstb xm_packetnum ; update last seen packet numberleax 128,x ; increment buffer pointerbra xm_rcv4 ; and go back for next packetxm_rcv_to2:leas 1,s ; get rid of stacked bytexm_rcv_to1:ldd #msgXmTimeoutswifcb MF_DisplayStringlbra Monitorxm_EOT: ; end of transmission received, returnldb #ACK ; ACK the EOTswifcb MF_SerialPutcharlbra Monitorxm_retry1:decabpl xm_rcv5lda xm_protocolcmpa #NAK ; are we already lowered down to checksum protocol?beq xm_noTransmitter ; did we try both checksum and CRC?lda #NAKsta xm_protocolbra xm_receivexm_noTransmitter:ldd #msgXmNoTransmitterswifcb MF_DisplayStringlbra MonitormsgXmTimeout:fcb "Xmodem: timed out",CR,LF,0msgXmNoTransmitter:fcb "XModem: transmitter not responding",CR,LF,0; ------------------------------------------------------------------------------; Calculate checksum value. The checksum is simply the low order eight bits of; the sum of all the bytes in the payload area.;; Stack space:; two words; Modifies:; xm_checksum contains the checksum value for the record; Parameters:; X = buffer address; Returns:; none; ------------------------------------------------------------------------------xm_calc_checksum:pshs d,xclraclrbxm_cs1:addb ,x+incacmpa #128blo xm_cs1andb #$FFstb xm_checksumpuls d,x,pc; ------------------------------------------------------------------------------; Compute CRC-16 of buffer.;;int calcrc(char *ptr, int count);{; int crc;; char i;; crc = 0;; while (--count >= 0); {; crc = crc ^ (int) (*ptr++ << 8);; i = 8;; do; {; if (crc & 0x8000); crc = crc << 1 ^ 0x1021;; else; crc = crc << 1;; } while(--i);; }; return (crc);;};; Modifies:; xm_crc variable; Parameters:; u = buffer address; Returns:; none; ------------------------------------------------------------------------------xm_calc_crc:pshs d,x,y,uclr xm_crcclr xm_crc+1ldu #0 ; u = byte countxm_crc1:ldb ,x+ ; get byteclr xm_tmp ; save in tempstb xm_tmp+1asl xm_tmp+1 ; shift temp eight bits to leftrol xm_tmpasl xm_tmp+1rol xm_tmpasl xm_tmp+1rol xm_tmpasl xm_tmp+1rol xm_tmpasl xm_tmp+1rol xm_tmpasl xm_tmp+1rol xm_tmpasl xm_tmp+1rol xm_tmpasl xm_tmp+1rol xm_tmpldd xm_crc ; crc = crc ^ tmpeora xm_tmpeorb xm_tmp+1std xm_crcldy #0xm_crc4:ldb xm_crc ; get high bytebitb #$8 ; check for $8000beq xm_crc2 ; no? then just go shiftldd xm_crc ; loadaslb ; shiftrolaeorb #$021 ; and xoreora #$001std xm_crc ; store it backbra xm_crc3xm_crc2:ldd xm_crc ; loadaslb ; shiftrolastd xm_crc ; and storexm_crc3:inycmpy #8 ; repeat eight timesblo xm_crc4leau 1,u ; increment byte countcmpu #128ldd xm_crc ; we want only a 16-bit CRCanda #$0Fstd xm_crcblo xm_crc1puls d,x,y,u,pcxm_outbyteAsHex:pshs dldd CharOutVec ; get current char out vectorpshs d ; save itldd #ScreenDisplayChar ; set output vector to screen displaystd CharOUtVecldd 2,s ; get passed datalbsr DispByteAsHex ; and display on-screenldb #' 'lbsr ScreenDisplayCharpuls d ; get back old char out vectorstd CharOutVec ; and restore itpuls d ; restore input argumentsrts
