Jump to content

Datapath connection problem in systemc rtl design


james_eali

Recommended Posts

I am trying to design a GCD chip in SystemC using the model in the image. However, I have eliminated the subtractor and the comparator, and insert an ALU instead to have both functionalities in one module. I did not use the EOC either. Here is my code

#include <systemc.h>
#include <ctime>

class Register : public sc_module 
{
public:
	sc_in<sc_logic> clk, reset, enable;
	sc_in<int> reg_in;
	sc_out <int> reg_out;

	SC_HAS_PROCESS(Register);
	Register(sc_module_name)
	{ 
		SC_METHOD(registering);
		sensitive << clk << reset;
	}
	void registering()
	{
		if (reset == '1')
			reg_out = 0;
		else if (clk->event() && (clk == '1'))
			if (enable == '1') reg_out = reg_in;
	}
};
class Multiplexer: public sc_module
{
public:
	sc_in<int> in1, in2;
	sc_in<sc_logic> sel;
	sc_out <int> Out;

	SC_CTOR(Multiplexer)
	{
		SC_METHOD(muxing);
		sensitive << in1 << in2 << sel;
	}
	void muxing()
	{
		Out = (sel == '0') ? in1 : in2;
	}
};
class ALU : public sc_module
{
public:
	sc_in <int> in1{ "in1" }, in2{ "in2" };
	sc_out <int> out_sub{ "out_sub" };
	sc_in < sc_logic > Opmode{ "Opmode" };
	sc_out <sc_logic> equal{ "equal" }, greater{ "greater" };

	SC_CTOR(ALU)
	{
		SC_METHOD(subtract);
		sensitive << in1 << in2;
		SC_METHOD(compare);
		sensitive << in1 << in2;
	}

	void subtract()
	{
		out_sub = 0;
		if (Opmode == '0')
			out_sub = in1 - in2;
	}
	void compare()
	{
		if (Opmode == '1')
		{
			if (in1 == in2) equal = SC_LOGIC_1;
			else if (in1 > in2) greater = SC_LOGIC_1;
			else greater = SC_LOGIC_0;
		}
	}
};
class DataPath: public sc_module
{
public:
	sc_in <int> A{ "A" }, B { "B" };
	sc_in <sc_logic> clk{ "clk" }, reset{"reset"};
	sc_in <sc_logic> a_sel{ "a_sel" }, b_sel{ "b_sel" };
	sc_in <sc_logic> ld_a{ "ld_a" }, ld_b{ "ld_b" }, ld_GCD{ "ld_b" }, OP_mode{"OP_mode"};
	sc_in<sc_logic> sel_in1{ "sel_in1" }, sel_in2{"sel_in2"};
	sc_out <int> GCD{"GCD"};
	sc_out <sc_logic> AEB{ "AEB" }, AGB{"AGB"}; // A equal to B, A greater to B

	sc_signal<int> alu_in1{ "alu_in1" }, alu_in2{ "alu_in2" }, alu_out{"alu_out"};
	sc_signal<int> regA_in{ "regA_in" }, regA_out{"regA_out"};
	sc_signal<int> regB_in{ "regB_in" }, regB_out{"regB_out"};
	sc_signal<sc_logic> regA_enb{ "regA_enb" }, regB_enb{ "regA_enb" }, regGCD_enb{"regGCD_enb"};

	Multiplexer *muxA, *muxB, *muxRA, *muxRB;
	Register *RA, *RB, *RGCD;
	ALU *alu;
	
	
	SC_CTOR(DataPath)
	{
		muxA = new Multiplexer("muxA");
		muxA->in1(A); 
		muxA->in2(alu_out); 
		muxA->sel(a_sel); 
		muxA->Out(regA_in);
		muxB = new Multiplexer("muxB");
		muxB->in1(B); 
		muxB->in2(alu_out); 
		muxB->sel(b_sel); 
		muxB->Out(regB_in);
		RA = new Register("RA");
		RA->clk(clk); 
		RA->enable(regA_enb); 
		RA->reset(reset); 
		RA->reg_in(regA_in); 
		RA->reg_out(regA_out);
		RB = new Register("RB");
		RB->clk(clk); 
		RB->enable(regB_enb); 
		RB->reset(reset); 
		RB->reg_in(regB_in); 
		RB->reg_out(regB_out);
		muxRA = new Multiplexer("muxRA");
		muxRA->in1(regA_out); 
		muxRA->in2(regB_out); 
		muxRA->sel(sel_in1); 
		muxRA->Out(alu_in1);
		muxRB = new Multiplexer("muxRB");
		muxRB->in1(regA_out); 
		muxRB->in2(regB_out); 
		muxRB->sel(sel_in2); 
		muxRB->Out(alu_in2);
		alu = new ALU("alu");
		alu->in1(alu_in1); 
		alu->in2(alu_in2); 
		alu->out_sub(alu_out); 
		alu->equal(AEB);
		alu->greater(AGB);
		alu->Opmode(OP_mode);
		RGCD = new Register("RGCD");
		RGCD->clk(clk); 
		RGCD->enable(regGCD_enb); 
		RGCD->reset(reset); 
		RGCD->reg_in(B); 
		RGCD->reg_out(GCD);


		/*SC_METHOD(datapath_function);
		sensitive << reset << a_sel << b_sel << sel_in1 << sel_in2
			<< ld_a << ld_b << ld_GCD;*/

	}

	/*void datapath_function()
	{
		regA_in = (a_sel->read() == '0') ? A.read() : alu_out.read();
		regB_in = (b_sel->read() == '0') ? B.read() : alu_out.read();
		regA_out = (regA_enb.read() == '1' && ld_a.read() == '1') ? regA_in : regA_out;
		regB_out = (regB_enb.read() == '1' && ld_b.read() == '1') ? regB_in : regB_out;
		alu_in1 = (sel_in1->read() == '0') ? regA_out: regB_out;
		alu_in2 = (sel_in2->read() == '0') ? regA_out : regB_out;
		if (OP_mode->read() == "0") alu->subtract();
		else alu->compare(); 

	}*/
};
class Controller : public sc_module
{
public:
	sc_in <sc_logic> start{ "start" }, clk{ "clk" }, rst{ "rst" }, AEB{ "AEB" }, AGB{"AGB"};
	sc_out <sc_logic> a_sel{"a_sel"}, b_sel{ "b_sel" }, ld_a{ "ld_a" }, ld_b{ "ld_b" }, ld_GCD{ "ld_GCD" }, OP_mode{ "OP_mode" };
	sc_out<sc_logic> sel_ALU_in1{ "sel_ALU_in1" }, sel_ALU_in2{"sel_ALU_in2"};

	enum states {idle, compare};
	sc_signal <states> P_state{ "P_state" }, N_state{"N_state"}; // present and next states
	
	SC_CTOR(Controller)
	{
		
		SC_METHOD(next_state_gen);
		sensitive << start << P_state;
		SC_THREAD(seq_function);
		sensitive << clk << rst;
	}
	void next_state_gen();
	void seq_function()
	{
		while(1)
		{
			if (rst == '1')
				P_state = idle;
			else if (clk->event() && (clk == '1'))
				P_state = N_state;
			wait();
		}
	}
};
void Controller::next_state_gen()
{
	switch (P_state)
	{
	case idle:
		a_sel = SC_LOGIC_0, 
		b_sel = SC_LOGIC_0,
		ld_a = SC_LOGIC_0, 
		ld_b = SC_LOGIC_0, 
		ld_GCD = SC_LOGIC_0;
		if (start == SC_LOGIC_1)
		{
			ld_a = SC_LOGIC_1, ld_b = SC_LOGIC_1;
			N_state = compare;
		}
		else
			N_state = P_state;
		break;
	case compare:
		sel_ALU_in1 = SC_LOGIC_0; 
		sel_ALU_in2 = SC_LOGIC_1;
		OP_mode = SC_LOGIC_1;
		if (AEB == SC_LOGIC_1)
		{
			ld_GCD = SC_LOGIC_1;
			N_state = idle;
		}
		else if(AGB == SC_LOGIC_1)
		{
			OP_mode = SC_LOGIC_1;
			a_sel = SC_LOGIC_1;
			N_state = P_state;
		}
		else
		{
			sel_ALU_in1 = SC_LOGIC_1; 
			sel_ALU_in2 = SC_LOGIC_0;
			OP_mode = SC_LOGIC_1;
			b_sel = SC_LOGIC_1;
			N_state = P_state;
		}
		break;
	default:
		N_state = idle;
		break;
	}
}
class GCD_ASIC : public sc_module
{
public:
	sc_in <sc_logic> clk{ "clk" }, rst{ "rst" }, start{"start"};
	sc_in <int> A{"A"}, B{ "B" };
	sc_out <int> GCD{"GCD"};
	
	sc_signal <sc_logic> selA{ "selA" }, selB{ "selB" };
	sc_signal <sc_logic> ALUsel_1{ "ALUsel_1" }, ALUsel_2{"ALUsel_2"};
	sc_signal <sc_logic> LdRA{ "LdRA" }, LdRB{ "LdRB" }, LdGCD{ "LdGCD" }, OP_Sel{"OP_Sel"};
	sc_signal <sc_logic> AEB{ "AEB" }, AGB{"AGB"};



	SC_CTOR(GCD_ASIC)
	{
		DP = new DataPath("DataPath");
		DP->clk(clk); 
		DP->A(A); 
		DP->B(B); 
		DP->reset(rst); 
		DP->a_sel(selA);
		DP->b_sel(selB);
		DP->ld_a(LdRA);
		DP->ld_b(LdRB);
		DP->sel_in1(ALUsel_1);
		DP->sel_in2(ALUsel_2);
		DP->OP_mode(OP_Sel);
		DP->AEB(AEB);
		DP->AGB(AGB);
		DP->ld_GCD(LdGCD);
		DP->GCD(GCD);
		CR = new Controller("Controller");
		CR->clk(clk);
		CR->start(start);
		CR->rst(rst);
		CR->a_sel(selA);
		CR->b_sel(selB);
		CR->ld_a(LdRA);
		CR->ld_b(LdRB);
		CR->OP_mode(OP_Sel);
		CR->AEB(AEB);
		CR->AGB(AGB);
		CR->ld_GCD(LdGCD);
		CR->sel_ALU_in1(ALUsel_1);
		CR->sel_ALU_in2(ALUsel_2);
	}
protected:
	DataPath *DP;
	Controller *CR;
};
class GCD_ASIC_TB : public sc_module
{
public:
	sc_signal <sc_logic> clk, rst, start;
	sc_signal <int> A, B;
	sc_signal <int> GCD;

	GCD_ASIC *DUT;

	SC_CTOR(GCD_ASIC_TB) 
	{
		DUT = new GCD_ASIC("DESIGN_UNDER_TEST");
		DUT->clk(clk);
		DUT->rst(rst);
		DUT->start(start);
		DUT->A(A);
		DUT->B(B);
		DUT->GCD(GCD);
		
		SC_THREAD(clocking);
		SC_THREAD(reseting);
		SC_THREAD(inputing);
	}

	void clocking();
	void reseting();
	void inputing();
};
void GCD_ASIC_TB:: clocking()
{
	while (true)
	{
		wait(10, SC_NS);
		clk = SC_LOGIC_0;
		wait(10, SC_NS);
		clk = SC_LOGIC_1;
	}
}
void GCD_ASIC_TB::reseting()
{
	while (true)
	{
		wait(12, SC_NS);
		rst = SC_LOGIC_0;
		wait(15, SC_NS);
		rst = SC_LOGIC_1;
		wait(32, SC_NS);
		rst = SC_LOGIC_0;
		wait();
	}
}
void GCD_ASIC_TB::inputing()
{
	wait(2, SC_NS);
	start = SC_LOGIC_0;
	wait(20, SC_NS);
	start = SC_LOGIC_1;
	wait(20, SC_NS);
	//wait();

	while (true)
	{
		srand(time(0));
		wait(7, SC_NS);
		A = (int)(rand() % 256 + 1);
        srand(time(0));
		wait(5, SC_NS);
		B = (int)(rand() % 256 + 1);
	}
}

int sc_main(int argc, char* argv[])
{
	
	GCD_ASIC_TB TB ("test_bench");
	sc_trace_file *vcd_file;

	vcd_file = sc_create_vcd_trace_file("GCD_TEST");
	sc_trace(vcd_file, TB.clk, "clock");
	sc_trace(vcd_file, TB.rst, "reset");
	sc_trace(vcd_file, TB.start, "start");
	sc_trace(vcd_file, TB.A, "A");
	sc_trace(vcd_file, TB.B, "B");
	sc_trace(vcd_file, TB.GCD, "GCD");

	sc_start(12000, SC_NS);
	sc_close_vcd_trace_file(vcd_file);
	
	return 0;
}

 

The problem is does not work. 

Could you please tell me where I am doing wrong?

Capture.PNG

Link to comment
Share on other sites

  • james_eali changed the title to RTL greatest common divisor design and simulation problem in sc_main

Your design has several issues and flaws. The issues are:

  1. In ALU you assign a value to opc_out in the constructor. At that point the port does not have a signal attached. You need to move this assignement into subtract:
        void subtract()
        {
            out_sub = 0;
            if (Opmode == '0')
                out_sub = in1 - in2;
        }

     

  2. You do not connect Opmode to a signal in Datapath

Aside of that these are the flaws I see:

  • you should name your signals and port. This helps to debig things. Using C++11 (which all actuall compilers use by default) you can do it like this which does not give to much overhead:
    class ALU : public sc_module
    {
    public:
        sc_in <int> in1{"in1"}, in2{"in2"};
        sc_out <int> out_sub{"out_sub"};
        sc_in < sc_logic > Opmode{"Opmode"};
        sc_out <sc_logic> equal{"equal"}, greater{"greater"};

     

  • There is no need to create modules dynamically except you want to do this in before_end_of_elaboation(). This eases readability and enures consistent memory management and destructor calls.
  • Dont do multiple declarations and assignements in the same line. Although C/C++ permits I highly recommend to avoid:
    void Controller::next_state_gen()
    {
        switch (P_state)
        {
        case idle:
            a_sel = SC_LOGIC_0, b_sel = SC_LOGIC_0,
            ld_a = SC_LOGIC_0, ld_b = SC_LOGIC_0, ld_GCD = SC_LOGIC_0;

    It makes reading and understanding your code difficult. And code is much more read than written.

 

Link to comment
Share on other sites

Thank you for your time dear Eyck. I have fixed the issues and some of flaws (edited original posted). Then, when I ran the program new errors, such as "regA_in cannot have multiple drivers; the first driver is in datapath_function and the second in muxA.muxing()" appeared.

So I commented out the whole datapath_function and the program worked. However, the it did not generate anything output. i.e. the vcd file only contains the Ain, Bin, Clock,... and the GCD output is always zero.

Could you guide me on this please?

Link to comment
Share on other sites

  • james_eali changed the title to Datapath connection problem in systemc rtl design
  • 3 weeks later...

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...