FreeCalypso > hg > ueda-linux
view ueda/sverp/elaborate.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 | 7b4f78fcca08 |
children |
line wrap: on
line source
/* * Here we elaborate the hierarchy and create our flat netlist. */ #include <stdio.h> #include <stdlib.h> #include <string.h> #include <strings.h> #include "struct.h" #include "lexer.h" /* for MAXDIGITS */ 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++; } }