Fixed problem in DeviceSettings::strParam, returned wrong string
[avr-sim.git] / src / Usart.cpp
blobd8dbded8f2bf2b17beae2b966390c33eb4d501b1
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 ucsrc = 0;
67 baudRate = 1;
68 frameLength = 0;
70 txState = TX_FINISHED;
71 txShift = 0;
72 txBitCount = 0;
73 txRate = 0;
75 rxState = RX_FINISHED;
76 rxShift = 0;
77 rxBitCount = 0;
78 rxSample = 0;
80 bus.claimInterrupt(txVec, this);
83 Usart::~Usart() {
86 bool Usart::attachReg(const char *name, IORegister *reg) {
87 if( strcmp(name, "udr") == 0 )
88 udr = reg;
89 else if( strcmp(name, "ucsra") == 0 )
90 ucsra = reg;
91 else if( strcmp(name, "ucsrb") == 0 )
92 ucsrb = reg;
93 else if( strcmp(name, "ubrrl") == 0 )
94 ubrrl = reg;
95 else if( strcmp(name, "ubrrh") == 0 )
96 ubrrh = reg;
97 else
98 return false;
100 reg->registerHW(this);
101 return true;
104 bool Usart::finishBuild() {
105 return ( (udr != 0) &&
106 (ucsra != 0) && (ucsrb != 0) &&
107 (ubrrl != 0) && (ubrrh != 0) );
110 void Usart::setUdr(unsigned char udr) {
111 udrWrite = udr;
112 this->udr->set(udrRead);
114 if( (*ucsra & UDRE) != 0 ) {
115 // if the data register was empty, we clear the UDRE flag now
116 ucsra->set( *ucsra & ~UDRE );
118 // If interrupt was raised, clear it.
119 if( (*ucsrb & UDRIE) != 0 )
120 bus.clearInterrupt( udreVec );
124 void Usart::setUcsra(unsigned char val) {
125 // The TXC Flag bit can be cleared by writing a one to its bit location.
126 if( (val & TXC) != 0 )
127 ucsra->set( *ucsra & ~TXC );
129 // Handle interrupts
130 const unsigned char irqold = ucsrb_old & ucsra_old;
131 const unsigned char irqnew = ucsrb_old & *ucsra;
133 unsigned char changed = irqold ^ irqnew;
134 unsigned char setnew = changed & irqnew;
135 unsigned char clearnew = changed & (~irqnew);
137 checkForNewSetIrq(setnew);
138 checkForNewClearIrq(clearnew);
140 ucsra_old = *ucsra;
143 void Usart::setUcsrb(unsigned char val) {
144 // RXEN or TXEN on and previously off?
145 if( ( (val & (RXEN|TXEN)) != 0 ) &&
146 ( (ucsrb_old & (RXEN|TXEN)) == 0 ) ) {
147 bus.setBreakDelta(baudRate, this);
150 setFramelength();
152 // Handle interrupts
153 const unsigned char irqold = ucsrb_old & ucsra_old;
154 const unsigned char irqnew = *ucsrb & ucsra_old;
156 unsigned char changed = irqold ^ irqnew;
157 unsigned char setnew = changed & irqnew;
158 unsigned char clearnew = changed & (~irqnew);
160 checkForNewSetIrq(setnew);
161 checkForNewClearIrq(clearnew);
163 ucsrb_old = *ucsrb;
166 void Usart::setFramelength() {
167 if( (ucsrb_old & UCSZ2) != 0 ) {
168 frameLength=9;
169 } else {
170 switch( ucsrc & (UCSZ1|UCSZ0) ) {
171 case 0:
172 frameLength=5;
173 break;
175 case UCSZ0:
176 frameLength=6;
177 break;
179 case UCSZ1:
180 frameLength=7;
181 break;
183 case UCSZ0|UCSZ1:
184 frameLength=8;
185 break;
190 void Usart::regChanged( IORegister *reg ) {
191 if( reg == udr ) {
192 setUdr( *udr );
193 } else if( reg == ubrrl ) {
194 baudRate = ((*ubrrh << 8) | *ubrrl) + 1;
195 bus.reassignBreakDelta(baudRate, this);
196 } else if( reg == ubrrh ) {
197 if( (*ubrrh & URSEL) != 0 ) {
198 ucsrc = *ubrrh;
199 setFramelength();
200 } else {
201 baudRate = ((ubrrh->get() << 8) | ubrrl->get()) + 1;
202 bus.reassignBreakDelta(baudRate, this);
204 } else if( reg == ucsra ) {
205 setUcsra( *ucsra );
206 } else if( reg == ucsrb ) {
207 setUcsrb( *ucsrb );
211 void Usart::step() {
212 if( (*ucsrb & RXEN) != 0 )
213 receiveCycle();
215 if( (*ucsrb & TXEN) != 0 ) {
216 if( ++txRate == samplerate() ) {
217 transmitCycle();
218 txRate = 0;
222 bus.setBreakDelta(baudRate, this);
225 void Usart::receiveCycle() {
226 switch( rxState ) {
227 case RX_STARTBIT:
228 break;
230 case RX_DATABIT:
231 break;
233 case RX_PARITY:
234 break;
236 case RX_STOPBIT:
237 break;
239 case RX_STOPBIT2:
240 break;
242 case RX_FINISHED:
243 default:
247 // Handle interrupts
248 const unsigned char irqold = ucsrb_old & ucsra_old;
249 const unsigned char irqnew = ucsrb_old & *ucsra;
251 unsigned char changed = irqold ^ irqnew;
252 unsigned char setnew = changed & irqnew;
253 unsigned char clearnew = changed & (~irqnew);
255 checkForNewSetIrq(setnew);
256 checkForNewClearIrq(clearnew);
258 ucsra_old = *ucsra;
261 void Usart::transmitCycle() {
262 if( (txState == TX_FINISHED) && ((*ucsra & UDRE) == 0) ) {
263 // Shift data in
264 txShift = udrWrite;
265 if( (*ucsrb & TXB8) != 0 )
266 txShift |= 0x100; // Set bit 8
268 ucsra->set( (*ucsra & ~TXC) | UDRE );
269 txState = TX_STARTBIT;
272 switch( txState ) {
273 case TX_STARTBIT:
274 txBitCount = 0;
275 txState = TX_DATABIT;
276 break;
278 case TX_DATABIT:
279 txBitCount++;
281 if( txBitCount >= frameLength ) {
282 if( (ucsrc & (UPM0|UPM1)) != 0 )
283 txState = TX_PARITY;
284 else
285 txState = TX_STOPBIT;
287 break;
289 case TX_PARITY:
290 if( (ucsrc & UPM0) != 0 )
291 ;//even parity to send
292 else
293 ;//odd parity to send
295 txState = TX_STOPBIT;
296 break;
298 case TX_STOPBIT:
299 if( (ucsrc & USBS) != 0 )
300 txState = TX_STOPBIT2;
302 case TX_STOPBIT2:
303 if( (*ucsra & UDRE) == 0 ) {
304 // Shift data in
305 txShift = udrWrite;
306 if( (*ucsrb & TXB8) != 0 )
307 txShift |= 0x100; // Set bit 8
309 ucsra->set( (*ucsra & ~TXC) | UDRE );
310 txState = TX_STARTBIT;
311 } else {
312 txState = TX_COMPLETE;
314 break;
316 case TX_COMPLETE:
317 // Transmission finished and no further data
318 ucsra->set( *ucsra | TXC );
319 txState = TX_FINISHED;
320 break;
322 case TX_FINISHED:
323 default:
327 // Handle interrupts
328 const unsigned char irqold = ucsrb_old & ucsra_old;
329 const unsigned char irqnew = ucsrb_old & *ucsra;
331 unsigned char changed = irqold ^ irqnew;
332 unsigned char setnew = changed & irqnew;
333 unsigned char clearnew = changed & (~irqnew);
335 checkForNewSetIrq(setnew);
336 checkForNewClearIrq(clearnew);
338 ucsra_old = *ucsra;
341 void Usart::reset() {
342 baudRate = 1;
343 frameLength = 0;
345 // Fetch register values
346 setUcsra( *ucsra );
347 setUcsrb( *ucsrb );
348 if( (*ubrrh & URSEL) != 0 ) {
349 ucsrc = *ubrrh;
350 setFramelength();
353 txState = TX_FINISHED;
354 txShift = 0;
355 txBitCount = 0;
356 txRate = 0;
358 rxState = RX_FINISHED;
359 rxShift = 0;
360 rxBitCount = 0;
361 rxSample = 0;
364 void Usart::beforeInvokeInterrupt(unsigned int vector) {
365 if( vector == txVec )
366 ucsra->set( *ucsra & ~TXC );
369 void Usart::checkForNewSetIrq(unsigned char val) {
370 if( val & UDRE ) { bus.raiseInterrupt( udreVec ); }
371 if( val & RXC ) { bus.raiseInterrupt( rxVec ); }
372 if( val & TXC ) { bus.raiseInterrupt( txVec ); }
375 void Usart::checkForNewClearIrq(unsigned char val) {
376 if( val & UDRE ) { bus.clearInterrupt( udreVec ); }
377 if( val & RXC ) { bus.clearInterrupt( rxVec ); }
378 if( val & TXC ) { bus.clearInterrupt( txVec ); }