Таблицы прав в коде? Как структурировать конечный автомат?

У меня есть (несколько) большая таблица истинности/конечная машина, которую мне нужно реализовать в моем коде (встроенный C). Я ожидаю, что спецификация поведения этого конечного автомата изменится в будущем, и поэтому я хотел бы сохранить это легко модифицируемым в будущем.

Моя таблица истинности имеет 4 входа и 4 выхода. У меня есть все это в электронной таблице Excel, и если бы я мог просто вставить это в свой код с небольшим форматированием, это было бы идеально.

Я думал, что хотел бы получить доступ к моей таблице истинности так:

u8 newState[] = decisionTable[input1][input2][input3][input4];

И затем я мог получить доступ к выходным значениям с помощью:

setOutputPin( LINE_0, newState[0] );
setOutputPin( LINE_1, newState[1] );
setOutputPin( LINE_2, newState[2] );
setOutputPin( LINE_3, newState[3] );

Но для того, чтобы это получить, похоже, мне пришлось бы делать довольно запутанную таблицу, например:

static u8 decisionTable[][][][][] =
 {{{{ 0, 0, 0, 0 },
    { 0, 0, 0, 0 }},
   {{ 0, 0, 0, 0 },
    { 0, 0, 0, 0 }}},
  {{{ 0, 0, 1, 1 },
    { 0, 1, 1, 1 }},
   {{ 0, 1, 0, 1 },
    { 1, 1, 1, 1 }}}},
 {{{{ 0, 1, 0, 1 },
    { 1, 1, 1, 1 }},
   {{ 0, 1, 0, 1 },
    { 1, 1, 1, 1 }}},
  {{{ 0, 1, 1, 1 },
    { 0, 1, 1, 1 }},
   {{ 0, 1, 0, 1 },
    { 1, 1, 1, 1 }}}};

Вложенные скобки могут быть несколько запутанными - есть ли у кого-нибудь лучшее представление о том, как я могу хранить симпатичную таблицу в моем коде?

Спасибо!

Изменить на основе ответа HUAGHAGUAH:

Использование объединения каждого входа (спасибо - я бы хотел "принять" 3 или 4 из этих ответов), я думаю, что я попытаюсь использовать его как двухмерный массив. Я буду индексировать в свой массив с помощью небольшого макросдвигающего макроса:

#define SM_INPUTS( in0, in1, in2, in3 ) ((in0 << 0) | (in1 << 1) | (in2 << 2) | (in3 << 3))

И это позволит массиву таблицы истинности выглядеть так:

static u8 decisionTable[][] = {
{ 0, 0, 0, 0 },
{ 0, 0, 0, 0 },
{ 0, 0, 0, 0 },
{ 0, 0, 0, 0 },
{ 0, 0, 1, 1 },
{ 0, 1, 1, 1 },
{ 0, 1, 0, 1 },
{ 1, 1, 1, 1 },
{ 0, 1, 0, 1 },
{ 1, 1, 1, 1 },
{ 0, 1, 0, 1 },
{ 1, 1, 1, 1 },
{ 0, 1, 1, 1 },
{ 0, 1, 1, 1 },
{ 0, 1, 0, 1 },
{ 1, 1, 1, 1 }};

И затем я могу получить доступ к моей таблице истинности так:

decisionTable[ SM_INPUTS( line1, line2, line3, line4 ) ]

Я дам этот выстрел и посмотрю, как это работает. Я также буду заменять 0 и 1 более полезными #defines, которые выражают то, что означает каждое состояние, вместе с/**/комментариями, которые объясняют входы для каждой строки выходов. Спасибо за помощь, всем!

Ответ 1

Нет необходимости в многомерной таблице. С 4-битным = > 4-битным отображением вы можете иметь один выход для отображения массива u8 [16] для выходов. Поиск состояния будет намного дешевле, и вы можете извлечь отдельные биты с помощью операций смены и маски.

Если алгоритм заполнения строк легко кодифицировать, вы можете #define макрос, чтобы заполнить каждую строку индексом.

Ответ 2

Я бы предложил либо (предпочтительные подходы сначала):

  • Используйте макрос для инициализации каждой "строки" - это скроет фигурные скобки внутри макросообщения.
  • Используйте комментарии для разбивки строк.
  • Используйте функцию init для инициализации контекста явно - возможно, используйте функции для инициализации каждого раздела. Это похоже на первый вариант выше, но имеет недостаток, что функция init должна быть вызвана до использования конечного автомата.

Ответ 3

Лично я бы прочитал его из файла конфигурации. CSV, возможно, который легко экспортировать из Excel. Или вы можете просто скопировать и вставить из Excel в обычный текст, который дает вам значения, разделенные пробелами, которые также легко импортировать.

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

Ответ 4

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

1111,0000
1110,0110
...

для сжатия данных, представляют значения как байты (два nybbles)...

где/как хранить его для мягкого кодирования в вашей конкретной конфигурации встроенной системы, только вы можете сказать; -)

Ответ 5

Если таблица истинности действительно только 4x4x4x4, я бы использовал макросы. Если это когда-либо будет расти, я бы использовал Ragel. Скорее всего, это сделает меньший, более быстрый код C, чем вы.

Ответ 6

Я не вижу ссылки на текущее состояние, чтобы получить ваше состояние вывода. Это означает, что это не государственная машина, а только таблица истинности. Есть четыре входа, поэтому есть только 16 возможных комбинаций ввода. Итак, таблица с 16 позициями должна это сделать.

Ответ 7

Обычно, когда у вас есть такая проблема, вы пытаетесь свести ее к простой логической формуле. Я не понимаю, почему это не лучший подход. Он был бы намного более компактным и читабельным, плюс он имел бы возможность быть быстрее (я думаю, что несколько AND и OR будут выполняться быстрее, чем сбор умножений/сдвигов + доступ к памяти, необходимый для подхода таблицы поиска). Самый простой способ уменьшить эту таблицу до булевой формулы - это K-Map.