Skip to content

Instantly share code, notes, and snippets.

@jdryg
Last active April 21, 2019 09:07
Show Gist options
  • Save jdryg/d3a41277e352ff749d6abe2164530ee9 to your computer and use it in GitHub Desktop.
Save jdryg/d3a41277e352ff749d6abe2164530ee9 to your computer and use it in GitHub Desktop.
3-valued logic functions
// 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