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
|
||||
* 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();
|
||||
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);
|
||||
|
||||
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) {
|
||||
/* Special case that the expression is 1 bit
|
||||
|
|
@ -794,44 +794,26 @@ void cprop_functor::lpm_mux(Design*des, NetMux*obj)
|
|||
return;
|
||||
|
||||
/* 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. */
|
||||
bool flag = true;
|
||||
|
||||
if (! obj->pin_Data(0).nexus()->drivers_constant()) {
|
||||
flag = false;
|
||||
}
|
||||
|
||||
if (flag && obj->pin_Data(0).nexus()->driven_value() != verinum::Vz) {
|
||||
flag = false;
|
||||
}
|
||||
|
||||
if (flag) {
|
||||
replace_with_bufif(des, obj, NetLogic::BUFIF1);
|
||||
if (obj->pin_Data(0).nexus()->drivers_constant() &&
|
||||
obj->pin_Data(0).nexus()->driven_value() == verinum::Vz) {
|
||||
replace_with_mos(des, obj, NetLogic::NMOS);
|
||||
count += 1;
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
/* If instead the second input is all constant Vz, replace the
|
||||
NetMux with an array of BUFIF0 devices. */
|
||||
flag = true;
|
||||
if (! obj->pin_Data(1).nexus()->drivers_constant()) {
|
||||
flag = false;
|
||||
}
|
||||
|
||||
if (flag && obj->pin_Data(1).nexus()->driven_value() != verinum::Vz) {
|
||||
flag = false;
|
||||
}
|
||||
|
||||
if (flag) {
|
||||
replace_with_bufif(des, obj, NetLogic::BUFIF0);
|
||||
NetMux with an array of PMOS devices. */
|
||||
if (obj->pin_Data(1).nexus()->drivers_constant() &&
|
||||
obj->pin_Data(1).nexus()->driven_value() == verinum::Vz) {
|
||||
replace_with_mos(des, obj, NetLogic::PMOS);
|
||||
count += 1;
|
||||
return;
|
||||
}
|
||||
|
||||
/* 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;
|
||||
if ((sel_val != verinum::Vz) && (sel_val != verinum::Vx)) {
|
||||
NetBUFZ*tmp = new NetBUFZ(obj->scope(), obj->name(), obj->width());
|
||||
|
|
@ -974,4 +956,3 @@ void cprop(Design*des)
|
|||
cprop_dc_functor dc;
|
||||
des->functor(&dc);
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue