]> cloudbase.mooo.com Git - avrcpm.git/blame - avr/sw-uart.asm
* Renamed Z80int.asm to 8080int-orig.asm
[avrcpm.git] / avr / sw-uart.asm
CommitLineData
9c15f366
L
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
31srx_state:
32 .byte 1
33srx_char_to:
34 .byte 1
35srx_dr:
36 .byte 1
37;srx_lastedge:
38; .byte 2
39stx_bitcount:
40 .byte 1
41stx_dr:
42 .byte 1
43rxcount:
44 .byte 1
45rxidx_w:
46 .byte 1
47rxidx_r:
48 .byte 1
49txcount:
50 .byte 1
51txidx_w:
52 .byte 1
53txidx_r:
54 .byte 1
55rxfifo:
56 .byte RXBUFSIZE
57txfifo:
58 .byte TXBUFSIZE
59
60
61 .cseg
62
63; Init
64uart_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
9c15f366 86
4675c141
L
87; Timer/Counter1 Input Capture interrupt
88
89 INTERRUPT ICP1addr
9c15f366
L
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
fa9059af 122 sts srx_dr,_0
9c15f366
L
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
137srxi_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
163srxi_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
fa9059af
L
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
174srxi_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
9c15f366
L
180srxi_1be:
181 sts srx_dr,temp
182 ldi temp,2
183 sts srx_state,temp
184 rjmp srxi_end2
185
186srxi_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
204srxi_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
224srxi_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
237srxi_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
244srxi_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
264srxi_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
277srxi_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
284srxi_complete0:
285 sts srx_char_to,_0 ;clear timeout
286 sts srx_state,_0 ;next state
287srxi_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
313srxi_ov: ;endif
314
315srxi_end2:
316 pop temp2
317srxi_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
9c15f366 329
4675c141
L
330; Timer/Counter1 Compare Match A interrupt
331
332 INTERRUPT OC1Aaddr
9c15f366
L
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
360stxi_0:
361 outm8 TCCR1A,zh
362 pop zh
363 pop temp
364 out sreg,temp
365 pop temp
366 reti
367
368; more characters?
369stxi_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
399stxi_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
412srx_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
fa9059af 419 sts srx_state,_0 ;next state
9c15f366
L
420 push temp
421
422#if 0
423 ldi temp,'|'
424 rcall uartputc
425#endif
fa9059af
L
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
432srxto_store:
9c15f366
L
433 mov zl,temp
434 com zl
435 andi zl,0x80
436srxto_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
459srxto_ov: ;endif
9c15f366
L
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
467uartgetc:
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
495uartputc:
496 push zh
497 push zl
498 in zl,sreg
499 push zl
500 push temp
501sputc_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
527sputc_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
537uart_wait_empty:
538 push temp
539uwe_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