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;
70 txState
= TX_FINISHED
;
75 rxState
= RX_FINISHED
;
80 bus
.claimInterrupt(txVec
, this);
86 bool Usart::attachReg(const char *name
, IORegister
*reg
) {
87 if( strcmp(name
, "udr") == 0 )
89 else if( strcmp(name
, "ucsra") == 0 )
91 else if( strcmp(name
, "ucsrb") == 0 )
93 else if( strcmp(name
, "ubrrl") == 0 )
95 else if( strcmp(name
, "ubrrh") == 0 )
100 reg
->registerHW(this);
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
) {
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
);
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
);
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);
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
);
166 void Usart::setFramelength() {
167 if( (ucsrb_old
& UCSZ2
) != 0 ) {
170 switch( ucsrc
& (UCSZ1
|UCSZ0
) ) {
190 void Usart::regChanged( IORegister
*reg
) {
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 ) {
201 baudRate
= ((ubrrh
->get() << 8) | ubrrl
->get()) + 1;
202 bus
.reassignBreakDelta(baudRate
, this);
204 } else if( reg
== ucsra
) {
206 } else if( reg
== ucsrb
) {
212 if( (*ucsrb
& RXEN
) != 0 )
215 if( (*ucsrb
& TXEN
) != 0 ) {
216 if( ++txRate
== samplerate() ) {
222 bus
.setBreakDelta(baudRate
, this);
225 void Usart::receiveCycle() {
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
);
261 void Usart::transmitCycle() {
262 if( (txState
== TX_FINISHED
) && ((*ucsra
& UDRE
) == 0) ) {
265 if( (*ucsrb
& TXB8
) != 0 )
266 txShift
|= 0x100; // Set bit 8
268 ucsra
->set( (*ucsra
& ~TXC
) | UDRE
);
269 txState
= TX_STARTBIT
;
275 txState
= TX_DATABIT
;
281 if( txBitCount
>= frameLength
) {
282 if( (ucsrc
& (UPM0
|UPM1
)) != 0 )
285 txState
= TX_STOPBIT
;
290 if( (ucsrc
& UPM0
) != 0 )
291 ;//even parity to send
293 ;//odd parity to send
295 txState
= TX_STOPBIT
;
299 if( (ucsrc
& USBS
) != 0 )
300 txState
= TX_STOPBIT2
;
303 if( (*ucsra
& UDRE
) == 0 ) {
306 if( (*ucsrb
& TXB8
) != 0 )
307 txShift
|= 0x100; // Set bit 8
309 ucsra
->set( (*ucsra
& ~TXC
) | UDRE
);
310 txState
= TX_STARTBIT
;
312 txState
= TX_COMPLETE
;
317 // Transmission finished and no further data
318 ucsra
->set( *ucsra
| TXC
);
319 txState
= TX_FINISHED
;
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
);
341 void Usart::reset() {
345 // Fetch register values
348 if( (*ubrrh
& URSEL
) != 0 ) {
353 txState
= TX_FINISHED
;
358 rxState
= RX_FINISHED
;
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
); }