~arcachofo/simulide/1.1.0

« back to all changes in this revision

Viewing changes to src/gpsim/pic-processor.cc

  • Committer: arcachofo
  • Date: 2021-01-01 14:23:42 UTC
  • Revision ID: arcachofo@simulide.com-20210101142342-ozfljnll44g5lbl3
Initial Commit 0.5.15-RC3

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
   Copyright( C) 1998 T. Scott Dattalo
 
3
 
 
4
This file is part of the libgpsim library of gpsim
 
5
 
 
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.
 
10
 
 
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.
 
15
 
 
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>.
 
19
*/
 
20
 
 
21
#include <typeinfo>
 
22
#include <stdio.h>
 
23
#ifdef _WIN32
 
24
#include "unistd.h"
 
25
#else
 
26
#include <unistd.h>
 
27
#endif
 
28
#ifndef _MSC_VER
 
29
#include <sys/time.h>
 
30
#endif
 
31
#include <time.h>
 
32
#include <iostream>
 
33
#include <iomanip>
 
34
#include <string>
 
35
 
 
36
#include "pic-processor.h"
 
37
#include "pic-registers.h"
 
38
#include "pic_list.h"
 
39
 
 
40
//========================================================================
 
41
//
 
42
// pic_processor
 
43
//
 
44
// This file contains all( most?) of the code that simulates those features
 
45
// common to all pic microcontrollers.
 
46
//
 
47
//========================================================================
 
48
 
 
49
pic_processor::pic_processor(const char *_name )
 
50
    : Processor(_name),
 
51
      wdt(this, 18.0e-3),indf(0),fsr(0), stack(0), status(0),
 
52
      Wreg(0), pcl(0), pclath(0),
 
53
      tmr0(this,"tmr0" ),
 
54
      m_configMemory(0),
 
55
      m_MCLR(0), m_MCLR_Save(0), m_MCLRMonitor(0),
 
56
      PPLx4(false), clksource(0), clkcontrol(0)
 
57
{
 
58
    m_phase1     = new PhaseExec1( this );
 
59
    m_phase2     = new PhaseExec2( this );
 
60
    m_phaseInter = new PhaseInter( this );
 
61
    m_phaseIdle  = new PhaseIdle( this );
 
62
    m_phaseCurr  = m_phase1;
 
63
 
 
64
    eeprom = 0;
 
65
 
 
66
    pll_factor = 0;
 
67
 
 
68
    Integer::setDefaultBitmask(0xff);
 
69
 
 
70
    // Test code for logging to disk:
 
71
    for( int i=0; i<4; i++ ) osc_pin_Number[i] = 254;
 
72
}
 
73
 
 
74
pic_processor::~pic_processor()
 
75
{
 
76
    delete_SfrReg(Wreg);
 
77
    delete_SfrReg(pcl);
 
78
 
 
79
    delete_SfrReg(pclath);
 
80
    delete_SfrReg(status);
 
81
    delete_SfrReg(indf);
 
82
 
 
83
    delete stack;
 
84
 
 
85
    delete m_phase1;
 
86
    delete m_phase2;
 
87
    delete m_phaseInter;
 
88
    delete m_phaseIdle;
 
89
 
 
90
    delete m_configMemory;
 
91
 
 
92
    if( m_MCLR)        m_MCLR->setMonitor(0);
 
93
    if( m_MCLR_Save)   m_MCLR_Save->setMonitor(0);
 
94
    if( m_MCLRMonitor) delete m_MCLRMonitor;
 
95
 
 
96
    if( clksource)  delete clksource;
 
97
    if( clkcontrol) delete clkcontrol;
 
98
}
 
99
 
 
100
//-------------------------------------------------------------------
 
101
//
 
102
//    create
 
103
//
 
104
//  The purpose of this member function is to 'create' a pic processor.
 
105
// Since this is a base class member function, only those things that
 
106
// are common to all pics are created.
 
107
 
 
108
void pic_processor::create( )
 
109
{
 
110
    init_program_memory( program_memory_size() );
 
111
    init_register_memory( register_memory_size() );
 
112
 
 
113
    pc->set_cpu( this );
 
114
 
 
115
    Wreg   = new WREG( this, "W" );
 
116
    pcl    = new PCL( this, "pcl" );
 
117
    pclath = new PCLATH( this, "pclath" );
 
118
    status = new StatusReg( this );
 
119
    indf   = new INDF( this, "indf" );
 
120
 
 
121
    register_bank = &registers[0];  // Define the active register bank
 
122
 
 
123
    create_config_memory();
 
124
}
 
125
 
 
126
//-------------------------------------------------------------------
 
127
//
 
128
// add_SfrReg
 
129
//
 
130
// The purpose of this routine is to add one special function register
 
131
// to the file registers. If the sfr has a physical address( like the
 
132
// status or tmr0 registers) then a pointer to that register will be
 
133
// placed in the file register map.
 
134
 
 
135
// FIXME It doesn't make any sense to initialize the por_value here!
 
136
// FIXME The preferred way is to initialize all member data in their
 
137
// FIXME parent's constructor.
 
138
 
 
139
void pic_processor::add_SfrReg( Register *reg, uint addr,
 
140
                                     RegisterValue por_value,
 
141
                                     const char *new_name,
 
142
                                     bool warn_dup )
 
143
{
 
144
    reg->set_cpu(this);
 
145
    if(addr < register_memory_size())
 
146
    {
 
147
        if( registers[addr])
 
148
        {
 
149
            if( registers[addr]->isa() == Register::INVALID_REGISTER)
 
150
            {
 
151
                delete registers[addr];
 
152
                registers[addr] = reg;
 
153
            }
 
154
        }
 
155
        else registers[addr] = reg;
 
156
 
 
157
        reg->address = addr;
 
158
        reg->alias_mask = 0;
 
159
 
 
160
        if(new_name) reg->new_name(new_name);
 
161
    }
 
162
    reg->value       = por_value;
 
163
    reg->por_value   = por_value;  /// FIXME why are we doing this?
 
164
    reg->initialize();
 
165
}
 
166
 
 
167
// Use this function when register is initialized on WDT reset to
 
168
// same value as a POR.
 
169
void pic_processor::add_SfrRegR(SfrReg *reg, uint addr,
 
170
                                      RegisterValue por_value,
 
171
                                      const char *new_name,
 
172
                                      bool warn_dup )
 
173
{
 
174
    add_SfrReg( reg, addr, por_value, new_name, warn_dup );
 
175
    reg->wdtr_value = por_value;
 
176
}
 
177
 
 
178
 
 
179
// This both deletes the register from the registers array,
 
180
// but also deletes the register object.
 
181
 
 
182
void pic_processor::delete_SfrReg( Register *pReg )
 
183
{
 
184
    if( pReg )
 
185
    {
 
186
        uint a = pReg->getAddress();
 
187
 
 
188
        if( 0) cout << __FUNCTION__ << " addr = 0x"<<hex<<a <<" reg " << pReg->name_str<<endl;
 
189
 
 
190
        if( a<nRegisters && registers[a] == pReg ) delete_file_registers(a,a);
 
191
        else delete pReg;
 
192
    }
 
193
}
 
194
 
 
195
// This is the inverse of add_SfrReg and does not delete the register.
 
196
 
 
197
void pic_processor::remove_SfrReg(Register *ppReg)
 
198
{
 
199
    if( ppReg)
 
200
    {
 
201
        uint a = ppReg->getAddress();
 
202
        if( a == AN_INVALID_ADDRESS ) return;
 
203
        if( registers[a] == ppReg )   delete_file_registers(a,a,true);
 
204
    }
 
205
}
 
206
 
 
207
bool pic_processor::set_config_word( uint address, uint cfg_word )
 
208
{
 
209
    int i = get_config_index(address);
 
210
 
 
211
    if( i >= 0)
 
212
    {
 
213
        m_configMemory->getConfigWord(i)->set((int)cfg_word);
 
214
        if( i==0 )
 
215
        {
 
216
            config_word = cfg_word;
 
217
        }
 
218
        return true;
 
219
    }
 
220
    return false;
 
221
}
 
222
 
 
223
uint pic_processor::get_config_word(uint address)
 
224
{
 
225
    int i= get_config_index(address);
 
226
 
 
227
    if( i >= 0 ) return m_configMemory->getConfigWord(i)->getVal();
 
228
 
 
229
    return 0xffffffff;
 
230
}
 
231
 
 
232
int pic_processor::get_config_index(uint address)
 
233
{
 
234
    if( m_configMemory)
 
235
    {
 
236
        for(int i = 0; i < m_configMemory->getnConfigWords(); i++)
 
237
        {
 
238
            if( m_configMemory->getConfigWord(i))
 
239
            {
 
240
                if( m_configMemory->getConfigWord(i)->ConfigWordAdd() == address)
 
241
                {
 
242
                    return i;
 
243
                }
 
244
            }
 
245
        }
 
246
    }
 
247
    return -1;
 
248
}
 
249
 
 
250
//------------------------------------------------------------------------
 
251
// ConfigMemory - Base class
 
252
ConfigWord::ConfigWord(const char*_name, uint default_val, pic_processor *pCpu, uint addr, bool EEw)
 
253
    : Integer(_name, default_val ), m_pCpu(pCpu), m_addr(addr),
 
254
      EEWritable(EEw)
 
255
{ }
 
256
 
 
257
void ConfigWord::get(int64_t &i)
 
258
{
 
259
    Integer::get(i);
 
260
}
 
261
 
 
262
//------------------------------------------------------------------------
 
263
ConfigMemory::ConfigMemory(pic_processor *pCpu, uint nWords)
 
264
    : m_pCpu(pCpu)
 
265
    , m_nConfigWords(nWords)
 
266
{
 
267
    if( nWords > 0 && nWords < 100)
 
268
    {
 
269
        m_ConfigWords = new ConfigWord*[nWords];
 
270
 
 
271
        for( uint i=0; i<nWords; i++ ) m_ConfigWords[i] = 0;
 
272
    }
 
273
}
 
274
 
 
275
ConfigMemory::~ConfigMemory()
 
276
{
 
277
    delete [] m_ConfigWords;
 
278
}
 
279
 
 
280
int ConfigMemory::addConfigWord(uint addr, ConfigWord *pConfigWord)
 
281
{
 
282
    if( addr < m_nConfigWords)
 
283
    {
 
284
        m_ConfigWords[addr] = pConfigWord;
 
285
        return 1;
 
286
    }
 
287
    delete pConfigWord;
 
288
    return 0;
 
289
}
 
290
 
 
291
ConfigWord *ConfigMemory::getConfigWord(uint addr)
 
292
{
 
293
    return addr < m_nConfigWords ? m_ConfigWords[addr] : 0;
 
294
}
 
295
//-------------------------------------------------------------------
 
296
class MCLRPinMonitor : public PinMonitor
 
297
{
 
298
public:
 
299
    MCLRPinMonitor(pic_processor *pCpu);
 
300
    ~MCLRPinMonitor() {}
 
301
 
 
302
    virtual void setDrivenState(char);
 
303
    virtual void setDrivingState(char) {}
 
304
    virtual void set_nodeVoltage(double) {}
 
305
    virtual void putState(char) {}
 
306
    virtual void setDirection() {}
 
307
 
 
308
private:
 
309
    pic_processor *m_pCpu;
 
310
    char m_cLastResetState;
 
311
};
 
312
 
 
313
MCLRPinMonitor::MCLRPinMonitor(pic_processor *pCpu)
 
314
    : m_pCpu(pCpu),
 
315
      m_cLastResetState('I')  // I is not a valid state. It's used here for 'I'nitialization
 
316
{ }
 
317
 
 
318
void MCLRPinMonitor::setDrivenState(char newState)
 
319
{
 
320
    if( newState =='0' || newState =='w')
 
321
    {
 
322
        m_cLastResetState = '0';
 
323
        m_pCpu->reset(MCLR_RESET);
 
324
    }
 
325
 
 
326
    if( newState =='1' || newState =='W')
 
327
    {
 
328
        if( m_cLastResetState == '0') m_pCpu->reset(EXIT_RESET);
 
329
 
 
330
        m_cLastResetState = '1';
 
331
    }
 
332
}
 
333
 
 
334
//-------------------------------------------------------------------
 
335
void pic_processor::createMCLRPin(int pkgPinNumber)
 
336
{
 
337
    if( m_MCLR) cout << "BUG?: assigning multiple MCLR pins: " << __FILE__ << dec << " " << __LINE__ << endl;
 
338
 
 
339
    assign_pin( pkgPinNumber, m_MCLR );
 
340
 
 
341
    m_MCLRMonitor = new MCLRPinMonitor(this);
 
342
    m_MCLR->setMonitor(m_MCLRMonitor);
 
343
}
 
344
 
 
345
//-------------------------------------------------------------------
 
346
// This function is called instead of createMCLRPin where the pin
 
347
// is already defined, but the configuration word has set the function
 
348
// to MCLR
 
349
 
 
350
void pic_processor::assignMCLRPin(int pkgPinNumber)
 
351
{
 
352
    if( m_MCLR == NULL )
 
353
    {
 
354
        m_MCLR_pin = pkgPinNumber;
 
355
        m_MCLR = new IOPIN( "MCLR", OPEN_COLLECTOR ) ;
 
356
 
 
357
        m_MCLR_Save = get_pin( pkgPinNumber );
 
358
        assign_pin( pkgPinNumber,m_MCLR );
 
359
 
 
360
        m_MCLRMonitor = new MCLRPinMonitor(this);
 
361
        m_MCLR->setMonitor( m_MCLRMonitor );
 
362
    }
 
363
    else if( m_MCLR != get_pin( pkgPinNumber ) )
 
364
    {
 
365
        cout << "BUG?: assigning multiple MCLR pins: "
 
366
             << dec << pkgPinNumber << " " << __FILE__ <<  " "
 
367
             << __LINE__ << endl;
 
368
    }
 
369
}
 
370
//-------------------------------------------------------------------
 
371
// This function sets the pin currently set as MCLR back to its original function
 
372
void pic_processor::unassignMCLRPin()
 
373
{
 
374
    if( m_MCLR_Save )
 
375
    {
 
376
        assign_pin( m_MCLR_pin, m_MCLR_Save );
 
377
 
 
378
        if( m_MCLR )
 
379
        {
 
380
            m_MCLR->setMonitor(0);
 
381
            m_MCLR = NULL;
 
382
            
 
383
            if( m_MCLRMonitor )
 
384
            {
 
385
                delete m_MCLRMonitor;
 
386
                m_MCLRMonitor = NULL;
 
387
            }
 
388
        }
 
389
    }
 
390
}
 
391
//--------------------------------------------------
 
392
//
 
393
class IO_SignalControl : public SignalControl
 
394
{
 
395
public:
 
396
    IO_SignalControl(char _dir){ direction = _dir; }
 
397
    ~IO_SignalControl(){}
 
398
    virtual char getState() { return direction; }
 
399
    virtual void release() {}
 
400
    void setState(char _dir) { direction = _dir; }
 
401
 
 
402
private:
 
403
    char direction;
 
404
};
 
405
 
 
406
// This function sets a label on a pin and if PinMod is defined
 
407
// removes its control from it's port register
 
408
//
 
409
void pic_processor::set_clk_pin(uint pkg_Pin_Number,
 
410
                                PinModule *PinMod,
 
411
                                const char * name,
 
412
                                bool in,
 
413
                                PicPortRegister *m_port,
 
414
                                PicTrisRegister *m_tris,
 
415
                                PicLatchRegister *m_lat)
 
416
{
 
417
    if( PinMod )
 
418
    {
 
419
        if( m_port)
 
420
        {
 
421
            uint mask = m_port->getEnableMask();
 
422
            mask &= ~(1<< PinMod->getPinNumber());
 
423
            m_port->setEnableMask(mask);
 
424
            
 
425
            if( m_tris ) m_tris->setEnableMask(mask);
 
426
            if( m_lat )  m_lat->setEnableMask(mask);
 
427
        }
 
428
        if( !clksource)
 
429
        {
 
430
            clksource  = new PeripheralSignalSource(PinMod);
 
431
            clkcontrol = new IO_SignalControl(in ? '1' : '0');
 
432
        }
 
433
        PinMod->setSource( clksource );
 
434
        PinMod->setControl( clkcontrol );
 
435
        PinMod->updatePinModule();
 
436
    }
 
437
}
 
438
 
 
439
// This function reverses the effects of the previous function
 
440
void pic_processor::clr_clk_pin(uint pkg_Pin_Number,
 
441
                                PinModule *PinMod,
 
442
                                PicPortRegister *m_port,
 
443
                                PicTrisRegister *m_tris,
 
444
                                PicLatchRegister *m_lat)
 
445
{
 
446
    if( PinMod)
 
447
    {
 
448
        if( m_port)
 
449
        {
 
450
            uint mask = m_port->getEnableMask();
 
451
            mask |=( 1<< PinMod->getPinNumber());
 
452
            m_port->setEnableMask(mask);
 
453
            
 
454
            if( m_tris) m_tris->setEnableMask(mask);
 
455
            if( m_lat)  m_lat->setEnableMask(mask);
 
456
        }
 
457
        PinMod->setSource(0);
 
458
        PinMod->setControl(0);
 
459
        PinMod->updatePinModule();
 
460
    }
 
461
}
 
462
 
 
463
void pic_processor::osc_mode(uint value)
 
464
{
 
465
    IOPIN *m_pin;
 
466
    uint pin_Number =  get_osc_pin_Number(0);
 
467
 
 
468
    if( pin_Number < 253)  m_pin = get_pin( pin_Number );
 
469
 
 
470
    if(( pin_Number =  get_osc_pin_Number(1)) < 253
 
471
            &&( m_pin = get_pin( pin_Number )) )
 
472
    {
 
473
        pll_factor = 0;
 
474
        if( value < 5 )
 
475
        {
 
476
            set_clk_pin(pin_Number, m_osc_Monitor[1], "OSC2", true);
 
477
        }
 
478
        else if(value == 6 )
 
479
        {
 
480
            pll_factor = 2;
 
481
            set_clk_pin(pin_Number, m_osc_Monitor[1], "CLKO", false);
 
482
        }
 
483
        else clr_clk_pin(pin_Number, m_osc_Monitor[1]);
 
484
    }
 
485
}
 
486
 
 
487
void pic_processor::Wput(uint value)
 
488
{
 
489
    Wreg->put(value);
 
490
}
 
491
 
 
492
uint pic_processor::Wget()
 
493
{
 
494
    return Wreg->get();
 
495
}
 
496
 
 
497
void pic_processor::set_eeprom( EEPROM *e )
 
498
{
 
499
    eeprom = e;
 
500
}
 
501
 
 
502
void pic_processor::enter_sleep() // processor is about to go to sleep, update the status register.
 
503
{
 
504
    status->put_TO(1);
 
505
    status->put_PD(0);
 
506
 
 
507
    sleep_time = m_cycle;
 
508
    wdt.update();
 
509
    pc->increment();
 
510
    save_pNextPhase = m_phaseCurr->getNextPhase();
 
511
    save_CurrentPhase = m_phaseCurr;
 
512
    m_phaseCurr->setNextPhase( m_phaseIdle );
 
513
    m_phaseCurr = m_phaseIdle;
 
514
    m_phaseCurr->setNextPhase( m_phaseIdle );
 
515
    m_ActivityState = ePASleeping;
 
516
}
 
517
 
 
518
void pic_processor::exit_sleep()
 
519
{
 
520
    if( m_cycle == sleep_time )// If enter and exit sleep at same clock cycle, restore execute state
 
521
    {
 
522
        m_phaseCurr = save_CurrentPhase;
 
523
        m_phaseCurr->setNextPhase( save_pNextPhase );
 
524
    }
 
525
    else
 
526
    {
 
527
        m_phaseCurr = m_phase1;
 
528
        m_phaseCurr->setNextPhase( m_phase1 );
 
529
    }
 
530
    m_ActivityState = ePAActive;
 
531
}
 
532
 
 
533
bool pic_processor::is_sleeping()
 
534
{
 
535
    return m_ActivityState == ePASleeping;
 
536
}
 
537
 
 
538
void pic_processor::BP_set_interrupt()
 
539
{
 
540
    m_phaseInter->firstHalf();
 
541
}
 
542
 
 
543
void pic_processor::pm_write( ) // program memory write
 
544
{
 
545
    m_ActivityState = ePAPMWrite;
 
546
 
 
547
    do incrementCycle();     // burn cycles until we're through writing
 
548
    while( have_pm_write() );
 
549
}
 
550
 
 
551
void pic_processor::reset( RESET_TYPE r )// Reset the pic on desired reset type.
 
552
{
 
553
    m_halted = true;
 
554
    resetRegisters( r );
 
555
    m_halted = false;
 
556
 
 
557
    stack->reset( r );
 
558
    wdt.reset( r );
 
559
    pc->reset();
 
560
    //m_activeCB.clear(); // Usart not working here
 
561
    //m_cycle = 0;
 
562
    //qDebug() << "pic_processor::reset"<<m_activeCB.uniqueKeys();
 
563
 
 
564
    switch( r )
 
565
    {
 
566
    case POR_RESET:
 
567
        //cout << "POR reset\n";
 
568
        m_phaseCurr = m_phaseCurr ? m_phaseCurr : m_phase1;
 
569
        m_ActivityState = ePAActive;
 
570
        break;
 
571
 
 
572
    case SOFT_RESET:
 
573
        cout << "Reset due to Software reset instruction\n";
 
574
        m_phaseCurr = m_phase1;
 
575
        m_phaseCurr->setNextPhase( m_phase1 );
 
576
        m_ActivityState = ePAActive;
 
577
        break;
 
578
 
 
579
    case MCLR_RESET:
 
580
        cout << "MCLR reset\n";
 
581
        m_phaseCurr = m_phaseIdle;
 
582
        m_phaseCurr->setNextPhase( m_phaseIdle );
 
583
        m_ActivityState = ePAIdle;
 
584
        break;
 
585
 
 
586
    case IO_RESET:
 
587
        cout << "IO reset\n";
 
588
        m_phaseCurr = m_phase1;
 
589
        m_phaseCurr->setNextPhase( m_phase1 );
 
590
        m_ActivityState = ePAActive;
 
591
        break;
 
592
 
 
593
    case WDT_RESET:
 
594
        cout << "Reset on Watch Dog Timer expire\n";
 
595
        m_phaseCurr = m_phaseCurr ? m_phaseCurr : m_phase1;
 
596
        m_phaseCurr->setNextPhase( m_phase1 );
 
597
        m_ActivityState = ePAActive;
 
598
        break;
 
599
 
 
600
    case EXIT_RESET:        // MCLR reset has cleared
 
601
        cout <<"MCLR low, resume execution\n";
 
602
        m_phaseCurr = m_phaseCurr ? m_phaseCurr : m_phase1;
 
603
        m_phaseCurr->setNextPhase(m_phase1);
 
604
        m_ActivityState = ePAActive;
 
605
        return;
 
606
        break;
 
607
 
 
608
    case STKOVF_RESET:
 
609
        cout << "Reset on Stack overflow\n";
 
610
        m_phaseCurr = m_phaseCurr ? m_phaseCurr : m_phaseIdle;
 
611
        m_phaseCurr->setNextPhase(m_phaseIdle);
 
612
        m_ActivityState = ePAActive;
 
613
        break;
 
614
 
 
615
    case STKUNF_RESET:
 
616
        cout << "Reset on Stack undeflow\n";
 
617
        m_phaseCurr = m_phaseCurr ? m_phaseCurr : m_phaseIdle;
 
618
        m_phaseCurr->setNextPhase(m_phaseIdle);
 
619
        m_ActivityState = ePAActive;
 
620
        break;
 
621
 
 
622
    default:
 
623
        printf("pic_processor::reset unknow reset type %d\n", r);
 
624
        m_ActivityState = ePAActive;
 
625
        break;
 
626
    }
 
627
}