<@U016EM8L91B> Is there a reason you use the older...
# magic
m
@User Is there a reason you use the older version tech27 file? I am having an isuse now where I still have a substract connection problem with my tech file, but not with yours. But then I have some DRC errors that are found with yours in other cells but not the version 30 file.
t
Yeah, the reason is that because of openlane I haven't used qflow in ages and forgot that's where I put the most recent SCMOS tech files. . .
m
And they aren't real DRC errors. They seem to be with how it processes the contacts from the gds incorrectly:
Let me make sure I'm using the most recent. I had grabbed them from qflow before.
t
The older version of the tech file is from MOSIS and defines specific multi-layer contacts and not general-purpose stacking types. The stacking contact issue can usually be made to go away simply by adding the keyword "stacking" at the end of the "contact" section in the techfile. But the version 31 techfile was supposed to go through and remove all the specific-purpose multi-layer contacts so the whole thing is cleaner. But that's almost certainly unrelated to the LVS issue.
m
Yes, it is unrelated.
Ok. I'm going to stick with the newest version from qflow (which I'm already using). I don't see this error fixed when I run using that...
It still has an NMOS with a disconnected substrate connection in the subcircuit pinv_0
(Same test case as before)
t
Okay, I can confirm the issue. Feeling of going round and round the same error. . . The .ext file is correct. ext2spice is not adding the substrate node to the subcircuit definition for inv_0. I seem to be unable to disambiguate the case where an implicit substrate connection is required and the case where it needs to be removed. Since the disambiguating factor was supposed to be "is used as the bulk connection to a device in the subcircuit", then it most definitely should have been flagged as a must-have port. So in principle, that should have worked, so I guess I now need to go figure out why it didn't.
Maybe it's because the transistor itself is in a subcircuit and the substrate flag doesn't get propagated up the hierarchy. . .
The reason this error goes round and round is because the comes from fixing the problem where ext2spice keeps adding port connections to substrate even for cells that don't have any internal connections to substrate. Every cell has a connection to substrate, technically, but the rule for LVS is that a cell is not going to call out a substrate port unless it's connected to a device somewhere. This seems like a straightforward policy to follow, but it does require looking all the way down the hierarchy to the bottommost devices.
m
Yes, I see this with simple generated nand3 gates too. Is there a workaround? I don't like the idea of flattening individual transistors though.
t
I'm working on a fix. The problem is that propagating the substrate node flag up is difficult, because the node is processed through a bunch of "merge" statements which may run through various cells. So for the error in question, the "ground" pin of pinv_0 first visited the pfet substrate which is not a port of any device (pfets being in nwells), then visited the nfet substrate which is a port. I'm looking at a solution now where I do more bookkeeping of the connections so I can reliably propagate up the substrate pin flag.
m
@User Are you doing LVS directly on magic data or converted from GDS? If you're converting from GDS, you can virtually flatten the primitive cells before extracting. I use
gds flatglob *_?mos_m*
for the sram modules.
m
@User Thanks, that will be a work around for DRC/LVS for now.
That seems to fix the problem in pbuf but not in some other cells.
A temporary fix seems to be to not do unique extraction of nets. But then I risk leaving something unconnected (though I know it isn't right now...)
t
@User: I just pushed an update to 8.3.273 that should resolve this problem.
👍 1
@User: Note that although for some of these errors (like this one) it seems that recent updates are breaking things, there are a surprising number of methods in magic that can depend on the ordering of things in a hash table and therefore can break at any time for any reason after working fine for numerous examples. In this case, it is the specific order of pairs of nodes in the connectivity hash table. Traversed in almost any other order, it would have produced a correct netlist. There are several parts of the code that make me cringe when I realize an error is implicated there. The hierarchical extraction code is probably the worst of them, too.
m
I really want to dig into this at some point to learn to debug it myself and to learn some of the algorithms. I started using klayout for DRC/LVS as well and their tool behaves very differently, especially for LVS. The most annoying thing (in my opinion) is that they require all subcircuits to match and don't flatten if they fail to
However, they don't abstract LVS to a graph isomorphism. It really leverages the layout during the comparison
m
@User I think the ordering of things in the hash table might have something to do with some of the hash keys being created with a name and file id, but then only checking the name on lookup. See the third bullet here https://github.com/RTimothyEdwards/netgen/discussions/50
t
@User: The file number is not part of the hash key. The file number is just provided so that when it looks up entries for that specific string hash, it will return only the hash entry that also matches the file number.
m
@User Seems to me that you're saying that the same name in different files will have the same hash, but the lookup will only return the one with the matching file number. That's not what I see from the code.
Copy code
struct hashlist *HashInt2PtrInstall(char *name, int c, void *ptr,
                        struct hashdict *dict)
{
  struct hashlist *np;
  unsigned long hashval;

  hashval = genhash(name, c, dict->hashsize);
  for (np = dict->hashtab[hashval]; np != NULL; np = np->next)
    if (!strcmp(name, np->name)) {
      np->ptr = ptr;
      return (np);              /* match found in hash table */
    }

  /* not in table, so install it */
  if ((np = (struct hashlist *) CALLOC(1,sizeof(struct hashlist))) == NULL)
    return (NULL);
  if ((np->name = strsave(name)) == NULL) return (NULL);
  np->ptr = ptr;
  np->next = dict->hashtab[hashval];
  return(dict->hashtab[hashval] = np);
}
HashInt2PtrInstall
calls
genhash
to create a hash with
c
as a file number.
Copy code
unsigned long genhash(char *s, int c, int hashsize)
{
        unsigned long hashval;

        for (hashval = (unsigned long)c; *s != '\0'; )
            hashval = (*s++) + (hashval << 6) + (hashval << 16) - hashval;
        return (hashsize == 0) ? hashval : (hashval % hashsize);
}
genhash
begins the hash creation with
c
. So when file number is 0, it's the same as a hash without the file number, but any other file number will give a different hash. And then in
Copy code
void *HashInt2Lookup(char *s, int c, struct hashdict *dict)
{
  struct hashlist *np;
  unsigned long hashval;

  hashval = genhash(s, c, dict->hashsize);

  for (np = dict->hashtab[hashval]; np != NULL; np = np->next)
    if (!strcmp(s, np->name))
      return (np->ptr); /* correct match */

  return (NULL); /* not found */
}
The file number is again used in the hash creation, but only the name is checked in the bucket lookup! So theoretically, if the same name occurred in both files and generated the same hash, this routine would only return the first one found (which may not be from the correct file). Currently
c
is not stored in the hash, so there's no way to check it. Am I missing something?
Incidentally,
genhash
is case-sensitive only. Also, I'm working on a patch that will do dynamic hash resizing.
t
I agree the code is incorporating the file number into the hash, which I guess makes sense, if you want a unique hash for cells with the same name from two different netlists, so I guess I did that so as not to have to check the hash entries for the right one. Sorry, it's been a while since I implemented that.