This page describes the code of the systemc parameterized CRC module.
                            
                            - 
							This generic serial CRC module, optionally gets input from user and during elaborate phase, it dynamically instantiates the required components, registers and x-or gates and connects them all.
							
 
 
                            - 
							I have learned a lot from this project. 
							First the goal was to be able to create a highly generic systemc component.
							When working with pointers, memory run over may occurs. In my case resulting in segmentation fault error. This is best debugged using a debugger. I selected GDB. Of great help was the debugger command bt: back trace.
							
 
                            - 
							The user may select to control the used polynum and its length form the command line. In that case the values are checked. When non-valid choices are made, it is fixed by the code. An assertion in the automatically insertion code makes sure, that a wrong value did not selected.
							
...
int sc_main(int argc, char* argv[]) {
  unsigned pol_len = 32;
  if (argc > 1) pol_len = atoi (argv[1]);
  if (pol_len <  4) pol_len = 4;
  if (pol_len > 32) pol_len = 32;
  cout << "crc_aut_inst pol_len=" << pol_len << " a=" << argc << endl;
...
//connect clock to every flop register
regp->pclk(pclk);
if( i == 0 ) {
  if( (pol & 0x1) == 0 ) {
    cout << "crc_aut_inst error x(0) of polynum must be 1 " << sc_time_stamp() << endl;
    sc_stop();
...
							
							
 
                            - 
                            The function sc_stop() can be replaced by SC_REPORT_ERROR to stop and print an error message.
							
  crc_aut_inst(
    sc_module_name name, unsigned pol, unsigned pol_len, sc_trace_file* _tf
  ): sc_module(name), tf(_tf) {
    char inst_buf[10];
    static const char* MSGID = "crc_auto_inst MDG";
    ...
	          cout << "crc_aut_inst error x(0) of polynum must be 1 " << sc_time_stamp() << endl;
		      SC_REPORT_ERROR(MSGID, "crc_aut_inst errorst");
	          //sc_stop();
							
							
 
                            - 
							The test-bench includes a generator, which drives stimuli. To make thing simple, I created an array of bytes and have them initialized. The data is taken from an ethernet project, which is also available at this site:
                             IP STACK ethernet project .
							The generator is implemented using the statement  SC_THREAD so later I can wait one cycle using the simple statement wait() .
							
//SC_HAS_PROCESS(pkt_drive);
//pkt_drive(sc_module_name name): sc_module(name)
SC_CTOR(pkt_drive) {
  //SC_METHOD(gen_p);
  SC_THREAD(gen_p);
  sensitive << pclk.pos();
							
							
 
                            - 
                            Per each polynum coefficient, a register is instantiated. Depending on coefficient value a x-or gate may be instantiated (1 means instantiate). The string inst_buf  is used for selecting the instance name. A register gets the name u_[0-9]* and x-or gate is named x_[0-9]*.
							
char inst_buf[10];
...
//auto inst
for (unsigned i=0; i < pol_len; i++) {
  sprintf(inst_buf, "u_%d", i); //instance name
  reg* regp = new reg(inst_buf);
  cout << "crc_aut_inst inst=" << inst_buf << endl;
  //connect clock to every flop register
  regp->pclk(pclk);
...
if( (pol & 0x1) == 0 ) {
  regp->data_in(*data_pr);
} else {
sc_signal<bool>* sig_xor_o = new sc_signal<bool>;
sprintf(inst_buf, "x_%d", i); //instance name
bool_xor* u_xor = new bool_xor(inst_buf);
u_xor->a(data_in);
u_xor->b(*data_pr);
u_xor->o(*sig_xor_o);
		  regp->data_in(*sig_xor_o);//tmp
...
							
							
 
                            - 
                            VCD waves are recorded both at the highest level and in crc_auto_inst  module. A c_trace_file *tf pointer is passed to the module.
							
sc_trace_file *tf;
tf = sc_create_vcd_trace_file("crc_auto_inst");
//26, 23, 22, 16, 12, 11, 10, 8, 7, 5, 4, 2, 1, 0
//33222222222211111111110000000000
//10987654321098765432109876543210
//00000100110000010001110110110111
crc_aut_inst u_dut("u_dut", 0x04c11db7, pol_len, tf);
...
//crc auto instance
class crc_aut_inst : public sc_module {
public:
  sc_trace_file *tf;
...
  crc_aut_inst(
    sc_module_name name, unsigned pol, unsigned pol_len, sc_trace_file* _tf
  ): sc_module(name), tf(_tf) {
  char inst_buf[10];
  sc_signal* data_pr  = 0;//previous data
  //sc_trace(tf, pclk, "clk");
  br>
  sprintf(inst_buf, "s_%d", i); //instance name
  sc_trace(tf, *data_pr, inst_buf);
                            
							
 
                            - 
                            To debug one can print the instance name:
							
                            class reg : public sc_module {
                            ...
                              void main() {
                                data_ou = data_in.read(); 
	                            cout << "reg " << name() << " " << sc_time_stamp() << endl;
                              }
                            
							
 
                            - 
                            If a break point in the auto instance component is required, one can add the following code and put there a break point:
							
if(strcmp(name(), "u_dut.u_26")) {//no match
  cout << "reg1 " << name() << " " << sc_time_stamp() << endl;
} else {//match
  //Place a break point on this line.
  cout << "reg2 " << name() << " " << sc_time_stamp() << endl;
}
                            
							
 
                             
                            To go to main project page:  systemc parameterized CRC module .
                           Contact me now at: |