fpga: pin placer cost table 2, add the built master bitstream
Ограничение MCU_MOSI OFFSET hold маргинально уже в стоке: запас +0.458 нс. Поэтому любое изменение нетлиста переставляет размещение и может его опрокинуть. A/B в ISE: сток - Timing Score 0, версия на маске при cost table 1 - 5480. Cost table 2 даёт Timing Score 0, причём запас по hold на MCU_MOSI больше стокового: +0.642 против +0.458 нс. Значение зафиксировано в VNA.xise одной строкой, иначе следующая сборка снова словит нарушение. Ресурсы финальной сборки: 2302 LUT против 2189 у стока (40% против 38% ёмкости xc6slx9). Промежуточные 2182, которые я приводил раньше, были из сборки с cost table 1 - её перебор потом переделал, и упаковка map изменилась. Битстрим положен как top_master_per_point_switching.bin, а не поверх top_master.bin: последний - одна из двух копий невосстановимого битстрима, из которого собран текущий combined.vnafw. Документ приведён в согласованное состояние: таблица контракта и описание Sweep.vhd отставали от версии на маске. Собрано и проверено на машине сборки: ISE 14.7 в виртуалке, xtclsh в батч-режиме. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -433,7 +433,7 @@
|
|||||||
<property xil_pn:name="Specify Top Level Instance Names Post-Route" xil_pn:value="Default" xil_pn:valueState="default"/>
|
<property xil_pn:name="Specify Top Level Instance Names Post-Route" xil_pn:value="Default" xil_pn:valueState="default"/>
|
||||||
<property xil_pn:name="Specify Top Level Instance Names Post-Translate" xil_pn:value="Default" xil_pn:valueState="default"/>
|
<property xil_pn:name="Specify Top Level Instance Names Post-Translate" xil_pn:value="Default" xil_pn:valueState="default"/>
|
||||||
<property xil_pn:name="Speed Grade" xil_pn:value="-2" xil_pn:valueState="non-default"/>
|
<property xil_pn:name="Speed Grade" xil_pn:value="-2" xil_pn:valueState="non-default"/>
|
||||||
<property xil_pn:name="Starting Placer Cost Table (1-100) Map spartan6" xil_pn:value="1" xil_pn:valueState="default"/>
|
<property xil_pn:name="Starting Placer Cost Table (1-100) Map spartan6" xil_pn:value="2" xil_pn:valueState="non-default"/>
|
||||||
<property xil_pn:name="Synthesis Tool" xil_pn:value="XST (VHDL/Verilog)" xil_pn:valueState="default"/>
|
<property xil_pn:name="Synthesis Tool" xil_pn:value="XST (VHDL/Verilog)" xil_pn:valueState="default"/>
|
||||||
<property xil_pn:name="Target Simulator" xil_pn:value="Please Specify" xil_pn:valueState="default"/>
|
<property xil_pn:name="Target Simulator" xil_pn:value="Please Specify" xil_pn:valueState="default"/>
|
||||||
<property xil_pn:name="Target UCF File Name" xil_pn:value="top.ucf" xil_pn:valueState="non-default"/>
|
<property xil_pn:name="Target UCF File Name" xil_pn:value="top.ucf" xil_pn:valueState="non-default"/>
|
||||||
|
|||||||
BIN
Binary file not shown.
@@ -10,6 +10,7 @@ ba729999be7849187704cf4ccbc4ae4a8877b0860eee1b44225c0585537bb091 *extracted/mast
|
|||||||
56654a0344556d24ecca10f119e0226b8297a2bb89d1aa4217280854e9ffa7bd *extracted/slave_stm32.bin
|
56654a0344556d24ecca10f119e0226b8297a2bb89d1aa4217280854e9ffa7bd *extracted/slave_stm32.bin
|
||||||
# битстримы и прошивки MCU в дереве проекта
|
# битстримы и прошивки MCU в дереве проекта
|
||||||
c0e69bbcadd9fac20de10acbe1875ceba39cc7ce35a7c64ed54f44150560ef75 *LibreVNA/FPGA/VNA/top_master.bin
|
c0e69bbcadd9fac20de10acbe1875ceba39cc7ce35a7c64ed54f44150560ef75 *LibreVNA/FPGA/VNA/top_master.bin
|
||||||
|
e184eb92bef1c698849511845fa8d7543287ed1e696c2b461520533112913113 *LibreVNA/FPGA/VNA/top_master_per_point_switching.bin
|
||||||
71f12345b1bed31f6a8b78e2eaa30503f26556cedcbff4615cd5a998953210d5 *LibreVNA/FPGA/VNA/top_external_lo_slave.bin
|
71f12345b1bed31f6a8b78e2eaa30503f26556cedcbff4615cd5a998953210d5 *LibreVNA/FPGA/VNA/top_external_lo_slave.bin
|
||||||
9e063008fabc872c8d534793851116373e6730cfbeaec17de18c1ba8bf7e9ca2 *LibreVNA/FPGA/VNA/top.bin
|
9e063008fabc872c8d534793851116373e6730cfbeaec17de18c1ba8bf7e9ca2 *LibreVNA/FPGA/VNA/top.bin
|
||||||
ba729999be7849187704cf4ccbc4ae4a8877b0860eee1b44225c0585537bb091 *LibreVNA/Software/VNA_embedded/build/VNA_embedded.bin
|
ba729999be7849187704cf4ccbc4ae4a8877b0860eee1b44225c0585537bb091 *LibreVNA/Software/VNA_embedded/build/VNA_embedded.bin
|
||||||
|
|||||||
@@ -39,51 +39,57 @@
|
|||||||
| Биты | Поле | Значение в этом режиме |
|
| Биты | Поле | Значение в этом режиме |
|
||||||
|---|---|---|
|
|---|---|---|
|
||||||
| 0..2 | `stages` | 3 (то есть 4 стадии) |
|
| 0..2 | `stages` | 3 (то есть 4 стадии) |
|
||||||
| 3..5 | `port1Stage` | 0 — **индекс порта**, а не номер стадии |
|
| 3..5 | `port1Stage` | 0 — **первая стадия блока** порта 1 |
|
||||||
| 6..8 | `port2Stage` | 1 |
|
| 6..8 | `port2Stage` | 2 — первая стадия блока порта 2 |
|
||||||
| 9..11 | `port3Stage` → ширина под-стадии | `log2(положений ключа)` = 1 |
|
| 9..11 | `port3Stage` → ширина под-стадии | `log2(положений ключа)` = 1 |
|
||||||
| 12..14 | `port4Stage` | не используется |
|
| 12..14 | `port4Stage` | не используется |
|
||||||
| 15 | `unused2` | не используется |
|
| 15 | `unused2` | не используется |
|
||||||
|
|
||||||
|
Порт-стадия — это **первая стадия блока** порта, а не его индекс. Без под-стадий
|
||||||
|
блок вырождается в одну стадию, и значение совпадает с индексом, то есть со
|
||||||
|
стоковой раскладкой.
|
||||||
|
|
||||||
Поле `port3Stage` переиспользовано под ширину блока под-стадий: двухпортовая
|
Поле `port3Stage` переиспользовано под ширину блока под-стадий: двухпортовая
|
||||||
прошивка его игнорирует, поэтому формат пакета не меняется. **Ноль там —
|
прошивка его игнорирует, поэтому формат пакета не меняется. **Ноль там —
|
||||||
стоковая раскладка**, так что хост с `stimulus_switch_positions = 1` остаётся
|
стоковая раскладка**, так что хост с `stimulus_switch_positions = 1` остаётся
|
||||||
полностью совместим с немодифицированным прибором.
|
полностью совместим с немодифицированным прибором.
|
||||||
|
|
||||||
Слейвам обе порт-стадии выставляются в **7**. Стоковый приём «одна за последней
|
Слейвам обе порт-стадии выставляются в **7** — зарезервированное значение
|
||||||
стадией» здесь не работает: при 4 стадиях старшие биты счётчика принимают только
|
«порт не излучает». Стоковый приём «одна за последней стадией» здесь не работает:
|
||||||
значения 0 и 1, свободного значения не остаётся, и слейв начал бы излучать.
|
при 4 стадиях старшие биты счётчика принимают только значения 0 и 1, свободного
|
||||||
|
значения не остаётся, и слейв начал бы излучать.
|
||||||
|
|
||||||
## FPGA мастера
|
## FPGA мастера
|
||||||
|
|
||||||
Сделано в [`multi_libreVNA_firmware/reproduce/LibreVNA/FPGA/VNA/`](multi_libreVNA_firmware/reproduce/LibreVNA/FPGA/VNA/),
|
Сделано и собрано в
|
||||||
осталось собрать битстрим в ISE.
|
[`multi_libreVNA_firmware/reproduce/LibreVNA/FPGA/VNA/`](multi_libreVNA_firmware/reproduce/LibreVNA/FPGA/VNA/).
|
||||||
|
|
||||||
### `Sweep.vhd`
|
### `Sweep.vhd`
|
||||||
|
|
||||||
Порт включался по точному совпадению, поэтому излучал ровно в одной стадии, и во
|
Порт включался по точному совпадению, поэтому излучал ровно в одной стадии, и во
|
||||||
второй под-стадии зондирующего сигнала просто не было. Сравнение вынесено в
|
второй под-стадии зондирующего сигнала просто не было. Сравнение вынесено в
|
||||||
функцию `port_excites`: младшие `SUBSTAGE_BITS` бит счётчика стадий — положение
|
функцию `port_excites`: младшие `SUBSTAGE_BITS` бит счётчика стадий — положение
|
||||||
ключа, старшие — номер порта. Сдвиг на переменное число бит синтезируется в
|
ключа, и они **маскируются** из сравнения, а старшие биты выбирают порт.
|
||||||
трёхбитный barrel shifter.
|
|
||||||
|
|
||||||
```vhdl
|
```vhdl
|
||||||
if unsigned(port_stage) > shift_right(unsigned(last_stage), to_integer(unsigned(substage_width))) then
|
if port_stage = PORT_STAGE_DISABLED then -- "111", порт не излучает
|
||||||
return false;
|
return false;
|
||||||
end if;
|
end if;
|
||||||
return shift_right(stage, to_integer(unsigned(substage_width))) = unsigned(port_stage);
|
return (std_logic_vector(stage) and compare_mask) = (port_stage and compare_mask);
|
||||||
```
|
```
|
||||||
|
|
||||||
Совместимость со стоком **строгая, а не приблизительная**. При `SUBSTAGE_BITS = 0`
|
Маска декодируется из `SUBSTAGE_BITS` тремя вентилями, причём нераспознанная
|
||||||
сдвиг нулевой и условие вырождается в `stage_cnt = port_stage` плюс проверка
|
ширина даёт все единицы — чтобы неконфигурированный прибор никогда не выродился
|
||||||
`port_stage <= STAGES`. Эта проверка не может ничего изменить: счётчик стадий
|
в «каждый порт излучает в каждой стадии».
|
||||||
пробегает только `0..STAGES`, поэтому при `port_stage > STAGES` совпадения не было
|
|
||||||
бы и так. То есть для всех существующих вызовов поведение идентично — включая
|
|
||||||
ручной режим и анализатор спектра, где `STAGES = 0`.
|
|
||||||
|
|
||||||
Значение выше последней порт-стадии никогда не совпадает — так хост глушит
|
Совместимость со стоком **строгая, а не приблизительная**. При `SUBSTAGE_BITS = 0`
|
||||||
излучение слейвов, посылая им 7. Старый хост слал «одну за последней», это тоже
|
маска все единицы, и выражение становится буквально стоковым
|
||||||
глушит.
|
`stage_cnt = port_stage`. Значит для всех существующих вызовов поведение
|
||||||
|
идентично — включая ручной режим и анализатор спектра, где `STAGES = 0`.
|
||||||
|
|
||||||
|
Значение 7 зарезервировано под «порт выключен»: так хост глушит излучение
|
||||||
|
слейвов. Стоковый хост слал «одну за последней стадией», и это тоже не совпадает
|
||||||
|
ни с одной реальной стадией, так что новый битстрим работает и со старым хостом.
|
||||||
|
|
||||||
### `SPIConfig.vhd` и `top.vhd`
|
### `SPIConfig.vhd` и `top.vhd`
|
||||||
|
|
||||||
@@ -101,6 +107,38 @@ when 6 => STAGES <= spi_buf_out(15 downto 13);
|
|||||||
В `top.vhd` добавлен сигнал `sweep_substage_bits` и проброшен от `SPIConfig` к
|
В `top.vhd` добавлен сигнал `sweep_substage_bits` и проброшен от `SPIConfig` к
|
||||||
`Sweep`.
|
`Sweep`.
|
||||||
|
|
||||||
|
### Почему маска, а не сдвиг
|
||||||
|
|
||||||
|
Первая версия сравнивала `shift_right(stage_cnt, substage_bits)` с номером порта.
|
||||||
|
Функционально верно, но переменный сдвиг синтезируется в barrel shifter, а
|
||||||
|
вызывался он четырежды (по два на порт): **+142 LUT** при всего +3 регистрах.
|
||||||
|
Разводка поехала, и контрольная сборка показала нарушение hold на входе
|
||||||
|
`MCU_MOSI` — на шине, по которой MCU пишет регистры FPGA. Сбой там означал бы
|
||||||
|
неверную конфигурацию развёртки, то есть крайне неприятный в поиске отказ.
|
||||||
|
|
||||||
|
Маска обходится несколькими вентилями и такого эффекта не даёт.
|
||||||
|
|
||||||
|
### Cost table размещателя — обязательно
|
||||||
|
|
||||||
|
Ограничение `MCU_MOSI OFFSET = IN ... BEFORE MCU_SCK` маргинально **уже в стоке**:
|
||||||
|
запас по hold всего +0.458 нс. Поэтому любое изменение нетлиста переставляет
|
||||||
|
размещение и может его опрокинуть. Проверено прямым A/B: сток даёт Timing Score 0,
|
||||||
|
первая версия правки — 1880, версия на маске при cost table 1 — 5480.
|
||||||
|
|
||||||
|
Решается штатно, подбором cost table. В `VNA.xise` зафиксировано:
|
||||||
|
|
||||||
|
```xml
|
||||||
|
<property xil_pn:name="Starting Placer Cost Table (1-100) Map spartan6" xil_pn:value="2" .../>
|
||||||
|
```
|
||||||
|
|
||||||
|
С этим значением **Timing Score 0**, а запас по hold на `MCU_MOSI` даже больше
|
||||||
|
стокового: +0.642 нс против +0.458. Ресурсы: 2302 LUT против 2189 у стока (40%
|
||||||
|
против 38% ёмкости xc6slx9).
|
||||||
|
|
||||||
|
**Не сбрасывайте это свойство в 1.** Если после правок в VHDL тайминг снова
|
||||||
|
поедет — перебирайте cost table дальше (3, 4, 5…) и проверяйте `Timing Score` в
|
||||||
|
`top.par`; сборка каждого варианта около шести минут, синтез при этом кэширован.
|
||||||
|
|
||||||
### Проверка
|
### Проверка
|
||||||
|
|
||||||
Рядом лежит самопроверяющийся тестбенч `Test_Sweep.vhd` на четыре сценария: сток,
|
Рядом лежит самопроверяющийся тестбенч `Test_Sweep.vhd` на четыре сценария: сток,
|
||||||
@@ -112,8 +150,10 @@ when 6 => STAGES <= spi_buf_out(15 downto 13);
|
|||||||
ghdl -a --std=93 Sweep.vhd Test_Sweep.vhd && ghdl -r --std=93 Test_Sweep
|
ghdl -a --std=93 Sweep.vhd Test_Sweep.vhd && ghdl -r --std=93 Test_Sweep
|
||||||
```
|
```
|
||||||
|
|
||||||
Тест проверен мутацией: если вернуть стоковое точное сравнение, сценарии с
|
Тест проверен мутацией: если выбросить маску из сравнения, сценарии с
|
||||||
под-стадиями падают, а стоковый продолжает проходить.
|
под-стадиями падают (8 сработавших проверок), а стоковый продолжает проходить.
|
||||||
|
|
||||||
|
VHDL держите в чистом ASCII: GHDL отвергает не-ASCII символы даже в комментариях.
|
||||||
|
|
||||||
## Прошивка STM32 LibreVNA
|
## Прошивка STM32 LibreVNA
|
||||||
|
|
||||||
@@ -136,8 +176,6 @@ FPGA::SetupSweep(s.stages, s.port1Stage, s.port2Stage, s.syncMode != 0,
|
|||||||
```
|
```
|
||||||
|
|
||||||
Собирать так же, как описано в [`reproduce/README.md`](multi_libreVNA_firmware/reproduce/README.md).
|
Собирать так же, как описано в [`reproduce/README.md`](multi_libreVNA_firmware/reproduce/README.md).
|
||||||
Отдельно: битстрим мастера единственный в своём роде, `top.bin` перезаписывается
|
|
||||||
каждой сборкой ISE — переименовывать сразу.
|
|
||||||
|
|
||||||
## Контроллер ключа (отдельный STM32)
|
## Контроллер ключа (отдельный STM32)
|
||||||
|
|
||||||
@@ -188,13 +226,36 @@ STM32 прибора в Hi-Z на обеих линиях (`GPIO_MODE_INPUT`, `N
|
|||||||
|
|
||||||
### 1. Битстрим FPGA мастера (Xilinx ISE 14.7)
|
### 1. Битстрим FPGA мастера (Xilinx ISE 14.7)
|
||||||
|
|
||||||
|
**Уже собран.** Лежит в `FPGA/VNA/top_master_per_point_switching.bin`,
|
||||||
|
sha256 `e184eb92bef1c698849511845fa8d754…`, Timing Score 0. Пересобирать нужно
|
||||||
|
только после правок в VHDL.
|
||||||
|
|
||||||
|
Имя отдельное намеренно: `top_master.bin` оставлен нетронутым — это одна из двух
|
||||||
|
копий невосстановимого битстрима, из которого собран текущий `combined.vnafw`
|
||||||
|
(вторая — `extracted/master_fpga.bin`). Заменить его новым стоит только после
|
||||||
|
проверки на железе.
|
||||||
|
|
||||||
|
Как собрать заново — в GUI:
|
||||||
|
|
||||||
1. Скопировать [`multi_libreVNA_firmware/reproduce/LibreVNA/FPGA`](multi_libreVNA_firmware/reproduce/LibreVNA/FPGA)
|
1. Скопировать [`multi_libreVNA_firmware/reproduce/LibreVNA/FPGA`](multi_libreVNA_firmware/reproduce/LibreVNA/FPGA)
|
||||||
в общую папку виртуалки (`C:\shared\LibreVNA\FPGA`).
|
в общую папку виртуалки (`C:\shared\LibreVNA\FPGA`).
|
||||||
2. Открыть **`VNA.xise`** — проект мастера. Не `VNA_external_lo_slave.xise`.
|
2. Открыть **`VNA.xise`** — проект мастера. Не `VNA_external_lo_slave.xise`.
|
||||||
3. Process → **Generate Programming File**.
|
3. Process → **Generate Programming File**.
|
||||||
4. Забрать `top.bin` **сразу** и переименовать в `top_master.bin`: оба проекта
|
4. Забрать `top.bin` **сразу** и переименовать в
|
||||||
|
`top_master_per_point_switching.bin`: оба проекта
|
||||||
пишут в один и тот же файл, и следующая сборка его затрёт. Именно так был
|
пишут в один и тот же файл, и следующая сборка его затрёт. Именно так был
|
||||||
потерян исходный мастер-битстрим.
|
потерян исходный мастер-битстрим.
|
||||||
|
5. Проверить `Timing Score` в `top.par` — должен быть 0 (см. про cost table выше).
|
||||||
|
|
||||||
|
Или из командной строки в госте, без GUI:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd ~/shared/LibreVNA/FPGA/VNA # лучше скопировать на локальный диск: vboxsf медленная
|
||||||
|
source /opt/Xilinx/14.7/ISE_DS/settings64.sh
|
||||||
|
printf 'project open VNA.xise\nprocess run "Generate Programming File"\nproject close\n' > /tmp/bit.tcl
|
||||||
|
xtclsh /tmp/bit.tcl
|
||||||
|
grep "Timing Score" top.par
|
||||||
|
```
|
||||||
|
|
||||||
Битстрим невоспроизводим побайтово (place & route недетерминирован плюс
|
Битстрим невоспроизводим побайтово (place & route недетерминирован плюс
|
||||||
timestamp внутри), так что новый файл будет отличаться от старого при любом
|
timestamp внутри), так что новый файл будет отличаться от старого при любом
|
||||||
@@ -215,7 +276,7 @@ make BINPATH="<путь к arm-none-eabi из CubeIDE>/tools/bin" -j4
|
|||||||
```bash
|
```bash
|
||||||
cd multi_libreVNA_firmware/reproduce/LibreVNA
|
cd multi_libreVNA_firmware/reproduce/LibreVNA
|
||||||
python3 AssembleFirmware.py \
|
python3 AssembleFirmware.py \
|
||||||
--bitstream FPGA/VNA/top_master.bin \
|
--bitstream FPGA/VNA/top_master_per_point_switching.bin \
|
||||||
--mcu Software/VNA_embedded/build/VNA_embedded.bin \
|
--mcu Software/VNA_embedded/build/VNA_embedded.bin \
|
||||||
--output ../combined_per_point_switching.vnafw
|
--output ../combined_per_point_switching.vnafw
|
||||||
```
|
```
|
||||||
|
|||||||
Reference in New Issue
Block a user