lsils/mockturtle

Getting parse errors when reading Verilog files using Lorina Verilog reader

Closed this issue · 5 comments

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;
}
  1. 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
  1. 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

  • OS: Linux
  • Compiler: GCC 11.4.0
  • Compilation mode: RELEASE

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

  • I have tried to run in DEBUG mode and there was no assertion failure (or the reported bug is an assertion failure).
  • I have made sure that the provided code compiles and the testcase reproduces the error.
  • I have minimized the testcase.

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";

@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.

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.

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).

@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:

  • The input Verilog file should be RTL level description.
  • Hierarchical modules and arithmetic expressions are not supported.
  • Syntax of MAJ3 is: ( OP1 & OP2 ) | ( OP1 & OP3 ) | ( OP2 & OP3 )
  • Specify each elementary gate in a separate assignment statement

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!