fpga: replace variable shift with a compare mask in port gating
Контрольная сборка стока в ISE показала, что первая версия правки внесла нарушение тайминга: сток даёт Timing Score 0, а она — 1880 (hold на входе MCU_MOSI). Причина — shift_right с переменным сдвигом синтезируется в barrel shifter, а вызывался он четырежды: +142 LUT при +3 регистрах, из-за чего поехало размещение и пострадала SPI-шина, по которой MCU пишет регистры FPGA. Сбой там означал бы неверную конфигурацию развёртки. Теперь младшие биты счётчика стадий просто маскируются, а маска декодируется из SUBSTAGE_BITS тремя вентилями. Итог: 2182 LUT против 2189 у стока, то есть логика стала дешевле стоковой. При SUBSTAGE_BITS=0 маска все единицы и выражение вырождается в стоковое stage_cnt = port_stage буквально. Заодно контракт стал однозначнее: хост присылает ПЕРВУЮ стадию блока порта, а не индекс порта. Без под-стадий это то же число, поэтому стоковая совместимость сохраняется, а зарезервированное "7 = порт выключен" больше не может совпасть с настоящей стадией (при четырёх под-стадиях маскированная семёрка совпадала с блоком второго порта). Из VHDL убраны не-ASCII символы: GHDL отвергает их даже в комментариях. Проверено: тестбенч проходит все четыре сценария и падает под мутацией (8 сработавших проверок), 305 python-тестов зелёные, ISE собирает битстрим. Остаточное нарушение hold на MCU_MOSI ловится подбором cost table размещателя — ограничение маргинально уже в стоке (запас +0.458 нс). Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -465,8 +465,11 @@ class PerPointStimulusSwitchingTest(unittest.TestCase):
|
||||
)
|
||||
stage_word = struct.unpack_from("<H", master, 25)[0]
|
||||
self.assertEqual(stage_word & 0x07, 3) # 4 stages -> last index 3
|
||||
self.assertEqual((stage_word >> 3) & 0x07, 0) # port 1 selected by upper stage bits 0
|
||||
self.assertEqual((stage_word >> 6) & 0x07, 1) # port 2 -> 1
|
||||
# Port stages are the FIRST stage of each port's block: port 1 owns stages
|
||||
# 0..1 and port 2 owns 2..3, so the bitstream matches them on the stage bits
|
||||
# above the substage block.
|
||||
self.assertEqual((stage_word >> 3) & 0x07, 0)
|
||||
self.assertEqual((stage_word >> 6) & 0x07, 2)
|
||||
self.assertEqual((stage_word >> 9) & 0x07, 1) # log2(2 positions) = 1 substage bit
|
||||
|
||||
slave = build_sweep_settings_payload(
|
||||
|
||||
Reference in New Issue
Block a user