~ubuntu-branches/ubuntu/raring/picprog/raring

« back to all changes in this revision

Viewing changes to .pc/20_iopl.patch/picport.cc

  • Committer: Package Import Robot
  • Author(s): Koichi Akabe
  • Date: 2011-12-03 10:08:38 UTC
  • mfrom: (4.1.3 sid)
  • Revision ID: package-import@ubuntu.com-20111203100838-f05iyixkqjdh2byd
Tags: 1.9.1-2
* debian/control
  - changed priority from extra to optional
  - narrowed environments: linux-any kfreebsd-any

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* -*- c++ -*-
 
2
 
 
3
This is Picprog, Microchip PIC programmer software for the serial port device.
 
4
Copyright © 1997,2002,2003,2004,2006,2007,2008,2010 Jaakko Hyvätti
 
5
 
 
6
This program is free software: you can redistribute it and/or modify
 
7
it under the terms of the GNU General Public License as published by
 
8
the Free Software Foundation, either version 3 of the License, or
 
9
(at your option) any later version.
 
10
 
 
11
This program 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
 
14
GNU General Public License for more details.
 
15
 
 
16
You should have received a copy of the GNU General Public License
 
17
along with this program.  If not, see http://www.gnu.org/licenses/ .
 
18
 
 
19
The author may be contacted at:
 
20
 
 
21
Email: Jaakko.Hyvatti@iki.fi
 
22
URL:   http://www.iki.fi/hyvatti/
 
23
Phone: +358 40 5011222
 
24
 
 
25
Please send any suggestions, bug reports, success stories etc. to the
 
26
Email address above.  Include word 'picprog' in the subject line to
 
27
make sure your email passes my spam filtering.
 
28
 
 
29
*/
 
30
 
 
31
#include <iostream>
 
32
#include <fstream>
 
33
#include <iomanip>
 
34
#include <string>
 
35
#include <cstring>
 
36
#include <cstdlib>
 
37
#include <cerrno>
 
38
#include <ctime>
 
39
 
 
40
#include <sys/ioctl.h>
 
41
#include <sys/io.h>
 
42
#include <fcntl.h>
 
43
#include <sys/time.h>
 
44
#include <unistd.h>
 
45
#include <termios.h>
 
46
#include <sysexits.h>
 
47
#include <sched.h>
 
48
 
 
49
#include "picport.h"
 
50
 
 
51
using namespace std;
 
52
 
 
53
#ifndef O_NONBLOCK
 
54
#define O_NONBLOCK O_NDELAY
 
55
#endif
 
56
 
 
57
unsigned int picport::tsc_1000ns = 0;
 
58
 
 
59
// Data bitrate delay, ns.
 
60
// Cable delay is tested and this value adjusted when port is opened.
 
61
int picport::cable_delay = 0;
 
62
 
 
63
// Set this to -1 if you want to use nanosleep when running as root.
 
64
// This only works with 2.4 kernels, 2.6 series kernels no more work.
 
65
int picport::use_nanosleep = 0;
 
66
 
 
67
// 
 
68
static bool disable_interrupts = 1;
 
69
 
 
70
void
 
71
picport::set_clock_data (int rts, int dtr)
 
72
{
 
73
  if (hardware == k8048) {
 
74
    rts = !rts;
 
75
    dtr = !dtr;
 
76
  }
 
77
  // Before first call to set_clock_data, read the modem status like this:
 
78
  // ioctl (fd, TIOCMGET, &modembits);
 
79
  if (rts)
 
80
    modembits |= TIOCM_RTS;
 
81
  else
 
82
    modembits &= ~TIOCM_RTS;
 
83
  if (dtr)
 
84
    modembits |= TIOCM_DTR;
 
85
  else
 
86
    modembits &= ~TIOCM_DTR;
 
87
  if (0 > ioctl (fd, TIOCMSET, &modembits)) {
 
88
    int e = errno;
 
89
    tcsetattr (fd, TCSANOW, &saved);
 
90
    cerr << "Unable to set RTS/DTR on tty " << portname << ":" << strerror (e) << endl;
 
91
    exit (EX_IOERR);
 
92
  }
 
93
}
 
94
 
 
95
void
 
96
picport::set_vpp (int vpp)
 
97
{
 
98
  if (hardware == k8048)
 
99
    vpp = !vpp;
 
100
  if (0 > ioctl (fd, vpp ? TIOCSBRK : TIOCCBRK, 0)) {
 
101
    int e = errno;
 
102
    if (vpp)
 
103
      ioctl (fd, TIOCCBRK, 0);
 
104
    tcsetattr (fd, TCSANOW, &saved);
 
105
    cerr << "Unable to " << (vpp ? "start" : "stop") << " break on tty "
 
106
        << portname << ":" << strerror (e) << endl;
 
107
    exit (EX_IOERR);
 
108
  }
 
109
}
 
110
 
 
111
picport::picport (const char *tty, bool nordtsc, bool slow, bool reboot,
 
112
                  hardware_types h)
 
113
  : addr (0), debug_on (0), hardware (h)
 
114
{
 
115
  for (int i = 0; i < 16; ++i)
 
116
    W [i] = 0;
 
117
  portname = new char [strlen (tty) + 1];
 
118
  strcpy (portname, tty);
 
119
 
 
120
  if (0 > (fd = open (tty, O_RDWR|O_NOCTTY|O_NONBLOCK))) {
 
121
    int e = errno;
 
122
    cerr << "Unable to open tty " << tty << ":" << strerror (e) << endl;
 
123
    exit (EX_IOERR);
 
124
  }
 
125
  tcgetattr (fd, &saved);
 
126
  termstate = saved;
 
127
  termstate.c_iflag = IGNBRK | IGNPAR;
 
128
  termstate.c_oflag = 0;
 
129
  termstate.c_cflag = B9600 | CS8 | CREAD | CLOCAL;
 
130
  termstate.c_lflag = 0;
 
131
  tcsetattr (fd, TCSANOW, &termstate);
 
132
 
 
133
  // Initialize lines for programming
 
134
 
 
135
  // RTS/DTR low, sleep and then TxD high (program voltage)
 
136
 
 
137
  ioctl (fd, TIOCCBRK, 0);
 
138
  // Before first call to set_clock_data, read the modem status.
 
139
  ioctl (fd, TIOCMGET, &modembits);
 
140
  modembits &= ~(TIOCM_RTS | TIOCM_DTR);
 
141
  ioctl (fd, TIOCMSET, &modembits);
 
142
  usleep (1000);
 
143
  // Check the CTS.  If it is up, even when we just lowered DTR,
 
144
  // we probably are not talking to a JDM type programmer.
 
145
  int i = 0;
 
146
  ioctl (fd, TIOCMGET, &i);
 
147
  if (i & TIOCM_CTS) {
 
148
    tcsetattr (fd, TCSANOW, &saved);
 
149
    cerr << tty << ":CTS is high, probably we are not connected to a programmer but a modem or terminal." << endl;
 
150
    exit (EX_IOERR);
 
151
  }
 
152
 
 
153
  struct sched_param scp;
 
154
  scp.sched_priority = sched_get_priority_min (SCHED_FIFO);
 
155
  // sched_get_priority_max()
 
156
  // scp.sched_priority = 50;
 
157
  cerr << "Trying realtime priority " << scp.sched_priority << endl;
 
158
  if (sched_setscheduler (0, SCHED_FIFO, &scp)) {
 
159
    cerr << "Cannot use real time scheduling: " << strerror(errno) << endl;
 
160
    // Not root.  Cannot use realtime scheduling.
 
161
    use_nanosleep = 0;
 
162
  }
 
163
  if (iopl (3))
 
164
    disable_interrupts = 0;
 
165
 
 
166
#ifdef CPU_SETSIZE
 
167
  // When computing the delay loops, we do not want the cpu's to change.
 
168
  // Pick the first cpu in the current allowed set.
 
169
  cpu_set_t new_mask;
 
170
  cpu_set_t cur_mask;
 
171
  CPU_ZERO(&cur_mask);
 
172
  CPU_ZERO(&new_mask);
 
173
  if (sched_getaffinity(0, sizeof (cur_mask), &cur_mask) < 0) {
 
174
    tcsetattr (fd, TCSANOW, &saved);
 
175
    cerr << "Getting affinity functions do not work." << endl;
 
176
    exit (EX_IOERR);
 
177
  }
 
178
  for (int cpuno = 0; cpuno < CPU_SETSIZE; ++cpuno)
 
179
    if (CPU_ISSET (cpuno, &cur_mask)) {
 
180
      CPU_SET (cpuno, &new_mask);
 
181
      sched_getaffinity (0, sizeof (new_mask), &new_mask);
 
182
      // We want to print informative line only if we really
 
183
      // have multiple cpu's.
 
184
      for (int cpuno1 = cpuno+1; cpuno1 < CPU_SETSIZE; ++cpuno1)
 
185
        if (CPU_ISSET (cpuno1, &cur_mask)) {
 
186
          cerr << "Bound to CPU " << cpuno << endl;
 
187
          break;
 
188
        }
 
189
    }
 
190
#endif // CPU_SETSIZE
 
191
 
 
192
#ifdef RDTSC_WORKS
 
193
  if (!nordtsc && !use_nanosleep && !tsc_1000ns) {
 
194
    // Read /proc/cpuinfo for clock speed, or if that fails, try our
 
195
    // own test.
 
196
    ifstream cpui ("/proc/cpuinfo");
 
197
    string w;
 
198
    unsigned int mhz = 1; // 1MHz is just a flag that tsc was found
 
199
    while (cpui) {
 
200
      cpui >> w;
 
201
      if ("MHz" == w) {
 
202
        unsigned int tmp;
 
203
        // Read just the integer part.  No need for the rest.
 
204
        cpui >> w >> tmp;
 
205
        // Update this when we have 100 GHz CPUs.
 
206
        if (tmp >= 4 && tmp <= 100000)
 
207
          mhz = tmp;
 
208
      }
 
209
      if ("tsc" == w && mhz) {
 
210
        // tsc capability found.  Use it.
 
211
        tsc_1000ns = mhz;
 
212
        break;
 
213
      }
 
214
    }
 
215
 
 
216
    // If the /proc fs did not contain clock speed but indicated
 
217
    // tsc capability, test the approximate clock speed.
 
218
    if (1 == tsc_1000ns) {
 
219
      // Loop the test 20 times, and select the smallest count.
 
220
      for (int recount = 0; recount < 20; ++recount) {
 
221
        struct timeval tv1, tv2;
 
222
        unsigned long a1, d1, a2, d2;
 
223
 
 
224
        // Wait for when a microsecond changes
 
225
        gettimeofday (&tv2, 0);
 
226
        do {
 
227
          gettimeofday (&tv1, 0);
 
228
        } while (tv2.tv_usec == tv1.tv_usec);
 
229
        asm volatile("rdtsc":"=a" (a1), "=d" (d1));
 
230
        tv1.tv_usec += 1000;
 
231
        if (tv1.tv_usec >= 1000000) {
 
232
          tv1.tv_usec -= 1000000;
 
233
          tv1.tv_sec ++;
 
234
        }
 
235
        do {
 
236
          gettimeofday (&tv2, 0);
 
237
        } while (tv2.tv_sec < tv1.tv_sec
 
238
                 || (tv2.tv_sec == tv1.tv_sec && tv2.tv_usec < tv1.tv_usec));
 
239
        asm volatile("rdtsc":"=a" (a2), "=d" (d2));
 
240
        if (a2 < a1)
 
241
          d2 --;
 
242
        a2 -= a1;
 
243
        a2 &= 0xffffffff; // for x86_64
 
244
        d2 -= d1;
 
245
        if (d2)
 
246
          continue;
 
247
        a2 /= 1000;
 
248
        if (tsc_1000ns <= 1 || tsc_1000ns > a2)
 
249
          tsc_1000ns = a2;
 
250
      }
 
251
      if (tsc_1000ns <= 1) {
 
252
        tcsetattr (fd, TCSANOW, &saved);
 
253
        cerr << "Unable to determine CPU clock speed for delay loops." << endl;
 
254
        exit (EX_IOERR);
 
255
      }
 
256
    }
 
257
    if (tsc_1000ns >= 1) {
 
258
      cout << "CPU clock speed: " << tsc_1000ns << " MHz" << endl;
 
259
    }
 
260
  }
 
261
#endif
 
262
 
 
263
  if (tsc_1000ns > 1 && disable_interrupts)
 
264
    cerr << "Disable interrupts during delays." << endl;
 
265
 
 
266
  if (reboot) {
 
267
    // Power off any microcontroller that may be running a program.
 
268
    cerr << "Power off." << endl;
 
269
    set_clock_data (1, 1);
 
270
    set_vpp (1);
 
271
    usleep (500000); // 0.5s delay should discharge Vdd.
 
272
  }
 
273
 
 
274
  // /MCLR must go down for a while first
 
275
  set_vpp (0);
 
276
  usleep (10);
 
277
  // Power up
 
278
  set_clock_data (0, 0);
 
279
  set_vpp (1);
 
280
  // Charge Vdd
 
281
  usleep (25000);
 
282
 
 
283
  // Detect delays that are needed for cable lenght
 
284
  bool successful_echo = false;
 
285
  for (int i = 1; i <= 100; ++i) {
 
286
    int data_out = i & 1;
 
287
    // toggle data, keep clock off / power on
 
288
    if (data_out)
 
289
      modembits |= TIOCM_DTR;
 
290
    else
 
291
      modembits &= ~TIOCM_DTR;
 
292
    ioctl (fd, TIOCMSET, &modembits);
 
293
    delay (cable_delay);
 
294
    int data_in;
 
295
    ioctl (fd, TIOCMGET, &data_in);
 
296
    data_in = 0 != (data_in & TIOCM_CTS);
 
297
    delay (1000000);
 
298
    successful_echo = data_out == data_in;
 
299
    if (!successful_echo)
 
300
      cable_delay += 100; // Another 100 ns added for cable length
 
301
    ioctl (fd, TIOCMGET, &data_in);
 
302
    data_in = 0 != (data_in & TIOCM_CTS);
 
303
    if (data_out != data_in) {
 
304
      ioctl (fd, TIOCCBRK, 0);
 
305
      tcsetattr (fd, TCSANOW, &saved);
 
306
      cerr << "No JDM compatible hardware detected." << endl;
 
307
      exit (EX_IOERR);
 
308
    }
 
309
  }
 
310
  set_clock_data (0, 0);
 
311
 
 
312
  if (!successful_echo) {
 
313
    ioctl (fd, TIOCCBRK, 0);
 
314
    tcsetattr (fd, TCSANOW, &saved);
 
315
    cerr << "Cable too long." << endl;
 
316
    exit (EX_IOERR);
 
317
  }
 
318
 
 
319
  cable_delay += 100; // Another 100 ns added just for safety
 
320
  if (slow && cable_delay < 10000)
 
321
    cable_delay = 10000;
 
322
  if (1 == use_nanosleep)
 
323
    cerr << "Using " << cable_delay << " ns delays with real time priority." << endl;
 
324
  else if (tsc_1000ns > 1)
 
325
    cerr << "Using " << cable_delay << " ns delays." << endl;
 
326
  else if (cable_delay > 1000)
 
327
    cerr << "Using " << ((cable_delay + 999) / 1000) << " µs delays." << endl;
 
328
  else
 
329
    cerr << "Using >1 µs delays. --rdtsc may work for faster timings." << endl;
 
330
}
 
331
 
 
332
picport::~picport ()
 
333
{
 
334
  set_vpp (0);
 
335
  usleep (1);
 
336
  tcsetattr (fd, TCSANOW, &saved);
 
337
  close (fd);
 
338
  delete [] portname;
 
339
}
 
340
 
 
341
void picport::reset (unsigned long reset_address)
 
342
{
 
343
  set_clock_data (0, 0);
 
344
  usleep (100); // Make sure we have the power there.
 
345
  set_vpp (0);
 
346
  usleep (50);
 
347
  set_vpp (1);
 
348
  usleep (10);
 
349
  addr = reset_address;
 
350
}
 
351
 
 
352
void picport::delay (long ns)
 
353
{
 
354
  if (1 == use_nanosleep) {
 
355
    timespec ts = {ns / 1000000000, ns % 1000000000}, ts2;
 
356
    while (nanosleep (&ts, &ts2) && EINTR == errno)
 
357
      ts = ts2;
 
358
    return;
 
359
  }
 
360
 
 
361
#ifdef RDTSC_WORKS
 
362
  if (tsc_1000ns > 1) {
 
363
    unsigned long a1, d1, a2, d2;
 
364
    if (ns <= 10000 && disable_interrupts)
 
365
      asm volatile("pushf; cli");
 
366
    asm volatile("rdtsc":"=a" (a1), "=d" (d1));
 
367
    d2 = d1;
 
368
    if (ns > 10000)
 
369
      // This is not as accurate but does not overflow
 
370
      a2 = 0xffffffff & (a1 + 1 + (ns+999)/1000*tsc_1000ns);
 
371
    else
 
372
      a2 = 0xffffffff & (a1 + 1 + (ns*tsc_1000ns + 999) / 1000);
 
373
    if (a2 < a1)
 
374
      d2++;
 
375
    do {
 
376
      asm volatile("rdtsc":"=a" (a1), "=d" (d1));
 
377
    } while (d1 < d2 || (d1 == d2 && a1 < a2));
 
378
    if (ns <= 10000 && disable_interrupts)
 
379
      asm volatile("popf");
 
380
    return;
 
381
  }
 
382
  // Fall back to gettimeofday() if tsc is not available.
 
383
#endif // RDTSC_WORKS
 
384
 
 
385
  // Delay loop that should take more than a microsecond to execute.
 
386
  // Check the real time clock and break out if at least the specified
 
387
  // number of microseconds has gone.
 
388
 
 
389
  struct timeval tv1, tv2;
 
390
  gettimeofday (&tv2, 0);
 
391
  tv2.tv_usec += 1 + (ns + 999)/1000;
 
392
  if (tv2.tv_usec >= 1000000) {
 
393
    tv2.tv_usec -= 1000000;
 
394
    tv2.tv_sec++;
 
395
  }
 
396
  do {
 
397
    gettimeofday (&tv1, 0);
 
398
  } while (tv1.tv_sec < tv2.tv_sec
 
399
           || (tv1.tv_sec == tv2.tv_sec && tv1.tv_usec < tv2.tv_usec));
 
400
}
 
401
 
 
402
void picport::p_out (int b)
 
403
{
 
404
  struct timeval tv1, tv2;
 
405
  gettimeofday (&tv1, 0);
 
406
  if (tsc_1000ns > 1 && disable_interrupts)
 
407
    asm volatile("pushf; cli");
 
408
  set_clock_data (1, b); // set data, clock up
 
409
  delay (cable_delay);
 
410
  set_clock_data (0, b); // clock down
 
411
  if (tsc_1000ns > 1 && disable_interrupts)
 
412
    asm volatile("popf");
 
413
  gettimeofday (&tv2, 0);
 
414
 
 
415
  // We may have spent a long time in an interrupt or in another task
 
416
  // with clock down, so the pic may be pretty drained for power now.
 
417
  // Recharge at least as long as we were without power.
 
418
  long matching_delay = (tv2.tv_sec-tv1.tv_sec) * 1000000 + tv2.tv_usec - tv1.tv_usec;
 
419
  if (matching_delay > 10) // 10 µs should be enough to charge up
 
420
    matching_delay = 10;
 
421
  matching_delay *= 1000;
 
422
  if (matching_delay < cable_delay)
 
423
    matching_delay = cable_delay;
 
424
  delay (matching_delay);
 
425
}
 
426
 
 
427
int picport::p_in ()
 
428
{
 
429
  struct timeval tv1, tv2;
 
430
  gettimeofday (&tv1, 0);
 
431
  if (tsc_1000ns > 1 && disable_interrupts)
 
432
    asm volatile("pushf; cli");
 
433
  set_clock_data (1, 1); // clock up
 
434
  delay (cable_delay);
 
435
  set_clock_data (0, 1); // set data up, clock down
 
436
  if (tsc_1000ns > 1 && disable_interrupts)
 
437
    asm volatile("popf");
 
438
  gettimeofday (&tv2, 0);
 
439
 
 
440
  // We may have spent a long time in an interrupt or in another task
 
441
  // with clock down, so the pic may be pretty drained for power now.
 
442
  // Recharge at least as long as we were without power.
 
443
  long matching_delay = (tv2.tv_sec-tv1.tv_sec) * 1000000 + tv2.tv_usec - tv1.tv_usec;
 
444
  if (matching_delay > 10) // 10 µs should be enough to charge up
 
445
    matching_delay = 10;
 
446
  matching_delay *= 1000;
 
447
  if (matching_delay < cable_delay)
 
448
    matching_delay = cable_delay;
 
449
  delay (matching_delay);
 
450
 
 
451
  int i;
 
452
 
 
453
  ioctl (fd, TIOCMGET, &i);
 
454
  i = 0 != (i & TIOCM_CTS);
 
455
  if (hardware == k8048)
 
456
    return !i;
 
457
  return i;
 
458
}
 
459
 
 
460
int picport::command18 (enum commands18 comm, int data)
 
461
{
 
462
  int i, shift = comm;
 
463
  if (nop_prog == comm) {
 
464
    // A programming command must leave the last bit clock pulse up
 
465
    p_out (0);
 
466
    p_out (0);
 
467
    p_out (0);
 
468
    set_clock_data (1, 0); // clock up
 
469
    delay (1000*1000); // P9 >1 ms programming time
 
470
    set_clock_data (0, 0); // clock down
 
471
    // P10 >5 µs high voltage discharge time
 
472
    // Later models listed as > 100 µs
 
473
    delay (100*1000);
 
474
  } else {
 
475
    for (i = 0; i < 4; i++)
 
476
      p_out ((shift >> i) & 1);
 
477
    set_clock_data (0, 0); // set data down
 
478
    delay (1000);
 
479
  }
 
480
 
 
481
  shift = 0; // default return value
 
482
 
 
483
  switch (comm) {
 
484
  case nop_erase:
 
485
    // Erase cycle has delay between command and data
 
486
    usleep (10000); // P11 5 ms + P10 5 µs erase time
 
487
    // FALLTHROUGH
 
488
 
 
489
  case instr:
 
490
  case nop_prog:
 
491
    if (0x0e00 == (data & 0xff00))
 
492
      W[0] = data & 0x00ff;
 
493
    else if (0x6ef8 == data)
 
494
      addr = (addr & 0x00ffff) | (W[0] << 16);
 
495
    else if (0x6ef7 == data)
 
496
      addr = (addr & 0xff00ff) | (W[0] << 8);
 
497
    else if (0x6ef6 == data)
 
498
      addr = (addr & 0xffff00) | W[0];
 
499
    goto sw;
 
500
 
 
501
  case twrite_dec2:
 
502
    addr -= 2;
 
503
    goto sw;
 
504
 
 
505
  case twrite_inc2:
 
506
    addr += 2;
 
507
    // FALLTHROUGH
 
508
 
 
509
  case twrite:
 
510
  case twrite_prog:
 
511
  sw:
 
512
    for (i = 0; i < 16; i++)
 
513
      p_out ((data >> i) & 1);
 
514
    set_clock_data (0, 0); // set data down
 
515
    break;
 
516
 
 
517
  case tread_dec:
 
518
    --addr;
 
519
    goto sr;
 
520
 
 
521
  case tread_inc:
 
522
  case inc_tread:
 
523
    ++addr;
 
524
    // FALLTHROUGH
 
525
 
 
526
  case shift_out:
 
527
  case tread:
 
528
  sr:
 
529
    for (i = 0; i < 8; i++)
 
530
      p_out(0);
 
531
    delay (1000);
 
532
    for (i = 0; i < 8; i++)
 
533
      shift |= p_in () << i;
 
534
    set_clock_data (0, 0); // set data down
 
535
  }
 
536
 
 
537
  delay (1000);
 
538
  return shift;
 
539
}
 
540
 
 
541
int picport::command30 (enum commands30 comm, int data)
 
542
{
 
543
  int i, shift = comm;
 
544
  for (i = 0; i < 4; i++)
 
545
    p_out ((shift >> i) & 1);
 
546
 
 
547
  shift = 0; // default return value
 
548
 
 
549
  switch (comm) {
 
550
  case SIX:
 
551
 
 
552
    if (0x200000 == (data & 0xff0000))
 
553
      W[data & 15] = (data & 0x0ffff0) >> 4;
 
554
    else if (0xEB0000 == (data & 0xfff87f))
 
555
      W[(data >> 7) & 15] = 0;
 
556
    else if (0xBA1830 == (data & 0xfff870)) {
 
557
      // TBLRDL
 
558
      ++W[(data >> 7) & 15];
 
559
      ++W[data & 15];
 
560
    } else if (0xBA0830 == (data & 0xfff870)) {
 
561
      // TBLRDL
 
562
      ++W[(data >> 7) & 15];
 
563
      ++W[data & 15];
 
564
    } else if (0x880190 == (data & 0xfffff0))
 
565
      addr = (W[data & 15] << 16) & 0xff0000;
 
566
    addr = (addr & 0xff0000) | W[6];
 
567
 
 
568
    for (i = 0; i < 24; i++)
 
569
      p_out ((data >> i) & 1);
 
570
    break;
 
571
 
 
572
  case REGOUT:
 
573
    for (i = 0; i < 8; i++)
 
574
      p_out(0);
 
575
    for (i = 0; i < 16; i++)
 
576
      shift |= p_in () << i;
 
577
  }
 
578
  set_clock_data (0, 0); // set data down
 
579
 
 
580
  return shift;
 
581
}
 
582
 
 
583
void picport::setaddress (unsigned long a)
 
584
{
 
585
  if (0 != a && addr == a)
 
586
    return;
 
587
 
 
588
  command18 (instr, 0x0e00 | ((a & 0xff0000) >> 16));
 
589
  command18 (instr, 0x6ef8);
 
590
  command18 (instr, 0x0e00 | ((a & 0x00ff00) >> 8));
 
591
  command18 (instr, 0x6ef7);
 
592
  command18 (instr, 0x0e00 | (a & 0x0000ff));
 
593
  command18 (instr, 0x6ef6);
 
594
}
 
595
 
 
596
void picport::setaddress30 (unsigned long a)
 
597
{
 
598
  if (0 != a && addr == a)
 
599
    return;
 
600
 
 
601
  command30 (SIX, 0x200000 | ((a & 0xff0000) >> 12)); // MOV #, W0
 
602
  command30 (SIX, 0x880190); // MOV W0, TBLPAG
 
603
  command30 (SIX, 0x200006 | ((a & 0x00ffff) << 4)); // MOV #, W6
 
604
}
 
605
 
 
606
// -1 == error, no programmer present
 
607
 
 
608
int picport::command (enum commands comm, int data)
 
609
{
 
610
  int tmp1, tmp2;
 
611
 
 
612
  // first, send out the command, 6 bits
 
613
 
 
614
  int i, shift = comm;
 
615
  for (i = 0; i < 6; i++)
 
616
    p_out ((shift >> i) & 1);
 
617
  set_clock_data (0, 0); // set data down
 
618
 
 
619
  shift = 0; // default return value
 
620
 
 
621
  switch (comm) {
 
622
  case inc_addr:
 
623
    ++addr;
 
624
    if (data != 0) { // 12f508 and 12f509
 
625
      if (addr >= (unsigned long)(data))
 
626
        addr = 0;
 
627
      break;
 
628
    }
 
629
 
 
630
    if (addr >= 0x4000)
 
631
      addr = 0x2000;
 
632
    break;
 
633
 
 
634
  case data_from_prog:
 
635
  case data_from_data:
 
636
    delay (1000);
 
637
    tmp1 = p_in ();
 
638
    for (i = 0; i < 14; i++)
 
639
      shift |= p_in () << i;
 
640
    tmp2 = p_in ();
 
641
    set_clock_data (0, 0); // set data down
 
642
 
 
643
#ifdef CHECK_START_STOP
 
644
    // Start and stop bits must be 1.  Most of the old chips at least
 
645
    // conform to this test, but apparently pic12f635 and some other
 
646
    // later chips do not.
 
647
 
 
648
    if (!tmp1 || !tmp2) {
 
649
      cerr << portname << ":PIC programmer missing or chip fault" << endl;
 
650
      return -1;
 
651
    }
 
652
#endif
 
653
 
 
654
    if (data_from_data == comm) {
 
655
 
 
656
      // Check that the leftover bits were valid, all 1's.
 
657
      // This detects if the programmer is not connected to the port.
 
658
      // Unfortunately later chips clear these bits, so we must
 
659
      // accept both all 1's and all 0's.
 
660
 
 
661
      if ((shift & 0x3f00) != 0x3f00
 
662
          && (shift & 0x3f00) != 0x0000) {
 
663
        cerr << portname << ": read value "
 
664
             << hex << setfill('0') << setw(4) << shift << dec
 
665
             << ": PIC programmer or chip fault\n"
 
666
          "Is code protection enabled?  "
 
667
          "Use --erase option to disable code protection." << endl;
 
668
        return -1;
 
669
      }
 
670
 
 
671
      shift &= 0xff;
 
672
    }
 
673
    break;
 
674
 
 
675
  case load_conf:
 
676
    addr = 0x2000;
 
677
    // FALLTHROUGH
 
678
 
 
679
  case data_for_prog:
 
680
  case data_for_data:
 
681
    delay (1000);
 
682
    p_out (0);
 
683
    for (i = 0; i < 14; i++)
 
684
      p_out ((data >> i) & 1);
 
685
    p_out (0);
 
686
    set_clock_data (0, 0); // set data down
 
687
    break;
 
688
 
 
689
  default:
 
690
    ;
 
691
  }
 
692
 
 
693
  delay (1000);
 
694
  return shift;
 
695
}
 
696