FreeCalypso > hg > ueda-linux
diff ueda/sverp/elaborate.c @ 0:cd92449fdb51
initial import of ueda and ifctf-part-lib from ifctfvax CVS
author | Space Falcon <falcon@ivan.Harhan.ORG> |
---|---|
date | Mon, 20 Jul 2015 00:24:37 +0000 |
parents | |
children | 7b4f78fcca08 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ueda/sverp/elaborate.c Mon Jul 20 00:24:37 2015 +0000 @@ -0,0 +1,392 @@ +/* + * Here we elaborate the hierarchy and create our flat netlist. + */ + +#include <stdio.h> +#include <strings.h> +#include "struct.h" +#include "lexer.h" /* for MAXDIGITS */ + +extern char *malloc(); + +struct output_net *output_net_head; +struct output_element *output_element_head; +int total_good_nets, total_singular_nets, total_null_nets; +int total_output_elements; + +static struct output_net **output_net_tail = &output_net_head; +static struct output_element **output_element_tail = &output_element_head; + +static struct output_net ** +alloc_mod_net_array(mod) + struct module_def *mod; +{ + int total_wires; + unsigned alloc_size; + register struct output_net **array; + + total_wires = mod->nwires_ports + mod->nwires_internal; + alloc_size = sizeof(struct output_net *) * total_wires; + array = (struct output_net **) malloc(alloc_size); + if (!array) { + perror("malloc"); + exit(1); + } + return(array); +} + +static struct output_net ** +alloc_connect_net_array(mod) + struct module_def *mod; +{ + register unsigned alloc_size; + register struct output_net **array; + + alloc_size = sizeof(struct output_net *) * mod->nwires_ports; + array = (struct output_net **) malloc(alloc_size); + if (!array) { + perror("malloc"); + exit(1); + } + bzero(array, alloc_size); + return(array); +} + +static struct output_net * +create_real_net(hier_prefix, base_name, is_bus, bus_pos) + char *hier_prefix, *base_name; +{ + int len; + register char *buf; + register struct output_net *net; + + len = sizeof(struct output_net) + strlen(hier_prefix) + + strlen(base_name) + 1; + if (is_bus) + len += MAXDIGITS + 2; + buf = malloc(len); + if (!buf) { + perror("malloc"); + exit(1); + } + net = (struct output_net *) buf; + bzero(net, sizeof(struct output_net)); + buf += sizeof(struct output_net); + if (is_bus) + sprintf(buf, "%s%s[%d]", hier_prefix, base_name, bus_pos); + else + sprintf(buf, "%s%s", hier_prefix, base_name); + net->name = buf; + *output_net_tail = net; + output_net_tail = &net->next; + return(net); +} + +static void +create_module_nets(mod, hier_prefix, fillp) + struct module_def *mod; + char *hier_prefix; + register struct output_net **fillp; +{ + register struct module_net_def *nd; + register int i, incr; + + for (nd = mod->nets; nd; nd = nd->next) { + if (nd->is_port) + continue; + if (!nd->is_bus) { + *fillp++ = create_real_net(hier_prefix, nd->name, 0); + continue; + } + if (nd->bus_msb < nd->bus_lsb) + incr = 1; + else + incr = -1; + for (i = nd->bus_msb; i != nd->bus_lsb + incr; i += incr) + *fillp++ = create_real_net(hier_prefix, nd->name, 1, i); + } +} + +elaborate_module(mod, inst_name, hier_prefix, in_conn_array) + register struct module_def *mod; + char *inst_name, *hier_prefix; + struct output_net **in_conn_array; +{ + register struct output_net **mod_net_array; + register struct module_def_subinst *sub; + + if (mod->nwires_internal) { + mod_net_array = alloc_mod_net_array(mod); + if (mod->nwires_ports) + bcopy(in_conn_array, mod_net_array, + sizeof(struct output_net *) * mod->nwires_ports); + create_module_nets(mod, hier_prefix, + mod_net_array + mod->nwires_ports); + } else + mod_net_array = in_conn_array; + + for (sub = mod->subinst; sub; sub = sub->next) + elaborate_subinst(mod, inst_name, hier_prefix, mod_net_array, + sub); + + if (mod->nwires_internal) + free(mod_net_array); +} + +static void +report_connect_conflict(new_inst, ce, offset) + char *new_inst; + struct connect_entry *ce; + int offset; +{ + register struct module_net_def *port = ce->down_portdef; + int bus_pos; + + if (port->is_bus) { + offset += ce->down_offset; + if (port->bus_msb > port->bus_lsb) + bus_pos = port->bus_msb - offset; + else + bus_pos = port->bus_msb + offset; + fprintf(stderr, + "elaborating %s: multiple connections to port %s[%d]\n", + new_inst, port->name, bus_pos); + } else + fprintf(stderr, + "elaborating %s: multiple connections to port %s\n", + new_inst, port->name); + exit(1); +} + +static void +check_connect_conflict(new_inst, ce, conn_array) + char *new_inst; + register struct connect_entry *ce; + register struct output_net **conn_array; +{ + register int start, i; + + start = ce->down_portdef->array_index + ce->down_offset; + for (i = 0; i < ce->down_width; i++) + if (conn_array[start + i]) + report_connect_conflict(new_inst, ce, i); +} + +static struct output_net * +create_nc_net(mup, old_inst, ce) + struct module_def *mup; + char *old_inst; + struct connect_entry *ce; +{ + register struct output_net *net; + + net = (struct output_net *) malloc(sizeof(struct output_net)); + if (!net) { + perror("malloc"); + exit(1); + } + bzero(net, sizeof(struct output_net)); + net->nc_module_name = mup->name; + net->nc_module_lineno = ce->src_lineno; + net->nc_module_inst = old_inst; + return(net); +} + +static struct output_net * +process_subinst_connect(mup, sub, old_inst, new_inst, mod_net_array, conn_array) + struct module_def *mup; + struct module_def_subinst *sub; + char *old_inst, *new_inst; + struct output_net **mod_net_array; + register struct output_net **conn_array; +{ + struct output_net *nc_head = 0, **nc_tail = &nc_head; + register struct connect_entry *ce; + int start; + register int i; + register struct output_net *nc_net; + + for (ce = sub->connections; ce; ce = ce->next) { + check_connect_conflict(new_inst, ce, conn_array); + if (ce->up_netdef) { + bcopy(mod_net_array + ce->up_netdef->array_index + + ce->up_offset, + conn_array + ce->down_portdef->array_index + + ce->down_offset, + sizeof(struct output_net *) * ce->up_width); + continue; + } + /* it's a no-connect */ + start = ce->down_portdef->array_index + ce->down_offset; + for (i = 0; i < ce->down_width; i++) { + nc_net = create_nc_net(mup, old_inst, ce); + conn_array[start + i] = nc_net; + *nc_tail = nc_net; + nc_tail = &nc_net->next; + } + } + return(nc_head); +} + +static void +report_missing_connect(new_inst, port, offset) + char *new_inst; + register struct module_net_def *port; + int offset; +{ + int bus_pos; + + if (port->is_bus) { + if (port->bus_msb > port->bus_lsb) + bus_pos = port->bus_msb - offset; + else + bus_pos = port->bus_msb + offset; + fprintf(stderr, + "elaborating %s: missing connection to port %s[%d]\n", + new_inst, port->name, bus_pos); + } else + fprintf(stderr, + "elaborating %s: missing connection to port %s\n", + new_inst, port->name); + exit(1); +} + +static void +check_missing_connect(new_inst, mdown, conn_array) + char *new_inst; + struct module_def *mdown; + struct output_net **conn_array; +{ + register struct module_net_def *port; + register struct output_net **connp = conn_array; + register int i; + + for (port = mdown->nets; port; port = port->next) { + if (!port->is_port) + return; /* all ports are upfront */ + if (!port->is_bus) { + if (!*connp++) + report_missing_connect(new_inst, port, 0); + continue; + } + for (i = 0; i < port->bus_width; i++) + if (!*connp++) + report_missing_connect(new_inst, port, i); + } +} + +static void +report_bad_nc_net(net) + register struct output_net *net; +{ + fprintf(stderr, +"error: NC pseudo-net created at module %s line %d inst %s goes to more than one pin\n", + net->nc_module_name, net->nc_module_lineno, + net->nc_module_inst); + exit(1); +} + +static void +check_nc_nets(head) + struct output_net *head; +{ + register struct output_net *net; + + for (net = head; net; net = net->next) + if (net->npoints > 1) + report_bad_nc_net(net); +} + +elaborate_subinst(mup, inst_name, hier_prefix, mod_net_array, sub) + struct module_def *mup; + char *inst_name, *hier_prefix; + struct output_net **mod_net_array; + struct module_def_subinst *sub; +{ + char *new_inst, *new_prefix; + struct module_def *mdown = sub->submod_def; + struct output_net **conn_array, *nc_nets; + + new_inst = malloc(strlen(hier_prefix) + strlen(sub->inst_name) + 1); + if (!new_inst) { + perror("malloc"); + exit(1); + } + sprintf(new_inst, "%s%s", hier_prefix, sub->inst_name); + if (mdown->nports) { + conn_array = alloc_connect_net_array(mdown); + nc_nets = process_subinst_connect(mup, sub, inst_name, new_inst, + mod_net_array, conn_array); + check_missing_connect(new_inst, mdown, conn_array); + } else { + conn_array = 0; + nc_nets = 0; + } + + if (mdown->is_primitive) + elaborate_primitive(mdown, new_inst, conn_array); + else { + new_prefix = malloc(strlen(hier_prefix) + + strlen(sub->inst_name) + 2); + if (!new_prefix) { + perror("malloc"); + exit(1); + } + sprintf(new_prefix, "%s%s.", hier_prefix, sub->inst_name); + elaborate_module(mdown, new_inst, new_prefix, conn_array); + free(new_prefix); + if (conn_array) + free(conn_array); + } + + if (nc_nets) + check_nc_nets(nc_nets); +} + +static void +incr_net_points_for_output_element(elem) + struct output_element *elem; +{ + register struct output_net **p, **endp; + + p = elem->connections; + endp = p + elem->prim_def->nports; + for (; p < endp; p++) + (*p)->npoints++; +} + +elaborate_primitive(mod, inst_name, in_conn_array) + struct module_def *mod; + char *inst_name; + struct output_net **in_conn_array; +{ + register struct output_element *elem; + + elem = (struct output_element *) malloc(sizeof(struct output_element)); + if (!elem) { + perror("malloc"); + exit(1); + } + elem->prim_def = mod; + elem->hier_inst_name = inst_name; + elem->connections = in_conn_array; + elem->next = 0; + *output_element_tail = elem; + output_element_tail = &elem->next; + total_output_elements++; + incr_net_points_for_output_element(elem); +} + +tally_output_nets() +{ + register struct output_net *net; + + for (net = output_net_head; net; net = net->next) { + if (net->npoints > 1) + total_good_nets++; + else if (net->npoints == 1) + total_singular_nets++; + else + total_null_nets++; + } +}