pcb-rnd knowledge pool


Layer group subtyping: the purpose field

layer_purp by Tibor 'Igor2' Palinkas on 2018-09-11

Tags: insight, layer, group, layergroup, purpose, binding, outline, boundary, mech, route, routing, plated, unplated

node source



Abstract: How the layer system got extended with a layer group purpose, that behaves like a free form subtype. Reasons to do this instead of introducing hardwired bits for the new types. How this system works with existing mechanisms such as layer binding.


History: from PCB to pcb-rnd

In the original PCB code, there was no layer type indication of any sort. There were some heuristics and assumptions instead: if you had N layers then the first N-2 layers were copper or outline layers and the last two layers were silk layers (in a specific order to know which one is top or bottom). The outline layer was really just a copper layer with the name "outline" - and the code at some points checked the name of non-silk layers to figure if it was outline.

There were layer groups, used only for two things: tell if a layer is top or bottom and control which layers' visibility are toggled together.

This changed in pcb-rnd starting from late 2016, during the big layer rewrite, which was the first step of the data model rewrite. In the new model, layer groups have a so called layer type bitfield. There are some bits to specify the type of the layer group (e.g. copper or silk or mask), and another few bits to specify the location (top, intern, bottom, virtual).

This new model also makes a clear separation between "physical layers" (layer groups) and "drawing canvases" (layers). Layers are used only to make different colors or compose a group by drawing positively (adding ink) or negatively (erasing ink).

Purpose field: user defined flexibility

The above system is flexible enough that we could introduce editable solder mask and paste layers. However, there are two major areas it could not cover:

Because of the second, the trivial upgrade was adding a second, "subtype" field, called the purpose of the layer group. This is a free form text, so that the user can specify any value. This allows us to write plugins that look for specific layer group types, not depending on group names but flexible, extensible subtypes.

But once this system was in place, I realized that it can solve the problem with the "too many routed types" as well. The outline layer type got removed and three new types got introduced.

For the user this means that for some layer group types it is not enough to specify the main type (e.g. boundary) but the purpose (subtype) needs to be set too, to refine the meaning (e.g. uroute or proute). Or, in other words, when the user is browsing layer types from a list, the items are not a single type, but a type-purpose pair - which is not more complicated and won't make the list longer either. In return, the same mechanism can handle flexible/custom user subtypes and can be extended in the future without rising compatibility questions.

Purpose vs. location

There are two kind of layer groups: ones that are participating in the stackup and others that don't.

The location bits of the stackup layers are set automatically as they are deduced directly from the stackup. For example the topmost copper layer group is marked with the TOP location bit. The direction of deduction is always stackup -> bits, so changing the location bits in the layer type bitfield wouldn't change the physical location of the group, only would make the group data incoherent. There are also some restrictions, for example there can be only one top copper group, only one top silk group, etc. An atypical example is all the boundary and routed/cut/punched mech layers: they are part of the stackup and are forced to be global (cutting through all layers). Non-cut mech layers, such as adhesives belong to the off-stackup group (see below).

Other layer groups are off-stackup, which means they do not exist as part of the board stackup but as independent data - however, they are often marked with location bits to know which board side they refer to. For these layers the primary source of information is the location bit in the main layer type bitfield, as set by the user. Typical examples:

Layer binding vs. purpose

Layer binding is semi-automatic: a subcircuit or a buffer has a layer recipe and pcb-rnd tries to find the best match for that recipe on the current board. This is done in two steps:

In practice this means if the board has two boundary layers, one with purpose set to uroute and the other set to proute and there's a recipe that wants a boundary layer but does not specify purpose, pcb-rnd will pick either layer (semi-randomly). To make sure the layer recipe addresses the right layer, it should contain a purpose field that is either uroute or proute.

However, if then the recipe now with the purpose field set to proute is applied on a board where there's only a "classic outline" layer, that is a boundary layer with purpose uroute, it will be bound to that layer automatically. That is because it's the closest thing we have, with the highest score.

On one hand this is flexibility: on a simpler board/fab combination the user decides to keep only 2 routed layers, one plated, one unplated, instead of keeping 4 (separate set of plated/unplated for "outer" boundary and for "inner slot" mech). Because of this flexible mechanism, layers intended for slotting will silently end up on the next best routed layers, the boundary layers. No user interaction needed. But when the fab requires separate slot layers to be sent, the user would create all 4 layer groups and the same bindings would automatically prefer the mech layers for slots if the recipes were set up correctly.

On the other hand this is a risk too, which we may want DRC to capture long term: a padstack slot can easily become unplated because there's no plated routed boundary/mech layer available. Note: the choice to make this not an error, and rely on later DRC checks is thought over and intentional.