3
0
Fork 0
mirror of https://github.com/YosysHQ/yosys synced 2026-02-14 04:41:48 +00:00
This commit is contained in:
Emil J 2026-02-12 17:12:04 +01:00 committed by GitHub
commit 2766f9331e
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
8 changed files with 246 additions and 14 deletions

View file

@ -210,7 +210,9 @@ static void create_ff(RTLIL::Module *module, const LibertyAst *node)
auto [iq_sig, iqn_sig] = find_latch_ff_wires(module, node);
RTLIL::SigSpec clk_sig, data_sig, clear_sig, preset_sig;
bool clk_polarity = true, clear_polarity = true, preset_polarity = true;
const std::string name = RTLIL::unescape_id(module->name);
bool clear_preset_reported = false;
for (auto child : node->children) {
if (child->id == "clocked_on")
clk_sig = parse_func_expr(module, child->value.c_str());
@ -220,10 +222,21 @@ static void create_ff(RTLIL::Module *module, const LibertyAst *node)
clear_sig = parse_func_expr(module, child->value.c_str());
if (child->id == "preset")
preset_sig = parse_func_expr(module, child->value.c_str());
// TODO with $priority cell, any pair of clear_preset_var1 clear_preset_var2
// can be modeled as a pair of flops with different priority
// rather than just having IQN = ~IQ
if (child->id == "clear_preset_var1" || child->id == "clear_preset_var2") {
if (child->value.size() != 1)
log_error("Unexpected length of clear_preset_var* value %s in FF cell %s\n", child->value, name);
if (child->value[0] != 'X' && !clear_preset_reported) {
log_warning("FF cell %s has well-defined clear&preset behavior, but Yosys models it as undefined\n", name);
clear_preset_reported = true;
}
}
}
if (clk_sig.size() == 0 || data_sig.size() == 0)
log_error("FF cell %s has no next_state and/or clocked_on attribute.\n", RTLIL::unescape_id(module->name));
log_error("FF cell %s has no next_state and/or clocked_on attribute.\n", name);
for (bool rerun_invert_rollback = true; rerun_invert_rollback;)
{

View file

@ -157,6 +157,7 @@ struct Async2syncPass : public Pass {
SigSpec sig_set = ff.sig_set;
SigSpec sig_clr = ff.sig_clr;
SigSpec sig_clr_inv = ff.sig_clr;
if (!ff.pol_set) {
if (!ff.is_fine)
@ -166,24 +167,34 @@ struct Async2syncPass : public Pass {
}
if (ff.pol_clr) {
if (!ff.is_fine)
sig_clr_inv = module->Not(NEW_ID, sig_clr);
else
sig_clr_inv = module->NotGate(NEW_ID, sig_clr);
} else {
if (!ff.is_fine)
sig_clr = module->Not(NEW_ID, sig_clr);
else
sig_clr = module->NotGate(NEW_ID, sig_clr);
}
SigSpec set_and_clr = module->AndGate(NEW_ID, sig_set, sig_clr);
if (!ff.is_fine) {
SigSpec tmp = module->Or(NEW_ID, ff.sig_d, sig_set);
module->addAnd(NEW_ID, tmp, sig_clr, new_d);
tmp = module->And(NEW_ID, tmp, sig_clr_inv);
module->addMux(NEW_ID, tmp, Const(State::Sx, ff.width), set_and_clr, new_d);
tmp = module->Or(NEW_ID, new_q, sig_set);
module->addAnd(NEW_ID, tmp, sig_clr, ff.sig_q);
tmp = module->And(NEW_ID, tmp, sig_clr_inv);
module->addMux(NEW_ID, tmp, Const(State::Sx, ff.width), set_and_clr, ff.sig_q);
} else {
SigSpec tmp = module->OrGate(NEW_ID, ff.sig_d, sig_set);
module->addAndGate(NEW_ID, tmp, sig_clr, new_d);
tmp = module->AndGate(NEW_ID, tmp, sig_clr_inv);
module->addMuxGate(NEW_ID, tmp, State::Sx, set_and_clr, new_d);
tmp = module->OrGate(NEW_ID, new_q, sig_set);
module->addAndGate(NEW_ID, tmp, sig_clr, ff.sig_q);
tmp = module->AndGate(NEW_ID, tmp, sig_clr_inv);
module->addMuxGate(NEW_ID, tmp, State::Sx, set_and_clr, ff.sig_q);
}
ff.sig_d = new_d;

View file

@ -123,10 +123,14 @@ struct Clk2fflogicPass : public Pass {
return module->Mux(NEW_ID, a, b, s);
}
SigSpec bitwise_sr(Module *module, SigSpec a, SigSpec s, SigSpec r, bool is_fine) {
if (is_fine)
return module->AndGate(NEW_ID, module->OrGate(NEW_ID, a, s), module->NotGate(NEW_ID, r));
else
return module->And(NEW_ID, module->Or(NEW_ID, a, s), module->Not(NEW_ID, r));
if (is_fine) {
return module->MuxGate(NEW_ID, module->AndGate(NEW_ID, module->OrGate(NEW_ID, a, s), module->NotGate(NEW_ID, r)), RTLIL::State::Sx, module->AndGate(NEW_ID, s, r));
} else {
std::vector<SigBit> y;
for (int i = 0; i < a.size(); i++)
y.push_back(module->MuxGate(NEW_ID, module->AndGate(NEW_ID, module->OrGate(NEW_ID, a[i], s[i]), module->NotGate(NEW_ID, r[i])), RTLIL::State::Sx, module->AndGate(NEW_ID, s[i], r[i])));
return y;
}
}
void execute(std::vector<std::string> args, RTLIL::Design *design) override
{

View file

@ -64,8 +64,8 @@ select -assert-count 1 t:dffe
select -assert-none t:dffn t:dffsr t:dffe t:$_NOT_ %% %n t:* %i
design -load orig
dfflibmap -prepare -liberty dfflibmap_dffn_dffe.lib -liberty dfflibmap_dffsr.lib
dfflibmap -map-only -liberty dfflibmap_dffn_dffe.lib -liberty dfflibmap_dffsr.lib
dfflibmap -prepare -liberty dfflibmap_dffn_dffe.lib -liberty dfflibmap_dffsr_r.lib
dfflibmap -map-only -liberty dfflibmap_dffn_dffe.lib -liberty dfflibmap_dffsr_r.lib
clean
select -assert-count 5 t:$_NOT_

View file

@ -7,8 +7,8 @@ library(test) {
clear : "CLEAR";
preset : "PRESET";
clear_preset_var1 : L;
clear_preset_var2 : L;
}
clear_preset_var2 : H;
}
pin(D) {
direction : input;
}
@ -28,6 +28,6 @@ library(test) {
pin(QN) {
direction: output;
function : "IQN";
}
}
}
}

View file

@ -0,0 +1,33 @@
library(test) {
cell (dffsr) {
area : 6;
ff("IQ", "IQN") {
next_state : "D";
clocked_on : "CLK";
clear : "CLEAR";
preset : "PRESET";
clear_preset_var1 : H;
clear_preset_var2 : L;
}
pin(D) {
direction : input;
}
pin(CLK) {
direction : input;
}
pin(CLEAR) {
direction : input;
}
pin(PRESET) {
direction : input;
}
pin(Q) {
direction: output;
function : "IQ";
}
pin(QN) {
direction: output;
function : "IQN";
}
}
}

View file

@ -8,6 +8,78 @@ $_DFF_P_ ff0 (.C(C), .D(D), .Q(Q[0]));
$_DFF_PP0_ ff1 (.C(C), .D(D), .R(R), .Q(Q[1]));
$_DFF_PP1_ ff2 (.C(C), .D(D), .R(R), .Q(Q[2]));
$_DFFSR_PPP_ ff3 (.C(C), .D(D), .R(R), .S(S), .Q(Q[3]));
$_DFFSR_NNN_ ff4 (.C(C), .D(D), .R(~R), .S(~S), .Q(Q[4]));
$_DFFE_PP_ ff5 (.C(C), .D(D), .E(E), .Q(Q[5]));
assign Q[11:6] = ~Q[5:0];
endmodule
EOT
proc
opt
read_liberty dfflibmap_dffsr_s.lib
copy top top_unmapped
dfflibmap -liberty dfflibmap_dffsr_s.lib top
async2sync
flatten
opt_clean -purge
equiv_make top top_unmapped equiv
equiv_induct equiv
equiv_status -assert equiv
##################################################################
design -reset
read_verilog -sv -icells <<EOT
module top(input C, D, E, S, R, output [11:0] Q);
$_DFF_P_ ff0 (.C(C), .D(D), .Q(Q[0]));
$_DFF_PP0_ ff1 (.C(C), .D(D), .R(R), .Q(Q[1]));
$_DFF_PP1_ ff2 (.C(C), .D(D), .R(R), .Q(Q[2]));
$_DFFSR_PPP_ ff3 (.C(C), .D(D), .R(R), .S(S), .Q(Q[3]));
$_DFFSR_NNN_ ff4 (.C(C), .D(D), .R(~R), .S(~S), .Q(Q[4]));
$_DFFE_PP_ ff5 (.C(C), .D(D), .E(E), .Q(Q[5]));
assign Q[11:6] = ~Q[5:0];
endmodule
EOT
proc
opt
read_liberty dfflibmap_dffsr_r.lib
copy top top_unmapped
dfflibmap -liberty dfflibmap_dffsr_r.lib top
async2sync
flatten
opt_clean -purge
equiv_make top top_unmapped equiv
equiv_induct equiv
equiv_status -assert equiv
##################################################################
design -reset
read_verilog -sv -icells <<EOT
module top(input C, D, E, S, R, output [11:0] Q);
$_DFF_P_ ff0 (.C(C), .D(D), .Q(Q[0]));
$_DFF_PP0_ ff1 (.C(C), .D(D), .R(R), .Q(Q[1]));
$_DFF_PP1_ ff2 (.C(C), .D(D), .R(R), .Q(Q[2]));
// Formal checking of directly instantiated DFFSR doesn't work at the moment
// likely due to an equiv_induct assume bug #5196

View file

@ -0,0 +1,99 @@
##################################################################
read_verilog -sv -icells <<EOT
module top(input C, D, E, S, R, output [7:0] Q);
always @( posedge C, posedge S, posedge R)
if (R)
Q[0] <= 0;
else if (S)
Q[0] <= 1;
else
Q[0] <= D;
always @( posedge C, posedge S, posedge R)
if (S)
Q[1] <= 1;
else if (R)
Q[1] <= 0;
else
Q[1] <= D;
always @( posedge C, posedge S, posedge R)
if (R)
Q[2] <= 0;
else if (S)
Q[2] <= 1;
else if (E)
Q[2] <= D;
always @( posedge C, posedge S, posedge R)
if (S)
Q[3] <= 1;
else if (R)
Q[3] <= 0;
else if (E)
Q[3] <= D;
assign Q[7:4] = ~Q[3:0];
endmodule
EOT
proc
opt
read_liberty dfflibmap_dffsr_s.lib
copy top top_unmapped
dfflibmap -liberty dfflibmap_dffsr_s.lib top
async2sync
flatten
opt_clean -purge
equiv_make top top_unmapped equiv
equiv_induct equiv
equiv_status -assert equiv
##################################################################
delete top equiv
copy top_unmapped top
dfflibmap -liberty dfflibmap_dffsr_r.lib top
async2sync
flatten
opt_clean -purge
equiv_make top top_unmapped equiv
equiv_induct equiv
equiv_status -assert equiv
##################################################################
delete top equiv
copy top_unmapped top
dfflibmap -liberty dfflibmap_dffsr_mixedpol.lib top
async2sync
flatten
opt_clean -purge
equiv_make top top_unmapped equiv
equiv_induct equiv
equiv_status -assert equiv
##################################################################
delete top equiv
copy top_unmapped top
dfflibmap -liberty dfflibmap_dffsr_not_next.lib top
async2sync
flatten
opt_clean -purge
equiv_make top top_unmapped equiv
equiv_induct equiv
equiv_status -assert equiv