Fixed problem in DeviceSettings::strParam, returned wrong string
[avr-sim.git] / src / Spi.cpp
blob258907d8c5ae2a8d1f442c7508ff07a3c97fbbe4
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 "Spi.h"
20 #include "Registers.h"
21 #include "Bus.h"
22 #include <cstring>
24 enum {
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 */
35 enum {
36 SPI2X = 1<<0, /* Double SPI Speed */
37 WCOL = 1<<6, /* Write Collision flag */
38 SPIF = 1<<7 /* SPI Interrupt flag */
41 namespace avr {
43 Spi::Spi(Bus & bus, unsigned int stcVec) : Hardware(bus), stcVec(stcVec) {
44 bus.claimInterrupt(stcVec, this);
47 Spi::~Spi() {
50 bool Spi::attachReg(const char *name, IORegister *reg) {
51 if( strcmp(name, "spdr") == 0 )
52 spdr = reg;
53 else if( strcmp(name, "spcr") == 0 )
54 spcr = reg;
55 else if( strcmp(name, "spsr") == 0 )
56 spsr = reg;
57 else
58 return false;
60 reg->registerHW(this);
61 return true;
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);
72 setClkDiv();
73 spsr_old = val;
76 void Spi::setSpdr(unsigned char val) {
77 spdrWrite = val;
79 if( ((*spcr & (SPE|MSTR)) == (SPE|MSTR)) ) {
80 // Enabled and master
81 if( state != READY ) {
82 //Write Collision
83 spsr->set( *spsr | WCOL);
84 } else {
85 spsr->set( *spsr & ~(SPIF|WCOL) );
86 state = START_MASTER;
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 )
100 clkDiv *= 2;
103 void Spi::regChanged( IORegister *reg ) {
104 if( reg == spdr ) {
105 setSpdr( *spdr );
106 } else if( reg == spcr ) {
107 setSpcr( *spcr );
108 } else if( reg == spsr ) {
109 setClkDiv();
113 void Spi::step() {
114 if( state == START_MASTER ) {
115 bitCnt = 0;
116 state = MASTER;
119 if( state == MASTER ) {
120 if( ++bitCnt == 7 ) {
121 spsr->set( *spsr | SPIF );
122 if( (*spcr & SPIE) != 0 )
123 bus.raiseInterrupt(stcVec);
125 state = READY;
129 bus.setBreakDelta(clkDiv, this);
132 void Spi::reset() {
133 clkDiv = 0;
134 bitCnt = 0;
135 spdrWrite = 0;
136 spdrRead = 0;
137 spsr_old = *spsr;
139 state = READY;
142 void Spi::beforeInvokeInterrupt(unsigned int vector) {
143 if( vector == stcVec )
144 spsr->set( *spsr & ~SPIF );