base:xmodem-send_and_receive
no way to compare when less than two revisions
Differences
This shows you the differences between two versions of the page.
— | base:xmodem-send_and_receive [2015-04-17 04:34] (current) – created - external edit 127.0.0.1 | ||
---|---|---|---|
Line 1: | Line 1: | ||
+ | ====== XMODEM/CRC Send and Receive ====== | ||
+ | < | ||
+ | ; XMODEM/CRC Sender/ | ||
+ | ; | ||
+ | ; By Daryl Rictor Aug 2002 | ||
+ | ; | ||
+ | ; A simple file transfer program to allow transfers between the SBC and a | ||
+ | ; console device utilizing the x-modem/CRC transfer protocol. | ||
+ | ; ~1200 bytes of either RAM or ROM, 132 bytes of RAM for the receive buffer, | ||
+ | ; and 12 bytes of zero page RAM for variable storage. | ||
+ | ; | ||
+ | ; | ||
+ | ; This implementation of XMODEM/CRC does NOT conform strictly to the | ||
+ | ; XMODEM protocol standard in that it (1) does not accurately time character | ||
+ | ; reception or (2) fall back to the Checksum mode. | ||
+ | ; (1) For timing, it uses a crude timing loop to provide approximate | ||
+ | ; delays. | ||
+ | ; found that CPU clock speed of up to 5MHz also work but may not in | ||
+ | ; every case. Windows HyperTerminal worked quite well at both speeds! | ||
+ | ; | ||
+ | ; (2) Most modern terminal programs support XMODEM/CRC which can detect a | ||
+ | ; wider range of transmission errors so the fallback to the simple checksum | ||
+ | ; calculation was not implemented to save space. | ||
+ | ; | ||
+ | ; | ||
+ | ; Files transferred via XMODEM-CRC will have the load address contained in | ||
+ | ; the first two bytes in little-endian format: | ||
+ | ; FIRST BLOCK | ||
+ | ; | ||
+ | ; | ||
+ | ; | ||
+ | ; | ||
+ | ; | ||
+ | ; Subsequent blocks | ||
+ | ; | ||
+ | ; | ||
+ | ; One note, XMODEM send 128 byte blocks. | ||
+ | ; you wish to save is smaller than the 128 byte block boundary, then | ||
+ | ; the last block will be padded with zeros. | ||
+ | ; data will be written back to the original location. | ||
+ | ; padded zeros WILL also be written into RAM, which could overwrite other | ||
+ | ; data. | ||
+ | ; | ||
+ | ; | ||
+ | ; | ||
+ | ; zero page variables (adjust these to suit your needs) | ||
+ | ; | ||
+ | ; | ||
+ | lastblk = $35 ; | ||
+ | blkno = $36 ; | ||
+ | errcnt = $37 ; | ||
+ | bflag = $37 ; | ||
+ | |||
+ | crc = $38 ; | ||
+ | crch = $39 ; | ||
+ | |||
+ | ptr = $3a ; | ||
+ | ptrh = $3b ; | ||
+ | |||
+ | eofp = $3c ; | ||
+ | eofph = $3d ; | ||
+ | |||
+ | retry = $3e ; | ||
+ | retry2 = $3f ; | ||
+ | |||
+ | ; | ||
+ | ; | ||
+ | ; non-zero page variables and buffers | ||
+ | ; | ||
+ | ; | ||
+ | Rbuff = $0300 | ||
+ | ; | ||
+ | ; | ||
+ | ; | ||
+ | ; tables and constants | ||
+ | ; | ||
+ | ; | ||
+ | ; The crclo & crchi labels are used to point to a lookup table to calculate | ||
+ | ; the CRC for the 128 byte data blocks. | ||
+ | ; tables. | ||
+ | ; file) and the other is to build them at run-time. | ||
+ | ; then these two labels will need to be un-commented and declared in RAM. | ||
+ | ; | ||
+ | ; | ||
+ | ;crchi = $7E00 | ||
+ | ; | ||
+ | ; | ||
+ | ; | ||
+ | ; XMODEM Control Character Constants | ||
+ | SOH = $01 ; | ||
+ | EOT = $04 ; | ||
+ | ACK = $06 ; | ||
+ | NAK = $15 ; | ||
+ | CAN = $18 ; | ||
+ | CR = $0d ; | ||
+ | LF = $0a ; | ||
+ | ESC = $1b ; | ||
+ | |||
+ | ; | ||
+ | ; | ||
+ | ; | ||
+ | ; Xmodem/CRC transfer routines | ||
+ | ; By Daryl Rictor, August 8, 2002 | ||
+ | ; | ||
+ | ; v1.0 released on Aug 8, 2002. | ||
+ | ; | ||
+ | ; | ||
+ | *= $FA00 ; Start of program (adjust to your needs) | ||
+ | ; | ||
+ | ; Enter this routine with the beginning address stored in the zero page address | ||
+ | ; pointed to by ptr & ptrh and the ending address stored in the zero page address | ||
+ | ; pointed to by eofp & eofph. | ||
+ | ; | ||
+ | ; | ||
+ | jmp XmodemRcv ; | ||
+ | XModemSend jsr PrintMsg ; | ||
+ | lda # | ||
+ | sta errcnt ; | ||
+ | sta lastblk ; | ||
+ | lda # | ||
+ | sta blkno ; | ||
+ | Wait4CRC lda # | ||
+ | sta retry2 ; | ||
+ | jsr GetByte ; | ||
+ | bcc Wait4CRC ; | ||
+ | cmp #" | ||
+ | beq SetstAddr ; | ||
+ | cmp # | ||
+ | bne Wait4CRC ; | ||
+ | jmp PrtAbort ; | ||
+ | SetstAddr ldy # | ||
+ | ldx # | ||
+ | lda # | ||
+ | sta Rbuff ; | ||
+ | lda # | ||
+ | sta Rbuff+1 ; | ||
+ | lda ptr ; | ||
+ | sta Rbuff+2 ; | ||
+ | lda ptrh ; | ||
+ | sta Rbuff+3 ; | ||
+ | jmp Ldbuff1 ; | ||
+ | |||
+ | LdBuffer lda Lastblk ; | ||
+ | beq LdBuff0 ; | ||
+ | jmp Done ; yes, we're done | ||
+ | LdBuff0 ldx # | ||
+ | ldy # | ||
+ | inc Blkno ; | ||
+ | lda Blkno ; | ||
+ | sta Rbuff ; | ||
+ | eor # | ||
+ | sta Rbuff+1 ; | ||
+ | |||
+ | LdBuff1 lda (ptr), | ||
+ | sta Rbuff, | ||
+ | LdBuff2 sec ; | ||
+ | lda eofp ; | ||
+ | sbc ptr ; | ||
+ | bne LdBuff4 ; | ||
+ | lda eofph ; | ||
+ | sbc ptrh ; | ||
+ | bne LdBuff4 ; | ||
+ | inc LastBlk ; | ||
+ | LdBuff3 inx ; | ||
+ | cpx # | ||
+ | beq SCalcCRC ; | ||
+ | lda # | ||
+ | sta Rbuff, | ||
+ | beq LdBuff3 ; | ||
+ | |||
+ | LdBuff4 inc ptr ; | ||
+ | bne LdBuff5 ; | ||
+ | inc ptrh ; | ||
+ | LdBuff5 inx ; | ||
+ | cpx # | ||
+ | bne LdBuff1 ; | ||
+ | SCalcCRC jsr CalcCRC | ||
+ | lda crch ; | ||
+ | sta Rbuff, | ||
+ | iny ; | ||
+ | lda crc ; | ||
+ | sta Rbuff, | ||
+ | Resend ldx # | ||
+ | lda #SOH | ||
+ | jsr Put_chr ; | ||
+ | SendBlk lda Rbuff, | ||
+ | jsr Put_chr ; | ||
+ | inx ; | ||
+ | cpx # | ||
+ | bne SendBlk ; | ||
+ | lda # | ||
+ | sta retry2 ; | ||
+ | jsr GetByte ; | ||
+ | bcc Seterror ; | ||
+ | cmp # | ||
+ | beq LdBuffer ; | ||
+ | cmp # | ||
+ | beq Seterror ; | ||
+ | cmp # | ||
+ | beq PrtAbort ; | ||
+ | ; fall through to error counter | ||
+ | Seterror inc errcnt ; | ||
+ | lda errcnt ; | ||
+ | cmp # | ||
+ | bne Resend ; | ||
+ | PrtAbort jsr Flush ; | ||
+ | jmp Print_Err ; | ||
+ | Done Jmp Print_Good ; | ||
+ | ; | ||
+ | ; | ||
+ | ; | ||
+ | |||
+ | XModemRcv jsr PrintMsg ; | ||
+ | lda #$01 | ||
+ | sta blkno ; | ||
+ | sta bflag ; | ||
+ | StartCrc lda #" | ||
+ | jsr Put_Chr ; | ||
+ | lda #$FF | ||
+ | sta retry2 ; | ||
+ | lda #$00 | ||
+ | | ||
+ | sta crch ; | ||
+ | jsr GetByte ; | ||
+ | | ||
+ | bcc StartCrc ; | ||
+ | |||
+ | StartBlk lda # | ||
+ | sta retry2 ; | ||
+ | jsr GetByte ; | ||
+ | bcc StartBlk ; | ||
+ | GotByte cmp # | ||
+ | bne GotByte1 ; | ||
+ | ; | ||
+ | brk ; YES - do BRK or change to RTS if desired | ||
+ | GotByte1 | ||
+ | beq BegBlk ; | ||
+ | cmp # | ||
+ | bne BadCrc ; | ||
+ | jmp RDone ; | ||
+ | BegBlk ldx # | ||
+ | GetBlk lda # | ||
+ | sta retry2 ; | ||
+ | GetBlk1 jsr GetByte ; | ||
+ | bcc BadCrc ; | ||
+ | GetBlk2 sta Rbuff, | ||
+ | inx ; inc buffer pointer | ||
+ | cpx # | ||
+ | bne GetBlk ; | ||
+ | ldx # | ||
+ | lda Rbuff, | ||
+ | cmp blkno ; | ||
+ | beq GoodBlk1 ; | ||
+ | jsr Print_Err ; | ||
+ | jsr Flush ; | ||
+ | ; | ||
+ | brk ; unexpected block # - fatal error - BRK or RTS | ||
+ | GoodBlk1 eor # | ||
+ | inx ; | ||
+ | cmp Rbuff, | ||
+ | beq GoodBlk2 ; matched! | ||
+ | jsr Print_Err ; | ||
+ | jsr Flush ; mismatched - flush buffer and then do BRK | ||
+ | ; | ||
+ | brk ; bad 1's comp of block# | ||
+ | GoodBlk2 jsr CalcCRC ; | ||
+ | lda Rbuff, | ||
+ | cmp crch ; | ||
+ | bne BadCrc ; | ||
+ | iny ; | ||
+ | lda Rbuff, | ||
+ | cmp crc ; | ||
+ | beq GoodCrc ; | ||
+ | BadCrc jsr Flush ; | ||
+ | lda # | ||
+ | jsr Put_Chr ; | ||
+ | jmp StartBlk ; | ||
+ | GoodCrc ldx # | ||
+ | lda blkno ; | ||
+ | cmp # | ||
+ | bne CopyBlk ; | ||
+ | lda bflag ; | ||
+ | beq CopyBlk ; | ||
+ | lda Rbuff, | ||
+ | sta ptr ; | ||
+ | inx ; | ||
+ | lda Rbuff, | ||
+ | sta ptr+1 ; | ||
+ | inx ; point to first byte of data | ||
+ | dec bflag ; | ||
+ | CopyBlk ldy # | ||
+ | CopyBlk3 lda Rbuff, | ||
+ | sta (ptr), | ||
+ | inc ptr ; | ||
+ | bne CopyBlk4 ; | ||
+ | inc ptr+1 ; | ||
+ | CopyBlk4 inx ; | ||
+ | cpx # | ||
+ | bne CopyBlk3 ; | ||
+ | IncBlk inc blkno ; | ||
+ | lda # | ||
+ | jsr Put_Chr ; | ||
+ | jmp StartBlk ; | ||
+ | |||
+ | RDone lda # | ||
+ | jsr Put_Chr ; | ||
+ | jsr Flush ; | ||
+ | jsr Print_Good ; | ||
+ | rts ; | ||
+ | ; | ||
+ | ; | ||
+ | ; | ||
+ | ; I/O Device Specific Routines | ||
+ | ; | ||
+ | ; Two routines are used to communicate with the I/O device. | ||
+ | ; | ||
+ | ; " | ||
+ | ; return without waiting with the Carry flag CLEAR if no character is | ||
+ | ; present or return with the Carry flag SET and the character in the " | ||
+ | ; register if one was present. | ||
+ | ; | ||
+ | ; " | ||
+ | ; if this routine waits for the port to be ready. | ||
+ | ; character was send upon return from this routine. | ||
+ | ; | ||
+ | ; Here is an example of the routines used for a standard 6551 ACIA. | ||
+ | ; You would call the ACIA_Init prior to running the xmodem transfer | ||
+ | ; routine. | ||
+ | ; | ||
+ | ACIA_Data = $7F70 ; | ||
+ | ACIA_Status = $7F71 ; | ||
+ | ACIA_Command = $7F72 ; | ||
+ | ACIA_Control = $7F73 ; | ||
+ | |||
+ | ACIA_Init | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | ; | ||
+ | ; input chr from ACIA (no waiting) | ||
+ | ; | ||
+ | Get_Chr clc ; | ||
+ | | ||
+ | | ||
+ | beq Get_Chr2 ; | ||
+ | | ||
+ | | ||
+ | Get_Chr2 | ||
+ | ; | ||
+ | ; output to OutPut Port | ||
+ | ; | ||
+ | Put_Chr | ||
+ | Put_Chr1 | ||
+ | and # | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | ; | ||
+ | ; | ||
+ | ; subroutines | ||
+ | ; | ||
+ | ; | ||
+ | ; | ||
+ | GetByte lda # | ||
+ | sta retry ; | ||
+ | StartCrcLp jsr Get_chr ; | ||
+ | bcs GetByte1 ; | ||
+ | dec retry ; | ||
+ | bne StartCrcLp ; | ||
+ | dec retry2 ; | ||
+ | bne StartCrcLp ; | ||
+ | clc ; if loop times out, CLC, else SEC and return | ||
+ | GetByte1 rts ; | ||
+ | ; | ||
+ | Flush lda # | ||
+ | sta retry2 ; | ||
+ | Flush1 jsr GetByte ; | ||
+ | bcs Flush ; | ||
+ | rts ; else done | ||
+ | ; | ||
+ | PrintMsg ldx # | ||
+ | PrtMsg1 lda | ||
+ | beq PrtMsg2 | ||
+ | jsr Put_Chr | ||
+ | inx | ||
+ | bne PrtMsg1 | ||
+ | PrtMsg2 rts | ||
+ | Msg .byte " | ||
+ | .BYTE | ||
+ | | ||
+ | ; | ||
+ | Print_Err ldx # | ||
+ | PrtErr1 lda | ||
+ | beq PrtErr2 | ||
+ | jsr Put_Chr | ||
+ | inx | ||
+ | bne PrtErr1 | ||
+ | PrtErr2 rts | ||
+ | ErrMsg .byte " | ||
+ | .BYTE | ||
+ | .byte 0 | ||
+ | ; | ||
+ | Print_Good ldx # | ||
+ | Prtgood1 lda | ||
+ | beq Prtgood2 | ||
+ | jsr Put_Chr | ||
+ | inx | ||
+ | bne Prtgood1 | ||
+ | Prtgood2 rts | ||
+ | GoodMsg .byte EOT, | ||
+ | .byte " | ||
+ | .BYTE | ||
+ | .byte 0 | ||
+ | |||
+ | |||
+ | ; | ||
+ | ; | ||
+ | ; | ||
+ | ; | ||
+ | ; | ||
+ | ; CRC subroutines | ||
+ | ; | ||
+ | ; | ||
+ | CalcCRC lda # | ||
+ | sta crc ; | ||
+ | sta crch ; | ||
+ | ldy # | ||
+ | CalcCRC1 lda Rbuff, | ||
+ | eor crc+1 ; Quick CRC computation with lookup tables | ||
+ | | ||
+ | lda crc ; with the byte send in the " | ||
+ | eor CRCHI,X | ||
+ | sta crc+1 | ||
+ | lda CRCLO,X | ||
+ | sta crc | ||
+ | iny ; | ||
+ | cpy # | ||
+ | bne CalcCRC1 ; | ||
+ | rts ; y=82 on exit | ||
+ | ; | ||
+ | ; Alternate solution is to build the two lookup tables at run-time. | ||
+ | ; be desirable if the program is running from ram to reduce binary upload time. | ||
+ | ; The following code generates the data for the lookup tables. | ||
+ | ; un-comment the variable declarations for crclo & crchi in the Tables and Constants | ||
+ | ; section above and call this routine to build the tables before calling the | ||
+ | ; " | ||
+ | ; | ||
+ | ; | ||
+ | ; ldx #$00 | ||
+ | ; LDA #$00 | ||
+ | ; | ||
+ | ; sta crchi,x | ||
+ | ; inx | ||
+ | ; | ||
+ | ; ldx #$00 | ||
+ | ;fetch txa | ||
+ | ; | ||
+ | ; | ||
+ | ; ldy #$08 | ||
+ | ; | ||
+ | ; | ||
+ | ; | ||
+ | ; | ||
+ | ; eor #$10 | ||
+ | ; | ||
+ | ; | ||
+ | ; eor #$21 | ||
+ | ; | ||
+ | ; | ||
+ | ; | ||
+ | ; inx | ||
+ | ; | ||
+ | ; rts | ||
+ | ; | ||
+ | ; The following tables are used to calculate the CRC for the 128 bytes | ||
+ | ; in the xmodem data blocks. | ||
+ | ; store this program in ROM. If you choose to build them at run-time, | ||
+ | ; then just delete them and define the two labels: crclo & crchi. | ||
+ | ; | ||
+ | ; low byte CRC lookup table (should be page aligned) | ||
+ | *= $FD00 | ||
+ | crclo | ||
+ | .byte $00, | ||
+ | .byte $31, | ||
+ | .byte $62, | ||
+ | .byte $53, | ||
+ | .byte $C4, | ||
+ | .byte $F5, | ||
+ | .byte $A6, | ||
+ | .byte $97, | ||
+ | .byte $88, | ||
+ | .byte $B9, | ||
+ | .byte $EA, | ||
+ | .byte $DB, | ||
+ | .byte $4C, | ||
+ | .byte $7D, | ||
+ | .byte $2E, | ||
+ | .byte $1F, | ||
+ | |||
+ | ; hi byte CRC lookup table (should be page aligned) | ||
+ | *= $FE00 | ||
+ | crchi | ||
+ | .byte $00, | ||
+ | .byte $12, | ||
+ | .byte $24, | ||
+ | .byte $36, | ||
+ | .byte $48, | ||
+ | .byte $5A, | ||
+ | .byte $6C, | ||
+ | .byte $7E, | ||
+ | .byte $91, | ||
+ | .byte $83, | ||
+ | .byte $B5, | ||
+ | .byte $A7, | ||
+ | .byte $D9, | ||
+ | .byte $CB, | ||
+ | .byte $FD, | ||
+ | .byte $EF, | ||
+ | ; | ||
+ | ; | ||
+ | ; End of File | ||
+ | ; | ||
+ | </ |
base/xmodem-send_and_receive.txt · Last modified: 2015-04-17 04:34 by 127.0.0.1