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