#include <systemc>

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

template <typename T>
SC_MODULE(gcd) {
    sc_in<T> x_i, y_i;
    sc_out<T> r_o;
    SC_CTOR(gcd) {
        SC_METHOD(run);
        sensitive << x_i << y_i;
    }
private:
    void run() {
        T x = x_i.read();
        T y = y_i.read();
        while (x != y) {
            if (x > y) {
                x -= y;
            } else {
                y -= x;
            }
        }
        r_o.write(x);
    }
};

template <typename T>
SC_MODULE(tb_gcd) {
    sc_in<T> r_i;
    sc_out<T> x_o, y_o;
    SC_CTOR(tb_gcd) {
        SC_THREAD(run);
    }
private:
    void check(const T& x, const T& y, const T& r) {
        wait(10, SC_NS);
        x_o.write(x);
        y_o.write(y);
        wait(10, SC_NS);
        assert(r_i.read() == r);
    }
    void run() {
        check(0, 0, 0);
        check(234, 96, 6);
        check(12345, 67891, 1);
        check(12345, 67890, 15);
        check(12345, 12345, 12345);

        wait(10, SC_NS);
        x_o.write(0);
        y_o.write(0);
        sc_stop();
    }
};

int sc_main(int argc, char *argv[]) {
    gcd<unsigned int> gcd("gcd");
    tb_gcd<unsigned int> tb_gcd("tb_gcd");
    sc_buffer<unsigned int> x, y, r;
    
    gcd.x_i(x);
    gcd.y_i(y);
    gcd.r_o(r);

    tb_gcd.x_o(x);
    tb_gcd.y_o(y);
    tb_gcd.r_i(r);

    sc_start();

    return 0;
}
