FreeCalypso > hg > ueda-linux
diff ueda/sverp/link.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/link.c Mon Jul 20 00:24:37 2015 +0000 @@ -0,0 +1,198 @@ +/* + * ueda-sverp link pass + */ + +#include <stdio.h> +#include <strings.h> +#include "struct.h" + +extern struct module_def *glob_module_list, *top_module_def; +extern int top_module_candidates; + +extern struct module_def *find_module_by_name(); + +static void +toplevel_candidate(mod) + struct module_def *mod; +{ + top_module_candidates++; + if (!top_module_def) + top_module_def = mod; +} + +static struct module_net_def * +find_port_by_name(mod, portname) + struct module_def *mod; + register char *portname; +{ + register struct module_net_def *n; + + for (n = mod->nets; n; n = n->next) + if (!strcmp(n->name, portname)) + break; + if (n && n->is_port) + return(n); + else + return(0); +} + +static void +handle_downport_range(mup, ins, conn) + struct module_def *mup; + struct module_def_subinst *ins; + register struct connect_entry *conn; +{ + register struct module_net_def *port; + + port = conn->down_portdef; + if (!port->is_bus) { + fprintf(stderr, +"module %s line %d: mod %s port %s is not a bus, range spec is meaningless\n", + mup->name, conn->src_lineno, ins->submod_name, + port->name); + exit(1); + } + if (port->bus_msb > port->bus_lsb) { + if (conn->down_range_msb < conn->down_range_lsb) { +error_reversed: fprintf(stderr, + "module %s line %d: reversed range on bus port %s\n", + mup->name, conn->src_lineno, port->name); + exit(1); + } + if (conn->down_range_msb > port->bus_msb) { +error_outofrange: fprintf(stderr, + "module %s line %d: subrange on bus port %s exceeds full bus range\n", + mup->name, conn->src_lineno, port->name); + exit(1); + } + if (conn->down_range_lsb < port->bus_lsb) + goto error_outofrange; + conn->down_offset = port->bus_msb - conn->down_range_msb; + conn->down_width = conn->down_range_msb - conn->down_range_lsb + + 1; + } else { + if (conn->down_range_msb > conn->down_range_lsb) + goto error_reversed; + if (conn->down_range_msb < port->bus_msb) + goto error_outofrange; + if (conn->down_range_lsb > port->bus_lsb) + goto error_outofrange; + conn->down_offset = conn->down_range_msb - port->bus_msb; + conn->down_width = conn->down_range_lsb - conn->down_range_msb + + 1; + } +} + +static void +connect_by_name(mup, ins) + struct module_def *mup; + register struct module_def_subinst *ins; +{ + register struct connect_entry *conn; + register struct module_net_def *port; + + for (conn = ins->connections; conn; conn = conn->next) { + port = find_port_by_name(ins->submod_def, conn->down_portname); + if (!port) { + fprintf(stderr, + "instance %s in module %s: lower module %s has no port named \"%s\"\n", + ins->inst_name, mup->name, + ins->submod_name, conn->down_portname); + exit(1); + } + conn->down_portdef = port; + if (conn->down_range_given) + handle_downport_range(mup, ins, conn); + else { + conn->down_offset = 0; + conn->down_width = port->bus_width; + } + } +} + +static void +connect_by_order(mup, ins) + struct module_def *mup; + register struct module_def_subinst *ins; +{ + struct module_def *mdown; + register struct module_net_def *port; + register struct connect_entry *conn; + + mdown = ins->submod_def; + if (ins->connect_by_order != mdown->nports) { + fprintf(stderr, +"instance %s in module %s: connect by order port count mismatch (%d ports, %d connections)\n", + ins->inst_name, mup->name, mdown->nports, + ins->connect_by_order); + exit(1); + } + for (conn = ins->connections, port = mdown->nets; conn; + conn = conn->next, port = port->next) { + conn->down_portdef = port; + conn->down_offset = 0; + conn->down_width = port->bus_width; + } +} + +static void +check_width_match(mup, ins) + struct module_def *mup; + struct module_def_subinst *ins; +{ + register struct connect_entry *conn; + + for (conn = ins->connections; conn; conn = conn->next) + if (conn->up_netdef && conn->up_width != conn->down_width) { + fprintf(stderr, + "module %s line %d: width mismatch on connection to port %s\n", + mup->name, conn->src_lineno, + conn->down_portdef->name); + exit(1); + } +} + +static void +linkpass_process_inst(mup, ins) + struct module_def *mup; + register struct module_def_subinst *ins; +{ + register struct module_def *mdown; + + mdown = find_module_by_name(ins->submod_name); + if (!mdown) { + fprintf(stderr, + "instance %s in module %s: lower module \"%s\" not found\n", + ins->inst_name, mup->name, ins->submod_name); + exit(1); + } + ins->submod_def = mdown; + if (ins->connect_by_order) + connect_by_order(mup, ins); + else + connect_by_name(mup, ins); + check_width_match(mup, ins); +} + +static void +linkpass_process_mod(mod) + struct module_def *mod; +{ + register struct module_def_subinst *ins; + + for (ins = mod->subinst; ins; ins = ins->next) + linkpass_process_inst(mod, ins); +} + +link_pass() +{ + register struct module_def *m; + + for (m = glob_module_list; m; m = m->next) { + if (m->is_primitive) + continue; + if (!m->nports) + toplevel_candidate(m); + linkpass_process_mod(m); + } +}