An optimized mux should use MOS devices not bufif devices.
The bufif devices do not correctly propagate the Z value as required by the standard. The MOS devices do propagate a Z value, but they do not correctly handle the case where both inputs are Z and the select is undefined/Z. The standard specifies that this should be X, but we produce Z. The full MUX and %blend operator also function this way, so Icarus may not match the standard, but it is consistent. I would also argue that the standard is incorrect. If both inputs are Z then the output should be Z no matter what select is.
This commit is contained in:
parent
a654bdc169
commit
de2b10b445
43
cprop.cc
43
cprop.cc
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 1998-2005 Stephen Williams (steve@icarus.com)
|
* Copyright (c) 1998-2008 Stephen Williams (steve@icarus.com)
|
||||||
*
|
*
|
||||||
* This source code is free software; you can redistribute it
|
* This source code is free software; you can redistribute it
|
||||||
* and/or modify it in source code form under the terms of the GNU
|
* and/or modify it in source code form under the terms of the GNU
|
||||||
|
|
@ -739,7 +739,7 @@ v }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void replace_with_bufif(Design*des, NetMux*obj, NetLogic::TYPE type)
|
static void replace_with_mos(Design*des, NetMux*obj, NetLogic::TYPE type)
|
||||||
{
|
{
|
||||||
NetScope*scope = obj->scope();
|
NetScope*scope = obj->scope();
|
||||||
NetLogic*tmp = new NetLogic(obj->scope(),
|
NetLogic*tmp = new NetLogic(obj->scope(),
|
||||||
|
|
@ -749,7 +749,7 @@ static void replace_with_bufif(Design*des, NetMux*obj, NetLogic::TYPE type)
|
||||||
des->add_node(tmp);
|
des->add_node(tmp);
|
||||||
|
|
||||||
connect(obj->pin_Result(), tmp->pin(0));
|
connect(obj->pin_Result(), tmp->pin(0));
|
||||||
connect(obj->pin_Data(type==NetLogic::BUFIF0? 0 : 1), tmp->pin(1));
|
connect(obj->pin_Data(type==NetLogic::PMOS? 0 : 1), tmp->pin(1));
|
||||||
|
|
||||||
if (obj->width() == 1) {
|
if (obj->width() == 1) {
|
||||||
/* Special case that the expression is 1 bit
|
/* Special case that the expression is 1 bit
|
||||||
|
|
@ -794,44 +794,26 @@ void cprop_functor::lpm_mux(Design*des, NetMux*obj)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
/* If the first input is all constant Vz, then replace the
|
/* If the first input is all constant Vz, then replace the
|
||||||
NetMux with an array of BUFIF1 devices, with the enable
|
NetMux with an array of NMOS devices, with the enable
|
||||||
connected to the select input. */
|
connected to the select input. */
|
||||||
bool flag = true;
|
if (obj->pin_Data(0).nexus()->drivers_constant() &&
|
||||||
|
obj->pin_Data(0).nexus()->driven_value() == verinum::Vz) {
|
||||||
if (! obj->pin_Data(0).nexus()->drivers_constant()) {
|
replace_with_mos(des, obj, NetLogic::NMOS);
|
||||||
flag = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (flag && obj->pin_Data(0).nexus()->driven_value() != verinum::Vz) {
|
|
||||||
flag = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (flag) {
|
|
||||||
replace_with_bufif(des, obj, NetLogic::BUFIF1);
|
|
||||||
count += 1;
|
count += 1;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* If instead the second input is all constant Vz, replace the
|
/* If instead the second input is all constant Vz, replace the
|
||||||
NetMux with an array of BUFIF0 devices. */
|
NetMux with an array of PMOS devices. */
|
||||||
flag = true;
|
if (obj->pin_Data(1).nexus()->drivers_constant() &&
|
||||||
if (! obj->pin_Data(1).nexus()->drivers_constant()) {
|
obj->pin_Data(1).nexus()->driven_value() == verinum::Vz) {
|
||||||
flag = false;
|
replace_with_mos(des, obj, NetLogic::PMOS);
|
||||||
}
|
|
||||||
|
|
||||||
if (flag && obj->pin_Data(1).nexus()->driven_value() != verinum::Vz) {
|
|
||||||
flag = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (flag) {
|
|
||||||
replace_with_bufif(des, obj, NetLogic::BUFIF0);
|
|
||||||
count += 1;
|
count += 1;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If the select input is constant, then replace with a BUFZ */
|
/* If the select input is constant, then replace with a BUFZ */
|
||||||
flag = obj->pin_Sel().nexus()->drivers_constant();
|
bool flag = obj->pin_Sel().nexus()->drivers_constant();
|
||||||
verinum::V sel_val = flag? obj->pin_Sel().nexus()->driven_value() : verinum::Vx;
|
verinum::V sel_val = flag? obj->pin_Sel().nexus()->driven_value() : verinum::Vx;
|
||||||
if ((sel_val != verinum::Vz) && (sel_val != verinum::Vx)) {
|
if ((sel_val != verinum::Vz) && (sel_val != verinum::Vx)) {
|
||||||
NetBUFZ*tmp = new NetBUFZ(obj->scope(), obj->name(), obj->width());
|
NetBUFZ*tmp = new NetBUFZ(obj->scope(), obj->name(), obj->width());
|
||||||
|
|
@ -974,4 +956,3 @@ void cprop(Design*des)
|
||||||
cprop_dc_functor dc;
|
cprop_dc_functor dc;
|
||||||
des->functor(&dc);
|
des->functor(&dc);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue