Библиотека C ++ с поддержкой 3-значной логики: 0,1, X - PullRequest
6 голосов
/ 06 октября 2010

Я работаю над симулятором для микропроцессора, написанным на C ++.

Я ищу способ моделировать элементы состояния на аппаратном обеспечении, которое только что было включено и еще не было сброшенопуть.Элемент реального состояния будет иметь неизвестное значение, равное 0 или 1, но в моделях программного обеспечения это обычно моделируется как X, что означает unknown .

Я ищубиблиотека на C ++, которая может моделировать эти X значения, включая их распространение.То есть ему нужно знать, как обрабатывать логические и арифметические операции с X es:

1 AND X = X
0 AND X = 0
1  +  X = X

и т. Д.

Существует ли такая библиотека, которая является стабильной ибыстро?

Редактировать:

Я не упомянул, что мой текущий код работает с битовыми векторами.Точнее, я использую стандартные типы данных uint_*t, и это те, которые я хочу заменить.Какую бы библиотеку я не использовал, она должна поддерживать арифметику, сдвиги и логические операторы, чтобы она была полезной.

Ответы [ 4 ]

12 голосов
/ 06 октября 2010

Попробуйте Boost.Tribool .

Класс tribool действует как встроенный тип bool, но для логики с тремя состояниями.Три состояния: true, false и indeterminate, где первые два состояния эквивалентны состояниям типа C ++ bool, а последнее состояние представляет неизвестное логическое значение (которое может быть true илиfalse, мы не знаем).

Вы можете увидеть тестовый костюм и документацию заголовка для правил, которые поддерживает этот класс.

Повышающие библиотеки довольно высокого качества и в хорошем состоянии, поэтому вам не нужно беспокоиться о их стабильности.И "быстро" ... ну трудно быть медленным для простых классов, как это :).Операции реализованы с помощью сравнения целых чисел от 2 до 3 с предложениями 1 или 2 if, поэтому оно должно быть достаточно эффективным.

7 голосов
/ 06 октября 2010

Возможно, вы захотите разрешить более трех состояний, если вы пытаетесь смоделировать аппаратные линии. Вот что Altera использует в симуляторе FPGA:

  • 1: Сильный Высокий (транзистор, приводимый в движение VDD)
  • 0: Сильный низкий (транзистор, управляемый на VSS)
  • H: Слабый Высокий (сопротивление резистора до VDD)
  • L: Weak Low (сопротивление резистора до VSS)
  • Z: высокий импеданс (ненаправленная линия)
  • X: неизвестно
  • W: Слабый Неизвестный
  • U: неинициализированный
  • DC: не волнует

Возможно, вам не нужны W, U и DC. Вы можете бросить H, L и Z, если ваши автобусы всегда ездят.

Verilog использует еще больше уровней для моделирования на уровне ворот , с семью мощностями привода для каждого логического уровня. Дополнительные уровни моделируют емкостное воздействие на сигнальные линии. Это, вероятно, больше, чем вам нужно.

РЕДАКТИРОВАТЬ: Поскольку вы упомянули векторы битов, я должен сказать, что, ИМХО, вы не найдете такую ​​библиотеку для публичного использования и постоянно обновлялись, потому что 1) там просто не так много программистов нуждаются в такой вещи, и 2) даже среди них, из-за вышеупомянутых опций для моделирования линейных уровней, есть небольшая совместимость. Трибоолы Boost могут быть запущены в эксплуатацию, но они не будут быстрыми, поскольку операции будут поэлементными, а хранилище не будет оптимизировано, но они могут быть вашим единственным выбором, если у кого-то есть аллергия на написание собственной библиотеки, которая делает именно то, что вам нужно.

Например, допустим, вам нужен класс, который представляет векторы битов с четырьмя возможными уровнями: 1, 0, X и Z. Во-первых, вы должны определить эквивалентные битовые комбинации для каждого уровня (например, X = 00, Z = 01, 0 = 10, 1 = 11; X был выбран в качестве состояния сброса)

Для каждой операции вы должны записать таблицу истинности, предпочтительно в Карта Карно форма:

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.

EDIT2: Меня только что осенило, что шаблонный класс 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")

... который кажется наиболее интуитивным способом дополнить один вектор размером другого (легко показать, что такое заполнение должно не быть неявным, ever ) или объединить векторы.

EDIT3: Меня просто осенило (да, я медленный), что, если бы вы действительно хотели сделать обобщенную версию этого, вы могли бы сделать это с основанный на политике дизайн :

struct TwoLevelLogic
{   enum
    {   kNumPlanes = 1
    };
    static void And(int32_t[] result, int32_t[] lhs, int32_t[] rhs)
    {    result[0] = lhs[0] & rhs[0];
    }
};

struct FourLevelLogic
{   enum
    {   kNumPlanes = 2
    };
    static void And(int32_t[] result, int32_t[] lhs, int32_t[] rhs)
    {    int32_t x = lhs[1] & rhs[1];
         result[1] = x;
         result[0] = lhs[0] & rhs[0] & x;
    }
};

template<typename LogicType, size_t NBits>
class BitVector
{private:
    enum { NWords = (NBits+31)/32 };
    int32_t storage[NWords][LogicType::kNumPlanes];
public:
    BitVector<LogicType, NBits> operator &(BitVector<LogicType, NBits>& rhs)
    {    BitVector<LogicType, NBits> result;
         for(unsigned k = 0; k < NWords; ++k)
             LogicType::And(result.storage[k], storage[k], rhs.storage[k]);
         return result;
    }
};

template<size_t NBits> 
class BitVector4L: public BitVector<FourLevelLogic, NBits> {};

Тогда, если вы хотите использовать другое логическое представление, скажем, девять уровней или даже два, вы можете определить новые политики для поддержки этих форматов. Кроме того, вы можете вычислить различные политики в разных областях вашей проблемы (скажем, 4 уровня для вашей платы, 9 для чипа и 2 для симулятора процессора) и определить функции преобразования для преодоления пробелов.

Опять же, я не пытался построить это, поэтому я не уверен, что это оптимизирует идеально.

5 голосов
/ 06 октября 2010

Boost имеет библиотеку tribool, но я не могу комментировать ее качество, так как никогда не использовал ее:

http://www.boost.org/doc/libs/1_44_0/doc/html/tribool.html

0 голосов
/ 06 октября 2010

Я не знаком с упомянутой выше библиотекой надстройки, но, похоже, она поддерживает только одно логическое значение, а не битовое поле.Вы можете сделать это самостоятельно без лишней суеты, используя следующую технику:

class Logic
{
    unsigned x, xu;

public:
    Logic(unsigned x, unsigned xu)
    {
        this->x = x;
        this->xu = xu;
    }

    Logic operator&(const Logic &rhs) const
    {
        return Logic(
            x & rhs.x,
            xu & (rhs.x | rhs.xu) | rhs.xu & (x | xu));
    }

    Logic operator|(const Logic &rhs) const
    {
        return Logic(
            x | rhs.x,
            xu & (~rhs.x | rhs.xu) | rhs.xu & (~x | xu));
    }
};

Отказ от ответственности - это требует проверки!

Если вы планируете выполнять многие из них одновременно, вылучше использовать 64-битные целые числа вместо отдельных трибоолов.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...