-
Notifications
You must be signed in to change notification settings - Fork 8
/
Copy pathxmodem.s
377 lines (344 loc) · 8.86 KB
/
xmodem.s
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
;#######################################################################
; Xmodem Routines
;#######################################################################
;-----------------------------------------------------------------------
; Receive a byte over the serial connection.
RXBYTE SUBROUTINE
.norx
LDX RXBUFR
CPX RXBUFW
BEQ .norx
; Handle new byte
LDA RXBUF,X ; new character
INC RXBUFR ; acknowledge byte by incrementing
RTS
;-----------------------------------------------------------------------
; Flush the receive buffer
RXFLUSH SUBROUTINE
.rxflush
LDX RXBUFR
CPX RXBUFW
BEQ .rxempty ; loop till flushed
INC RXBUFR ; acknowledge byte by incrementing
JMP .rxflush
.rxempty
RTS
;-----------------------------------------------------------------------
; Initialize an XMODEM receive transfer.
XINITRX SUBROUTINE
LDA #1
STA XBLK ; reset block number to first block
LDA #0
STA XFINAL ; reset XMODEM final byte of transmission flag.
STA XABRT ; reset the abort flag
LDA #"C"
JSR SENDCH
RTS
;-----------------------------------------------------------------------
; Receive a block via XMODEM.
XRECV SUBROUTINE
.xrxstart
LDA #0
STA XCRC
STA XCRC+1
JSR RXBYTE
CMP #$1B ; ESC character
BNE .xrx
LDA #1
STA XABRT ; set abort flag
LDA #"X"
JMP XERROR
.xrx
CMP #$01 ; SOH character
BEQ .xrxdata0
CMP #$04 ; EOT character
BNE .xrxretry
; EOT recieved
LDA #1
STA XFINAL
JSR RXFLUSH ; flush RX buffer
JMP XACK ; send ACK and return
.xrxretry
JSR RXFLUSH
LDA #$15 ; NAK character
JSR SENDCH
; After sending NAK, check for keypress on terminal
.rxkey
LDA KBDNEW
BEQ .norxkey
LDA #$0
STA KBDNEW
LDA KBDBYTE
BMI .rxtrmkey ; Key's above $80 are special keys for the terminal
.rxtrmkey
CMP #$F0 ; $F0 - Menu key
BEQ .rxmenu
.norxkey
JMP .xrxstart
.xrxdata0
LDY #0
.xrxdata1
JSR RXBYTE
STA XBUF,Y
INY
CPY #$84 ; received entire block of 133 bytes?
BNE .xrxdata1
; we have received the full block into XBUF
LDY #0
LDA XBUF,Y ; get block number
CMP XBLK
BEQ .xrxblockchksm
LDA #"N"
JMP XERROR
.xrxblockchksm
EOR #$FF
INY
CMP XBUF,Y ; compare block number checksum
BEQ .xrxblockdata0
LDA #"K"
JMP XERROR
.xrxblockdata0
LDY #2
.xrxblockdata1
LDA XBUF,Y
JSR FINDXCRC
INY
CPY #$82 ; 128 bytes of data
BNE .xrxblockdata1
; we have calculated the CRC for the block of data
LDA XBUF,Y ; get block CRC hi byte
CMP XCRC+1
BNE .xrxretry
INY
LDA XBUF,Y
CMP XCRC
BNE .xrxretry
; At this point, we have a good block of data in XBLK
JMP XACK
.rxmenu
LDX #1
STX XABRT
RTS
;-----------------------------------------------------------------------
; Acknowledge receipt of XMODEM block.
XACK SUBROUTINE
INC XBLK ; increment block counter
LDA #$06 ; ACK character
JSR SENDCH ; send ACK
RTS
;-----------------------------------------------------------------------
; Initialize an XMODEM send transfer.
XINITTX SUBROUTINE
LDA #0
STA XFINAL ; reset XMODEM final byte of transmission flag.
LDA #1
STA XBLK ; reset block number to first block
LDX #$02 ; start data at buffer index 2
STX XBUFIX ; save XBUF index
.xinittx
JSR RXBYTE
CMP #"C"
BNE .xesctx
; received the "C" byte to begin the transfer
RTS
.xesctx
CMP #$1B ; ESC character
BNE .xinittx
LDA #"X"
JMP XERROR
;-----------------------------------------------------------------------
; Send accumulator byte via XMODEM.
XSEND SUBROUTINE
LDX XBUFIX ; Retrieve XBUF offset
STA XBUF,X ; send BASIC program byte to buffer
LDA XFINAL
CMP #1
BNE .xsendmore
.xsendfinal
INX
CPX #$82 ; buffer contain 128 bytes?
BEQ .xmit ; yes, then fetch CRC
LDA #0
STA XBUF,X ; fill rest of buffer with 0
JMP .xsendfinal ; loop until buffer filled
.xsendmore
INX
CPX #$82 ; buffer contain 128 bytes?
BEQ .xmit ; yes, then transmit block
STX XBUFIX ; Save new XBUF offset
RTS
.xmit
JMP XMIT
;-----------------------------------------------------------------------
; Start a new block.
XNEWTX SUBROUTINE
LDY #$AE
LDX #0
STX XERRCNT ; XMODEM error count
LDA XBLK
STA XBUF ; store block number in first byte of buffer
EOR #$FF
STA XBUF+1 ; store block number checksum in second byte
RTS
;-----------------------------------------------------------------------
; Transmit XMODEM block.
XMIT SUBROUTINE
JSR XNEWTX
LDA #0
STA XBUFIX ; reset the buffer index to 0
STA XCRC
STA XCRC+1
LDY #2
.crcbuf
LDA XBUF,Y
JSR FINDXCRC
INY
CPY #$82
BNE .crcbuf
LDA XCRC+1
STA XBUF,Y
INY
LDA XCRC
STA XBUF,Y
.xsendsoh
LDA #$01 ; SOH character
JSR SENDCH
; JSR HEXOUT
LDX #0
STX XBUFIX
.xsend
LDA XBUF,X
JSR SENDCH
; JSR HEXOUT
INC XBUFIX
LDX XBUFIX
CPX #$84 ; sent final byte?
BNE .xsend
JSR RXBYTE
CMP #$06 ; ACK character
BNE .xnak
; Block was sent successfully!
INC XBLK ; increment block number
LDX #$02 ; start data at buffer index 2 for next block
STX XBUFIX ; save XBUF index
LDA XFINAL
CMP #1
BNE .xmitexit
JMP XFINISH
.xmitexit
RTS ; return after transmitting
.xnak
CMP #$15 ; NAK character
BEQ .xerror
CMP #$1B ; ESC character
BEQ .xabort
.xerror
INC XERRCNT
LDA XERRCNT
CMP #$0A ; 10 errors?
BNE .xsendsoh ; if no, resend block
.xabort
LDA #"X"
JMP XERROR
;-----------------------------------------------------------------------
; Finish an XMODEM transfer by sending final block and the
; End of Transmission sequence.
XFINISH SUBROUTINE
LDX XBUFIX
CPX #$02 ; no data bytes?
BEQ .xtxeot
.xfinish
CPX #$82 ; buffer contain 128 bytes?
BNE .xfinfill
JSR XMIT ; transmit final block
JMP .xtxeot
.xfinfill
LDA #0
STA XBUF,X ; fill rest of buffer with 0
INX
JMP .xfinish
.xtxeot
INC XFINAL
LDX XFINAL
CPX #3 ; wait for ACK at most 3 times
BEQ .xtxdone
LDA #$04 ; EOT charachter
JSR SENDCH ; send EOT
JSR RXBYTE
CMP #$06 ; ACK character
BNE .xtxeot
.xtxdone
JSR RXFLUSH
RTS
;-----------------------------------------------------------------------
; Use the CRC lookup tables to determine the CRC.
FINDXCRC SUBROUTINE
EOR XCRC+1
TAX
LDA XCRC
EOR XCRCHI,X
STA XCRC+1
LDA XCRCLO,X
STA XCRC
RTS
;-----------------------------------------------------------------------
; Flush RX buffer, print error, and return.
XERROR SUBROUTINE
JSR PRINTCH ; Print the error indicator character in A
LDA #" "
JSR PRINTCH
JSR RXFLUSH
LDA #<X_ERROR
LDY #>X_ERROR
JSR PRINTSTR
RTS
;-----------------------------------------------------------------------
; XMODEM Control Characters
;SOH EQU #$01
;EOT EQU #$04
;ACK EQU #$06
;NAK EQU #$15
;CAN EQU #$18
;CR EQU #$0d
;LF EQU #$0a
;ESC EQU #$1b
;-----------------------------------------------------------------------
; CRC lookup table for low byte
XCRCLO
DC.B $00,$21,$42,$63,$84,$A5,$C6,$E7,$08,$29,$4A,$6B,$8C,$AD,$CE,$EF
DC.B $31,$10,$73,$52,$B5,$94,$F7,$D6,$39,$18,$7B,$5A,$BD,$9C,$FF,$DE
DC.B $62,$43,$20,$01,$E6,$C7,$A4,$85,$6A,$4B,$28,$09,$EE,$CF,$AC,$8D
DC.B $53,$72,$11,$30,$D7,$F6,$95,$B4,$5B,$7A,$19,$38,$DF,$FE,$9D,$BC
DC.B $C4,$E5,$86,$A7,$40,$61,$02,$23,$CC,$ED,$8E,$AF,$48,$69,$0A,$2B
DC.B $F5,$D4,$B7,$96,$71,$50,$33,$12,$FD,$DC,$BF,$9E,$79,$58,$3B,$1A
DC.B $A6,$87,$E4,$C5,$22,$03,$60,$41,$AE,$8F,$EC,$CD,$2A,$0B,$68,$49
DC.B $97,$B6,$D5,$F4,$13,$32,$51,$70,$9F,$BE,$DD,$FC,$1B,$3A,$59,$78
DC.B $88,$A9,$CA,$EB,$0C,$2D,$4E,$6F,$80,$A1,$C2,$E3,$04,$25,$46,$67
DC.B $B9,$98,$FB,$DA,$3D,$1C,$7F,$5E,$B1,$90,$F3,$D2,$35,$14,$77,$56
DC.B $EA,$CB,$A8,$89,$6E,$4F,$2C,$0D,$E2,$C3,$A0,$81,$66,$47,$24,$05
DC.B $DB,$FA,$99,$B8,$5F,$7E,$1D,$3C,$D3,$F2,$91,$B0,$57,$76,$15,$34
DC.B $4C,$6D,$0E,$2F,$C8,$E9,$8A,$AB,$44,$65,$06,$27,$C0,$E1,$82,$A3
DC.B $7D,$5C,$3F,$1E,$F9,$D8,$BB,$9A,$75,$54,$37,$16,$F1,$D0,$B3,$92
DC.B $2E,$0F,$6C,$4D,$AA,$8B,$E8,$C9,$26,$07,$64,$45,$A2,$83,$E0,$C1
DC.B $1F,$3E,$5D,$7C,$9B,$BA,$D9,$F8,$17,$36,$55,$74,$93,$B2,$D1,$F0
;-----------------------------------------------------------------------
; CRC lookup table for high byte
XCRCHI
DC.B $00,$10,$20,$30,$40,$50,$60,$70,$81,$91,$A1,$B1,$C1,$D1,$E1,$F1
DC.B $12,$02,$32,$22,$52,$42,$72,$62,$93,$83,$B3,$A3,$D3,$C3,$F3,$E3
DC.B $24,$34,$04,$14,$64,$74,$44,$54,$A5,$B5,$85,$95,$E5,$F5,$C5,$D5
DC.B $36,$26,$16,$06,$76,$66,$56,$46,$B7,$A7,$97,$87,$F7,$E7,$D7,$C7
DC.B $48,$58,$68,$78,$08,$18,$28,$38,$C9,$D9,$E9,$F9,$89,$99,$A9,$B9
DC.B $5A,$4A,$7A,$6A,$1A,$0A,$3A,$2A,$DB,$CB,$FB,$EB,$9B,$8B,$BB,$AB
DC.B $6C,$7C,$4C,$5C,$2C,$3C,$0C,$1C,$ED,$FD,$CD,$DD,$AD,$BD,$8D,$9D
DC.B $7E,$6E,$5E,$4E,$3E,$2E,$1E,$0E,$FF,$EF,$DF,$CF,$BF,$AF,$9F,$8F
DC.B $91,$81,$B1,$A1,$D1,$C1,$F1,$E1,$10,$00,$30,$20,$50,$40,$70,$60
DC.B $83,$93,$A3,$B3,$C3,$D3,$E3,$F3,$02,$12,$22,$32,$42,$52,$62,$72
DC.B $B5,$A5,$95,$85,$F5,$E5,$D5,$C5,$34,$24,$14,$04,$74,$64,$54,$44
DC.B $A7,$B7,$87,$97,$E7,$F7,$C7,$D7,$26,$36,$06,$16,$66,$76,$46,$56
DC.B $D9,$C9,$F9,$E9,$99,$89,$B9,$A9,$58,$48,$78,$68,$18,$08,$38,$28
DC.B $CB,$DB,$EB,$FB,$8B,$9B,$AB,$BB,$4A,$5A,$6A,$7A,$0A,$1A,$2A,$3A
DC.B $FD,$ED,$DD,$CD,$BD,$AD,$9D,$8D,$7C,$6C,$5C,$4C,$3C,$2C,$1C,$0C
DC.B $EF,$FF,$CF,$DF,$AF,$BF,$8F,$9F,$6E,$7E,$4E,$5E,$2E,$3E,$0E,$1E
X_ERROR
DC.B "XMODEM ERROR!",0