4. cschem implementation - attributes

4.1. Are priorities distractive?

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

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

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

{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:

{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:

{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:

{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.