]>
Commit | Line | Data |
---|---|---|
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 | rxint: | |
70 | .org URXCaddr | |
71 | rjmp rxint ; USART receive int. | |
72 | ||
73 | .org rxint | |
74 | push temp | |
75 | in temp,sreg | |
76 | push temp | |
77 | push zh | |
78 | push zl | |
79 | inm8 temp,RXTXDR0 | |
80 | lds zh,rxcount ;if rxcount < RXBUFSIZE | |
81 | cpi zh,RXBUFSIZE ; (room for at least 1 char?) | |
82 | brsh rxi_ov ; | |
83 | inc zh ; | |
84 | sts rxcount,zh ; rxcount++ | |
85 | ||
86 | ldi zl,low(rxfifo) ; | |
87 | lds zh,rxidx_w ; | |
88 | add zl,zh ; | |
89 | inc zh ; | |
90 | andi zh,RXBUFMASK ; | |
91 | sts rxidx_w,zh ; rxidx_w = ++rxidx_w % RXBUFSIZE | |
92 | ldi zh,high(rxfifo) ; | |
93 | brcc PC+2 ; | |
94 | inc zh ; | |
95 | st z,temp ; rxfifo[rxidx_w] = char | |
96 | rxi_ov: ;endif | |
97 | pop zl | |
98 | pop zh | |
99 | pop temp | |
100 | out sreg,temp | |
101 | pop temp | |
102 | reti | |
103 | ||
104 | ||
105 | ;Fetches a char from the buffer to temp. If none available, waits till one is. | |
106 | ||
107 | uartgetc: | |
108 | lds temp,rxcount ; Number of characters in buffer | |
109 | tst temp | |
110 | breq uartgetc ;Wait for char | |
111 | ||
112 | push zh | |
113 | push zl | |
114 | ldi zl,low(rxfifo) | |
115 | ldi zh,high(rxfifo) | |
116 | lds temp,rxidx_r | |
117 | add zl,temp | |
118 | brcc PC+2 | |
119 | inc zh | |
120 | inc temp | |
121 | andi temp,RXBUFMASK | |
122 | sts rxidx_r,temp | |
123 | cli | |
124 | lds temp,rxcount | |
125 | dec temp | |
126 | sts rxcount,temp | |
127 | sei | |
128 | ld temp,z ;don't forget to get the char | |
129 | pop zl | |
130 | pop zh | |
131 | ret | |
132 | ||
133 | txint: | |
134 | .org UDREaddr | |
135 | rjmp txint ; USART transmit int. | |
136 | ||
137 | .org txint | |
138 | push temp | |
139 | in temp,sreg | |
140 | push temp | |
141 | lds temp,txcount ;if txcount != 0 | |
142 | tst temp ; | |
143 | breq txi_e ; | |
144 | ||
145 | dec temp ; | |
146 | sts txcount,temp ; --txcount | |
147 | push zh ; | |
148 | push zl ; | |
149 | ldi zl,low(txfifo) ; | |
150 | ldi zh,high(txfifo) ; | |
151 | lds temp,txidx_r ; | |
152 | add zl,temp ; | |
153 | brcc PC+2 ; | |
154 | inc zh ; | |
155 | inc temp ; | |
156 | andi temp,TXBUFMASK ; | |
157 | sts txidx_r,temp ; | |
158 | ld temp,z | |
159 | outm8 RXTXDR0,temp | |
160 | pop zl | |
161 | pop zh | |
162 | txi_e: ;endif | |
163 | lds temp,txcount | |
164 | tst temp | |
165 | brne txi_x | |
166 | ldi temp, (1<<TXEN0) | (1<<RXEN0) | (1<<RXCIE0) | |
167 | outm8 UCSR0B,temp | |
168 | txi_x: | |
169 | pop temp | |
170 | out sreg,temp | |
171 | pop temp | |
172 | reti | |
173 | ||
174 | ||
175 | ;Sends a char from temp to the uart. | |
176 | uartputc: | |
177 | push zh | |
178 | push zl | |
179 | push temp | |
180 | putc_l: | |
181 | lds temp,txcount ;do { | |
182 | cpi temp,TXBUFSIZE ; | |
183 | brsh putc_l ;} while (txcount >= TXBUFSIZE) | |
184 | ||
185 | ldi zl,low(txfifo) ; | |
186 | ldi zh,high(txfifo) ; | |
187 | lds temp,txidx_w ; | |
188 | add zl,temp ; | |
189 | brcc PC+2 ; | |
190 | inc zh ; | |
191 | inc temp ; | |
192 | andi temp,TXBUFMASK ; | |
193 | sts txidx_w,temp ; txidx_w = ++txidx_w % TXBUFSIZE | |
194 | pop temp ; | |
195 | st z,temp ; txfifo[txidx_w] = char | |
196 | cli | |
197 | lds zl,txcount | |
198 | inc zl | |
199 | sts txcount,zl | |
200 | ldi zl, (1<<UDRIE0) | (1<<TXEN0) | (1<<RXEN0) | (1<<RXCIE0) | |
201 | outm8 UCSR0B,zl | |
202 | sei | |
203 | pop zl | |
204 | pop zh | |
205 | ret | |
206 | ||
207 | ; vim:set ts=8 noet nowrap | |
208 |