]> cloudbase.mooo.com Git - avrcpm.git/blob - avrcpm/avr/hw-uart.asm
* New macros sbiw and INTERRUPT:
[avrcpm.git] / avrcpm / avr / hw-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 UBRR_VAL ((F_CPU+BAUD*8)/(BAUD*16)-1) /* clever rounding */
25
26 #define RXBUFMASK RXBUFSIZE-1
27 #define TXBUFMASK TXBUFSIZE-1
28
29 .dseg
30
31 rxcount:
32 .byte 1
33 rxidx_w:
34 .byte 1
35 rxidx_r:
36 .byte 1
37 txcount:
38 .byte 1
39 txidx_w:
40 .byte 1
41 txidx_r:
42 .byte 1
43 rxfifo:
44 .byte RXBUFSIZE
45 txfifo:
46 .byte TXBUFSIZE
47
48
49 .cseg
50 ; Init
51 uart_init:
52
53 ldi temp, (1<<TXEN0) | (1<<RXEN0) | (1<<RXCIE0)
54 outm8 UCSR0B,temp
55 .ifdef URSEL
56 ldi temp, (1<<URSEL) | (1<<UCSZ01) | (1<<UCSZ00)
57 .else
58 ldi temp, (1<<UCSZ01) | (1<<UCSZ00)
59 .endif
60 outm8 UCSR0C,temp
61 ldi temp, HIGH(UBRR_VAL)
62 outm8 UBRR0H,temp
63 ldi temp, LOW(UBRR_VAL)
64 outm8 UBRR0L,temp
65 ret
66
67 ; Save received character in a circular buffer. Do nothing if buffer overflows.
68
69 ; USART receive interrupt
70
71 INTERRUPT URXCaddr
72
73 push temp
74 in temp,sreg
75 push temp
76 push zh
77 push zl
78 inm8 temp,RXTXDR0
79 lds zh,rxcount ;if rxcount < RXBUFSIZE
80 cpi zh,RXBUFSIZE ; (room for at least 1 char?)
81 brsh rxi_ov ;
82 inc zh ;
83 sts rxcount,zh ; rxcount++
84
85 ldi zl,low(rxfifo) ;
86 lds zh,rxidx_w ;
87 add zl,zh ;
88 inc zh ;
89 andi zh,RXBUFMASK ;
90 sts rxidx_w,zh ; rxidx_w = ++rxidx_w % RXBUFSIZE
91 ldi zh,high(rxfifo) ;
92 brcc PC+2 ;
93 inc zh ;
94 st z,temp ; rxfifo[rxidx_w] = char
95 rxi_ov: ;endif
96 pop zl
97 pop zh
98 pop temp
99 out sreg,temp
100 pop temp
101 reti
102
103
104 ;Fetches a char from the buffer to temp. If none available, waits till one is.
105
106 uartgetc:
107 lds temp,rxcount ; Number of characters in buffer
108 tst temp
109 breq uartgetc ;Wait for char
110
111 push zh
112 push zl
113 ldi zl,low(rxfifo)
114 ldi zh,high(rxfifo)
115 lds temp,rxidx_r
116 add zl,temp
117 brcc PC+2
118 inc zh
119 inc temp
120 andi temp,RXBUFMASK
121 sts rxidx_r,temp
122 cli
123 lds temp,rxcount
124 dec temp
125 sts rxcount,temp
126 sei
127 ld temp,z ;don't forget to get the char
128 pop zl
129 pop zh
130 ret
131
132 ; USART transmit interrupt
133
134 INTERRUPT UDREaddr
135
136 push temp
137 in temp,sreg
138 push temp
139 lds temp,txcount ;if txcount != 0
140 tst temp ;
141 breq txi_e ;
142
143 dec temp ;
144 sts txcount,temp ; --txcount
145 push zh ;
146 push zl ;
147 ldi zl,low(txfifo) ;
148 ldi zh,high(txfifo) ;
149 lds temp,txidx_r ;
150 add zl,temp ;
151 brcc PC+2 ;
152 inc zh ;
153 inc temp ;
154 andi temp,TXBUFMASK ;
155 sts txidx_r,temp ;
156 ld temp,z
157 outm8 RXTXDR0,temp
158 pop zl
159 pop zh
160 txi_e: ;endif
161 lds temp,txcount
162 tst temp
163 brne txi_x
164 ldi temp, (1<<TXEN0) | (1<<RXEN0) | (1<<RXCIE0)
165 outm8 UCSR0B,temp
166 txi_x:
167 pop temp
168 out sreg,temp
169 pop temp
170 reti
171
172
173 ;Sends a char from temp to the uart.
174 uartputc:
175 push zh
176 push zl
177 push temp
178 putc_l:
179 lds temp,txcount ;do {
180 cpi temp,TXBUFSIZE ;
181 brsh putc_l ;} while (txcount >= TXBUFSIZE)
182
183 ldi zl,low(txfifo) ;
184 ldi zh,high(txfifo) ;
185 lds temp,txidx_w ;
186 add zl,temp ;
187 brcc PC+2 ;
188 inc zh ;
189 inc temp ;
190 andi temp,TXBUFMASK ;
191 sts txidx_w,temp ; txidx_w = ++txidx_w % TXBUFSIZE
192 pop temp ;
193 st z,temp ; txfifo[txidx_w] = char
194 cli
195 lds zl,txcount
196 inc zl
197 sts txcount,zl
198 ldi zl, (1<<UDRIE0) | (1<<TXEN0) | (1<<RXEN0) | (1<<RXCIE0)
199 outm8 UCSR0B,zl
200 sei
201 pop zl
202 pop zh
203 ret
204
205 ; vim:set ts=8 noet nowrap
206