From 3d8f8bcd4527574356e4eb8e45f29cf72faafa7f Mon Sep 17 00:00:00 2001 From: "Brian S. Dean" Date: Sun, 14 Oct 2001 23:17:26 +0000 Subject: [PATCH] Use lex/yacc for parsing the config file. Re-work the config file format using a more human-readable format. Read part descriptions from the config file now instead of hard-coding them. Update usage(). Cleanup unused code. git-svn-id: svn://svn.savannah.nongnu.org/avrdude/trunk/avrdude@79 81a1dc3b-b13d-400b-aceb-764788c761c2 --- Makefile | 20 +- Makefile.inc | 8 +- avr.c | 137 +++-- avr.h | 68 +-- avrdude.conf.sample | 315 +++++++++- config.c | 283 +++++++++ config.h | 84 +++ config_gram.y | 307 ++++++++++ lexer.l | 137 +++++ lists.c | 1355 +++++++++++++++++++++++++++++++++++++++++++ lists.h | 91 +++ main.c | 610 +++++++------------ pindefs.h | 16 - term.c | 10 +- 14 files changed, 2900 insertions(+), 541 deletions(-) create mode 100644 config.c create mode 100644 config.h create mode 100644 config_gram.y create mode 100644 lexer.l create mode 100644 lists.c create mode 100644 lists.h diff --git a/Makefile b/Makefile index 6c919665..07d30ad0 100644 --- a/Makefile +++ b/Makefile @@ -17,28 +17,36 @@ DIRS = ${BINDIR} ${MANDIR} ${DOCDIR} ${CONFIGDIR} INSTALL = /usr/bin/install -c -o root -g wheel -CFLAGS = -g -Wall --pedantic -DCONFIG_DIR=\"${CONFIGDIR}\" - +CFLAGS = -g -Wall --pedantic -DCONFIG_DIR=\"${CONFIGDIR}\" ${YYDEF} LDFLAGS = +YFLAGS = -t -d -v INSTALL_PROGRAM = ${INSTALL} -m 555 -s INSTALL_DATA = ${INSTALL} -m 444 INSTALL_MANUAL = ${INSTALL_DATA} -LIBS = -lreadline +LIBS = -lreadline + +YYDEF = -DYYSTYPE="struct token_t *" + .include "Makefile.inc" +EXTRA_OBJS = config_gram.o lexer.o +OBJECTS = ${EXTRA_OBJS} ${OBJS} + all : + @if [ ! -f y.tab.h ]; then touch y.tab.h; fi make depend make ${TARGET} -${TARGET} : ${OBJS} - ${CC} ${LDFLAGS} -o ${TARGET} ${OBJS} ${LIBS} +${TARGET} : ${OBJECTS} + ${CC} ${LDFLAGS} -o ${TARGET} ${OBJECTS} ${LIBS} clean : - rm -f *~ *.core ${TARGET} *.o + rm -f *.o lexer.c ${TARGET} *~ *.core y.tab.c y.tab.h + touch y.tab.h install : dirs \ ${BINDIR}/${TARGET} \ diff --git a/Makefile.inc b/Makefile.inc index e22d5242..04dd5297 100644 --- a/Makefile.inc +++ b/Makefile.inc @@ -1,8 +1,14 @@ -.SUFFIXES: .o .c +.SUFFIXES: .o .c .l .y first_rule : all +.y.o: + ${YACC} ${YFLAGS} ${.IMPSRC} + ${CC} ${CFLAGS} -c y.tab.c + rm -f y.tab.c + mv y.tab.o ${.TARGET} + .depend : .PHONY @echo "# dependencies generated `date +'%D %T'`" > .depend diff --git a/avr.c b/avr.c index 381dbbec..66223a92 100644 --- a/avr.c +++ b/avr.c @@ -36,12 +36,14 @@ #include "avr.h" +#include "config.h" #include "pindefs.h" #include "ppi.h" -extern char * progname; -extern char progbuf[]; +extern char * progname; +extern char progbuf[]; +extern PROGRAMMER * pgm; char * avr_version = "$Id$"; @@ -49,6 +51,7 @@ char * avr_version = "$Id$"; /* Need to add information for 2323, 2343, and 4414 */ +#if 0 struct avrpart parts[] = { {"AT90S1200", "1200", 20000, {{0, 64, 0, 0, 9000, 20000, {0x00, 0xff }, NULL}, /* eeprom */ @@ -87,8 +90,6 @@ struct avrpart parts[] = { #define N_AVRPARTS (sizeof(parts)/sizeof(struct avrpart)) - - int avr_list_parts(FILE * f, char * prefix) { int i; @@ -114,6 +115,56 @@ struct avrpart * avr_find_part(char * p) return NULL; } +#endif + + +AVRPART * avr_new_part(void) +{ + AVRPART * p; + + p = (AVRPART *)malloc(sizeof(AVRPART)); + if (p == NULL) { + fprintf(stderr, "new_part(): out of memory\n"); + exit(1); + } + + memset(p, 0, sizeof(*p)); + + p->id[0] = 0; + p->desc[0] = 0; + + return p; +} + + + +AVRPART * avr_dup_part(AVRPART * d) +{ + AVRPART * p; + int i; + + p = (AVRPART *)malloc(sizeof(AVRPART)); + if (p == NULL) { + fprintf(stderr, "avr_dup_part(): out of memory\n"); + exit(1); + } + + *p = *d; + + for (i=0; imem[i].buf = (unsigned char *)malloc(p->mem[i].size); + if (p->mem[i].buf == NULL) { + fprintf(stderr, + "avr_dup_part(): out of memory (memsize=%d)\n", + p->mem[i].size); + exit(1); + } + memset(p->mem[i].buf, 0, p->mem[i].size); + } + + return p; +} + /* @@ -127,16 +178,16 @@ int avr_txrx_bit(int fd, int bit) * read the result bit (it is either valid from a previous clock * pulse or it is ignored in the current context) */ - r = ppi_getpin(fd, pinno[PIN_AVR_MISO]); + r = ppi_getpin(fd, pgm->pinno[PIN_AVR_MISO]); /* set the data input line as desired */ - ppi_setpin(fd, pinno[PIN_AVR_MOSI], bit); + ppi_setpin(fd, pgm->pinno[PIN_AVR_MOSI], bit); /* * pulse the clock line, clocking in the MOSI data, and clocking out * the next result bit */ - ppi_pulsepin(fd, pinno[PIN_AVR_SCK]); + ppi_pulsepin(fd, pgm->pinno[PIN_AVR_SCK]); return r; } @@ -180,8 +231,8 @@ int avr_cmd(int fd, unsigned char cmd[4], unsigned char res[4]) /* * read a byte of data from the indicated memory region */ -unsigned char avr_read_byte(int fd, struct avrpart * p, - int memtype, unsigned long addr) +unsigned char avr_read_byte(int fd, AVRPART * p, + int memtype, unsigned long addr) { unsigned short offset; unsigned char cmd[4]; @@ -189,8 +240,8 @@ unsigned char avr_read_byte(int fd, struct avrpart * p, /* order here is very important, AVR_EEPROM, AVR_FLASH, AVR_FLASH+1 */ static unsigned char cmdbyte[3] = { 0xa0, 0x20, 0x28 }; - LED_ON(fd, pinno[PIN_LED_PGM]); - LED_OFF(fd, pinno[PIN_LED_ERR]); + LED_ON(fd, pgm->pinno[PIN_LED_PGM]); + LED_OFF(fd, pgm->pinno[PIN_LED_ERR]); offset = 0; @@ -206,7 +257,7 @@ unsigned char avr_read_byte(int fd, struct avrpart * p, avr_cmd(fd, cmd, res); - LED_OFF(fd, pinno[PIN_LED_PGM]); + LED_OFF(fd, pgm->pinno[PIN_LED_PGM]); return res[3]; } @@ -218,7 +269,7 @@ unsigned char avr_read_byte(int fd, struct avrpart * p, * * Return the number of bytes read, or -1 if an error occurs. */ -int avr_read(int fd, struct avrpart * p, int memtype) +int avr_read(int fd, AVRPART * p, int memtype) { unsigned char rbyte; unsigned long i; @@ -243,14 +294,14 @@ int avr_read(int fd, struct avrpart * p, int memtype) /* * write a byte of data to the indicated memory region */ -int avr_write_bank(int fd, struct avrpart * p, int memtype, +int avr_write_bank(int fd, AVRPART * p, int memtype, unsigned short bank) { unsigned char cmd[4]; unsigned char res[4]; - LED_ON(fd, pinno[PIN_LED_PGM]); - LED_OFF(fd, pinno[PIN_LED_ERR]); + LED_ON(fd, pgm->pinno[PIN_LED_PGM]); + LED_OFF(fd, pgm->pinno[PIN_LED_ERR]); cmd[0] = 0x4c; cmd[1] = bank >> 8; /* high order bits of address */ @@ -265,7 +316,7 @@ int avr_write_bank(int fd, struct avrpart * p, int memtype, */ usleep(p->mem[memtype].max_write_delay); - LED_OFF(fd, pinno[PIN_LED_PGM]); + LED_OFF(fd, pgm->pinno[PIN_LED_PGM]); return 0; } @@ -273,8 +324,8 @@ int avr_write_bank(int fd, struct avrpart * p, int memtype, /* * write a byte of data to the indicated memory region */ -int avr_write_byte(int fd, struct avrpart * p, int memtype, - unsigned long addr, unsigned char data) +int avr_write_byte(int fd, AVRPART * p, int memtype, + unsigned long addr, unsigned char data) { unsigned char cmd[4]; unsigned char res[4]; @@ -302,8 +353,8 @@ int avr_write_byte(int fd, struct avrpart * p, int memtype, addr = addr % p->mem[memtype].bank_size; } - LED_ON(fd, pinno[PIN_LED_PGM]); - LED_OFF(fd, pinno[PIN_LED_ERR]); + LED_ON(fd, pgm->pinno[PIN_LED_PGM]); + LED_OFF(fd, pgm->pinno[PIN_LED_ERR]); offset = 0; @@ -326,7 +377,7 @@ int avr_write_byte(int fd, struct avrpart * p, int memtype, * page complete immediately, we only need to delay when we commit * the whole page via the avr_write_bank() routine. */ - LED_OFF(fd, pinno[PIN_LED_PGM]); + LED_OFF(fd, pgm->pinno[PIN_LED_PGM]); return 0; } @@ -357,14 +408,14 @@ int avr_write_byte(int fd, struct avrpart * p, int memtype, * we couldn't write the data, indicate our displeasure by * returning an error code */ - LED_OFF(fd, pinno[PIN_LED_PGM]); - LED_ON(fd, pinno[PIN_LED_ERR]); + LED_OFF(fd, pgm->pinno[PIN_LED_PGM]); + LED_ON(fd, pgm->pinno[PIN_LED_ERR]); return -1; } } - LED_OFF(fd, pinno[PIN_LED_PGM]); + LED_OFF(fd, pgm->pinno[PIN_LED_PGM]); return 0; } @@ -378,7 +429,7 @@ int avr_write_byte(int fd, struct avrpart * p, int memtype, * * Return the number of bytes written, or -1 if an error occurs. */ -int avr_write(int fd, struct avrpart * p, int memtype, int size) +int avr_write(int fd, AVRPART * p, int memtype, int size) { int rc; int wsize; @@ -386,7 +437,7 @@ int avr_write(int fd, struct avrpart * p, int memtype, int size) unsigned char data; int werror; - LED_OFF(fd, pinno[PIN_LED_ERR]); + LED_OFF(fd, pgm->pinno[PIN_LED_ERR]); werror = 0; @@ -410,7 +461,7 @@ int avr_write(int fd, struct avrpart * p, int memtype, int size) if (rc) { fprintf(stderr, " ***failed; "); fprintf(stderr, "\n"); - LED_ON(fd, pinno[PIN_LED_ERR]); + LED_ON(fd, pgm->pinno[PIN_LED_ERR]); werror = 1; } @@ -424,7 +475,7 @@ int avr_write(int fd, struct avrpart * p, int memtype, int size) i % p->mem[memtype].bank_size, i-p->mem[memtype].bank_size+1, i); fprintf(stderr, "\n"); - LED_ON(fd, pinno[PIN_LED_ERR]); + LED_ON(fd, pgm->pinno[PIN_LED_ERR]); werror = 1; } } @@ -435,7 +486,7 @@ int avr_write(int fd, struct avrpart * p, int memtype, int size) * make sure the error led stay on if there was a previous write * error, otherwise it gets cleared in avr_write_byte() */ - LED_ON(fd, pinno[PIN_LED_ERR]); + LED_ON(fd, pgm->pinno[PIN_LED_ERR]); } } @@ -466,18 +517,18 @@ int avr_program_enable(int fd) /* * issue the 'chip erase' command to the AVR device */ -int avr_chip_erase(int fd, struct avrpart * p) +int avr_chip_erase(int fd, AVRPART * p) { unsigned char data[4] = {0xac, 0x80, 0x00, 0x00}; unsigned char res[4]; - LED_ON(fd, pinno[PIN_LED_PGM]); + LED_ON(fd, pgm->pinno[PIN_LED_PGM]); avr_cmd(fd, data, res); usleep(p->chip_erase_delay); avr_initialize(fd, p); - LED_OFF(fd, pinno[PIN_LED_PGM]); + LED_OFF(fd, pgm->pinno[PIN_LED_PGM]); return 0; } @@ -524,7 +575,7 @@ void avr_powerdown(int fd) /* * initialize the AVR device and prepare it to accept commands */ -int avr_initialize(int fd, struct avrpart * p) +int avr_initialize(int fd, AVRPART * p) { int rc; int tries; @@ -532,9 +583,9 @@ int avr_initialize(int fd, struct avrpart * p) avr_powerup(fd); - ppi_setpin(fd, pinno[PIN_AVR_SCK], 0); - ppi_setpin(fd, pinno[PIN_AVR_RESET], 0); - ppi_pulsepin(fd, pinno[PIN_AVR_RESET]); + ppi_setpin(fd, pgm->pinno[PIN_AVR_SCK], 0); + ppi_setpin(fd, pgm->pinno[PIN_AVR_RESET], 0); + ppi_pulsepin(fd, pgm->pinno[PIN_AVR_RESET]); usleep(20000); /* 20 ms XXX should be a per-chip parameter */ @@ -546,7 +597,7 @@ int avr_initialize(int fd, struct avrpart * p) * order to possibly get back into sync with the chip if we are out * of sync. */ - if (strcmp(p->partdesc, "AT90S1200")==0) { + if (strcmp(p->desc, "AT90S1200")==0) { avr_program_enable(fd); } else { @@ -555,7 +606,7 @@ int avr_initialize(int fd, struct avrpart * p) rc = avr_program_enable(fd); if (rc == 0) break; - ppi_pulsepin(fd, pinno[PIN_AVR_SCK]); + ppi_pulsepin(fd, pgm->pinno[PIN_AVR_SCK]); tries++; } while (tries < 32); @@ -583,7 +634,7 @@ char * avr_memtstr(int memtype) } -int avr_initmem(struct avrpart * p) +int avr_initmem(AVRPART * p) { int i; @@ -607,7 +658,7 @@ int avr_initmem(struct avrpart * p) * * Return the number of bytes verified, or -1 if they don't match. */ -int avr_verify(struct avrpart * p, struct avrpart * v, int memtype, int size) +int avr_verify(AVRPART * p, AVRPART * v, int memtype, int size) { int i; unsigned char * buf1, * buf2; @@ -665,7 +716,7 @@ void avr_mem_display(char * prefix, FILE * f, AVRMEM * m, int type) -void avr_display(FILE * f, struct avrpart * p, char * prefix) +void avr_display(FILE * f, AVRPART * p, char * prefix) { int i; char * buf; @@ -675,7 +726,7 @@ void avr_display(FILE * f, struct avrpart * p, char * prefix) "%sAVR Part : %s\n" "%sChip Erase delay : %d us\n" "%sMemory Detail :\n\n", - prefix, p->partdesc, + prefix, p->desc, prefix, p->chip_erase_delay, prefix); diff --git a/avr.h b/avr.h index c4b04d0a..ba488c67 100644 --- a/avr.h +++ b/avr.h @@ -45,15 +45,6 @@ #define AVR_MAXMEMTYPES 2 /* just flash and eeprom */ -#if 0 -struct avrmem { - int startaddr; - int size; - unsigned char * buf; - struct avrmem * next; -}; -#endif - typedef struct avrmem { int banked; /* bank addressed (e.g. ATmega flash) */ int size; /* total memory size in bytes */ @@ -66,42 +57,27 @@ typedef struct avrmem { } AVRMEM; -struct avrpart { - char * partdesc; /* long part name */ - char * optiontag; /* short part name */ +#define AVR_DESCLEN 64 +#define AVR_IDLEN 32 +typedef struct avrpart { + char desc[AVR_DESCLEN]; /* long part name */ + char id[AVR_IDLEN]; /* short part name */ int chip_erase_delay; /* microseconds */ AVRMEM mem[AVR_MAXMEMTYPES]; - -#if 0 - int memsize[AVR_MAXMEMTYPES]; /* sizes for eeprom, - flash, etc, indexed by - AVR_EEPROM or AVR_FLASH */ - unsigned char f_readback; /* flash write polled readback value */ - unsigned char e_readback[2]; /* eeprom write polled readback values */ - int min_write_delay; /* microseconds */ - int max_write_delay; /* microseconds */ -#if 1 - unsigned char * mem[AVR_MAXMEMTYPES]; /* pointers to avr memory - buffers, indexed by - AVR_EEPROM or AVR_FLASH */ -#else - struct avrmem * mem[AVR_MAXMEMTYPES]; /* pointers to avr memory - buffers, indexed by - AVR_EEPROM or AVR_FLASH */ -#endif -#endif -}; +} AVRPART; extern struct avrpart parts[]; -int avr_list_parts(FILE * f, char * prefix); +AVRPART * avr_find_part(char * p); -struct avrpart * avr_find_part(char * p); +AVRPART * avr_new_part(void); + +AVRPART * avr_dup_part(AVRPART * d); int avr_txrx_bit(int fd, int bit); @@ -109,22 +85,22 @@ unsigned char avr_txrx(int fd, unsigned char byte); int avr_cmd(int fd, unsigned char cmd[4], unsigned char res[4]); -unsigned char avr_read_byte(int fd, struct avrpart * p, - int memtype, unsigned long addr); +unsigned char avr_read_byte(int fd, AVRPART * p, + int memtype, unsigned long addr); -int avr_read(int fd, struct avrpart * p, int memtype); +int avr_read(int fd, AVRPART * p, int memtype); -int avr_write_bank(int fd, struct avrpart * p, int memtype, +int avr_write_bank(int fd, AVRPART * p, int memtype, unsigned short bank); -int avr_write_byte(int fd, struct avrpart * p, int memtype, - unsigned long addr, unsigned char data); +int avr_write_byte(int fd, AVRPART * p, int memtype, + unsigned long addr, unsigned char data); -int avr_write(int fd, struct avrpart * p, int memtype, int size); +int avr_write(int fd, AVRPART * p, int memtype, int size); int avr_program_enable(int fd); -int avr_chip_erase(int fd, struct avrpart * p); +int avr_chip_erase(int fd, AVRPART * p); int avr_signature(int fd, unsigned char sig[4]); @@ -132,16 +108,16 @@ void avr_powerup(int fd); void avr_powerdown(int fd); -int avr_initialize(int fd, struct avrpart * p); +int avr_initialize(int fd, AVRPART * p); char * avr_memtstr(int memtype); -int avr_initmem(struct avrpart * p); +int avr_initmem(AVRPART * p); -int avr_verify(struct avrpart * p, struct avrpart * v, int memtype, +int avr_verify(AVRPART * p, AVRPART * v, int memtype, int size); -void avr_display(FILE * f, struct avrpart * p, char * prefix); +void avr_display(FILE * f, AVRPART * p, char * prefix); #endif diff --git a/avrdude.conf.sample b/avrdude.conf.sample index afa63de1..4e0000f3 100644 --- a/avrdude.conf.sample +++ b/avrdude.conf.sample @@ -1,27 +1,310 @@ # $Id$ # -# Programmer Pin Configurations +# AVRPROG Configuration File # -# The format of these entries is as follows: -# c::[desc=:][[=:]...] +# This file contains configuration data used by AVRPROG which describes +# the programming hardware pinouts and also provides part definitions. +# AVRPROG's "-C" command line option specifies the location of the +# configuration file. The "-c" option names the programmer confiuration +# which must match one of the entry's "id" parameter. The "-p" option +# identifies which part AVRPROG is going to be programming and must match +# one of the parts' "id" parameter. # -# Example: for a programmer called PGM-1 that uses pin 2 and 3 for -# power, pins 4, 5, and 6 for RESET, SCK, and MOSI, and pin 10 for -# MISO, we could use the following entry: +# Possible entry formats are: # -# c:pgm-1 : desc=Programmer 1:vcc=2,3:reset=4:sck=5:mosi=6:miso=10 +# programmer +# id = [, [, ] ...] ; # are quoted strings +# desc = ; # quoted string +# vcc = [, ... ] ; # pin number +# reset = ; # pin number +# sck = ; # pin number +# mosi = ; # pin number +# miso = ; # pin number +# errled = ; # pin number +# rdyled = ; # pin number +# pgmled = ; # pin number +# vfyled = ; # pin number +# ; # -# Continuation lines are supported, use a backslash (\) as the last -# character of the line and the next line will included as part of the -# configuration data. +# part +# id = ; # quoted string +# desc = ; # quoted string +# chip_erase_delay = ; # micro-seconds +# eeprom +# banked = ; # yes / no +# size = ; # bytes +# bank_size = ; # bytes +# num_banks = ; # numeric +# min_write_delay = ; # micro-seconds +# max_write_delay = ; # micro-seconds +# readback_p1 = ; # byte value +# readback_p2 = ; # byte value +# ; +# flash +# banked = ; # yes / no +# size = ; # bytes +# bank_size = ; # bytes +# num_banks = ; # numeric +# min_write_delay = ; # micro-seconds +# max_write_delay = ; # micro-seconds +# readback_p1 = ; # byte value +# readback_p2 = ; # byte value +# ; +# ; +# +# If any of the above parameters is not specified, the default value of +# 0 is used for numerics or the empty string ("") for string values. +# If a required parameter is left empty, AVRPROG will complain. +# +# See below for some examples. # -c:bsd : desc=Brian Dean's programmer:vcc=2,3,4,5:reset=7:sck=8:\ - mosi=9:miso=10 +programmer + id = "bsd", "default"; + desc = "Brian Dean's Programmer"; + vcc = 2, 3, 4, 5; + reset = 7; + sck = 8; + mosi = 9; + miso = 10; +; -c:dt006 : desc=Dontronics DT006:reset=4:sck=5:mosi=2:miso=11 +programmer + id = "dt006"; + desc = "Dontronics DT006"; + reset = 4; + sck = 8; + mosi = 9; + miso = 10; +; -c:alf : desc=Tony Freibel's programmer:vcc=2,3,4,5:buff=6:\ - reset=7:sck=8:mosi=9:miso=10:errled=1:rdyled=14:pgmled=16:\ - vfyled=17 +programmer + id = "alf"; + desc = "Tony Friebel's Programmer"; + vcc = 2, 3, 4, 5; + buff = 6; + reset = 7; + sck = 8; + mosi = 9; + miso = 10; + errled = 1; + rdyled = 14; + pgmled = 16; + vfyled = 17; +; + + +part + id = "1200"; + desc = "AT90S1200"; + chip_erase_delay = 20000; + eeprom + banked = no; + size = 64; + bank_size = 0; + num_banks = 0; + min_write_delay = 9000; + max_write_delay = 20000; + readback_p1 = 0x00; + readback_p2 = 0xff; + ; + flash + banked = no; + size = 1024; + bank_size = 0; + num_banks = 0; + min_write_delay = 9000; + max_write_delay = 20000; + readback_p1 = 0xff; + readback_p2 = 0x00; + ; + ; + +part + id = "2313"; + desc = "AT90S2313"; + chip_erase_delay = 20000; + eeprom + banked = no; + size = 128; + bank_size = 0; + num_banks = 0; + min_write_delay = 9000; + max_write_delay = 20000; + readback_p1 = 0x80; + readback_p2 = 0x7f; + ; + flash + banked = no; + size = 2048; + bank_size = 0; + num_banks = 0; + min_write_delay = 9000; + max_write_delay = 20000; + readback_p1 = 0x7f; + readback_p2 = 0x00; + ; + ; + + +part + id = "2333"; + desc = "AT90S2333"; + chip_erase_delay = 20000; + eeprom + banked = no; + size = 128; + bank_size = 0; + num_banks = 0; + min_write_delay = 9000; + max_write_delay = 20000; + readback_p1 = 0x00; + readback_p2 = 0xff; + ; + flash + banked = no; + size = 2048; + bank_size = 0; + num_banks = 0; + min_write_delay = 9000; + max_write_delay = 20000; + readback_p1 = 0xff; + readback_p2 = 0x00; + ; + ; + + +part + id = "4433"; + desc = "AT90S4433"; + chip_erase_delay = 20000; + eeprom + banked = no; + size = 256; + bank_size = 0; + num_banks = 0; + min_write_delay = 9000; + max_write_delay = 20000; + readback_p1 = 0x00; + readback_p2 = 0xff; + ; + flash + banked = no; + size = 4096; + bank_size = 0; + num_banks = 0; + min_write_delay = 9000; + max_write_delay = 20000; + readback_p1 = 0xff; + readback_p2 = 0x00; + ; + ; + + +part + id = "4434"; + desc = "AT90S4434"; + chip_erase_delay = 20000; + eeprom + banked = no; + size = 256; + bank_size = 0; + num_banks = 0; + min_write_delay = 9000; + max_write_delay = 20000; + readback_p1 = 0x00; + readback_p2 = 0xff; + ; + flash + banked = no; + size = 4096; + bank_size = 0; + num_banks = 0; + min_write_delay = 9000; + max_write_delay = 20000; + readback_p1 = 0xff; + readback_p2 = 0x00; + ; + ; + + +part + id = "8515"; + desc = "AT90S8515"; + chip_erase_delay = 20000; + eeprom + banked = no; + size = 512; + bank_size = 0; + num_banks = 0; + min_write_delay = 9000; + max_write_delay = 20000; + readback_p1 = 0x80; + readback_p2 = 0x7f; + ; + flash + banked = no; + size = 8192; + bank_size = 0; + num_banks = 0; + min_write_delay = 9000; + max_write_delay = 20000; + readback_p1 = 0x7f; + readback_p2 = 0x00; + ; + ; + + +part + id = "8535"; + desc = "AT90S8535"; + chip_erase_delay = 20000; + eeprom + banked = no; + size = 512; + bank_size = 0; + num_banks = 0; + min_write_delay = 9000; + max_write_delay = 20000; + readback_p1 = 0x00; + readback_p2 = 0xff; + ; + flash + banked = no; + size = 8192; + bank_size = 0; + num_banks = 0; + min_write_delay = 9000; + max_write_delay = 20000; + readback_p1 = 0xff; + readback_p2 = 0x00; + ; + ; + + +part + id = "103"; + desc = "ATMEGA103"; + chip_erase_delay = 112000; + eeprom + banked = no; + size = 4096; + bank_size = 0; + num_banks = 0; + min_write_delay = 4000; + max_write_delay = 9000; + readback_p1 = 0x00; + readback_p2 = 0xff; + ; + flash + banked = yes; + size = 131072; + bank_size = 256; + num_banks = 512; + min_write_delay = 22000; + max_write_delay = 56000; + readback_p1 = 0xff; + readback_p2 = 0x00; + ; + ; diff --git a/config.c b/config.c new file mode 100644 index 00000000..5b259c2f --- /dev/null +++ b/config.c @@ -0,0 +1,283 @@ +/* $Id$ */ + +#include +#include +#include +#include + +#include "avr.h" +#include "config.h" +#include "y.tab.h" + +char string_buf[MAX_STR_CONST]; +char *string_buf_ptr; + +LISTID string_list; +LISTID number_list; +PROGRAMMER * current_prog; +AVRPART * current_part; +int current_mem; +LISTID part_list; +LISTID programmers; + +int lineno = 0; +char * infile = NULL; + +#define DEBUG 0 + +char * config_version = "$Id$"; + + +int init_config(void) +{ + string_list = lcreat(NULL, 0); + number_list = lcreat(NULL, 0); + current_prog = NULL; + current_part = NULL; + current_mem = 0; + part_list = lcreat(NULL, 0); + programmers = lcreat(NULL, 0); + + lineno = 1; + infile = NULL; + + return 0; +} + + + +int yywrap() +{ + return 1; +} + + +int yyerror(char * errmsg) +{ + fprintf(stderr, "%s at %s:%d\n", errmsg, infile, lineno); + exit(1); +} + + +TOKEN * new_token(int primary) +{ + TOKEN * tkn; + + tkn = (TOKEN *)malloc(sizeof(TOKEN)); + if (tkn == NULL) { + fprintf(stderr, "new_token(): out of memory\n"); + exit(1); + } + + memset(tkn, 0, sizeof(TOKEN)); + + tkn->primary = primary; + + return tkn; +} + + +void free_token(TOKEN * tkn) +{ + if (tkn) { + switch (tkn->primary) { + case TKN_STRING: + case TKN_ID: + if (tkn->value.string) + free(tkn->value.string); + tkn->value.string = NULL; + break; + } + + free(tkn); + } +} + + +void free_tokens(int n, ...) +{ + TOKEN * t; + va_list ap; + + va_start(ap, n); + while (n--) { + t = va_arg(ap, TOKEN *); + free_token(t); + } + va_end(ap); +} + + + +TOKEN * number(char * text) +{ + struct token_t * tkn; + + tkn = new_token(TKN_NUMBER); + tkn->value.type = V_NUM; + tkn->value.number = atof(text); + +#if DEBUG + fprintf(stderr, "NUMBER(%g)\n", tkn->value.number); +#endif + + return tkn; +} + + +TOKEN * hexnumber(char * text) +{ + struct token_t * tkn; + char * e; + + tkn = new_token(TKN_NUMBER); + tkn->value.type = V_NUM; + tkn->value.number = strtoul(text, &e, 16); + if ((e == text) || (*e != 0)) { + fprintf(stderr, "error at %s:%d: can't scan hex number \"%s\"\n", + infile, lineno, text); + exit(1); + } + +#if DEBUG + fprintf(stderr, "HEXNUMBER(%g)\n", tkn->value.number); +#endif + + return tkn; +} + + +TOKEN * string(char * text) +{ + struct token_t * tkn; + int len; + + tkn = new_token(TKN_STRING); + + len = strlen(text); + + tkn->value.type = V_STR; + tkn->value.string = (char *) malloc(len+1); + if (tkn->value.string == NULL) { + fprintf(stderr, "id(): out of memory\n"); + exit(1); + } + strcpy(tkn->value.string, text); + +#if DEBUG + fprintf(stderr, "STRING(%s)\n", tkn->value.string); +#endif + + return tkn; +} + + +TOKEN * id(char * text) +{ + struct token_t * tkn; + int len; + + tkn = new_token(TKN_ID); + + len = strlen(text); + + tkn->value.type = V_STR; + tkn->value.string = (char *) malloc(len+1); + if (tkn->value.string == NULL) { + fprintf(stderr, "id(): out of memory\n"); + exit(1); + } + strcpy(tkn->value.string, text); + +#if DEBUG + fprintf(stderr, "ID(%s)\n", tkn->value.string); +#endif + + return tkn; +} + + +TOKEN * keyword(int primary) +{ + struct token_t * tkn; + + tkn = new_token(primary); + + return tkn; +} + + +void print_token(TOKEN * tkn) +{ + if (!tkn) + return; + + fprintf(stderr, "token = %d = ", tkn->primary); + switch (tkn->primary) { + case TKN_NUMBER: + fprintf(stderr, "NUMBER, value=%g", tkn->value.number); + break; + + case TKN_STRING: + fprintf(stderr, "STRING, value=%s", tkn->value.string); + break; + + case TKN_ID: + fprintf(stderr, "ID, value=%s", tkn->value.string); + break; + + default: + fprintf(stderr, ""); + break; + } + + fprintf(stderr, "\n"); +} + + +void pyytext(void) +{ +#if DEBUG + extern char * yytext; + + fprintf(stderr, "TOKEN: \"%s\"\n", yytext); +#endif +} + + +PROGRAMMER * new_programmer(void) +{ + PROGRAMMER * p; + int i; + + p = (PROGRAMMER *)malloc(sizeof(PROGRAMMER)); + if (p == NULL) { + fprintf(stderr, "new_programmer(): out of memory\n"); + exit(1); + } + + memset(p, 0, sizeof(*p)); + + p->id = lcreat(NULL, 0); + p->desc[0] = 0; + + for (i=0; ipinno[i] = 0; + + return p; +} + + +char * dup_string(char * str) +{ + char * s; + + s = strdup(str); + if (s == NULL) { + fprintf(stderr, "dup_string(): out of memory\n"); + exit(1); + } + + return s; +} + diff --git a/config.h b/config.h new file mode 100644 index 00000000..256cc322 --- /dev/null +++ b/config.h @@ -0,0 +1,84 @@ +/* $Id$ */ + +#ifndef __config_h__ +#define __config_h__ + +#include "lists.h" +#include "pindefs.h" +#include "avr.h" + + +#define MAX_STR_CONST 1024 + +enum { V_NONE, V_NUM, V_STR }; +typedef struct value_t { + int type; + double number; + char * string; +} VALUE; + + +typedef struct token_t { + int primary; + VALUE value; +} TOKEN; + + +#define PGM_DESCLEN 80 +typedef struct programmer_t { + LISTID id; + char desc[PGM_DESCLEN]; + unsigned int pinno[N_PINS]; +} PROGRAMMER; + +extern FILE * yyin; +extern PROGRAMMER * current_prog; +extern AVRPART * current_part; +extern int current_mem; +extern LISTID programmers; +extern LISTID part_list; +extern int lineno; +extern char * infile; +extern LISTID string_list; +extern LISTID number_list; + +#if 0 +#define YYSTYPE struct token_t * +#endif +extern YYSTYPE yylval; + +extern char string_buf[MAX_STR_CONST]; +extern char *string_buf_ptr; + +int yyparse(void); + + +int init_config(void); + +TOKEN * new_token(int primary); + +void free_token(TOKEN * tkn); + +void free_tokens(int n, ...); + +TOKEN * number(char * text); + +TOKEN * hexnumber(char * text); + +TOKEN * string(char * text); + +TOKEN * id(char * text); + +TOKEN * keyword(int primary); + +void print_token(TOKEN * tkn); + +PROGRAMMER * new_programmer(void); + +AVRPART * new_part(void); + +AVRPART * dup_part(AVRPART * d); + +char * dup_string(char * str); + +#endif diff --git a/config_gram.y b/config_gram.y new file mode 100644 index 00000000..f32d10f0 --- /dev/null +++ b/config_gram.y @@ -0,0 +1,307 @@ +/* $Id$ */ + +%token K_BANK_SIZE +%token K_BANKED +%token K_BUFF +%token K_CHIP_ERASE_DELAY +%token K_DESC +%token K_EEPROM +%token K_ERRLED +%token K_FLASH +%token K_ID +%token K_MAX_WRITE_DELAY +%token K_MIN_WRITE_DELAY +%token K_MISO +%token K_MOSI +%token K_NO +%token K_NUM_BANKS +%token K_PART +%token K_PGMLED +%token K_PROGRAMMER +%token K_RDYLED +%token K_READBACK_P1 +%token K_READBACK_P2 +%token K_RESET +%token K_SCK +%token K_SIZE +%token K_VCC +%token K_VFYLED +%token K_YES + +%token TKN_COMMA +%token TKN_EQUAL +%token TKN_SEMI +%token TKN_NUMBER +%token TKN_STRING +%token TKN_ID + +%start config + +%% + + +config : + def | + config def +; + + +def : + prog_def TKN_SEMI | + part_def TKN_SEMI +; + + +prog_def : + K_PROGRAMMER + { current_prog = new_programmer(); } + prog_parms + { + if (lsize(current_prog->id) == 0) { + fprintf(stderr, + "%s: error at %s:%d: required parameter id not specified\n", + progname, infile, lineno); + exit(1); + } + ladd(programmers, current_prog); + current_prog = NULL; + } +; + + +part_def : + K_PART + { current_part = avr_new_part(); } + part_parms + { + if (current_part->id[0] == 0) { + fprintf(stderr, + "%s: error at %s:%d: required parameter id not specified\n", + progname, infile, lineno); + exit(1); + } + ladd(part_list, current_part); + current_part = NULL; + } +; + + +string_list : + TKN_STRING { ladd(string_list, $1); } | + string_list TKN_COMMA TKN_STRING { ladd(string_list, $3); } +; + + +num_list : + TKN_NUMBER { ladd(number_list, $1); } | + num_list TKN_COMMA TKN_NUMBER { ladd(number_list, $3); } +; + + +prog_parms : + prog_parm TKN_SEMI | + prog_parms prog_parm TKN_SEMI +; + + +prog_parm : + K_ID TKN_EQUAL string_list { + { + TOKEN * t; + while (lsize(string_list)) { + t = lrmv_n(string_list, 1); + ladd(current_prog->id, dup_string(t->value.string)); + free_token(t); + } + } + } | + + K_DESC TKN_EQUAL TKN_STRING { + strncpy(current_prog->desc, $3->value.string, PGM_DESCLEN); + current_prog->desc[PGM_DESCLEN-1] = 0; + free_token($3); + } | + + K_VCC TKN_EQUAL num_list { + { + TOKEN * t; + int pin; + + current_prog->pinno[PPI_AVR_VCC] = 0; + + while (lsize(number_list)) { + t = lrmv_n(number_list, 1); + pin = t->value.number; + if ((pin < 2) || (pin > 9)) { + fprintf(stderr, + "%s: error at line %d of %s: VCC must be one or more " + "pins from the range 2-9\n", + progname, lineno, infile); + exit(1); + } + + current_prog->pinno[PPI_AVR_VCC] |= (1 << (pin-2)); + + free_token(t); + } + } + } | + + K_RESET TKN_EQUAL TKN_NUMBER { assign_pin(PIN_AVR_RESET, $3); } | + K_SCK TKN_EQUAL TKN_NUMBER { assign_pin(PIN_AVR_SCK, $3); } | + K_MOSI TKN_EQUAL TKN_NUMBER { assign_pin(PIN_AVR_MOSI, $3); } | + K_MISO TKN_EQUAL TKN_NUMBER { assign_pin(PIN_AVR_MISO, $3); } | + K_BUFF TKN_EQUAL TKN_NUMBER { assign_pin(PIN_AVR_BUFF, $3); } | + K_ERRLED TKN_EQUAL TKN_NUMBER { assign_pin(PIN_LED_ERR, $3); } | + K_RDYLED TKN_EQUAL TKN_NUMBER { assign_pin(PIN_LED_RDY, $3); } | + K_PGMLED TKN_EQUAL TKN_NUMBER { assign_pin(PIN_LED_PGM, $3); } | + K_VFYLED TKN_EQUAL TKN_NUMBER { assign_pin(PIN_LED_VFY, $3); } +; + + +part_parms : + part_parm TKN_SEMI | + part_parms part_parm TKN_SEMI +; + + +part_parm : + K_ID TKN_EQUAL TKN_STRING + { + strncpy(current_part->id, $3->value.string, AVR_IDLEN); + current_part->id[AVR_IDLEN-1] = 0; + free_token($3); + } | + + K_DESC TKN_EQUAL TKN_STRING + { + strncpy(current_part->desc, $3->value.string, AVR_DESCLEN); + current_part->desc[AVR_DESCLEN-1] = 0; + free_token($3); + } | + + K_CHIP_ERASE_DELAY TKN_EQUAL TKN_NUMBER + { + current_part->chip_erase_delay = $3->value.number; + free_token($3); + } | + + K_EEPROM { current_mem = AVR_M_EEPROM; } + mem_specs | + + K_FLASH { current_mem = AVR_M_FLASH; } + mem_specs +; + + +yesno : + K_YES | K_NO +; + + +mem_specs : + mem_spec TKN_SEMI | + mem_specs mem_spec TKN_SEMI +; + + +mem_spec : + K_BANKED TKN_EQUAL yesno + { + current_part->mem[current_mem].banked = $3->primary == K_YES ? 1 : 0; + free_token($3); + } | + + K_SIZE TKN_EQUAL TKN_NUMBER + { + current_part->mem[current_mem].size = $3->value.number; + free_token($3); + } | + + + K_BANK_SIZE TKN_EQUAL TKN_NUMBER + { + current_part->mem[current_mem].bank_size = $3->value.number; + free_token($3); + } | + + K_NUM_BANKS TKN_EQUAL TKN_NUMBER + { + current_part->mem[current_mem].num_banks = $3->value.number; + free_token($3); + } | + + K_MIN_WRITE_DELAY TKN_EQUAL TKN_NUMBER + { + current_part->mem[current_mem].min_write_delay = $3->value.number; + free_token($3); + } | + + K_MAX_WRITE_DELAY TKN_EQUAL TKN_NUMBER + { + current_part->mem[current_mem].max_write_delay = $3->value.number; + free_token($3); + } | + + K_READBACK_P1 TKN_EQUAL TKN_NUMBER + { + current_part->mem[current_mem].readback[0] = $3->value.number; + free_token($3); + } | + + K_READBACK_P2 TKN_EQUAL TKN_NUMBER + { + current_part->mem[current_mem].readback[1] = $3->value.number; + free_token($3); + } +; + + +%% + +#include +#include + +#include "config.h" +#include "lists.h" +#include "pindefs.h" +#include "avr.h" + +extern char * progname; + +int yylex(void); +int yyerror(char * errmsg); + + +#if 0 +static char * vtypestr(int type) +{ + switch (type) { + case V_NUM : return "NUMERIC"; + case V_STR : return "STRING"; + default: + return ""; + } +} +#endif + + +static int assign_pin(int pinno, TOKEN * v) +{ + int value; + + value = v->value.number; + + if ((value <= 0) || (value >= 18)) { + fprintf(stderr, + "%s: error at line %d of %s: pin must be in the " + "range 1-17\n", + progname, lineno, infile); + exit(1); + } + + current_prog->pinno[pinno] = value; + + return 0; +} + diff --git a/lexer.l b/lexer.l new file mode 100644 index 00000000..60e75a20 --- /dev/null +++ b/lexer.l @@ -0,0 +1,137 @@ +/* $Id$ */ + +%{ +/* need this for the call to atof() below */ +#include +#include +#include +#include +#include +#include + +#include "config.h" +#include "y.tab.h" +#include "lists.h" + +extern int lineno; +extern char * infile; + +void pyytext(void); + +%} + +DIGIT [0-9] +HEXDIGIT [0-9a-fA-F] +ID [_a-zA-Z][_a-zA-Z0-9]* +SIGN [+-] + +%x str +%x incl +%x comment + +%% + +{SIGN}*{DIGIT}+ { yylval = number(yytext); return TKN_NUMBER; } +{SIGN}*{DIGIT}+"."{DIGIT}* { yylval = number(yytext); return TKN_NUMBER; } +{SIGN}*"."{DIGIT}* { yylval = number(yytext); return TKN_NUMBER; } + +"\"" { string_buf_ptr = string_buf; BEGIN(str); } + +0x{HEXDIGIT}+ { yylval = hexnumber(yytext); return TKN_NUMBER; } + + + +# { /* The following eats '#' style comments to end of line */ + BEGIN(comment); } +[^\n] /* eat comments */ +\n { lineno++; BEGIN(INITIAL); } + + +"/*" { /* The following eats multiline C style comments */ + int c; + int comment_start; + + comment_start = lineno; + while (1) { + while (((c = input()) != '*') && (c != EOF)) { + /* eat up text of comment, but keep counting lines */ + if (c == '\n') + lineno++; + } + + if (c == '*') { + while ((c = input()) == '*') + ; + if (c == '/') + break; /* found the end */ + } + + if (c == EOF) { + fprintf(stderr, "error at %s:%d: EOF in comment\n", + infile, lineno); + fprintf(stderr, " comment started on line %d\n", + comment_start); + exit(1); + break; + } + } + } + + +{ + \" { *string_buf_ptr = 0; string_buf_ptr = string_buf; + yylval = string(string_buf_ptr); BEGIN(INITIAL); return TKN_STRING; } + \\n *string_buf_ptr++ = '\n'; + \\t *string_buf_ptr++ = '\t'; + \\r *string_buf_ptr++ = '\r'; + \\b *string_buf_ptr++ = '\b'; + \\f *string_buf_ptr++ = '\f'; + \\(.|\n) *(string_buf_ptr++) = yytext[1]; + [^\\\n\"]+ { char *yptr = yytext; while (*yptr) + *(string_buf_ptr++) = *(yptr++); } + \n { fprintf(stderr, "error at line %d: unterminated character constant\n", + lineno); + exit(1); } +} + +bank_size { yylval=NULL; return K_BANK_SIZE; } +banked { yylval=NULL; return K_BANKED; } +buff { yylval=NULL; return K_BUFF; } +chip_erase_delay { yylval=NULL; return K_CHIP_ERASE_DELAY; } +desc { yylval=NULL; return K_DESC; } +eeprom { yylval=NULL; return K_EEPROM; } +errled { yylval=NULL; return K_ERRLED; } +flash { yylval=NULL; return K_FLASH; } +id { yylval=NULL; return K_ID; } +max_write_delay { yylval=NULL; return K_MAX_WRITE_DELAY; } +min_write_delay { yylval=NULL; return K_MIN_WRITE_DELAY; } +miso { yylval=NULL; return K_MISO; } +mosi { yylval=NULL; return K_MOSI; } +num_banks { yylval=NULL; return K_NUM_BANKS; } +part { yylval=NULL; return K_PART; } +pgmled { yylval=NULL; return K_PGMLED; } +programmer { yylval=NULL; return K_PROGRAMMER; } +rdyled { yylval=NULL; return K_RDYLED; } +readback_p1 { yylval=NULL; return K_READBACK_P1; } +readback_p2 { yylval=NULL; return K_READBACK_P2; } +reset { yylval=NULL; return K_RESET; } +sck { yylval=NULL; return K_SCK; } +size { yylval=NULL; return K_SIZE; } +vcc { yylval=NULL; return K_VCC; } +vfyled { yylval=NULL; return K_VFYLED; } + +no { yylval=new_token(K_NO); return K_NO; } +yes { yylval=new_token(K_YES); return K_YES; } + +"," { yylval = NULL; pyytext(); return TKN_COMMA; } +"=" { yylval = NULL; pyytext(); return TKN_EQUAL; } +";" { yylval = NULL; pyytext(); return TKN_SEMI; } + +"\n" { lineno++; } +[ \t]+ /* ignore whitespace */ + +. { fprintf(stderr, "error at %s:%d unrecognized character: \"%s\"\n", + infile, lineno, yytext); exit(1); } + +%% + diff --git a/lists.c b/lists.c new file mode 100644 index 00000000..b355096b --- /dev/null +++ b/lists.c @@ -0,0 +1,1355 @@ + /* $Id$ */ + + +/*---------------------------------------------------------------------- + Id: lists.c,v 1.4 2001/08/19 23:26:20 bsd Exp $ + ----------------------------------------------------------------------*/ +/*------------------------------------------------------------------------ + lists.c + + General purpose linked list routines. These routines implement a + generic doubly linked list. Any data type may be placed in the + lists. Stacking and Queuing routines are provided via #defines + declared in 'lists.h'. + + Author : Brian Dean + Date : 10 January, 1990 + ------------------------------------------------------------------------*/ +#include +#include + +#include "lists.h" + +char * lists_version = "$Id$"; + +#define MAGIC 0xb05b05b0 + +#define CHECK_MAGIC 0 /* set to 1 to enable memory overwrite detection */ + +#ifdef BOS +#define MALLOC(size,x) kmalloc(size,x) +#define FREE kfree +#else +#define MALLOC(size,x) malloc(size) +#define FREE free +#endif + + +/*------------------------------------------------------------ +| required private data structures + ------------------------------------------------------------*/ +typedef struct LISTNODE { +#if CHECK_MAGIC + unsigned int magic1; +#endif + struct LISTNODE * next; /* chain to next item in the list */ + struct LISTNODE * prev; /* chain to previous item in the list */ + void * data; /* pointer to user data */ +#if CHECK_MAGIC + unsigned int magic2; +#endif +} LISTNODE; + + +typedef struct NODEPOOL { +#if CHECK_MAGIC + unsigned int magic1; +#endif + struct NODEPOOL * chain_next; /* chain to next node pool */ + struct NODEPOOL * chain_prev; /* chain to previous node pool */ +#if CHECK_MAGIC + unsigned int magic2; +#endif +} NODEPOOL; + + +typedef struct LIST { +#if CHECK_MAGIC + unsigned int magic1; +#endif + int num; /* number of elements in the list */ + short int free_on_close; /* free the LIST memory on close T/F */ + short int poolsize; /* list node allocation size */ + int n_ln_pool; /* number of listnodes in a pool */ + LISTNODE * top; /* top of the list */ + LISTNODE * bottom; /* bottom of the list */ + LISTNODE * next_ln; /* next available list node */ + NODEPOOL * np_top; /* top of the node pool chain */ + NODEPOOL * np_bottom; /* bottom of the node pool chain */ +#if CHECK_MAGIC + unsigned int magic2; +#endif +} LIST; + + +/* allocate list nodes in 512 byte chunks, giving 42 elements */ +#define DEFAULT_POOLSIZE 512 + + +#if CHECK_MAGIC +#define CKMAGIC(p) { if (p->magic1 != MAGIC) breakpoint(); \ + if (p->magic2 != MAGIC) breakpoint(); } + +#define CKNPMAGIC(p) cknpmagic(p) + +#define CKLNMAGIC(p) cklnmagic(p) + +#define CKLMAGIC(p) cklmagic(p) +#else +#define CKMAGIC(p) + +#define CKNPMAGIC(p) + +#define CKLNMAGIC(p) + +#define CKLMAGIC(p) +#endif + + +static int insert_ln ( LIST * l, LISTNODE * ln, void * data_ptr ); + + +#if CHECK_MAGIC +static int cknpmagic ( LIST * l ) +{ + NODEPOOL * np; + int i; + + i = 0; + np = l->np_top; + while (np) { + i++; + CKMAGIC(np); + np = np->chain_next; + } + + i = 0; + np = l->np_bottom; + while (np) { + i++; + CKMAGIC(np); + np = np->chain_prev; + } + + return 0; +} + + + +static int cklnmagic ( LIST * l ) +{ + LISTNODE * ln; + int i; + + i = 0; + ln = l->top; + while (ln) { + i++; + CKMAGIC(ln); + ln = ln->next; + } + + i = 0; + ln = l->bottom; + while (ln) { + i++; + CKMAGIC(ln); + ln = ln->prev; + } + + return 0; +} + + +static int cklmagic ( LIST * l ) +{ + CKMAGIC(l); + CKNPMAGIC(l); + CKLNMAGIC(l); + CKMAGIC(l); + return 0; +} +#endif + + +/*------------------------------------------------------------ +| new_node_pool +| +| Create and initialize a new pool of list nodes. This is +| just a big block of memory with the first sizeof(NODEPOOL) +| bytes reserved. The first available list node resides at +| offset sizeof(NODEPOOL). + ------------------------------------------------------------*/ +static +NODEPOOL * +new_nodepool ( LIST * l ) +{ + NODEPOOL * np; + LISTNODE * ln; + int i; + + CKLMAGIC(l); + + /*-------------------------------------------------- + | get a block of memory for the new pool + --------------------------------------------------*/ + np = (NODEPOOL *) MALLOC ( l->poolsize, "list node pool" ); + if (np == NULL) { + return NULL; + } + + /*-------------------------------------------------- + | initialize the chaining information at the + | beginning of the pool. + --------------------------------------------------*/ +#if CHECK_MAGIC + np->magic1 = MAGIC; +#endif + np->chain_next = NULL; + np->chain_prev = NULL; +#if CHECK_MAGIC + np->magic2 = MAGIC; +#endif + + /*-------------------------------------------------- + | initialize all the list nodes within the node + | pool, which begin just after the NODEPOOL + | structure at the beginning of the memory block + --------------------------------------------------*/ + ln = (LISTNODE *) (&np[1]); + +#if CHECK_MAGIC + ln[0].magic1 = MAGIC; +#endif + ln[0].data = NULL; + ln[0].next = &ln[1]; + ln[0].prev = NULL; +#if CHECK_MAGIC + ln[0].magic2 = MAGIC; +#endif + + for (i=1; in_ln_pool-1; i++) { +#if CHECK_MAGIC + ln[i].magic1 = MAGIC; +#endif + ln[i].data = NULL; + ln[i].next = &ln[i+1]; + ln[i].prev = &ln[i-1]; +#if CHECK_MAGIC + ln[i].magic2 = MAGIC; +#endif + } + +#if CHECK_MAGIC + ln[l->n_ln_pool-1].magic1 = MAGIC; +#endif + ln[l->n_ln_pool-1].data = NULL; + ln[l->n_ln_pool-1].next = NULL; + ln[l->n_ln_pool-1].prev = &ln[l->n_ln_pool-2]; +#if CHECK_MAGIC + ln[l->n_ln_pool-1].magic2 = MAGIC; +#endif + + CKMAGIC(np); + + CKLMAGIC(l); + + return np; +} + + + +/*------------------------------------------------------------ +| get_listnode +| +| Get the next available list node. If there are no more +| list nodes, another pool of list nodes is allocated. If +| that fails, NULL is returned. + ------------------------------------------------------------*/ +static +LISTNODE * +get_listnode ( LIST * l ) +{ + LISTNODE * ln; + NODEPOOL * np; + + CKLMAGIC(l); + + if (l->next_ln == NULL) { + /*-------------------------------------------------- + | allocate a new node pool and chain to the others + --------------------------------------------------*/ + np = new_nodepool(l); + if (np == NULL) { + CKLMAGIC(l); + return NULL; + } + + if (l->np_top == NULL) { + /*-------------------------------------------------- + | this is the first node pool for this list, + | directly assign to the top and bottom. + --------------------------------------------------*/ + l->np_top = np; + l->np_bottom = np; + np->chain_next = NULL; + np->chain_prev = NULL; + } + else { + /*-------------------------------------------------- + | this is an additional node pool, add it to the + | chain. + --------------------------------------------------*/ + np->chain_next = NULL; + np->chain_prev = l->np_bottom; + l->np_bottom->chain_next = np; + l->np_bottom = np; + } + + /*-------------------------------------------------- + | set the list's pointer to the next available + | list node to the first list node in this new + | pool. + --------------------------------------------------*/ + l->next_ln = (LISTNODE *)&np[1]; + + CKMAGIC(np); + } + + /*-------------------------------------------------- + | get the next available list node, set the list's + | next available list node to the next one in the + | list. + --------------------------------------------------*/ + ln = l->next_ln; + l->next_ln = ln->next; + + CKMAGIC(ln); + + /*-------------------------------------------------- + | initialize the new list node and return + --------------------------------------------------*/ + ln->next = NULL; + ln->prev = NULL; + ln->data = NULL; + + CKLMAGIC(l); + + return ln; +} + + + +/*------------------------------------------------------------ +| free_listnode +| +| Return a list node to the pool of list nodes. This puts +| the node at the head of the free list, so that the next +| call to 'get_listnode', with return the most recently +| freed one. + ------------------------------------------------------------*/ +static +int +free_listnode ( LIST * l, LISTNODE * ln ) +{ + CKLMAGIC(l); + + /*-------------------------------------------------- + | insert the list node at the head of the list of + | free list nodes. + --------------------------------------------------*/ + ln->prev = NULL; + ln->data = NULL; + ln->next = l->next_ln; + l->next_ln = ln; + + CKLMAGIC(l); + + return 0; +} + + + +/*---------------------------------------------------------------------- + lcreat + + Create a new list data structure. + + If liststruct is not NULL, it is used to provide the memory space + for the list structure instance, otherwise, the necessary memory is + malloc'd. + + If elements is zero, the default poolsize is used, otherwise, + poolsizes of 'elements' elements are malloc'd to obtain the memory + for list nodes. Minimum element count is 5. + + The first node pool is not preallocated; instead it is malloc'd at + the time of the first use. + ----------------------------------------------------------------------*/ +LISTID +lcreat ( void * liststruct, int elements ) +{ + LIST * l; + + if (LISTSZ != sizeof(LIST)) { + printf ( "lcreat(): warning, LISTSZ[%d] != sizeof(LIST)[%d]\n", + LISTSZ, sizeof(LIST) ); + } + + if (liststruct == NULL) { + /*-------------------------------------------------- + allocate memory for the list itself + --------------------------------------------------*/ + l = (LIST *) MALLOC ( sizeof(LIST), "list struct" ); + if (l == NULL) { + return NULL; + } + l->free_on_close = 1; + } + else { + /*----------------------------------------------------------------- + use the memory given to us for the list structure + -----------------------------------------------------------------*/ + l = liststruct; + l->free_on_close = 0; + } + + /*-------------------------------------------------- + | initialize the list + --------------------------------------------------*/ +#if CHECK_MAGIC + l->magic1 = MAGIC; + l->magic2 = MAGIC; +#endif + l->top = NULL; + l->bottom = NULL; + l->num = 0; + + if (elements == 0) { + l->poolsize = DEFAULT_POOLSIZE; + } + else { + l->poolsize = elements*sizeof(LISTNODE)+sizeof(NODEPOOL); + } + + l->n_ln_pool = (l->poolsize-sizeof(NODEPOOL))/sizeof(LISTNODE); + + if (l->n_ln_pool < 5) { + if (!liststruct) { + FREE(l); + } + return NULL; + } + + l->np_top = NULL; + l->np_bottom = NULL; + l->next_ln = NULL; + + CKLMAGIC(l); + + return (LISTID)l; +} + + +/*-------------------------------------------------- +| ldestroy_cb +| +| destroy an existing list data structure, calling +| the user routine 'ucleanup' on the data pointer +| of each list element. Allows the user to free +| up a list data structure and have this routine +| call their function to free up each list element +| at the same time. + --------------------------------------------------*/ +void +ldestroy_cb ( LISTID lid, void (*ucleanup)() ) +{ + LIST * l; + LISTNODE * ln; + + l = (LIST *)lid; + + CKLMAGIC(l); + + ln = l->top; + while (ln != NULL) { + ucleanup ( ln->data ); + ln = ln->next; + } + + ldestroy ( l ); +} + + + +/*-------------------------------------------------- +| ldestroy +| +| destroy an existing list data structure. +| +| assumes that each data element does not need to +| be freed. + --------------------------------------------------*/ +void +ldestroy ( LISTID lid ) +{ + LIST * l; + NODEPOOL * p1, * p2; + + l = (LIST *)lid; + + CKLMAGIC(l); + + /*-------------------------------------------------- + | free each node pool - start at the first node + | pool and free each successive until there are + | no more. + --------------------------------------------------*/ + p1 = l->np_top; + while (p1 != NULL) { + p2 = p1->chain_next; + FREE(p1); + p1 = p2; + } + + /*-------------------------------------------------- + | now free the memory occupied by the list itself + --------------------------------------------------*/ + if (l->free_on_close) { + FREE ( l ); + } +} + + + + +/*------------------------------------------------------------ +| ladd +| +| add list - add item p to the list + ------------------------------------------------------------*/ +int +ladd ( LISTID lid, void * p ) +{ + LIST * l; + LISTNODE *lnptr; + + l = (LIST *)lid; + + CKLMAGIC(l); + + lnptr = get_listnode(l); + if (lnptr==NULL) { +#ifdef BOS + breakpoint(); +#endif + return -1; + } + + CKMAGIC(lnptr); + + lnptr->data = p; + + if (l->top == NULL) { + l->top = lnptr; + l->bottom = lnptr; + lnptr->next = NULL; + lnptr->prev = NULL; + } + else { + lnptr->prev = l->bottom; + lnptr->next = NULL; + l->bottom->next = lnptr; + l->bottom = lnptr; + } + l->num++; + + CKLMAGIC(l); + + return 0; +} + + + +/*------------------------------------------------------------ +| laddo +| +| add list, ordered - add item p to the list, use 'compare' +| function to place 'p' when the comparison 'p' is less than +| the next item. Return 0 if this was a unique entry, +| else return 1 indicating a duplicate entry, i.e., the +| compare function returned 0 while inserting the element. + ------------------------------------------------------------*/ +int +laddo ( LISTID lid, void * p, int (*compare)(const void *p1,const void *p2), + LNODEID * firstdup ) +{ + LIST * l; + LISTNODE * ln; + int dup, cmp; + + l = (LIST *)lid; + + CKLMAGIC(l); + + dup = 0; + ln = l->top; + + while (ln!=NULL) { + CKMAGIC(ln); + cmp = compare(p,ln->data); + if (cmp == 0) { + dup = 1; + if (firstdup) + *firstdup = ln; + } + if (cmp < 0) { + insert_ln(l,ln,p); + CKLMAGIC(l); + return dup; + } + else { + ln = ln->next; + } + } + + ladd(l,p); + + CKLMAGIC(l); + + return dup; +} + + +/*--------------------------------------------------------------------------- +| laddu +| +| add list, ordered, unique - add item p to the list, use 'compare' +| function to place 'p' when the comparison 'p' is less than the next +| item. Return 1 if the item was added, 0 if not. +| + --------------------------------------------------------------------------*/ +int +laddu ( LISTID lid, void * p, int (*compare)(const void *p1,const void *p2) ) +{ + LIST * l; + LISTNODE * ln; + int cmp; + + l = (LIST *)lid; + + CKLMAGIC(l); + + ln = l->top; + + while (ln!=NULL) { + CKMAGIC(ln); + cmp = compare(p,ln->data); + if (cmp == 0) { + CKLMAGIC(l); + return 0; + } + if (cmp < 0) { + insert_ln(l,ln,p); + CKLMAGIC(l); + return 1; + } + else { + ln = ln->next; + } + } + + ladd(l,p); + + CKLMAGIC(l); + + return 1; +} + + + + +LNODEID +lfirst ( LISTID lid ) +{ + CKLMAGIC(((LIST *)lid)); + return ((LIST *)lid)->top; +} + + +LNODEID +llast ( LISTID lid ) +{ + CKLMAGIC(((LIST *)lid)); + return ((LIST *)lid)->bottom; +} + + +LNODEID +lnext ( LNODEID lnid ) +{ + CKMAGIC(((LISTNODE *)lnid)); + return ((LISTNODE *)lnid)->next; +} + + +LNODEID +lprev ( LNODEID lnid ) +{ + CKMAGIC(((LISTNODE *)lnid)); + return ((LISTNODE *)lnid)->prev; +} + + +void * +ldata ( LNODEID lnid ) +{ + CKMAGIC(((LISTNODE *)lnid)); + return ((LISTNODE *)lnid)->data; +} + + + +int +lsize ( LISTID lid ) +{ + CKLMAGIC(((LIST *)lid)); + return ((LIST *)lid)->num; +} + + + +/*------------------------------------------------------------ +| lcat +| +| catenate - catenate l2 to l1, return pointer to l1. + ------------------------------------------------------------*/ +LISTID +lcat ( LISTID lid1, LISTID lid2 ) +{ + CKLMAGIC(((LIST *)lid1)); + CKLMAGIC(((LIST *)lid2)); + while (lsize(lid2)) { + ladd ( lid1, lrmv_n(lid2,1) ); + } + + CKLMAGIC(((LIST *)lid1)); + CKLMAGIC(((LIST *)lid2)); + + return lid1; +} + + + +/*---------------------------------------------------------------------- +| lget +| +| get from list, last item - return pointer to the data of the last +| item in the list, non-destructive + ----------------------------------------------------------------------*/ +void * +lget ( LISTID lid ) +{ + LIST * l; + LISTNODE * p; + + l = (LIST *)lid; + + CKLMAGIC(l); + + p = l->bottom; + + if (p == NULL) { + CKLMAGIC(l); + return NULL; + } + else { + CKLMAGIC(l); + return p->data; + } +} + + + +/*--------------------------------------------------------------- +| lget_n +| +| get from list, index - return the nth list item, +| non-destructive + ---------------------------------------------------------------*/ +void * +lget_n ( LISTID lid, unsigned int n ) +{ + int i; + LIST * l; + LISTNODE * ln; + + l = (LIST *)lid; + + CKLMAGIC(l); + + if ((n<1)||(n>lsize(l))) { + return NULL; + } + + ln = l->top; + i = 1; + while (ln && (i!=n)) { + CKMAGIC(ln); + ln = ln->next; + i++; + } + + if (ln) { + CKLMAGIC(l); + return ln->data; + } + else { + CKLMAGIC(l); + return NULL; + } +} + + + +/*--------------------------------------------------------------- +| lget_ln +| +| get from list, listnode - return the nth list item, the +| listnode is returned instead of the data, non-destructive + ---------------------------------------------------------------*/ +LNODEID +lget_ln ( LISTID lid, unsigned int n ) +{ + int i; + LIST * l; + LISTNODE * ln; + + l = (LIST *)lid; + + CKLMAGIC(l); + + if ((n<1)||(n>lsize(l))) { + return NULL; + } + + ln = l->top; + i = 1; + while (i!=n) { + CKMAGIC(ln); + ln = ln->next; + i++; + } + + CKLMAGIC(l); + return (LNODEID)ln; +} + + + +/*---------------------------------------------------------------------- +| insert_ln +| +| insert data, listnode - insert data just before the list item +| pointed to by 'ln'. +| +| This routine is not intended to be called directly by the user +| because the validity of ln is not checked. This routine is called +| by list manipulation routines within this module, in which ln is +| known to point to a valid list node. + ----------------------------------------------------------------------*/ +static +int +insert_ln ( LIST * l, LISTNODE * ln, void * data_ptr ) +{ + LISTNODE * lnptr; + + CKLMAGIC(l); + + if (ln==NULL) { + ladd ( l, data_ptr ); + CKLMAGIC(l); + return 0; + } + + lnptr = get_listnode(l); + if (lnptr == NULL) { +#ifdef BOS + breakpoint(); +#endif + return -1; + } + + CKMAGIC(lnptr); + + lnptr->data = data_ptr; + + if (ln==l->top) { + /*------------------------------ + | insert before the list head + ------------------------------*/ + lnptr->next = ln; + lnptr->prev = NULL; + ln->prev = lnptr; + l->top = lnptr; + } + else if (ln==NULL) { + /*----------------- + | list was empty + -----------------*/ + lnptr->next = NULL; + lnptr->prev = l->bottom; + l->bottom->next = lnptr; + l->bottom = lnptr; + } + else { + /*----------------------------------- + | insert in the middle of the list + -----------------------------------*/ + lnptr->next = ln; + lnptr->prev = ln->prev; + lnptr->next->prev = lnptr; + lnptr->prev->next = lnptr; + } + + l->num++; + + CKLMAGIC(l); + + return 0; +} + + + +/*----------------------------------------------------------------- +| lins_n +| +| Insert data before the nth item in the list. + -----------------------------------------------------------------*/ +int +lins_n ( LISTID lid, void * data_ptr, unsigned int n ) +{ + int i; + LIST * l; + LISTNODE * ln; + + l = (LIST *)lid; + + CKLMAGIC(l); + + if ((n<1)||(n>(l->num+1))) { + return -1; + } + + if (l->num == 0) { + return ladd ( lid, data_ptr ); + } + + /*---------------------------------- + | locate the nth item in the list + ----------------------------------*/ + ln = l->top; + i = 1; + while (ln && (i!=n)) { + CKMAGIC(ln); + ln = ln->next; + i++; + } + + if (!ln) { + CKLMAGIC(l); + return -1; + } + + CKLMAGIC(l); + + /*----------------------------------------- + | insert before the nth item in the list + -----------------------------------------*/ + return insert_ln ( l, ln, data_ptr ); +} + + +/*----------------------------------------------------------------- +| lins_ln +| +| Insert data before the list node pointed to by ln. + -----------------------------------------------------------------*/ +int +lins_ln ( LISTID lid, LNODEID lnid, void * data_ptr ) +{ + LIST * l; + LISTNODE * ln; + LISTNODE * ln_ptr; + + l = (LIST *)lid; + ln = (LISTNODE *)lnid; + + CKLMAGIC(l); + + CKMAGIC(ln); + + /*----------------------------------------- + | validate that ln is indeed in the list + -----------------------------------------*/ + ln_ptr = l->top; + while ((ln_ptr!=NULL)&&(ln_ptr!=ln)) { + CKMAGIC(ln_ptr); + ln_ptr = ln_ptr->next; + } + + if (ln_ptr == NULL) { + CKLMAGIC(l); + return -1; + } + + CKLMAGIC(l); + + /*-------------------------------- + | insert the data into the list + --------------------------------*/ + return insert_ln ( l, ln, data_ptr ); +} + + + +/*---------------------------------------------------------------------- +| remove_ln +| +| Remove the item in the list pointed to by ln. This routine is not +| intended to be called directly by the user because the validity +| of ln is not checked. This routine is called by list manipulation +| routines within this module, in which ln is known to point to a +| valid list node. + ----------------------------------------------------------------------*/ +static +void * +remove_ln ( LIST * l, LISTNODE * ln ) +{ + void * r; + + CKLMAGIC(l); + + CKMAGIC(ln); + + if (ln==l->top) { + /*------------------------------ + | remove the head of the list + ------------------------------*/ + l->top = ln->next; + if (l->top != NULL) { + l->top->prev = NULL; + } + else { + /*---------------------------------------- + | this was the only item in the list + ----------------------------------------*/ + l->bottom = NULL; + } + } + else if (ln==l->bottom) { + /*------------------------------ + | remove the tail of the list + ------------------------------*/ + l->bottom = ln->prev; + if (l->bottom != NULL) { + l->bottom->next = NULL; + } + } + else { + /*------------------------------------- + | remove from the middle of the list + -------------------------------------*/ + ln->prev->next = ln->next; + ln->next->prev = ln->prev; + } + + /*----------------------------- + | prepare to return the data + -----------------------------*/ + r = ln->data; + + /*----------------------------------------------- + | free the listnode for re-use + -----------------------------------------------*/ + free_listnode(l,ln); + + /*------------------------------------ + | adjust the item count of the list + ------------------------------------*/ + l->num--; + + CKLMAGIC(l); + + return r; +} + + + +/*------------------------------------------------------------------------- +| lrmv_d +| +| remove from list, data - removes the data element from the list, +| destructive + -------------------------------------------------------------------------*/ +void * +lrmv_d ( LISTID lid, void * data_ptr ) +{ + LIST * l; + LISTNODE * ln; + int i; + + l = (LIST *)lid; + + CKLMAGIC(l); + + i = 0; + ln = l->top; + while (ln && (ln->data != data_ptr)) { + i++; + CKMAGIC(ln); + ln = ln->next; + } + + if (ln == NULL) { + CKLMAGIC(l); + return NULL; + } + else { + CKLMAGIC(l); + return remove_ln ( l, ln ); + } +} + + + +/*------------------------------------------------------------------------- +| lrmv_ln +| +| remove from list, by list node - remove the data element pointed to +| by 'ln' from the list, destructive + -------------------------------------------------------------------------*/ +void * +lrmv_ln ( LISTID lid, LNODEID lnid ) +{ + LIST * l; + LISTNODE * ln; + LISTNODE * p; + + l = (LIST *)lid; + ln = (LISTNODE *)lnid; + + CKLMAGIC(l); + + CKMAGIC(ln); + + p = l->top; + while ((p!=NULL)&&(p!=ln)) { + CKMAGIC(p); + p = p->next; + } + + if (p==NULL) { + CKLMAGIC(l); + return NULL; + } + else { + CKLMAGIC(l); + return remove_ln ( l, p ); + } +} + + + +/*---------------------------------------------------------------------- +| lrmv_n +| +| remove from list, by item number - remove the nth element from +| the list. + ----------------------------------------------------------------------*/ +void * +lrmv_n ( LISTID lid, unsigned int n ) +{ + int i; + LIST * l; + LISTNODE * ln; + + l = (LIST *)lid; + + CKLMAGIC(l); + + if ((n<1)||(n>l->num)) { + return NULL; + } + + ln = l->top; + i = 1; + while (ln && (i!=n)) { + CKMAGIC(ln); + ln = ln->next; + i++; + } + + if (ln) { + CKLMAGIC(l); + return remove_ln ( l, ln ); + } + else { + CKLMAGIC(l); + return NULL; + } +} + + +/*---------------------------------------------------------------------- +| lrmv +| +| remove from list, last item - remove the last item from the list, +| destructive + ----------------------------------------------------------------------*/ +void * +lrmv ( LISTID lid ) +{ + LIST * l; + LISTNODE * p; + + l = (LIST *)lid; + + CKLMAGIC(l); + + p = l->bottom; + + if (p == NULL) { + CKLMAGIC(l); + return NULL; + } + else { + CKLMAGIC(l); + return remove_ln ( l, p ); + } +} + + + +/*---------------------------------------------------------------------- +| lsrch +| +| search list - return data element pointed to by 'p', NULL if not +| found + ----------------------------------------------------------------------*/ +void * +lsrch ( LISTID lid, void * p, int (* compare)(void * p1, void * p2) ) +{ + LIST * l; + LISTNODE * ln; + + l = (LIST *)lid; + + CKLMAGIC(l); + + ln = l->top; + + while (ln!=NULL) { + CKMAGIC(ln); + if (compare(p,ln->data) == 0) { + CKLMAGIC(l); + return ln->data; + } + else { + ln = ln->next; + } + } + + CKLMAGIC(l); + return NULL; +} + + +int lprint ( FILE * f, LISTID lid ) +{ + LIST * l; + LISTNODE * ln; + NODEPOOL * np; + int count; + + l = (LIST *)lid; + + fprintf ( f, "list id 0x%08x internal data structures:\n", + (unsigned int)lid ); +#if CHECK_MAGIC + if ((l->magic1 != MAGIC) || (l->magic2 != MAGIC)) { + fprintf ( f, " *** WARNING: LIST MAGIC IS CORRUPT ***\n" ); + } + fprintf ( f, + " magic1=0x%08x\n" + " magic2=0x%08x\n", + l->magic1, l->magic2 ); +#endif + fprintf ( f, " num f pool n_ln top bottom next_ln np_top np_bottom\n" ); + fprintf ( f, " ---- - ---- ---- ---------- ---------- ---------- ---------- ----------\n" ); + fprintf ( f, " %4d %1d %4d %4d %10p %10p %10p %10p %10p\n", + l->num, l->free_on_close, l->poolsize, l->n_ln_pool, + l->top, l->bottom, + l->next_ln, l->np_top, l->np_bottom ); + + + fprintf ( f, + " node pools:\n" + " idx np magic1 next prev magic2\n" + " ---- ---------- ---------- ---------- ---------- ----------\n" ); + count = 0; + np = l->np_top; + while (np != NULL) { + count++; + fprintf ( f, " %4d %10p 0x%08x %10p %10p 0x%08x\n", + count, np, +#if CHECK_MAGIC + np->magic1, +#else + 0, +#endif + np->chain_next, np->chain_prev, +#if CHECK_MAGIC + np->magic2 +#else + 0 +#endif + ); + np = np->chain_next; + } + + if (f) { + fprintf ( f, + " list elements:\n" + " n ln magic1 next prev data magic2\n" + " ---- ---------- ---------- ---------- ---------- ---------- ----------\n" ); + count = 0; + ln = l->top; + while (ln != NULL) { + count++; + fprintf ( f, " %4d %10p %10x %10p %10p %10p %10x\n", + count, ln, +#if CHECK_MAGIC + ln->magic1, +#else + 0, +#endif + ln->next, ln->prev, ln->data, +#if CHECK_MAGIC + ln->magic2 +#else + 0 +#endif + ); + ln = lnext(ln); + } + if (count != l->num) { + fprintf ( f, + " *** list count is not correct\n" + " *** list id indicates %d, counted items = %d\n", + l->num, count ); + } + } + + return 0; +} diff --git a/lists.h b/lists.h new file mode 100644 index 00000000..2217d957 --- /dev/null +++ b/lists.h @@ -0,0 +1,91 @@ +/* $Id$ */ + +/*---------------------------------------------------------------------- + Id: lists.h,v 1.2 2001/08/19 23:13:17 bsd Exp $ + ----------------------------------------------------------------------*/ +/*---------------------------------------------------------------------- + General purpose linked list routines - header file declarations. + + Author : Brian Dean + Date : 10 January, 1990 + ----------------------------------------------------------------------*/ +#ifndef __lists_h__ +#define __lists_h__ + +#include + +typedef void * LISTID; +typedef void * LNODEID; + + +/*---------------------------------------------------------------------- + several defines to access the LIST structure as as stack or a queue + --- use for program readability + ----------------------------------------------------------------------*/ +#define STACKID LISTID +#define SNODEID LNODEID +#define QUEUEID LISTID +#define QNODEID LNODEID + + +#define PUSH(s,d) lins_n(s,d,1) /* push 'd' onto the stack */ +#define POP(s) lrmv_n(s,1) /* pop the stack */ +#define LOOKSTACK(s) lget_n(s,1) /* look at the top of the stack, + but don't pop */ + + +#define ENQUEUE(q,d) lins_n(q,d,1) /* put 'd' on the end of the queue */ +#define DEQUEUE(q) lrmv(q) /* remove next item from the front of + the queue */ +#define REQUEUE(q,d) ladd(q,d) /* re-insert (push) item back on the + front of the queue */ +#define LOOKQUEUE(q) lget(q) /* return next item on the queue, + but don't dequeue */ +#define QUEUELEN(q) lsize(q) /* length of the queue */ + + +#define LISTADD(l,d) ladd(l,d) /* add to end of the list */ +#define LISTRMV(l,d) lrmv_d(l,d) /* remove from end of the list */ + + +#define LISTSZ 32 /* size of internal private LIST structure */ + + +/* .................... Function Prototypes .................... */ + +LISTID lcreat ( void * liststruct, int poolsize ); +void ldestroy ( LISTID lid ); +void ldestroy_cb ( LISTID lid, void (*ucleanup)() ); + +LNODEID lfirst ( LISTID ); /* head of the list */ +LNODEID llast ( LISTID ); /* tail of the list */ +LNODEID lnext ( LNODEID ); /* next item in the list */ +LNODEID lprev ( LNODEID ); /* previous item in the list */ +void * ldata ( LNODEID ); /* data at the current position */ +int lsize ( LISTID ); /* number of elements in the list */ + +int ladd ( LISTID lid, void * p ); +int laddo ( LISTID lid, void *p, + int (*compare)(const void *p1,const void *p2), + LNODEID * firstdup ); +int laddu ( LISTID lid, void * p, + int (*compare)(const void *p1,const void *p2)); +int lins_n ( LISTID lid, void * d, unsigned int n ); +int lins_ln ( LISTID lid, LNODEID lnid, void * data_ptr ); + +void * lget ( LISTID lid ); +void * lget_n ( LISTID lid, unsigned int n ); +LNODEID lget_ln ( LISTID lid, unsigned int n ); + +void * lrmv ( LISTID lid ); +void * lrmv_n ( LISTID lid, unsigned int n ); +void * lrmv_ln ( LISTID lid, LNODEID lnid ); +void * lrmv_d ( LISTID lid, void * data_ptr ); + +LISTID lcat ( LISTID lid1, LISTID lid2 ); + +void * lsrch ( LISTID lid, void * p, int (*compare)(void *p1,void *p2)); + +int lprint ( FILE * f, LISTID lid ); + +#endif diff --git a/main.c b/main.c index f4508913..520f47d6 100644 --- a/main.c +++ b/main.c @@ -33,9 +33,8 @@ * Code to program an Atmel AVR AT90S device using the parallel port. * * Pin definitions can be changed via a config file. Below is the - * default pin configuration. - * - * Make the following (minimal) connections: + * default pin configuration in the absence of a config definition + * which lists "default" as one of its ids. * * Parallel Port Programmer Function * ------------- ----------------------------- @@ -46,8 +45,9 @@ * Pin 10 <- AVR MISO (data out) * Pin 18 Signal Ground * - * Additionally, the following conntections can be made to enable - * additional features: + * Additionally, the following connections can be made to enable + * additional features, however, to enable these features use the + * pin configuration id "alf" ("-c alf" on the command line): * * Parallel Port Programmer Function * ------------- ----------------------------- @@ -86,6 +86,7 @@ #include #include "avr.h" +#include "config.h" #include "fileio.h" #include "pindefs.h" #include "ppi.h" @@ -95,22 +96,26 @@ #define DEFAULT_PARALLEL "/dev/ppi0" extern char * avr_version; +extern char * config_version; extern char * fileio_version; +extern char * lists_version; extern char * main_version; extern char * ppi_version; extern char * term_version; -#define N_MODULES 5 +#define N_MODULES 7 -char ** modules[5] = { - &avr_version, - &fileio_version, +char ** modules[N_MODULES] = { + &avr_version, + &config_version, + &fileio_version, + &lists_version, &main_version, &ppi_version, &term_version }; -char * version = "1.3.0"; +char * version = "1.4.0"; char * main_version = "$Id$"; @@ -119,7 +124,10 @@ char progbuf[PATH_MAX]; /* temporary buffer of spaces the same length as progname; used for lining up multiline messages */ -unsigned int pinno[N_PINS]; +PROGRAMMER * pgm = NULL; + +PROGRAMMER compiled_in_pgm; + /* * usage message @@ -127,11 +135,12 @@ unsigned int pinno[N_PINS]; void usage(void) { fprintf(stderr, - "Usage: %s -p partno [-e] [-E exitspec[,exitspec]] [-f format] " - "[-F] [-V]\n" + "\nUsage: %s -p partno [-e] [-E exitspec[,exitspec]] [-f format] " + "[-F]\n" " %s[-i filename] [-m memtype] [-o filename] [-P parallel] " - "[-t]\n\n", - progname, progbuf); + "[-t]\n" + " %s[-c programmer] [-C config-file] [-v [-v]] [-n]\n\n", + progname, progbuf, progbuf); } @@ -145,18 +154,18 @@ int getexitspecs(char *s, int *set, int *clr) while ((cp = strtok(s, ","))) { if (strcmp(cp, "reset") == 0) { - *clr |= ppi_getpinmask(pinno[PIN_AVR_RESET]); + *clr |= ppi_getpinmask(pgm->pinno[PIN_AVR_RESET]); } else if (strcmp(cp, "noreset") == 0) { - *set |= ppi_getpinmask(pinno[PIN_AVR_RESET]); + *set |= ppi_getpinmask(pgm->pinno[PIN_AVR_RESET]); } else if (strcmp(cp, "vcc") == 0) { - if (pinno[PPI_AVR_VCC]) - *set |= pinno[PPI_AVR_VCC]; + if (pgm->pinno[PPI_AVR_VCC]) + *set |= pgm->pinno[PPI_AVR_VCC]; } else if (strcmp(cp, "novcc") == 0) { - if (pinno[PPI_AVR_VCC]) - *clr |= pinno[PPI_AVR_VCC]; + if (pgm->pinno[PPI_AVR_VCC]) + *clr |= pgm->pinno[PPI_AVR_VCC]; } else { return -1; @@ -267,318 +276,26 @@ int print_module_versions(FILE * outf, char * timestamp) } -#define MAX_LINE_LEN 1024 -#define MAX_PIN_NAME 64 -int parse_config(int lineno, char * infile, char * config, char * s, - unsigned int * pinno, char * desc, int desclen) -{ - char pin_name[MAX_PIN_NAME]; - char * p; - int i; - int pins; - unsigned int value; - unsigned int v; - char * e; - - pins = 0; - p = s; - - while (1) { - - while (*p && isspace(*p)) - p++; - - if (*p == 0) { - if (pins == 0) { - fprintf(stderr, - "%s: warning: no pins configured using config entry \"%s\" " - "at line %d of %s\n", - progname, config, lineno, infile); - } - return 0; - } - - /* - * parse the pin name - */ - pin_name[0] = 0; - i = 0; - while (*p && (i 9)) { - fprintf(stderr, - "%s: error at line %d of %s: VCC must be one or more " - "pins from the range 2-9\n", - progname, lineno, infile); - return -1; - } - value |= (1 << (v-2)); - } - else { - if ((v <= 0) || (v >= 18)) { - fprintf(stderr, - "%s: error at line %d of %s: pin must be in the " - "range 1-17\n", - progname, lineno, infile); - return -1; - } - value = v; - } - - p = e; - while (*p && (isspace(*p)||(*p == ','))) - p++; - } - - if (strcasecmp(pin_name, "VCC")==0) - pinno[PPI_AVR_VCC] = value; - else if (strcasecmp(pin_name, "BUFF")==0) - pinno[PIN_AVR_BUFF] = value; - else if (strcasecmp(pin_name, "RESET")==0) - pinno[PIN_AVR_RESET] = value; - else if (strcasecmp(pin_name, "SCK")==0) - pinno[PIN_AVR_SCK] = value; - else if (strcasecmp(pin_name, "MOSI")==0) - pinno[PIN_AVR_MOSI] = value; - else if (strcasecmp(pin_name, "MISO")==0) - pinno[PIN_AVR_MISO] = value; - else if (strcasecmp(pin_name, "ERRLED")==0) - pinno[PIN_LED_ERR] = value; - else if (strcasecmp(pin_name, "RDYLED")==0) - pinno[PIN_LED_RDY] = value; - else if (strcasecmp(pin_name, "PGMLED")==0) - pinno[PIN_LED_PGM] = value; - else if (strcasecmp(pin_name, "VFYLED")==0) - pinno[PIN_LED_VFY] = value; - else { - fprintf(stderr, - "%s: error at line %d of %s: invalid pin name \"%s\"\n", - progname, lineno, infile, pin_name); - return -1; - } - - pins++; - } - } - - while (*p && (*p == ':')) - p++; - } - - return 0; -} - - - -int read_config(char * infile, char * config, unsigned int * pinno, - char * desc, int desclen) +int read_config(char * file) { FILE * f; - char line[MAX_LINE_LEN]; - char buf[MAX_LINE_LEN]; - char configname[MAX_PIN_NAME]; - int len, lineno, rc, cont; - char * p, * q; - int i; - for (i=0; i= MAX_LINE_LEN) { - fprintf(stderr, - "%s: buffer length of %d exceed at line %d of \"%s\"\n", - progname, MAX_LINE_LEN, lineno, infile); - return -2; - } - - if (cont) - continue; /* continuation line, keep going */ - - /* - * read the configuration name from the beginning of the line - */ - p = buf; - i = 0; - while (*p && (i < MAX_PIN_NAME) && (!(isspace(*p)||(*p == ':')))) { - configname[i++] = *p; - p++; - } - if (i == MAX_PIN_NAME) { - fprintf(stderr, "%s: configuration name too long at line %d of \"%s\"\n", - progname, lineno, infile); - return -3; - } - configname[i] = 0; - - /* - * position 'p' to the beginning of the pin information - */ - while (*p && (isspace(*p) || (*p == ':'))) - p++; - - if (strcasecmp(configname, config) == 0) { - strlcpy(desc, "no description", desclen); - rc = parse_config(lineno, infile, config, p, pinno, desc, desclen); - if (rc) { - fprintf(stderr, "%s: error parsing config file \"%s\" at line %d\n", - progname, infile, lineno); - return -3; - } - - return 0; - } - - buf[0] = 0; - } - - /* - * config entry not found - */ - - fprintf(stderr, "%s: config entry \"%s\" not found in file \"%s\"\n", - progname, config, infile); - - return -5; + return 0; } @@ -608,20 +325,20 @@ char * vccpins_str(unsigned int pmask) } -void pinconfig_display(char * p, char * config, char * desc) +void pinconfig_display(char * p) { char vccpins[64]; - if (pinno[PPI_AVR_VCC]) { + if (pgm->pinno[PPI_AVR_VCC]) { snprintf(vccpins, sizeof(vccpins), " = pins %s", - vccpins_str(pinno[PPI_AVR_VCC])); + vccpins_str(pgm->pinno[PPI_AVR_VCC])); } else { vccpins[0] = 0; } fprintf(stderr, "%sProgrammer Pin Configuration: %s (%s)\n", p, - config ? config : "DEFAULT", desc); + (char *)ldata(lfirst(pgm->id)), pgm->desc); fprintf(stderr, "%s VCC = 0x%02x %s\n" @@ -634,32 +351,92 @@ void pinconfig_display(char * p, char * config, char * desc) "%s RDY LED = %d\n" "%s PGM LED = %d\n" "%s VFY LED = %d\n", - p, pinno[PPI_AVR_VCC], vccpins, - p, pinno[PIN_AVR_BUFF], - p, pinno[PIN_AVR_RESET], - p, pinno[PIN_AVR_SCK], - p, pinno[PIN_AVR_MOSI], - p, pinno[PIN_AVR_MISO], - p, pinno[PIN_LED_ERR], - p, pinno[PIN_LED_RDY], - p, pinno[PIN_LED_PGM], - p, pinno[PIN_LED_VFY]); + p, pgm->pinno[PPI_AVR_VCC], vccpins, + p, pgm->pinno[PIN_AVR_BUFF], + p, pgm->pinno[PIN_AVR_RESET], + p, pgm->pinno[PIN_AVR_SCK], + p, pgm->pinno[PIN_AVR_MOSI], + p, pgm->pinno[PIN_AVR_MISO], + p, pgm->pinno[PIN_LED_ERR], + p, pgm->pinno[PIN_LED_RDY], + p, pgm->pinno[PIN_LED_PGM], + p, pgm->pinno[PIN_LED_VFY]); } void verify_pin_assigned(int pin, char * desc) { - if (pinno[pin] == 0) { + if (pgm->pinno[pin] == 0) { fprintf(stderr, "%s: error: no pin has been assigned for %s\n", progname, desc); exit(1); } } - -#define MAX_DESC_LEN 80 + +PROGRAMMER * locate_pinconfig(LISTID programmers, char * configid) +{ + LNODEID ln1, ln2; + PROGRAMMER * p; + char * id; + int found; + + found = 0; + + for (ln1=lfirst(programmers); ln1 && !found; ln1=lnext(ln1)) { + p = ldata(ln1); + for (ln2=lfirst(p->id); ln2 && !found; ln2=lnext(ln2)) { + id = ldata(ln2); + if (strcasecmp(configid, id) == 0) + found = 1; + } + } + + if (found) + return p; + + return NULL; +} + + +AVRPART * locate_part(LISTID parts, char * partdesc) +{ + LNODEID ln1; + AVRPART * p; + int found; + + found = 0; + + for (ln1=lfirst(parts); ln1 && !found; ln1=lnext(ln1)) { + p = ldata(ln1); + if ((strcasecmp(partdesc, p->id) == 0) || + (strcasecmp(partdesc, p->desc) == 0)) + found = 1; + } + + if (found) + return p; + + return NULL; +} + + +void list_parts(FILE * f, char * prefix, LISTID parts) +{ + LNODEID ln1; + AVRPART * p; + + for (ln1=lfirst(parts); ln1; ln1=lnext(ln1)) { + p = ldata(ln1); + fprintf(f, "%s%s = %s\n", prefix, p->id, p->desc); + } + + return; +} + + /* * main routine @@ -675,15 +452,12 @@ int main(int argc, char * argv []) int len; /* length for various strings */ unsigned char sig[4]; /* AVR signature bytes */ unsigned char nulldev[4]; /* 0xff signature bytes for comparison */ - struct avrpart * p, ap1; /* which avr part we are programming */ - struct avrpart * v, ap2; /* used for verify */ + struct avrpart * p; /* which avr part we are programming */ + struct avrpart * v; /* used for verify */ int readorwrite; /* true if a chip read/write op was selected */ int ppidata; /* cached value of the ppi data register */ int vsize=-1; /* number of bytes to verify */ char timestamp[64]; - char configfile[PATH_MAX]; /* pin configuration file */ - char * pinconfig; - char desc[MAX_DESC_LEN]; /* options / operating mode variables */ int memtype; /* AVR_FLASH or AVR_EEPROM */ @@ -700,8 +474,20 @@ int main(int argc, char * argv []) int ppisetbits; /* bits to set in ppi data register at exit */ int ppiclrbits; /* bits to clear in ppi data register at exit */ char * exitspecs; /* exit specs string from command line */ - int verbose; + int verbose; /* verbose output */ + char * pinconfig; /* programmer id */ + char * partdesc; /* part id */ + char configfile[PATH_MAX]; /* pin configuration file */ + progname = rindex(argv[0],'/'); + if (progname) + progname++; + else + progname = argv[0]; + + init_config(); + + partdesc = NULL; readorwrite = 0; parallel = DEFAULT_PARALLEL; outputf = NULL; @@ -718,7 +504,8 @@ int main(int argc, char * argv []) ppisetbits = 0; ppiclrbits = 0; exitspecs = NULL; - pinconfig = NULL; + pgm = NULL; + pinconfig = "avrprog"; /* compiled-in default */ verbose = 0; strcpy(configfile, CONFIG_DIR); @@ -727,30 +514,25 @@ int main(int argc, char * argv []) strcat(configfile, "/"); strcat(configfile, "avrprog.conf"); - for (i=0; iid = lcreat(NULL, 0); + ladd(pgm->id, dup_string("avrprog")); + strcpy(pgm->desc, "avrprog compiled-in default"); + for (i=0; ipinno[i] = 0; + pgm->pinno[PPI_AVR_VCC] = 0x0f; /* ppi pins 2-5, data reg bits 0-3 */ + pgm->pinno[PIN_AVR_BUFF] = 0; + pgm->pinno[PIN_AVR_RESET] = 7; + pgm->pinno[PIN_AVR_SCK] = 8; + pgm->pinno[PIN_AVR_MOSI] = 9; + pgm->pinno[PIN_AVR_MISO] = 10; + pgm->pinno[PIN_LED_ERR] = 0; + pgm->pinno[PIN_LED_RDY] = 0; + pgm->pinno[PIN_LED_PGM] = 0; + pgm->pinno[PIN_LED_VFY] = 0; len = strlen(progname) + 2; for (i=0; ipinno[PIN_LED_RDY]); + LED_OFF(fd, pgm->pinno[PIN_LED_ERR]); + LED_OFF(fd, pgm->pinno[PIN_LED_PGM]); + LED_OFF(fd, pgm->pinno[PIN_LED_VFY]); /* * enable the 74367 buffer, if connected; this signal is active low */ - ppi_setpin(fd, pinno[PIN_AVR_BUFF], 0); + ppi_setpin(fd, pgm->pinno[PIN_AVR_BUFF], 0); /* * initialize the chip in preperation for accepting commands @@ -1029,7 +821,7 @@ int main(int argc, char * argv []) } /* indicate ready */ - LED_ON(fd, pinno[PIN_LED_RDY]); + LED_ON(fd, pgm->pinno[PIN_LED_RDY]); fprintf(stderr, "%s: AVR device initialized and ready to accept instructions\n", @@ -1171,7 +963,7 @@ int main(int argc, char * argv []) * verify that the in memory file (p->mem[AVR_M_FLASH|AVR_M_EEPROM]) * is the same as what is on the chip */ - LED_ON(fd, pinno[PIN_LED_VFY]); + LED_ON(fd, pgm->pinno[PIN_LED_VFY]); fprintf(stderr, "%s: verifying %s memory against %s:\n", progname, avr_memtstr(memtype), inputf); @@ -1181,7 +973,7 @@ int main(int argc, char * argv []) if (rc < 0) { fprintf(stderr, "%s: failed to read all of %s memory, rc=%d\n", progname, avr_memtstr(memtype), rc); - LED_ON(fd, pinno[PIN_LED_ERR]); + LED_ON(fd, pgm->pinno[PIN_LED_ERR]); exitrc = 1; goto main_exit; } @@ -1191,7 +983,7 @@ int main(int argc, char * argv []) if (rc < 0) { fprintf(stderr, "%s: verification error; content mismatch\n", progname); - LED_ON(fd, pinno[PIN_LED_ERR]); + LED_ON(fd, pgm->pinno[PIN_LED_ERR]); exitrc = 1; goto main_exit; } @@ -1199,7 +991,7 @@ int main(int argc, char * argv []) fprintf(stderr, "%s: %d bytes of %s verified\n", progname, rc, avr_memtstr(memtype)); - LED_OFF(fd, pinno[PIN_LED_VFY]); + LED_OFF(fd, pgm->pinno[PIN_LED_VFY]); } @@ -1217,9 +1009,9 @@ int main(int argc, char * argv []) /* * disable the 74367 buffer, if connected; this signal is active low */ - ppi_setpin(fd, pinno[PIN_AVR_BUFF], 1); + ppi_setpin(fd, pgm->pinno[PIN_AVR_BUFF], 1); - LED_OFF(fd, pinno[PIN_LED_RDY]); + LED_OFF(fd, pgm->pinno[PIN_LED_RDY]); close(fd); diff --git a/pindefs.h b/pindefs.h index f41e1021..4c102315 100644 --- a/pindefs.h +++ b/pindefs.h @@ -32,7 +32,6 @@ #ifndef __pindefs_h__ #define __pindefs_h__ -#if 1 enum { PPI_AVR_VCC=1, PIN_AVR_BUFF, @@ -47,21 +46,6 @@ enum { N_PINS }; -extern unsigned int pinno[N_PINS]; - -#else -#define PPI_AVR_VCC 0x0f /* ppi pins 2-5, data reg bits 0-3 */ -#define PIN_AVR_BUFF 6 -#define PIN_AVR_RESET 7 -#define PIN_AVR_SCK 8 -#define PIN_AVR_MOSI 9 -#define PIN_AVR_MISO 10 -#define PIN_LED_ERR 1 -#define PIN_LED_RDY 14 -#define PIN_LED_PGM 16 -#define PIN_LED_VFY 17 -#endif - #define LED_ON(fd,pin) ppi_setpin(fd,pin,0) #define LED_OFF(fd,pin) ppi_setpin(fd,pin,1) diff --git a/term.c b/term.c index b258ff3f..b529dcc9 100644 --- a/term.c +++ b/term.c @@ -37,12 +37,14 @@ #include #include "avr.h" +#include "config.h" #include "pindefs.h" #include "ppi.h" -extern char * progname; -extern char progbuf[]; +extern char * progname; +extern char progbuf[]; +extern PROGRAMMER * pgm; struct command { @@ -362,7 +364,7 @@ int cmd_write(int fd, struct avrpart * p, int argc, char * argv[]) } } - LED_OFF(fd, pinno[PIN_LED_ERR]); + LED_OFF(fd, pgm->pinno[PIN_LED_ERR]); for (werror=0, i=0; ipinno[PIN_LED_ERR]); } }