# 4. cschem implementation - attributes

## 4.1. Are priorities distractive?

{imp4:0} Attribute priorities are designed with {pol:3} in mind:

- in the most common, simple use cases, the user can ignore attribute priorities
- for complex tasks priorities can be used to have full control over what part of the system may overwrite a specific attribute

{imp4:2} The simple case has the following attribute modification precedence:

- plugins may ovewrite attributes that are not explicitly specified by the user (on the sheet or in the lib)
- if multiple plugins are going to write the same attribute, there is an explicit, simple, clear order of plugin precedence mandated by the view configuration
- attributes specified by the user in library (referenced groups) are stronger than attributes calculated by plugins (i.e. an attribute explicitly specified in a library symbol won't be overridden by a plugin by default)
- attributes at the place of group_ref override attributes coming from the referenced group or plugins (i.e. attributes of a symbol instance override attributes from the lib or plugins)

{imp4:3} To achieve this, cschem needs only two conventions:

- a default user priority value
- explicit priority ranges for each plugin, which is just a fancy way setting the order of plugins

{imp4:4} In that simplest and most common case, the user ignores priorities so all attributes the user creates will have the same priority. The user needs to make sure not to enter contradictionary attributes. Library attributes automatically get lower priority due to the +100 offset. Plugins automatically get lower priority due to their priority range starting over 1000. Every plugin uses only their "normal" priority range. The only priority-related feature the UI needs to display is the order of plugins in the view.

{imp4:5} This is pretty much how gschem worked implicitly, except a few corner cases are handled better in cschem:

- "lib attributes overriden by local attributes" works in both
- gschem silently accepted attribute collision and the user had no way to prioritize one attribute over the other; the outcome of the collision was hard to predict
- gschem backends/mechanisms could freely overwrite user attributes
- gschem could not run multiple backends in a modular/flexible way, only multiple mechanisms (such as slotting) plus one backend; the order of these were hardwired

{imp4:6} The next simple step is when the user manually bumps the priority of an attribute. A common example is to raise the priority to resolve a collision. Another trivial example is to lower the priority to make a locally specified attribute a fallback but let specific (or all) plugins override it.

## 4.2. attribute key "paths"

{imp4:7} Attribute keys within an AoO form a flat map - most of the code do not need to care about the actual format of the key string. This works well as long as there are only a few plugins and attributes defined. However, as the number of attribute specifiers increase, there will be more and more collisions.

{imp4:8} A typical example is the identifier of a pin: the same schematics may be the source of simulation and the source of a pcb layout. In both cases a specific pin of a component needs to be addressed, but the same pin may have a different address ("pin number") for simulation and for PCB. The user needs to specify both, thus the key must differ. A possible solution is to use "pinnumber" and "pinseq", but that might be confusing - "number" and "seq" doesn't really explain that one is for PCB or about the physical object the other is for the SPICE syntax. However, it already has a common prefix: "pin".

{imp4:9} The "path" syntax standrardizes the solution for this situation, recommending to use "pcb/pinnum" and "spice/pinnum" instead of "pinnumber" and "pinseq". When the convention is used consistently, attributes are groupped by their name. The UI may offer very simple ways, such as alphabetic ordering, or more complex ways, such as tree view, for helping the user navigate among the attribute groups. Still, the non-UI code does not need to explicitly know about these groups, these are just naming conventions.

{imp4:10} Similar method is used by the OpenStreetMap project, where tag naming conventions use ":" separators,such as building:levels or name:en, name:de.

{imp4:11} This may sound painful to use in practice, e.g. user would need to set the "pcb/footprint" attribute instead of simply setting the "footprint". The practical solution for this would be a plugin that can convert short named attributes to long named attributes. For example the device mapper plugin will look for a device specification (short named); when that's found, it will consult the database and render pcb/footprint and the pinout; if it is not found, it will look for "footprint" and copies that to "pcb/footprint". If the user wants to override the final footprint, the user can enter "pcb/footprint", with the default user priority this will easily override the value the device mapper would emit.

{imp4:12} At the end, as {imp4:13} suggests, trivail cases are easy: the good old "footprint" attribute works; it is just not a hardwired behaviour but the result of an opitonal plugin.

## 4.3. hash vs. list vs. array vs. scalar

{imp4:14} Vast majority of attributes will be a simple text string that is interpreted in an attribute-specific way, usually following one of the "cschem-" formats. This setup is flexible and easy for both users and programmers.

{imp4:15} However it's also common that the value is a list of, or array of scalars. To avoid each attribute and plugin inventing its own syntax for listing multiple values, cschem specifies attribute values to be either scalar or array.

{imp4:16} Furthermore attribute keys can be regarded as "paths" within their AoO, using the "path separator" slash. This is only an UI convention, the code does not need to care about it.

{imp4:17} This means from the UI perspective the attribute subtree has a hash root, using the "paths" may have "hash children". The last level can be an array (if the attribute value is an array), but the leaves, the actual values are always scalar.

## 4.4. examples

### 4.4.1. compilation history of a pin number

{imp4:18} Assume the following view:

- gschem_slot (compatibility plugin): normal pirority 15081..15090
- devmap plugin (device mapper): normal pirority 15041..15050
- export_pcb: normal pirority 12011..12020

{imp4:19} A typical attribute source for the pin's pcb/pinnum would be:

    15085::p::gschem_slot::slotting
    15045::p::devmap::derived from devmap

The final value is the one from 15045

{imp4:20} And for the display/number attribute (that would tell the GUI what pin number to display):

    12015::p::export_pcb::derived from pcb/pinnum

{imp4:21} If the user has a manual override on the pin number, the history of pcb/pinnum would look like this:

    350::u::my_symbol.lht:32.11::
    250::u::foo.lth:182.4::
    15085::p-::gschem_slot::slotting
    15045::p-::devmap::derived from devmap

First the value was set by the library (350), then got ovrridden by the instance-value specified by the user in the group_ref (250). The slotting plugin an the device mapper failed to modify the user specified value. The final value is the one from 250.

{imp4:22} If the user has a weak manual falback on the pin number, the history of pcb/pinnum would look like this:

    31050::u::foo.lth:182.4::
    15085::p::gschem_slot::slotting
    15045::p::devmap::derived from devmap

First the value was set by the instance-value specified by the user in the group_ref (31050). The slotting plugin an the device mapper can then modify the user specified value. The final value is the one from 15045. If the slotting or the devmap plugin did not modify the attribute, the user's weak value from 31050 would be the final value.

### 4.4.2. example on attribute symlinks

{imp4:23} The symbol/..::pcb/footprint means "find the closest symbol we are in, go one group up and use the pcb/footprint attribute from there".

{imp4:24} A more typical use is referencing a parameter attribute in a hierarchical design. For example in the child sheet implementing an amplifier will contain 6 opamps. The footprint attribute (attribute key called "pcb/footprint") should not be hardwired in the child sheet but should be provided by the parent. This is realized by:

- the opamp symbols used in the child sheet has its pcb/footprint attribute as a chscem-symlink pointing to "sheet::cschem/param/omamp-footprint"
- there is a default value specified in the child sheet attributes: cschem/param/omamp-footprint = so8
- the parent sheet symbol that instantiates the child sheet contains an attribute cschem/param/omamp-footprint = dip8

{imp4:25} When the instantiation happens, the parent symbol's atribute will override the sheet's original cschem/param/omamp-footprint attribute, so the final value of that attribute for this instance is "dip8". When the abstract model is compiled, the final value of the component's pcb/footprint will be copied from the sheet instance's cschem/param/omamp-footprint attribute because of the symlink dereference, thus will end up as dip8.

### 4.4.3. example on attribute key prefixes

{imp4:26} In slotting, multiple (concrete) symbols have the same name and will be merged into the same (abstract) component. Most attributes, like footprint, are either specified only once, or if they are specified in multiple symbols they have same value so there's no collision.

{imp4:27} However, when using devmap, the user also needs to specify the slot number, per symbol. Normally this would be slot=1, slot=2, slot=3, ... attributes, but these would collide during merge. The solution is to prefix keys with a minus sign, so symbol attributes are -slot=1, -slot=2, -slot=3. Minus prefixed conrete attributes are ignored during compilation, the resulting component does not have a slot attribute and there's no collision.

### 4.4.4. safe keys for user attributes

{imp4:28} Users would store their own attributes in groups, especially in symbols and wirenets. They would choose arbitrary attribute keys that do not clash with current attribute keys used by the code of a given implementation (e.g. sch-rnd) at the given time. However, future versions of the same implementation or a different implementation could use that same attribute key for other purposes, causing a clash, making the user's sheet non-portable.

{imp4:29} To avoid this problem, the convention is that attribute key prefix usr/ is reserved for user attributes: no code shall depend on such attributes. Such attributes shall be used exclusively by the user, e.g. on the GUI or exported to netlists and BOMs.