Logo Search packages:      
Sourcecode: faumachine version File versions  Download package

faum-gnetlist.c

/* $Id: faum-gnetlist.c,v 1.93 2009-01-30 15:19:09 vrsieh Exp $ 
 *
 * Copyright (C) 2008-2009 FAUmachine Team <info@faumachine.org>.
 * This program is free software. You can redistribute it and/or modify it
 * under the terms of the GNU General Public License, either version 2 of
 * the License, or (at your option) any later version. See COPYING.
 */

#define DEBUG     0

#include <assert.h>
#include <errno.h>
#include <getopt.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

struct sig {
      struct sig *next;
      struct sig *prev;

      const char *name;
      const char *type;
      int is_port;
};
struct port {
      struct port *next;
      struct port *prev;

      char *name;
      char *type;

      struct sig *sig;
};

struct comp {
      int x;
      int y;
      unsigned int rotate;
      unsigned int mirror;
      char *sym_file;

      struct el *con_first;
      struct el *con_last;
};
struct net {
      int x0;
      int y0;
      int x1;
      int y1;

      struct sig *sig;
};
struct pin {
      int x0;
      int y0;
      int x1;
      int y1;
      unsigned int color;

      struct sig *sig;
};
struct text {
      int x;
      int y;
      unsigned int color;
      unsigned int size;
      unsigned int visible;
      unsigned int hide;      /* 1: Hide name, 2: Hide value */
      unsigned int angle;
      unsigned int align;
      char *str[128];
};
struct bus {
      int x0;
      int y0;
      int x1;
      int y1;
      unsigned int color;

      struct sig *sig;
};
struct el {
      struct el *prev;
      struct el *next;

      struct el *child_first;
      struct el *child_last;

      enum {
            COMP, NET, PIN, TEXT, BUS
      } type;
      union {
            struct comp comp;
            struct net net;
            struct pin pin;
            struct text text;
            struct bus bus;
      } u;
};

char *progname;
char *inname;

static const struct {
      const char *from;
      const char *to;
      const char *include;
} sig_translate[] = {
      /* Keep sorted! */
      { "agp_bus", "sig_agp_bus", "sig_agp_bus.h" },
      { "agp_bus_main", "sig_agp_bus_main", "sig_agp_bus.h" },
      { "boolean", "sig_boolean", "sig_boolean.h" },
      { "boolean_or", "sig_boolean_or", "sig_boolean_or.h" },
      { "cs", "sig_cs", "sig_cs.h" },
      { "dio24", "sig_dio24", "sig_dio24.h" },
      { "dio48", "sig_dio48", "sig_dio48.h" },
      { "eth", "sig_eth", "sig_eth.h" },
      { "fault", "sig_fault", "sig_fault.h" },
      { "host_bus", "sig_host_bus", "sig_host_bus.h" },
      { "host_bus_main", "sig_host_bus_main", "sig_host_bus.h" },
      { "i2c_bus", "sig_i2c_bus", "sig_i2c_bus.h" },
      { "icc_bus", "sig_icc_bus", "sig_icc_bus.h" },
      { "ide_bus", "sig_ide_bus", "sig_ide_bus.h" },
      { "integer", "sig_integer", "sig_integer.h" },
      { "isa_bus", "sig_isa_bus", "sig_isa_bus.h" },
      { "isa_bus_dma", "sig_isa_bus_dma", "sig_isa_bus.h" },
      { "isa_bus_main", "sig_isa_bus_main", "sig_isa_bus.h" },
      { "mem_bus", "sig_mem_bus", "sig_mem_bus.h" },
      { "mem_bus_main", "sig_mem_bus_main", "sig_mem_bus.h" },
      { "parallel", "sig_parallel", "sig_parallel.h" },
      { "pci_bus", "sig_pci_bus", "sig_pci_bus.h" },
      { "pci_bus_idsel", "sig_pci_bus_idsel", "sig_pci_bus.h" },
      { "pci_bus_main", "sig_pci_bus_main", "sig_pci_bus.h" },
      { "power_board", "sig_power_board", "sig_power.h" },
      { "power_board_at", "sig_power_board_at", "sig_power.h" },
      { "power_device", "sig_power_device", "sig_power.h" },
      { "ps2", "sig_ps2", "sig_ps2.h" },
      { "scsi_bus", "sig_scsi_bus", "sig_scsi_bus.h" },
      { "serial", "sig_serial", "sig_serial.h" },
      { "shugart_bus", "sig_shugart_bus", "sig_shugart_bus.h" },
      { "sound", "sig_sound", "sig_sound.h" },
      { "std_logic", "sig_std_logic", "sig_std_logic.h" },
      { "usb_bus", "sig_usb_bus", "sig_usb_bus.h" },
      { "usb_bus_main", "sig_usb_bus_main", "sig_usb_bus.h" },
      { "vga", "sig_vga", "sig_vga.h" },
      { "video", "sig_video", "sig_video.h" },
      { NULL, NULL, NULL }
};

static struct entry {
      const char *port;
      unsigned int seq;
      struct sig *sig;
} entry[1000];
static unsigned int nentries;

static void
table_init(void)
{
      nentries = 0;
}

static void
table_add(const char *label, const char *seq, struct sig *sig)
{
      entry[nentries].port = label;
      if (seq) {
            entry[nentries].seq = atoi(seq);
      } else {
            entry[nentries].seq = 0;
      }
      entry[nentries].sig = sig;
      nentries++;
}

static void
table_sort(void)
{
      unsigned int i;
      int done;

      if (nentries <= 1) {
            /* Nothing to sort... */
            return;
      }

      do {
            done = 1;
            for (i = 0; i < nentries - 1; i++) {
                  if (entry[i + 1].seq < entry[i].seq
                   || (entry[i + 1].seq == entry[i].seq
                    && strcmp(entry[i + 1].port, entry[i].port) < 0)) {
                        const char *port_tmp;
                        unsigned int seq_tmp;
                        struct sig *sig_tmp;

                        port_tmp = entry[i].port;
                        seq_tmp = entry[i].seq;
                        sig_tmp = entry[i].sig;
                        entry[i].port = entry[i + 1].port;
                        entry[i].seq = entry[i + 1].seq;
                        entry[i].sig = entry[i + 1].sig;
                        entry[i + 1].port = port_tmp;
                        entry[i + 1].seq = seq_tmp;
                        entry[i + 1].sig = sig_tmp;
                        done = 0;
                  }
            }
      } while (! done);
}

static const char *
sig_type(const char *s)
{
      unsigned int i;

      for (i = 0; ; i++) {
            if (sig_translate[i].from == NULL) {
                  fprintf(stderr, "ERROR: %s: %s: unknown signal type.\n",
                              progname, s);
                  return s;
            }
            if (strcmp(sig_translate[i].from, s) == 0) {
                  return sig_translate[i].to;
            }
      }
}

static const char *
sig_include(const char *s)
{
      unsigned int i;

      for (i = 0; ; i++) {
            if (sig_translate[i].from == NULL) {
                  fprintf(stderr, "ERROR: %s: %s: unknown signal type.\n",
                              progname, s);
                  return s;
            }
            if (strcmp(sig_translate[i].from, s) == 0) {
                  return sig_translate[i].include;
            }
      }
}

static void
mangle(char *buf, const char *real)
{
      char c;

      while ((c = *real++) != '\0') {
            switch (c) {
            case '0' ... '9':
            case 'A' ... 'Z':
            case 'a' ... 'z':
            case '_':
                  *buf++ = c;
                  break;
            case '.':
                  *buf++ = '_';
                  break;
            case '#':
                  *buf++ = '_';
                  *buf++ = 'h';
                  *buf++ = 'a';
                  *buf++ = 's';
                  *buf++ = 'h';
                  *buf++ = '_';
                  break;
            case '+':
                  *buf++ = '_';
                  *buf++ = 'p';
                  *buf++ = 'l';
                  *buf++ = 'u';
                  *buf++ = 's';
                  *buf++ = '_';
                  break;
            case '-':
                  *buf++ = '_';
                  *buf++ = 'm';
                  *buf++ = 'i';
                  *buf++ = 'n';
                  *buf++ = 'u';
                  *buf++ = 's';
                  *buf++ = '_';
                  break;
            default:
                  fprintf(stderr, "ERROR: %s: Bad character '%c' in signal name.\n",
                              progname, c);
                  break;
            }
      }
      *buf = '\0';
}

static const char *
name(const char *real)
{
      static char buf[10][100];
      static unsigned int bufno = 0;

      bufno %= 10;

      mangle(&buf[bufno][0], real);

      return buf[bufno++];
}

static const char *
sig_name(const char *real)
{
      static char buf[10][100];
      static unsigned int bufno = 0;

      bufno %= 10;

      strcpy(buf[bufno], "sig_");
      mangle(&buf[bufno][strlen("sig_")], real);

      return buf[bufno++];
}

static const char *
port_name(const char *real)
{
      static char buf[10][100];
      static unsigned int bufno = 0;

      bufno %= 10;

      strcpy(buf[bufno], "port_");
      mangle(&buf[bufno][strlen("port_")], real);

      return buf[bufno++];
}

static const char *
ident_tmp(void)
{
      static unsigned int nr = 0;
      char tmp[100];

      sprintf(tmp, "tmp%06u", nr++);
      return strdup(tmp);
}

int
_ungetc(int c, FILE *stream)
{
      if (c != EOF) {
            return ungetc(c, stream);
      } else {
            return c;
      }
}

void
skip_white(FILE *fp)
{
      int c;

      c = fgetc(fp);
      while (c == '\t'
          || c == '\n'
          || c == '\r'
          || c == ' ') {
            c = fgetc(fp);
      }
      _ungetc(c, fp);
}

int
read_char(FILE *fp, char *cp)
{
      int c;

      skip_white(fp);

      c = fgetc(fp);

      if (c == EOF
       || c == '\0') {
            return EOF;
      } else {
            *cp = c;
            return 0;
      }
}

int
read_int(FILE *fp, int *ip)
{
      int sign;
      int c;

      skip_white(fp);

      *ip = 0;
      c = fgetc(fp);
      if (c == '-') {
            sign = -1;
            c = fgetc(fp);
      } else {
            sign = 1;
      }
      while ('0' <= c && c <= '9') {
            *ip *= 10;
            *ip += c - '0';
            c = fgetc(fp);
      }
      _ungetc(c, fp);

      *ip *= sign;

      return 0;
}

int
read_ident(FILE *fp, char *ident)
{
      int c;
      int x;

      skip_white(fp);

      x = 0;
      c = fgetc(fp);
      while (c != EOF
          && c != '\0'
          && c != '\t'
          && c != '\n'
          && c != '\r'
          && c != ' ') {
            ident[x++] = c;
            c = fgetc(fp);
      }
      ident[x] = '\0';
      _ungetc(c, fp);

      return 0;
}

int
read_line(FILE *fp, char *ident)
{
      int c;
      int x;

      c = fgetc(fp);
      while (c != '\n') {
            c = fgetc(fp);
      }

      x = 0;
      c = fgetc(fp);
      while (c != EOF
          && c != '\0'
          && c != '\n'
          && c != '\r') {
            ident[x++] = c;
            c = fgetc(fp);
      }
      ident[x] = '\0';
      _ungetc(c, fp);

      return 0;
}

/*forward*/ static int
readp_sub(FILE *fp, struct el **firstp, struct el **lastp);

static int
read_list(FILE *fp, struct el **firstp, struct el **lastp)
{
      int ret;
      char c;
      int num;
      int i;
      char ident[1024];
      struct el *e;

      *firstp = NULL;
      *lastp = NULL;

      for (;;) {
            ret = read_char(fp, &c);
            if (ret == EOF) {
                  _ungetc(EOF, fp);
                  break;
            }
            if (c == ']'
             || c == '}') {
                  _ungetc(c, fp);
                  break;
            }

            switch (c) {
            case '{':
            case '[':
                  assert(0);
                  break;
            case 'A':
                  /* Arc */
                  e = NULL;

                  read_int(fp, &num);
                  read_int(fp, &num);
                  read_int(fp, &num);
                  read_int(fp, &num);
                  read_int(fp, &num);
                  read_int(fp, &num);
                  read_int(fp, &num);
                  read_int(fp, &num);
                  read_int(fp, &num);
                  read_int(fp, &num);
                  read_int(fp, &num);
                  break;
            case 'B':
                  /* Box */
                  e = NULL;

                  read_int(fp, &num);
                  read_int(fp, &num);
                  read_int(fp, &num);
                  read_int(fp, &num);
                  read_int(fp, &num);
                  read_int(fp, &num);
                  read_int(fp, &num);
                  read_int(fp, &num);
                  read_int(fp, &num);
                  read_int(fp, &num);
                  read_int(fp, &num);
                  read_int(fp, &num);
                  read_int(fp, &num);
                  read_int(fp, &num);
                  read_int(fp, &num);
                  read_int(fp, &num);
                  break;
            case 'C':
                  /* Component */
                  e = malloc(sizeof(*e));
                  assert(e);
                  memset(e, 0, sizeof(*e));
                  e->type = COMP;
                  read_int(fp, &e->u.comp.x); /* X Coord */
                  read_int(fp, &e->u.comp.y); /* Y Coord */
                  read_int(fp, &num);
                  read_int(fp, &e->u.comp.rotate); /* Rotate */
                  read_int(fp, &e->u.comp.mirror); /* Mirror */
                  read_ident(fp, ident); /* Sym File */
                  e->u.comp.sym_file = strdup(ident);
                  assert(e->u.comp.sym_file);
                  assert(e->u.comp.sym_file[0]);
                  readp_sub(fp, &e->child_first, &e->child_last);
                  break;
            case 'L':
                  e = NULL;

                  read_int(fp, &num); /* Start X */
                  read_int(fp, &num); /* Start Y */
                  read_int(fp, &num); /* End X */
                  read_int(fp, &num); /* End Y */
                  read_int(fp, &num); /* Color */
                  read_int(fp, &num); /* Width */
                  read_int(fp, &num);
                  read_int(fp, &num);
                  read_int(fp, &num);
                  read_int(fp, &num);
                  break;
            case 'N':
                  /* Single Signal */
                  e = malloc(sizeof(*e));
                  assert(e);
                  memset(e, 0, sizeof(*e));
                  e->type = NET;
                  read_int(fp, &e->u.net.x0); /* Start X */
                  read_int(fp, &e->u.net.y0); /* Start Y */
                  read_int(fp, &e->u.net.x1); /* End Y */
                  read_int(fp, &e->u.net.y1); /* End Y */
                  read_int(fp, &num); /* Color */
                  readp_sub(fp, &e->child_first, &e->child_last);
                  break;
            case 'P':
                  /* Pin */
                  e = malloc(sizeof(*e));
                  assert(e);
                  memset(e, 0, sizeof(*e));
                  e->type = PIN;
                  read_int(fp, &e->u.pin.x0); /* Start X */
                  read_int(fp, &e->u.pin.y0); /* Start Y */
                  read_int(fp, &e->u.pin.x1); /* End X */
                  read_int(fp, &e->u.pin.y1); /* End Y */
                  read_int(fp, &e->u.pin.color); /* Color */
                  read_int(fp, &num); /* ? */
                  read_int(fp, &num); /* ? */
                  readp_sub(fp, &e->child_first, &e->child_last);
                  break;
            case 'T': /* Text */
                  e = malloc(sizeof(*e));
                  assert(e);
                  memset(e, 0, sizeof(*e));
                  e->type = TEXT;
                  read_int(fp, &e->u.text.x);
                  read_int(fp, &e->u.text.y);
                  read_int(fp, &e->u.text.color);
                  read_int(fp, &e->u.text.size);
                  read_int(fp, &e->u.text.visible);
                  read_int(fp, &e->u.text.hide);
                  read_int(fp, &e->u.text.angle);
                  read_int(fp, &e->u.text.align);
                  read_int(fp, &num); /* Number of Lines */
                  for (i = 0; i < num; i++) {
                        read_line(fp, ident);
                        e->u.text.str[i] = strdup(ident);
                        assert(e->u.text.str[i]);
                  }
                  break;
            case 'U':
                  /* Bus */
                  e = malloc(sizeof(*e));
                  assert(e);
                  memset(e, 0, sizeof(*e));
                  e->type = BUS;
                  read_int(fp, &e->u.bus.x0); /* Start X */
                  read_int(fp, &e->u.bus.y0); /* Start Y */
                  read_int(fp, &e->u.bus.x1); /* End X */
                  read_int(fp, &e->u.bus.y1); /* End Y */
                  read_int(fp, &e->u.bus.color); /* Color */
                  read_int(fp, &num);
                  readp_sub(fp, &e->child_first, &e->child_last);
                  break;
            case 'V':
                  /* Circle */
                  e = NULL;

                  read_int(fp, &num);
                  read_int(fp, &num);
                  read_int(fp, &num);
                  read_int(fp, &num);
                  read_int(fp, &num);
                  read_int(fp, &num);
                  read_int(fp, &num);
                  read_int(fp, &num);
                  read_int(fp, &num);
                  read_int(fp, &num);
                  read_int(fp, &num);
                  read_int(fp, &num);
                  read_int(fp, &num);
                  read_int(fp, &num);
                  read_int(fp, &num);
                  break;
            case 'v': /* Version of gschem */
                  e = NULL;

                  read_int(fp, &num);
                  read_int(fp, &num);
                  break;
            default:
                  fprintf(stderr, "c=%c\n", c);
                  assert(0);
            }

            if (e) {
                  e->prev = *lastp;
                  e->next = NULL;
                  if (e->prev) {
                        e->prev->next = e;
                  } else {
                        *firstp = e;
                  }
                  *lastp = e;
            }
      }

      return 0;
}

static int
readp_sub(FILE *fp, struct el **firstp, struct el **lastp)
{
      char c;
      int ret;

      ret = read_char(fp, &c);
      if (ret == EOF) {
            _ungetc(EOF, fp);
            *firstp = NULL;
            *lastp = NULL;
            return EOF;
      }
      if (c != '{') {
            _ungetc(c, fp);
            *firstp = NULL;
            *lastp = NULL;
            return EOF;
      }

      read_list(fp, firstp, lastp);

      ret = read_char(fp, &c);
      assert(ret != EOF
          && c == '}');

      return 0;
}

static const char *
lookup_str(struct el *e, const char *n)
{
      if (e->type == TEXT
       && e->u.text.str[0]
       && strncmp(e->u.text.str[0], n, strlen(n)) == 0
       && e->u.text.str[0][strlen(n)] == '=') {
            return &e->u.text.str[0][strlen(n) + 1];
      } else {
            return NULL;
      }
}

static const char *
lookup_n(struct el *e, const char *str, unsigned int n)
{
      struct el *ce;
      const char *value;

      for (ce = e->child_first; ce; ce = ce->next) {
            value = lookup_str(ce, str);
            if (value) {
                  if (n == 0) {
                        return value;
                  } else {
                        n--;
                  }
            }
      }
      if (e->type == COMP) {
            for (ce = e->u.comp.con_first; ce; ce = ce->next) {
                  value = lookup_str(ce, str);
                  if (value) {
                        if (n == 0) {
                              return value;
                        } else {
                              n--;
                        }
                  }
            }
      }
      return NULL;
}

static const char *
lookup(struct el *e, const char *str)
{
      return lookup_n(e, str, 0);
}

#define MIN(x, y) (((x) < (y)) ? (x) : (y))
#define MAX(x, y) (((x) < (y)) ? (y) : (x))

static int
connected_point_line(
      int x,
      int y,
      int x0,
      int y0,
      int x1,
      int y1
)
{
      if (x == x0 && y == y0) {
            return 1;
      } else if (x == x1 && y == y1) {
            return 1;
      } else if (x0 == x1) {
            if (x == x0
             && MIN(y0, y1) <= y && y <= MAX(y0, y1)) {
                  return 1;
            } else {
                  return 0;
            }
      } else if (y0 == y1) {
            if (y == y0
             && MIN(x0, x1) <= x && x <= MAX(x0, x1)) {
                  return 1;
            } else {
                  return 0;
            }
      } else {
#if DEBUG
            static int count = 0;

            if (count < 10) {
                  fprintf(stderr, "WARNING: x0=%d, y0=%d, x1=%d, y1=%d\n",
                              x0, y0, x1, y1);
                  count++;
            } else if (count == 10) {
                  fprintf(stderr, "WARNING: more warnings following...\n");
                  count++;
            }
#endif

            return 0;
      }
}

static int
connected_line_line(
      int xa0,
      int ya0,
      int xa1,
      int ya1,
      int xb0,
      int yb0,
      int xb1,
      int yb1
)
{
      return connected_point_line(xa0, ya0, xb0, yb0, xb1, yb1)
          || connected_point_line(xa1, ya1, xb0, yb0, xb1, yb1)
          || connected_point_line(xb0, yb0, xa0, ya0, xa1, ya1)
          || connected_point_line(xb1, yb1, xa0, ya0, xa1, ya1);
}

static void
connect_to(
      const char *comp_type,
      const char *comp_name,
      unsigned int level,
      struct sig *sig,
      int x0,
      int y0,
      int x1,
      int y1,
      struct el *first,
      struct el *last
)
{
      struct el *e;

      for (e = first; e; e = e->next) {
            switch (e->type) {
            case COMP: {
                  int x0_new;
                  int y0_new;
                  int x1_new;
                  int y1_new;
                  int tmp;

                  x0_new = x0 - e->u.comp.x;
                  y0_new = y0 - e->u.comp.y;
                  x1_new = x1 - e->u.comp.x;
                  y1_new = y1 - e->u.comp.y;

                  /*
                   * Note:
                   * If component was rotated by 90 counterclockwise
                   * we must back-rotate by 90 clockwise!
                   */
                  switch (e->u.comp.rotate) {
                  case 0:
                        /* Nothing to do... */
                        break;
                  case 90:
                        /* x'=y, y'=-x */
                        tmp = x0_new;
                        x0_new = y0_new;
                        y0_new = -tmp;

                        tmp = x1_new;
                        x1_new = y1_new;
                        y1_new = -tmp;
                        break;
                  case 180:
                        /* x'=-x, y'=-y */
                        x0_new = -x0_new;
                        y0_new = -y0_new;

                        x1_new = -x1_new;
                        y1_new = -y1_new;
                        break;
                  case 270:
                        /* x'=-y, y'=x */
                        tmp = x0_new;
                        x0_new = -y0_new;
                        y0_new = tmp;

                        tmp = x1_new;
                        x1_new = -y1_new;
                        y1_new = tmp;
                        break;
                  default:
                        assert(0);
                  }

                  assert(e->u.comp.mirror == 0);
                  connect_to(lookup(e, "device"), lookup(e, "refdes"),
                              level + 1, sig,
                              x0_new, y0_new, x1_new, y1_new,
                              e->u.comp.con_first, e->u.comp.con_last);
                  break;
                }
            case NET:
                  if ((sig->name
                    && lookup(e, "netname")
                    && strcmp(sig->name, lookup(e, "netname")) == 0)
                   || connected_line_line(
                              e->u.net.x0, e->u.net.y0,
                              e->u.net.x1, e->u.net.y1,
                              x0, y0, x1, y1)) {
                        if (e->u.net.sig == sig) {
                              /* Nothing to do... */
                        } else if (e->u.net.sig != NULL) {
                              assert(0);
                        } else {
                              const char *netname;

                              e->u.net.sig = sig;

                              netname = lookup(e, "netname");
                              if (netname) {
                                    if (sig->name) {
                                          if (strcmp(sig->name, netname) != 0) {
                                                fprintf(stderr, "ERROR: signal \"%s\" connected to signal \"%s\".\n", netname, sig->name);
                                          }
                                    } else {
                                          sig->name = netname;
                                    }
                              }

                              connect_to(comp_type, comp_name,
                                          level, sig,
                                          e->u.net.x0, e->u.net.y0,
                                          e->u.net.x1, e->u.net.y1,
                                          first, last);
                        }
                  }
                  break;
            case PIN:
                  if (connected_line_line(
                              e->u.pin.x0, e->u.pin.y0,
                              e->u.pin.x1, e->u.pin.y1,
                              x0, y0, x1, y1)) {
                        if (e->u.pin.sig == sig) {
                              /* Nothing to do... */
                        } else if (e->u.pin.sig != NULL) {
                              fprintf(stderr, "ERROR: Port \"%s\" of \"%s\" already connected.\n",
                                          lookup(e, "pinlabel"),
                                          comp_name);
                        } else {
                              const char *label;
                              const char *type;

                              e->u.pin.sig = sig;

                              if (level == 0) {
                                    sig->is_port = 1;
                              }

                              label = lookup(e, "pinlabel");
                              if (! label) {
                                    fprintf(stderr, "ERROR: Pin of \"%s\" has no pinlabel attribute.\n", comp_type);
                                    label = "unknown";
                              }
                              assert(label);
                              if (level == 0) {
                                    if (sig->name) {
                                          if (strcmp(sig->name, label) != 0) {
                                                fprintf(stderr, "ERROR: Port \"%s\" of \"%s\" connected to named signal \"%s\".\n", label, comp_name, sig->name);
                                          }
                                    } else {
                                          sig->name = label;
                                    }
                              }

                              type = lookup(e, "type");
                              if (! type) {
                                    fprintf(stderr, "ERROR: Pin \"%s\" in \"%s\" has no type attribute.\n", label, comp_type);
                                    type = "boolean";
                              }
                              assert(type);
                              if (sig->type) {
                                    if (strcmp(sig->type, type) != 0) {
                                          fprintf(stderr, "ERROR: Port \"%s\" of \"%s\" has type \"%s\" and is connected to signal of type \"%s\".\n", label, comp_type, type, sig->type);
                                    }
                              } else {
                                    sig->type = type;
                              }

#if DEBUG
                              fprintf(stderr, " %s/%s", comp_name, label);
#endif

                              connect_to(comp_type, comp_name,
                                          level, sig,
                                          e->u.pin.x0, e->u.pin.y0,
                                          e->u.pin.x1, e->u.pin.y1,
                                          first, last);
                        }
                  }
                  break;
            case TEXT:
                  /* Nothing to connect... */
                  break;
            case BUS:
                  if ((sig->name
                    && lookup(e, "netname")
                    && strcmp(sig->name, lookup(e, "netname")) == 0)
                   || connected_line_line(
                              e->u.bus.x0, e->u.bus.y0,
                              e->u.bus.x1, e->u.bus.y1,
                              x0, y0, x1, y1)) {
                        if (e->u.bus.sig == sig) {
                              /* Nothing to do... */
                        } else if (e->u.bus.sig != NULL) {
                              assert(0);
                        } else {
                              const char *netname;

                              e->u.bus.sig = sig;

                              netname = lookup(e, "netname");
                              if (netname) {
                                    if (sig->name) {
                                          assert(strcmp(sig->name, netname) == 0);
                                    } else {
                                          sig->name = netname;
                                    }
                              }

                              connect_to(comp_type, comp_name,
                                          level, sig,
                                          e->u.bus.x0, e->u.bus.y0,
                                          e->u.bus.x1, e->u.bus.y1,
                                          first, last);
                        }
                  }
                  break;
            }
      }
}

static void
connect(
      const char *comp_type,
      const char *comp_name,
      unsigned int level,
      struct el *first,
      struct el *last,
      struct sig **sig_firstp,
      struct sig **sig_lastp
)
{
      struct el *e;
      struct sig *sig;

      /*
       * First round:
       * connect all *named* nets/busses.
       */
      for (e = first; e; e = e->next) {
            sig = NULL;
            switch (e->type) {
            case COMP:
                  break;
            case NET:
                  if (! lookup(e, "netname")) {
                        break;
                  }
                  if (! e->u.net.sig) {
                        sig = malloc(sizeof(*sig));
                        assert(sig);
                        memset(sig, 0, sizeof(*sig));

                        sig->name = lookup(e, "netname");

                        connect_to(comp_type, comp_name, level, sig,
                                    e->u.net.x0, e->u.net.y0,
                                    e->u.net.x1, e->u.net.y1,
                                    first, last);
                  }
                  break;
            case PIN:
                  break;
            case TEXT:
                  /* Nothing to connect... */
                  break;
            case BUS:
                  if (! lookup(e, "netname")) {
                        break;
                  }
                  if (! e->u.bus.sig) {
                        sig = malloc(sizeof(*sig));
                        assert(sig);
                        memset(sig, 0, sizeof(*sig));

                        sig->name = lookup(e, "netname");

                        connect_to(comp_type, comp_name, level, sig,
                                    e->u.bus.x0, e->u.bus.y0,
                                    e->u.bus.x1, e->u.bus.y1,
                                    first, last);
                  }
                  break;
            }
            if (sig) {
                  assert(sig->name);
                  if (! sig->type) {
                        fprintf(stderr, "ERROR: signal %s not connected to any pin.\n",
                                    sig->name);
                        sig->type = "boolean";
                  }

#if DEBUG
                  fprintf(stderr, " -> %s (%s)\n", sig->name, sig->type);
#endif

                  sig->prev = *sig_lastp;
                  sig->next = NULL;
                  if (sig->prev) {
                        sig->prev->next = sig;
                  } else {
                        *sig_firstp = sig;
                  }
                  *sig_lastp = sig;
            }
      }

      /*
       * Second round:
       * Connect all *unnamed* nets/busses.
       */
      for (e = first; e; e = e->next) {
            sig = NULL;
            switch (e->type) {
            case COMP:
                  break;
            case NET:
                  if (! e->u.net.sig) {
                        sig = malloc(sizeof(*sig));
                        assert(sig);
                        memset(sig, 0, sizeof(*sig));

                        connect_to(comp_type, comp_name, level, sig,
                                    e->u.net.x0, e->u.net.y0,
                                    e->u.net.x1, e->u.net.y1,
                                    first, last);
                  }
                  break;
            case PIN:
                  if (! e->u.pin.sig) {
                        sig = malloc(sizeof(*sig));
                        assert(sig);
                        memset(sig, 0, sizeof(*sig));

                        connect_to(comp_type, comp_name, level, sig,
                                    e->u.pin.x0, e->u.pin.y0,
                                    e->u.pin.x1, e->u.pin.y1,
                                    first, last);
                  }
                  break;
            case TEXT:
                  /* Nothing to connect... */
                  break;
            case BUS:
                  if (! e->u.bus.sig) {
                        sig = malloc(sizeof(*sig));
                        assert(sig);
                        memset(sig, 0, sizeof(*sig));

                        connect_to(comp_type, comp_name, level, sig,
                                    e->u.bus.x0, e->u.bus.y0,
                                    e->u.bus.x1, e->u.bus.y1,
                                    first, last);
                  }
                  break;
            }
            if (sig) {
                  if (! sig->name) {
                        sig->name = ident_tmp();
                  }
                  if (! sig->type) {
                        fprintf(stderr, "ERROR: signal %s not connected to any pin.\n",
                                    sig->name);
                        sig->type = "boolean";
                  }

#if DEBUG
                  fprintf(stderr, " -> %s (%s)\n", sig->name, sig->type);
#endif

                  sig->prev = *sig_lastp;
                  sig->next = NULL;
                  if (sig->prev) {
                        sig->prev->next = sig;
                  } else {
                        *sig_firstp = sig;
                  }
                  *sig_lastp = sig;
            }
      }

      /*
       * Third round:
       * Connect nets/busses in subcomponents.
       */
      for (e = first; e; e = e->next) {
            if (e->type != COMP) continue;

            connect(lookup(e, "device"), lookup(e, "refdes"), level + 1,
                        e->u.comp.con_first, e->u.comp.con_last,
                        sig_firstp, sig_lastp);
      }
}

static void
gen_h(
      FILE *fp,
      const char *type,
      int chip,
      struct el *first,
      struct el *last,
      struct sig *sig_first,
      struct sig *sig_last
)
{
      struct el *e;
      struct sig *sig;
      char include[100][100];
      unsigned int nincludes;
      unsigned int i;

      /*
       * Generate Header
       */
      fprintf(fp, "/*\n");
      fprintf(fp, " * WARNING:\n");
      fprintf(fp, " *\n");
      fprintf(fp, " * Automatically generated from %s.\n", inname);
      fprintf(fp, " */\n");

      fprintf(fp, "\n");

      /*
       * Generate Signal Include List
       */
      nincludes = 0;
      for (sig = sig_first; sig; sig = sig->next) {
            if (! sig->is_port) continue;

            for (i = 0; ; i++) {
                  if (i == nincludes) {
                        strcpy(include[nincludes], sig_include(sig->type));
                        nincludes++;
                        break;
                  }
                  if (strcmp(include[i], sig_include(sig->type)) == 0) {
                        break;
                  }
            }
      }
      if (1 < nincludes) {
            for (;;) {
                  int done;

                  done = 1;

                  for (i = 0; i < nincludes - 1; i++) {
                        if (strcmp(include[i + 1], include[i]) < 0) {
                              char tmp[100];

                              strcpy(tmp, include[i]);
                              strcpy(include[i], include[i + 1]);
                              strcpy(include[i + 1], tmp);
                              done = 0;
                        }
                  }

                  if (done) {
                        break;
                  }
            }
      }
      for (i = 0; i < nincludes; i++) {
            fprintf(fp, "#include \"%s\"\n", include[i]);
      }

      fprintf(fp, "\n");

      /*
       * Generate <type>_init Function Prototype
       */
      fprintf(fp, "extern void\n");
      fprintf(fp, "%s_init(\n", type);
      fprintf(fp, "\tunsigned int nr");

      /* Ports */
      table_init();
      for (e = first; e; e = e->next) {
            if (e->type != PIN) continue;

            table_add(lookup(e, "pinlabel"), lookup(e, "pinseq"),
                        e->u.pin.sig);
      }
      table_sort();
      for (i = 0; i < nentries; i++) {
            fprintf(fp, ",\n");
            fprintf(fp, "\tstruct %s *%s",
                        sig_type(entry[i].sig->type),
                        port_name(entry[i].port));
      }
      fprintf(fp, "\n");
      fprintf(fp, ");\n");

      fprintf(fp, "\n");

      /*
       * Generate <type>_create Function Prototype
       */
      if (chip) {
            int count;

            fprintf(fp, "extern unsigned int\n");
            fprintf(fp, "%s_create(", type);

            /* Generics */
            count = 0;
            for (e = first; e; e = e->next) {
                  const char *generic;

                  if (e->type != TEXT
                   || ! e->u.text.str[0]
                   || strncmp(e->u.text.str[0], "generic=", strlen("generic=")) != 0) continue;

                  generic = e->u.text.str[0] + strlen("generic=");
                  assert(strchr(generic, '='));

                  if (0 < count) {
                        fprintf(fp, ", ");
                  }
                  if (*(strchr(generic, '=') + 1) == '"') {
                        fprintf(fp, "const char *");
                  } else {
                        fprintf(fp, "unsigned int");
                  }
                  count++;
            }

            if (count == 0) {
                  fprintf(fp, "void");
            }
            fprintf(fp, ");\n");
      } else {
            fprintf(fp, "extern void\n");
            fprintf(fp, "%s_create(unsigned int nr, const char *name", type);
            
            /* Generics */
            for (e = first; e; e = e->next) {
                  const char *generic;

                  if (e->type != TEXT
                   || ! e->u.text.str[0]
                   || strncmp(e->u.text.str[0], "generic=", strlen("generic=")) != 0) continue;

                  generic = e->u.text.str[0] + strlen("generic=");
                  assert(strchr(generic, '='));

                  if (*(strchr(generic, '=') + 1) == '"') {
                        fprintf(fp, ", const char *");
                  } else {
                        fprintf(fp, ", unsigned int");
                  }
            }

            fprintf(fp, ");\n");
      }

      /*
       * Generate <type>_destroy Function Prototype
       */
      fprintf(fp, "extern void\n");
      fprintf(fp, "%s_destroy(unsigned int nr);\n", type);
}

static void
gen_c_tmp(
      FILE *fp,
      const char *type,
      struct el *first,
      struct el *last,
      struct sig *sig_first,
      struct sig *sig_last
)
{
      struct el *e;
      unsigned int i;

      /*
       * Generate header.
       */
      fprintf(fp, "/*\n");
      fprintf(fp, " * %cId%c\n", '$', '$'); /* Fool CVS! */
      fprintf(fp, " *\n");
      fprintf(fp, " * Copyright (C) 2003-2009 FAUmachine Team <info@faumachine.org>.\n");
      fprintf(fp, " * This program is free software. You can redistribute it and/or modify it\n");
      fprintf(fp, " * under the terms of the GNU General Public License, either version 2 of\n");
      fprintf(fp, " * the License, or (at your option) any later version. See COPYING.\n");
      fprintf(fp, " */\n");

      fprintf(fp, "\n");

      /*
       * Generate include file list.
       */
      fprintf(fp, "#include <assert.h>\n");
      fprintf(fp, "#include <stdio.h>\n");
      fprintf(fp, "\n");
      fprintf(fp, "#include \"glue-shm.h\"\n");
      fprintf(fp, "\n");
      fprintf(fp, "#include \"%s.h\"\n", type);

      fprintf(fp, "\n");

      /*
       * Define CHIP.
       */
      fprintf(fp, "#define CHIP_(x) %s_ ## x\n", type);
      fprintf(fp, "#define CHIP \"%s\"\n", type);

      fprintf(fp, "\n");

      /*
       * Create cpssp struct.
       */
      fprintf(fp, "struct cpssp {\n");

      /* Output Ports */
      table_init();
      for (e = first; e; e = e->next) {
            if (e->type != PIN) continue;
            if (strcmp(lookup(e, "pintype"), "out") != 0) continue;

            table_add(lookup(e, "pinlabel"), lookup(e, "pinseq"),
                        e->u.pin.sig);
      }
      table_sort();
      for (i = 0; i < nentries; i++) {
            fprintf(fp, "\tstruct %s *%s;\n",
                        sig_type(entry[i].sig->type),
                        port_name(entry[i].port));
      }

      /* Input Ports */
      table_init();
      for (e = first; e; e = e->next) {
            if (e->type != PIN) continue;
            if (strcmp(lookup(e, "pintype"), "in") != 0) continue;

            table_add(lookup(e, "pinlabel"), lookup(e, "pinseq"),
                        e->u.pin.sig);
      }
      table_sort();
      for (i = 0; i < nentries; i++) {
            fprintf(fp, "\tunsigned int state_%s;\n",
                        name(entry[i].port));
      }

      /* In/Out Ports */
      table_init();
      for (e = first; e; e = e->next) {
            if (e->type != PIN) continue;
            if (strcmp(lookup(e, "pintype"), "io") != 0) continue;

            table_add(lookup(e, "pinlabel"), lookup(e, "pinseq"),
                        e->u.pin.sig);
      }
      table_sort();
      for (i = 0; i < nentries; i++) {
            fprintf(fp, "\tstruct %s *%s;\n",
                        sig_type(entry[i].sig->type),
                        port_name(entry[i].port));
            fprintf(fp, "\tunsigned int state_%s;\n",
                        name(entry[i].port));
      }

      /* Call Ports */
      table_init();
      for (e = first; e; e = e->next) {
            if (e->type != PIN) continue;
            if (strcmp(lookup(e, "pintype"), "call") != 0) continue;

            table_add(lookup(e, "pinlabel"), lookup(e, "pinseq"),
                        e->u.pin.sig);
      }
      table_sort();
      for (i = 0; i < nentries; i++) {
            fprintf(fp, "\tstruct %s *%s;\n",
                        sig_type(entry[i].sig->type),
                        port_name(entry[i].port));
      }

      fprintf(fp, "};\n");

      fprintf(fp, "\n");

      /*
       * Create <type>_init function.
       */
      fprintf(fp, "void\n");
      fprintf(fp, "CHIP_(init)(\n");
      fprintf(fp, "\tunsigned int nr");

      table_init();
      for (e = first; e; e = e->next) {
            if (e->type != PIN) continue;

            table_add(lookup(e, "pinlabel"), lookup(e, "pinseq"),
                        e->u.pin.sig);
      }
      table_sort();
      for (i = 0; i < nentries; i++) {
            fprintf(fp, ",\n");
            fprintf(fp, "\tstruct %s *%s",
                        sig_type(entry[i].sig->type),
                        port_name(entry[i].port));
      }

      fprintf(fp, "\n");
      fprintf(fp, ")\n");
      fprintf(fp, "{\n");

      table_init();
      for (e = first; e; e = e->next) {
            if (e->type != PIN) continue;
            if (strcmp(lookup(e, "pintype"), "in") != 0
             && strcmp(lookup(e, "pintype"), "io") != 0
             && strcmp(lookup(e, "pintype"), "call") != 0) continue;

            table_add(lookup(e, "pinlabel"), lookup(e, "pinseq"),
                        e->u.pin.sig);
      }
      table_sort();
      for (i = 0; i < nentries; i++) {
            fprintf(fp, "\tstatic const struct %s_funcs %s_funcs = {\n",
                        sig_type(entry[i].sig->type),
                        name(entry[i].port));
            fprintf(fp, "\t\t/* FIXME */\n");
            fprintf(fp, "\t};\n");
      }

      fprintf(fp, "\tstruct cpssp *cpssp;\n");
      fprintf(fp, "\n");
      fprintf(fp, "\tcpssp = shm_map(CHIP, nr, sizeof(*cpssp), 0);\n");
      fprintf(fp, "\n");
      fprintf(fp, "\t/* FIXME */\n");
      fprintf(fp, "\n");

      fprintf(fp, "\t/* Call */\n");

      table_init();
      for (e = first; e; e = e->next) {
            if (e->type != PIN) continue;
            if (strcmp(lookup(e, "pintype"), "call") != 0) continue;

            table_add(lookup(e, "pinlabel"), lookup(e, "pinseq"),
                        e->u.pin.sig);
      }
      table_sort();
      for (i = 0; i < nentries; i++) {
            fprintf(fp, "\tcpssp->%s = %s;\n",
                        port_name(entry[i].port),
                        port_name(entry[i].port));
            fprintf(fp, "\t%s_connect(%s, cpssp, &%s_funcs);\n",
                        sig_type(entry[i].sig->type),
                        port_name(entry[i].port),
                        name(entry[i].port));
            fprintf(fp, "\n");
      }

      fprintf(fp, "\t/* Out */\n");

      table_init();
      for (e = first; e; e = e->next) {
            if (e->type != PIN) continue;
            if (strcmp(lookup(e, "pintype"), "out") != 0
             && strcmp(lookup(e, "pintype"), "io") != 0) continue;

            table_add(lookup(e, "pinlabel"), lookup(e, "pinseq"),
                        e->u.pin.sig);
      }
      table_sort();
      for (i = 0; i < nentries; i++) {
            fprintf(fp, "\tcpssp->%s = %s;\n",
                        port_name(entry[i].port),
                        port_name(entry[i].port));
            fprintf(fp, "\t%s_connect_out(%s, cpssp, 0);\n",
                        sig_type(entry[i].sig->type),
                        port_name(entry[i].port));
            fprintf(fp, "\n");
      }

      fprintf(fp, "\t/* In */\n");

      table_init();
      for (e = first; e; e = e->next) {
            if (e->type != PIN) continue;
            if (strcmp(lookup(e, "pintype"), "in") != 0
             && strcmp(lookup(e, "pintype"), "io") != 0) continue;

            table_add(lookup(e, "pinlabel"), lookup(e, "pinseq"),
                        e->u.pin.sig);
      }
      table_sort();
      for (i = 0; i < nentries; i++) {
            fprintf(fp, "\tcpssp->state_%s = 0;\n",
                        name(entry[i].port));
            fprintf(fp, "\t%s_connect_in(%s, cpssp, &%s_funcs);\n",
                        sig_type(entry[i].sig->type),
                        port_name(entry[i].port),
                        name(entry[i].port));
            fprintf(fp, "\n");
      }

      fprintf(fp, "}\n");

      fprintf(fp, "\n");

      /*
       * Create <type>_create Function
       */
      fprintf(fp, "unsigned int\n");
      fprintf(fp, "CHIP_(create)(void)\n"); /* Generics - FIXME */
      fprintf(fp, "{\n");
      fprintf(fp, "\tstatic unsigned int nr = 0;\n");
      fprintf(fp, "\tstruct cpssp *cpssp;\n");
      fprintf(fp, "\n");
      fprintf(fp, "\tshm_create(CHIP, nr, sizeof(*cpssp));\n");
      fprintf(fp, "\tcpssp = shm_map(CHIP, nr, sizeof(*cpssp), 0);\n");
      fprintf(fp, "\n");
      fprintf(fp, "\t/* FIXME */\n");
      fprintf(fp, "\n");
      fprintf(fp, "\tshm_unmap(cpssp, sizeof(*cpssp));\n");
      fprintf(fp, "\n");
      fprintf(fp, "\treturn nr++;\n");
      fprintf(fp, "}\n");

      fprintf(fp, "\n");

      /*
       * Create <type>_destroy Function
       */
      fprintf(fp, "void\n");
      fprintf(fp, "CHIP_(destroy)(unsigned int nr)\n");
      fprintf(fp, "{\n");
      fprintf(fp, "\tstruct cpssp *cpssp;\n");
      fprintf(fp, "\n");
      fprintf(fp, "\tcpssp = shm_map(CHIP, nr, sizeof(*cpssp), 0);\n");
      fprintf(fp, "\n");
      fprintf(fp, "\t/* FIXME */\n");
      fprintf(fp, "\n");
      fprintf(fp, "\tshm_unmap(cpssp, sizeof(*cpssp));\n");
      fprintf(fp, "\tshm_destroy(CHIP, nr);\n");
      fprintf(fp, "}\n");
}

static void
gen_c(
      FILE *fp,
      const char *type,
      struct el *first,
      struct el *last,
      struct sig *sig_first,
      struct sig *sig_last
)
{
      struct el *e;
      struct sig *sig;
#if 0
      char include[100][100];
      unsigned int nincludes;
#endif
      unsigned int i;

      /*
       * Generate C Code (Header)
       */
      fprintf(fp, "/*\n");
      fprintf(fp, " * WARNING:\n");
      fprintf(fp, " *\n");
      fprintf(fp, " * Automatically generated from %s.\n", inname);
      fprintf(fp, " */\n");
      fprintf(fp, "\n");
      fprintf(fp, "#include \"glue-shm.h\"\n");
      fprintf(fp, "\n");
      for (e = first; e; e = e->next) {
            struct el *el;

            if (e->type != COMP
             || lookup(e, "graphical")
             || ! lookup(e, "device")) continue;

            for (el = first; ; el = el->next) {
                  if (el->type != COMP
                   || lookup(el, "graphical")
                   || ! lookup(el, "device")) continue;

                  if (e == el) {
                        fprintf(fp, "#include \"%s.h\"\n", lookup(e, "device"));
                  }
                  if (strcmp(lookup(el, "device"), lookup(e, "device")) == 0) {
                        break;
                  }
            }
      }
      fprintf(fp, "\n");
      fprintf(fp, "#include \"%s.h\"\n", type);
      fprintf(fp, "\n");
      fprintf(fp, "#define COMP\t\"%s\"\n", type);

      fprintf(fp, "\n");

      /*
       * Generate C Code (cpssp Struct)
       */
      fprintf(fp, "struct cpssp {\n");
      for (e = first; e; e = e->next) {
            if (e->type != COMP
             || lookup(e, "graphical")
             || ! lookup(e, "refdes")) continue;

            fprintf(fp, "\tunsigned int comp_%s;\n", lookup(e, "refdes"));
      }
      fprintf(fp, "};\n");

      fprintf(fp, "\n");

      /*
       * Generate C Code (*_init Function)
       */
      table_init();
      for (e = first; e; e = e->next) {
            if (e->type != PIN) continue;

            table_add(lookup(e, "pinlabel"), lookup(e, "pinseq"),
                        e->u.pin.sig);
      }
      table_sort();

      fprintf(fp, "void\n");
      fprintf(fp, "%s_init(\n", type);
      fprintf(fp, "\tunsigned int nr");
      for (i = 0; i < nentries; i++) {
            fprintf(fp, ",\n");
            fprintf(fp, "\tstruct %s *%s",
                        sig_type(entry[i].sig->type),
                        port_name(entry[i].port));
      }
      fprintf(fp, "\n");
      fprintf(fp, ")\n");
      fprintf(fp, "{\n");

      /* Signals */
      for (sig = sig_first; sig; sig = sig->next) {
            if (sig->is_port) continue;

            fprintf(fp, "\tstruct %s *%s;\n",
                        sig_type(sig->type), sig_name(sig->name));
      }
      fprintf(fp, "\tstruct cpssp *cpssp;\n");

      fprintf(fp, "\n");

      fprintf(fp, "\tcpssp = shm_map(COMP, nr, sizeof(*cpssp), 0);\n");

      fprintf(fp, "\n");

      /* Signals */
      for (sig = sig_first; sig; sig = sig->next) {
            if (sig->is_port) continue;

            fprintf(fp, "\t%s = %s_init(COMP \"-sig_%s\", nr);\n",
                        sig_name(sig->name), sig_type(sig->type),
                        sig->name);
      }

      fprintf(fp, "\n");

      /* Components */
      for (e = first; e; e = e->next) {
            struct el *ce;

            if (e->type != COMP
             || lookup(e, "graphical")
             || ! lookup(e, "refdes")) continue;

            table_init();
            for (ce = e->u.comp.con_first; ce; ce = ce->next) {
                  if (ce->type != PIN) continue;

                  table_add(lookup(ce, "pinlabel"), lookup(ce, "pinseq"),
                              ce->u.pin.sig);
            }
            table_sort();

            fprintf(fp, "\t%s_init(\n", lookup(e, "device"));
            fprintf(fp, "\t\tcpssp->comp_%s", lookup(e, "refdes"));
            for (i = 0; i < nentries; i++) {
                  fprintf(fp, ",\n");
                  if (entry[i].sig->is_port) {
                        fprintf(fp, "\t\t%s",
                                    port_name(entry[i].sig->name));
                  } else {
                        fprintf(fp, "\t\t%s",
                                    sig_name(entry[i].sig->name));
                  }
                  fprintf(fp, " /* %s */", entry[i].port);
            }
            fprintf(fp, "\n");
            fprintf(fp, "\t);\n");
      }

      fprintf(fp, "}\n");

      fprintf(fp, "\n");

      /*
       * Generate C Code (*_create Function)
       */
      /* Header */
      fprintf(fp, "void\n");
      fprintf(fp, "%s_create(unsigned int nr, const char *name", type);

      /* Generics */
      for (e = first; e; e = e->next) {
            const char *generic;

            if (e->type != TEXT
                        || ! e->u.text.str[0]
                        || strncmp(e->u.text.str[0], "generic=", strlen("generic=")) != 0) continue;

            generic = e->u.text.str[0] + strlen("generic=");
            assert(strchr(generic, '='));

            if (*(strchr(generic, '=') + 1) == '"') {
                  *(strchr(generic, '=')) = '\0';
                  fprintf(fp, ", const char *%s", generic);
            } else {
                  *(strchr(generic, '=')) = '\0';
                  fprintf(fp, ", unsigned int %s", generic);
            }
      }

      fprintf(fp, ")\n");

      fprintf(fp, "{\n");
      fprintf(fp, "\tstruct cpssp *cpssp;\n");
      fprintf(fp, "\n");
      fprintf(fp, "\tshm_create(COMP, nr, sizeof(*cpssp));\n");
      fprintf(fp, "\tcpssp = shm_map(COMP, nr, sizeof(*cpssp), 0);\n");
      fprintf(fp, "\n");
      
      /* Create Signals */
      for (sig = sig_first; sig; sig = sig->next) {
            if (sig->is_port) continue;

            fprintf(fp, "\t%s_create(COMP \"-sig_%s\", nr);\n",
                        sig_type(sig->type), sig->name);
      }

      fprintf(fp, "\n");

      /* Create Components */
      for (e = first; e; e = e->next) {
            if (e->type != COMP
             || lookup(e, "graphical")
             || ! lookup(e, "refdes")) continue;

            fprintf(fp, "\tcpssp->comp_%s = %s_create(",
                        lookup(e, "refdes"),
                        lookup(e, "device"));
            for (i = 0; ; i++) {
                  const char *generic;

                  generic = lookup_n(e, "generic", i);
                  if (! generic) {
                        break;
                  }
                  assert(strchr(generic, '='));
                  if (*(strchr(generic, '=') + 1) == '?'
                   || *(strchr(generic, '=') + 2) == '?') {
                        continue;
                  }
                  if (0 < i) {
                        fprintf(fp, ", ");
                  }
                  fprintf(fp, "%s", strchr(generic, '=') + 1);
            }
            fprintf(fp, ");\n");
      }

      /* Trailer */
      fprintf(fp, "\n");
      fprintf(fp, "\tshm_unmap(cpssp, sizeof(*cpssp));\n");
      fprintf(fp, "}\n");

      fprintf(fp, "\n");

      /*
       * Generate C Code (*_destroy Function)
       */
      /* Header */
      fprintf(fp, "void\n");
      fprintf(fp, "%s_destroy(unsigned int nr)\n", type);
      fprintf(fp, "{\n");
      fprintf(fp, "\tstruct cpssp *cpssp;\n");
      fprintf(fp, "\n");
      fprintf(fp, "\tcpssp = shm_map(COMP, nr, sizeof(*cpssp), 0);\n");
      fprintf(fp, "\n");
      
      /* Destroy Componets */
      for (e = first; e; e = e->next) {
            if (e->type != COMP
             || lookup(e, "graphical")
             || ! lookup(e, "refdes")) continue;

            fprintf(fp, "\t%s_destroy(cpssp->comp_%s);\n",
                        lookup(e, "device"),
                        lookup(e, "refdes"));
      }

      fprintf(fp, "\n");

      /* Destroy Signals */
      for (sig = sig_first; sig; sig = sig->next) {
            if (sig->is_port) continue;

            fprintf(fp, "\t%s_destroy(COMP \"-sig_%s\", nr);\n",
                        sig_type(sig->type), sig->name);
      }

      /* Trailer */
      fprintf(fp, "\n");
      fprintf(fp, "\tshm_unmap(cpssp, sizeof(*cpssp));\n");
      fprintf(fp, "\tshm_destroy(COMP, nr);\n");
      fprintf(fp, "}\n");
}

static void __attribute__((noreturn))
usage(int retval)
{
      fprintf(stderr, "Usage: %s <*.sch or *.sym file>\n", progname);
      exit(retval);
}

int
main(int argc, char **argv)
{
      int c;
      FILE *fp;
      struct el *first;
      struct el *last;
      struct el *e;
      struct sig *sig_first;
      struct sig *sig_last;
      char type[1024];
      char outname[1024];
      int ret;
      int chip;

      progname = *argv;

      while ((c = getopt(argc, argv, "")) != -1) {
            switch (c) {
            default:
                  usage(1);
            }
      }
      argc -= optind;
      argv += optind;

      if (0 < argc) {
            inname = *argv;
            argc--;
            argv++;
      } else {
            usage(1);
      }
      if (argc != 0) {
            usage(1);
      }
      if (! strchr(inname, '.')) {
            usage(1);
      }
      
      if (strchr(inname, '/')) {
            strcpy(type, strrchr(inname, '/') + 1);
      } else {
            strcpy(type, inname);
      }
      if (strchr(type, '.')) {
            *strchr(type, '.') = '\0';
      }

      /*
       * Read schematic file.
       */
#if DEBUG
      fprintf(stderr, "Reading %s...\n", inname);
#endif

      fp = fopen(inname, "r");
      if (! fp) {
            fprintf(stderr, "ERROR: %s: %s: %s.\n", progname,
                        inname, strerror(errno));
            exit(1);
      }
      assert(fp);

      read_list(fp, &first, &last);

      fclose(fp);

      /*
       * Read all component files.
       */
      for (e = first; e; e = e->next) {
            if (e->type != COMP
             || lookup(e, "graphical")) {
                  continue;
            }

#if DEBUG
            fprintf(stderr, "Reading %s...\n", e->u.comp.sym_file);
#endif

            fp = fopen(e->u.comp.sym_file, "r");
            if (! fp) {
                  fprintf(stderr, "ERROR: %s: %s: %s.\n", progname,
                              e->u.comp.sym_file, strerror(errno));
                  /* Ignore it... */
                  continue;
            }
            assert(fp);

            read_list(fp, &e->u.comp.con_first, &e->u.comp.con_last);

            fclose(fp);
      }

      /*
       * Build signal/connection lists.
       */
      sig_first = NULL;
      sig_last = NULL;
      connect(inname, "toplevel", 0, first, last, &sig_first, &sig_last);

      chip = (strcmp(strrchr(inname, '.'), ".sym") == 0);

      /*
       * Generate <type>.h File
       */
      strcpy(outname, inname);
      strcpy(strrchr(outname, '.'), ".h");
      fp = fopen(outname, "w");
      if (! fp) {
            fprintf(stderr, "%s: ERROR: Can't create %s: %s.\n", progname,
                        outname, strerror(errno));
            exit(1);
      }

      gen_h(fp, type, chip, first, last, sig_first, sig_last);

      ret = fclose(fp);
      assert(ret == 0);

      if (chip) {
            /*
             * Generate <type>.c.tmp File
             */
            strcpy(outname, inname);
            strcpy(strrchr(outname, '.'), ".c.tmp");
            fp = fopen(outname, "w");
            if (! fp) {
                  fprintf(stderr, "%s: ERROR: Can't create %s: %s.\n", progname,
                              outname, strerror(errno));
                  exit(1);
            }

            gen_c_tmp(fp, type, first, last, sig_first, sig_last);

            ret = fclose(fp);
            assert(ret == 0);

      } else {
            /*
             * Generate <type>.c File
             */
            strcpy(outname, inname);
            strcpy(strrchr(outname, '.'), ".c");
            fp = fopen(outname, "w");
            if (! fp) {
                  fprintf(stderr, "%s: ERROR: Can't create %s: %s.\n", progname,
                              outname, strerror(errno));
                  exit(1);
            }

            gen_c(fp, type, first, last, sig_first, sig_last);

            ret = fclose(fp);
            assert(ret == 0);
      }

      return 0;
}

Generated by  Doxygen 1.6.0   Back to index