avr: Construct the pin table more carefully
[avr-sim.git] / src / Usart.cpp
blob405a4d092aed12cce9aea03bedb43ff03349a462
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"
22 #include <cstring>
24 enum {
25 MPCM = 1<<0, /* Multi-processor Communication Mode */
26 U2X = 1<<1, /* Double X-mission Speed */
27 UPE = 1<<2, /* Parity Error */
28 DOR = 1<<3, /* Data OverRun */
29 FE = 1<<4, /* Framing Error */
30 UDRE = 1<<5, /* Data Register Empty */
31 TXC = 1<<6, /* Transmit Complete */
32 RXC = 1<<7, /* Receive Complete */
35 enum {
36 TXB8 = 1<<0, /* Transmit Data Bit 8 */
37 RXB8 = 1<<1, /* Receive Data Bit 8 */
38 UCSZ2 = 1<<2, /* Character Size */
39 TXEN = 1<<3, /* Transmitter Enable */
40 RXEN = 1<<4, /* Receiver Enable */
41 UDRIE = 1<<5, /* Data Register Interrupt Enable */
42 TXCIE = 1<<6, /* TX Complete Interrupt Enable */
43 RXCIE = 1<<7, /* RX Complete Interrupt Enable */
46 enum {
47 UCPO = 1<<0, /* Clock Polarity */
48 UCSZ0 = 1<<1, /* Character Size */
49 UCSZ1 = 1<<2, /* Character Size */
50 USBS = 1<<3, /* Stop Bit Select */
51 UPM0 = 1<<4, /* Parity Mode */
52 UPM1 = 1<<5, /* Parity Mode */
53 UMSEL = 1<<6, /* USART Mode Select */
54 URSEL = 1<<7 /* Register Select */
57 #define samplerate() ( ((ucsrc & UMSEL) == 0) ? (((ucsra_old & U2X) != 0) ? 8 : 16) : 2 )
59 namespace avr {
61 Usart::Usart(Bus & bus, const std::string & name, unsigned int udreVec,
62 unsigned int rxVec, unsigned int txVec)
63 : Hardware(bus), name(name), udreVec(udreVec), rxVec(rxVec), txVec(txVec) {
65 ucsra_old = ucsrb_old = 0;
66 baudRate = 1;
67 frameLength = 0;
69 txState = TX_FINISHED;
70 txShift = 0;
71 txBitCount = 0;
72 txRate = 0;
74 rxState = RX_FINISHED;
75 rxShift = 0;
76 rxBitCount = 0;
77 rxSample = 0;
79 bus.claimInterrupt(txVec, this);
82 Usart::~Usart() {
85 bool Usart::attachReg(const char *name, IORegister *reg) {
86 if( strcmp(name, "udr") == 0 )
87 udr = reg;
88 else if( strcmp(name, "ucsra") == 0 )
89 ucsra = reg;
90 else if( strcmp(name, "ucsrb") == 0 )
91 ucsrb = reg;
92 else if( strcmp(name, "ubrrl") == 0 )
93 ubrrl = reg;
94 else if( strcmp(name, "ubrrh") == 0 )
95 ubrrh = reg;
96 else
97 return false;
99 reg->registerHW(this);
100 return true;
103 bool Usart::finishBuild() {
104 return ( (udr != 0) &&
105 (ucsra != 0) && (ucsrb != 0) &&
106 (ubrrl != 0) && (ubrrh != 0) );
109 void Usart::setUdr(unsigned char udr) {
110 udrWrite = udr;
111 this->udr->set(udrRead);
113 if( (*ucsra & UDRE) != 0 ) {
114 // if the data register was empty, we clear the UDRE flag now
115 ucsra->set( *ucsra & ~UDRE );
117 // If interrupt was raised, clear it.
118 if( (*ucsrb & UDRIE) != 0 )
119 bus.clearInterrupt( udreVec );
123 void Usart::setUcsra(unsigned char val) {
124 // The TXC Flag bit can be cleared by writing a one to its bit location.
125 if( (val & TXC) != 0 )
126 ucsra->set( *ucsra & ~TXC );
128 // Handle interrupts
129 const unsigned char irqold = ucsrb_old & ucsra_old;
130 const unsigned char irqnew = ucsrb_old & *ucsra;
132 unsigned char changed = irqold ^ irqnew;
133 unsigned char setnew = changed & irqnew;
134 unsigned char clearnew = changed & (~irqnew);
136 checkForNewSetIrq(setnew);
137 checkForNewClearIrq(clearnew);
139 ucsra_old = *ucsra;
142 void Usart::setUcsrb(unsigned char val) {
143 // RXEN or TXEN on and previously off?
144 if( ( (val & (RXEN|TXEN)) != 0 ) &&
145 ( (ucsrb_old & (RXEN|TXEN)) == 0 ) ) {
146 bus.setBreakDelta(baudRate, this);
149 setFramelength();
151 // Handle interrupts
152 const unsigned char irqold = ucsrb_old & ucsra_old;
153 const unsigned char irqnew = *ucsrb & ucsra_old;
155 unsigned char changed = irqold ^ irqnew;
156 unsigned char setnew = changed & irqnew;
157 unsigned char clearnew = changed & (~irqnew);
159 checkForNewSetIrq(setnew);
160 checkForNewClearIrq(clearnew);
162 ucsrb_old = *ucsrb;
165 void Usart::setFramelength() {
166 if( (ucsrb_old & UCSZ2) != 0 ) {
167 frameLength=9;
168 } else {
169 switch( ucsrc & (UCSZ1|UCSZ0) ) {
170 case 0:
171 frameLength=5;
172 break;
174 case UCSZ0:
175 frameLength=6;
176 break;
178 case UCSZ1:
179 frameLength=7;
180 break;
182 case UCSZ0|UCSZ1:
183 frameLength=8;
184 break;
189 void Usart::regChanged( IORegister *reg ) {
190 if( reg == udr ) {
191 setUdr( *udr );
192 } else if( reg == ubrrl ) {
193 baudRate = ((*ubrrh << 8) | *ubrrl) + 1;
194 bus.reassignBreakDelta(baudRate, this);
195 } else if( reg == ubrrh ) {
196 if( (*ubrrh & URSEL) != 0 ) {
197 ucsrc = *ubrrh;
198 setFramelength();
199 } else {
200 baudRate = ((ubrrh->get() << 8) | ubrrl->get()) + 1;
201 bus.reassignBreakDelta(baudRate, this);
203 } else if( reg == ucsra ) {
204 setUcsra( *ucsra );
205 } else if( reg == ucsrb ) {
206 setUcsrb( *ucsrb );
210 void Usart::step() {
211 if( (*ucsrb & RXEN) != 0 )
212 receiveCycle();
214 if( (*ucsrb & TXEN) != 0 ) {
215 if( ++txRate == samplerate() ) {
216 transmitCycle();
217 txRate = 0;
221 bus.setBreakDelta(baudRate, this);
224 void Usart::receiveCycle() {
225 switch( rxState ) {
226 case RX_STARTBIT:
227 break;
229 case RX_DATABIT:
230 break;
232 case RX_PARITY:
233 break;
235 case RX_STOPBIT:
236 break;
238 case RX_STOPBIT2:
239 break;
241 case RX_FINISHED:
242 default:
246 // Handle interrupts
247 const unsigned char irqold = ucsrb_old & ucsra_old;
248 const unsigned char irqnew = ucsrb_old & *ucsra;
250 unsigned char changed = irqold ^ irqnew;
251 unsigned char setnew = changed & irqnew;
252 unsigned char clearnew = changed & (~irqnew);
254 checkForNewSetIrq(setnew);
255 checkForNewClearIrq(clearnew);
257 ucsra_old = *ucsra;
260 void Usart::transmitCycle() {
261 if( (txState == TX_FINISHED) && ((*ucsra & UDRE) == 0) ) {
262 // Shift data in
263 txShift = udrWrite;
264 if( (*ucsrb & TXB8) != 0 )
265 txShift |= 0x100; // Set bit 8
267 ucsra->set( (*ucsra & ~TXC) | UDRE );
268 txState = TX_STARTBIT;
271 switch( txState ) {
272 case TX_STARTBIT:
273 txBitCount = 0;
274 txState = TX_DATABIT;
275 break;
277 case TX_DATABIT:
278 txBitCount++;
280 if( txBitCount >= frameLength ) {
281 if( (ucsrc & (UPM0|UPM1)) != 0 )
282 txState = TX_PARITY;
283 else
284 txState = TX_STOPBIT;
286 break;
288 case TX_PARITY:
289 if( (ucsrc & UPM0) != 0 )
290 ;//even parity to send
291 else
292 ;//odd parity to send
294 txState = TX_STOPBIT;
295 break;
297 case TX_STOPBIT:
298 if( (ucsrc & USBS) != 0 )
299 txState = TX_STOPBIT2;
301 case TX_STOPBIT2:
302 if( (*ucsra & UDRE) == 0 ) {
303 // Shift data in
304 txShift = udrWrite;
305 if( (*ucsrb & TXB8) != 0 )
306 txShift |= 0x100; // Set bit 8
308 ucsra->set( (*ucsra & ~TXC) | UDRE );
309 txState = TX_STARTBIT;
310 } else {
311 txState = TX_COMPLETE;
313 break;
315 case TX_COMPLETE:
316 // Transmission finished and no further data
317 ucsra->set( *ucsra | TXC );
318 txState = TX_FINISHED;
319 break;
321 case TX_FINISHED:
322 default:
326 // Handle interrupts
327 const unsigned char irqold = ucsrb_old & ucsra_old;
328 const unsigned char irqnew = ucsrb_old & *ucsra;
330 unsigned char changed = irqold ^ irqnew;
331 unsigned char setnew = changed & irqnew;
332 unsigned char clearnew = changed & (~irqnew);
334 checkForNewSetIrq(setnew);
335 checkForNewClearIrq(clearnew);
337 ucsra_old = *ucsra;
340 void Usart::reset() {
341 baudRate = 1;
342 frameLength = 0;
344 // Fetch register values
345 setUcsra( *ucsra );
346 setUcsrb( *ucsrb );
347 if( (*ubrrh & URSEL) != 0 ) {
348 ucsrc = *ubrrh;
349 setFramelength();
352 txState = TX_FINISHED;
353 txShift = 0;
354 txBitCount = 0;
355 txRate = 0;
357 rxState = RX_FINISHED;
358 rxShift = 0;
359 rxBitCount = 0;
360 rxSample = 0;
363 void Usart::beforeInvokeInterrupt(unsigned int vector) {
364 if( vector == txVec )
365 ucsra->set( *ucsra & ~TXC );
368 void Usart::checkForNewSetIrq(unsigned char val) {
369 if( val & UDRE ) { bus.raiseInterrupt( udreVec ); }
370 if( val & RXC ) { bus.raiseInterrupt( rxVec ); }
371 if( val & TXC ) { bus.raiseInterrupt( txVec ); }
374 void Usart::checkForNewClearIrq(unsigned char val) {
375 if( val & UDRE ) { bus.clearInterrupt( udreVec ); }
376 if( val & RXC ) { bus.clearInterrupt( rxVec ); }
377 if( val & TXC ) { bus.clearInterrupt( txVec ); }