如果您试图建模硬件线路,则可能希望考虑允许超过三个状态。以下是Altera在其FPGA模拟器中使用的内容:
1: 强高(晶体管驱动到VDD)
0: 强低(晶体管驱动到VSS)
H: 弱高(电阻上拉到VDD)
L: 弱低(电阻下拉到VSS)
Z: 高阻(未驱动的线路)
X: 未知
W: 弱未知
U: 未初始化
DC: 不关心
如果总线始终被驱动,您可能不需要W、U和DC。 Verilog在门级建模中使用更多级别,并为每个逻辑电平提供7个驱动强度。额外的级别模拟信号线上的电容效应。这可能比您所需的要多。
编辑: 既然你提到了位向量,我必须说,在公共使用并保持最新状态的库中,你不太可能找到这样一个库,因为1)需要这样东西的程序员并不是很多,2)即使在他们中间,由于前面提到的建模线路电平的选项,兼容性很小。Boost的tribool可以被用来解决问题,但它们不会很快,因为操作将逐个元素进行,存储也不会被优化,但如果有人对编写一个完全符合您需求的内部库过敏,它们可能是您唯一的选择。
例如,假设你想要一个表示具有四个可能级别的位向量的类:1、0、X和Z。首先,你必须为每个级别定义等效的位模式(例如,X=00,Z=01,0=10,1=11;X被选为复位状态)
对于每个操作,你必须编写真值表,最好以Karnaugh Map形式呈现:
op: & | X (00) | Z (01) | 1 (11) | 0 (10)
-------+--------+--------+--------+--------
X (00) | X (00) | X (00) | X (00) | X (00)
-------+--------+--------+--------+--------
Z (01) | X (00) | X (00) | X (00) | X (00)
-------+--------+--------+--------+--------
1 (11) | X (00) | X (00) | 1 (11) | 0 (10)
-------+--------+--------+--------+--------
0 (10) | X (00) | X (00) | 0 (10) | 0 (10)
请注意,X经常获胜。这对大多数操作来说都是正确的。
然后从K图中计算布尔方程:
C = A & B
=> C1 = A1 & B1
C0 = A1 & B1 & A0 & B0 = C1 & A0 & B0
最后,将其翻译成C++:
template<size_t NBits> class BitVector
{private:
enum { NWords = (NBits+31)/32 };
int32_t storage[NWords][2];
public:
BitVector<NBits> operator &(BitVector<NBits>& rhs)
{ BitVector<NBits> result;
for(unsigned k = 0; k < NWords; ++k)
{ int32_t x = storage[k][1] & rhs.storage[k][0];
result.storage[k][1] = x;
result.storage[k][0] = storage[k][0] & rhs.storage[k][0] & x;
}
return result;
}
};
(注:我还没有测试上面的代码,所以使用时需自担风险。)
如果允许级别的集合发生变化,所有这些都必须重新做。这就是为什么这些库往往过于专业化,无法放入像Boost这样的通用库中。
编辑2:我突然想到BitVector模板类是少数几个重载逗号运算符有意义的用例之一:
template<size_t NBitsR>
BitVector<NBits+NBitsR> operator ,(const BitVector<NBitsR>& rhs);
这允许您连接位向量:
BitVector<8> a("1110 0111");
BitVector<4> b("0000");
BitVector<12> c = (a, b); // == BitVector<12>("0000 1110 0111")
...这似乎是将一个向量填充到另一个向量大小的最直观的方法(很容易证明这样的填充不应该是隐式的,永远不应该),或者将向量合并在一起。
编辑3:我突然意识到(是的,我很慢),如果你真的想做一个通用版本,你可以使用基于策略的设计:
struct TwoLevelLogic
;
static void And(int32_t[] result, int32_t[] lhs, int32_t[] rhs)
};
struct FourLevelLogic
;
static void And(int32_t[] result, int32_t[] lhs, int32_t[] rhs)
};
template<typename LogicType, size_t NBits>
class BitVector
;
int32_t storage[NWords][LogicType::kNumPlanes];
public:
BitVector<LogicType, NBits> operator &(BitVector<LogicType, NBits>& rhs)
};
template<size_t NBits>
class BitVector4L: public BitVector<FourLevelLogic, NBits> ;
然后,如果您想使用不同的逻辑表示,比如九个级别,甚至两个级别,那么您可以定义新的策略来支持这些格式。此外,您可以在问题的不同领域中使用不同的策略进行计算(例如,板子上使用4个级别,芯片上使用9个级别,处理器模拟器上使用2个级别),并定义转换函数来弥合差距。
同样,我还没有尝试构建它,所以我不确定它是否完美优化。