Timer8 now has a variable amount of output compare units.
[avr-sim.git] / src / Usart.cpp
blob399ad48b52be4e2050aa56d1702438157872f60a
1 /*
2 * avr-sim: An atmel AVR simulator
3 * Copyright (C) 2008 Tom Haber
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
19 #include "Usart.h"
20 #include "Bus.h"
21 #include "Registers.h"
23 enum {
24 MPCM = 1<<0, /* Multi-processor Communication Mode */
25 U2X = 1<<1, /* Double X-mission Speed */
26 UPE = 1<<2, /* Parity Error */
27 DOR = 1<<3, /* Data OverRun */
28 FE = 1<<4, /* Framing Error */
29 UDRE = 1<<5, /* Data Register Empty */
30 TXC = 1<<6, /* Transmit Complete */
31 RXC = 1<<7, /* Receive Complete */
34 enum {
35 TXB8 = 1<<0, /* Transmit Data Bit 8 */
36 RXB8 = 1<<1, /* Receive Data Bit 8 */
37 UCSZ2 = 1<<2, /* Character Size */
38 TXEN = 1<<3, /* Transmitter Enable */
39 RXEN = 1<<4, /* Receiver Enable */
40 UDRIE = 1<<5, /* Data Register Interrupt Enable */
41 TXCIE = 1<<6, /* TX Complete Interrupt Enable */
42 RXCIE = 1<<7, /* RX Complete Interrupt Enable */
45 enum {
46 UCPO = 1<<0, /* Clock Polarity */
47 UCSZ0 = 1<<1, /* Character Size */
48 UCSZ1 = 1<<2, /* Character Size */
49 USBS = 1<<3, /* Stop Bit Select */
50 UPM0 = 1<<4, /* Parity Mode */
51 UPM1 = 1<<5, /* Parity Mode */
52 UMSEL = 1<<6, /* USART Mode Select */
53 URSEL = 1<<7 /* Register Select */
56 #define samplerate() ( ((ucsrc & UMSEL) == 0) ? (((ucsra_old & U2X) != 0) ? 8 : 16) : 2 )
58 namespace avr {
60 Usart::Usart(Bus & bus, const std::string & name, unsigned int udreVec,
61 unsigned int rxVec, unsigned int txVec)
62 : Hardware(bus), name(name), udreVec(udreVec), rxVec(rxVec), txVec(txVec) {
64 ucsra_old = ucsrb_old = 0;
65 baudRate = 0;
66 frameLength = 0;
68 txState = TX_FINISHED;
69 txShift = 0;
70 txBitCount = 0;
71 txRate = 0;
73 rxState = RX_FINISHED;
74 rxShift = 0;
75 rxBitCount = 0;
76 rxSample = 0;
78 bus.claimInterrupt(txVec, this);
81 Usart::~Usart() {
84 bool Usart::attachReg(const char *name, IORegister *reg) {
85 if( strcmp(name, "udr") == 0 )
86 udr = reg;
87 else if( strcmp(name, "ucsra") == 0 )
88 ucsra = reg;
89 else if( strcmp(name, "ucsrb") == 0 )
90 ucsrb = reg;
91 else if( strcmp(name, "ubrrl") == 0 )
92 ubrrl = reg;
93 else if( strcmp(name, "ubrrh") == 0 )
94 ubrrh = reg;
95 else
96 return false;
98 reg->registerHW(this);
99 return true;
102 bool Usart::finishBuild() {
103 return ( (udr != 0) &&
104 (ucsra != 0) && (ucsrb != 0) &&
105 (ubrrl != 0) && (ubrrh != 0) );
108 void Usart::setUdr(unsigned char udr) {
109 udrWrite = udr;
110 this->udr->set(udrRead);
112 if( (*ucsra & UDRE) != 0 ) {
113 // if the data register was empty, we clear the UDRE flag now
114 ucsra->set( *ucsra & ~UDRE );
116 // If interrupt was raised, clear it.
117 if( (*ucsrb & UDRIE) != 0 )
118 bus.clearInterrupt( udreVec );
122 void Usart::setUcsra(unsigned char val) {
123 // The TXC Flag bit can be cleared by writing a one to its bit location.
124 if( (val & TXC) != 0 )
125 ucsra->set( *ucsra & ~TXC );
127 // Handle interrupts
128 const unsigned char irqold = ucsrb_old & ucsra_old;
129 const unsigned char irqnew = ucsrb_old & *ucsra;
131 unsigned char changed = irqold ^ irqnew;
132 unsigned char setnew = changed & irqnew;
133 unsigned char clearnew = changed & (~irqnew);
135 checkForNewSetIrq(setnew);
136 checkForNewClearIrq(clearnew);
138 ucsra_old = *ucsra;
141 void Usart::setUcsrb(unsigned char val) {
142 // RXEN or TXEN on and previously off?
143 if( ( (val & (RXEN|TXEN)) != 0 ) &&
144 ( (ucsrb_old & (RXEN|TXEN)) == 0 ) ) {
145 bus.setBreakDelta(baudRate, this);
148 setFramelength();
150 // Handle interrupts
151 const unsigned char irqold = ucsrb_old & ucsra_old;
152 const unsigned char irqnew = *ucsrb & ucsra_old;
154 unsigned char changed = irqold ^ irqnew;
155 unsigned char setnew = changed & irqnew;
156 unsigned char clearnew = changed & (~irqnew);
158 checkForNewSetIrq(setnew);
159 checkForNewClearIrq(clearnew);
161 ucsrb_old = *ucsrb;
164 void Usart::setFramelength() {
165 if( (ucsrb_old & UCSZ2) != 0 ) {
166 frameLength=9;
167 } else {
168 switch( ucsrc & (UCSZ1|UCSZ0) ) {
169 case 0:
170 frameLength=5;
171 break;
173 case UCSZ0:
174 frameLength=6;
175 break;
177 case UCSZ1:
178 frameLength=7;
179 break;
181 case UCSZ0|UCSZ1:
182 frameLength=8;
183 break;
188 void Usart::regChanged( IORegister *reg ) {
189 if( reg == udr ) {
190 setUdr( *udr );
191 } else if( reg == ubrrl ) {
192 baudRate = (*ubrrh << 8) | *ubrrl;
193 bus.reassignBreakDelta(baudRate, this);
194 } else if( reg == ubrrh ) {
195 if( (*ubrrh & URSEL) != 0 ) {
196 ucsrc = *ubrrh;
197 setFramelength();
198 } else {
199 baudRate = (*ubrrh << 8) | *ubrrl;
200 bus.reassignBreakDelta(baudRate, this);
202 } else if( reg == ucsra ) {
203 setUcsra( *ucsra );
204 } else if( reg == ucsrb ) {
205 setUcsrb( *ucsrb );
209 void Usart::step() {
210 if( (*ucsrb & RXEN) != 0 )
211 receiveCycle();
213 if( (*ucsrb & TXEN) != 0 ) {
214 if( ++txRate == samplerate() ) {
215 transmitCycle();
216 txRate = 0;
220 bus.setBreakDelta(baudRate, this);
223 void Usart::receiveCycle() {
224 switch( rxState ) {
225 case RX_STARTBIT:
226 break;
228 case RX_DATABIT:
229 break;
231 case RX_PARITY:
232 break;
234 case RX_STOPBIT:
235 break;
237 case RX_STOPBIT2:
238 break;
240 case RX_FINISHED:
241 default:
245 // Handle interrupts
246 const unsigned char irqold = ucsrb_old & ucsra_old;
247 const unsigned char irqnew = ucsrb_old & *ucsra;
249 unsigned char changed = irqold ^ irqnew;
250 unsigned char setnew = changed & irqnew;
251 unsigned char clearnew = changed & (~irqnew);
253 checkForNewSetIrq(setnew);
254 checkForNewClearIrq(clearnew);
256 ucsra_old = *ucsra;
259 void Usart::transmitCycle() {
260 if( (txState == TX_FINISHED) && ((*ucsra & UDRE) == 0) ) {
261 // Shift data in
262 txShift = udrWrite;
263 if( (*ucsrb & TXB8) != 0 )
264 txShift |= 0x100; // Set bit 8
266 ucsra->set( (*ucsra & ~TXC) | UDRE );
267 txState = TX_STARTBIT;
270 switch( txState ) {
271 case TX_STARTBIT:
272 txBitCount = 0;
273 txState = TX_DATABIT;
274 break;
276 case TX_DATABIT:
277 txBitCount++;
279 if( txBitCount >= frameLength ) {
280 if( (ucsrc & (UPM0|UPM1)) != 0 )
281 txState = TX_PARITY;
282 else
283 txState = TX_STOPBIT;
285 break;
287 case TX_PARITY:
288 if( (ucsrc & UPM0) != 0 )
289 ;//even parity to send
290 else
291 ;//odd parity to send
293 txState = TX_STOPBIT;
294 break;
296 case TX_STOPBIT:
297 if( (ucsrc & USBS) != 0 )
298 txState = TX_STOPBIT2;
300 case TX_STOPBIT2:
301 if( (*ucsra & UDRE) == 0 ) {
302 // Shift data in
303 txShift = udrWrite;
304 if( (*ucsrb & TXB8) != 0 )
305 txShift |= 0x100; // Set bit 8
307 ucsra->set( (*ucsra & ~TXC) | UDRE );
308 txState = TX_STARTBIT;
309 } else {
310 txState = TX_COMPLETE;
312 break;
314 case TX_COMPLETE:
315 // Transmission finished and no further data
316 ucsra->set( *ucsra | TXC );
317 txState = TX_FINISHED;
318 break;
320 case TX_FINISHED:
321 default:
325 // Handle interrupts
326 const unsigned char irqold = ucsrb_old & ucsra_old;
327 const unsigned char irqnew = ucsrb_old & *ucsra;
329 unsigned char changed = irqold ^ irqnew;
330 unsigned char setnew = changed & irqnew;
331 unsigned char clearnew = changed & (~irqnew);
333 checkForNewSetIrq(setnew);
334 checkForNewClearIrq(clearnew);
336 ucsra_old = *ucsra;
339 void Usart::reset() {
340 baudRate = 0;
341 frameLength = 0;
343 // Fetch register values
344 setUcsra( *ucsra );
345 setUcsrb( *ucsrb );
346 if( (*ubrrh & URSEL) != 0 ) {
347 ucsrc = *ubrrh;
348 setFramelength();
351 txState = TX_FINISHED;
352 txShift = 0;
353 txBitCount = 0;
354 txRate = 0;
356 rxState = RX_FINISHED;
357 rxShift = 0;
358 rxBitCount = 0;
359 rxSample = 0;
362 void Usart::beforeInvokeInterrupt(unsigned int vector) {
363 if( vector == txVec )
364 ucsra->set( *ucsra & ~TXC );
367 void Usart::checkForNewSetIrq(unsigned char val) {
368 if( val & UDRE ) { bus.raiseInterrupt( udreVec ); }
369 if( val & RXC ) { bus.raiseInterrupt( rxVec ); }
370 if( val & TXC ) { bus.raiseInterrupt( txVec ); }
373 void Usart::checkForNewClearIrq(unsigned char val) {
374 if( val & UDRE ) { bus.clearInterrupt( udreVec ); }
375 if( val & RXC ) { bus.clearInterrupt( rxVec ); }
376 if( val & TXC ) { bus.clearInterrupt( txVec ); }