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"
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 */
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 */
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 )
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;
68 txState
= TX_FINISHED
;
73 rxState
= RX_FINISHED
;
78 bus
.claimInterrupt(txVec
, this);
84 bool Usart::attachReg(const char *name
, IORegister
*reg
) {
85 if( strcmp(name
, "udr") == 0 )
87 else if( strcmp(name
, "ucsra") == 0 )
89 else if( strcmp(name
, "ucsrb") == 0 )
91 else if( strcmp(name
, "ubrrl") == 0 )
93 else if( strcmp(name
, "ubrrh") == 0 )
98 reg
->registerHW(this);
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
) {
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
);
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
);
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);
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
);
164 void Usart::setFramelength() {
165 if( (ucsrb_old
& UCSZ2
) != 0 ) {
168 switch( ucsrc
& (UCSZ1
|UCSZ0
) ) {
188 void Usart::regChanged( IORegister
*reg
) {
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 ) {
199 baudRate
= (*ubrrh
<< 8) | *ubrrl
;
200 bus
.reassignBreakDelta(baudRate
, this);
202 } else if( reg
== ucsra
) {
204 } else if( reg
== ucsrb
) {
210 if( (*ucsrb
& RXEN
) != 0 )
213 if( (*ucsrb
& TXEN
) != 0 ) {
214 if( ++txRate
== samplerate() ) {
220 bus
.setBreakDelta(baudRate
, this);
223 void Usart::receiveCycle() {
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
);
259 void Usart::transmitCycle() {
260 if( (txState
== TX_FINISHED
) && ((*ucsra
& UDRE
) == 0) ) {
263 if( (*ucsrb
& TXB8
) != 0 )
264 txShift
|= 0x100; // Set bit 8
266 ucsra
->set( (*ucsra
& ~TXC
) | UDRE
);
267 txState
= TX_STARTBIT
;
273 txState
= TX_DATABIT
;
279 if( txBitCount
>= frameLength
) {
280 if( (ucsrc
& (UPM0
|UPM1
)) != 0 )
283 txState
= TX_STOPBIT
;
288 if( (ucsrc
& UPM0
) != 0 )
289 ;//even parity to send
291 ;//odd parity to send
293 txState
= TX_STOPBIT
;
297 if( (ucsrc
& USBS
) != 0 )
298 txState
= TX_STOPBIT2
;
301 if( (*ucsra
& UDRE
) == 0 ) {
304 if( (*ucsrb
& TXB8
) != 0 )
305 txShift
|= 0x100; // Set bit 8
307 ucsra
->set( (*ucsra
& ~TXC
) | UDRE
);
308 txState
= TX_STARTBIT
;
310 txState
= TX_COMPLETE
;
315 // Transmission finished and no further data
316 ucsra
->set( *ucsra
| TXC
);
317 txState
= TX_FINISHED
;
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
);
339 void Usart::reset() {
343 // Fetch register values
346 if( (*ubrrh
& URSEL
) != 0 ) {
351 txState
= TX_FINISHED
;
356 rxState
= RX_FINISHED
;
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
); }