]> cloudbase.mooo.com Git - avrcpm.git/blob - sw-uart.asm
Test branch for FAT16
[avrcpm.git] / 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 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
136 srxi_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
162 srxi_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
169 srxi_1be:
170 sts srx_dr,temp
171 ldi temp,2
172 sts srx_state,temp
173 rjmp srxi_end2
174
175 srxi_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
193 srxi_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
213 srxi_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
226 srxi_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
233 srxi_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
253 srxi_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
266 srxi_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
273 srxi_complete0:
274 sts srx_char_to,_0 ;clear timeout
275 sts srx_state,_0 ;next state
276 srxi_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
302 srxi_ov: ;endif
303
304 srxi_end2:
305 pop temp2
306 srxi_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
318
319 ; Timer/Counter1 Compare Match A interrupt
320
321 INTERRUPT OC1Aaddr
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
349 stxi_0:
350 outm8 TCCR1A,zh
351 pop zh
352 pop temp
353 out sreg,temp
354 pop temp
355 reti
356
357 ; more characters?
358 stxi_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
388 stxi_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
401 srx_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
418 srxto_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
441 srxto_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
450 uartgetc:
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
478 uartputc:
479 push zh
480 push zl
481 in zl,sreg
482 push zl
483 push temp
484 sputc_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
510 sputc_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
520 uart_wait_empty:
521 push temp
522 uwe_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