#include <systemc>

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

SC_MODULE(Adder) {
    sc_out<sc_logic> S, Cout;
    sc_in<sc_logic> A, B, Cin;
    SC_CTOR(Adder) {
        SC_METHOD(add);
        sensitive << A << B << Cin;
    }
private:
    void add() { 
        S.write(A.read() ^ B.read() ^ Cin.read());
        Cout.write(A.read() & B.read() | Cin.read() & (A.read() ^ B.read()));
    }
};

SC_MODULE(Testbench) {
    sc_out<sc_logic> TA, TB, TCin;
    SC_CTOR(Testbench) {
        SC_THREAD(testprocess);
    }
private:
    void testprocess() {
        TA.write(SC_LOGIC_0);
        TB.write(SC_LOGIC_0);
        TCin.write(SC_LOGIC_0);
        wait(10, SC_NS);
        TA.write(SC_LOGIC_1);
        wait(10, SC_NS);
        TB.write(SC_LOGIC_1);
        wait(10, SC_NS);
        TCin.write(SC_LOGIC_1);
        wait(10, SC_NS);
        TA.write(SC_LOGIC_0);
        TB.write(SC_LOGIC_0);
        TCin.write(SC_LOGIC_0);
    }
};

int sc_main(int argc, char *argv[]) {
    sc_signal<sc_logic> A, B, Cin;
    sc_signal<sc_logic> S, Cout;
    Adder adder("adder"); 
    adder.A(A);
    adder.B(B);
    adder.Cin(Cin);
    adder.S(S);
    adder.Cout(Cout);
    Testbench tb("tb");
    tb.TA(A);
    tb.TB(B);
    tb.TCin(Cin);
    
    // Record (trace) signals for verification
    auto tf = sc_create_vcd_trace_file("trace");
    tf->set_time_unit(1, SC_NS);
    sc_trace(tf, A, "A");
    sc_trace(tf, B, "B");
    sc_trace(tf, Cin, "Cin");
    sc_trace(tf, S, "S");
    sc_trace(tf, Cout, "Cout");

    // Start the simulation for 200ns 
    sc_start(200, SC_NS);

    sc_close_vcd_trace_file(tf);
    return 0;
}
