/*
Copyright (C) 1998 T. Scott Dattalo
This file is part of gpsim.
gpsim is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
gpsim is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with gpasm; see the file COPYING. If not, write to
the Free Software Foundation, 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */
//
// p12x
//
// This file supports:
// PIC12C508
// PIC12C509
//
#include <stdio.h>
#include <iostream>
#include <string>
#include "packages.h"
#include "stimuli.h"
#include "i2c-ee.h"
#include "p12x.h"
#include "symbol.h"
//========================================================================
// The P12 devices with an EEPROM contain two die. One is the 12C core and
// the other is an I2C EEPROM (Actually, it is not know if there are two
// physical die. However, it is known that there are two functional layouts
// in the same package.) These two devices are connected internally.
class P12_I2C_EE : public I2C_EE
{
public:
P12_I2C_EE(pic_processor *, unsigned int _rom_size);
protected:
RegisterCollection *m_UiAccessOfRom; // User access to the rom.
};
P12_I2C_EE::P12_I2C_EE(pic_processor *pcpu, unsigned int _rom_size)
: I2C_EE(_rom_size)
{
if(pcpu) {
pcpu->ema.set_cpu(pcpu);
pcpu->ema.set_Registers(rom, rom_size);
m_UiAccessOfRom = new RegisterCollection(pcpu,
"eeData",
rom,
rom_size);
}
}
//========================================================================
void P12C508::create_iopin_map()
{
package = new Package(8);
if(!package)
return;
package->assign_pin(7, m_gpio->addPin(new IO_bi_directional_pu("gpio0"),0));
package->assign_pin(6, m_gpio->addPin(new IO_bi_directional_pu("gpio1"),1));
package->assign_pin(5, m_gpio->addPin(new IO_bi_directional("gpio2"),2));
package->assign_pin(4, m_gpio->addPin(new IOPIN("gpio3"),3));
package->assign_pin(3, m_gpio->addPin(new IO_bi_directional("gpio4"),4));
package->assign_pin(2, m_gpio->addPin(new IO_bi_directional("gpio5"),5));
package->assign_pin(1, 0);
package->assign_pin(8, 0);
}
//--------------------------------------------------------
void P12C508::reset(RESET_TYPE r)
{
m_tris->reset(r);
switch (r) {
case IO_RESET:
// Set GPWUF flag
status->put(status->get() | 0x80);
// fall through...
default:
_12bit_processor::reset(r);
}
}
//------------------------------------------------------------------------
#define STATUS_GPWUF 0x80
void P12C508::enter_sleep()
{
pic_processor::enter_sleep();
status->put( status->get() & ~STATUS_GPWUF);
cout << "enter sleep status="<<hex <<status->get()<<endl;
}
void P12C508::option_new_bits_6_7(unsigned int bits)
{
if(verbose)
cout << "p12c508 option_new_bits_6_7\n";
m_gpio->setPullUp ( (bits & (1<<6)) == (1<<6) );
}
void P12C508::create_sfr_map()
{
RegisterValue porVal(0,0);
add_sfr_register(indf, 0, porVal);
add_sfr_register(&tmr0, 1, porVal);
add_sfr_register(pcl, 2, porVal);
add_sfr_register(status, 3, porVal);
add_sfr_register(fsr, 4, porVal);
add_sfr_register(&osccal,5, porVal);
add_sfr_register(m_gpio, 6, porVal);
add_sfr_register(m_tris, 0xffffffff, RegisterValue(0x3f,0));
add_sfr_register(W, 0xffffffff, porVal);
add_sfr_register(&option_reg, 0xffffffff, RegisterValue(0xff,0));
osccal.new_name("osccal");
}
void P12C508::create_symbols()
{
_12bit_processor::create_symbols();
//symbol_table.add_register(m_gpio);
symbol_table.add_register(m_tris);
}
void P12C508::dump_registers ()
{
_12bit_processor::dump_registers();
cout << "tris = 0x" << hex << m_tris->value.get() << '\n';
cout << "osccal = 0x" << osccal.value.get() << '\n';
}
void P12C508::tris_instruction(unsigned int tris_register)
{
m_tris->put(W->value.get());
trace.write_TRIS(m_tris->value.get());
}
void P12C508::create()
{
create_iopin_map();
_12bit_processor::create();
add_file_registers(0x07, 0x1f, 0);
P12C508::create_sfr_map();
create_invalid_registers ();
tmr0.set_cpu(this,m_gpio,2);
tmr0.start(0);
pc->reset();
}
Processor * P12C508::construct(const char *name)
{
P12C508 *p = new P12C508(name);
p->pc->set_reset_address(0x1ff);
p->create();
p->create_symbols();
symbol_table.add_module(p,p->name_str.c_str());
return p;
}
P12C508::P12C508(const char *_name, const char *desc)
: _12bit_processor(_name,desc)
{
if(verbose)
cout << "12c508 constructor, type = " << isa() << '\n';
m_gpio = new GPIO("gpio",8,0x3f);
m_tris = new PicTrisRegister("tris",m_gpio);
m_tris->wdtr_value=RegisterValue(0x3f,0);
if(config_modes)
config_modes->valid_bits = config_modes->CM_FOSC0 | config_modes->CM_FOSC1 |
config_modes->CM_FOSC1x | config_modes->CM_WDTE | config_modes->CM_MCLRE;
}
P12C508::~P12C508()
{
}
//--------------------------------------------------------
void P12C509::create_sfr_map()
{
}
Processor * P12C509::construct(const char *name)
{
P12C509 *p = new P12C509(name);
if (verbose)
cout << " 12c508 construct\n";
p->pc->set_reset_address(0x3ff);
p->create();
p->create_symbols();
symbol_table.add_module(p,p->name_str.c_str());
return p;
}
void P12C509::create()
{
if ( verbose )
cout << " 12c509 create \n";
P12C508::create();
alias_file_registers(0x00,0x0f,0x20);
add_file_registers(0x30, 0x3f, 0);
pa_bits = PA0; // the 509 has two code pages (i.e. PAO in status is used)
indf->base_address_mask2 = 0x3F; // RP - need this or INDF won't work right
}
P12C509::P12C509(const char *_name, const char *desc)
: P12C508(_name,desc)
{
if(verbose)
cout << "12c509 constructor, type = " << isa() << '\n';
}
//--------------------------------------------------------
// construct function is identical to 12C508 version ??
Processor * P12CE518::construct(const char *name)
{
P12CE518 *p = new P12CE518(name);
if(verbose)
cout << " 12ce518 construct\n";
p->pc->set_reset_address(0x1ff);
p->create();
if(verbose)
cout << " ... create symbols\n";
p->create_symbols();
symbol_table.add_module(p,p->name_str.c_str());
return p;
}
void P12CE518::create_iopin_map()
{
P12C508::create_iopin_map();
// Define the valid I/O pins.
//gpio.valid_iopins = 0xff;
}
void P12CE518::create()
{
Stimulus_Node *scl, *sda;
if(verbose)
cout << " 12ce518 create \n";
P12C508::create();
if(verbose)
cout << " adding serial EE\n";
m_eeprom = new P12_I2C_EE(this, 0x10);
m_eeprom->debug();
// GPIO bits 6 and 7 are not bonded to physical pins, but are tied
// to the internal I2C device.
m_gpio->setEnableMask(0xc0 | m_gpio->getEnableMask());
RegisterValue por_value(0xc0,0x00);
m_gpio->value = por_value;
m_gpio->por_value = por_value;
m_gpio->wdtr_value = por_value;
m_gpio->put(0xc0);
// Kludge to force top two bits to be outputs
m_tris->put(0x3f);
{
scl = new Stimulus_Node ( "EE_SCL" );
IO_bi_directional_pu *io_scl = new IO_bi_directional_pu("gpio7");
io_scl->update_pullup('1',true);
io_scl->setDrivingState(true);
io_scl->setDriving(true);
scl->attach_stimulus( m_gpio->addPin(io_scl,7));
scl->update();
}
{
sda = new Stimulus_Node ( "EE_SDA" );
IO_open_collector *io_sda = new IO_open_collector("gpio6");
// enable the pullup resistor.
io_sda->update_pullup('1',true);
io_sda->setDrivingState(true);
io_sda->setDriving(true);
m_gpio->addPin(io_sda,6);
sda->attach_stimulus (io_sda);
sda->update();
}
m_eeprom->attach ( scl, sda );
/*
ema.set_cpu(this);
ema.set_Registers(m_eeprom->rom, m_eeprom->rom_size);
*/
}
P12CE518::P12CE518(const char *_name, const char *desc)
: P12C508(_name,desc)
{
if(verbose)
cout << "12CE518 constructor, type = " << isa() << '\n';
if(config_modes)
config_modes->valid_bits = config_modes->CM_FOSC0 | config_modes->CM_FOSC1 |
config_modes->CM_FOSC1x | config_modes->CM_WDTE | config_modes->CM_MCLRE;
}
void P12CE518::tris_instruction(unsigned int tris_register)
{
unsigned int w_val;
w_val = W->value.get();
m_tris->put ( w_val & 0x3F ); // top two bits always output
trace.write_TRIS(w_val);
}
//--------------------------------------------------------
void P12CE519::create_sfr_map()
{
}
Processor * P12CE519::construct(const char *name)
{
P12CE519 *p = new P12CE519(name);
cout << " 12ce519 construct\n";
p->pc->set_reset_address(0x3ff);
p->create();
p->create_symbols();
symbol_table.add_module(p,p->name_str.c_str());
return p;
}
void P12CE519::create()
{
if ( verbose )
cout << " 12ce519 create \n";
P12CE518::create();
alias_file_registers(0x00,0x0f,0x20);
add_file_registers(0x30, 0x3f, 0);
pa_bits = PA0; // the 519 has two code pages (i.e. PAO in status is used)
indf->base_address_mask2 = 0x3F; // RP - need this or INDF won't work right
}
P12CE519::P12CE519(const char *_name, const char *desc)
: P12CE518(_name,desc)
{
if(verbose)
cout << "12ce519 constructor, type = " << isa() << '\n';
}
//--------------------------------------------------------
//
// GPIO Port
GPIO::GPIO(const char *port_name, unsigned int numIopins,
unsigned int enableMask)
: PicPortRegister (port_name, numIopins, enableMask)
{
}
void GPIO::setbit(unsigned int bit_number, bool new_value)
{
unsigned int lastDrivenValue = rvDrivenValue.data;
PortRegister::setbit(bit_number, new_value);
// If gpio bit 0,1 or 3 changed states AND
// ~GPWU is low (wake up on change is enabled) AND
// the processor is sleeping.
// Then wake
if ((lastDrivenValue ^ rvDrivenValue.data) & 0x0b) {
if( ((cpu12->option_reg.value.get() & 0x80) == 0) && bp.have_sleep()) {
if(verbose)
cout << "IO bit changed while the processor was sleeping,\n\
so the processor is waking up\n";
cpu->reset(IO_RESET);
}
}
}
void GPIO::setPullUp ( bool bNewPU )
{
m_bPU = !bNewPU;
if ( verbose & 16 )
printf("GPIO::setPullUp() =%d\n",(m_bPU?1:0));
unsigned int mask = getEnableMask();
for (unsigned int i=0, m=1; mask; i++, m<<= 1)
if (mask & m)
{
mask ^= m;
getPin(i)->update_pullup ( m_bPU ? '1' : '0', true );
}
}
//--------------------------------------------------------
//------------------------------------------------------------------------
void P10F200::create_iopin_map()
{
package = new Package(6);
if(!package)
return;
package->assign_pin(1, m_gpio->addPin(new IO_bi_directional_pu("gpio0"),0));
package->assign_pin(3, m_gpio->addPin(new IO_bi_directional_pu("gpio1"),1));
package->assign_pin(4, m_gpio->addPin(new IO_bi_directional("gpio2"),2));
package->assign_pin(6, m_gpio->addPin(new IOPIN("gpio3"),3));
package->assign_pin(2, 0);
package->assign_pin(5, 0);
}
/*
void P10F200::create_sfr_map()
{
RegisterValue porVal(0,0);
add_sfr_register(indf, 0, porVal);
add_sfr_register(&tmr0, 1, porVal);
add_sfr_register(pcl, 2, porVal);
add_sfr_register(status, 3, porVal);
add_sfr_register(fsr, 4, porVal);
add_sfr_register(&osccal,5, porVal);
add_sfr_register(m_gpio, 6, porVal);
add_sfr_register(m_tris, 0xffffffff, RegisterValue(0x0f,0));
add_sfr_register(W, 0xffffffff, porVal);
add_sfr_register(&option_reg, 0xffffffff, RegisterValue(0xff,0));
osccal.new_name("osccal");
}
*/
void P10F200::create()
{
create_iopin_map();
_12bit_processor::create();
add_file_registers(0x10, 0x1f, 0); // 10F200 only has 16 bytes RAM
P12C508::create_sfr_map();
create_invalid_registers ();
tmr0.set_cpu(this,m_gpio,2);
tmr0.start(0);
pc->reset();
}
Processor * P10F200::construct(const char *name)
{
P10F200 *p = new P10F200(name);
p->pc->set_reset_address(0x0ff);
p->create();
p->create_symbols();
symbol_table.add_module(p,p->name_str.c_str());
return p;
}
P10F200::P10F200(const char *_name, const char *desc)
: P12C508(_name,desc)
{
if(verbose)
cout << "10f200 constructor, type = " << isa() << '\n';
m_gpio = new GPIO("gpio",8,0x0f);
m_tris = new PicTrisRegister("tris",m_gpio);
m_tris->wdtr_value=RegisterValue(0x3f,0);
if(config_modes)
config_modes->valid_bits = config_modes->CM_WDTE | config_modes->CM_MCLRE;
}
P10F200::~P10F200()
{
}
//------------------------------------------------------------------------
void P10F202::create()
{
create_iopin_map();
_12bit_processor::create();
add_file_registers(0x08, 0x1f, 0); // 10F202 has 24 bytes RAM
P12C508::create_sfr_map();
create_invalid_registers ();
tmr0.set_cpu(this,m_gpio,2);
tmr0.start(0);
pc->reset();
}
Processor * P10F202::construct(const char *name)
{
P10F202 *p = new P10F202(name);
p->pc->set_reset_address(0x1ff);
p->create();
p->create_symbols();
symbol_table.add_module(p,p->name_str.c_str());
return p;
}
P10F202::P10F202(const char *_name, const char *desc)
: P10F200(_name,desc)
{
if(verbose)
cout << "10f202 constructor, type = " << isa() << '\n';
}
syntax highlighted by Code2HTML, v. 0.9.1