]> cloudbase.mooo.com Git - avrcpm.git/blame - avr/sw-uart.asm
* cpm/Makefile
[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
122 ldi temp,1
123 sts srx_state,temp
124 ldi temp,2
125 sts srx_char_to,temp
126 sbis P_RXD-2,RXD ;RXD still low?
127 rjmp srxi_end2
128 ldi zl,(1<<ICNC1)|(1<<CS10) ;next edge is falling edge
129 outm8 TCCR1B,zl
130 ldi zh,(1<<ICF1) ;clear pending int
131 out TIFR1,zh
132 sts srx_state,_0
133 sts srx_char_to,_0
134 rjmp srxi_end2
135
136srxi_S1:
137 cpi temp,1
138 brne srxi_S2
139
140; State 1: Check start bit (and collect 0-bits)
141
142; lds temp,srx_lastedge
143; lds temp2,srx_lastedge+1
144; sts srx_lastedge,zl
145; sts srx_lastedge+1,zh
146
147 movw temp,srx_lastedgel
148 movw srx_lastedgel,zl
149
150 sub zl,temp
151 sbc zh,temp2
152 subi zl,low ((SSER_BIT_TC+1)/2)
153 sbci zh,high((SSER_BIT_TC+1)/2)
154 brcs srxi_sberr
155
156; mov temp,zh
157; rcall printhex
158; mov temp,zl
159; rcall printhex
160
161 ldi temp,0x80
162srxi_1l:
163 subi zl,low(SSER_BIT_TC)
164 sbci zh,high(SSER_BIT_TC)
165 brcs srxi_1be
166 lsr temp
167 brcc srxi_1l
168 rjmp srxi_complete
169srxi_1be:
170 sts srx_dr,temp
171 ldi temp,2
172 sts srx_state,temp
173 rjmp srxi_end2
174
175srxi_sberr:
176 ldi temp,(1<<ICNC1)|(1<<CS10) ;next edge is falling edge
177 outm8 TCCR1B,temp
178 ldi temp,(1<<ICF1) ;clear pending int
179 out TIFR1,temp
180 sts srx_state,_0 ;next state
181#if 1
182 ldi temp,'?'
183 rcall uartputc
184 subi zl,low (-(SSER_BIT_TC+1)/2)
185 sbci zh,high(-(SSER_BIT_TC+1)/2)
186 mov temp,zh
187 rcall printhex
188 mov temp,zl
189 rcall printhex
190#endif
191 rjmp srxi_end2
192
193srxi_S2:
194 cpi temp,2
195 brne srxi_S3
196
197; State 2: collect 1-bits
198
199; lds temp,srx_lastedge
200; lds temp2,srx_lastedge+1
201; sts srx_lastedge,zl
202; sts srx_lastedge+1,zh
203
204 movw temp,srx_lastedgel
205 movw srx_lastedgel,zl
206
207 sub zl,temp
208 sbc zh,temp2
209 subi zl,low ((SSER_BIT_TC+1)/2)
210 sbci zh,high((SSER_BIT_TC+1)/2)
211
212 lds temp,srx_dr
213srxi_2l:
214 sec ;one more 1 bit
215 ror temp
216 brcs srxi_complete1 ;8 bits recieved
217 subi zl,low(SSER_BIT_TC)
218 sbci zh,high(SSER_BIT_TC)
219 brcc srxi_2l
220
221 sts srx_dr,temp
222 ldi temp,3
223 sts srx_state,temp
224 rjmp srxi_end2
225
226srxi_complete1:
227 ldi temp2,1 ;We are in start bit now.
228 sts srx_state,temp2
229 ldi temp2,2
230 sts srx_char_to,temp2
231 rjmp srxi_complete
232
233srxi_S3:
234 cpi temp,3
235 brne srxi_S4
236
237; State 3: collect 0-bits
238
239; lds temp,srx_lastedge
240; lds temp2,srx_lastedge+1
241; sts srx_lastedge,zl
242; sts srx_lastedge+1,zh
243
244 movw temp,srx_lastedgel
245 movw srx_lastedgel,zl
246
247 sub zl,temp
248 sbc zh,temp2
249 subi zl,low ((SSER_BIT_TC+1)/2)
250 sbci zh,high((SSER_BIT_TC+1)/2)
251
252 lds temp,srx_dr
253srxi_3l:
254 ;one more 0 bit
255 lsr temp
256 brcs srxi_complete0 ;8 bits recieved
257 subi zl,low(SSER_BIT_TC)
258 sbci zh,high(SSER_BIT_TC)
259 brcc srxi_3l
260
261 sts srx_dr,temp
262 ldi temp,2
263 sts srx_state,temp
264 rjmp srxi_end2
265
266srxi_S4:
267 ldi zl,(1<<ICNC1)|(1<<CS10) ;next edge is falling edge
268 outm8 TCCR1B,zl
269 ldi zl,(1<<ICF1) ;clear pending int
270 sts srx_state,_0 ;next state
271 rjmp srxi_end2
272
273srxi_complete0:
274 sts srx_char_to,_0 ;clear timeout
275 sts srx_state,_0 ;next state
276srxi_complete:
277#if 0
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 out TIFR1,zl
282#endif
283
284; Save received character in a circular buffer. Do nothing if buffer overflows.
285
286 lds zh,rxcount ;if rxcount < RXBUFSIZE
287 cpi zh,RXBUFSIZE ; (room for at least 1 char?)
288 brsh srxi_ov ;
289 inc zh ;
290 sts rxcount,zh ; rxcount++
291
292 ldi zl,low(rxfifo) ;
293 lds zh,rxidx_w ;
294 add zl,zh ;
295 inc zh ;
296 andi zh,RXBUFMASK ;
297 sts rxidx_w,zh ; rxidx_w = ++rxidx_w % RXBUFSIZE
298 ldi zh,high(rxfifo) ;
299 brcc PC+2 ;
300 inc zh ;
301 st z,temp ; rxfifo[rxidx_w] = char
302srxi_ov: ;endif
303
304srxi_end2:
305 pop temp2
306srxi_end:
307 pop zl
308 pop zh
309 pop temp
310 out sreg,temp
311 pop temp
312 reti
313
314
315;----------------------------------------------------------------------
316
317 .cseg
9c15f366 318
4675c141
L
319; Timer/Counter1 Compare Match A interrupt
320
321 INTERRUPT OC1Aaddr
9c15f366
L
322
323 push temp
324 in temp,sreg
325 push temp
326 push zh
327
328 inm8 temp,OCR1AL
329 inm8 zh,OCR1AH
330 subi temp,low(-SSER_BIT_TC)
331 sbci zh,high(-SSER_BIT_TC)
332 outm8 OCR1AH,zh
333 outm8 OCR1AL,temp
334 lds temp,stx_bitcount
335 tst temp
336 breq stxi_nxtchar
337
338 dec temp
339 sts stx_bitcount,temp
340 ldi zh,9 ;Start bit?
341 cp temp,zh
342 ldi zh,(1<<COM1A1)
343 breq stxi_0
344 lds temp,stx_dr
345 sbrs temp,0
346 ldi zh,(1<<COM1A1)|(1<<COM1A0)
347 lsr temp
348 sts stx_dr,temp
349stxi_0:
350 outm8 TCCR1A,zh
351 pop zh
352 pop temp
353 out sreg,temp
354 pop temp
355 reti
356
357; more characters?
358stxi_nxtchar:
359 lds temp,txcount ;if txcount != 0
360 tst temp ;
361 breq stxi_dis
362; get next char
363 push zl
364 dec temp ;
365 sts txcount,temp ; --txcount
366 ldi zl,low(txfifo) ;
367 ldi zh,high(txfifo) ;
368 lds temp,txidx_r ;
369 add zl,temp ;
370 brcc PC+2 ;
371 inc zh ;
372 inc temp ;
373 andi temp,TXBUFMASK ;
374 sts txidx_r,temp ;
375 ld temp,z
376 com temp
377 sts stx_dr,temp
378 ldi temp,10
379 sts stx_bitcount,temp
380 pop zl
381 pop zh
382 pop temp
383 out sreg,temp
384 pop temp
385 reti
386
387; disable transmitter
388stxi_dis:
389 ldi temp,(1<<COM1A1)|(1<<COM1A0)
390 outm8 TCCR1A,temp
391 inm8 temp,TIMSK1
392 andi temp,~(1<<OCIE1A)
393 outm8 TIMSK1,temp
394 pop zh
395 pop temp
396 out sreg,temp
397 pop temp
398 reti
399;------------------------------------------------------------------
400
401srx_to:
402#if 0
403 ldi zl,(1<<ICNC1)|(1<<CS10) ;next edge is falling edge
404 outm8 TCCR1B,zl
405 ldi zl,(1<<ICF1) ;clear pending int
406 out TIFR1,zl
407#endif
408 push temp
409
410#if 0
411 ldi temp,'|'
412 rcall uartputc
413#endif
414 lds temp,srx_dr
415 mov zl,temp
416 com zl
417 andi zl,0x80
418srxto_l:
419 lsr temp
420 or temp,zl
421 brcc srxto_l
422
423; Save received character in a circular buffer. Do nothing if buffer overflows.
424
425 lds zh,rxcount ;if rxcount < RXBUFSIZE
426 cpi zh,RXBUFSIZE ; (room for at least 1 char?)
427 brsh srxto_ov ;
428 inc zh ;
429 sts rxcount,zh ; rxcount++
430
431 ldi zl,low(rxfifo) ;
432 lds zh,rxidx_w ;
433 add zl,zh ;
434 inc zh ;
435 andi zh,RXBUFMASK ;
436 sts rxidx_w,zh ; rxidx_w = ++rxidx_w % RXBUFSIZE
437 ldi zh,high(rxfifo) ;
438 brcc PC+2 ;
439 inc zh ;
440 st z,temp ; rxfifo[rxidx_w] = char
441srxto_ov: ;endif
442 sts srx_state,_0 ;next state
443
444 pop temp
445 ret
446
447
448;Fetches a char from the buffer to temp. If none available, waits till one is.
449
450uartgetc:
451 lds temp,rxcount ;Number of characters in buffer
452 tst temp
453 breq uartgetc ;Wait for char
454
455 push zh
456 push zl
457 ldi zl,low(rxfifo)
458 ldi zh,high(rxfifo)
459 lds temp,rxidx_r
460 add zl,temp
461 brcc PC+2
462 inc zh
463 inc temp
464 andi temp,RXBUFMASK
465 sts rxidx_r,temp
466 cli
467 lds temp,rxcount
468 dec temp
469 sts rxcount,temp
470 sei
471 ld temp,z ;don't forget to get the char
472 pop zl
473 pop zh
474 ret
475
476;Sends a char from temp to the soft uart.
477
478uartputc:
479 push zh
480 push zl
481 in zl,sreg
482 push zl
483 push temp
484sputc_l:
485 lds temp,txcount ;do {
486 cpi temp,TXBUFSIZE ;
487 brsh sputc_l ;} while (txcount >= TXBUFSIZE)
488
489 ldi zl,low(txfifo) ;
490 ldi zh,high(txfifo) ;
491 lds temp,txidx_w ;
492 add zl,temp ;
493 brcc PC+2 ;
494 inc zh ;
495 inc temp ;
496 andi temp,TXBUFMASK ;
497 sts txidx_w,temp ; txidx_w = ++txidx_w % TXBUFSIZE
498 pop temp ;
499 st z,temp ; txfifo[txidx_w] = char
500 cli
501 lds zh,txcount
502 inc zh
503 sts txcount,zh
504 dec zh
505 brne sputc_e
506; Enable transmitter
507 inm8 zh,TIMSK1
508 ori zh,(1<<OCIE1A)
509 outm8 TIMSK1,zh
510sputc_e:
511 pop zl
512 out sreg,zl
513 pop zl
514 pop zh
515 ret
516
517
518; Wait, till tx buffer is empty.
519
520uart_wait_empty:
521 push temp
522uwe_loop:
523 lds temp,txcount
524 tst temp
525 brne uwe_loop
526 pop temp
527 ret
528
529
530; vim:set ts=8 noet nowrap
531