#include <systemc>

using namespace sc_core;
using namespace sc_dt;
using namespace std;

SC_MODULE(Dynamic) {
    sc_in_clk clk; 
    sc_out<int> outport;
    SC_CTOR(Dynamic) {
        SC_THREAD(produce);
        sensitive << clk.pos(); // static sensitivity list
        SC_THREAD(consume);
        sensitive << clk.pos(); // static sensitivity list
        pkt = 0;
    }
private:
    sc_event p_event, c_event; 
    int pkt;
    int produce_packet(){
        return ++pkt;
    }
    void consume_packet(int packet){
        cout << "@ " << sc_time_stamp() << ": Packet written out: " << packet << endl;
        outport.write(packet);
    }
    void produce() {
        while (true) {
            pkt = produce_packet();
            cout << "@ " << sc_time_stamp() << ": Packet produced: " << pkt << endl;
            p_event.notify(5, SC_NS); // notify p_event after 5 ns
            wait(); // wait for 1 event from static sensitivity list clk.pos()
            wait(c_event); // wait for c_event
        }
    }
    void consume() {
        while (true) {
            wait(p_event); // wait for p_event
            consume_packet(pkt);
            cout << "@ " << sc_time_stamp() << ": Packet consumed: " << pkt << endl;
            wait(3); // wait for 3 events from static sensitivity list clk.pos()
            c_event.notify(); // notify c_event immediately 
        }
    }
};

int sc_main(int argc, char *argv[]) {
    Dynamic d("d");
    sc_clock clock("clock", 3, SC_NS);
    sc_signal<int> out;
    d.clk(clock);
    d.outport(out);

    auto tf = sc_create_vcd_trace_file("trace");
    tf->set_time_unit(100, SC_PS);
    sc_trace(tf, clock, "clock");
    sc_trace(tf, out, "out");

    sc_start(30, SC_NS);

    sc_close_vcd_trace_file(tf);
    cin.get();
    return 0;
}