lsils / mockturtle

C++ logic network library
MIT License
191 stars 133 forks source link

Getting parse errors when reading Verilog files using Lorina Verilog reader #624

Closed Maya7991 closed 9 months ago

Maya7991 commented 9 months ago

Getting parse errors when reading Verilog files using Lorina Verilog reader. I want to read a Verilog file, generate it's Majority-Inverter Graph(MIG) and write it to a Verilog file.

To Reproduce Steps to reproduce the behavior:

  1. Using mockturtle latest version.

  2. Main.cpp

    int main()
    {
    std::string input_file, output_file, top;
    std::cout << "Enter the input verilog file name: "; // filename.v
    std::cin >> input_file;
    std::cout << "Enter the name of top module: ";
    std::cin >> top;
    
    diagnostics consumer;
    lorina::diagnostic_engine diag( &consumer );
    klut_network gate_network;
    
    if ( lorina::read_verilog( input_file, verilog_reader( gate_network, top ), &diag) != lorina::return_code::success )
    {
      fmt::print( "[e] Could not read input file `{}`\n", input_file );
      return -1;
    }
    mig_network mig;
    mig = convert_klut_to_graph<mig_network>( klut );
    mig_network mig1 = cleanup_dangling(mig);
    write_verilog(mig, "mig_output.v");
    return 0;
    }
  3. The input Verilog file for which the error occurs.

    module full_adder(a, b, cin, S, Cout);
    input a, b, cin;
    output S,Cout;
    assign S = a ^ b ^ cin;
    assign Cout = (a & b) | (b & cin) | (a & cin); 
    endmodule
  4. Error messages or print-outs you see (if any) (preferably copy-pasted as-is).

[e] Diagnostic Message: `cannot parse expression on right-hand side of assign `Cout``
[e] Diagnostic Message: `cannot parse assign statement`

Environment

Additional context The error occurs when parsing the line assign Cout = (a & b) | (b & cin) | (a & cin); and works fine for other lines. I tested the code for a half-adder Verilog file which has assign cout = a & b; and it works. Please help me to find a workaround in reading Verilog files. Is this is not the right approach for reading a Verilog and converting it to MIG using Mockturtle.

Check list

aletempiac commented 9 months ago

The MAJ3 operation is parsed using a fixed structure. In particular, the parser expects the variables to be in the following configuration: ( OP1 & OP2 ) | ( OP1 & OP3 ) | ( OP2 & OP3 ).

Hence, the correct way of writing the majority operation in your Verilog code is as follows: assign Cout = (a & b) | (a & cin) | (b & cin);

Moreover, note that you can read from a Verilog file directly into an MIG:

  lorina::text_diagnostics consumer;
  lorina::diagnostic_engine diag( &consumer );
  mig_network mig;

  if ( lorina::read_verilog( input_file, verilog_reader( mig ), &diag ) != lorina::return_code::success )
  {
    fmt::print( "[e] Could not read input file `{}`\n", input_file );
    return -1;
  }

  std::cout << mig.num_gates() << " " << depth_view{ mig }.depth() << "\n";
Maya7991 commented 9 months ago

@aletempiac The input Verliog file is not in MIG format. I have mentioned the task is to convert an input Verilog file into MIG format which is why I am not reading the Verilog file directly into an MIG network as you are suggesting. This issue is with Lorina Verilog reader. While reading a Verilog file, the reader is not able to parse assign Cout = (a & b) | (b & cin) | (a & cin); even though it follows the Verliog syntax.

aletempiac commented 9 months ago

My answer contains the solution. I kindly invite you to read it again thoroughly.

I repeat it here in case you didn't get it. This is your Cout assignment in Verilog: assign Cout = (a & b) | (b & cin) | (a & cin); The correct solution is: assign Cout = (a & b) | (a & cin) | (b & cin); Look carefully at the order of the operands.

Moreover, I restate the possibility of reading directly into MIGs. "I have mentioned the task is to convert an input Verilog file into MIG format which is why I am not reading the Verilog file directly into an MIG network as you are suggesting": this is needed only from BLIF files.

lee30sonia commented 9 months ago

Just to explain a bit more: The Verilog parser in lorina and the associated reader in mockturtle currently do not support all of the possible Verilog syntax, because there are too many possibilities and we, as academic users, usually don't need most of them. For example, hierarchical modules and arithmetic expressions are not supported. To keep the parsed network corresponding well to the input file, we require (in most cases) the file to specify each elementary gate in a separate assignment to avoid differences in grouping and to make parsing simpler. The syntax to represent a majority gate as @aletempiac mentioned is a very special case we hard-coded within our tools to be able to save MIGs as-is (i.e., a file written out by mockturtle matches the syntax lorina+mockturtle can read in again) and being compatible with other common tools (e.g. if read by ABC, a majority gate will be decomposed into 3 ANDs and 2 ORs).

Maya7991 commented 9 months ago

@aletempiac Thank you for the solution and my apologies for overlooking the order of operands as I was expecting the reader to parse any type of statement that follows the Verilog syntax.

@lee30sonia Thank you for the detailed explanation. This addresses all my concerns regarding the Parser.

Let me summarize the points I have understood:

For example( 1 bit full subtractor)

module full_subtractor(a, b, Bin, D, Bout);
  input a, b, Bin;
  output D, Bout;  
      assign D = a ^ b ^ Bin;
      assign Bout = (~a & b) | (~(a ^ b) & Bin);    // will give parse error
endmodule

This has to be rewritten as following:

module full_subtractor(a, b, Bin, D, Bout);
  input a, b, Bin;
  output D, Bout;
      assign D = a ^ b ^ Bin;
      assign temp = a ^ b;
      assign temp1 = ~temp & Bin;
      assign temp2 = ~a & b;
      assign Bout = temp1 | temp2; 
endmodule

I want to express my sincere thanks for the prompt responses from the team. Your clear and concise guidance is really helpful, and is greatly appreciated!