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 
22 //
23 // p16f62x
24 //
25 //  This file supports:
26 //    PIC16F627
27 //    PIC16F628
28 //    PIC16F648
29 //
30 
31 #include <iostream>
32 
33 #include "p16f62x.h"
34 #include "pic-ioports.h"
35 #include "packages.h"
36 #include "ui.h"
37 
P16F62x(const char * _name,const char * desc)38 P16F62x::P16F62x(const char *_name, const char *desc)
39   : P16X6X_processor(_name, desc),
40     usart(this),
41     comparator(this)
42 {
43 }
44 
45 
~P16F62x()46 P16F62x::~P16F62x()
47 {
48   delete_file_registers(0xc0, 0xef);
49   delete_file_registers(0x120, 0x14f);
50   remove_sfr_register(&usart.rcsta);
51   remove_sfr_register(&usart.txsta);
52   remove_sfr_register(&usart.spbrg);
53   remove_sfr_register(&comparator.cmcon);
54   remove_sfr_register(&comparator.vrcon);
55   delete_sfr_register(usart.txreg);
56   delete_sfr_register(usart.rcreg);
57   delete eeprom;
58 }
59 
60 
create_iopin_map()61 void P16F62x::create_iopin_map()
62 {
63   package = new Package(18);
64 
65   if (!package) {
66     return;
67   }
68 
69   // Now Create the package and place the I/O pins
70   package->assign_pin(17, m_porta->addPin(new IO_bi_directional("porta0"), 0));
71   package->assign_pin(18, m_porta->addPin(new IO_bi_directional("porta1"), 1));
72   package->assign_pin(1, m_porta->addPin(new IO_bi_directional("porta2"), 2));
73   package->assign_pin(2, m_porta->addPin(new IO_bi_directional("porta3"), 3));
74   package->assign_pin(3, m_porta->addPin(new IO_open_collector("porta4"), 4));
75   package->assign_pin(4, m_porta->addPin(new IO_bi_directional("porta5"), 5));
76   package->assign_pin(15, m_porta->addPin(new IO_bi_directional("porta6"), 6));
77   package->assign_pin(16, m_porta->addPin(new IO_bi_directional("porta7"), 7));
78   package->assign_pin(5, 0);  // Vss
79   package->assign_pin(6, m_portb->addPin(new IO_bi_directional_pu("portb0"), 0));
80   package->assign_pin(7, m_portb->addPin(new IO_bi_directional_pu("portb1"), 1));
81   package->assign_pin(8, m_portb->addPin(new IO_bi_directional_pu("portb2"), 2));
82   package->assign_pin(9, m_portb->addPin(new IO_bi_directional_pu("portb3"), 3));
83   package->assign_pin(10, m_portb->addPin(new IO_bi_directional_pu("portb4"), 4));
84   package->assign_pin(11, m_portb->addPin(new IO_bi_directional_pu("portb5"), 5));
85   package->assign_pin(12, m_portb->addPin(new IO_bi_directional_pu("portb6"), 6));
86   package->assign_pin(13, m_portb->addPin(new IO_bi_directional_pu("portb7"), 7));
87   package->assign_pin(14, 0);  // Vdd
88 }
89 
90 
create_sfr_map()91 void P16F62x::create_sfr_map()
92 {
93   add_file_registers(0xc0, 0xef, 0);   // 0xa0 - 0xbf are created in the P16X6X_processor class
94   add_file_registers(0x120, 0x14f, 0);
95   alias_file_registers(0x70, 0x7f, 0x80);
96   alias_file_registers(0x70, 0x7f, 0x100);
97   alias_file_registers(0x70, 0x7f, 0x180);
98   alias_file_registers(0x0, 0x0, 0x100);    // INDF exists in all four pages, 16x6x did the first two
99   alias_file_registers(0x0, 0x0, 0x180);
100   alias_file_registers(0x01, 0x04, 0x100);
101   alias_file_registers(0x81, 0x84, 0x100);
102   remove_sfr_register(m_trisa);
103   add_sfr_register(m_trisa, 0x85, RegisterValue(0xff, 0));
104   alias_file_registers(0x06, 0x06, 0x100);
105   alias_file_registers(0x86, 0x86, 0x100);
106   add_sfr_register(get_eeprom()->get_reg_eedata(),  0x9a);
107   add_sfr_register(get_eeprom()->get_reg_eeadr(),   0x9b);
108   add_sfr_register(get_eeprom()->get_reg_eecon1(),  0x9c, RegisterValue(0, 0));
109   add_sfr_register(get_eeprom()->get_reg_eecon2(),  0x9d);
110   // PCLATH
111   alias_file_registers(0x0a, 0x0a, 0x100);
112   alias_file_registers(0x0a, 0x0a, 0x180);
113   alias_file_registers(0x0b, 0x0b, 0x100);
114   alias_file_registers(0x0b, 0x0b, 0x180);
115   usart.initialize(pir1, &(*m_portb)[2], &(*m_portb)[1],
116                    new _TXREG(this, "txreg", "USART Transmit Register", &usart),
117                    new _RCREG(this, "rcreg", "USART Receiver Register", &usart));
118   add_sfr_register(&usart.rcsta, 0x18, RegisterValue(0, 0), "rcsta");
119   add_sfr_register(&usart.txsta, 0x98, RegisterValue(2, 0), "txsta");
120   add_sfr_register(&usart.spbrg, 0x99, RegisterValue(0, 0), "spbrg");
121   add_sfr_register(usart.txreg,  0x19, RegisterValue(0, 0), "txreg");
122   add_sfr_register(usart.rcreg,  0x1a, RegisterValue(0, 0), "rcreg");
123   intcon = &intcon_reg;
124   intcon_reg.set_pir_set(get_pir_set());
125   // Link the comparator and voltage ref to porta
126   comparator.initialize(get_pir_set(), &(*m_porta)[2], &(*m_porta)[0],
127                         &(*m_porta)[1], &(*m_porta)[2], &(*m_porta)[3], &(*m_porta)[3],
128                         &(*m_porta)[4]);
129   comparator.cmcon.set_configuration(1, 0, AN0, AN3, AN0, AN3, ZERO);
130   comparator.cmcon.set_configuration(2, 0, AN1, AN2, AN1, AN2, ZERO);
131   comparator.cmcon.set_configuration(1, 1, AN0, AN2, AN3, AN2, NO_OUT);
132   comparator.cmcon.set_configuration(2, 1, AN1, AN2, AN1, AN2, NO_OUT);
133   comparator.cmcon.set_configuration(1, 2, AN0, VREF, AN3, VREF, NO_OUT);
134   comparator.cmcon.set_configuration(2, 2, AN1, VREF, AN2, VREF, NO_OUT);
135   comparator.cmcon.set_configuration(1, 3, AN0, AN2, AN0, AN2, NO_OUT);
136   comparator.cmcon.set_configuration(2, 3, AN1, AN2, AN1, AN2, NO_OUT);
137   comparator.cmcon.set_configuration(1, 4, AN0, AN3, AN0, AN3, NO_OUT);
138   comparator.cmcon.set_configuration(2, 4, AN1, AN2, AN1, AN2, NO_OUT);
139   comparator.cmcon.set_configuration(1, 5, NO_IN, NO_IN, NO_IN, NO_IN, ZERO);
140   comparator.cmcon.set_configuration(2, 5, AN1, AN2, AN1, AN2, NO_OUT);
141   comparator.cmcon.set_configuration(1, 6, AN0, AN2, AN0, AN2, OUT0);
142   comparator.cmcon.set_configuration(2, 6, AN1, AN2, AN1, AN2, OUT1);
143   comparator.cmcon.set_configuration(1, 7, NO_IN, NO_IN, NO_IN, NO_IN, ZERO);
144   comparator.cmcon.set_configuration(2, 7, NO_IN, NO_IN, NO_IN, NO_IN, ZERO);
145   add_sfr_register(&comparator.cmcon, 0x1f, RegisterValue(0, 0), "cmcon");
146   add_sfr_register(&comparator.vrcon, 0x9f, RegisterValue(0, 0), "vrcon");
147   comparator.cmcon.put(0);
148   // Link ccp1 onto portb
149   ccp1con.setIOpin(&((*m_portb)[3]));
150 }
151 
152 
create_symbols()153 void P16F62x::create_symbols()
154 {
155   if (verbose) {
156     std::cout << "62x create symbols\n";
157   }
158 
159   Pic14Bit::create_symbols();
160 }
161 
162 
set_out_of_range_pm(unsigned int address,unsigned int value)163 void P16F62x::set_out_of_range_pm(unsigned int address, unsigned int value)
164 {
165   if ((address >= 0x2100) && (address < 0x2100 + get_eeprom()->get_rom_size())) {
166     get_eeprom()->change_rom(address - 0x2100, value);
167   }
168 }
169 
170 
171 //========================================================================
set_config_word(unsigned int address,unsigned int cfg_word)172 bool P16F62x::set_config_word(unsigned int address, unsigned int cfg_word)
173 {
174   enum {
175     CFG_FOSC0 = 1 << 0,
176     CFG_FOSC1 = 1 << 1,
177     CFG_FOSC2 = 1 << 4,
178     CFG_MCLRE = 1 << 5
179   };
180 
181   // Let the base class do most of the work:
182 
183   if (pic_processor::set_config_word(address, cfg_word)) {
184     if (verbose) {
185       std::cout << "p16f628 setting config word 0x" << std::hex << cfg_word << '\n';
186     }
187 
188     unsigned int valid_pins = m_porta->getEnableMask();
189     set_int_osc(false);
190 
191     // Careful these bits not adjacent
192     switch (cfg_word & (CFG_FOSC0 | CFG_FOSC1 | CFG_FOSC2)) {
193     case 0:  // LP oscillator: low power crystal is on RA6 and RA7
194     case 1:     // XT oscillator: crystal/resonator is on RA6 and RA7
195     case 2:     // HS oscillator: crystal/resonator is on RA6 and RA7
196       (m_porta->getPin(6))->newGUIname("OSC2");
197       (m_porta->getPin(7))->newGUIname("OSC1");
198       break;
199 
200     case 0x13:  // ER oscillator: RA6 is CLKOUT, resistor (?) on RA7
201       (m_porta->getPin(6))->newGUIname("CLKOUT");
202       (m_porta->getPin(7))->newGUIname("OSC1");
203       break;
204 
205     case 3:     // EC:  RA6 is an I/O, RA7 is a CLKIN
206     case 0x12:  // ER oscillator: RA6 is an I/O, RA7 is a CLKIN
207       (m_porta->getPin(7))->newGUIname("CLKIN");
208       valid_pins = (valid_pins & 0x7f) | 0x40;
209       break;
210 
211     case 0x10:  // INTRC: Internal Oscillator, RA6 and RA7 are I/O's
212       set_int_osc(true);
213       (m_porta->getPin(6))->newGUIname("porta6");
214       (m_porta->getPin(7))->newGUIname("porta7");
215       valid_pins |= 0xc0;
216       break;
217 
218     case 0x11:  // INTRC: Internal Oscillator, RA7 is an I/O, RA6 is CLKOUT
219       set_int_osc(true);
220       (m_porta->getPin(6))->newGUIname("CLKOUT");
221       (m_porta->getPin(7))->newGUIname("porta7");
222       valid_pins = (valid_pins & 0xbf) | 0x80;
223       break;
224     }
225 
226     // If the /MCLRE bit is set then RA5 is the MCLR pin, otherwise it's
227     // a general purpose I/O pin.
228 
229     if (!(cfg_word & CFG_MCLRE)) {
230       unassignMCLRPin();
231       valid_pins |= (1 << 5);           // porta5 IO port
232 
233     } else {
234       assignMCLRPin(4); 	// pin 4
235     }
236 
237     //cout << " porta valid_iopins " << porta->valid_iopins <<
238     //   "  tris valid io " << trisa.valid_iopins << '\n';
239 
240     if (valid_pins != m_porta->getEnableMask()) { // enable new pins for IO
241       m_porta->setEnableMask(valid_pins);
242       m_porta->setTris(m_trisa);
243     }
244 
245     return true;
246   }
247 
248   return false;
249 }
250 
251 
252 //========================================================================
create(int,unsigned int eeprom_size)253 void P16F62x::create(int /* ram_top */, unsigned int eeprom_size)
254 {
255   create_iopin_map();
256   _14bit_processor::create();
257   EEPROM_PIR *e = new EEPROM_PIR(this, pir1);
258   e->initialize(eeprom_size);
259   //e->set_pir_set(get_pir_set());
260   e->set_intcon(&intcon_reg);
261   // assign this eeprom to the processor
262   set_eeprom_pir(e);
263   P16X6X_processor::create_sfr_map();
264   status->rp_mask = 0x60;  // rp0 and rp1 are valid.
265   indf->base_address_mask1 = 0x80; // used for indirect accesses above 0x100
266   indf->base_address_mask2 = 0x1ff; // used for indirect accesses above 0x100
267   P16F62x::create_sfr_map();
268   // Build the links between the I/O Pins and the internal peripherals
269   //1ccp1con.iopin = portb->pins[3];
270 }
271 
272 
273 //========================================================================
274 //
275 // Pic 16F627
276 //
277 
construct(const char * name)278 Processor * P16F627::construct(const char *name)
279 {
280   P16F627 *p = new P16F627(name);
281   p->P16F62x::create(0x2f, 128);
282   p->create_invalid_registers();
283   p->create_symbols();
284   return p;
285 }
286 
287 
P16F627(const char * _name,const char * desc)288 P16F627::P16F627(const char *_name, const char *desc)
289   : P16F62x(_name, desc)
290 {
291   if (verbose) {
292     std::cout << "f627 constructor, type = " << isa() << '\n';
293   }
294 }
295 
296 
297 //========================================================================
298 //
299 // Pic 16F628
300 //
301 
construct(const char * name)302 Processor * P16F628::construct(const char *name)
303 {
304   P16F628 *p = new P16F628(name);
305   p->P16F62x::create(0x2f, 128);
306   p->create_invalid_registers();
307   p->create_symbols();
308   return p;
309 }
310 
311 
P16F628(const char * _name,const char * desc)312 P16F628::P16F628(const char *_name, const char *desc)
313   : P16F627(_name, desc)
314 {
315   if (verbose) {
316     std::cout << "f628 constructor, type = " << isa() << '\n';
317   }
318 }
319 
320 
~P16F628()321 P16F628::~P16F628()
322 {
323   if (verbose) {
324     std::cout << "'628 destructor\n";
325   }
326 }
327 
328 
329 //========================================================================
330 //
331 // Pic 16F648
332 //
333 
construct(const char * name)334 Processor * P16F648::construct(const char *name)
335 {
336   P16F648 *p = new P16F648(name);
337   p->P16F62x::create(0x2f, 256);
338   p->create_sfr_map();
339   p->create_invalid_registers();
340   p->create_symbols();
341   return p;
342 }
343 
344 
P16F648(const char * _name,const char * desc)345 P16F648::P16F648(const char *_name, const char *desc)
346   : P16F628(_name, desc)
347 {
348   if (verbose) {
349     std::cout << "f648 constructor, type = " << isa() << '\n';
350   }
351 }
352 
353 
~P16F648()354 P16F648::~P16F648()
355 {
356   delete_file_registers(0x150, 0x16f);
357 }
358 
359 
create_sfr_map()360 void P16F648::create_sfr_map()
361 {
362   add_file_registers(0x150, 0x16f, 0);
363 }
364