]> cloudbase.mooo.com Git - avrcpm.git/blob - avr/sw-uart.asm
* avr/Z80int-jmp.asm
[avrcpm.git] / avr / sw-uart.asm
1 ; Serial interface using the ATmega8/88 USART.
2 ; This is part of the Z80-CP/M emulator written by Sprite_tm.
3 ;
4 ; Copyright (C) 2010 Leo C.
5 ;
6 ; This file is part of avrcpm.
7 ;
8 ; avrcpm is free software: you can redistribute it and/or modify it
9 ; under the terms of the GNU General Public License as published by
10 ; the Free Software Foundation, either version 3 of the License, or
11 ; (at your option) any later version.
12 ;
13 ; avrcpm is distributed in the hope that it will be useful,
14 ; but WITHOUT ANY WARRANTY; without even the implied warranty of
15 ; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 ; GNU General Public License for more details.
17 ;
18 ; You should have received a copy of the GNU General Public License
19 ; along with avrcpm. If not, see <http://www.gnu.org/licenses/>.
20 ;
21 ; $Id$
22 ;
23
24 #define SSER_BIT_TC (F_CPU+BAUD/2) / BAUD
25
26 #define RXBUFMASK RXBUFSIZE-1
27 #define TXBUFMASK TXBUFSIZE-1
28
29 .dseg
30
31 srx_state:
32 .byte 1
33 srx_char_to:
34 .byte 1
35 srx_dr:
36 .byte 1
37 ;srx_lastedge:
38 ; .byte 2
39 stx_bitcount:
40 .byte 1
41 stx_dr:
42 .byte 1
43 rxcount:
44 .byte 1
45 rxidx_w:
46 .byte 1
47 rxidx_r:
48 .byte 1
49 txcount:
50 .byte 1
51 txidx_w:
52 .byte 1
53 txidx_r:
54 .byte 1
55 rxfifo:
56 .byte RXBUFSIZE
57 txfifo:
58 .byte TXBUFSIZE
59
60
61 .cseg
62
63 ; Init
64 uart_init:
65
66 ; - Init clock/timer system and serial port
67
68 ; Init timer 1 as
69 ; - Soft UART TX (OC1A/OCR1A).
70 ; - Soft UART RX (ICP1/ICR1).
71 ; - 1ms System timer is already configured at this point.
72
73 ldi temp,(1<<COM1A1)|(1<<COM1A0) ;OC1A high on compare match (UART TX)
74 outm8 TCCR1A,temp
75
76 ldi temp,(1<<ICF1) ;clear pending int
77 out TIFR1,temp
78 inm8 temp,TIMSK1
79 ori temp,(1<<ICIE1) ;Enable input capture int. (UART RX)
80 outm8 TIMSK1,temp
81 ret
82
83 ;------------------------------------------------------------------
84
85 .cseg
86
87 ; Timer/Counter1 Input Capture interrupt
88
89 INTERRUPT ICP1addr
90
91 push temp
92 in temp,sreg
93 push temp
94 push zh
95 push zl
96 inm8 zl,ICR1L
97 inm8 zh,ICR1H
98 push temp2
99 ldi temp2,(1<<ICES1)
100 inm8 temp,TCCR1B
101 eor temp,temp2 ;toggle edge
102 outm8 TCCR1B,temp
103 ldi temp,(1<<ICF1) ;clear pending int
104 out TIFR1,temp
105
106 #if 0
107 lds temp,srx_state
108 subi temp,-'0'
109 rcall uartputc
110 lds temp,srx_dr
111 rcall printhex
112 #endif
113 lds temp,srx_state
114 cpi temp,0
115 brne srxi_S1
116
117 ; State 0: Wait for start bit
118
119 ; sts srx_lastedge,zl ;save beginning of start bit
120 ; sts srx_lastedge+1,zh
121 movw srx_lastedgel,zl
122 sts srx_dr,_0
123 ldi temp,1
124 sts srx_state,temp
125 ldi temp,2
126 sts srx_char_to,temp
127 sbis P_RXD-2,RXD ;RXD still low?
128 rjmp srxi_end2
129 ldi zl,(1<<ICNC1)|(1<<CS10) ;next edge is falling edge
130 outm8 TCCR1B,zl
131 ldi zh,(1<<ICF1) ;clear pending int
132 out TIFR1,zh
133 sts srx_state,_0
134 sts srx_char_to,_0
135 rjmp srxi_end2
136
137 srxi_S1:
138 cpi temp,1
139 brne srxi_S2
140
141 ; State 1: Check start bit (and collect 0-bits)
142
143 ; lds temp,srx_lastedge
144 ; lds temp2,srx_lastedge+1
145 ; sts srx_lastedge,zl
146 ; sts srx_lastedge+1,zh
147
148 movw temp,srx_lastedgel
149 movw srx_lastedgel,zl
150
151 sub zl,temp
152 sbc zh,temp2
153 subi zl,low ((SSER_BIT_TC+1)/2)
154 sbci zh,high((SSER_BIT_TC+1)/2)
155 brcs srxi_sberr
156
157 ; mov temp,zh
158 ; rcall printhex
159 ; mov temp,zl
160 ; rcall printhex
161
162 ldi temp,0x80
163 srxi_1l:
164 subi zl,low(SSER_BIT_TC)
165 sbci zh,high(SSER_BIT_TC)
166 brcs srxi_1be
167 lsr temp
168 brcc srxi_1l
169
170 subi zl,low(SSER_BIT_TC) ; stop bit?
171 sbci zh,high(SSER_BIT_TC)
172 brcc srxi_1fe
173 rjmp srxi_complete0 ; ok, x00 (^@) received
174 srxi_1fe:
175 sts srx_char_to,_0 ; no stop bit --> framing error --> break
176 sts srx_state,_0
177 sbr intstat,(1<<i_break)
178 rjmp srxi_end2
179
180 srxi_1be:
181 sts srx_dr,temp
182 ldi temp,2
183 sts srx_state,temp
184 rjmp srxi_end2
185
186 srxi_sberr:
187 ldi temp,(1<<ICNC1)|(1<<CS10) ;next edge is falling edge
188 outm8 TCCR1B,temp
189 ldi temp,(1<<ICF1) ;clear pending int
190 out TIFR1,temp
191 sts srx_state,_0 ;next state
192 #if 1
193 ldi temp,'?'
194 rcall uartputc
195 subi zl,low (-(SSER_BIT_TC+1)/2)
196 sbci zh,high(-(SSER_BIT_TC+1)/2)
197 mov temp,zh
198 rcall printhex
199 mov temp,zl
200 rcall printhex
201 #endif
202 rjmp srxi_end2
203
204 srxi_S2:
205 cpi temp,2
206 brne srxi_S3
207
208 ; State 2: collect 1-bits
209
210 ; lds temp,srx_lastedge
211 ; lds temp2,srx_lastedge+1
212 ; sts srx_lastedge,zl
213 ; sts srx_lastedge+1,zh
214
215 movw temp,srx_lastedgel
216 movw srx_lastedgel,zl
217
218 sub zl,temp
219 sbc zh,temp2
220 subi zl,low ((SSER_BIT_TC+1)/2)
221 sbci zh,high((SSER_BIT_TC+1)/2)
222
223 lds temp,srx_dr
224 srxi_2l:
225 sec ;one more 1 bit
226 ror temp
227 brcs srxi_complete1 ;8 bits recieved
228 subi zl,low(SSER_BIT_TC)
229 sbci zh,high(SSER_BIT_TC)
230 brcc srxi_2l
231
232 sts srx_dr,temp
233 ldi temp,3
234 sts srx_state,temp
235 rjmp srxi_end2
236
237 srxi_complete1:
238 ldi temp2,1 ;We are in start bit now.
239 sts srx_state,temp2
240 ldi temp2,2
241 sts srx_char_to,temp2
242 rjmp srxi_complete
243
244 srxi_S3:
245 cpi temp,3
246 brne srxi_S4
247
248 ; State 3: collect 0-bits
249
250 ; lds temp,srx_lastedge
251 ; lds temp2,srx_lastedge+1
252 ; sts srx_lastedge,zl
253 ; sts srx_lastedge+1,zh
254
255 movw temp,srx_lastedgel
256 movw srx_lastedgel,zl
257
258 sub zl,temp
259 sbc zh,temp2
260 subi zl,low ((SSER_BIT_TC+1)/2)
261 sbci zh,high((SSER_BIT_TC+1)/2)
262
263 lds temp,srx_dr
264 srxi_3l:
265 ;one more 0 bit
266 lsr temp
267 brcs srxi_complete0 ;8 bits recieved
268 subi zl,low(SSER_BIT_TC)
269 sbci zh,high(SSER_BIT_TC)
270 brcc srxi_3l
271
272 sts srx_dr,temp
273 ldi temp,2
274 sts srx_state,temp
275 rjmp srxi_end2
276
277 srxi_S4:
278 ldi zl,(1<<ICNC1)|(1<<CS10) ;next edge is falling edge
279 outm8 TCCR1B,zl
280 ldi zl,(1<<ICF1) ;clear pending int
281 sts srx_state,_0 ;next state
282 rjmp srxi_end2
283
284 srxi_complete0:
285 sts srx_char_to,_0 ;clear timeout
286 sts srx_state,_0 ;next state
287 srxi_complete:
288 #if 0
289 ldi zl,(1<<ICNC1)|(1<<CS10) ;next edge is falling edge
290 outm8 TCCR1B,zl
291 ldi zl,(1<<ICF1) ;clear pending int
292 out TIFR1,zl
293 #endif
294
295 ; Save received character in a circular buffer. Do nothing if buffer overflows.
296
297 lds zh,rxcount ;if rxcount < RXBUFSIZE
298 cpi zh,RXBUFSIZE ; (room for at least 1 char?)
299 brsh srxi_ov ;
300 inc zh ;
301 sts rxcount,zh ; rxcount++
302
303 ldi zl,low(rxfifo) ;
304 lds zh,rxidx_w ;
305 add zl,zh ;
306 inc zh ;
307 andi zh,RXBUFMASK ;
308 sts rxidx_w,zh ; rxidx_w = ++rxidx_w % RXBUFSIZE
309 ldi zh,high(rxfifo) ;
310 brcc PC+2 ;
311 inc zh ;
312 st z,temp ; rxfifo[rxidx_w] = char
313 srxi_ov: ;endif
314
315 srxi_end2:
316 pop temp2
317 srxi_end:
318 pop zl
319 pop zh
320 pop temp
321 out sreg,temp
322 pop temp
323 reti
324
325
326 ;----------------------------------------------------------------------
327
328 .cseg
329
330 ; Timer/Counter1 Compare Match A interrupt
331
332 INTERRUPT OC1Aaddr
333
334 push temp
335 in temp,sreg
336 push temp
337 push zh
338
339 inm8 temp,OCR1AL
340 inm8 zh,OCR1AH
341 subi temp,low(-SSER_BIT_TC)
342 sbci zh,high(-SSER_BIT_TC)
343 outm8 OCR1AH,zh
344 outm8 OCR1AL,temp
345 lds temp,stx_bitcount
346 tst temp
347 breq stxi_nxtchar
348
349 dec temp
350 sts stx_bitcount,temp
351 ldi zh,9 ;Start bit?
352 cp temp,zh
353 ldi zh,(1<<COM1A1)
354 breq stxi_0
355 lds temp,stx_dr
356 sbrs temp,0
357 ldi zh,(1<<COM1A1)|(1<<COM1A0)
358 lsr temp
359 sts stx_dr,temp
360 stxi_0:
361 outm8 TCCR1A,zh
362 pop zh
363 pop temp
364 out sreg,temp
365 pop temp
366 reti
367
368 ; more characters?
369 stxi_nxtchar:
370 lds temp,txcount ;if txcount != 0
371 tst temp ;
372 breq stxi_dis
373 ; get next char
374 push zl
375 dec temp ;
376 sts txcount,temp ; --txcount
377 ldi zl,low(txfifo) ;
378 ldi zh,high(txfifo) ;
379 lds temp,txidx_r ;
380 add zl,temp ;
381 brcc PC+2 ;
382 inc zh ;
383 inc temp ;
384 andi temp,TXBUFMASK ;
385 sts txidx_r,temp ;
386 ld temp,z
387 com temp
388 sts stx_dr,temp
389 ldi temp,10
390 sts stx_bitcount,temp
391 pop zl
392 pop zh
393 pop temp
394 out sreg,temp
395 pop temp
396 reti
397
398 ; disable transmitter
399 stxi_dis:
400 ldi temp,(1<<COM1A1)|(1<<COM1A0)
401 outm8 TCCR1A,temp
402 inm8 temp,TIMSK1
403 andi temp,~(1<<OCIE1A)
404 outm8 TIMSK1,temp
405 pop zh
406 pop temp
407 out sreg,temp
408 pop temp
409 reti
410 ;------------------------------------------------------------------
411
412 srx_to:
413 #if 0
414 ldi zl,(1<<ICNC1)|(1<<CS10) ;next edge is falling edge
415 outm8 TCCR1B,zl
416 ldi zl,(1<<ICF1) ;clear pending int
417 out TIFR1,zl
418 #endif
419 sts srx_state,_0 ;next state
420 push temp
421
422 #if 0
423 ldi temp,'|'
424 rcall uartputc
425 #endif
426 lds temp,srx_dr ;only 0 if timeout after leading edge of start bit.
427 tst temp
428 brne srxto_store
429 sbr intstat,(1<<i_break)
430 rjmp srxto_ov
431
432 srxto_store:
433 mov zl,temp
434 com zl
435 andi zl,0x80
436 srxto_l:
437 lsr temp
438 or temp,zl
439 brcc srxto_l
440
441 ; Save received character in a circular buffer. Do nothing if buffer overflows.
442
443 lds zh,rxcount ;if rxcount < RXBUFSIZE
444 cpi zh,RXBUFSIZE ; (room for at least 1 char?)
445 brsh srxto_ov ;
446 inc zh ;
447 sts rxcount,zh ; rxcount++
448
449 ldi zl,low(rxfifo) ;
450 lds zh,rxidx_w ;
451 add zl,zh ;
452 inc zh ;
453 andi zh,RXBUFMASK ;
454 sts rxidx_w,zh ; rxidx_w = ++rxidx_w % RXBUFSIZE
455 ldi zh,high(rxfifo) ;
456 brcc PC+2 ;
457 inc zh ;
458 st z,temp ; rxfifo[rxidx_w] = char
459 srxto_ov: ;endif
460
461 pop temp
462 ret
463
464
465 ;Fetches a char from the buffer to temp. If none available, waits till one is.
466
467 uartgetc:
468 lds temp,rxcount ;Number of characters in buffer
469 tst temp
470 breq uartgetc ;Wait for char
471
472 push zh
473 push zl
474 ldi zl,low(rxfifo)
475 ldi zh,high(rxfifo)
476 lds temp,rxidx_r
477 add zl,temp
478 brcc PC+2
479 inc zh
480 inc temp
481 andi temp,RXBUFMASK
482 sts rxidx_r,temp
483 cli
484 lds temp,rxcount
485 dec temp
486 sts rxcount,temp
487 sei
488 ld temp,z ;don't forget to get the char
489 pop zl
490 pop zh
491 ret
492
493 ;Sends a char from temp to the soft uart.
494
495 uartputc:
496 push zh
497 push zl
498 in zl,sreg
499 push zl
500 push temp
501 sputc_l:
502 lds temp,txcount ;do {
503 cpi temp,TXBUFSIZE ;
504 brsh sputc_l ;} while (txcount >= TXBUFSIZE)
505
506 ldi zl,low(txfifo) ;
507 ldi zh,high(txfifo) ;
508 lds temp,txidx_w ;
509 add zl,temp ;
510 brcc PC+2 ;
511 inc zh ;
512 inc temp ;
513 andi temp,TXBUFMASK ;
514 sts txidx_w,temp ; txidx_w = ++txidx_w % TXBUFSIZE
515 pop temp ;
516 st z,temp ; txfifo[txidx_w] = char
517 cli
518 lds zh,txcount
519 inc zh
520 sts txcount,zh
521 dec zh
522 brne sputc_e
523 ; Enable transmitter
524 inm8 zh,TIMSK1
525 ori zh,(1<<OCIE1A)
526 outm8 TIMSK1,zh
527 sputc_e:
528 pop zl
529 out sreg,zl
530 pop zl
531 pop zh
532 ret
533
534
535 ; Wait, till tx buffer is empty.
536
537 uart_wait_empty:
538 push temp
539 uwe_loop:
540 lds temp,txcount
541 tst temp
542 brne uwe_loop
543 pop temp
544 ret
545
546
547 ; vim:set ts=8 noet nowrap
548