Jump to content

    

dxp

Свой
  • Content Count

    4237
  • Joined

  • Last visited

Community Reputation

0 Обычный

4 Followers

About dxp

  • Rank
    Adept

Информация

  • Город
    Array

Recent Profile Visitors

10428 profile views
  1. Т.е. если скрипт рожает то, что надо, следовательно он подтаскивает внутри всё, что требуется. Посмотрите, какие команды он там применяет. Чтобы восстановить вид, надо кроме этого тикля ещё ui файлик сохранять, в нём layout и хранится, насколько помню.
  2. Всё же не понятен такой момент. Вот если вы нарисуете руками и отредактируете всё, что нужно, то если теперь сохранить этот BD в Tcl скрипт (через экспорт), потом удалить BD из проекта, и, наконец, запустить сохранённый скрипт из консоли, оно родит корректно всё то же самое, что вы руками сделали?
  3. Хотите сказать, что действие, выполненное через GUI, не выполняется с помощью команды, которую же сама Vivado генерит на это действие?
  4. А вы возьмите откатите сделанное в GUI действие. И запустите эту команду из консоли. Что произойдёт с интерконнектом?
  5. Опытные люди тут на форуме объяснили, что cells в BD не параметризуются снаружи, т.е. тут автоматизации не достичь. Поэтому только через Tcl. BD ж по сути Tcl и есть, просто в графическом виде. Ну, строго говоря, там внутреннее описание не Tcl (раньше было XML, сейчас JSON), но суть та же: используется некий язык для описания параметров и межсоединений. Зато в Tcl можно экспортировать и потом запуском Tcl скрипта создать весь BD. Собственно, это вышеприведённый скрипт и делает. У меня он запускается на этапе создания проекта. У нас подход такой, что проекты (xpr) ценности не представляют и являются продуктом, которые генерирует система сборки исходя из заданных параметров. Вот на этом этапе этот скрипт и запускает в качестве хука для скрипта создания проекта. Что касается то после этого действия вы увидите в консоли Вивады тиклевую команду, которая выполнила это действие. Вот эту команду и добавить в скрипт (или если она там есть, но с другими параметрами, то подкорректировать эти параметры). Т.е. по сути выполнить действие через GUI IPI с целью подсмотреть, как это действие выполнить командой. И перенести после этого в скрипт. Так скрипт будет всегда делать автоматически все нужные действия. Для проверки правильности можно просто удалить из проекта BD и запустить скрипт из консоли. Он должен будет родить BD заново. После этого проверить правильность через тот же GUI IPI. Но это нечасто приходится делать - обычно структура BD как-то на первых этапах уже "кристаллизуется", потом уже только параметры меняются. А это легко передаётся в Tcl скрипт через включаемые файлы. А чтобы не забывать пересоздать BD при изменении влияющего параметра служит как раз система сборки, которая отслеживает зависимости - например, изменился параметр, который влияет на BD в том числе, - и собирает все нужные цели. Если при этом надо пересоздать проект, то и это делается (это ненакладная цель - 6-7 секунд на это уходит на моей не самой быстрой машине). Таким образом, если не надо менять структуру (наличие тех или иных cell'ов и их межсоединения), то править скрипт BD не приходится. Всё пересобирается автоматом.
  6. Боюсь, что именно так: "бросил на канвас и всё завертелось" не получится. Рисование BD в GUI есть операция ручная. И все действия там ручные. В противоположность скрипты, будучи запущенными, всё делают без вмешательства. Но там и описание получается текстом (местами малочитебельным). Насколько понял, вы имеете в виду подход через IP Integrator. Если речь только про IP ядра, которые можно традиционно инстанцировать в HDL, там рам всё проще: сгенерил из скрипта корку и всё. Параметры корки скрипту передать. А с IP Integrator процесс несколько иной. Я делаю так: исходно рисуется BD, экспортируется Tcl скрипт, из которого выдираю непосредственно описание инстансов и межсоединений (оно там ближе к концу компактно лежит). Далее это помещаю в свой скрипт-шаблон между прологом и эпилогом, получается нечто такое: #================================================================================ # # Prologue # source $BUILD_SRC_DIR/cfg_params.tcl source $BUILD_SRC_DIR/impl_env.tcl set bd_name noc_slon set bd_path "${PROJECT_NAME}.srcs/sources_1/bd/${bd_name}/${bd_name}.bd" set cips_name versal_cips_mamont puts "\n======== Create block design \"$bd_name\" ========" create_bd_design "${bd_name}" update_compile_order -fileset sources_1 open_bd_design ${bd_path} #------------------------------------------------------------------------------- # # BD Configuration Section # create_bd_cell -type ip -vlnv xilinx.com:ip:versal_cips:3.1 ${cips_name} set_property -dict [ \ list CONFIG.PS_PMC_CONFIG " \ PMC_REF_CLK_FREQMHZ ${PMC_REF_CLK} \ PS_NUM_FABRIC_RESETS 0 \ PS_USE_PMCPL_CLK0 0 \ PS_USE_PMCPL_CLK1 0 \ PS_USE_PMCPL_CLK2 0 \ PS_USE_PMCPL_CLK3 0 \ SMON_ALARMS Set_Alarms_On \ SMON_ENABLE_TEMP_AVERAGING 0 \ SMON_TEMP_AVERAGING_SAMPLES 8 \ " \ CONFIG.PS_PMC_CONFIG_APPLIED {1} \ ] \ [get_bd_cells ${cips_name}] apply_bd_automation -rule xilinx.com:bd_rule:cips -config { \ board_preset {No} \ boot_config {Custom} \ configure_noc {Add new AXI NoC} \ debug_config {Custom} \ design_flow {Full System} \ mc_type {None} \ num_mc {1} \ pl_clocks {None} \ pl_resets {None} \ } \ [get_bd_cells ${cips_name}] # Create interface ports set CH0_DDR4_0_0 [ create_bd_intf_port -mode Master -vlnv xilinx.com:interface:ddr4_rtl:1.0 CH0_DDR4_0_0 ] set S00_AXI [ create_bd_intf_port -mode Slave -vlnv xilinx.com:interface:aximm_rtl:1.0 S00_AXI ] set_property -dict [ list \ CONFIG.ADDR_WIDTH {64} \ CONFIG.ARUSER_WIDTH {0} \ <...> CONFIG.WUSER_BITS_PER_BYTE {1} \ CONFIG.WUSER_WIDTH {0} \ ] $S00_AXI set sys_clk0_0 [ create_bd_intf_port -mode Slave -vlnv xilinx.com:interface:diff_clock_rtl:1.0 sys_clk0_0 ] set_property -dict [ list \ CONFIG.FREQ_HZ {200000000} \ ] $sys_clk0_0 # Create ports set clk [ create_bd_port -dir I -type clk -freq_hz 250000000 clk ] set_property -dict [ list \ CONFIG.ASSOCIATED_BUSIF {S00_AXI} \ ] $clk # Create instance: axi_noc_0, and set properties set axi_noc_0 [ create_bd_cell -type ip -vlnv xilinx.com:ip:axi_noc:1.0 axi_noc_0 ] set_property -dict [ list \ CONFIG.LOGO_FILE {data/noc_mc.png} \ CONFIG.CONTROLLERTYPE {DDR4_SDRAM} \ <...> CONFIG.MC_EN_ECC_SCRUBBING {false} \ CONFIG.MC_INIT_MEM_USING_ECC_SCRUB {false} \ ] $axi_noc_0 set_property -dict [ list \ #CONFIG.DATA_WIDTH {64} \ #CONFIG.CONNECTIONS {MC_0 { read_bw {1720} write_bw {1720} read_avg_burst {4} write_avg_burst {4}} } \ CONFIG.CONNECTIONS {MC_0 { read_bw {12500} write_bw {12500} read_avg_burst {4} write_avg_burst {4}} } \ CONFIG.CATEGORY {pl} \ ] [get_bd_intf_pins /axi_noc_0/S00_AXI] set_property -dict [ list \ CONFIG.ASSOCIATED_BUSIF {S00_AXI} \ ] [get_bd_pins /axi_noc_0/aclk0] # Create interface connections connect_bd_intf_net -intf_net S00_AXI_1 [get_bd_intf_ports S00_AXI] [get_bd_intf_pins axi_noc_0/S00_AXI] connect_bd_intf_net -intf_net axi_noc_0_CH0_DDR4_0 [get_bd_intf_ports CH0_DDR4_0_0] [get_bd_intf_pins axi_noc_0/CH0_DDR4_0] connect_bd_intf_net -intf_net sys_clk0_0_1 [get_bd_intf_ports sys_clk0_0] [get_bd_intf_pins axi_noc_0/sys_clk0] # Create port connections connect_bd_net -net clk_1 [get_bd_ports clk] [get_bd_pins axi_noc_0/aclk0] # Create address segments assign_bd_address -offset 0x00000000 -range 0x80000000 -target_address_space [get_bd_addr_spaces noc_tg/Data] [get_bd_addr_segs axi_noc_0/S00_AXI/C0_DDR_LOW0] -force #================================================================================ # # Epilogue # #------------------------------------------------------------------------------- # # BD Final Tasks Section # validate_bd_design make_wrapper -files [get_files ${bd_path}] -top add_files -norecurse ${PROJECT_NAME}.gen/sources_1/bd/${bd_name}/hdl/${bd_name}_wrapper.v update_compile_order -fileset sources_1 puts "\n-------- Export simulation for \"$bd_name\" --------" set sim_top_name [get_property top [get_filesets sim_1]] set_property top ${bd_name}_wrapper [get_filesets sim_1] generate_target simulation [get_files ${bd_path}] -force export_simulation -of_objects [get_files ${bd_path}] -simulator questa -absolute_path -force -directory ${SIM_SCRIPT_DIR} set_property top $sim_top_name [get_filesets sim_1] #-------------------------------------------------------------------------------- И уже в этом скрипте правлю по месту то, что надо. Управляющие параметры передаются через подключаемые файлы. С этого момента данный скрипт является основным для BD - если что-то надо подправить на уровне GUI интегратора, то делаю это в GUI и смотрю, какую команду Vivado выдаёт в консоль. Добавляю (или меняю) это в этом скрипте. Но чаще всего достаточно поправить прямо в тексте. После генерирования BD в GUI интегратора всё это легко проверяется. Автоматизация достигается сама собой, а параметризация через внешние файлы. Вся эта кухня управляется системой сборки, дабы автоматизировать генерирование скриптов и запуск инструментов по зависимостям (например, при изменении каких-либо параметров), но можно и руками запускать или из пакетного файла.
  7. Вы заметили, что я вам не отвечал? Я давно принял для себя правило, не вступать с отдельными персонажами в дискуссии, ибо это бесполезно и неприятно. В данном случае я сплоховал - забыл, что вы из этого списка (давно уже не имел с вами дел). Все ваши выступления тут как обычно на тему "какой я крутой, продвинутый, прокачанный, опытный и всё знающий, а вы куда лезете со свиным рылом в калашный ряд со своими горбатыми предложениями - это ж костыли, костыли" - отсюда и подробные и не нужные пояснения, как и что работает с мутексами (и без вас это всё известно). Решение с отдельным процессом эффективное (быстрое и дешёвое в смысле накладных расходов) и элегантное. Не универсальное как и всё на свете. Не устраивает оно вас, ну достаточно сказать, мне не нравится этот подход потому-то и потому-то. А обзывая это костылями вы показываете свой истинный уровень. Никогда не пользовался игнор-списком, но в данном случае сделаю исключение.
  8. У нас парк осциллографов насчитывает с полдюжины LeCroy'ев. Со встроенными компами (по здешней терминологии "взрослых") штук пять (WaveRunner 2 шт., WaveSurfer 3 шт). WR были ещё в 2006-м году приобретены. Один из них я апгдейдил (проц и память). Из всех них сломалось только в одном - конденсатор в источнике питания сдох, заменили его своими силами, работает по сей день. Кроме того, было приобретено позже ещё пара WafeSurver, у которых уже не было выделенного доступа в встроенному компу (там линукс ембеддед какой-то), комп этот просто GUI обеспечивает. Из этих один поломался. Т.ч. по надёжности я бы не сказал, что встроенный полноценный комп как-то на это влияет. Тут скорее похоже на ситуацию с автомобилями: современные автомобили дорогие и одноразовые. И похоже, что это относится не только к этим сферам - общая тенденция: снижение качества, запрограммированный "износ".
  9. Что значит "занял устройство"? Смысл ведь вынести работу с общим ресурсом (в том числе и если это пусть устройство) в отдельный поток с нужным приоритетом. Вот пусть этот поток и "занимает устройство". Выглядит так: поток 8 хочет что-то сделать с устройством, сам к нему не лезет, а просто кидает в очередь, которую слушает поток 1, задание (адрес объекта). Да, поток 3 будет ждать по-любому, но это будет точно так же и в случае с инверсией приоритетов. Смысл инверсии приоритетов не в том, чтобы поток 3 мог отобрать доступ у потока 8 (это по логике задачи невозможно и не нужно), а в том, чтобы, например, поток 5 не вытеснил поток 8 на непонятное время, тормозя тем самым более приоритетный поток 3. Именно эту задачу решает инверсия приоритетов: поток 3 даёт временно поработать потоку 8 на своём приоритете, чтобы никакой поток с более низким, чем 3, приоритетом не мог вмешаться, чтобы модель приоритетного вытеснения (всегда работает наиболее приоритетный поток из готовых к выполнению) соблюдалась. В любом случае имеет место схема: "высокоприоритетный поток выполняет какую-то работу низкоприоритетного". В случае инверсии приоритетов высокоприоритетный пускает поработать низкоприоритетный "на своём рабочем месте", а в случае очереди заданий низкоприоритетный "попросил" другой высокоприоритетный поток сделать эту работу. Какой способ лучше, определяется "ценой вопроса". Если потоки дорогие и тяжёлые, а колбасить потороха оси на этом фоне необременительно, что инверсия приоритетов вполне. Если потоки дёшевы, то наоборот. В случае простых, лёгких RTOS очевидно второй вариант в выигрыше. По коду там несколько строк. Работает это очень быстро. Код прозрачный. Легко переносится из проекта в проект (у меня в любом проекте есть всегда фоновый процесс, который и выполняет всякие такие несрочные, но затратные вычислительно задания, а в некоторых есть и foreground процесс - как раз для срочных дел). Это никакие не костыли, а очень простой, красивый и эффективный паттерн проектирования. Как раз инверсия приоритетов с перетряхиванием в потрохах RTOS кучи всего, не имеющего непосредственного отношения к рассматриваемому контексту "на всякий случай" - чтобы обеспечить корректность во всех кейсах, и выглядит натуральными костылями.
  10. именно потому что Мутексы с инверсией приоритетов подходят для толстых осей, где накладные и так большие, на их фоне пробег про объектам оси с целью корректного изменения приоритетов выглядит не так затратно. Для мелких осей накладные соизмеримы или больше затрат на непосредственную работу с объектом блокировки. Задача легко решается без таких мутексов путём "делегирования" работы потоку с достаточно высоким приоритетом. Например, к объекту лезут два потока с приоритетами 3 и 8 (меньше - выше приоритет), чтобы поток с приоритетом 8 не блокировал работу потока с приоритетом 3, можно работу с объектом в потоке 8 реализовать в отдельной функции, указатель на которую метнуть в очередь специального foreground потока с приоритетом, например 1. На простой иерархии классов с виртуальными функциями получается очень просто и эффективно: заводится абстрактный базовый класс TJob, от него рожается сколько надо производных классов-заданий, при постановке задания в очередь, которую читает поток с приоритетом 1, кидается указатель на объект-задание. Точно так же реализуется обработка фоновых заданий: если есть затратные по времени, но не приоритетные задачи (какие-нить вычисления длительные), потоки не выполняют их в своём цикле, а скидывают в очередь низкоприоритетного потока. Тут на стр. 125 подробно описано с примером.
  11. Токен - широкий термин. Гитхаб имеет в виду нечто конкретное. Я не вникал во внутреннюю механику, тупо сделал по инструкции, много времени не заняло. Вроде по этой: https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/creating-a-personal-access-token Далее надо положить логин и токен (вместо пароля) как обычно в .git-credentials, чтобы гит каждый раз не спрашивал реквизиты доступа.
  12. Опередили: тоже хотел пример с функцией в always @* привести. Ещё одно важное отличие: в начальный момент (момент времени 0) always_comb всегда делает единоразовый прогон, хотя его переменные ещё не триггернулись - это соответствует поведению аппаратной логики. always @* будет ждать триггера. Если, например, есть два блока, которые влияют на триггеринг друг друга, то они будут стоят и ждать, кто первый пнёт. Это тоже не соответствует поведению логики на синтезе. Ну, и третье заметное отличие в том, что в always @* допускается писать в переменную из разных блоков, а в always_comb нет. Конечно, на синтезе эта ошибка проявится, но лучше, когда это ловится раньше. Поэтому синтезируемый код, предназначенный для описания комбинационной логики, однозначно целесообразнее писать с использованием always_comb. Его именно для этого и ввели в язык.
  13. +1. При правильном подходе (адекватных моделях и грамотном описании) отладка в железе может понадобиться в основном потому, что на симе не удаётся сымитировать все кейсы, которые реально имеют место быть.
  14. github.com при соединении git по https перешёл со схемы "логин:пароль" на схему "логин:токен". Токен - это наподобие пароля, но намного более длинная и замороченная штука, и работает, насколько я понял, не как пароль, а скорее как ключ шифрования. Как его сгенерить, есть инструкция. Я себе сделал. SSH хороший вариант, но не везде работает - 22-й порт может быть закрыт по соображениям безопасности. https более универсальный. github.com рекомендует https.
  15. Ну, если не нужно, то не нужно, я ж не настаиваю. :) Возражение было только на тему, что чтение (конечно, произвольных транзакций, т.е. с произвольных адресов и произвольной длины и на максимальной скорости) - это просто. Это, увы, совсем не просто. Особенно, когда при широком слове (16 байт и более) принимать CplD с RCB 64, когда они там прилетают от 1 до 64, а также 128 или 256, и это непредсказуемо. И когда нужно сдвигать 32-битные слова (при пересечении границ 4к) и байты (когда адрес не кратен 32-разрядному слову). И всё это на потоке в реальном времени на высокой скорости. Да, всё реализуемо, но потребовало прилично времени и усилий. Доступ к регистрам у нас тоже ординарный 32-разрядный, сделан через самодельный мост TLP-AXI4-Lite. По чтению и по записи. Это и в самом деле достаточно тривиально. И просто запись в хостовую память по выровненным адресам и без пересечения границ страниц тоже реализуется достаточно несложно. Накладных там минимум, проводил тесты на скорость, заливал 4 МБ буфер, скорость получалась 14.5 Gbps (Gen2 x4, MPS - 256 байт). Хорошо, когда есть возможность выбирать условия передачи. В прикладном проекте, к сожалению, такой возможности нет (адреса и длины произвольные).