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/>.
21 #include "Registers.h"
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 */
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 */
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 )
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;
69 txState
= TX_FINISHED
;
74 rxState
= RX_FINISHED
;
79 bus
.claimInterrupt(txVec
, this);
85 bool Usart::attachReg(const char *name
, IORegister
*reg
) {
86 if( strcmp(name
, "udr") == 0 )
88 else if( strcmp(name
, "ucsra") == 0 )
90 else if( strcmp(name
, "ucsrb") == 0 )
92 else if( strcmp(name
, "ubrrl") == 0 )
94 else if( strcmp(name
, "ubrrh") == 0 )
99 reg
->registerHW(this);
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
) {
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
);
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
);
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);
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
);
165 void Usart::setFramelength() {
166 if( (ucsrb_old
& UCSZ2
) != 0 ) {
169 switch( ucsrc
& (UCSZ1
|UCSZ0
) ) {
189 void Usart::regChanged( IORegister
*reg
) {
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 ) {
200 baudRate
= ((ubrrh
->get() << 8) | ubrrl
->get()) + 1;
201 bus
.reassignBreakDelta(baudRate
, this);
203 } else if( reg
== ucsra
) {
205 } else if( reg
== ucsrb
) {
211 if( (*ucsrb
& RXEN
) != 0 )
214 if( (*ucsrb
& TXEN
) != 0 ) {
215 if( ++txRate
== samplerate() ) {
221 bus
.setBreakDelta(baudRate
, this);
224 void Usart::receiveCycle() {
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
);
260 void Usart::transmitCycle() {
261 if( (txState
== TX_FINISHED
) && ((*ucsra
& UDRE
) == 0) ) {
264 if( (*ucsrb
& TXB8
) != 0 )
265 txShift
|= 0x100; // Set bit 8
267 ucsra
->set( (*ucsra
& ~TXC
) | UDRE
);
268 txState
= TX_STARTBIT
;
274 txState
= TX_DATABIT
;
280 if( txBitCount
>= frameLength
) {
281 if( (ucsrc
& (UPM0
|UPM1
)) != 0 )
284 txState
= TX_STOPBIT
;
289 if( (ucsrc
& UPM0
) != 0 )
290 ;//even parity to send
292 ;//odd parity to send
294 txState
= TX_STOPBIT
;
298 if( (ucsrc
& USBS
) != 0 )
299 txState
= TX_STOPBIT2
;
302 if( (*ucsra
& UDRE
) == 0 ) {
305 if( (*ucsrb
& TXB8
) != 0 )
306 txShift
|= 0x100; // Set bit 8
308 ucsra
->set( (*ucsra
& ~TXC
) | UDRE
);
309 txState
= TX_STARTBIT
;
311 txState
= TX_COMPLETE
;
316 // Transmission finished and no further data
317 ucsra
->set( *ucsra
| TXC
);
318 txState
= TX_FINISHED
;
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
);
340 void Usart::reset() {
344 // Fetch register values
347 if( (*ubrrh
& URSEL
) != 0 ) {
352 txState
= TX_FINISHED
;
357 rxState
= RX_FINISHED
;
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
); }