base:xmodem-receive
no way to compare when less than two revisions
Differences
This shows you the differences between two versions of the page.
— | base:xmodem-receive [2015-04-17 04:34] (current) – created - external edit 127.0.0.1 | ||
---|---|---|---|
Line 1: | Line 1: | ||
+ | ====== XMODEM/CRC receive ====== | ||
+ | < | ||
+ | ; XMODEM/CRC Receiver for the 65C02 | ||
+ | ; | ||
+ | ; By Daryl Rictor & Ross Archer | ||
+ | ; | ||
+ | ; 21st century code for 20th century CPUs (tm?) | ||
+ | ; | ||
+ | ; A simple file transfer program to allow upload from a console device | ||
+ | ; to the SBC utilizing the x-modem/CRC transfer protocol. | ||
+ | ; under 1k of either RAM or ROM, 132 bytes of RAM for the receive buffer, | ||
+ | ; and 8 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 uploaded via XMODEM-CRC must be | ||
+ | ; in .o64 format -- the first two bytes are the load address in | ||
+ | ; little-endian format: | ||
+ | ; FIRST BLOCK | ||
+ | ; | ||
+ | ; | ||
+ | ; | ||
+ | ; | ||
+ | ; | ||
+ | ; Subsequent blocks | ||
+ | ; | ||
+ | ; | ||
+ | ; The TASS assembler and most Commodore 64-based tools generate this | ||
+ | ; data format automatically and you can transfer their .obj/.o64 output | ||
+ | ; file directly. | ||
+ | ; | ||
+ | ; The only time you need to do anything special is if you have | ||
+ | ; a raw memory image file (say you want to load a data | ||
+ | ; table into memory). For XMODEM you'll have to | ||
+ | ; " | ||
+ | ; Otherwise, XMODEM would have no idea where to start putting | ||
+ | ; the data. | ||
+ | |||
+ | ; | ||
+ | ; | ||
+ | ; zero page variables (adjust these to suit your needs) | ||
+ | ; | ||
+ | ; | ||
+ | crc = $38 ; | ||
+ | crch = $39 ; | ||
+ | |||
+ | ptr = $3a ; | ||
+ | ptrh = $3b ; | ||
+ | |||
+ | blkno = $3c ; | ||
+ | retry = $3d ; | ||
+ | retry2 = $3e ; | ||
+ | bflag = $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 upload routine | ||
+ | ; By Daryl Rictor, July 31, 2002 | ||
+ | ; | ||
+ | ; v0.3 tested good minus CRC | ||
+ | ; v0.4 CRC fixed!!! init to $0000 rather than $FFFF as stated | ||
+ | ; v0.5 added CRC tables vs. generation at run time | ||
+ | ; v 1.0 recode for use with SBC2 | ||
+ | ; v 1.1 added block 1 masking (block 257 would be corrupted) | ||
+ | |||
+ | *= $7B00 ; Start of program (adjust to your needs) | ||
+ | ; | ||
+ | XModem 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 ; | ||
+ | lda # | ||
+ | sta crc ; | ||
+ | sta crch ; | ||
+ | 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 Done ; | ||
+ | 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 ldy # | ||
+ | CalcCrc lda Rbuff, | ||
+ | jsr UpdCrc ; | ||
+ | iny ; | ||
+ | cpy # | ||
+ | bne 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 ; | ||
+ | Done lda # | ||
+ | jsr Put_Chr ; | ||
+ | jsr Flush ; | ||
+ | jsr Print_Good ; | ||
+ | rts ; | ||
+ | ; | ||
+ | ; | ||
+ | ; | ||
+ | ; 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 " | ||
+ | .BYTE | ||
+ | .byte 0 | ||
+ | ; | ||
+ | ; | ||
+ | ; | ||
+ | ; 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 # | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | ; | ||
+ | ; | ||
+ | ; | ||
+ | ; CRC subroutines | ||
+ | ; | ||
+ | ; | ||
+ | UpdCrc 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 | ||
+ | rts | ||
+ | ; | ||
+ | ; 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) | ||
+ | *= $7D00 | ||
+ | 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) | ||
+ | *= $7E00 | ||
+ | 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-receive.txt · Last modified: 2015-04-17 04:34 by 127.0.0.1