view ueda/libuschem/graphnets.c @ 116:bb9908f36e23

m4-fp/qfpmnf.inc: basic fixes
author Mychaela Falconia <falcon@freecalypso.org>
date Sat, 13 Jun 2020 04:14:10 +0000
parents cd92449fdb51
children
line wrap: on
line source

/*
 * preen_graphnets() functionality
 */

#include <sys/types.h>
#include <stdio.h>
#include <strings.h>
#include "schemstruct.h"
#include "graphsym.h"

extern char *malloc();

extern struct graphsym_pininst *find_comp_pininst();
extern struct graphsym_pininst *find_pin_by_coord();

static struct schem *schem_being_preened;
static int dowarn, docorrect, severe_err;

static int
tjoin_hit_check(obj, tjoin)
	struct schemobj *obj;
	register struct netpoint *tjoin;
{
	register struct netpoint *netpt, *nextpt;

	for (netpt = obj->netobj_points; netpt && (nextpt = netpt->netpt_next);
	     netpt = nextpt) {
		if (!netpt->netpt_coord_valid || !nextpt->netpt_coord_valid) {
			fprintf(stderr,
"%s: line %d: Pin w/o coordinates impedes search for Tjoin antecedent\n",
				schem_being_preened->orig_filename,
				obj->obj_lineno);
			severe_err = -1;
			return(-1);
		}
		/* check for horizontal segments */
		if (netpt->netpt_y == tjoin->netpt_y &&
		    nextpt->netpt_y == tjoin->netpt_y) {
			if (tjoin->netpt_x > netpt->netpt_x &&
			    tjoin->netpt_x < nextpt->netpt_x)
				return(1);
			if (tjoin->netpt_x < netpt->netpt_x &&
			    tjoin->netpt_x > nextpt->netpt_x)
				return(1);
		}
		/* check for vertical segments */
		if (netpt->netpt_x == tjoin->netpt_x &&
		    nextpt->netpt_x == tjoin->netpt_x) {
			if (tjoin->netpt_y > netpt->netpt_y &&
			    tjoin->netpt_y < nextpt->netpt_y)
				return(1);
			if (tjoin->netpt_y < netpt->netpt_y &&
			    tjoin->netpt_y > nextpt->netpt_y)
				return(1);
		}
	}
	return(0);
}

static struct schemobj *
find_grouphead_tail(ghead)
	register struct schemobj *ghead;
{
	register struct schemobj *obj, *next;

	for (obj = ghead; ; obj = next) {
		next = obj->obj_next;
		if (next->obj_type != OBJTYPE_GRAPHNET)
			return(obj);
		if (next->netobj_grouphead != ghead)
			return(obj);
	}
}

static
preen_tjoin(obj, netpt, first, got_tjoin)
	struct schemobj *obj;
	register struct netpoint *netpt;
	int first, *got_tjoin;
{
	register struct schem *schem;
	register struct schemobj *prevobj;
	struct schemobj *ghead;
	register int c;

	schem = schem_being_preened;
	if (first)
		*got_tjoin = 1;
	else if (!netpt->netpt_next) {
		if (*got_tjoin) {
			fprintf(stderr,
		"%s: line %d: Tjoin on both ends of a GraphNet is illegal\n",
				schem->orig_filename, obj->obj_lineno);
			severe_err = -1;
			return;
		}
		*got_tjoin = 1;
	} else {
		fprintf(stderr,
	"%s: line %d: Tjoin in the middle of a GraphNet is meaningless\n",
			schem->orig_filename, obj->obj_lineno);
		severe_err = -1;
		return;
	}
	for (prevobj = obj->obj_prev, c = 0;
	     prevobj != (struct schemobj *)schem; prevobj = prevobj->obj_prev)
		if (prevobj->obj_type == OBJTYPE_GRAPHNET) {
			c = tjoin_hit_check(prevobj, netpt);
			if (c < 0)
				return;
			if (c)
				break;
		}
	if (!c) {
		fprintf(stderr, "%s: line %d: Tjoin antecedent not found\n",
			schem->orig_filename, obj->obj_lineno);
		severe_err = -1;
		return;
	}
	netpt->netpt_tjoin_to = prevobj;
	obj->netobj_grouphead = ghead = prevobj->netobj_grouphead;
	/* netname logic */
	if (obj->netobj_netname) {
		/* accumulate on the group head */
		if (!ghead->netobj_netname)
			ghead->netobj_netname = obj->netobj_netname;
		else if (strcmp(ghead->netobj_netname, obj->netobj_netname)) {
			fprintf(stderr,
			"%s: line %d: Tjoin connects two netnames: %s and %s\n",
				schem->orig_filename, obj->obj_lineno,
				ghead->netobj_netname, obj->netobj_netname);
			severe_err = -1;
			return;
		}
	}
	/* shuffling around to bring groups together */
	prevobj = obj->obj_prev;
	if (prevobj->obj_type != OBJTYPE_GRAPHNET ||
	    prevobj->netobj_grouphead != ghead) {
		prevobj = find_grouphead_tail(ghead);
		schemobj_unlink(obj);
		schemobj_insert_after(prevobj, obj);
	}
}

static
preen_pin(obj, netpt)
	struct schemobj *obj;
	register struct netpoint *netpt;
{
	register int i = 0, c;
	struct graphsym_pininst *pinc, *pinn;
	struct schemobj *comp;
	char *soughtpin;
	int bynum;

	if (netpt->netpt_coord_valid) {
		i |= 2;
		pinc = find_pin_by_coord(schem_being_preened, netpt->netpt_x,
					 netpt->netpt_y);
	}
	if (netpt->netpt_pin_nameref) {
		i |= 1;
		c = parse_pin_nameref(schem_being_preened, obj->obj_lineno,
					netpt->netpt_pin_nameref, &comp,
					&soughtpin, &bynum);
		if (c < 0)
			severe_err = -1;
	}
	switch (i) {
	case 1:
		if (dowarn)
			fprintf(stderr,
	"%s: line %d: Pin w/o coordinates, run uschem-rewrite -g to fix\n",
				schem_being_preened->orig_filename,
				obj->obj_lineno);
		if (c < 0)
			return;
		if (!comp->compobj_isgraph) {
nograph:		fprintf(stderr,
	"%s: line %d: %s: GraphNet refers to a non-graphical component\n",
				schem_being_preened->orig_filename,
				obj->obj_lineno, netpt->netpt_pin_nameref);
			severe_err = -1;
			return;
		}
		pinn = find_comp_pininst(comp, soughtpin, bynum);
		if (!pinn) {
pinnotfound:		fprintf(stderr, "%s: line %d: %s: pin not found\n",
				schem_being_preened->orig_filename,
				obj->obj_lineno, netpt->netpt_pin_nameref);
			severe_err = -1;
			return;
		}
		/* fix it */
		netpt->netpt_x = pinn->x;
		netpt->netpt_y = pinn->y;
		netpt->netpt_coord_valid = 1;
		return;
	case 2:
		if (dowarn)
			fprintf(stderr,
"%s: line %d: Pin given by coordinates only, run uschem-rewrite -g to fix\n",
				schem_being_preened->orig_filename,
				obj->obj_lineno);
		if (!pinc) {
			fprintf(stderr,
				"%s: line %d: no pin found at (%d,%d)\n",
				schem_being_preened->orig_filename,
				obj->obj_lineno, netpt->netpt_x,
				netpt->netpt_y);
			severe_err = -1;
			return;
		}
		comp = pinc->compinst;
		if (comp->obj_type != OBJTYPE_COMPINST) {
			fprintf(stderr,
				"%s: line %d: Pin refers to a non-component\n",
				schem_being_preened->orig_filename,
				obj->obj_lineno);
			severe_err = -1;
			return;
		}
		if (!docorrect)
			return;
		if (pinc->pindef->gspd_pinname) {
			soughtpin = pinc->pindef->gspd_pinname;
			bynum = 0;
		} else if (pinc->pindef->gspd_pinnumber) {
			soughtpin = pinc->pindef->gspd_pinnumber;
			bynum = 1;
		} else {
			fprintf(stderr,
		"%s: %s pin at (%d,%d) has no pinname or pinnumber attribute\n",
				schem_being_preened->orig_filename,
				comp->compobj_instname, netpt->netpt_x,
				netpt->netpt_y);
			severe_err = -1;
			return;
		}
		netpt->netpt_pin_nameref =
			malloc(strlen(comp->compobj_instname) +
				strlen(soughtpin) + 2);
		if (!netpt->netpt_pin_nameref) {
			perror("malloc");
			exit(1);
		}
		sprintf(netpt->netpt_pin_nameref, "%s%c%s",
			comp->compobj_instname, bynum ? '-' : '.', soughtpin);
		return;
	case 3:
		if (!dowarn || c < 0)
			return;
		if (!comp->compobj_isgraph)
			goto nograph;
		pinn = find_comp_pininst(comp, soughtpin, bynum);
		if (!pinn)
			goto pinnotfound;
		if (pinc != pinn)
			fprintf(stderr,
	"%s: line %d: Pin(%d,%d)=%s: pin name and coordinates don't match\n",
				schem_being_preened->orig_filename,
				obj->obj_lineno, netpt->netpt_x, netpt->netpt_y,
				netpt->netpt_pin_nameref);
		return;
	}
}

static
preen_pseudopin(obj, netpt)
	struct schemobj *obj;
	register struct netpoint *netpt;
{
	register struct graphsym_pininst *pin;
	register struct schemobj *ghead;

	pin = find_pin_by_coord(schem_being_preened, netpt->netpt_x,
				netpt->netpt_y);
	if (!pin) {
		fprintf(stderr, "%s: line %d: no pin found at (%d,%d)\n",
			schem_being_preened->orig_filename, obj->obj_lineno,
			netpt->netpt_x, netpt->netpt_y);
		severe_err = -1;
		return;
	}
	if (pin->compinst->obj_type != OBJTYPE_GRAPHSYM) {
		fprintf(stderr,
"%s: line %d: Pseudo refers to a real component pin (use Pin instead)\n",
			schem_being_preened->orig_filename, obj->obj_lineno);
		severe_err = -1;
		return;
	}
	if (!pin->pindef->gspd_forcenet)
		return;
	obj->netobj_forcenets++;
	ghead = obj->netobj_grouphead;
	if (!ghead)
		ghead = obj;
	if (!ghead->netobj_netname) {
		if (dowarn)
			fprintf(stderr,
"%s: line %d: GraphNet needs to be forced to net %s (run uschem-rewrite -g to fix)\n",
				schem_being_preened->orig_filename,
				obj->obj_lineno, pin->pindef->gspd_forcenet);
		if (docorrect)
			ghead->netobj_netname = pin->pindef->gspd_forcenet;
	} else if (strcmp(ghead->netobj_netname, pin->pindef->gspd_forcenet)) {
		fprintf(stderr,
"%s: line %d: Graphnet %s is forced to net %s by a special symbol connection\n",
			schem_being_preened->orig_filename, obj->obj_lineno,
			ghead->netobj_netname, pin->pindef->gspd_forcenet);
		severe_err = -1;
	}
}

static
do_graphnet(obj, do_tjoin, do_pins)
	struct schemobj *obj;
{
	register struct netpoint *netpt;
	register int first;
	int got_tjoin = 0;

	if (do_tjoin)
		obj->netobj_grouphead = obj;	/* for now at least */
	for (netpt = obj->netobj_points, first = 1; netpt;
	     netpt = netpt->netpt_next, first = 0) {
		if (dowarn && first && !netpt->netpt_next)
			fprintf(stderr, "%s: line %d: singular GraphNet\n",
				schem_being_preened->orig_filename,
				obj->obj_lineno);
		switch (netpt->netpt_type) {
		case NETPT_TYPE_TJOIN:
			if (do_tjoin)
				preen_tjoin(obj, netpt, first, &got_tjoin);
			continue;
		case NETPT_TYPE_PIN:
			if (do_pins)
				preen_pin(obj, netpt);
			continue;
		case NETPT_TYPE_PSEUDO:
			if (do_pins)
				preen_pseudopin(obj, netpt);
			continue;
		}
	}
}

preen_graphnets(schem, do_tjoin, do_pins, warn, correct)
	struct schem *schem;
{
	register struct schemobj *obj, *next;

	schem_being_preened = schem;
	dowarn = warn;
	docorrect = correct;
	severe_err = 0;
	for (obj = schem->obj_next; obj != (struct schemobj *)schem;
	     obj = next) {
		next = obj->obj_next;
		if (obj->obj_type == OBJTYPE_GRAPHNET)
			do_graphnet(obj, do_tjoin, do_pins);
	}
	return(severe_err);
}