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/>.
20 #include "Registers.h"
25 SPR0
= 1<<0, /* Clock Rate Select 0 */
26 SPR1
= 1<<1, /* Clock Rate Select 1 */
27 CPHA
= 1<<2, /* Clock Phase */
28 CPOL
= 1<<3, /* Clock Polarity */
29 MSTR
= 1<<4, /* Master / Slave Select */
30 DORD
= 1<<5, /* Data Order */
31 SPE
= 1<<6, /* SPI Enable */
32 SPIE
= 1<<7 /* SPI Interrupt Enable */
36 SPI2X
= 1<<0, /* Double SPI Speed */
37 WCOL
= 1<<6, /* Write Collision flag */
38 SPIF
= 1<<7 /* SPI Interrupt flag */
43 Spi::Spi(Bus
& bus
, unsigned int stcVec
) : Hardware(bus
), stcVec(stcVec
) {
44 bus
.claimInterrupt(stcVec
, this);
50 bool Spi::attachReg(const char *name
, IORegister
*reg
) {
51 if( strcmp(name
, "spdr") == 0 )
53 else if( strcmp(name
, "spcr") == 0 )
55 else if( strcmp(name
, "spsr") == 0 )
60 reg
->registerHW(this);
64 bool Spi::finishBuild() {
65 return ( (spdr
!= 0) && (spcr
!= 0) && (spsr
!= 0) );
68 void Spi::setSpcr(unsigned char val
) {
69 if( ((val
& SPE
) != 0) && ((spsr_old
& SPE
) == 0) )
70 bus
.setBreakDelta(clkDiv
, this);
76 void Spi::setSpdr(unsigned char val
) {
79 if( ((*spcr
& (SPE
|MSTR
)) == (SPE
|MSTR
)) ) {
81 if( state
!= READY
) {
83 spsr
->set( *spsr
| WCOL
);
85 spsr
->set( *spsr
& ~(SPIF
|WCOL
) );
91 void Spi::setClkDiv() {
92 switch( *spcr
& (SPR1
|SPR0
) ) {
93 case 0: clkDiv
= 2; break;
94 case SPR0
: clkDiv
= 8; break;
95 case SPR1
: clkDiv
= 32; break;
96 case SPR1
|SPR0
: clkDiv
= 64; break;
99 if( (*spsr
& SPI2X
) != 0 )
103 void Spi::regChanged( IORegister
*reg
) {
106 } else if( reg
== spcr
) {
108 } else if( reg
== spsr
) {
114 if( state
== START_MASTER
) {
119 if( state
== MASTER
) {
120 if( ++bitCnt
== 7 ) {
121 spsr
->set( *spsr
| SPIF
);
122 if( (*spcr
& SPIE
) != 0 )
123 bus
.raiseInterrupt(stcVec
);
129 bus
.setBreakDelta(clkDiv
, this);
142 void Spi::beforeInvokeInterrupt(unsigned int vector
) {
143 if( vector
== stcVec
)
144 spsr
->set( *spsr
& ~SPIF
);