Search code examples
yosys

Combinatorial synthesis: Better technology mapping results


Using the following script, I am synthesising to a standard cell library for which I have a lib file, my_library.lib:

read_liberty -lib  my_library.lib
script yosys_readfiles.ys
proc; opt; memory; opt; fsm -norecode; opt
techmap; opt
dfflibmap -liberty my_library.lib
abc -liberty my_library.lib
hilomap -hicell LIB_TIEHI Y -locell LIB_TIELO Y
clean
write_verilog -noattr -noexpr output.v
stat

While this generally works, I found that some of the logic isn't mapped efficiently. For example, I have the following Verilog model of a 4-way multiplexer:

module mux4(
     input  i0,
     input  i1,
     input  i2,
     input  i3,
     input  s0,
     input  s1,
     output z
   );
   reg    zint;
   parameter tdelay = `default_gate_delay;
   always @(i0 or i1 or i2 or i3 or s0 or s1) begin
      case ({s1, s0})
        2'b00:       zint <= i0;
        2'b01:       zint <= i1;    
        2'b10:       zint <= i2;    
        2'b11:       zint <= i3;    
        default:     zint <= i3;
      endcase
   end
   assign z = zint;
endmodule

Yosys synthesised this to the following gate-level netlist:

/* Generated by Yosys 0.5+ (git sha1 f13e387, gcc 5.3.1-8ubuntu2 -O2 -fstack-protector-strong -fPIC -Os) */

module mux4(i0, i1, i2, i3, s0, s1, z);
  wire _00_;
  wire _01_;
  wire _02_;
  wire _03_;
  wire _04_;
  wire _05_;
  input i0;
  input i1;
  input i2;
  input i3;
  input s0;
  input s1;
  output z;
  wire zint;
  NAND3 _06_ (
    .A(s1),
    .B(s0),
    .C(i3),
    .Y(_04_)
  );
  INV _07_ (
    .A(s1),
    .Y(_05_)
  );
  NAND3 _08_ (
    .A(_05_),
    .B(s0),
    .C(i1),
    .Y(_00_)
  );
  INV _09_ (
    .A(s0),
    .Y(_01_)
  );
  NAND3 _10_ (
    .A(_05_),
    .B(_01_),
    .C(i0),
    .Y(_02_)
  );
  NAND3B _11_ (
    .AN(s0),
    .B(s1),
    .C(i2),
    .Y(_03_)
  );
  NAND4 _12_ (
    .A(_02_),
    .B(_00_),
    .C(_03_),
    .D(_04_),
    .Y(z)
  );
  assign zint = z;
endmodule

Since the library I am using already has a MXI4 cell, I would have expected something similar to the following instead:

module mux4(i0, i1, i2, i3, s0, s1, z);
  input i0;
  input i1;
  input i2;
  input i3;
  input s0;
  input s1;
  output z;
  MXI4 _12_ (
    .A(i0),
    .B(i1),
    .C(i2),
    .D(i3),
    .S0(s0),
    .S1(s1),
    .Y(z)
  );
endmodule

I am wondering how I can direct Yosys to use the MXI4 cell instead of the cascaded NAND instances above as this would result in a significant reduction in area. While for this specific cell, I could use the same technique as described in this answer to manually map to the MXI4 cell, but I am concerned that there may be other (more complex) areas of my design where such a manual mapping is either not as obvious and/or infeasible.

One thing I tried was to add the following option to the abc command in my synthesis script, which I found on Reddit:

-script +strash;scorr;ifraig;retime,{D};strash;dch,-f;map,-M,1,{D}

But it didn't solve the problem either. (Also I couldn't find any documentation on some of these ABC commands, any help there would be appreciated as well.)


Solution

  • The following ABC script should be able to map the MUX4, or it least it is when using the ABC version that is bundled with Yosys 0.7:

    abc -liberty my_library.lib -script \
        +strash;ifraig;scorr;dc2;dretime;strash;&get,-n;&dch,-f;&nf,{D};&put
    

    Starting with git commit 8927e19 this is the new default script for abc -liberty.