view ueda/libueda/xga.c @ 83:88cdef7e6b1b

BOM tallying code factored out of ueda-mkbom
author Mychaela Falconia <falcon@freecalypso.org>
date Thu, 23 Feb 2017 19:27:14 +0000
parents c91e7a30fab3
children
line wrap: on
line source

/*
 * This module contains the function that implements the reading of PGA/BGA
 * package description files and some related functions.
 */

#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include "xga.h"

extern char *copystr();

extern FILE *find_symlib_file();
extern char sought_libfile_fullpath[];

parse_xga_pinnumber(desc, pinstr, parsed)
	register struct grid_pkg_desc *desc;
	register char *pinstr;
	struct xga_parsed_pinnum *parsed;
{
	char *rowfind;
	int col;

	if (!isupper(pinstr[0]) || !isdigit(pinstr[1]))
		return(-1);
	rowfind = index(desc->row_letters, pinstr[0]);
	if (!rowfind)
		return(-1);
	if (!string_is_valid_decnum(pinstr + 1))
		return(-1);
	col = atoi(pinstr + 1);
	if (col < 1 || col > desc->ncolumns)
		return(-1);
	parsed->row_0based = rowfind - desc->row_letters;
	parsed->col_0based = col - 1;
	return(0);
}

static void
check_complete(desc)
	register struct grid_pkg_desc *desc;
{
	register char *array;

	if (desc->holes_array)			/* already allocated */
		return;
	if (!desc->nrows || !desc->ncolumns)	/* not specified yet */
		return;
	/* allocate it! */
	array = malloc(desc->nrows * desc->ncolumns);
	if (!array) {
		perror("malloc");
		exit(1);
	}
	desc->holes_array = array;
	bzero(array, desc->nrows * desc->ncolumns);
}

static void
validate_rows_arg(arg, filename, lineno)
	char *arg, *filename;
	int lineno;
{
	register char *cp;
	register int c, prev;

	prev = 0;
	for (cp = arg; c = *cp++; prev = c) {
		if (c < 'A' || c > 'Z') {
			fprintf(stderr,
	"%s line %d: rows setting: only uppercase letters are allowed\n",
				filename, lineno);
			exit(1);
		}
		if (c <= prev) {
			fprintf(stderr,
		"%s line %d: rows setting: letters must be increasing\n",
				filename, lineno);
			exit(1);
		}
	}
}

static void
handle_rows_line(desc, arg, filename, lineno)
	struct grid_pkg_desc *desc;
	char *arg, *filename;
	int lineno;
{
	register char *cp, *np;

	if (desc->row_letters) {
		fprintf(stderr, "%s line %d: duplicate rows setting\n",
			filename, lineno);
		exit(1);
	}
	for (cp = arg; isspace(*cp); cp++)
		;
	if (*cp == '\0' || *cp == '#') {
		fprintf(stderr, "%s line %d: rows setting has no argument\n",
			filename, lineno);
		exit(1);
	}
	for (np = cp; *cp && !isspace(*cp); cp++)
		;
	if (*cp)
		*cp++ = '\0';
	validate_rows_arg(np, filename, lineno);
	desc->row_letters = copystr(np);
	desc->nrows = strlen(np);
	check_complete(desc);
}

static void
handle_columns_line(desc, arg, filename, lineno)
	struct grid_pkg_desc *desc;
	char *arg, *filename;
	int lineno;
{
	register char *cp, *np;

	if (desc->ncolumns) {
		fprintf(stderr, "%s line %d: duplicate columns setting\n",
			filename, lineno);
		exit(1);
	}
	for (cp = arg; isspace(*cp); cp++)
		;
	if (*cp == '\0' || *cp == '#') {
		fprintf(stderr, "%s line %d: columns setting has no argument\n",
			filename, lineno);
		exit(1);
	}
	for (np = cp; *cp && !isspace(*cp); cp++)
		;
	if (*cp)
		*cp++ = '\0';
	if (!string_is_valid_decnum(np)) {
		fprintf(stderr,
			"%s line %d: columns setting must be a number\n",
			filename, lineno);
		exit(1);
	}
	desc->ncolumns = atoi(np);
	if (desc->ncolumns < 1) {
		fprintf(stderr, "%s line %d: columns number must be positive\n",
			filename, lineno);
		exit(1);
	}
	check_complete(desc);
}

static void
handle_hole_spec(desc, arg, filename, lineno)
	register struct grid_pkg_desc *desc;
	char *arg, *filename;
	int lineno;
{
	char *arg2;
	struct xga_parsed_pinnum start_parsed, end_parsed;
	register int r, c;

	arg2 = index(arg, '-');
	if (arg2)
		*arg2++ = '\0';
	else
		arg2 = arg;
	if (parse_xga_pinnumber(desc, arg, &start_parsed) < 0) {
		fprintf(stderr,
	"%s line %d: \"%s\" is not a valid pin position for this package\n",
			filename, lineno, arg);
		exit(1);
	}
	if (parse_xga_pinnumber(desc, arg2, &end_parsed) < 0) {
		fprintf(stderr,
	"%s line %d: \"%s\" is not a valid pin position for this package\n",
			filename, lineno, arg2);
		exit(1);
	}
	if (start_parsed.row_0based == end_parsed.row_0based) {
		r = start_parsed.row_0based;
		if (start_parsed.col_0based > end_parsed.col_0based) {
error_reversed:		fprintf(stderr,
			"%s line %d: hole ranges need to be increasing\n",
				filename, lineno);
			exit(1);
		}
		for (c = start_parsed.col_0based; c <= end_parsed.col_0based;
		     c++)
			desc->holes_array[r * desc->ncolumns + c] = 1;
	} else if (start_parsed.col_0based == end_parsed.col_0based) {
		c = start_parsed.col_0based;
		if (start_parsed.row_0based > end_parsed.row_0based)
			goto error_reversed;
		for (r = start_parsed.row_0based; r <= end_parsed.row_0based;
		     r++)
			desc->holes_array[r * desc->ncolumns + c] = 1;
	} else {
		fprintf(stderr,
		"%s line %d: hole ranges must be horizontal or vertical\n",
			filename, lineno);
		exit(1);
	}
}

static void
handle_hole_line(desc, arg, filename, lineno)
	struct grid_pkg_desc *desc;
	char *arg, *filename;
	int lineno;
{
	register char *cp, *np;

	if (!desc->holes_array) {
		fprintf(stderr,
		"%s line %d: rows and columns must be defined before holes\n",
			filename, lineno);
		exit(1);
	}
	for (cp = arg; ; ) {
		while (isspace(*cp))
			cp++;
		if (*cp == '\0' || *cp == '#')
			break;
		for (np = cp; *cp && !isspace(*cp); cp++)
			;
		if (*cp)
			*cp++ = '\0';
		handle_hole_spec(desc, np, filename, lineno);
	}
}

struct grid_pkg_desc *
read_grid_pkg_file(filename)
	char *filename;
{
	FILE *f;
	char linebuf[1024];
	int lineno;
	register char *cp, *np;
	struct grid_pkg_desc *desc;

	f = find_symlib_file(filename, NULL);
	if (!f) {
		fprintf(stderr, "Cannot find xGA definition file %s\n",
			filename);
		exit(1);
	}
	desc = (struct grid_pkg_desc *) malloc(sizeof(struct grid_pkg_desc));
	if (!desc) {
		perror("malloc");
		exit(1);
	}
	bzero(desc, sizeof(struct grid_pkg_desc));
	for (lineno = 1; fgets(linebuf, sizeof linebuf, f); lineno++) {
		for (cp = linebuf; isspace(*cp); cp++)
			;
		if (*cp == '\0' || *cp == '#')
			continue;
		for (np = cp; *cp && !isspace(*cp); cp++)
			;
		if (*cp)
			*cp++ = '\0';
		if (!strcmp(np, "rows"))
			handle_rows_line(desc, cp, sought_libfile_fullpath,
					 lineno);
		else if (!strcmp(np, "columns"))
			handle_columns_line(desc, cp, sought_libfile_fullpath,
						lineno);
		else if (!strcmp(np, "hole"))
			handle_hole_line(desc, cp, sought_libfile_fullpath,
					 lineno);
		else {
			fprintf(stderr,
				"%s line %d: setting \"%s\" not understood\n",
				sought_libfile_fullpath, lineno, np);
			exit(1);
		}
	}
	fclose(f);

	if (!desc->nrows) {
		fprintf(stderr, "error: %s contains no rows setting\n",
			sought_libfile_fullpath);
		exit(1);
	}
	if (!desc->ncolumns) {
		fprintf(stderr, "error: %s contains no columns setting\n",
			sought_libfile_fullpath);
		exit(1);
	}
	return(desc);
}

free_grid_pkg_desc(desc)
	struct grid_pkg_desc *desc;
{
	free(desc->row_letters);
	free(desc->holes_array);
	free(desc);
}