view ueda/unet-utils/unet-destar.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 a93e4b07fdf3
children
line wrap: on
line source

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include <unistd.h>
#include "../libunet/unetrd.h"
#include "../libunet/nethash.h"

extern struct net *enter_net_object();
extern struct net *find_net_by_name();
extern struct net *net_list_head;

static char *input_filename, *output_filename;
static struct unetrd_state rdstate;
static struct unetrd_out rdout;
static int total_input_nets, total_output_nets;
static struct net *starpoint_head;
static FILE *tempFILE, *outFILE;
static int net_comment_column;

struct netextra {
	struct	net *squashed_to;
	int	npoints;
};

static FILE *
tempfile()
{
	char template[16];
	register int fd;
	register FILE *f;

	strcpy(template, "/tmp/uedaXXXXXX");
	fd = mkstemp(template);
	if (fd < 0) {
		perror("mkstemp");
		exit(1);
	}
	unlink(template);
	f = fdopen(fd, "r+w");
	if (!f) {
		perror("fdopen");
		exit(1);
	}
	return(f);
}

static void
dump_tempfile()
{
	register FILE *inf = tempFILE;
	register FILE *outf = outFILE;
	register int c;

	rewind(inf);
	while ((c = getc(inf)) != EOF)
		putc(c, outf);
	fclose(inf);
}

static void
process_starpoint_head()
{
	register struct net *n;
	register struct netextra *nx;

	n = find_net_by_name(rdout.connect_to_net);
	for (;;) {
		nx = (struct netextra *)(n + 1);
		if (!nx->squashed_to)
			break;
		n = nx->squashed_to;
	}
	starpoint_head = n;
}

static void
process_starpoint_arm()
{
	register struct net *n;
	register struct netextra *nx;

	n = find_net_by_name(rdout.connect_to_net);
	if (n == starpoint_head) {
		fprintf(stderr,
			"%s line %d: starpoint between net %s and itself!\n",
			input_filename, rdstate.lineno, n->name);
		exit(1);
	}
	nx = (struct netextra *)(n + 1);
	if (nx->squashed_to) {
		fprintf(stderr,
			"%s line %d: net %s has already been squashed\n",
			input_filename, rdstate.lineno, n->name);
		exit(1);
	}
	nx->squashed_to = starpoint_head;
}

static void
process_starpoint()
{
	starpoint_head = 0;
	for (;;) {
		if (!read_unet_line(&rdstate, &rdout)) {
			fprintf(stderr, "%s error: EOF in STARPOINT block\n",
				input_filename);
			exit(1);
		}
		if (rdout.typecode == UNETOBJ_CLOSINGBRACE)
			break;
		switch(rdout.typecode) {
		case UNETOBJ_PRIMITIVE:
		case UNETOBJ_ALTNAME:
		case UNETOBJ_ATTR:
			continue;
		case UNETOBJ_PIN:
			if (!rdout.connect_to_net) {
				fprintf(stderr,
		"%s line %d: no-connect is meaningless for a starpoint arm\n",
					input_filename, rdstate.lineno);
				exit(1);
			}
			if (!starpoint_head)
				process_starpoint_head();
			else
				process_starpoint_arm();
			continue;
		case UNETOBJ_PINMAP:
			fprintf(stderr,
			"%s line %d: PINMAP meaningless in a STARPOINT block\n",
				input_filename, rdstate.lineno);
			exit(1);
		default:
			fprintf(stderr,
		"%s line %d: object type %s unexpected in STARPOINT block\n",
				input_filename, rdstate.lineno, rdout.keyword);
			exit(1);
		}
	}
}

static void
process_component_pin()
{
	register struct net *n;
	register struct netextra *nx;

	if (!rdout.connect_to_net) {
		fprintf(tempFILE, "  %s %s = NC (%s)\n", rdout.keyword,
			rdout.objname, rdout.nc_comment);
		return;
	}
	n = find_net_by_name(rdout.connect_to_net);
	for (;;) {
		nx = (struct netextra *)(n + 1);
		if (!nx->squashed_to)
			break;
		n = nx->squashed_to;
	}
	fprintf(tempFILE, "  %s %s = NET %s\n", rdout.keyword, rdout.objname,
		n->name);
	nx->npoints++;
}

static void
process_component()
{
	fprintf(tempFILE, "\nCOMPONENT %s {\n", rdout.objname);
	for (;;) {
		if (!read_unet_line(&rdstate, &rdout)) {
			fprintf(stderr, "%s error: EOF in COMPONENT block\n",
				input_filename);
			exit(1);
		}
		if (rdout.typecode == UNETOBJ_CLOSINGBRACE)
			break;
		switch(rdout.typecode) {
		case UNETOBJ_PRIMITIVE:
		case UNETOBJ_ALTNAME:
			fprintf(tempFILE, "  %s %s\n", rdout.keyword,
				rdout.objname);
			continue;
		case UNETOBJ_ATTR:
			fprintf(tempFILE, "  ATTR %s=%s\n", rdout.objname,
				rdout.attr_value);
			continue;
		case UNETOBJ_PIN:
		case UNETOBJ_PINMAP:
			process_component_pin();
			continue;
		default:
			fprintf(stderr,
		"%s line %d: object type %s unexpected in COMPONENT block\n",
				input_filename, rdstate.lineno, rdout.keyword);
			exit(1);
		}
	}
	fputs("}\n", tempFILE);
}

static void
process_input_unet()
{
	struct net *n;
	int state = 0;

	open_unet_input_file(input_filename, &rdstate);
	while (read_unet_line(&rdstate, &rdout)) {
		switch(rdout.typecode) {
		case UNETOBJ_CLOSINGBRACE:
			fprintf(stderr,
		"%s line %d: unexpected '}' outside of component block\n",
				input_filename, rdstate.lineno);
			exit(1);
		case UNETOBJ_NET:
			if (state == 0)
				state = 1;
			else if (state > 1) {
				fprintf(stderr,
"error: all input nets must precede all starpoints and components (%s line %d)\n",
					input_filename, rdstate.lineno);
				exit(1);
			}
			n = enter_net_object(rdout.objname,
						sizeof(struct netextra));
			bzero(n + 1, sizeof(struct netextra));
			total_input_nets++;
			continue;
		case UNETOBJ_STARPOINT:
			if (state < 1) {
				fprintf(stderr,
		"error (%s line %d): STARPOINT without any preceding NETs\n",
					input_filename, rdstate.lineno);
				exit(1);
			}
			if (state > 2) {
				fprintf(stderr,
	"error: all STARPOINTs must precede all COMPONENTs (%s line %d)\n",
					input_filename, rdstate.lineno);
				exit(1);
			}
			state = 2;
			process_starpoint();
			continue;
		case UNETOBJ_COMPONENT:
			if (state < 1) {
				fprintf(stderr,
		"error (%s line %d): COMPONENT without any preceding NETs\n",
					input_filename, rdstate.lineno);
				exit(1);
			}
			if (state < 3) {
				tempFILE = tempfile();
				state = 3;
			}
			process_component();
			continue;
		default:
			fprintf(stderr,
				"%s line %d: unexpected object type %s\n",
				input_filename, rdstate.lineno, rdout.keyword);
			exit(1);
		}
	}
}

static void
find_net_comment_column()
{
	register struct net *n;
	register struct netextra *nx;
	register int len, maxlen;

	maxlen = 0;
	for (n = net_list_head; n; n = n->nextinlist) {
		nx = (struct netextra *)(n + 1);
		if (nx->squashed_to)
			continue;
		total_output_nets++;
		len = strlen(n->name);
		if (len > maxlen)
			maxlen = len;
	}
	maxlen += 4;
	do
		maxlen++;
	while (maxlen % 8);
	net_comment_column = maxlen;
}

static void
output_nets()
{
	register struct net *n;
	register struct netextra *nx;
	register int col;

	fprintf(outFILE, "\n# %d input nets reduced to %d joined nets:\n#\n",
		total_input_nets, total_output_nets);
	for (n = net_list_head; n; n = n->nextinlist) {
		nx = (struct netextra *)(n + 1);
		if (nx->squashed_to)
			continue;
		fprintf(outFILE, "NET %s", n->name);
		col = 4 + strlen(n->name);
		do {
			fputc('\t', outFILE);
			col += 8;
			col &= ~7;
		} while (col < net_comment_column);
		fprintf(outFILE, "# %d points\n", nx->npoints);
	}
}

static void
generate_output()
{
	if (output_filename) {
		outFILE = fopen(output_filename, "w");
		if (!outFILE) {
			perror(output_filename);
			exit(1);
		}
	} else
		outFILE = stdout;
	fprintf(outFILE,
		"# This netlist has been generated by unet-destar from %s\n",
		input_filename);
	output_nets();
	dump_tempfile();
	if (outFILE != stdout)
		fclose(outFILE);
}

main(argc, argv)
	char **argv;
{
	if (argc < 2 || argc > 3) {
		fprintf(stderr, "usage: %s input.unet [output.unet]\n",
			argv[0]);
		exit(1);
	}
	input_filename = argv[1];
	output_filename = argv[2];
	process_input_unet();
	find_net_comment_column();
	generate_output();
	exit(0);
}