Chapter 3: Communication

FIFOs, Mutexes, Semaphores, and Custom Channels

When to use built-in channels and how to design communication abstractions of your own.

Not every connection should be a signal. SystemC includes higher-level channels such as FIFOs, mutexes, and semaphores because many system models care more about transactions and resources than individual wires.

sc_fifo

sc_fifo<T> models queued communication:

#include <systemc>
using namespace sc_core;
 
SC_MODULE(Producer) {
  sc_fifo_out<int> out{"out"};
 
  SC_CTOR(Producer) {
    SC_THREAD(run);
  }
 
  void run() {
    for (int i = 0; i != 8; ++i) {
      out.write(i);
      std::cout << "Wrote " << i << " at " << sc_time_stamp() << std::endl;
      wait(10, SC_NS);
    }
  }
};
 
SC_MODULE(Consumer) {
  sc_fifo_in<int> in{"in"};
  SC_CTOR(Consumer) { SC_THREAD(run); }
  void run() {
    while (true) {
      int val = in.read();
      std::cout << "Read " << val << " at " << sc_time_stamp() << std::endl;
    }
  }
};
 
int sc_main(int, char*[]) {
  sc_fifo<int> fifo(4);
  Producer p("p");
  Consumer c("c");
  p.out(fifo);
  c.in(fifo);
  sc_start(100, SC_NS);
  return 0;
}

The blocking write() waits when the FIFO is full. The blocking read() waits when the FIFO is empty. This is often perfect for modeling pipelines, queues, and producer-consumer systems.

Mutexes and Semaphores

sc_mutex and sc_semaphore model shared resources. Use them when the model question is about arbitration or resource ownership.

#include <systemc>
using namespace sc_core;
 
SC_MODULE(Master) {
  sc_port<sc_mutex_if> bus_lock{"bus_lock"};
 
  SC_CTOR(Master) { SC_THREAD(run); }
 
  void run() {
    bus_lock->lock();
    std::cout << name() << " got lock at " << sc_time_stamp() << std::endl;
    wait(20, SC_NS);
    bus_lock->unlock();
  }
};
 
int sc_main(int, char*[]) {
  sc_mutex mutex("mutex");
  Master m1("m1"), m2("m2");
  m1.bus_lock(mutex);
  m2.bus_lock(mutex);
  sc_start(50, SC_NS);
  return 0;
}

These are modeling constructs, not magic performance tools. Use them when they express the system behavior clearly.

Custom Channels

Custom channels are where SystemC becomes a modeling framework rather than a fixed simulator. You define an interface, implement it in a channel, and bind modules to that interface.

Good custom channels hide policy:

  • timing
  • arbitration
  • buffering
  • tracing
  • protocol conversion
  • statistics

The module using the channel should care about the operation it needs, not the machinery behind it.

Design Rule

If the connection is a wire, use a signal. If the connection is a transaction, use an interface or TLM socket. If the connection is a queue, use a FIFO. If the connection is a shared resource, use a mutex or semaphore. The model reads better when the channel matches the concept.

Comments and Corrections