2
Copyright (C) 1998 Scott Dattalo
4
This file is part of the libgpsim library of gpsim
6
This library is free software; you can redistribute it and/or
7
modify it under the terms of the GNU Lesser General Public
8
License as published by the Free Software Foundation; either
9
version 2.1 of the License, or (at your option) any later version.
11
This library is distributed in the hope that it will be useful,
12
but WITHOUT ANY WARRANTY; without even the implied warranty of
13
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14
Lesser General Public License for more details.
16
You should have received a copy of the GNU Lesser General Public
17
License along with this library; if not, see
18
<http://www.gnu.org/licenses/lgpl-2.1.html>.
28
#include "14bit-processors.h"
29
#include "14bit-tmrs.h"
30
#include "a2dconverter.h"
36
#define Dprintf(arg) {printf("%s:%d-%s() ",__FILE__,__LINE__,__FUNCTION__); printf arg; }
38
#define Dprintf(arg) {}
41
//--------------------------------------------------
42
// member functions for the TMR0 base class
43
//--------------------------------------------------
44
TMR0::TMR0(Processor *pCpu, const char *pName )
46
prescale(1), prescale_counter(0), old_option(0),
47
state(STOPPED), synchronized_cycle(0),
48
future_cycle(0), last_cycle(0),
49
m_pOptionReg(0), m_t1gcon(0), m_adcon2(0),
50
m_bLastClockedState(false), t0xcs(false)
55
for (int i = 0; i < 4; i++)
59
//------------------------------------------------------------------------
63
//------------------------------------------------------------------------
66
// Called when the I/O pin driving TMR0 changes states.
68
void TMR0::setSinkState(char new3State)
70
bool bNewState = new3State == '1';
72
if (m_bLastClockedState != bNewState) {
73
m_bLastClockedState = bNewState;
75
if (get_t0cs() && !get_t0xcs() && bNewState != get_t0se())
80
void TMR0::set_cpu(Processor *new_cpu, PortRegister *reg, uint pin, OPTION_REG *pOption)
83
m_pOptionReg = pOption;
84
reg->addSink(this,pin);
87
// RCP - add an alternate way to connect to a CPU
88
void TMR0::set_cpu(Processor *new_cpu, PinModule *pin,OPTION_REG *pOption)
91
m_pOptionReg = pOption;
95
//------------------------------------------------------------
103
// If tmr0 is running, then stop it:
104
if (state & RUNNING) {
106
// refresh the current value.
109
state &= (~RUNNING); // the timer is disabled.
115
void TMR0::start(int restart_value, int sync)
118
Dprintf(("restart_value=%d(0x%x) sync=%d\n",restart_value, restart_value, sync));
120
state |= RUNNING; // the timer is on
122
value.put(restart_value&0xff);
124
//old_option = cpu_pic->option_reg.value.get();
125
old_option = m_pOptionReg->get_value();
127
prescale = 1 << get_prescale();
128
prescale_counter = prescale;
131
Dprintf(("External clock\n"));
136
synchronized_cycle = cpu->currentCycle() + sync;
138
last_cycle = (restart_value % max_counts()) * prescale;
139
last_cycle = synchronized_cycle - last_cycle;
141
uint64_t fc = last_cycle + max_counts() * prescale;
143
if(future_cycle) cpu->reassign_break( future_cycle, fc, this );
144
else cpu->setBreakAbs( fc, this );
148
Dprintf(("last_cycle:0x%" PRINTF_GINT64_MODIFIER "x future_cycle:0x%" PRINTF_GINT64_MODIFIER "x\n",last_cycle,future_cycle));
152
void TMR0::clear_trigger()
158
cpu->clear_break( this );
163
uint TMR0::get_prescale()
165
Dprintf(("OPTION::PSA=%u\n", m_pOptionReg->get_psa()));
167
//return (cpu_pic->option_reg.get_psa() ? 0 : (1+cpu_pic->option_reg.get_prescale()));
168
return (m_pOptionReg->get_psa() ? 0 : (1+m_pOptionReg->get_prescale()));
171
// This is used to drive timer ias counter of IO port if T0CS is true
173
void TMR0::increment()
177
if((state & RUNNING) == 0)
180
if(--prescale_counter == 0)
182
prescale_counter = prescale;
183
if(value.get() >= (max_counts()-1))
185
//cout << "TMR0 rollover because of external clock ";
191
value.put(value.get() + 1);
193
// cout << "TMR0 value ="<<value.get() << '\n';
197
void TMR0::put_value(uint new_value)
201
value.put(new_value & 0xff);
203
// If tmr0 is enabled, then start it up.
208
void TMR0::put(uint new_value)
212
put_value(new_value);
215
uint TMR0::get_value()
217
// If the TMR0 is being read immediately after being written, then
218
// it hasn't had enough time to synchronize with the PIC's clock.
219
if(cpu->currentCycle() <= synchronized_cycle)
222
// If we're running off the external clock or the tmr is disabled
223
// then just return the register value.
224
if(get_t0cs() || ((state & RUNNING)==0))
227
int new_value = (int )((cpu->currentCycle() - last_cycle)/ prescale);
229
if (new_value == (int)max_counts())
231
// tmr0 is about to roll over. However, the user code
232
// has requested the current value before the callback function
233
// has been invoked. So do callback and return 0.
237
cpu->clear_break( this );
243
if (new_value >= (int)max_counts())
245
cout << "TMR0: bug TMR0 is larger than " << max_counts() - 1 << "...\n";
246
cout << "cycles.value = " << cpu->currentCycle() <<
247
" last_cycle = " << last_cycle <<
248
" prescale = " << prescale <<
249
" calculated value = " << new_value << '\n';
251
// cop out. tmr0 has a bug. So rather than annoy
252
// the user with an infinite number of messages,
253
// let's just go ahead and reset the logic.
255
last_cycle = new_value*prescale;
256
last_cycle = cpu->currentCycle() - last_cycle;
257
synchronized_cycle = last_cycle;
260
value.put(new_value);
267
value.put(get_value());
270
void TMR0::new_prescale()
276
int option_diff = old_option ^ m_pOptionReg->get_value();
278
old_option ^= option_diff; // save old option value. ( (a^b) ^b = a)
280
if(option_diff & OPTION_REG::T0CS)
282
// TMR0's clock source has changed.
284
if(m_pOptionReg->get_t0cs())
290
cpu->clear_break(this);
298
// Refresh the current tmr0 value. The current tmr0 value is used
299
// below to recompute the value for 'last_cycle'
302
if(get_t0cs() || ((state & RUNNING)==0))
304
prescale = 1 << get_prescale();
305
prescale_counter = prescale;
309
if(last_cycle < (int64_t)cpu->currentCycle())
310
new_value = (uint)((cpu->currentCycle() - last_cycle)/prescale);
314
if(new_value>=max_counts())
316
cout << "TMR0 bug (new_prescale): exceeded max count"<< max_counts() <<'\n';
317
cout << " last_cycle = 0x" << hex << last_cycle << endl;
318
cout << " cpu cycle = 0x" << hex << (cpu->currentCycle()) << endl;
320
cout << " prescale = 0x" << hex << prescale << endl;
322
// Get the current value of TMR0
323
// cout << "cycles " << cycles.value << " old prescale " << prescale;
325
prescale = 1 << get_prescale();
326
prescale_counter = prescale;
328
last_cycle = value.get() * prescale;
329
last_cycle = cpu->currentCycle() - last_cycle;
330
synchronized_cycle = last_cycle;
332
uint64_t fc = last_cycle + max_counts() * prescale;
334
cpu->reassign_break( future_cycle, fc, this );
341
bool TMR0::get_t0cs()
344
//return cpu_pic->option_reg.get_t0cs() != 0;
345
return m_pOptionReg->get_t0cs() != 0;
347
bool TMR0::get_t0se()
349
//return cpu_pic->option_reg.get_t0se() != 0;
350
return m_pOptionReg->get_t0se() != 0;
353
void TMR0::set_t0if()
355
if(cpu_pic->base_isa() == _14BIT_PROCESSOR_ ||
356
cpu_pic->base_isa() == _14BIT_E_PROCESSOR_)
358
cpu14->intcon->set_t0if();
362
m_t1gcon->T0_gate(true);
363
// Spec sheet does not indicate when the overflow signal
364
// is cleared, so I am assuming it is just a pulse. RRR
365
m_t1gcon->T0_gate(false);
367
if (m_adcon2) m_adcon2->t0_overflow();
369
for(int i =0; i < 4; i++)
370
if (m_clc[i]) m_clc[i]->t0_overflow();
373
void TMR0::set_clc( CLC *_clc, int index )
375
qDebug()<<"TMR0::set_clc"<<index;
379
// TMR0 callback is called when the cycle counter hits the break point that
380
// was set in TMR0::put. The cycle counter will clear the break point, so
381
// we don't need to worry about it. At this point, TMR0 is rolling over.
383
void TMR0::callback()
386
Dprintf(("now=0x%" PRINTF_GINT64_MODIFIER "x\n",cpu->get_cycles()->get()));
388
if((state & RUNNING) == 0) {
390
cout << "TMR0 callback ignored because timer is disabled\n";
393
// If tmr0 is being clocked by the external clock, then at some point
394
// the simulate code must have switched from the internal clock to
395
// external clock. The cycle break point was still set, so just ignore it.
398
future_cycle = 0; // indicates that tmr0 no longer has a break point
403
synchronized_cycle = cpu->currentCycle();
404
last_cycle = synchronized_cycle;
405
future_cycle = last_cycle + max_counts()*prescale;
406
cpu->setBreakAbs( future_cycle, this );
410
void TMR0::reset(RESET_TYPE r)
421
void TMR0::callback_print()
426
// Suspend TMR0 for sleep
429
if((state & RUNNING))
435
// wake up TMR0 when sleep command terminates
438
if ((state & SLEEPING))
440
if (! (state & RUNNING))
443
start(value.get(), 0);
445
else state &= ~SLEEPING;