Last active
April 21, 2019 09:07
-
-
Save jdryg/d3a41277e352ff749d6abe2164530ee9 to your computer and use it in GitHub Desktop.
3-valued logic functions
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 3-valued logic functions based on the encoding described in | |
// "Boolean Analysis of MOS Circuits" | |
// http://www.cs.cmu.edu/~bryant/pubdir/tcad87b.pdf | |
// | |
// Each of the 3 states, 0, 1 and X is encoded using 2 bits | |
// 0 => 01 | |
// 1 => 10 | |
// X => 11 | |
// | |
// with 00 indicating an invalid state (used for uninitialized signals). | |
// | |
// This is similar to positional cube encoding used in logic | |
// minimization algorithms (with X indicating a don't care condition). | |
// | |
#ifndef LOGIC3_H | |
#define LOGIC3_H | |
#include <stdint.h> | |
#ifndef LOGIC3_CONFIG_SIGNAL_MAX_WIDTH | |
#define LOGIC3_CONFIG_SIGNAL_MAX_WIDTH 32 | |
#endif | |
#if LOGIC3_CONFIG_SIGNAL_MAX_WIDTH == 16 | |
typedef uint16_t signal_t; | |
#elif LOGIC3_CONFIG_SIGNAL_MAX_WIDTH == 32 | |
typedef uint32_t signal_t; | |
#else // LOGIC3_CONFIG_SIGNAL_MAX_WIDTH | |
#error "Invalid LOGIC3_CONFIG_SIGNAL_MAX_WIDTH value" | |
#endif | |
struct Signal | |
{ | |
signal_t s0; | |
signal_t s1; | |
}; | |
// Convert 32-bit integer to Signal | |
inline Signal makeSignal(uint32_t val, uint32_t size) | |
{ | |
Signal s = { 0, 0 }; | |
for (uint32_t i = 0; i < size; ++i) { | |
const uint32_t bit = (val >> i) & 1; | |
if (bit == 0) { | |
s.s0 |= (1 << i); | |
} else { | |
s.s1 |= (1 << i); | |
} | |
} | |
return s; | |
} | |
inline Signal undefined() | |
{ | |
return { signal_t(~0), signal_t(~0) }; | |
} | |
inline Signal uninitialized() | |
{ | |
return { 0, 0 }; | |
} | |
inline bool isEqual(Signal a, Signal b, uint32_t size) | |
{ | |
const uint32_t mask = (1 << size) - 1; | |
const signal_t x0 = a.s0 ^ b.s0; | |
const signal_t x1 = a.s1 ^ b.s1; | |
return ((x0 | x1) & mask) == 0; | |
// return (a.s0 & mask) == (b.s0 & mask) | |
// && (a.s1 & mask) == (b.s1 & mask); | |
} | |
// A Signal is considered Undefined if at least 1 of each states | |
// is Undefined (b11). | |
inline bool isUndefined(Signal s) | |
{ | |
return (s.s0 & s.s1) != 0; | |
} | |
inline bool isUninitialized(Signal s) | |
{ | |
return (s.s0 | s.s1) == 0; | |
} | |
// A | NOT A | |
// --------------- | |
// 0 (01) | 1 (10) | |
// 1 (10) | 0 (01) | |
// X (11) | X (11) | |
// | |
inline Signal not1(Signal a) | |
{ | |
return { a.s1, a.s0 }; | |
} | |
// A | B | AND | |
// ------------------------ | |
// 0 (01) | 0 (01) | 0 (01) | |
// 0 (01) | 1 (10) | 0 (01) | |
// 0 (01) | X (11) | 0 (01) | |
// 1 (10) | 0 (01) | 0 (01) | |
// 1 (10) | 1 (10) | 1 (10) | |
// 1 (10) | X (11) | X (11) | |
// X (11) | 0 (01) | 0 (01) | |
// X (11) | 1 (10) | X (11) | |
// X (11) | X (11) | X (11) | |
// | |
inline Signal and2(Signal a, Signal b) | |
{ | |
return { | |
signal_t(a.s0 | b.s0), | |
signal_t(a.s1 & b.s1) | |
}; | |
} | |
template<typename T> | |
inline Signal andn(T t) { return t; } | |
template<typename A, typename B> | |
inline Signal andn(A a, B b) { return and2(a, b); } | |
template<typename A, typename... Args> | |
inline Signal andn(A a, Args... args) { return and2(a, andn(args...)); } | |
// A | B | OR | |
// ------------------------ | |
// 0 (01) | 0 (01) | 0 (01) | |
// 0 (01) | 1 (10) | 1 (10) | |
// 0 (01) | X (11) | X (11) | |
// 1 (10) | 0 (01) | 1 (10) | |
// 1 (10) | 1 (10) | 1 (10) | |
// 1 (10) | X (11) | 1 (10) | |
// X (11) | 0 (01) | X (11) | |
// X (11) | 1 (10) | 1 (10) | |
// X (11) | X (11) | X (11) | |
// | |
inline Signal or2(Signal a, Signal b) | |
{ | |
return { | |
signal_t(a.s0 & b.s0), | |
signal_t(a.s1 | b.s1) | |
}; | |
} | |
template<typename T> | |
inline Signal orn(T t) { return t; } | |
template<typename A, typename B> | |
inline Signal orn(A a, B b) { return or2(a, b); } | |
template<typename A, typename... Args> | |
inline Signal orn(A a, Args... args) { return or2(a, orn(args...)); } | |
// A | B | NAND | |
// ------------------------ | |
// 0 (01) | 0 (01) | 1 (10) | |
// 0 (01) | 1 (10) | 1 (10) | |
// 0 (01) | X (11) | 1 (10) | |
// 1 (10) | 0 (01) | 1 (10) | |
// 1 (10) | 1 (10) | 0 (01) | |
// 1 (10) | X (11) | X (11) | |
// X (11) | 0 (01) | 1 (10) | |
// X (11) | 1 (10) | X (11) | |
// X (11) | X (11) | X (11) | |
// | |
inline Signal nand2(Signal a, Signal b) | |
{ | |
return { | |
signal_t(a.s1 & b.s1), | |
signal_t(a.s0 | b.s0) | |
}; | |
} | |
template<typename A, typename... Args> | |
inline Signal nandn(A a, Args... args) { return nand2(a, andn(args...)); } | |
// A | B | NOR | |
// ------------------------ | |
// 0 (01) | 0 (01) | 1 (10) | |
// 0 (01) | 1 (10) | 0 (01) | |
// 0 (01) | X (11) | X (11) | |
// 1 (10) | 0 (01) | 0 (01) | |
// 1 (10) | 1 (10) | 0 (01) | |
// 1 (10) | X (11) | 0 (01) | |
// X (11) | 0 (01) | X (11) | |
// X (11) | 1 (10) | 0 (01) | |
// X (11) | X (11) | X (11) | |
// | |
inline Signal nor2(Signal a, Signal b) | |
{ | |
return { | |
signal_t(a.s1 | b.s1), | |
signal_t(a.s0 & b.s0) | |
}; | |
} | |
template<typename A, typename... Args> | |
inline Signal norn(A a, Args... args) { return nor2(a, orn(args...)); } | |
// A | B | XOR | |
// ------------------------ | |
// 0 (01) | 0 (01) | 0 (01) | |
// 0 (01) | 1 (10) | 1 (10) | |
// 0 (01) | X (11) | X (11) | |
// 1 (10) | 0 (01) | 1 (10) | |
// 1 (10) | 1 (10) | 0 (01) | |
// 1 (10) | X (11) | X (11) | |
// X (11) | 0 (01) | X (11) | |
// X (11) | 1 (10) | X (11) | |
// X (11) | X (11) | X (11) | |
// | |
inline Signal xor2(Signal a, Signal b) | |
{ | |
return { | |
signal_t((a.s1 & b.s1) | (a.s0 & b.s0)), | |
signal_t((a.s0 & b.s1) | (a.s1 & b.s0)) | |
}; | |
} | |
inline Signal merge1(const Signal* inputs, uint32_t numBits) | |
{ | |
Signal r = { 0, 0 }; | |
for (uint32_t i = 0; i < numBits; ++i) { | |
const Signal input = inputs[i]; | |
r.s0 |= (input.s0 & 1) << i; | |
r.s1 |= (input.s1 & 1) << i; | |
} | |
return r; | |
} | |
inline void split1(Signal a, uint32_t numBits, Signal* outputs) | |
{ | |
for (uint32_t i = 0; i < numBits; ++i) { | |
outputs[i].s0 = (a.s0 >> i) & 1; | |
outputs[i].s1 = (a.s1 >> i) & 1; | |
} | |
} | |
#endif |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment