Optimize complex combinational logic in DFG (#6298)
This patch adds DfgLogic, which is a vertex that represents a whole,
arbitrarily complex combinational AstAlways or AstAssignW in the
DfgGraph.
Implementing this requires computing the variables live at entry to the
AstAlways (variables read by the block), so there is a new
ControlFlowGraph data structure and a classical data-flow analysis based
live variable analysis to do that at the variable level (as opposed to
bit/element level).
The actual CFG construction and live variable analysis is best effort,
and might fail for currently unhandled constructs or data types. This
can be extended later.
V3DfgAstToDfg is changed to convert the Ast into an initial DfgGraph
containing only DfgLogic, DfgVertexSplice and DfgVertexVar vertices.
The DfgLogic are then subsequently synthesized into primitive operations
by the new V3DfgSynthesize pass, which is a combination of the old
V3DfgAstToDfg conversion and new code to handle AstAlways blocks with
complex flow control.
V3DfgSynthesize by default will synthesize roughly the same constructs
as V3DfgAstToDfg used to handle before, plus any logic that is part of a
combinational cycle within the DfgGraph. This enables breaking up these
cycles, for which there are extensions to V3DfgBreakCycles in this patch
as well. V3DfgSynthesize will then delete all non synthesized or non
synthesizable DfgLogic vertices and the rest of the Dfg pipeline is
identical, with minor changes to adjust for the changed representation.
Because with this change we can now eliminate many more UNOPTFLAT, DFG
has been disabled in all the tests that specifically target testing the
scheduling and reporting of circular combinational logic.
2025-08-19 16:06:38 +02:00
|
|
|
// DESCRIPTION: Verilator: Verilog Test module
|
|
|
|
|
//
|
|
|
|
|
// This file ONLY is placed under the Creative Commons Public Domain, for
|
|
|
|
|
// any use, without warranty, 2025 by Geza Lore.
|
|
|
|
|
// SPDX-License-Identifier: CC0-1.0
|
|
|
|
|
|
|
|
|
|
`define signal(name, expr) wire [$bits(expr)-1:0] ``name = expr
|
|
|
|
|
|
|
|
|
|
module t (
|
|
|
|
|
`include "portlist.vh" // Boilerplate generated by t_dfg_break_cycles.py
|
|
|
|
|
rand_a, rand_b, srand_a, srand_b
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
`include "portdecl.vh" // Boilerplate generated by t_dfg_break_cycles.py
|
|
|
|
|
|
|
|
|
|
input rand_a;
|
|
|
|
|
input rand_b;
|
|
|
|
|
input srand_a;
|
|
|
|
|
input srand_b;
|
|
|
|
|
wire logic [63:0] rand_a;
|
|
|
|
|
wire logic [63:0] rand_b;
|
|
|
|
|
wire logic signed [63:0] srand_a;
|
|
|
|
|
wire logic signed [63:0] srand_b;
|
|
|
|
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
|
|
logic [2:0] simple;
|
|
|
|
|
always_comb begin
|
|
|
|
|
simple[0] = rand_a[0];
|
|
|
|
|
simple[1] = rand_a[1];
|
|
|
|
|
simple[2] = rand_a[2];
|
|
|
|
|
end
|
|
|
|
|
`signal(SIMPLE, simple);
|
|
|
|
|
|
|
|
|
|
logic [1:0] reassign;
|
|
|
|
|
always_comb begin
|
|
|
|
|
reassign[0] = rand_a[0];
|
|
|
|
|
reassign[0] = ~rand_a[0];
|
|
|
|
|
reassign[1] = rand_a[1];
|
|
|
|
|
reassign[1] = ~rand_a[1];
|
|
|
|
|
end
|
|
|
|
|
`signal(REASSIGN, reassign);
|
|
|
|
|
|
|
|
|
|
logic [1:0] use_intermediate_a;
|
|
|
|
|
logic [1:0] use_intermediate_b;
|
|
|
|
|
always_comb begin
|
|
|
|
|
use_intermediate_a[0] = rand_a[0];
|
|
|
|
|
use_intermediate_b[0] = ~use_intermediate_a[0];
|
|
|
|
|
use_intermediate_a[1] = rand_a[1];
|
|
|
|
|
use_intermediate_a[0] = ~rand_a[0];
|
|
|
|
|
use_intermediate_b[1] = ~use_intermediate_a[1];
|
|
|
|
|
use_intermediate_a[1] = ~rand_a[1];
|
|
|
|
|
end
|
|
|
|
|
`signal(USE_INTERMEDIATE, {use_intermediate_a, use_intermediate_b});
|
|
|
|
|
|
|
|
|
|
logic [2:0] self_circular;
|
|
|
|
|
always_comb begin
|
|
|
|
|
self_circular[0] = rand_a[0];
|
|
|
|
|
self_circular[1] = ~self_circular[0];
|
|
|
|
|
self_circular[2] = ~self_circular[1];
|
|
|
|
|
end
|
|
|
|
|
`signal(SELF_CIRCULAR, self_circular);
|
|
|
|
|
|
|
|
|
|
logic [2:0] part_circular;
|
|
|
|
|
always_comb begin
|
|
|
|
|
part_circular[0] = rand_a[0];
|
|
|
|
|
part_circular[1] = ~part_circular[0];
|
|
|
|
|
end
|
|
|
|
|
// part_circular[2] deliberately undriven!
|
|
|
|
|
`signal(PART_CIRCULAR, part_circular);
|
|
|
|
|
|
|
|
|
|
logic [3:0] split_circular;
|
|
|
|
|
always_comb begin
|
|
|
|
|
split_circular[0] = rand_a[0];
|
|
|
|
|
split_circular[2] = rand_a[1];
|
|
|
|
|
end
|
|
|
|
|
always_comb begin
|
|
|
|
|
split_circular[1] = ~split_circular[0];
|
|
|
|
|
split_circular[3] = ~split_circular[2];
|
|
|
|
|
end
|
|
|
|
|
`signal(SPLIT_CIRCULAR, split_circular);
|
|
|
|
|
|
|
|
|
|
logic [3:0] conditional_a;
|
|
|
|
|
always_comb begin
|
|
|
|
|
conditional_a = 4'd0;
|
|
|
|
|
if (rand_a[0]) begin
|
|
|
|
|
conditional_a = rand_b[3:0];
|
|
|
|
|
end else begin
|
|
|
|
|
conditional_a = ~rand_b[3:0];
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
`signal(CONDITONAL_A, conditional_a);
|
|
|
|
|
|
|
|
|
|
logic [3:0] conditional_b;
|
|
|
|
|
always_comb begin
|
|
|
|
|
conditional_b = 4'd0;
|
|
|
|
|
if (rand_a[0]) begin
|
|
|
|
|
conditional_b = rand_b[3:0];
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
`signal(CONDITONAL_B, conditional_b);
|
|
|
|
|
|
|
|
|
|
// verilator lint_off LATCH
|
|
|
|
|
logic [3:0] conditional_c;
|
|
|
|
|
always_comb begin // nosynth
|
|
|
|
|
if (rand_a[0]) begin
|
|
|
|
|
conditional_c = rand_b[3:0];
|
|
|
|
|
end
|
|
|
|
|
if (~rand_a[0]) begin
|
|
|
|
|
conditional_c = ~rand_b[3:0];
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
`signal(CONDITONAL_C, conditional_c);
|
|
|
|
|
// verilator lint_on LATCH
|
|
|
|
|
|
|
|
|
|
logic [3:0] conditional_d;
|
|
|
|
|
always_comb begin
|
|
|
|
|
if (rand_a[0]) begin
|
|
|
|
|
conditional_d = rand_b[3:0];
|
|
|
|
|
end else if (rand_a[1]) begin
|
|
|
|
|
conditional_d = ~rand_b[3:0];
|
|
|
|
|
end else begin
|
|
|
|
|
conditional_d = rand_b[7:4];
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
`signal(CONDITONAL_D, conditional_d);
|
|
|
|
|
|
|
|
|
|
logic [3:0] conditional_e;
|
|
|
|
|
always_comb begin
|
|
|
|
|
conditional_e = 4'd0;
|
|
|
|
|
if (rand_a[0]) begin
|
|
|
|
|
conditional_e = rand_b[3:0];
|
|
|
|
|
end else begin
|
|
|
|
|
if (rand_a[1]) begin
|
|
|
|
|
conditional_e = rand_b[3:0];
|
|
|
|
|
end else begin
|
|
|
|
|
conditional_e = rand_b[7:4];
|
|
|
|
|
end
|
|
|
|
|
conditional_e = ~conditional_e;
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
`signal(CONDITONAL_E, conditional_e);
|
|
|
|
|
|
|
|
|
|
logic condigional_f;
|
|
|
|
|
always_comb begin
|
|
|
|
|
if (rand_b[0]) begin
|
|
|
|
|
condigional_f = 1'h1;
|
|
|
|
|
if (rand_b[1]) begin
|
|
|
|
|
condigional_f = rand_a[0];
|
|
|
|
|
end
|
|
|
|
|
end else begin
|
|
|
|
|
condigional_f = 1'b0;
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
`signal(CONDITONAL_F, condigional_f);
|
|
|
|
|
|
2025-08-25 14:47:45 +02:00
|
|
|
logic [2:0] conditional_g;
|
|
|
|
|
always_comb begin
|
|
|
|
|
if (rand_a[0]) begin
|
|
|
|
|
if (rand_a[1]) begin
|
|
|
|
|
if (rand_a[2]) begin
|
|
|
|
|
conditional_g = 3'b111;
|
|
|
|
|
end else begin
|
|
|
|
|
conditional_g = 3'b011;
|
|
|
|
|
end
|
|
|
|
|
end else begin
|
|
|
|
|
if (rand_a[2]) begin
|
|
|
|
|
conditional_g = 3'b101;
|
|
|
|
|
end else begin
|
|
|
|
|
conditional_g = 3'b001;
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
end else begin
|
|
|
|
|
if (rand_a[1]) begin
|
|
|
|
|
if (rand_a[2]) begin
|
|
|
|
|
conditional_g = 3'b110;
|
|
|
|
|
end else begin
|
|
|
|
|
conditional_g = 3'b010;
|
|
|
|
|
end
|
|
|
|
|
end else begin
|
|
|
|
|
if (rand_a[2]) begin
|
|
|
|
|
conditional_g = 3'b100;
|
|
|
|
|
end else begin
|
|
|
|
|
conditional_g = 3'b000;
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
`signal(CONDITONAL_G, conditional_g);
|
|
|
|
|
|
|
|
|
|
logic [2:0] conditional_h;
|
|
|
|
|
always_comb begin
|
|
|
|
|
if (rand_a[0]) begin
|
|
|
|
|
if (rand_a[1]) begin
|
|
|
|
|
conditional_h = 3'b011;
|
|
|
|
|
if (rand_a[2]) begin
|
|
|
|
|
conditional_h = 3'b111;
|
|
|
|
|
end
|
|
|
|
|
end else begin
|
|
|
|
|
conditional_h = 3'b001;
|
|
|
|
|
if (rand_a[2]) begin
|
|
|
|
|
conditional_h = 3'b101;
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
end else begin
|
|
|
|
|
if (rand_a[1]) begin
|
|
|
|
|
conditional_h = 3'b010;
|
|
|
|
|
if (rand_a[2]) begin
|
|
|
|
|
conditional_h = 3'b110;
|
|
|
|
|
end
|
|
|
|
|
end else begin
|
|
|
|
|
conditional_h = 3'b000;
|
|
|
|
|
if (rand_a[2]) begin
|
|
|
|
|
conditional_h = 3'b100;
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
`signal(CONDITONAL_H, conditional_h);
|
|
|
|
|
|
|
|
|
|
logic [2:0] conditional_i;
|
|
|
|
|
always_comb begin // Dumbass trailing zeroes count
|
|
|
|
|
do begin
|
|
|
|
|
conditional_i = 3'd0;
|
|
|
|
|
if (rand_a[0]) break;
|
|
|
|
|
conditional_i = 3'd1;
|
|
|
|
|
if (rand_a[1]) break;
|
|
|
|
|
conditional_i = 3'd2;
|
|
|
|
|
if (rand_a[2]) break;
|
|
|
|
|
conditional_i = 3'd3;
|
|
|
|
|
if (rand_a[3]) break;
|
|
|
|
|
conditional_i = 3'd4;
|
|
|
|
|
end while (0);
|
|
|
|
|
end
|
|
|
|
|
`signal(CONDITONAL_I, conditional_i);
|
|
|
|
|
|
|
|
|
|
logic [2:0] conditional_j;
|
|
|
|
|
always_comb begin // Even more dumbass trailing ones count
|
|
|
|
|
do begin
|
|
|
|
|
conditional_j = 3'd0;
|
|
|
|
|
if (rand_a[0]) begin
|
|
|
|
|
conditional_j = 3'd1;
|
|
|
|
|
end else begin
|
|
|
|
|
break;
|
|
|
|
|
end
|
|
|
|
|
if (rand_a[1]) begin
|
|
|
|
|
conditional_j = 3'd2;
|
|
|
|
|
end else begin
|
|
|
|
|
break;
|
|
|
|
|
end
|
|
|
|
|
if (rand_a[2]) begin
|
|
|
|
|
conditional_j = 3'd3;
|
|
|
|
|
end else begin
|
|
|
|
|
break;
|
|
|
|
|
end
|
|
|
|
|
if (rand_a[3]) begin
|
|
|
|
|
conditional_j = 3'd4;
|
|
|
|
|
end
|
|
|
|
|
end while (0);
|
|
|
|
|
end
|
|
|
|
|
`signal(CONDITONAL_J, conditional_j);
|
|
|
|
|
|
|
|
|
|
logic [2:0] conditional_k;
|
|
|
|
|
always_comb begin
|
|
|
|
|
if (rand_b[0]) begin
|
|
|
|
|
do begin
|
|
|
|
|
conditional_k = 3'd0;
|
|
|
|
|
if (rand_a[0]) break;
|
|
|
|
|
conditional_k = 3'd1;
|
|
|
|
|
if (rand_a[1]) break;
|
|
|
|
|
conditional_k = 3'd2;
|
|
|
|
|
if (rand_a[2]) break;
|
|
|
|
|
conditional_k = 3'd3;
|
|
|
|
|
if (rand_a[3]) break;
|
|
|
|
|
conditional_k = 3'd4;
|
|
|
|
|
end while (0);
|
|
|
|
|
end else begin
|
|
|
|
|
do begin
|
|
|
|
|
conditional_k = 3'd0;
|
|
|
|
|
if (rand_a[0]) begin
|
|
|
|
|
conditional_k = 3'd1;
|
|
|
|
|
end else begin
|
|
|
|
|
break;
|
|
|
|
|
end
|
|
|
|
|
if (rand_a[1]) begin
|
|
|
|
|
conditional_k = 3'd2;
|
|
|
|
|
end else begin
|
|
|
|
|
break;
|
|
|
|
|
end
|
|
|
|
|
if (rand_a[2]) begin
|
|
|
|
|
conditional_k = 3'd3;
|
|
|
|
|
end else begin
|
|
|
|
|
break;
|
|
|
|
|
end
|
|
|
|
|
if (rand_a[3]) begin
|
|
|
|
|
conditional_k = 3'd4;
|
|
|
|
|
end
|
|
|
|
|
end while (0);
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
`signal(CONDITONAL_K, conditional_k);
|
|
|
|
|
|
|
|
|
|
logic [1:0] conditional_l_a;
|
|
|
|
|
logic [1:0] conditional_l_b;
|
|
|
|
|
always_comb begin
|
|
|
|
|
do begin
|
|
|
|
|
conditional_l_a = 2'd0;
|
|
|
|
|
if (rand_a[1:0] == 2'd0) break;
|
|
|
|
|
conditional_l_a = 2'd1;
|
|
|
|
|
if (rand_a[1:0] == 2'd1) break;
|
|
|
|
|
conditional_l_a = 2'd2;
|
|
|
|
|
if (rand_a[1:0] == 2'd2) break;
|
|
|
|
|
conditional_l_a = 2'd3;
|
|
|
|
|
end while (0);
|
|
|
|
|
do begin
|
|
|
|
|
conditional_l_b = 2'd0;
|
|
|
|
|
if (rand_b[1:0] == 2'd0) break;
|
|
|
|
|
conditional_l_b = 2'd1;
|
|
|
|
|
if (rand_b[1:0] == 2'd1) break;
|
|
|
|
|
conditional_l_b = 2'd2;
|
|
|
|
|
if (rand_b[1:0] == 2'd2) break;
|
|
|
|
|
conditional_l_b = 2'd3;
|
|
|
|
|
end while (0);
|
|
|
|
|
end
|
|
|
|
|
`signal(CONDITONAL_L, {conditional_l_b, conditional_l_a});
|
|
|
|
|
|
Optimize complex combinational logic in DFG (#6298)
This patch adds DfgLogic, which is a vertex that represents a whole,
arbitrarily complex combinational AstAlways or AstAssignW in the
DfgGraph.
Implementing this requires computing the variables live at entry to the
AstAlways (variables read by the block), so there is a new
ControlFlowGraph data structure and a classical data-flow analysis based
live variable analysis to do that at the variable level (as opposed to
bit/element level).
The actual CFG construction and live variable analysis is best effort,
and might fail for currently unhandled constructs or data types. This
can be extended later.
V3DfgAstToDfg is changed to convert the Ast into an initial DfgGraph
containing only DfgLogic, DfgVertexSplice and DfgVertexVar vertices.
The DfgLogic are then subsequently synthesized into primitive operations
by the new V3DfgSynthesize pass, which is a combination of the old
V3DfgAstToDfg conversion and new code to handle AstAlways blocks with
complex flow control.
V3DfgSynthesize by default will synthesize roughly the same constructs
as V3DfgAstToDfg used to handle before, plus any logic that is part of a
combinational cycle within the DfgGraph. This enables breaking up these
cycles, for which there are extensions to V3DfgBreakCycles in this patch
as well. V3DfgSynthesize will then delete all non synthesized or non
synthesizable DfgLogic vertices and the rest of the Dfg pipeline is
identical, with minor changes to adjust for the changed representation.
Because with this change we can now eliminate many more UNOPTFLAT, DFG
has been disabled in all the tests that specifically target testing the
scheduling and reporting of circular combinational logic.
2025-08-19 16:06:38 +02:00
|
|
|
logic [7:0] partial_conditional_a;
|
|
|
|
|
always_comb begin
|
|
|
|
|
partial_conditional_a[1:0] = 2'd0;
|
|
|
|
|
if (rand_a[0]) begin
|
|
|
|
|
partial_conditional_a[0] = rand_b[0];
|
|
|
|
|
end else begin
|
|
|
|
|
partial_conditional_a[1] = rand_b[1];
|
|
|
|
|
end
|
|
|
|
|
partial_conditional_a[4:3] = rand_b[4:3];
|
|
|
|
|
end
|
|
|
|
|
`signal(PARTIAL_CONDITONAL_A, partial_conditional_a);
|
|
|
|
|
|
|
|
|
|
logic [3:0] partial_conditional_b;
|
|
|
|
|
always_comb begin
|
|
|
|
|
partial_conditional_b[1:0] = 2'd0;
|
|
|
|
|
if (rand_a[0]) begin
|
|
|
|
|
partial_conditional_b[0] = rand_b[0];
|
|
|
|
|
end
|
|
|
|
|
if (rand_a[1]) begin
|
|
|
|
|
partial_conditional_b[1] = rand_b[1];
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
`signal(PARTIAL_CONDITONAL_B, partial_conditional_b);
|
|
|
|
|
|
|
|
|
|
logic [3:0] becomes_full;
|
|
|
|
|
always_comb begin
|
|
|
|
|
becomes_full[2:0] = rand_a[2:0];
|
|
|
|
|
becomes_full[3] = ~rand_a[3];
|
|
|
|
|
if (rand_b[0]) begin
|
|
|
|
|
becomes_full = ~becomes_full;
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
`signal(BECOMES_FULL, becomes_full);
|
|
|
|
|
|
|
|
|
|
// verilator lint_off LATCH
|
|
|
|
|
logic [3:0] latch_a;
|
|
|
|
|
logic [3:0] latch_b;
|
|
|
|
|
always_comb begin // nosynth
|
|
|
|
|
if (rand_b[0]) begin
|
|
|
|
|
latch_a[3:1] = ~rand_a[3:1];
|
|
|
|
|
end
|
|
|
|
|
latch_b = latch_a;
|
|
|
|
|
end
|
|
|
|
|
assign latch_a[0] = rand_a[0];
|
|
|
|
|
`signal(LATCH, latch_b);
|
|
|
|
|
// verilator lint_on LATCH
|
|
|
|
|
|
|
|
|
|
// verilator lint_off MULTIDRIVEN
|
|
|
|
|
logic static_temporary_a;
|
|
|
|
|
logic static_temporary_b;
|
|
|
|
|
logic static_temporary_tmp;
|
|
|
|
|
always_comb begin // revert
|
|
|
|
|
static_temporary_tmp = rand_a[0];
|
|
|
|
|
static_temporary_a = ~static_temporary_tmp;
|
|
|
|
|
end
|
|
|
|
|
always_comb begin // revert
|
|
|
|
|
static_temporary_tmp = static_temporary_a;
|
|
|
|
|
static_temporary_b = ~static_temporary_tmp;
|
|
|
|
|
end
|
|
|
|
|
// verilator lint_on MULTIDRIVEN
|
|
|
|
|
`signal(STATIC_TEMPORARY, {static_temporary_tmp, static_temporary_b, static_temporary_a, rand_a[0]});
|
|
|
|
|
|
|
|
|
|
logic [2:0] partial_temporary_a;
|
|
|
|
|
logic [2:0] partial_temporary_tmp;
|
|
|
|
|
always_comb begin
|
|
|
|
|
partial_temporary_tmp[2] = rand_a[3];
|
|
|
|
|
partial_temporary_tmp[1] = rand_a[2];
|
|
|
|
|
partial_temporary_tmp[0] = rand_a[1];
|
|
|
|
|
partial_temporary_a = partial_temporary_tmp;
|
|
|
|
|
end
|
|
|
|
|
`signal(PARTIAL_TEMPORARY, partial_temporary_a);
|
2025-08-25 14:47:45 +02:00
|
|
|
|
|
|
|
|
logic circular_0_x;
|
|
|
|
|
logic circular_0_y;
|
|
|
|
|
logic circular_0_z;
|
|
|
|
|
always_comb begin
|
|
|
|
|
circular_0_x = 1'b0;
|
|
|
|
|
circular_0_y = 1'd0;
|
|
|
|
|
if (rand_b[0]) begin
|
|
|
|
|
circular_0_x = 1'b1;
|
|
|
|
|
if (circular_0_z) begin
|
|
|
|
|
circular_0_y = 1'd1;
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
assign circular_0_z = circular_0_x & rand_a[0];
|
|
|
|
|
`signal(CIRCULAR_0, {circular_0_x, circular_0_y, circular_0_z});
|
|
|
|
|
|
|
|
|
|
logic [2:0] nsp_a; // Non series-parallel CFG
|
|
|
|
|
always_comb begin
|
|
|
|
|
do begin
|
|
|
|
|
nsp_a = 3'd0; // BB 0 -> BB 1 / BB 2
|
|
|
|
|
if (rand_a[1:0] == 2'd0) begin
|
|
|
|
|
nsp_a = 3'd1; // BB 1 -> BB 4
|
|
|
|
|
end else begin
|
|
|
|
|
nsp_a = 3'd2; // BB 2 -> BB 3 / BB 4
|
|
|
|
|
if (rand_a[1:0] == 2'd1) begin
|
|
|
|
|
nsp_a = 3'd3; // BB3 -> BB 5
|
|
|
|
|
break;
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
nsp_a = 3'd4; // BB 4 -> BB 5
|
|
|
|
|
end while (0);
|
|
|
|
|
//nsp_a = 3'd5; // BB 5
|
|
|
|
|
end
|
|
|
|
|
`signal(NSP_A, nsp_a);
|
|
|
|
|
|
|
|
|
|
logic [2:0] nsp_b; // Non series-parallel CFG
|
|
|
|
|
always_comb begin
|
|
|
|
|
do begin
|
|
|
|
|
nsp_b = 3'd0;
|
|
|
|
|
if (rand_a[1:0] == 2'd0) begin
|
|
|
|
|
nsp_b = 3'd1;
|
|
|
|
|
end else begin
|
|
|
|
|
nsp_b = 3'd2;
|
|
|
|
|
if (rand_a[1:0] == 2'd1) begin
|
|
|
|
|
nsp_b = 3'd3;
|
|
|
|
|
break;
|
|
|
|
|
end else begin
|
|
|
|
|
nsp_b = 3'd4;
|
|
|
|
|
if (rand_a[1:0] == 2'd2) begin
|
|
|
|
|
nsp_b = 3'd5;
|
|
|
|
|
end else begin
|
|
|
|
|
nsp_b = 3'd6;
|
|
|
|
|
break;
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
nsp_b = 3'd7;
|
|
|
|
|
end while (0);
|
|
|
|
|
end
|
|
|
|
|
`signal(NSP_B, nsp_b);
|
|
|
|
|
|
|
|
|
|
logic [2:0] part_sp_a; // Contains series-parallel sub-graph CFG
|
|
|
|
|
always_comb begin
|
|
|
|
|
do begin
|
|
|
|
|
part_sp_a = 3'd0;
|
|
|
|
|
if (rand_a[0]) begin
|
|
|
|
|
part_sp_a = 3'd1;
|
|
|
|
|
if (rand_a[1]) begin
|
|
|
|
|
part_sp_a = 3'd2;
|
|
|
|
|
end
|
|
|
|
|
end else begin
|
|
|
|
|
part_sp_a = 3'd3;
|
|
|
|
|
if (rand_a[2]) begin
|
|
|
|
|
part_sp_a = 3'd4;
|
|
|
|
|
if (rand_a[3]) begin
|
|
|
|
|
part_sp_a = 3'd5;
|
|
|
|
|
end
|
|
|
|
|
break;
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
part_sp_a = 3'd6;
|
|
|
|
|
if (rand_a[4]) begin
|
|
|
|
|
part_sp_a = 3'd7;
|
|
|
|
|
end
|
|
|
|
|
end while (0);
|
|
|
|
|
end
|
|
|
|
|
`signal(PART_SP_A, part_sp_a);
|
|
|
|
|
|
|
|
|
|
logic [1:0] both_break;
|
|
|
|
|
always_comb begin
|
|
|
|
|
do begin
|
|
|
|
|
if (rand_a[0]) begin
|
|
|
|
|
both_break = 2'd0;
|
|
|
|
|
break;
|
|
|
|
|
end else begin
|
|
|
|
|
both_break = 2'd1;
|
|
|
|
|
break;
|
|
|
|
|
end
|
|
|
|
|
// Unreachable
|
|
|
|
|
if (rand_a[1]) begin
|
|
|
|
|
both_break = 2'd2;
|
|
|
|
|
end
|
|
|
|
|
end while(0);
|
|
|
|
|
end
|
|
|
|
|
`signal(BOTH_BREAK, both_break);
|
|
|
|
|
|
Optimize complex combinational logic in DFG (#6298)
This patch adds DfgLogic, which is a vertex that represents a whole,
arbitrarily complex combinational AstAlways or AstAssignW in the
DfgGraph.
Implementing this requires computing the variables live at entry to the
AstAlways (variables read by the block), so there is a new
ControlFlowGraph data structure and a classical data-flow analysis based
live variable analysis to do that at the variable level (as opposed to
bit/element level).
The actual CFG construction and live variable analysis is best effort,
and might fail for currently unhandled constructs or data types. This
can be extended later.
V3DfgAstToDfg is changed to convert the Ast into an initial DfgGraph
containing only DfgLogic, DfgVertexSplice and DfgVertexVar vertices.
The DfgLogic are then subsequently synthesized into primitive operations
by the new V3DfgSynthesize pass, which is a combination of the old
V3DfgAstToDfg conversion and new code to handle AstAlways blocks with
complex flow control.
V3DfgSynthesize by default will synthesize roughly the same constructs
as V3DfgAstToDfg used to handle before, plus any logic that is part of a
combinational cycle within the DfgGraph. This enables breaking up these
cycles, for which there are extensions to V3DfgBreakCycles in this patch
as well. V3DfgSynthesize will then delete all non synthesized or non
synthesizable DfgLogic vertices and the rest of the Dfg pipeline is
identical, with minor changes to adjust for the changed representation.
Because with this change we can now eliminate many more UNOPTFLAT, DFG
has been disabled in all the tests that specifically target testing the
scheduling and reporting of circular combinational logic.
2025-08-19 16:06:38 +02:00
|
|
|
endmodule
|