Techmap by example

As a quick recap, the techmap command replaces cells in the design with implementations given as Verilog code (called “map files”). It can replace Yosys’ internal cell types (such as $or) as well as user-defined cell types.

  • Verilog parameters are used extensively to customize the internal cell types.

  • Additional special parameters are used by techmap to communicate meta-data to the map files.

  • Special wires are used to instruct techmap how to handle a module in the map file.

  • Generate blocks and recursion are powerful tools for writing map files.

Code examples used in this document are included in the Yosys code base under docs/source/code_examples/techmap.

Mapping OR3X1

Note

This is a simple example for demonstration only. Techmap shouldn’t be used to implement basic logic optimization.

Listing 98 red_or3x1_map.v
module \$reduce_or (A, Y);

    parameter A_SIGNED = 0;
    parameter A_WIDTH = 0;
    parameter Y_WIDTH = 0;

    input [A_WIDTH-1:0] A;
    output [Y_WIDTH-1:0] Y;

    function integer min;
        input integer a, b;
        begin
            if (a < b)
                min = a;
            else
                min = b;
        end
    endfunction

    genvar i;
    generate begin
        if (A_WIDTH == 0) begin
            assign Y = 0;
        end
        if (A_WIDTH == 1) begin
            assign Y = A;
        end
        if (A_WIDTH == 2) begin
            wire ybuf;
            OR3X1 g (.A(A[0]), .B(A[1]), .C(1'b0), .Y(ybuf));
            assign Y = ybuf;
        end
        if (A_WIDTH == 3) begin
            wire ybuf;
            OR3X1 g (.A(A[0]), .B(A[1]), .C(A[2]), .Y(ybuf));
            assign Y = ybuf;
        end
        if (A_WIDTH > 3) begin
            localparam next_stage_sz = (A_WIDTH+2) / 3;
            wire [next_stage_sz-1:0] next_stage;
            for (i = 0; i < next_stage_sz; i = i+1) begin
                localparam bits = min(A_WIDTH - 3*i, 3);
                assign next_stage[i] = |A[3*i +: bits];
            end
            assign Y = |next_stage;
        end
    end endgenerate
endmodule
../_images/red_or3x1.svg
Listing 99 red_or3x1_test.ys
read_verilog red_or3x1_test.v
hierarchy -check -top test

techmap -map red_or3x1_map.v;;

splitnets -ports
show -prefix red_or3x1 -format dot -notitle -lib red_or3x1_cells.v
Listing 100 red_or3x1_test.v
module test (A, Y);
    input [6:0] A;
    output Y;
    assign Y = |A;
endmodule

Conditional techmap

  • In some cases only cells with certain properties should be substituted.

  • The special wire _TECHMAP_FAIL_ can be used to disable a module in the map file for a certain set of parameters.

  • The wire _TECHMAP_FAIL_ must be set to a constant value. If it is non-zero then the module is disabled for this set of parameters.

  • Example use-cases:

    • coarse-grain cell types that only operate on certain bit widths

    • memory resources for different memory geometries (width, depth, ports, etc.)

Example:

../_images/sym_mul.svg
Listing 101 sym_mul_map.v
module \$mul (A, B, Y);
    parameter A_SIGNED = 0;
    parameter B_SIGNED = 0;
    parameter A_WIDTH = 1;
    parameter B_WIDTH = 1;
    parameter Y_WIDTH = 1;

    input [A_WIDTH-1:0] A;
    input [B_WIDTH-1:0] B;
    output [Y_WIDTH-1:0] Y;

    wire _TECHMAP_FAIL_ = A_WIDTH != B_WIDTH || B_WIDTH != Y_WIDTH;

    MYMUL #( .WIDTH(Y_WIDTH) ) g ( .A(A), .B(B), .Y(Y) );
endmodule
Listing 102 sym_mul_test.v
module test(A, B, C, Y1, Y2);
    input   [7:0] A, B, C;
    output  [7:0] Y1 = A * B;
    output [15:0] Y2 = A * C;
endmodule
Listing 103 sym_mul_test.ys
read_verilog sym_mul_test.v
hierarchy -check -top test

techmap -map sym_mul_map.v;;

show -prefix sym_mul -format dot -notitle -lib sym_mul_cells.v

Scripting in map modules

  • The special wires _TECHMAP_DO_* can be used to run Yosys scripts in the context of the replacement module.

  • The wire that comes first in alphabetical oder is interpreted as string (must be connected to constants) that is executed as script. Then the wire is removed. Repeat.

  • You can even call techmap recursively!

  • Example use-cases:

    • Using always blocks in map module: call proc

    • Perform expensive optimizations (such as freduce) on cells where this is known to work well.

    • Interacting with custom commands.

Note

PROTIP:

Commands such as shell, show -pause, and dump can be used in the _TECHMAP_DO_* scripts for debugging map modules.

Example:

../_images/mymul.svg
Listing 104 mymul_map.v
module MYMUL(A, B, Y);
    parameter WIDTH = 1;
    input [WIDTH-1:0] A, B;
    output reg [WIDTH-1:0] Y;

    wire [1023:0] _TECHMAP_DO_ = "proc; clean";

    integer i;
    always @* begin
        Y = 0;
        for (i = 0; i < WIDTH; i=i+1)
            if (A[i])
                Y = Y + (B << i);
    end
endmodule
Listing 105 mymul_test.v
module test(A, B, Y);
    input  [1:0] A, B;
    output [1:0] Y = A * B;
endmodule
Listing 106 mymul_test.ys
read_verilog mymul_test.v
hierarchy -check -top test

techmap -map sym_mul_map.v \
        -map mymul_map.v;;

rename test test_mapped
read_verilog mymul_test.v
miter -equiv test test_mapped miter
flatten miter

sat -verify -prove trigger 0 miter

splitnets -ports test_mapped/A
show -prefix mymul -format dot -notitle test_mapped

Handling constant inputs

  • The special parameters _TECHMAP_CONSTMSK_<port-name>_ and _TECHMAP_CONSTVAL_<port-name>_ can be used to handle constant input values to cells.

  • The former contains 1-bits for all constant input bits on the port.

  • The latter contains the constant bits or undef (x) for non-constant bits.

  • Example use-cases:

    • Converting arithmetic (for example multiply to shift).

    • Identify constant addresses or enable bits in memory interfaces.

Example:

../_images/mulshift.svg
Listing 107 mulshift_map.v
module MYMUL(A, B, Y);
    parameter WIDTH = 1;
    input [WIDTH-1:0] A, B;
    output reg [WIDTH-1:0] Y;

    parameter _TECHMAP_CONSTVAL_A_ = WIDTH'bx;
    parameter _TECHMAP_CONSTVAL_B_ = WIDTH'bx;

    reg _TECHMAP_FAIL_;
    wire [1023:0] _TECHMAP_DO_ = "proc; clean";

    integer i;
    always @* begin
    	_TECHMAP_FAIL_ <= 1;
        for (i = 0; i < WIDTH; i=i+1) begin
            if (_TECHMAP_CONSTVAL_A_ === WIDTH'd1 << i) begin
	        _TECHMAP_FAIL_ <= 0;
                Y <= B << i;
	    end
            if (_TECHMAP_CONSTVAL_B_ === WIDTH'd1 << i) begin
	        _TECHMAP_FAIL_ <= 0;
                Y <= A << i;
	    end
	end
    end
endmodule
Listing 108 mulshift_test.v
module test (A, X, Y);
input [7:0] A;
output [7:0] X = A * 8'd 6;
output [7:0] Y = A * 8'd 8;
endmodule
Listing 109 mulshift_test.ys
read_verilog mulshift_test.v
hierarchy -check -top test

techmap -map sym_mul_map.v \
        -map mulshift_map.v;;

show -prefix mulshift -format dot -notitle -lib sym_mul_cells.v

Handling shorted inputs

  • The special parameters _TECHMAP_BITS_CONNMAP_ and _TECHMAP_CONNMAP_<port-name>_ can be used to handle shorted inputs.

  • Each bit of the port correlates to an _TECHMAP_BITS_CONNMAP_ bits wide number in _TECHMAP_CONNMAP_<port-name>_.

  • Each unique signal bit is assigned its own number. Identical fields in the _TECHMAP_CONNMAP_<port-name>_ parameters mean shorted signal bits.

  • The numbers 0-3 are reserved for 0, 1, x, and z respectively.

  • Example use-cases:

    • Detecting shared clock or control signals in memory interfaces.

    • In some cases this can be used for for optimization.

Example:

../_images/addshift.svg
Listing 110 addshift_map.v
module \$add (A, B, Y);
  parameter A_SIGNED = 0;
  parameter B_SIGNED = 0;
  parameter A_WIDTH = 1;
  parameter B_WIDTH = 1;
  parameter Y_WIDTH = 1;

  input [A_WIDTH-1:0] A;
  input [B_WIDTH-1:0] B;
  output [Y_WIDTH-1:0] Y;

  parameter _TECHMAP_BITS_CONNMAP_ = 0;
  parameter _TECHMAP_CONNMAP_A_ = 0;
  parameter _TECHMAP_CONNMAP_B_ = 0;

  wire _TECHMAP_FAIL_ = A_WIDTH != B_WIDTH || B_WIDTH < Y_WIDTH ||
                        _TECHMAP_CONNMAP_A_ != _TECHMAP_CONNMAP_B_;

  assign Y = A << 1;
endmodule
Listing 111 addshift_test.v
module test (A, B, X, Y);
input [7:0] A, B;
output [7:0] X = A + B;
output [7:0] Y = A + A;
endmodule
Listing 112 addshift_test.ys
read_verilog addshift_test.v
hierarchy -check -top test

techmap -map addshift_map.v;;

show -prefix addshift -format dot -notitle

Notes on using techmap

  • Don’t use positional cell parameters in map modules.

  • You can use the $__-prefix for internal cell types to avoid collisions with the user-namespace. But always use two underscores or the internal consistency checker will trigger on these cells.

  • Techmap has two major use cases:

    • Creating good logic-level representation of arithmetic functions. This also means using dedicated hardware resources such as half- and full-adder cells in ASICS or dedicated carry logic in FPGAs.

    • Mapping of coarse-grain resources such as block memory or DSP cells.