#include <systemc>

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

SC_MODULE(Adder2Bits) {
    sc_in<sc_logic> A0, B0, A1, B1, Cin;
    sc_out<sc_logic> S0, S1, Cout;
    SC_CTOR(Adder2Bits) {
        SC_METHOD(add);
        sensitive << A0 << B0 << A1 << B1 << Cin;
    }
private:
    void add() {
        sc_uint<3> a = 0, b = 0, c = 0;
        a[1] = A1.read().to_bool(); a[0] = A0.read().to_bool(); 
        b[1] = B1.read().to_bool(); b[0] = B0.read().to_bool(); 
        c[0] = Cin.read().to_bool();
        sc_uint<3> s = a + b + c;
        S0.write(sc_logic(s[0].to_bool()));
        S1.write(sc_logic(s[1].to_bool()));
        Cout.write(sc_logic(s[2].to_bool()));
    }
};

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

int sc_main(int argc, char *argv[]){
    sc_signal<sc_logic> A1, A0, B1, B0, Cin;
    sc_signal<sc_logic> S0, S1, Cout;
    Adder2Bits adder2Bits("adder2Bits");
    Testbench testbench("testbench");
    adder2Bits.A1(A1);
    adder2Bits.A0(A0);
    adder2Bits.B1(B1);
    adder2Bits.B0(B0);
    adder2Bits.Cin(Cin);
    adder2Bits.S0(S0);
    adder2Bits.S1(S1);
    adder2Bits.Cout(Cout);
    testbench.TA0(A0);
    testbench.TA1(A1);
    testbench.TB1(B1);
    testbench.TB0(B0);
    testbench.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, A0, "A0");
    sc_trace(tf, A1, "A1");
    sc_trace(tf, B0, "B0");
    sc_trace(tf, B1, "B1");
    sc_trace(tf, Cin, "Cin");
    sc_trace(tf, S0, "S0");
    sc_trace(tf, S1, "S1");
    sc_trace(tf, Cout, "Cout");

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

    sc_close_vcd_trace_file(tf);
    return 0;
}
