Threads, événements, mailboxes et sémaphores
Faire travailler plusieurs parties du testbench en parallèle et choisir le bon mécanisme de synchronisation.
Plusieurs activités en même temps
Un testbench doit souvent générer des commandes, surveiller des réponses et gérer un timeout en parallèle. fork...join lance plusieurs threads.
fork
drive_requests();
monitor_responses();
watch_timeout();
joinjoin attend tous les threads. join_any reprend dès que l'un se termine. join_none reprend immédiatement et laisse les threads continuer. Avec join_any, il faut souvent arrêter proprement les autres branches, par exemple avec disable fork, afin de ne pas laisser un timeout ou un driver tourner après la fin du test.
Les variables locales automatiques évitent qu'une boucle partage involontairement la même valeur entre threads.
Événements
Un event transmet une notification sans transporter de données.
event reset_done;
fork
begin
apply_reset();
-> reset_done;
end
begin
@reset_done;
start_traffic();
end
join-> déclenche l'événement et @reset_done attend le prochain déclenchement. Un événement peut être manqué si le déclenchement arrive avant que le thread ne commence à attendre. Pour une condition persistante, une variable d'état avec wait(condition) est souvent plus adaptée.
Mailboxes
Une mailbox est un canal FIFO qui transporte des valeurs ou des handles d'objets entre threads.
mailbox #(bus_transaction) gen_to_drv = new();
// Générateur
gen_to_drv.put(tr);
// Driver
bus_transaction next_tr;
gen_to_drv.get(next_tr);put et get sont bloquants. try_put, try_get et try_peek permettent de continuer si l'opération n'est pas possible. Une mailbox bornée peut créer une contre-pression dans le testbench, mais il faut éviter qu'un mauvais ordre d'attente bloque tout l'environnement.
Sémaphores
Un sémaphore gère un nombre de clés représentant une ressource partagée.
semaphore bus_lock = new(1);
bus_lock.get(1);
drive_exclusive_sequence();
bus_lock.put(1);Avec une seule clé, il joue le rôle d'un verrou. Le code doit toujours rendre exactement les clés obtenues, y compris lorsqu'une erreur survient. Un sémaphore protège l'accès, mais ne transporte ni commande ni résultat.
Choisir le mécanisme
- utiliser
forkpour lancer des activités parallèles ; - un
eventpour un signal ponctuel sans données ; - une mailbox pour transmettre des transactions ;
- un sémaphore pour limiter l'accès à une ressource.
Une synchronisation simple est plus facile à déboguer. Les blocages viennent souvent d'un thread qui attend une notification déjà passée ou d'une ressource jamais rendue.
À retenir
fork...joincontrôle le lancement et l'attente de threads.- Un événement peut être manqué s'il n'est pas attendu au bon moment.
- Une mailbox transporte des transactions dans l'ordre FIFO.
- Un sémaphore protège une ressource partagée avec un nombre de clés.
- Chaque thread doit avoir une condition de fin et une stratégie de timeout.
📝 Tester mes connaissances - Quiz du chapitre