abstract: -value MVP, use buffer-normalized mode

This commit is contained in:
Emil J. Tywoniak 2025-02-07 10:46:50 +01:00
parent 497a6e0c59
commit eb8982a937
2 changed files with 121 additions and 62 deletions

View File

@ -57,70 +57,70 @@ bool abstract_state(Module* mod, Cell* cell, Wire* enable, bool enable_pol) {
return true;
}
bool abstract_value(Module* mod, Wire* wire, Wire* enable, bool enable_pol) {
// (void)mod->addMux(NEW_ID,
// mux_a,
// mux_b,
// enable,
// abstracted);
// cell->setPort(ID::D, SigSpec(abstracted));
return false;
}
struct AbstractInitCtx {
struct AbstractPortCtx {
Module* mod;
SigMap sigmap;
pool<SigBit> init_bits;
pool<std::pair<Cell*, IdString>> outs;
};
void collect_init_bits_cells(AbstractInitCtx& ctx) {
// TODO Should this discriminate between FFs and other cells?
for (auto cell : ctx.mod->selected_cells()) {
// Add all sigbits on all cell outputs to init_bits
for (auto &conn : cell->connections()) {
if (cell->output(conn.first)) {
for (auto bit : conn.second) {
log_debug("init: cell %s output %s\n", cell->name.c_str(), log_signal(bit));
ctx.init_bits.insert(ctx.sigmap(bit));
}
}
void collect_selected_ports(AbstractPortCtx& ctx) {
for (Cell* cell : ctx.mod->cells()) {
for (auto& conn : cell->connections()) {
// we bufnorm
log_assert(conn.second.is_wire() || conn.second.is_fully_const());
if (conn.second.is_wire() && cell->output(conn.first))
if (ctx.mod->selected(cell) || ctx.mod->selected(conn.second.as_wire()))
ctx.outs.insert(std::make_pair(cell, conn.first));
}
}
}
void collect_init_bits_wires(AbstractInitCtx& ctx) {
for (auto wire : ctx.mod->selected_wires()) {
auto canonical = ctx.sigmap(wire);
// Find canonical drivers of all the wire bits and add them to init_bits
for (auto bit : canonical.bits()) {
log_debug("init: wire %s bit %s\n", wire->name.c_str(), log_signal(bit));
ctx.init_bits.insert(ctx.sigmap(bit));
unsigned int abstract_value(Module* mod, Wire* enable, bool enable_pol) {
AbstractPortCtx ctx {mod, SigMap(mod), {}};
collect_selected_ports(ctx);
unsigned int changed = 0;
for (auto [cell, port] : ctx.outs) {
SigSpec sig = cell->getPort(port);
log_assert(sig.is_wire());
Wire* original = mod->addWire(NEW_ID, sig.size());
cell->setPort(port, original);
auto anyseq = mod->Anyseq(NEW_ID, sig.size());
// This code differs from abstract_state
// in that we reuse the original signal as the mux output,
// not input
SigSpec mux_a, mux_b;
if (enable_pol) {
mux_a = original;
mux_b = anyseq;
} else {
mux_a = anyseq;
mux_b = original;
}
(void)mod->addMux(NEW_ID,
mux_a,
mux_b,
enable,
sig);
changed++;
}
return changed;
}
unsigned int abstract_init(Module* mod) {
AbstractInitCtx ctx {mod, SigMap(mod), pool<SigBit>()};
pool<SigBit> init_bits;
collect_init_bits_cells(ctx);
collect_init_bits_wires(ctx);
AbstractPortCtx ctx {mod, SigMap(mod), {}};
collect_selected_ports(ctx);
unsigned int changed = 0;
for (SigBit bit : ctx.init_bits) {
next_sigbit:
if (!bit.is_wire() || !bit.wire->has_attribute(ID::init))
for (auto [cell, port] : ctx.outs) {
SigSpec sig = cell->getPort(port);
log_assert(sig.is_wire());
if (!sig.as_wire()->has_attribute(ID::init))
continue;
Const init = bit.wire->attributes.at(ID::init);
std::vector<RTLIL::State>& bits = init.bits();
bits[bit.offset] = RTLIL::State::Sx;
changed++;
for (auto bit : bits)
if (bit != RTLIL::State::Sx)
goto next_sigbit;
// All bits are Sx, erase init attribute entirely
bit.wire->attributes.erase(ID::init);
Const init = sig.as_wire()->attributes.at(ID::init);
sig.as_wire()->attributes.erase(ID::init);
changed += sig.size();
}
return changed;
}
@ -174,6 +174,7 @@ struct AbstractPass : public Pass {
}
extra_args(args, argidx, design);
design->bufNormalize(true);
unsigned int changed = 0;
if ((mode == State) || (mode == Value)) {
if (!enable_name.length())
@ -191,14 +192,13 @@ struct AbstractPass : public Pass {
if (ct.cell_types.count(cell->type))
changed += abstract_state(mod, cell, enable_wire, enable_pol);
} else {
// Value
for (auto wire : mod->selected_wires()) {
changed += abstract_value(mod, wire, enable_wire, enable_pol);
}
log_cmd_error("Unsupported (TODO)\n");
changed += abstract_value(mod, enable_wire, enable_pol);
}
}
log("Abstracted %d cells.\n", changed);
if (mode == State)
log("Abstracted %d cells.\n", changed);
else
log("Abstracted %d values.\n", changed);
} else if (mode == Initial) {
for (auto mod : design->selected_modules()) {
changed += abstract_init(mod);
@ -207,6 +207,7 @@ struct AbstractPass : public Pass {
} else {
log_cmd_error("No mode selected, see help message\n");
}
design->bufNormalize(false);
}
} AbstractPass;

View File

@ -1,9 +1,9 @@
read_verilog <<EOT
module half_clock (CLK, Q);
module half_clock (CLK, Q, magic);
input CLK;
output reg Q;
reg magic;
input magic;
always @(posedge CLK)
Q <= ~Q;
endmodule
@ -12,16 +12,16 @@ EOT
proc
# show -prefix before_base
abstract -state -enablen magic
check
check -assert
# show -prefix after_base
design -reset
read_verilog <<EOT
module half_clock_en (CLK, E, Q);
module half_clock_en (CLK, E, Q, magic);
input CLK;
input E;
output reg Q;
reg magic;
input magic;
always @(posedge CLK)
if (E)
Q <= ~Q;
@ -33,7 +33,7 @@ opt_expr
opt_dff
# show -prefix before_en
abstract -state -enablen magic
check
check -assert
# show -prefix after_en
design -reset
@ -50,9 +50,35 @@ proc
opt_expr
opt_dff
dump
select -none
abstract -init
check
select -clear
check -assert
# dump
design -reset
read_verilog <<EOT
module main (input [3:0] baz);
reg foo;
reg bar;
assign foo = bar;
assign bar = baz[0];
reg aaa = 1'b1;
always @(posedge bar)
aaa <= ~aaa;
endmodule
EOT
proc -noopt
# show -prefix before_init
dump
select -none
abstract -init
select -clear
# show -prefix after_init
dump
check -assert
# dump
design -reset
@ -85,6 +111,38 @@ opt_expr
opt_dff
# show -prefix before_a
abstract -state -enablen magic
check
check -assert
# show -prefix after_a
# opt_clean
# opt_clean
design -reset
read_verilog <<EOT
module this_adff (CLK, ARST, D, Q, magic);
parameter WIDTH = 2;
parameter CLK_POLARITY = 1'b1;
parameter ARST_POLARITY = 1'b1;
parameter ARST_VALUE = 0;
input CLK, ARST, magic;
input [WIDTH-1:0] D;
output reg [WIDTH-1:0] Q;
wire pos_clk = CLK == CLK_POLARITY;
wire pos_arst = ARST == ARST_POLARITY;
always @(posedge pos_clk, posedge pos_arst) begin
if (pos_arst)
Q <= ARST_VALUE;
else
Q <= D;
end
endmodule
EOT
proc
# show -prefix before_value
abstract -value -enablen magic
check -assert
clean
# show -prefix after_value
# dump