Fonctions logiques
Opérations booléennes
Les variables ou signaux booléens ne peuvent prendre que 2 états, qui peuvent être désignés par différents mnémoniques selon le contexte
| 0 | 1 |
|---|---|
| false | true |
| no | yes |
| off | on |
| low | high |
Dans la suite, le symbole X est en outre utilisé pour « don't care » (indifférent), c'est-à-dire que la valeur n'a aucune influence sur le résultat. Les fronts sont indiqués par la notation correspondante 0->1 ou 1->0.
À titre de comparaison, le lien avec les circuits intégrés logiques classiques de la série 74 est indiqué à de nombreux endroits (par ex. 74HC147). Pour les composants complexes, la fonction implémentée dans le module Math offre le plus souvent encore plus d'options que le modèle cité.
La fonction logique élémentaire la plus simple est l'élément inverseur « NOT » :
| NOT A | |
|---|---|
| A | (74HC04) |
| 0 | 1 |
| 1 | 0 |
Lorsque deux variables ou signaux booléens sont combinés, 2 fonctions logiques élémentaires AND et OR sont utilisées :
| A AND B | A OR B | A XOR B | ||
|---|---|---|---|---|
| A | B | (74HC21) | (74HC32) | (74HC86) |
| 0 | 0 | 0 | 0 | 0 |
| 0 | 1 | 0 | 1 | 1 |
| 1 | 0 | 0 | 1 | 1 |
| 1 | 1 | 1 | 1 | 0 |
L'élément XOR (OR exclusif) peut être réalisé par une combinaison complexe de AND, OR et NOT ; il est présenté ici comme élément à part afin de faciliter l'illustration de la fonction dans la suite.
En combinant avec un étage NOT, on obtient respectivement
| A NAND B | A NOR B | A NXOR B | ||
|---|---|---|---|---|
| A | B | (74HC00) | (74HC02) | (74HC266) |
| 0 | 0 | 1 | 1 | 1 |
| 0 | 1 | 1 | 0 | 0 |
| 1 | 0 | 1 | 0 | 0 |
| 1 | 1 | 0 | 0 | 1 |
Selon les types de données, les opérateurs et fonctions logiques suivants sont utilisés, les 64 bits du type numérique <uint> (unsigned integer) étant soumis individuellement aux fonctions logiques :
<bool> A, B | <uint> A, B | |
|---|---|---|
| NOT | !A | bNot(A) |
| AND | A && B | bAnd(A,B) |
| OR | A || B | bOr(A,B) |
| XOR | A ^^ B | bXOr(A,B) |
| NAND | !(A && B) | bNAnd(A,B) |
| NOR | !(A || B) | bNOr(A,B) |
| NXOR | !(A ^^ B) | bNXOr(A,B) |
Fonctions orientées bit
Ces fonctions de bits ne sont pas des opérateurs logiques ! Elles travaillent toujours sur la représentation interne en <uint> et convertissent donc d'abord tous les paramètres en type <uint>. Cela apparaît clairement, par exemple, avec la fonction bNot(), qui inverse tous les bits de la valeur d'entrée.
bNot(false) => bNot(0x00) => 0xFFFFFFFFFFFFFFFF => logic: truebNot(true) => bNot(0x01) => 0xFFFFFFFFFFFFFFFE => logic: true
Même si le résultat de l'opérateur XOR ^^ ressemble à celui de != (différent), le premier impose le type de données <bool> à ses opérandes, alors que != ou == recherchent la meilleure représentation commune aux deux types de données et, en cas de mélange de types différents, convertissent généralement l'opérande booléen en une valeur numérique 0 ou 1 (<uint>, <int>, <dbl>) pour la comparaison.
| Fonction | Description |
|---|---|
| bNot(x) | inversion orientée bit de x (voir aussi l'opérateur ~)Pour un NOT logique sur un terme <bool>, utiliser l'opérateur !. |
| bAnd(x1, ..., xN) | conjonction bit à bit (AND) de toutes les expressions x1, ..., xN |
| bNAnd(x1, ..., xN) | conjonction bit à bit (AND) de toutes les expressions x1, ..., xN, suivie d'une inversion |
| bOr(x1, ..., xN) | disjonction bit à bit (OR) de toutes les expressions x1, ..., xN |
| bNOr(x1, ..., xN) | disjonction bit à bit (OR) de toutes les expressions x1, ..., xN, suivie d'une inversion |
| bXor(x1, ..., xN) | disjonction exclusive bit à bit (OR) de toutes les expressions x1, ..., xN |
| bNXor(x1, ..., xN) | disjonction exclusive bit à bit (OR) de toutes les expressions x1, ..., xN, suivie d'une inversion |
| bShift(x,n) | décalage bit à bit (SHIFT) de x de n positions vers la gauche, vers la droite si n est négatif |
| bCount(x) | nombre de bits positionnés dans x |
| bTest(x,n) | test visant à déterminer si le n-ième bit de x est positionné, n correspond au poids du bit |
| bSet(x,n,v) | positionnement (v=true) ou effacement (v=false) du bit dans x |
Éléments logiques
Détection de fronts « posedge », « negedge », « onchange »
Pour les éléments de détection de fronts, le signal d'entrée peut être n'importe quelle valeur numérique scalaire de type <bool>, <uint>, <int> ou <dbl>.
| Fonction | Description |
|---|---|
| posedge(x) | renvoie true pendant une nanoseconde lorsque la valeur actuelle du signal y est supérieure à sa valeur précédente |
| negedge(x) | renvoie true pendant une nanoseconde lorsque la valeur actuelle du signal y est inférieure à sa valeur précédente |
| onchange(x) | renvoie true pendant une nanoseconde lorsque la valeur actuelle du signal y a changé par rapport à la valeur précédente |
En raison de la durée extrêmement courte du signal, de 1 ns seulement, un tel signal est en général manqué par la transmission MQTT. Seuls les enregistrements dans des fichiers OSF conviennent donc pour le contrôle ou la visualisation.
Bascule RS « rsFF »
Avec true sur l'entrée reset, la sortie passe à false ; avec true sur l'entrée set, la sortie est mise à true. reset est prioritaire.
Les entrées reset et set sont interprétées comme <bool>.
Q = rsFF(reset, set);
// Optionale Konfiguration
Qx = rsFF(..., { storage: <str>
});
| Propriété | Valeur | Description |
|---|---|---|
| storage | <str> | Nom d'une mémoire persistante pour l'état interne. Après un redémarrage du système, la sortie reprend ainsi la dernière valeur enregistrée. Le contenu de cette mémoire n'est utilisable à aucun autre endroit dans smartCORE. |
| reset | set | Sortie |
|---|---|---|
| 0 | 0 | Le dernier état est conservé |
| 0 | 1 | 1 |
| 1 | X | 0 |
Bascule JK « jkFF »
Sur front montant de l'entrée clock, les entrées de préparation j et k déterminent comment la sortie est modifiée (74HC73).
Avec true sur l'entrée reset, la sortie passe à false ; avec true sur l'entrée set, la sortie est mise à true. reset est prioritaire.
Toutes les entrées sont interprétées comme <bool>.
Q1 = jkFF(clock, j, k);
Q2 = jkFF(clock, j, k, reset);
Q3 = jkFF(clock, j, k, reset, set);
// Optionale Konfiguration für alle Varianten
Qx = jkFF(..., { storage: <str>
});
| Propriété | Valeur | Description |
|---|---|---|
| storage | <str> | Nom d'une mémoire persistante pour l'état interne. Après un redémarrage du système, la sortie reprend ainsi la dernière valeur enregistrée. Le contenu de cette mémoire n'est utilisable à aucun autre endroit dans smartCORE. |
| clock | j | k | reset | set | Sortie |
|---|---|---|---|---|---|
| 0 | X | X | 0 | 0 | Le dernier état est conservé |
| 1 | X | X | 0 | 0 | Le dernier état est conservé |
| 0->1 | 0 | 0 | 0 | 0 | Le dernier état est conservé |
| 0->1 | 0 | 1 | 0 | 0 | 0 |
| 0->1 | 1 | 0 | 0 | 0 | 1 |
| 0->1 | 1 | 1 | 0 | 0 | La sortie change d'état |
| X | X | X | 1 | X | 0 |
| X | X | X | 0 | 1 | 1 |
Bascule D « dFF »
Sur front montant de l'entrée clock, la valeur présente sur l'entrée data est mémorisée (74HC74).
Avec true sur l'entrée reset, la sortie passe à false ; avec true sur l'entrée set, la sortie est mise à true. reset est prioritaire.
Cette bascule peut mémoriser tous les types de données. À l'exception de data, toutes les entrées sont interprétées comme <bool>.
Q1 = dFF(clock, data);
Q2 = dFF(clock, data, reset);
Q3 = dFF(clock, data, reset, set);
// Optionale Konfiguration für alle Varianten
Qx = dFF(..., { storage: <str>
});
| Propriété | Valeur | Description |
|---|---|---|
| storage | <str> | Nom d'une mémoire persistante pour l'état interne. Après un redémarrage du système, la sortie reprend ainsi la dernière valeur enregistrée. Le contenu de cette mémoire n'est utilisable à aucun autre endroit dans smartCORE. |
| clock | data | reset | set | Sortie |
|---|---|---|---|---|
| 0 | X | 0 | 0 | La dernière valeur de sortie est conservée |
| 1 | X | 0 | 0 | La dernière valeur de sortie est conservée |
| 0->1 | <var> | 0 | 0 | Sortie et mémorisation de la valeur présente sur data |
| X | X | 1 | X | La sortie est mise à <false> |
| X | X | 0 | 1 | La sortie est mise à <true> |
Verrou D « dLatch »
Avec true sur l'entrée hold, la dernière valeur de l'entrée data est mémorisée ; sinon, la sortie suit directement l'entrée data (74HC75). Cette bascule peut mémoriser tous les types de données. L'entrée hold est interprétée comme <bool>.
Q = dLatch(hold, data);
// Optionale Konfiguration
Qx = dLatch(..., { storage: <str>
});
| Propriété | Valeur | Description |
|---|---|---|
| storage | <str> | Nom d'une mémoire persistante pour l'état interne. Après un redémarrage du système, la sortie reprend ainsi la dernière valeur enregistrée. Le contenu de cette mémoire n'est utilisable à aucun autre endroit dans smartCORE. |
| hold | data | Sortie |
|---|---|---|
| 0 | <var> | Suit la valeur présente sur data |
| 1 | X | La dernière valeur de sortie est conservée |
Si hold et data changent simultanément, la nouvelle valeur de data n'est déjà plus prise en compte.
Mémoire indexée « memory » 1
La fonction memory est un dLatch() ou un dFF() adressable, doté de fonctionnalités étendues. La valeur de retour est le vecteur de données mémorisé. Le type de données est défini par le paramètre preset.
MEM1 = memory(control, index, data, {...});
MEM2 = memory(control, index, data, reset, {...});
// mandatory configuration
MEMx = memory(..., { mode: <enum> // mandatory
, size: <uint> // mandatory
, preset: <var> // recommended
, weight: <dbl>
, storage: <str>
});
| Propriété | Valeur | Description |
|---|---|---|
| mode | <enum> | latch : avec true sur l'entrée control, la dernière valeur de l'entrée data est mémorisée dans l'élément index ; sinon, l'élément suit directement l'entrée data (comme dLatch())set : mem[index] = data, sur front montant de l'entrée control, la valeur de l'entrée data est mémorisée dans l'élément index (comme dFF())add : mem[index] += data, sur front montant de l'entrée control, la valeur de l'entrée data est ajoutée à l'élément index : mult : mem[index] *= data, sur front montant de l'entrée control, la valeur de l'entrée data est multipliée par l'élément indexweight : mem[index] = (1-weight)*mem[index] + weight*data, sur front montant de l'entrée control, la valeur de l'entrée data est multipliée par ce facteur de pondération et ajoutée à l'élément index pondéré inversement. |
| size | Nombre d'emplacements mémoire réservés (indexés à partir de 0 jusqu'à size-1) et taille du vecteur de sortie. | |
| preset | Initialisation de la mémoire (avec reset = true) et définition du type de données, par ex. 0.0 pour <dbl> ou 0 pour <int>. | |
| weight | Facteur de pondération pour le mode weight, plage de valeurs valide | |
| storage | <str> | Nom d'une mémoire persistante pour le vecteur de données. Après un redémarrage du système, la sortie reprend ainsi la dernière valeur enregistrée. Le contenu de cette mémoire n'est utilisable à aucun autre endroit dans smartCORE. |
Un élément du vecteur « mémoire » peut être lu avec la syntaxe d'indexation [...] ou la fonction GetCol(), y compris à différents endroits du texte de la formule :
e1 = MEMx[rdIndex];
e2 = GetCol(MEMx, rdIndex);
Un cas d'usage fréquent de la fonction memory() est, par exemple, la mémorisation de relevés de compteurs d'énergie. Dans ce cas, on obtiendrait en mode latch l'index à partir de la fonction decodeTime(), par ex. comme jour de la semaine, et l'on injecterait comme data le relevé cumulé du compteur d'énergie. L'entrée control est maintenue constamment à false afin de suivre les valeurs du compteur d'énergie.
Une seconde mémoire conserve de manière analogue les valeurs de la veille, de sorte que la consommation journalière résulte de la différence entre les vecteurs.
Une implémentation se trouve dans l'exemple 1c).
Multiplexeur « select »
Multiplexeur (74HC151). L'index i sélectionne un signal s0, s1, ... qui est ensuite transmis. Si i est négatif ou supérieur ou égal au nombre d'entrées (n+1), false est émis. Les signaux peuvent représenter n'importe quel type de données ; la sortie change donc également de type de données en conséquence.
y = select(i, s0, s1, ...sn);
| i | s0 | s1 | ... | sn | Sortie |
|---|---|---|---|---|---|
| < 0 | X | X | ... | X | false |
| 0 | <var> | X | ... | X | suit s0 |
| 1 | X | <var> | ... | X | suit s1 |
| n | X | X | ... | <var> | suit sn |
| > n | X | X | ... | X | false |
En langage C, cela correspondrait à l'instruction suivante :
switch(i)
{
case 0: return s0;
case 1: return s1;
// ...
case n: return sn;
default: return false;
}
Si les différents signaux sont déjà regroupés sous forme de vecteur, il est plus simple d'utiliser la syntaxe d'indexation pour les vecteurs :
VSig = [s0, s1, ...sn]; // eventually result of calculation or buffering
yi = VSig[i];
Il convient alors toutefois de veiller à ce que i reste dans une plage de valeurs valide [0 .. n].
Encodeur de priorité « prioEnc »
Encodeur de priorité (similaire au 74HC147 ou 74HC148). En comptant par ordre croissant, l'index de la première entrée active est émis. L'objet de configuration facultatif permet de régler des variantes de fonctionnement. Toutes les entrées sont interprétées comme <bool>.
enc1 = prioEnc(e0, e1, ...);
// Optionale Konfiguration
encX = prioEnc(..., { none: <int>
, active: <bool>
, edge: <bool>
, map: [<int>]
, latch: <bool>
, startup: inf|<bool>
});
| Propriété | Valeur | Description |
|---|---|---|
| none | <int> | Si aucune entrée n'est active, cette valeur est émise (déf. : -1) |
| active | <bool> | Permet de régler le niveau à reconnaître comme actif (avec edge : false) (déf. : true). |
| edge | <bool> | Avec true, seuls les fronts positifs (active : true) ou négatifs (active : false) sont utilisés pour le déclenchement. |
| map | [<int>] | Table d'affectation des valeurs de sortie aux entrées de commande e0, e1, ... par ex.[1, 10, 100, 1000] |
| latch | <bool> | Avec true, l'index de la dernière entrée active est conservé (bouton radio). |
| startup | inf/<bool> | Définition d'un niveau de référence pour les entrées au démarrage du logiciel |
Dans le tableau suivant, une entrée est active lorsque l'état défini par les propriétés active et edge est vérifié. Sinon, elle est inactive.
| e0 | e1 | ... | en | Sortie |
|---|---|---|---|---|
| inactive | inactive | ... | inactive | latch = false : -1 ou valeur de la propriété none latch = true : la dernière valeur activée (bouton radio) |
| active | X | ... | X | 0 ou la valeur définie avec map[0] |
| inactive | active | ... | X | 1 ou la valeur définie avec map[1] |
| inactive | inactive | ... | active | n ou la valeur définie avec map[n] |
Pour le démarrage du système, il faut définir comment traiter le passé des entrées et si des fronts doivent ainsi être détectés immédiatement au démarrage. La propriété startup sert à cela :
-
inf : le premier échantillon du signal détermine la valeur dans le passé avant le démarrage du système ; aucun front n'est donc déclenché avec le premier échantillon.
-
<bool>: les entrées sont supposées avoir cette valeur de signal (true, false) dans le passé avant le démarrage du système. Un front peut ainsi éventuellement être déclenché avec le premier échantillon d'une entrée.
En langage C, cela correspondrait (sans edge, latch ni startup) à l'instruction suivante :
if (e0 == active)
return map.size() > 0 ? map[0] : 0;
else if (e1 == active)
return map.size() > 0 ? map[1] : 1;
// ...
else if (en == active)
return map.size() > 0 ? map[n] : n;
else
return none; // by default -1;