view ueda/uschem-utils/check.c @ 139:bf188727e606

donl-rename-parts reader: no tEDAx-style escapes
author Mychaela Falconia <falcon@freecalypso.org>
date Mon, 07 Sep 2020 04:25:11 +0000
parents cd92449fdb51
children
line wrap: on
line source

/*
 * This program (uschem-check) reads a uschem schematic into core, exercising
 * libuschem reading code.
 * It then performs the most basic DRC, or more specifically, the check is
 * focused on matching the graphical info with the netlist info - no attempt
 * is made to guess the sensibility of the actual electrical circuit.
 */

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

extern int optind;
extern char *optarg;

extern char *MCLfile;

extern struct schem *read_schem();

struct schem *schem;
int domcl, dosymbols, checkhash, donets;

main(argc, argv)
	char **argv;
{
	register int c;
	char **avp;

	while ((c = getopt(argc, argv, "hI:mM:s")) != EOF)
		switch (c) {
		case 'h':
			checkhash++;
			break;
		case 'I':
			add_symfile_dir(optarg);
			break;
		case 'm':
			domcl++;
			break;
		case 'M':
			MCLfile = optarg;
			break;
		case 's':
			dosymbols++;
			break;
		default:
usage:			fprintf(stderr, "usage: %s [-hImMs] schemfile...\n",
				argv[0]);
			exit(1);
		}
	if (!argv[optind])
		goto usage;

	if (domcl) {
		read_MCL();
		hash_MCL();
		if (checkhash)
			report_mclhash_quality();
	}
	if (dosymbols)
		set_default_sympath();

	for (avp = argv + optind; *avp; avp++) {
		schem = read_schem(*avp);
		hash_component_instances(schem);
		if (checkhash)
			report_compinst_hash_quality(schem);
		if (domcl)
			match_schem_to_mcl(schem);
		if (dosymbols) {
			load_graphsyms(schem);
			instantiate_graphsym_pins(schem, 1);
			if (checkhash)
				report_pininst_hash_quality(schem);
		}
		donets = 1;
		check_schem_objects();
		if (preen_graphnets(schem, 1, dosymbols, 1, 0) < 0)
			donets = 0;
		if (donets && (!schem->is_graph || dosymbols))
			check_exclusive_nets();
	}

	report_exclusive_net_violations();
	if (checkhash && dosymbols)
		report_graphsym_hash_quality();
	exit(0);
}

check_schem_objects()
{
	register struct schemobj *obj;

	for (obj = schem->obj_next; obj != (struct schemobj *)schem;
	     obj = obj->obj_next) {
		switch (obj->obj_type) {
		case OBJTYPE_COMPINST:
			if (obj->compobj_isgraph && !schem->is_graph)
				fprintf(stderr,
	"%s: line %d: graphical symbol used in a non-graphical schematic\n",
					schem->orig_filename, obj->obj_lineno);
			if (obj->compobj_isgraph && dosymbols &&
			    obj->compobj_graphsym->gs_forcenets)
				fprintf(stderr,
"%s: line %d: symbol \"%s\" on %s: forcenets won't have the desired effect\n",
					schem->orig_filename, obj->obj_lineno,
					obj->compobj_graph_symname,
					obj->compobj_instname);
			break;
		case OBJTYPE_GRAPHSYM:
			if (!schem->is_graph)
				fprintf(stderr,
		"%s: line %d: GraphSym object in a non-graphical schematic\n",
					schem->orig_filename, obj->obj_lineno);
			break;
		case OBJTYPE_GRAPHNET:
			if (!schem->is_graph) {
				fprintf(stderr,
		"%s: line %d: GraphNet object in a non-graphical schematic\n",
					schem->orig_filename, obj->obj_lineno);
				donets = 0;
			}
			break;
		case OBJTYPE_NETLINE:
			if (!schem->is_graph)
				fprintf(stderr,
		"%s: line %d: NetLine object in a non-graphical schematic\n",
					schem->orig_filename, obj->obj_lineno);
			break;
		case OBJTYPE_BUSSEG:
			if (!schem->is_graph)
				fprintf(stderr,
		"%s: line %d: BusSeg object in a non-graphical schematic\n",
					schem->orig_filename, obj->obj_lineno);
			break;
		case OBJTYPE_GRAPHBLOCK:
			if (!schem->is_graph)
				fprintf(stderr,
		"%s: line %d: graphics block in a non-graphical schematic\n",
					schem->orig_filename, obj->obj_lineno);
			break;
		}
		check_obj_decors(obj);
	}
}

check_obj_decors(obj)
	register struct schemobj *obj;
{
	register struct decoration *decor;

	for (decor = obj->obj_decorations; decor; decor = decor->decor_next)
	switch (decor->decor_type) {
	case DECOR_TYPE_DISPLAYATTR:
		if (!is_graphical_obj(obj))
			fprintf(stderr,
			"%s: line %d: DisplayAttr on a non-graphical object\n",
				schem->orig_filename, decor->decor_lineno);
		continue;
	case DECOR_TYPE_DISPLAYNETNAME:
		if (obj->obj_type != OBJTYPE_GRAPHNET)
			fprintf(stderr,
	"%s: line %d: DisplayNetName invalid in objects other than GraphNet\n",
				schem->orig_filename, decor->decor_lineno);
		continue;
	case DECOR_TYPE_GRAPHBLOCK:
		if (!is_graphical_obj(obj))
			fprintf(stderr,
	"%s: line %d: graphics block decoration on a non-graphical object\n",
				schem->orig_filename, decor->decor_lineno);
		break;
	case DECOR_TYPE_PINTONET:
		if (obj->obj_type != OBJTYPE_COMPINST) {
			fprintf(stderr,
	"%s: line %d: PinToNet invalid in objects other than components\n",
				schem->orig_filename, decor->decor_lineno);
			continue;
		}
		record_netname_reference(decor->decorpincon_netname, 0,
					 schem->orig_filename,
					 decor->decor_lineno);
		if (obj->compobj_isgraph && dosymbols)
			check_pintonet_graph(obj, decor);
		continue;
	case DECOR_TYPE_SYMONPIN:
		if (obj->obj_type != OBJTYPE_COMPINST) {
			fprintf(stderr,
	"%s: line %d: SymOnPin invalid in objects other than components\n",
				schem->orig_filename, decor->decor_lineno);
			continue;
		}
		if (!obj->compobj_isgraph) {
			fprintf(stderr,
		"%s: line %d: SymOnPin invalid on a non-graphical component\n",
				schem->orig_filename, decor->decor_lineno);
			continue;
		}
		if (dosymbols)
			check_symonpin(obj, decor);
	}
}

is_graphical_obj(obj)
	register struct schemobj *obj;
{
	switch (obj->obj_type) {
	case OBJTYPE_COMPINST:
		return(obj->compobj_isgraph);
	case OBJTYPE_GRAPHSYM:
	case OBJTYPE_GRAPHNET:
	case OBJTYPE_NETLINE:
	case OBJTYPE_BUSSEG:
	case OBJTYPE_GRAPHBLOCK:
		return(1);
	default:
		return(0);
	}
}

check_pintonet_graph(obj, condec)
	struct schemobj *obj;
	register struct decoration *condec;
{
	register struct decoration *symdec;

	/* is this pin represented graphically? */
	if (!is_pin_graphical(obj->compobj_graphsym, condec->decorpincon_pin))
		return;
	/* it is graphical -- look for matching SymOnPin */
	for (symdec = obj->obj_decorations; symdec; symdec = symdec->decor_next)
		if (symdec->decor_type == DECOR_TYPE_SYMONPIN &&
		    !strcmp(condec->decorpincon_pin, symdec->decorpinsym_pin))
			break;
	if (!symdec)
		fprintf(stderr, "%s: line %d: pin %s of %s is connected with PinToNet, but not marked with SymOnPin\n",
			schem->orig_filename, condec->decor_lineno,
			condec->decorpincon_pin, obj->compobj_instname);
}

is_pin_graphical(gs, matchkey)
	struct graphsym *gs;
	register char *matchkey;
{
	int bynum;
	register struct graphsym_pindef *pd;
	register char *pinid;

	if (matchkey[0] == '#') {
		bynum = 1;
		matchkey++;
	} else
		bynum = 0;
	for (pd = gs->gs_pins; pd; pd = pd->gspd_next) {
		pinid = bynum ? pd->gspd_pinnumber : pd->gspd_pinname;
		if (pinid && !strcmp(pinid, matchkey))
			return(1);
	}
	return(0);
}

check_symonpin(obj, symdec)
	struct schemobj *obj;
	struct decoration *symdec;
{
	struct graphsym *gs;
	struct graphsym_pindef *pindef;
	register struct decoration *ndec;

	gs = symdec->decorpinsym_gs;
	if (gs->gs_npins > 1) {
		fprintf(stderr,
		"%s: line %d: SymOnPin symbols may not have more than 1 pin\n",
			schem->orig_filename, symdec->decor_lineno);
		return;
	}
	pindef = gs->gs_pins;
	if (!pindef->gspd_forcenet)
		return;
	/* look for matching PinToNet */
	for (ndec = obj->obj_decorations; ndec; ndec = ndec->decor_next)
		if (ndec->decor_type == DECOR_TYPE_PINTONET &&
		    !strcmp(ndec->decorpincon_pin, symdec->decorpinsym_pin))
			break;
	if (!ndec) {
		fprintf(stderr,
"%s: line %d: SymOnPin implies connection to %s, but no matching PinToNet\n",
			schem->orig_filename, symdec->decor_lineno,
			pindef->gspd_forcenet);
		return;
	}
	if (strcmp(ndec->decorpincon_netname, pindef->gspd_forcenet))
		fprintf(stderr,
"%s: SymOnPin (line %d) and PinToNet (line %d) call for different nets!\n",
			schem->orig_filename, symdec->decor_lineno,
			ndec->decor_lineno);
}