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"
22 #include "ImplementationException.h"
26 bit_CS0
= 0, /* timer/counter clock select bit 0 */
32 mask_CS0
= 1 << bit_CS0
,
33 mask_CS1
= 1 << bit_CS1
,
34 mask_CS2
= 1 << bit_CS2
,
35 mask_CS
= (mask_CS0
| mask_CS1
| mask_CS2
),
39 CS_STOP
= 0x00, /* Stop, the Timer/Counter is stopped */
40 CS_CK
= 0x01, /* CK */
41 CS_CK_8
= 0x02, /* CK/8 */
42 CS_CK_64
= 0x03, /* CK/64 */
43 CS_CK_256
= 0x04, /* CK/256 */
44 CS_CK_1024
= 0x05, /* CK/1024 */
45 CS_EXT_FALL
= 0x06, /* External Pin Tn, falling edge */
46 CS_EXT_RISE
= 0x07, /* External Pin Tn, rising edge */
63 mask_WGM
= (WGM1
|WGM0
),
64 mask_COM
= (COM1
|COM0
),
71 MODE_FASTPWM
= (WGM0
|WGM1
)
83 #define overflow() *tifr |= tovmask
84 #define compareMatch() *tifr |= ocfmask
86 void OutputCompareUnit8::flush() {
90 void OutputCompareUnit8::regChanged(IORegister
*reg
) {
95 void OutputCompareUnit8::forceOutputCompare(IORegister
*tifr
, unsigned char tcnt
) {
96 compareMatchOutput( tifr
, tcnt
);
99 void OutputCompareUnit8::compareMatchOutput(IORegister
*tifr
, unsigned char tcnt
) {
100 // the non-PWM modes are NORMAL and CTC
101 // under NORMAL, there is no pin action for a compare match
102 // under CTC, the action is to clear the pin.
103 if( tcnt
== ocrBuf
) {
104 switch( compareMode
) {
109 //outputComparePin.toggle();
113 //outputComparePin.low();
117 //outputComparePin.high();
126 Timer8::Timer8(Bus
& bus
, unsigned char tovmask
, int compunits
,
127 unsigned char ocfmask
[])
128 : Hardware(bus
), tovmask(tovmask
), direction(1) {
129 blockCompareMatch
= true;
134 for(int i
= 0; i
< nUnits
; ++i
)
135 units
[i
].setMask( ocfmask
[i
] );
138 bool Timer8::attachReg(const char *name
, IORegister
*reg
) {
139 if( strcmp(name
, "tcnt") == 0 ) {
141 } else if( strcmp(name
, "tccr") == 0 ) {
143 } else if( strcmp(name
, "ocra") == 0 || strcmp(name
, "ocr") == 0 ) {
144 units
[0].setOcrRegister(reg
);
145 } else if( strcmp(name
, "ocrb") == 0 ) {
146 units
[1].setOcrRegister(reg
);
147 } else if( strcmp(name
, "ocrc") == 0 ) {
148 units
[2].setOcrRegister(reg
);
149 } else if( strcmp(name
, "tifr") == 0 ) {
155 reg
->registerHW(this);
159 bool Timer8::finishBuild() {
161 for(int i
= 0; i
< nUnits
; ++i
)
162 unitsOk
= unitsOk
&& units
[i
].ocrSet();
164 return (tcnt
!= 0) && (tccr
!= 0) && (tifr
!= 0) && unitsOk
;
167 void Timer8::regChanged( IORegister
*reg
) {
169 unsigned char val
= tccr
->get();
172 unsigned char timerModeNew
= val
& mask_WGM
;
173 if( timerMode
!= timerModeNew
)
175 timerMode
= timerModeNew
;
177 units
[0].setCompareMode( val
& mask_COM
);
180 for(int cntr
= 0; nUnits
; cntr
++ )
181 units
[cntr
].forceOutputCompare(tifr
, *tcnt
);
184 } else if( reg
== tcnt
) {
185 blockCompareMatch
= true;
187 if( (timerMode
== MODE_NORMAL
) || (timerMode
== MODE_CTC
) ) {
188 for(int i
= 0; i
< nUnits
; ++i
)
189 units
[i
].regChanged(reg
);
194 void Timer8::setClock(unsigned char tccr
) {
195 byte clk
= tccr
& mask_CS
;
198 bus
.clearBreak(this);
223 throw util::ImplementationException(
224 "external timer/counter sources not implemented" );
227 bus
.setBreakDelta(period
, this);
233 void Timer8::step() {
234 byte tcntVal
= tcnt
->get();
235 byte tcntSave
= tcntVal
;
238 switch( timerMode
) {
240 if( tcntVal
== TOP
) {
247 if( units
[0].compare(tcntVal
) ) {
254 if( (tcntVal
== TOP
) && (direction
== +1) ) {
257 } else if( (tcntVal
== BOTTOM
) && (direction
== -1) ) {
264 if( tcntVal
== TOP
) {
274 tcntVal
+= direction
;
276 if( ! blockCompareMatch
)
277 for(int cntr
= 0; cntr
< nUnits
; cntr
++ )
278 units
[cntr
].compareMatchOutput(tifr
, tcntSave
);
279 blockCompareMatch
= false;
281 tcnt
->set( tcntVal
);
282 bus
.setBreakDelta(period
, this);
285 void Timer8::flushOCRn() {
286 for(int cntr
= 0; cntr
< nUnits
; cntr
++ )