Вы написали кодировщик приоритетов здесь, где последнее условие применяется только в том случае, если ни одно из остальных не является действительным. Это часто медленнее реализовать (если инструмент синтеза не может оптимизировать отсутствие недоступного состояния), и его сложнее масштабировать (как вы обнаружили).
Также сложнее анализировать с точки зрения проверки того, что поток из каждого состояния корректен для всех возможных состояний.
Несмотря на то, что он может выглядеть менее оптимальным, более распространенным является запись конечного автомата как оператора case с использованием переменной состояния. Затем вы развертываете выражения «для каждого состояния, следующее условие состояния ...».
Используя кодировку, подразумеваемую в изображении , это было бы очевидным выражением
2'b01: nextState = (counter == 5'h0f) ? 2'b10 : 2'b01;
На основе состояния / следующего состояния вы также можете определить, какое поведение необходимо счетчику. Помните, что если у вас более одного счетчика, у вас есть некоторые неявные предположения о корреляции между состояниями счета и состояниями освещения.
Неочевидная часть этого вопроса заключается в том, что вам может не потребоваться последовательность из 4 состояний (как показано на схеме, где оси принимают «инвертированные» состояния), у вас есть до 16 потенциальных состояний, потому что у вас есть два набора огней. Вы должны сначала выбрать все возможные пути из одного из «стабильных» состояний, определив, каких состояний вам следует избегать (например, G / G). Это еще одна причина для отделения переменных состояния от выходов.