README100644 423 0 12546 6135543733 10376 0ustar luigiwheelNOTE ----- This is the "prog84" code modified to work with a serial port programmer, and accept Intel code. The serial port programmer is done as follows (wire colours are for the two samples I have): DB25 - DB9 - PIN (BLUE) +-----+ __ - 4 - DTR --+------+--[>|---| L05 |--+----+----> Vdd (14) (blue) | | +--+--+ | | | | | | | + _|_ | + | | ===== 100uF \ / ===== 22uF | | ===== --- ===== /// | | | | | /// | | +-------------+ | | | | | +------VVVVV---* RUN | | *--------> /MCLR (4) +------+------------------* PROG | __|_/ / / \ 14v / \ --+-- | (WHITE) - 5 GND --+----------------------------------> Vss (5) (shield) | /// 4.7K (GREEN) CLOCK - 7 RTS ------VVVVV----+---------------------> RB6 (12) | brown - 2 RxD ---------------+ 4.7K (ORANGE) DATA - 3 TxD ------VVVVV----+---------------------> RB7 (13) | black - 8 CTS ---------------+ First, drive DTR high to power the PIC. It must stay high long enough to charge the 100uF capacitor. To reset the PIC, pull DTR low. /MCLR goes to -0.7v (the zener behaves as a diode) and the 22uF capacitor charges to Vcc. Driving DTR active again, voltage on /MCLR goes to ~2Vcc thus bringing the PIC into programming mode (or run mode if the switch on the /MCLR line is set accordingly). Clock and data are generated by bit-bainging on RTS and TxD. Feedback for the data line is available through CTS. The connection with RxD is not useful during programming, but can serve if the PIC is talking RS232 on RB6. If programming lasts too long, the voltage on MCLR may drop below the threshold for programming. In this case the PIC must be reset again and programming restarted from the faulty location. --------------------------------------- The original message follows. WHAT IS THIS? wiml@netcom.com ------------- v0.9 26Dec1994 A PIC programmer. Specifically, I wrote this to program a PIC 16C84 through the parallel printer port of a Linux box using the PIC's serial programming mode and a homebuilt programmer loosely based on David Tait's. However, it uses a configuration file which should allow it to use almost any parallel-port based programmer; and the low-level I/O is in a separate file which could easily be replaced for operating systems other than Linux. This is *not* a "production" programmer; it doesn't do supply margining, or probably a bunch of other things. However, you have the source, so you can make it do whatever you want. This release is stable enough that I'm using it for my own tinkering with PICs and am doing development basically only when I discover it won't do something I want it to do. It should work out of the box on a Linux system, but it's not for the technically faint of heart (but then, if you're not comfortable mucking about with the system when it misbehaves, why are you running Linux?) If you make modifications or improvements, PLEASE send them to me so that I can maintain a coherent master copy and hopefully integrate everything into a portable, versatile, bulletproof driver. INSTALLATION ------------ Just type 'make'. The executables must be setgid kmem to run from a normal account; the Makfile will prompt you for the root password so it can do this. If you don't like that, enter a garbage password and setgid them yourself. On non-Linux machines, you will probably have to replace io_ports.c with whatever is appropriate to your system. This file contains routines to implement basic byte I/O by reading and writing /dev/port. On operating systems with no hardware protection (DOS, Windows, ...), you can just use inb() and outb(). Please send let me know about any changes you have to make to get this to work with your setup. You will need to create an lp_cfg file to tell these programs how to work with your hardware. See either the man page (prog84.man) or the old README file for details. MANIFEST -------- README This file. prog84.man A man page for prog84. old-README A README file from a previous revision of these programs. Contains some useful information. Makefile The makefile, of course. progmain.c Top-level routines for prog84. prog84.[hc] High-level routines for programming a 16C84. lp_io.c Buffered parallel-IO routines. io_ports.[hc] Low-level I/O routines. lp_cfg A sample configuration file. schematic.ps Schematic diagram for the simple programmer with which the sample configuration file works. jig.c A tool to allow you to interactively clock bits through the '84. lpttool.c A tool to allow you to write values to the parallel port and read the status register. dump.c Simple program to read out part of the '84's code and data. -------- Written by Wim Lewis: wiml@netcom.com or wiml@hhhh.org. old-README100644 423 0 17713 6032275054 11145 0ustar luigiwheelWHAT IS THIS? wiml@netcom.com ------------- v0.1 22Oct1994 A PIC programmer. Specifically, I wrote this to program a PIC 16C84 through the parallel printer port of a Linux box using the PIC's serial programming mode and a homebuilt programmer loosely based on David Tait's. However, it uses a configuration file which should allow it to use almost any parallel-port based programmer; and the low-level I/O is in a separate file which could easily be replaced for operating systems other than Linux. Right now it reads the "pictools format" files generated by Ian King's PIC assembler picasm. (Check ftp.funet.fi:pub/microprocs/pic for that and other PIC tools.) The pictools format has a couple of problems; I might change the programmer to read INHX files, or develop a third format. (I don't particularly want to add to the prolifration of file formats, but...) This is *not* a "production" programmer; it doesn't do supply margining, or probably a couple of other things. However, you have the source, so you can make it do whatever you want. This file is the only documentation aside from the source code; read it thoroughly --- there are many gotchas in the system. This release is stable enough that I'm using it for my own tinkering with PICs and am doing development basically only when I discover it won't do something I want it to do. It should work basically out of the box, but it's not for the technically faint of heart (but then, if you're not comfortable mucking about with the system when it misbehaves, why are you running Linux?) If you make modifications or improvements, PLEASE send them to me so that I can maintain a coherent master copy and hopefully integrate everything into a portable, versatile, bulletproof driver. INSTALLATION ------------ On a Linux box, this should compile out of the box; just type 'make'. The executables must be setgid kmem to run from a normal account; the makefile will prompt you for your root password so it can do this --- if you don't like that, change the $SETGID variable in the Makefile, or just enter a garbage password and setgid them yourself. On non-Linux machines, you will probably have to replace io_ports.c with whatever is appropriate to your system. This file contains routines to implement basic byte I/O by reading and writing /dev/port. On operating systems with no hardware protection (DOS, Windows, ...), you can just use inb() and outb(). Please send let me know about any changes you have to make to get this to work with your setup. Before running any of the programs (except lpttool) you will have to create the lp_cfg file. This file tells the program what pins on the I/O port control what functions of the programmer; it must be found in the cwd when the program starts. The file contains name-value pairs, one per line, with the value separated from the name by either a colon or an equals sign. Blank lines, and anything following a hash mark, are discarded. To name a pin, use the following symbols: d0 through d7 Data bits 0 through 7. c0 through c7 control-word bits 0 through 7. s0 through s7 status-word bits 0 through 7. ! or ~ indicates this bit is active low busy status 7, the "printer busy" bit ack status 6, the printer "ack" bit error status 3, ... you get the picture. The control-word and status-word names refer to the word read from the relevant I/O address. You'll have to look these up somewhere if you're using something other than busy, ack, and error. The programmer requires the following bits to be named: power --- set to 1 when the programmer wants the PIC's Vdd = +5v mclr --- set to 1 when the programmer wants the PIC's /MCLR = +13v clock --- used to clock data into the PIC (connect to PIC pin 12) data --- used to write data (pin 13) data_f -- sense return for data (pin 13) clock_f - sense return for clock (pin 12) rb6 --- synonym for "clock" rb7 --- synonym for "data" rb6_f --- synonym for "clock_f" rb7_f --- synonym for "data_f" Also, if your parallel port has a base I/O address other than the default 0x378, you can specify this as e.g. "base = 0x278". Here's an example configuration file showing some of the legal syntax. This is the configuration file I use; it works with the simple programmer whose schematic is in schematic.ps. power = !d1 mclr: !d0 rb7: ~d2 clock: ~d3 data_f = ~ack rb6_f = ~s4 base = 0x378 USAGE ----- Except for lpttool, all of these programs do a little bit of self-testing when they start up. If you get an error along the lines of "3 bad states" followed by an exit, this means that the self test failed. The test consists of putting the clock and data lines into their 4 possible states and checking that the clock_f and data_f lines change accordingly. The "bad states" indicates how many of these combinations were not read back correctly. lpttool: This allows you to read and write to & from the parallel port to test its basic operation or troubleshoot a recalcitrant circuit. It is invoked with an optional argument which is the base address of the parallel port to use (default 0x378). It accepts input in the following forms: - blank lines cause lpttool to read the status port (base+1) and display its value in decimal and hex, as well as symbolically - a line beginning with a question mark will read the data address and display the value in decimal and hex - anything else will be interpreted as a decimal number and written to the data port jig: This allows you to run a PIC serial programmer under manual control. It will display simple instructions on startup. dump: This will read the first 16 locations of data memory and the first 30 locations of program memory and dump them to stdout in pictools format (approximately). This is really only a skeleton of what a real dumping program would be. prog84: what you've been waiting for --- this will program a 16C84 from a pictools format file. It has the following command-line options: -v be verbose. If this occurs on the command line twice, it will be very verbose. Three times is ridiculous. -i nnn nnn nnn nnn Program the ID locations with the supplied values -p filename Program the chip from the given filename (pictools format) -h simple help -b, -a Verify the location being programmed before and/or after it is programmed. If you use -b, then prog84 will not waste time programming locations that already havethe correct value. If you do not use -a, prog84 will not verify locations after it programs them. It's probably always a good idea to use both -a and -b. NOTES ----- It's assumed that the drivers are open-collector with pullups, so the program writes a 1 when it wants the PIC to be able to drive the line. The program is a good deal slower than it needs to be. There are a lot of places where the Microchip databook requires a delay of at least one microsecond. In these places I've put a usleep(1) call, since a fast PC could possibly violate the timing restriction; but I suspect that Linux is waiting for a full jiffy (1/60 sec?). I need a call with better resolution. Maybe a busy wait? TODO ---- lpb_cfg_read() isn't very polished. The "base" spec shouldn't be special- cased; maybe there should be a "type" field in the name vector. The parseBit() routine should be spruced up so that it's smart enough to parse the symbolic names for all the status and control lines. The simpleminded parsing algorithm it uses now just doesn't cut it. Although the bits used are very configurable, the programmer can't deal with not having a clock_f line even though it doesn't ever use it. The self-test will fail without a clock_f line. If you don't have a clock_f line, you can just hack around the self-test in prog84.c. The configuration file lp_cfg is always read from the cwd. Is the name "prog84" taken? If so, I should think of a new one. Come to think of it, if anyone uses this to program a 6x or 7x, the name should be changed to reflect its slightly more general abilities... prog84.man100644 423 0 13132 6135547644 11333 0ustar luigiwheel.\" Man page for prog84, a 16C84 programmer driver .TH prog84 1 "26 December 1994" .SH NAME prog84 \- program a Microchip Technology PIC16C84 through the parallel or serial port .SH SYNOPSIS \fBprog84\fP [\fB-abhv\fP] [\fB-i\fP \fIn1 n2 n3 n4\fP] [\fB-v\fP \fIfile\fP] .SH DESCRIPTION The .B prog84 driver attempts to program a 16C84 EEPROM microcontroller in serial mode through a minimal driver circuit connected to a IBM-PC style parallel port, or to a serial port. It is designed to work easily with any such circuit by using the correct configuration file. See the HARDWARE section for information on the external circuitry required and how to specify it to .BR prog84 . .PP By default, .B prog84 does nothing when invoked. These command line options control what happens, in the order they are specified on the command line. .PP .TP .B -h Emits a brief help message listing the acceptable command line parameters. .TP \fB-i\fP \fIn1 n2 n3 n4\fP Program the chip's ID words with the specified values. Each value is 14 bits specified in C notation: decimal, or .B 0 followed by an octal value, or .B 0x followed by a value in hexadecimal. .TP \fB-p\fP \fIfilename\fP Program the PIC with the data contained in the .BR pictools -format file .IR filename . .PP The following options modify the behavior of the programming options. .TP .B -a After writing any location, read it back to verify that it was correctly programmed. .TP .B -b (default) Before writing any location, read it to see if it already contains the desired value. If so, the actual programming step is skipped. It's probably best to specify both the .B -a and .B -b options when programming a microcontroller. .TP .B -v Be more verbose. This option can be specified multiple times to increase the amount of output produced. One .B -v elicits a terse status display, showing which locations are being programmed and whether they verify correctly. Two will show the results of the initial hardware test and dump the information read from the configuration file. Three will produce a line of output describing every bit clocked into the PIC and the bit read back (probably more information than is useful on a regular basis). .PP .SH HADRWARE The circuitry connected to the parallel port must have the ability to control the power, MCLR, clock (RB6), and data (RB7) pins of the 16C84, as well as the ability to read back the state of the data (RB7) pin. .PP Information on the driver circuitry is read from the file .B lp_cfg in the working directory when .B prog84 is started. This file contains pin descriptions, one per line. Comments can be started with a hash mark and continue to the end of the line. Blank lines are ignored. Each data line must contain a pin name, a colon or equals sign, and a description of the parallel-port bit used for that pin. .PP A pin description can be \fBd\fP\fIn\fP to specify data bit \fIn\fP; \fBc\fP\fIn\fP to specify control bit \fIn\fP, or \fBs\fP\fIn\fP to specify status bit \fIn\fP. The bits are numbered starting with the LSB as 0, in the order they are found in the PC's I/O space. Any pin can be preceded by a tilde (~) or exclamation point (!) to reverse the sense of the bit, \fIe.g.\fP if the driver circuit uses inverting buffers. Additionally, some symbolic names are understood: \fBbusy\fP refers to status bit 7; \fBack\fP to status bit 6; and \fBerror\fP, bit 3. .PP The programmer requires the following bits to be specified: .TP power Set to 1 when the programmer wants the PIC's Vdd at +5 volts. .TP mclr Set to 1 when the programmer wants the PIC's /MCLR input set to the programming voltage (+13 volts). .TP clock Used to clock data into the PIC (connect to PIC pin 12) .TP data Used to write data and commands to the PIC (connect to PIC pin 13) .TP data_f A return line to read the state of the data pin .TP clock_f Optional; if specified, this should read the state of the clock pin at the PIC, and is used in the test sequence. .PP If your parallel port is at a base address other than 378 hex, you can specify the base address with a line of the form "base = 0x3bc". Even if your hardware allows you to read from bits other than the status bits (\fIe.g.\fP a bidirectional parallel port), .B prog84 is not smart enough to actually try to read from them. The data line is assumed to be open-collector; it will be driven high (1) when the driver wishes to read data back from the PIC. .SH BUGS The .B pictools file format is pretty esoteric, being produced by only one known assembler. .B prog84 should be extended to read the common Intel Hex format. Currently the file checksum information in the file is ignored. .PP The program should be smart enough to use the parallel programming mode if enough pins are available. .PP Because of realtime timing requirements which are hard to meet in user mode on a Unixlike operating system, .B prog84 cannot program the other members of the PIC family. .PP The configuration file, .BR lp_cfg , is always read from the current working directory, and has a somewhat restricted syntax. In particular, it would be useful to specify bits in terms of their positions on the DB-25 connector. .SH SEE ALSO The .B pictools assembler is written and maintained by Ian King, iek@advanced-robotics-research-centre.salford.ac.uk and is available via anonymous FTP from ftp.funet.fi in the /pub/microprocs/pic directory. .PP This code is based on the specifications in the Microchip Technology 1994 Data Book. .SH AUTHOR Written and copyright by Wim Lewis, wiml@netcom.com, wiml@omnigroup.com, wiml@hhhh.org. You may use, modify, and redistribute this code as long as you retain the attributions and do not incorporate it into a commercial product. Makefile100644 423 0 1322 6135547506 11126 0ustar luigiwheel# CFLAGS=-Wall -g #SETGID= echo 'chgrp kmem $@ ; chmod g+s $@' | su SETGID= STACK=prog84.o lp_io.o io_ports.o # PROGS= prog84 lpttool dump jig all: $(PROGS) tar: prog84.tgz # lpttool: lpttool.o io_ports.o cc -o lpttool lpttool.o io_ports.o jig: jig.o $(STACK) cc -o jig jig.o $(STACK) dump: dump.o $(STACK) cc -o dump dump.o $(STACK) prog84: progmain.o $(STACK) cc -o prog84 progmain.o $(STACK) sampler: sampler.o io_ports.o cc -o sampler sampler.o io_ports.o clean: - rm -f $(PROGS) *.o DISTRIB=README old-README prog84.man Makefile \ prog84.h io_ports.h progmain.c prog84.c lp_io.c io_ports.c \ jig.c lpttool.c dump.c \ lp_cfg lp_cfg.orig prog84.tgz: $(DISTRIB) tar cf - $(DISTRIB) | gzip --best > $@ prog84.h100644 423 0 5623 6135547105 10765 0ustar luigiwheel/* header for anything that wants to use the 16C84's serial programming mode */ #ifndef PROG84_H #define PROG84_H #include #include #include #include #include #include "io_ports.h" #ifndef EXTERN #define EXTERN extern #endif /*** *** Externally visible variables & functions ***/ /*** VARIABLES ***/ /*** *** Bit indicators for the various control & feedback signals. *** See lp_io for what a bit indicator is. ***/ EXTERN int p_power, p_mclr, p_clock, p_data, p_clock_f, p_data_f; /*** lp_io control structure ***/ EXTERN struct lp_io lpb; /*** name of file to read pin assignments from; defaults to lp_cfg ***/ EXTERN char *cfg_file; /*** set this to nonzero for copious output ***/ EXTERN int p84_verbose; EXTERN int verbose; /*** FUNCTIONS ***/ /*** *** set up and shut down the programmer, as well as the software layers *** under this (lpb_cfg_read, open_io(), etc.) ***/ void progSetup(); void progShutdown(); /* powers down */ void power_and_reset(); /*** simple hardware test sequence. called by progSetup(). *** returns non-zero on problem. ***/ int testHW(); /*** Routines to clock some bits through the chip serially. */ /*** send bits through the '84 */ unsigned int pipeBits(unsigned int, int); /*** send bits, confirm, exit on error ***/ void xPipeBits(unsigned int, int); /*** send command & 14 data bits ***/ void genericWrite(int, unsigned int); /*** send command, then read 14 data bits ***/ unsigned int genericRead(int); /* ************************************************************************ */ /* Defines for the descriptive programmer. */ /* MICROCHIP'S SERIAL COMMANDS */ #define SC_LOADCFG 0 /* DATA */ #define SC_CMD1 1 /* used to clear protection */ #define SC_LOADPROG 2 /* DATA */ #define SC_LOADDATA 3 /* DATA */ #define SC_READPROG 4 /* DATA */ #define SC_READDATA 5 /* DATA */ #define SC_INCREMENT 6 #define SC_CMD7 7 /* used to clear protection */ #define SC_PROGRAM 8 #define SC_ERASEPGM 9 #define SC_PARALLEL 10 /* not used */ #define SC_ERASEDATA 11 #define SC_CMD11 11 /* ??? */ /* Bit-twiddling macros, for convenience */ #define SET(bitname, value) lpb_write(&lpb, p_ ## bitname, value) #define GET(bitname) lpb_test(&lpb, p_ ## bitname) #define FLUSH do{ lpb_flush(&lpb); lpb_refresh(&lpb); } while(0) /* Commands that write */ #define loadConfiguration(cfg) genericWrite(SC_LOADCFG, cfg) #define loadProg(data) genericWrite(SC_LOADPROG, data) #define loadData(data) genericWrite(SC_LOADDATA, data) /* Commands that read */ #define readProg() genericRead(SC_READPROG) #define readData() genericRead(SC_READDATA) /* Commands that neither read nor write */ #define incAddr() xPipeBits(SC_INCREMENT, 6) #define doProgram() {xPipeBits(SC_PROGRAM, 6); usleep(10000); prog_w++; } #endif /* PROG84_H */ io_ports.h100644 423 0 4655 6130354405 11476 0ustar luigiwheel/*** io_ports.h - defs & decls for lower level bit I/O routines written and copyright October 1994 Wim Lewis, wiml@{netcom,omnigroup}.com distribution & re-use ok as long as you use this power wisely and only for good, never for evil */ #ifndef IO_PORTS_H #define IO_PORTS_H /*** *** Stuff in io_ports.c ***/ void open_io(void); /* open /dev/port */ void close_io(void); /* close /dev/port */ unsigned char in_byte(int); /* read one byte */ void out_byte(int, unsigned char); /* write one byte */ extern int dev_port_fd; /* the fd used to talk to the kernel */ /* Note: Bit masks for using the status (base+1) and ctl (base+2) ports can be found in /usr/include/linux/lp.h under Linux. Be sure to use the LP_Pwhatever constants and *not* the LP_whatever constants (which are for the device driver's status word, not the hardware's). */ /*** *** Stuff in lp_io.c ***/ /* This allows simple buffering of the bit changes to a line printer port */ struct lp_io { unsigned base; /* base I/O address */ /* Most recently written/read values */ unsigned last[7]; /* was 3 */ /* Desired values */ unsigned wanted[7]; /* was 3 */ }; void lpb_flush(struct lp_io *); /* write out all buffered changes */ void lpb_refresh(struct lp_io *); /* read in current values */ /* These two functions use "bit indicators" encoded into an int; see the bitmasks below. */ int lpb_test(struct lp_io *, int); void lpb_write(struct lp_io *, int, int); /* Bit indicators are encoded into ints and are passed to the set, reset, & test macros. Note that BI_TYPE is the offset from the parallel port base I/O address. NOTE: the serial port uses three bits (8 registers). */ #define BI_OFFSET 000007 /* Bit offset within the word */ #define BI_DATA 000000 /* Data bit? */ #define BI_STAT 000010 /* Status bit? */ #define BI_CTL 000020 /* Control bit? */ #define BI_TYPE 000070 /* Mask for DATA/CTL/STAT etc. */ #define BI_TYPE_SHIFT 3 #define BI_INVERSE 000100 /* Negative logic */ /* Associats a name with a bit indicator. */ struct lp_name { char *name; int *value; }; /* read a fileful of name-indicator pairs */ int lpb_cfg_read(const char *, int, struct lp_name *); void lpb_dump_names(int, struct lp_name *); #endif /* IO_PORTS_H */ progmain.c100644 423 0 26130 6135547300 11462 0ustar luigiwheel/*** *** Source for PIC programmer *** originally: prog84 *** *** Added support for serial programmer, lr 02-apr-96 ***/ #define EXTERN #include "prog84.h" /*** 26-mar-95 Luigi Rizzo: fixed a missing loadconf in programID() *** 01-apr-96 Luigi Rizzo: added clear device (-z) ***/ int argc; char **argv; char **argp; const char *usage = "Usage:\n" "\t-x filename read hex intel file & program\n" "\t-p filename read pictools format file & program\n" "\t-P speed apply power and run serial port at given speed\n" "\t-Q remove power from the device\n" "\t-a verify after programming each location\n" "\t-F force program even if value is already correct\n" "\t-i NN NN NN NN program ID locations\n" "\t-z fully clear the device (program & config)\n" "\t-v be more verbose\n" "\t-h print this help message & exit\n"; /* types of verification */ #define FORCE 0x1 #define VERIFY_AFTER 0x2 /* Argument processing functions */ long int shiftNum(char *); FILE *shiftFile(char *); int picPC; /* what we think the PIC's pc is right now */ int progMode= 0 ;/* default: program */ typedef char BOOL; BOOL progUp; /* has the programmer been initialized? */ int verify; /* what kinds of verification we do */ int errors = 0; /* how many programming errors */ int prog_w=0, read_w=0; /* total programmed and read words */ /* programming routines */ void programID(unsigned int *); void programPicTools(FILE *); void programIntel(FILE *); void programFuse(unsigned int); void programInit(); int handleSerial(int speed) { static int cycle=0; int base, a, d; programInit(); base=lpb.base; if (base!=0x3f8 && base!=0x2f8 && base!=0x3e8 && base != 0x2e8) { printf("Sorry, no serial port connected\n"); return 0; } d = 115200/ speed ; printf("Serial port at %d baud (0x%04x)\n", speed, d); if (d < 1 || d > 0xffff) { printf("sorry, unsupported speed\n"); return 0; } out_byte(base+4, 1 ); /* MCR: only set DTR */ a= 3 ; /* 8 data, 1 stop, no par, ... */ out_byte(base+3, a | 0x80); out_byte(base, d & 0xff); out_byte(base+1, (d>>8) & 0xff); out_byte(base+3, a); for ( ;; ) { int c; char d[2]; d[1]='\0'; d[0]='\0'; if (!(in_byte(base+5) & 0x1) ) { continue; } c=in_byte(base); if ( (c>=' ' && c<= 0x7f) || c==13 ||c==10 || c==8 || c==9) d[0]=c; cycle++; if (verbose) printf("rx [%6d] [0x%02x] 0x%02x %s\n", cycle, in_byte(base+5), c, d ); else printf(d); fflush(stdout); } } void programInit() { if (!progUp) { progSetup(); progUp = 1; } power_and_reset(); picPC = 0; progMode=0; } /*** *** jumps to a given address, possibly resetting the programmer. ***/ void jumpTo(unsigned addr) { /*** *** requests < 0x2100 mean working on program *** > 2100 work on data. Data can only be done if were in data *** or previously were reset. ***/ if ( !progUp || /*** was not active ***/ addr < picPC || /*** must go backwards ***/ (addr >= 0x2100 && (picPC !=0 && picPC < 0x2100) ) ) programInit(); /*** *** at this point, picPC is certainly <= addr ***/ if (addr >= 0x2100 && picPC==0) picPC= 0x2100; /*** doing data ***/ else if (picPC < 0x2000 && addr >= 0x2000) { loadConfiguration(0x3FFF); picPC = 0x2000; } for ( ; picPC < addr; picPC++) incAddr(); } /*** *** command "x" : clear protection fuse ***/ void ResetPic() { jumpTo(0x2007); pipeBits(SC_CMD1,6); pipeBits(SC_CMD7,6); doProgram(); pipeBits(SC_CMD1,6); pipeBits(SC_CMD7,6); } int main(int largc, char *largv[]) { char *cp; int i; unsigned int id[4]; unsigned int f; FILE *fp; verbose = 0; argc = largc; argv = largv; argp = largv + 1; read_w=0; prog_w=0; while ((cp = *(argp++))) { if (*cp != '-') { fprintf(stderr, "%s: %s is not an option\n", *argv, cp); exit(1); } switch(cp[1]) { case 'P': progSetup(); handleSerial(shiftNum("baud rate")); break; case 'Q': programInit(); progShutdown(); exit(0); case 'v': verbose ++; if(verbose > 1) p84_verbose ++; break; case 'i': for(i=0; i<4; i++) id[i] = shiftNum("id number"); programID(id); break; case 'c': f = shiftNum("configuration word"); programFuse(f); break; case 'z': ResetPic(); break; case 'x': fp = shiftFile("hex intel format file"); programIntel(fp); fclose(fp); break; case 'p': fp = shiftFile("pictools format file"); programPicTools(fp); fclose(fp); break; case 'h': printf(usage); exit(0); case 'a': verify |= VERIFY_AFTER; break; case 'F': verify |= FORCE; break; default: fprintf(stderr, "%s: unknown option \"%s\"\n", *argv, cp); exit(1); } } if (argc < 2) printf(usage); if(progUp) progShutdown(); printf("Read %d cells, programmed %d\n", read_w, prog_w); return 0; } /* Programming utilities */ void programID(unsigned int *id) { int i; jumpTo(0x2000); if (verbose) { printf("writing config ["); fflush(stdout); } loadConfiguration(id[0]); for (i = 0; i < 4; i++) { char *s=" "; /* default message */ unsigned int w=readProg(); read_w++; printf("ID %d : have 0x%04x, want 0x%04x\n", i, w, id[i]); if (w == id[i] && ! (verify & FORCE) ) { } else { loadProg(id[i]); /* needed! XXX */ doProgram(); if ((verify & VERIFY_AFTER) && (readProg() != id[i])) { s="X"; errors ++; } else { s="."; } } if (verbose) printf(s); if (i < 3) { if (verbose) fflush(stdout); incAddr(); } } if (verbose) printf("]\n"); picPC = 0x2003; } /* fuses */ #define WDT_FUSE 0x04 /* watchdog timer */ #define PUT_FUSE 0x08 /* power-up timer */ #define CP_FUSE 0x10 /* code protect */ #define FUSE_MASK 0x1F /* only these bits are implemented */ void programFuse(unsigned int f) { unsigned int w=readProg(); jumpTo(0x2007); if ((w & FUSE_MASK) == (f & FUSE_MASK)) { if (verbose) printf("fuses not changed; not re-programmed\n"); return; } if (verbose) printf("writing fuses\n"); loadProg(f); doProgram(); if (verify & VERIFY_AFTER) { int ver = readProg(); if ((ver & FUSE_MASK) != (f & FUSE_MASK)) { fprintf(stderr, "writing fuses: wrote %04x, verified as %04x\n", f, ver); errors ++; } } } void programData(unsigned int addr, int count, unsigned int *buf) { unsigned int w; again: jumpTo(addr); if (verbose) { printf("%d words at data offset 0x%04x [", count, addr); fflush(stdout); } while (count) { char *s=" "; w=readData() & 0xff; read_w++; if ( w == *buf && ! (verify & FORCE) ) { } else { if (verbose) printf("0x%04x: want 0x%02x have 0x%02x\n", picPC, *buf, w); loadData(*buf); doProgram(); s="."; } if (verbose) { printf(s); fflush(stdout); } if (readData() & 0xff != *buf) { printf("\bX"); fflush(stdout); errors ++; programInit(); goto again; } incAddr(); picPC ++; count --; buf ++; } if (verbose) { printf("]\n"); } } void programProg(unsigned int addr, int count, unsigned int *buf) { unsigned int w; again: jumpTo(addr); if (verbose) { printf("%2d words at offset %04x [", count, addr); fflush(stdout); } while (count) { char *s=" "; w=readProg(); read_w++; if ( w == *buf && ! (verify & FORCE) ) { } else { loadProg(*buf); doProgram(); s="."; } if (verbose) { printf(s); fflush(stdout); } if (readProg() != *buf) { printf("\bX"); fflush(stdout); errors ++; programInit(); goto again; } incAddr(); picPC ++; count --; buf ++; } if (verbose) { printf("]\n"); } } void programIntel(FILE *fp) { char buf[512]; unsigned ch, cl, ll, bl, bh, base, len, type; unsigned code_buf[32]; int i; while (fgets(buf, 512, fp)) { if (verbose) printf("--- read <%s>\n",buf); if (buf[0]!=':') { /* print bad line */ continue; } sscanf(buf+1,"%02x%02x%02x%02x",&ll,&bh,&bl, &type); len= (ll) /2; base= ((bh<<8) + bl) /2; if (base < 0x2100) { /*** normal code ***/ for (i=0; i0) programProg(base, len, code_buf); } else { for (i=0; i0) programData(base, len, code_buf); } if (type == 1) break; } } void programPicTools(FILE *fp) { BOOL have_fuses, have_id; unsigned id[4]; unsigned fuses; char buf[512]; unsigned code_addr = 0; int i; fuses = 0xFFF; while (fgets(buf, 512, fp)) { switch(*buf) { case 0: case '\n': case '\r': case '#': break; case 'I': if (sscanf(buf+1, "%i %i %i %i", &id[0], &id[1], &id[2], &id[3]) != 4) { fprintf(stderr,"error reading ID numbers\n"); exit(2); } have_id = 1; case 'A': sscanf(buf+1, "%x", &code_addr); break; case 'D': { unsigned code_buf[32]; int code_count; char *cp; code_count = strtol(buf+1, &cp, 10); if (cp == buf+1) { fprintf(stderr,"error reading data byte count\n"); exit(2); } for (i=0; i[data_f, clock_f]:"); for(i = 0; i < 4; i ++) fprintf(stderr, " %d%d->%d%d", (i>>1)&1, i&1, (ret[i]>>1)&1, (ret[i])&1); fprintf(stderr,"\n"); if (p_clock_f == -1) fprintf(stderr, "(clock_f simulated since I don't actually have it)\n"); if (m == 0x3120) fprintf(stderr, "clock and data reversed?\n" " (could be either the clock & data lines, or the sense lines)\n" ); switch(m & 0x1111) { case 0x0000: fprintf(stderr, "clock_f stuck low?\n"); break; case 0x0101: fprintf(stderr, "clock_f inverted?\n"); break; case 0x1111: fprintf(stderr, "clock_f stuck high?\n"); break; } switch(m & 0x2222) { case 0x0000: fprintf(stderr,"data_f stuck low?\n"); break; case 0x0022: fprintf(stderr,"data_f inverted?\n"); break; case 0x2222: fprintf(stderr,"data_f stuck high?\n"); break; } /*** *** here I evidently have a failure, and should return 1. However, *** I keep on trying in the hope it is a temporary thing. ***/ return 0; } /*** *** Pipe some bits through the 16C84. Returns the values read from *** the data pin at the appropriate point in the cycle for reading *** data mem. In a write, will return 'bits'. (Unless, of course, *** something's wrong.) ***/ unsigned int pipeBits(unsigned int bits, int count) { unsigned int ret = 0; int bit; for (bit=0; bit 1) printf(". bit %2d: send %d get %d\n", bit, bits&1, GET(data_f)?1:0); /* 100ns delay */ bits >>= 1; } SET(data, 1); /* the HI-Z state */ FLUSH; /* required guard time of at least 1 usec. */ return ret; } void xPipeBits(unsigned int bits, int count) { unsigned int ret; ret = pipeBits(bits, count); if (ret != bits) { fprintf(stderr, "ERROR: sent %d bits: %d (0%o), got %d (0%o)\n" "Resetting & powering down.\n", count, bits, bits, ret, ret); progShutdown(); exit(2); } } /* A generic command-plus-14-bits-to-write call */ void genericWrite(int cmd, unsigned int data) /* 6 bits of command, 14 bits of data */ { xPipeBits(cmd, 6); /* Send the command */ xPipeBits((data << 1) & 0x7FFE, 16); /* send the data */ } /* A generic command-plus-14-bits-to-read call */ unsigned int genericRead(int cmd) { unsigned int ret; xPipeBits(cmd, 6); /* send the command */ ret = pipeBits(0x7FFE, 16); /* read the result */ return((ret & 0x7FFE) >> 1); /* remove guard bits */ } void progSetup() { /* read the configuration file */ if (lpb_cfg_read(cfg_file, 11, names)) { fprintf(stderr, "error reading cfg file %s\n", cfg_file); exit(1); } if (p84_verbose) lpb_dump_names(7, names); /* open /dev/port */ open_io(); /* check that the programmer's not totally dead */ if (testHW()) { fprintf(stderr,"\nProgrammer is not responding, aborting.\n"); exit(1); } } void progShutdown() { SET(mclr, 0); FLUSH; usleep(1000); /* shutdown... */ SET(power, 0); SET(clock, 0); SET(data, 0); FLUSH; close_io(); } lp_io.c100644 423 0 15240 6135544756 10764 0ustar luigiwheel/*** *** lp_io.c buffered parallel-port I/O routines. These lie on top of the "asm IN/OUT" analogues in io_ports.c. For convenience, they define "bit indicators" which pack the register of a bit, its offset in the byte, and whether it's inverted or not into an int. There are two pieces of code in this file. The first part does simple buffered bitwise I/O: lpb_write(lpb, bit, val) val = lpb_test(lpb, bit) write to and read the bit indicated by 'bit' in the buffer pointed to by lpb. lpb_flush(lpb) writes out the data and control bytes lpb_refresh(lpb) reads in the status byte The second part parses a (very simple) configuration file format to fill in an array of bit indicators. This is lpb_cfg_read(), which takes a filename, a pointer to an array of (struct lp_name)s, and the length of the array, and tries to fill in the array from the data file. There is a companion function, lpb_dump_names, which takes an array or structs and its length, and dumps them to stdout for debugging. *** ***/ #include "io_ports.h" #include #include #include #include /* for strtoul() */ /* This turns on debugging output from lpb_cfg_read */ /* #define LPBDEBUG */ void lpb_write(struct lp_io *lpb, int bit, int val) { int mask = 1 << (bit & BI_OFFSET); int idx= (bit & BI_TYPE) >> BI_TYPE_SHIFT; if (bit & BI_INVERSE) val = !val; if (val) lpb->wanted[ idx ] |= mask; else lpb->wanted[ idx ] &= ~mask; } int lpb_test(struct lp_io *lpb, int bit) { int mask = 1 << (bit & BI_OFFSET); if (lpb->last[ (bit & BI_TYPE) >> BI_TYPE_SHIFT ] & mask) return (bit & BI_INVERSE)? 0 : 1; else return (bit & BI_INVERSE)? 1 : 0; } void lpb_flush(struct lp_io *lpb) { int i; for (i=0; i<7; i++) /* gratuitous loop construct */ if(lpb->wanted[i] != lpb->last[i]) { out_byte(lpb->base + i, (unsigned char)(lpb->wanted[i])); /* printf(".\b"); fflush(stdout); */ /* usleep(10); */ lpb->last[i] = lpb->wanted[i]; } } void lpb_refresh(lpb) struct lp_io *lpb; { /* printf(".\b"); fflush(stdout); */ /* usleep(10);*/ lpb->last[1] = in_byte(lpb->base + 1); lpb->last[6] = in_byte(lpb->base + 6); } /*** *** lpb_cfg_read() and helpers *** *** NOTE that any entry in the names vector with with the name "base" *** is treated specially; it is read as an integer (with C syntax for *** octal & hex) instead of being parsed as a bit spec *** *** Also note that the parseBit() routine is very simple minded right *** now and should probably be extended a little bit ***/ #define MAXLINE 512 static int parseBit(char *); int lpb_cfg_read(const char *filename, int namec, struct lp_name *namev) { FILE *fp; char buf[MAXLINE]; char *line, *cp; int wordlen; enum { wtNone, wtNumber, wtName } wordtype; int word; /* init */ fp = fopen(filename, "r"); if (!fp) { perror(filename); return -1; } while(fgets(buf, MAXLINE, fp)) { #ifdef LPBDEBUG printf("<%s>\n", buf); #endif /* Trim leading whitespace. */ for (cp = buf; *cp && isspace(*cp); cp++) ; line = cp; /* Remove comments. */ if ((cp = index(line, '#'))) *cp = (char)0; /* Skip blank lines. */ if (!*line) continue; /* Extract the first word of the line. */ for (cp = line; *cp; cp++) if(isspace(*cp) || (*cp == '=') || (*cp == ':')) break; wordlen = cp - line; #ifdef LPBDEBUG printf("[key <%.*s>]\n", wordlen, line); #endif /* Skip past the separator, if any */ while(*cp && isspace(*cp)) cp++; if ((*cp == '=') || (*cp == ':')) cp++; /* Find out what kind of word this is. */ wordtype = wtNone; if (!wordtype) for (word = 0; word < namec; word ++) if (wordlen == strlen(namev[word].name) && !strncmp(line, namev[word].name, wordlen)) { wordtype = wtName; #ifdef LPBDEBUG printf("[index %d]\n", word); #endif break; } if (wordtype == wtName && wordlen == 4 && !strncmp(line, "base", wordlen)) wordtype = wtNumber; #ifdef LPBDEBUG printf("[wordtype = %d]\n", wordtype); #endif /* Parse the word. */ switch (wordtype) { case wtNone: fprintf(stderr, "%s: don't know what to do with \"%.*s\"\n", filename, wordlen, line); break; case wtName: *(namev[word].value) = parseBit(cp); break; case wtNumber: *(namev[word].value) = strtoul(cp, (char **)NULL, 0); break; } } /* end of for-each-line loop */ fclose(fp); return(0); } static struct { char *name; int nameLen, value; } symBits[] = { { "busy", 4, BI_STAT | 7 }, { "ack", 3, BI_STAT | 6 }, { "error", 5, BI_STAT | 3 }, { "TxD", 3, 030 | 6 }, /* base +3, bit 6 */ { "RTS", 3, 040 | 1 }, /* base +4, bit 1 */ { "DTR", 3, 040 | 0 }, /* base +4, bit 0 */ { "CTS", 3, 060 | 4 }, /* base +6, bit 4 */ { NULL, 0, 0 } }; static int parseBit(char *spec) { char *cp = spec; int val = 0, valid = 0, i; #ifdef LPBDEBUG printf("[parsing bit <%s>]\n", spec); #endif if (!*cp) return -1; do { #ifdef LPBDEBUG printf("@%s,%d\n", cp, val); #endif switch(*cp) { case ' ': case '\t': case '\n': break; /* ignore whitespace */ case '!': case '~': val ^= BI_INVERSE; /* inversion */ break; #if 0 case 'd': case 'D': val &= ~(BI_TYPE | BI_OFFSET); val |= strtol(cp+1, &cp, 10) | BI_DATA; cp--; valid = 1; break; case 'c': case 'C': val &= ~(BI_TYPE | BI_OFFSET); val |= strtol(cp+1, &cp, 10) | BI_CTL; cp--; valid = 1; break; #endif case 's': case 'S': val &= ~(BI_TYPE | BI_OFFSET); val |= strtol(cp+1, &cp, 10) | BI_STAT; cp--; valid = 1; break; default: for (i = 0; symBits[i].name; i++) if (!strncmp(cp, symBits[i].name, symBits[i].nameLen)) { cp += symBits[i].nameLen - 1; val &= ~(BI_TYPE | BI_OFFSET); val |= symBits[i].value; valid = 1; break; } if (symBits[i].name) break; fprintf(stderr, "unrecognized pin name: \"%s\"\n", cp); return -1; } } while(*++cp); return (valid ? val : -1); } static const char * const typeNames[8] = { "data", "status", "control", "txd", "lcr", "---", "msr", "---" }; void lpb_dump_names(int namec, struct lp_name *namev) { int v, i; for (i=0; i> BI_TYPE_SHIFT ], v & BI_OFFSET, (v & BI_INVERSE) ? " inverted":""); } } io_ports.c100644 423 0 4200 6135545634 11466 0ustar luigiwheel/*** *** convenience routines for doing simple I/O with linux' /dev/port *** *** note that you have to have uid=root or gid=kmem to open /dev/port *** written and copyright October 1994 by *** Wim Lewis, wiml@{netcom,omnigroup}.com *** distribute, modify, re-use freely! ***/ #ifdef __FreeBSD__ #include #include #include #ifndef inb #define inb(y) \ ({ unsigned char _tmp__; \ asm volatile("inb %1, %0" : "=a" (_tmp__) : "d" ((unsigned short)(y))); \ _tmp__; }) #endif /* inb */ #ifndef outb #define outb(x, y) \ { asm volatile("outb %0, %1" : : "a" ((unsigned char)(y)) ,\ "d" ((unsigned short)(x))); } #endif static int portio_fd= -1; void close_io() { close(portio_fd); } void open_io() { portio_fd=open("/dev/io",O_RDWR); if (portio_fd <0 ) { perror("cannot open /dev/io"); exit(errno); } } void out_byte(int port, unsigned char byte) { outb(port,byte); } unsigned char in_byte(int port) { return inb(port); } #else #include "io_ports.h" #include #include #include #include #include int dev_port_fd = -1; void open_io() { dev_port_fd = open("/dev/port", O_RDWR); if(dev_port_fd < 0) { perror("/dev/port"); exit(errno); } } void close_io() { close(dev_port_fd); dev_port_fd = -1; } void out_byte(port, byte) int port; unsigned char byte; { off_t s; int r; s = lseek(dev_port_fd, port, 0); if(s < 0) perror("lseek"); else if(s != port) fprintf(stderr, "hmmm: seeking to %d, went to %ld.\n", port, (long)s); r = write(dev_port_fd, &byte, 1); if(r != 1) { fprintf(stderr, "hmmm: write returned %d\n", r); if(r < 0) perror("write"); } } unsigned char in_byte(port) int port; { off_t s; int r; unsigned char ch = 0; s = lseek(dev_port_fd, port, 0); if(s < 0) perror("lseek"); else if(s != port) fprintf(stderr, "hmmm: seeking to %d, went to %ld.\n", port, (long)s); r = read(dev_port_fd, &ch, 1); if(r != 1) { fprintf(stderr, "hmmm: read returned %d\n", r); if(r < 0) perror("read"); } return ch; } #endif jig.c100644 423 0 4263 6135547375 10416 0ustar luigiwheel/*** *** this is a simple program to drive the lines of the PIC programmer *** Not very important when the programmer works, just a nice *** debugging tool! ***/ #define EXTERN #include "prog84.h" void doSimple(name, bit, buf) const char *name; int bit; char *buf; { int num = atoi(buf); lpb_write(&lpb, bit, num?1:0); printf("%s O%s\n", name, num?"N":"FF"); lpb_flush(&lpb); } void jig() { char buf[256]; int bits, num; printf("\n*** simple jig mode. enter:\n" " p0 or p1 to turn power off or on\n" " m0 or m1 to set MCLR low or high\n" " c0 or c1 to set the clock input\n" " d0 or d1 to set the data input\n" " r to read the current clock & data sense lines\n" " d c to clock c bits of d, lsb first\n" " .conf to load configuration\n" " .read to read program memory\n" " .next to advance address\n" " .prog n to program current cell with n\n" ); while(fgets(buf, 256, stdin)) { if(!*buf) break; if (!strncmp(buf,".read",5)) { printf("read 0x%04x\n", genericRead(4)); continue; } if (!strncmp(buf,".next",5)) { pipeBits(6,6); continue; } if (!strncmp(buf,".conf",5)) { genericWrite(0, 0); /* load prog. mem */ printf("read 0x%04x\n", genericRead(4)); continue; } if (!strncmp(buf,".prog",5)) { int d; sscanf(buf+5,"%i", &d); genericWrite(2, d); /* load prog. mem */ pipeBits(8, 6); usleep(20000); continue; } if(*buf == 'p') { doSimple("power", p_power, buf+1); continue; } if(*buf == 'm') { doSimple("mclr", p_mclr, buf+1); continue; } if(*buf == 'c') { doSimple("clock", p_clock, buf+1); continue; } if(*buf == 'd') { doSimple("data", p_data, buf+1); continue; } if(*buf == 'r') { lpb_refresh(&lpb); printf("clock=%d data=%d\n", GET(clock_f), GET(data_f)); continue; } if(sscanf(buf, "%i %d", &bits, &num) != 2) { printf("?\n"); continue; } if(bits & ~((1< 0x%04x\n", bits, num, pipeBits(bits, num)); } } int main() { verbose = 1; progSetup(); jig(); progShutdown(); return 0; } lpttool.c100644 423 0 3330 6135545114 11321 0ustar luigiwheel/*** *** Another debugging tool for checking the parallel port ***/ #include #include #include #include "io_ports.h" #ifdef linux #include #endif #ifdef __FreeBSD__ #define LP_PERRORP 0x08 #define LP_PSELECD 0x10 #define LP_POUTPA 0x20 #define LP_PACK 0x40 #define LP_PBUSY 0x80 #endif #define IBUFLEN 128 #define LPT1_BASE (0x378) /* where LPT1: is on most h/w */ /* These assume that 'base' == LPT1_BASE or equiv. */ #define lp_data (base) /* write to this to change D0-D7 */ #define lp_status (base+1) /* read from this to get status */ #define lp_ctl (base+2) /* write to change the ctl lines */ int base = LPT1_BASE; int main(int argc, char *argv[]) { char buf[IBUFLEN]; unsigned char ch; if (argc == 2) base = atoi(argv[1]); if ((argc != 1) || (!base)) { fputs("Bad usage! No biscuit!\n", stderr); exit(8); } open_io(); /* opens /dev/port */ printf("base = %d (0x%x)\n", base, base); while (fgets(buf, IBUFLEN, stdin)) { if (buf[0] == '?') { ch = in_byte(lp_data); printf("<-- %d (0x%02x)\n", (int)ch, (int)ch); } else if (!buf[0] || buf[0] == '\n') { ch = in_byte(lp_status); printf("<+1 %d (0x%02x):", (int)ch, (int)ch); if (!(ch & LP_PBUSY)) printf(" BUSY"); if (!(ch & LP_PACK)) printf(" ACK"); if (ch & LP_POUTPA) printf(" OUT-OF-PAPER"); if (ch & LP_PSELECD) printf(" ONLINE"); if (!(ch & LP_PERRORP)) printf(" ERROR"); printf("\n"); } else { ch = (unsigned char)atoi(buf); out_byte(lp_data, ch); printf("--> %d (0x%02x)\n", (int)ch, (int)ch); } } close_io(); /* release /dev/port */ return(0); } dump.c100644 423 0 5325 6135547340 10602 0ustar luigiwheel/*** *** File: dump.c *** *** dumps the content of a 16c84 ***/ #define EXTERN #include "prog84.h" void dumpProg(unsigned, unsigned); void dumpData(unsigned, unsigned); void dumpCfg(); int buf[8]; void dump_buf(int buf_count) { int i; printf("D%d", buf_count); for(i=0; i1 && atoi(argv[1]) < 8192) last_addr=atoi(argv[1]); progSetup(); time(&now); printf("# pictools format dump file\n# created by %s on %s", argv[0], ctime(&now)); dumpCfg(); dumpData(0, 64); dumpProg(0, last_addr); progShutdown(); return 0; } void dumpProg(unsigned min_addr, unsigned max_addr) { int pic_addr=0; int buf_count; start_cfg(); printf("A%04x\n", min_addr); for (pic_addr=0; pic_addr < min_addr; pic_addr++) incAddr(); for (buf_count = 0 ; pic_addr < max_addr ; pic_addr++) { buf[buf_count ++] = readProg(); if (buf_count >= 8) { dump_buf(buf_count); buf_count = 0; } incAddr(); } if (buf_count) dump_buf(buf_count); } void dumpData(unsigned min_addr, unsigned max_addr) { int pic_addr; int buf_count; start_cfg(); printf("B%04x\n", min_addr); for (pic_addr=0; pic_addr < min_addr; pic_addr++) incAddr(); for (buf_count = 0 ; pic_addr < max_addr ; pic_addr++) { buf[buf_count ++] = readData(); if (buf_count >= 8) { dump_buf(buf_count); buf_count = 0; } incAddr(); } if (buf_count) dump_buf(buf_count); } char *xtal_names[] = { "LP oscillator", "XT Oscillator", "HS Oscillator", "RC Oscillator" }; void dumpCfg() { unsigned int id[4], fuses; int i; start_cfg(); printf("T84 # I can only understand '84s\n"); /* dummy load configuration command to get to cfg memory */ loadConfiguration(0x3FFF); for (i=0; i<7; i++) { if (i<4) id[i] = readProg(); incAddr(); } fuses = readProg(); printf("I%04x %04x %04x %04x # id locations\n", id[0], id[1], id[2], id[3]); printf("%s\n%s\n%s\nC%d 0 # %s\n", fuses & 0x10 ? "P1 # Code protection off" : "P0 # Code protection on", fuses & 0x08 ? "U1 # Power-Up Timer Enabled" : "U0 # Power-Up Timer disabled", fuses & 0x04 ? "W1 # Watchdog Enabled" : "W0 # Watchdog Disabled", fuses & 0x03, xtal_names[fuses & 3] ); } lp_cfg100644 423 0 316 6213037420 10607 0ustar luigiwheel# power = !d1 # mclr: !d0 # rb7: d2 # rb6: !d3 # rb7_f = ack # base = 0x378 ### for serial port: #base= 0x3e8 # com3, sio2 base= 0x2f8 # com2, sio1 power: DTR mclr: DTR data: TxD data_f: CTS clock: RTS lp_cfg.orig100644 423 0 117 6032275055 11554 0ustar luigiwheelpower = !d1 mclr: !d0 rb7: ~d2 rb6: ~d3 rb7_f = ~ack rb6_f = ~s4 base = 0x378