Добавление testbench'ей на языке Verilog в проект Vivado — различия между версиями
Korogodin (обсуждение | вклад) (→Добавление TB'а через скрипт регенерации проекта) |
Dneprov D (обсуждение | вклад) (→Ссылки) |
||
(не показаны 30 промежуточных версий 3 участников) | |||
Строка 1: | Строка 1: | ||
{{TOCright}} | {{TOCright}} | ||
− | Пусть у нас есть дизайн для Vivado, проект которого разворачивается в соответствии со статьей [[Vivado и Git]]. | + | Пусть у нас есть дизайн для Vivado, проект которого разворачивается в соответствии со статьей [[Vivado и Git]]. Это может быть как конечный дизайн, так и чей-то сабмодуль. Процедура добавления test bench'ей (далее TB) отличаться не будет, поэтому рассмотрим всё на примере сабмодуля '''imitator'''. |
− | '''Задача''' - добавить TB'и для модулей | + | '''Задача''' - добавить TB'и для модулей дизайна, причем |
* они должны храниться в СКВ и быть доступны всем разработчикам, | * они должны храниться в СКВ и быть доступны всем разработчикам, | ||
* имеются в виду TB'и на языке Verilog для симуляторов типа Vivado Simulator, ModelSim и т.д., а не тесты на языках Си или Matlab для Verilator'а. | * имеются в виду TB'и на языке Verilog для симуляторов типа Vivado Simulator, ModelSim и т.д., а не тесты на языках Си или Matlab для Verilator'а. | ||
Строка 16: | Строка 16: | ||
− | Наша конечная цель - правильно написанный скрипт регенерации проекта, включающий раскладывание TB'ей по полочкам | + | [[file:20160404_KDPV.gif|thumb|right|400px]] |
− | * средствами GUI создать новый набор для моделирования ( | + | |
+ | Наша конечная цель - файлы TB'ей и правильно написанный скрипт регенерации проекта, включающий раскладывание TB'ей по полочкам. Будем считать, что пользователь по-максимуму хочет использовать GUI и по-минимуму консоль и TCL. Тогда вырисовывается следующий workflow: | ||
+ | * средствами GUI создать новый набор файлов для моделирования (включающий код TB'а, тестируемые модули и т.п.), | ||
* через GUI настроить этот набор, | * через GUI настроить этот набор, | ||
* через GUI выгрузить код регенерации, | * через GUI выгрузить код регенерации, | ||
− | * подправить | + | * подправить существующий скрипт регенерации проекта так, чтобы TB'и разворачивались и настраивался вместе с проектом. |
Строка 27: | Строка 29: | ||
=== Создание нового набора для симуляции === | === Создание нового набора для симуляции === | ||
− | + | Создадим через GUI новый TB, а потом перенесем его в tcl-скрипт! Начнем с TB для модуля '''imichnl_synthesizer'''. | |
В ''Flow Navigator'' (это панель слева в Vivado) в разделе ''Simulation'' выбираем ''Simulation Settings'' | В ''Flow Navigator'' (это панель слева в Vivado) в разделе ''Simulation'' выбираем ''Simulation Settings'' | ||
Строка 70: | Строка 72: | ||
=== Код TB'а === | === Код TB'а === | ||
− | Пришло время наполнить imichnl_synthesizer_tb смысловым содержанием. Общий сброс, после чего каждую эпоху PHASE_RATE увеличивается на | + | Пришло время наполнить imichnl_synthesizer_tb смысловым содержанием. Общий сброс, после чего каждую эпоху PHASE_RATE увеличивается на 500: |
{{Hider|title = imichnl_synthesizer_tb.v | {{Hider|title = imichnl_synthesizer_tb.v | ||
|content = <source lang="verilog"> | |content = <source lang="verilog"> | ||
− | `timescale | + | `timescale 100ps / 1ps |
module imichnl_synthesizer_tb(); | module imichnl_synthesizer_tb(); | ||
Строка 116: | Строка 118: | ||
end | end | ||
− | always | + | always // 105.6 MHz |
− | # | + | #47 pclk = !pclk; |
event reset; | event reset; | ||
Строка 152: | Строка 154: | ||
end | end | ||
end | end | ||
+ | |||
+ | initial begin | ||
+ | forever begin | ||
+ | #10000500 -> epoch; | ||
+ | end | ||
+ | end | ||
+ | |||
+ | initial begin | ||
+ | #2000000 | ||
+ | forever begin | ||
+ | #10000000 -> fix; | ||
+ | end | ||
+ | end | ||
initial begin: TEST_CASE | initial begin: TEST_CASE | ||
#10 -> reset; | #10 -> reset; | ||
− | + | forever begin | |
− | + | #3000000 | |
− | + | phase_rate = phase_rate + 500; | |
− | + | @ (epoch); | |
− | + | end | |
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
end | end | ||
Строка 178: | Строка 188: | ||
Моделируем, настраиваем wave-форму | Моделируем, настраиваем wave-форму | ||
− | [[file: | + | [[file:20160404_vivado_revolution20.png|center]] |
Cохраняем настройки wave-формы в '''каталог tb''' через меню ''File->Save Waveform Configuration'', автоматом получая имя файла типа '''imichnl_synthesizer_tb_behav.wcfg''' | Cохраняем настройки wave-формы в '''каталог tb''' через меню ''File->Save Waveform Configuration'', автоматом получая имя файла типа '''imichnl_synthesizer_tb_behav.wcfg''' | ||
− | |||
== Добавление TB'а через скрипт регенерации проекта == | == Добавление TB'а через скрипт регенерации проекта == | ||
Сейчас все настройки TB'а, т.е. файлсета sim_imichnl_synthesizer, хранятся в песочнице, которая у нас не находится под системой контроля версий. Нужно добавить соответствующий код в скрипт регенерации проекта (традиционно его место до объявления настроек синтеза synth_1) | Сейчас все настройки TB'а, т.е. файлсета sim_imichnl_synthesizer, хранятся в песочнице, которая у нас не находится под системой контроля версий. Нужно добавить соответствующий код в скрипт регенерации проекта (традиционно его место до объявления настроек синтеза synth_1) | ||
− | {{Hider|title = Вставка в prj_imitator.tcl | + | {{Hider|title = Вставка в prj_imitator.tcl для регенерации sim_imichnl_synthesizer |
|content = <source lang="tcl"> | |content = <source lang="tcl"> | ||
# =============== imichnl_synthesizer module test bench ==================== | # =============== imichnl_synthesizer module test bench ==================== | ||
Строка 217: | Строка 226: | ||
Как я получил этот код? Я просто выгрузил через ''File -> Write Project Tcl'' новый скрипт регенерации проекта и вычленил из него блок, отвечающий за наш новый файлсет. | Как я получил этот код? Я просто выгрузил через ''File -> Write Project Tcl'' новый скрипт регенерации проекта и вычленил из него блок, отвечающий за наш новый файлсет. | ||
− | Ниже мы подробнее рассмотрим команды, используемые для регенерации TB'а. | + | Ниже мы подробнее рассмотрим команды, используемые для регенерации TB'а. Сделаем мы это на примере второго TB'а, т.к. он немного сложнее. |
== Добавляем второй TB == | == Добавляем второй TB == | ||
+ | |||
+ | Проделываем аналогичные действия для второго TB'а, получаем набор для моделирования sim_imitator_channel, включающий, помимо прочего, imitator_channel_tb.v. | ||
+ | {{Hider|title = imitator_channel_tb.v | ||
+ | |content = <source lang="tcl"> | ||
+ | `timescale 100ps / 1ps | ||
+ | |||
+ | `include "global_param.v" | ||
+ | `include "imichnl_param.v" | ||
+ | |||
+ | module imitator_channel_tb(); | ||
+ | |||
+ | parameter BASE_ADDR = `ADDR_WIDTH'h8000; | ||
+ | |||
+ | // [in] | ||
+ | reg clk; | ||
+ | reg pclk; | ||
+ | reg reset_n; | ||
+ | reg wr_en; | ||
+ | reg rd_en; | ||
+ | reg [`ADDR_WIDTH - 1 : 0] reg_addr; | ||
+ | reg [31 : 0] wdata; | ||
+ | reg intr_pulse; | ||
+ | reg fix_pulse; | ||
+ | |||
+ | // [out] | ||
+ | wire [31 : 0] rdata; | ||
+ | wire [`IMI_CHNLOUTWIDTH - 1 : 0] i_ch; // Синфазная компонента i-го канала | ||
+ | wire [`IMI_CHNLOUTWIDTH - 1 : 0] q_ch; // Квадратурная компонента i-го канала | ||
+ | |||
+ | `define chNum 0 | ||
+ | imitator_channel | ||
+ | #(BASE_ADDR + (`chNum << 6)) IMI_CH ( | ||
+ | .clk (clk), // In | ||
+ | .pclk (pclk), | ||
+ | .reset_n (reset_n), | ||
+ | .wr_en (wr_en), | ||
+ | .rd_en (rd_en), | ||
+ | .reg_addr (reg_addr), | ||
+ | .wdata (wdata), | ||
+ | .intr_pulse (intr_pulse), | ||
+ | .fix_pulse (fix_pulse), | ||
+ | .rdata (rdata), // Out | ||
+ | .i (i_ch), | ||
+ | .q (q_ch) | ||
+ | ); | ||
+ | |||
+ | initial begin | ||
+ | clk = 0; | ||
+ | pclk = 0; | ||
+ | reset_n = 1; | ||
+ | wr_en = 0; | ||
+ | rd_en = 0; | ||
+ | reg_addr = 0; | ||
+ | wdata = 0; | ||
+ | intr_pulse = 0; | ||
+ | fix_pulse = 0; | ||
+ | end | ||
+ | |||
+ | always // 105.6 MHz | ||
+ | #47 pclk = !pclk; | ||
+ | |||
+ | always // 60 MHz | ||
+ | #83 clk = !clk; | ||
+ | |||
+ | event reset; | ||
+ | event irq; | ||
+ | event fix; | ||
+ | |||
+ | event write; | ||
+ | event writeDone; | ||
+ | event read; | ||
+ | event readDone; | ||
+ | |||
+ | initial begin | ||
+ | forever begin | ||
+ | @ (reset) | ||
+ | @ (negedge pclk) | ||
+ | reset_n = 0; | ||
+ | @ (negedge pclk) | ||
+ | reset_n = 1; | ||
+ | end | ||
+ | end | ||
+ | |||
+ | initial begin | ||
+ | forever begin | ||
+ | @ (irq) | ||
+ | @ (negedge pclk) | ||
+ | intr_pulse = 1; | ||
+ | @ (negedge pclk) | ||
+ | intr_pulse = 0; | ||
+ | end | ||
+ | end | ||
+ | |||
+ | initial begin | ||
+ | forever begin | ||
+ | @ (fix) | ||
+ | @ (negedge pclk) | ||
+ | fix_pulse = 1; | ||
+ | @ (negedge pclk) | ||
+ | fix_pulse = 0; | ||
+ | end | ||
+ | end | ||
+ | |||
+ | initial begin | ||
+ | fork // Распараллеливание блоков | ||
+ | forever begin | ||
+ | #6000000 -> irq; | ||
+ | end | ||
+ | forever begin | ||
+ | #10000000 -> fix; | ||
+ | end | ||
+ | join | ||
+ | end | ||
+ | |||
+ | initial begin | ||
+ | forever begin | ||
+ | @ (write) | ||
+ | @ (negedge clk) | ||
+ | wr_en = 1; | ||
+ | @ (negedge clk) | ||
+ | @ (negedge clk) | ||
+ | @ (negedge clk) | ||
+ | wr_en = 0; | ||
+ | -> writeDone; | ||
+ | end | ||
+ | end | ||
+ | |||
+ | initial begin | ||
+ | forever begin | ||
+ | @ (read) | ||
+ | @ (negedge clk) | ||
+ | rd_en = 1; | ||
+ | @ (negedge clk) | ||
+ | @ (negedge clk) | ||
+ | @ (negedge clk) | ||
+ | rd_en = 0; | ||
+ | -> readDone; | ||
+ | end | ||
+ | end | ||
+ | |||
+ | initial begin: TEST_CASE | ||
+ | #10 -> reset; | ||
+ | |||
+ | #500 | ||
+ | |||
+ | // Write PHASE_RATE | ||
+ | reg_addr = (`chNum << 6) + `PHASE_RATE_OFFSET; | ||
+ | wdata = 32'd1000000; | ||
+ | -> write; | ||
+ | @ (writeDone); | ||
+ | |||
+ | // Configure GLONASS ST | ||
+ | reg_addr = (`chNum << 6) + `CODE_STATE1_OFFSET; | ||
+ | wdata = 32'hFFFFFFFF; | ||
+ | -> write; | ||
+ | @ (writeDone); | ||
+ | |||
+ | reg_addr = (`chNum << 6) + `CODE_BITMASK1_OFFSET; | ||
+ | wdata = 32'h08800000; | ||
+ | -> write; | ||
+ | @ (writeDone); | ||
+ | |||
+ | reg_addr = (`chNum << 6) + `CODE_OUT_BITMASK1_OFFSET; | ||
+ | wdata = 32'h0x02000000; | ||
+ | -> write; | ||
+ | @ (writeDone); | ||
+ | |||
+ | reg_addr = (`chNum << 6) + `CODE_STATE2_OFFSET; | ||
+ | wdata = 32'h00000000; | ||
+ | -> write; | ||
+ | @ (writeDone); | ||
+ | |||
+ | reg_addr = (`chNum << 6) + `CODE_BITMASK2_OFFSET; | ||
+ | wdata = 32'h00000000; | ||
+ | -> write; | ||
+ | @ (writeDone); | ||
+ | |||
+ | reg_addr = (`chNum << 6) + `CODE_OUT_BITMASK2_OFFSET; | ||
+ | wdata = 32'h0x00000000; | ||
+ | -> write; | ||
+ | @ (writeDone); | ||
+ | |||
+ | reg_addr = (`chNum << 6) + `PRN_LENGTH_OFFSET; | ||
+ | wdata = 511-1; | ||
+ | -> write; | ||
+ | @ (writeDone); | ||
+ | |||
+ | reg_addr = (`chNum << 6) + `PRN_LENGTH1_OFFSET; | ||
+ | wdata = 511-1; | ||
+ | -> write; | ||
+ | @ (writeDone); | ||
+ | |||
+ | reg_addr = (`chNum << 6) + `CHIP_MAX_OFFSET; | ||
+ | wdata = 511-1; | ||
+ | -> write; | ||
+ | @ (writeDone); | ||
+ | |||
+ | reg_addr = (`chNum << 6) + `PRN_INIT_OFFSET; | ||
+ | wdata = 0; | ||
+ | -> write; | ||
+ | @ (writeDone); | ||
+ | |||
+ | reg_addr = (`chNum << 6) + `PRN_INIT1_OFFSET; | ||
+ | wdata = 0; | ||
+ | -> write; | ||
+ | @ (writeDone); | ||
+ | |||
+ | reg_addr = (`chNum << 6) + `BOC_REGS_OFFSET; | ||
+ | wdata = 0; | ||
+ | -> write; | ||
+ | @ (writeDone); | ||
+ | |||
+ | reg_addr = (`chNum << 6) + `CODE_RATE_OFFSET; | ||
+ | wdata = 20783411; | ||
+ | -> write; | ||
+ | @ (writeDone); | ||
+ | |||
+ | reg_addr = (`chNum << 6) + `CODE_PHASE_OFFSET; | ||
+ | wdata = 0; | ||
+ | -> write; | ||
+ | @ (writeDone); | ||
+ | |||
+ | reg_addr = (`chNum << 6) + `EPOCH_AND_TOW_OFFSET; | ||
+ | wdata = 0; | ||
+ | -> write; | ||
+ | @ (writeDone); | ||
+ | |||
+ | reg_addr = (`chNum << 6) + `EPOCH_AND_SYMB_MAX_OFFSET; | ||
+ | wdata = 1000-1; | ||
+ | -> write; | ||
+ | @ (writeDone); | ||
+ | |||
+ | reg_addr = (`chNum << 6) + `CODE_DOINIT_OFFSET; | ||
+ | wdata = {16'h12AB, 16'b0}; | ||
+ | -> write; | ||
+ | @ (writeDone); | ||
+ | end | ||
+ | |||
+ | endmodule | ||
+ | </source> | ||
+ | |hidden = 1 | ||
+ | }} | ||
+ | |||
+ | TB задает два типа тактовых сигналов - один процессора, другой от РЧБ. В бесконечном цикле генерируются импульс эпохи и импульс снятия измерений. В TEST CASE дается сигнал сброса, затем канал имитатора конфигурируется под сигнал ГЛОНАСС СТ. | ||
+ | [[File:20160404_vivado_revolution19.png|center]] | ||
+ | |||
+ | |||
+ | А вот что мы добавляем в prj_imitator.tcl, чтобы этот набор для моделирования разворачивался вместе с проектом: | ||
+ | {{Hider|title = Вставка в prj_imitator.tcl для регенерации sim_imitator_channel | ||
+ | |content = <source lang="tcl"> | ||
+ | # =============== imitator_channel module test bench ==================== | ||
+ | # Create 'sim_imitator_channel' fileset (if not found) | ||
+ | if {[string equal [get_filesets -quiet sim_imitator_channel] ""]} { | ||
+ | create_fileset -simset sim_imitator_channel | ||
+ | } | ||
+ | |||
+ | set obj [get_filesets sim_imitator_channel] | ||
+ | set files [list \ | ||
+ | "[file normalize "$origin_dir/tb/imitator_channel_tb.v"]"\ | ||
+ | "[file normalize "$origin_dir/verilog/top/global_param.v"]"\ | ||
+ | "[file normalize "$origin_dir/verilog/imitator_channel.v"]"\ | ||
+ | "[file normalize "$origin_dir/verilog/imichnl_synthesizer.v"]"\ | ||
+ | "[file normalize "$origin_dir/verilog/imichnl_sin_table.v"]"\ | ||
+ | "[file normalize "$origin_dir/verilog/imichnl_param.v"]"\ | ||
+ | "[file normalize "$origin_dir/verilog/imichnl_regfile.v"]"\ | ||
+ | "[file normalize "$origin_dir/verilog/imichnl_cos_table.v"]"\ | ||
+ | "[file normalize "$origin_dir/verilog/imichnl_delay_reg.v"]"\ | ||
+ | "[file normalize "$origin_dir/$sub_dir/correlator/verilog/flag_sync.v"]"\ | ||
+ | "[file normalize "$origin_dir/$sub_dir/correlator/verilog/flag_sync_n.v"]"\ | ||
+ | "[file normalize "$origin_dir/$sub_dir/correlator/verilog/time_generator.v"]"\ | ||
+ | "[file normalize "$origin_dir/$sub_dir/correlator/verilog/channel_shift_reg.v"]"\ | ||
+ | "[file normalize "$origin_dir/$sub_dir/sync/verilog/level_sync.v"]"\ | ||
+ | "[file normalize "$origin_dir/$sub_dir/sync/verilog/signal_sync.v"]"\ | ||
+ | "[file normalize "$origin_dir/tb/imitator_channel_tb_behav.wcfg"]"\ | ||
+ | ] | ||
+ | add_files -norecurse -fileset $obj $files | ||
+ | |||
+ | # Set 'sim_imitator_channel' fileset properties | ||
+ | set obj [get_filesets sim_imitator_channel] | ||
+ | set_property "include_dirs" "$origin_dir/verilog $origin_dir/verilog/top" $obj | ||
+ | set_property "runtime" "3000000ns" $obj | ||
+ | set_property "source_set" "" $obj | ||
+ | set_property "top" "imitator_channel_tb" $obj | ||
+ | set_property "xelab.nosort" "1" $obj | ||
+ | set_property "xelab.unifast" "" $obj | ||
+ | set_property "xsim.simulate.runtime" "3000000ns" $obj | ||
+ | set_property "xsim.view" "$origin_dir/tb/imitator_channel_tb_behav.wcfg" $obj | ||
+ | # ============ End of imitator_channel module test bench ==================== | ||
+ | </source> | ||
+ | |hidden = 1 | ||
+ | }} | ||
+ | |||
+ | Обсудим команды, которые добавляются в скрипт. В первую очередь создается новый набор для симуляции, ему присваивается название sim_imitator_channel | ||
+ | <source lang="tcl"> | ||
+ | if {[string equal [get_filesets -quiet sim_imitator_channel] ""]} { | ||
+ | create_fileset -simset sim_imitator_channel | ||
+ | } | ||
+ | </source> | ||
+ | |||
+ | |||
+ | Далее в этот набор добавляются файлы: | ||
+ | <source lang="tcl"> | ||
+ | set obj [get_filesets sim_imitator_channel] | ||
+ | set files [list \ | ||
+ | "[file normalize "$origin_dir/tb/imitator_channel_tb.v"]"\ | ||
+ | "[file normalize "$origin_dir/verilog/top/global_param.v"]"\ | ||
+ | "[file normalize "$origin_dir/verilog/imitator_channel.v"]"\ | ||
+ | "[file normalize "$origin_dir/verilog/imichnl_synthesizer.v"]"\ | ||
+ | "[file normalize "$origin_dir/verilog/imichnl_sin_table.v"]"\ | ||
+ | "[file normalize "$origin_dir/verilog/imichnl_param.v"]"\ | ||
+ | "[file normalize "$origin_dir/verilog/imichnl_regfile.v"]"\ | ||
+ | "[file normalize "$origin_dir/verilog/imichnl_cos_table.v"]"\ | ||
+ | "[file normalize "$origin_dir/verilog/imichnl_delay_reg.v"]"\ | ||
+ | "[file normalize "$origin_dir/$sub_dir/correlator/verilog/flag_sync.v"]"\ | ||
+ | "[file normalize "$origin_dir/$sub_dir/correlator/verilog/flag_sync_n.v"]"\ | ||
+ | "[file normalize "$origin_dir/$sub_dir/correlator/verilog/time_generator.v"]"\ | ||
+ | "[file normalize "$origin_dir/$sub_dir/correlator/verilog/channel_shift_reg.v"]"\ | ||
+ | "[file normalize "$origin_dir/$sub_dir/sync/verilog/level_sync.v"]"\ | ||
+ | "[file normalize "$origin_dir/$sub_dir/sync/verilog/signal_sync.v"]"\ | ||
+ | "[file normalize "$origin_dir/tb/imitator_channel_tb_behav.wcfg"]"\ | ||
+ | ] | ||
+ | add_files -norecurse -fileset $obj $files | ||
+ | </source> | ||
+ | |||
+ | |||
+ | Далее указываются директории, в которых будет производиться поиск файл, подключенных с помощью директивы <code>`include</code>: | ||
+ | <source lang="tcl"> | ||
+ | set obj [get_filesets sim_imitator_channel] | ||
+ | set_property "include_dirs" "$origin_dir/verilog $origin_dir/verilog/top" $obj | ||
+ | </source> | ||
+ | |||
+ | |||
+ | Указывается топовый модуль для моделирования: | ||
+ | <source lang="tcl"> | ||
+ | set_property "top" "imitator_channel_tb" $obj | ||
+ | </source> | ||
+ | |||
+ | |||
+ | Указывается топовый модуль для моделирования: | ||
+ | <source lang="tcl"> | ||
+ | set_property "runtime" "3000000ns" $obj | ||
+ | set_property "xsim.simulate.runtime" "3000000ns" $obj | ||
+ | </source> | ||
+ | |||
+ | |||
+ | Указывается wave-форма: | ||
+ | <source lang="tcl"> | ||
+ | set_property "xsim.view" "$origin_dir/tb/imitator_channel_tb_behav.wcfg" $obj | ||
+ | </source> | ||
+ | |||
+ | |||
+ | Также в скрипте регенерации мы можем указать, какой набор симуляции считать активным по-умолчанию: | ||
+ | <source lang="tcl"> | ||
+ | current_fileset -simset [ get_filesets sim_imitator_channel ] | ||
+ | </source> | ||
+ | |||
+ | == Итоговый скрипт регенерации проекта == | ||
+ | |||
+ | |||
+ | Итоговый скрипт регенерации проекта imitator будет выглядеть так: | ||
+ | |||
+ | {{Hider|title = Скрипт регенерации проекта prj_imitator.tcl | ||
+ | |content = <source lang="tcl"> | ||
+ | #!/usr/bin/tclsh | ||
+ | # | ||
+ | # Vivado (TM) v2015.3 (64-bit) | ||
+ | # | ||
+ | # prj_imitator.tcl: Tcl script for re-creating project 'imitator' | ||
+ | # | ||
+ | # Generated by Vivado on Tue Mar 22 10:11:05 +0300 2016 | ||
+ | # IP Build 1367837 on Mon Sep 28 08:56:14 MDT 2015 | ||
+ | # | ||
+ | # This file contains the Vivado Tcl commands for re-creating the project to the state* | ||
+ | # when this script was generated. In order to re-create the project, please source this | ||
+ | # file in the Vivado Tcl Shell. | ||
+ | # | ||
+ | # * Note that the runs in the created project will be configured the same way as the | ||
+ | # original project, however they will not be launched automatically. To regenerate the | ||
+ | # run results please launch the synthesis/implementation runs as needed. | ||
+ | # | ||
+ | |||
+ | # Set the reference directory for source file relative paths (by default the value is script directory path) | ||
+ | set origin_dir "." | ||
+ | set sub_dir "sub" | ||
+ | set prj_name "imitator" | ||
+ | set prj_dir_name "prj_imitator" | ||
+ | set topmodule_name "imitator_top" | ||
+ | |||
+ | |||
+ | # Use origin directory path location variable, if specified in the tcl shell | ||
+ | if { [info exists ::origin_dir_loc] } { | ||
+ | set origin_dir $::origin_dir_loc | ||
+ | } | ||
+ | |||
+ | variable script_file | ||
+ | set script_file "prj_$prj_name.tcl" | ||
+ | |||
+ | # Help information for this script | ||
+ | proc help {} { | ||
+ | variable script_file | ||
+ | puts "\nDescription:" | ||
+ | puts "Recreate a Vivado project from this script. The created project will be" | ||
+ | puts "functionally equivalent to the original project for which this script was" | ||
+ | puts "generated. The script contains commands for creating a project, filesets," | ||
+ | puts "runs, adding/importing sources and setting properties on various objects.\n" | ||
+ | puts "Syntax:" | ||
+ | puts "$script_file" | ||
+ | puts "$script_file -tclargs \[--origin_dir <path>\]" | ||
+ | puts "$script_file -tclargs \[--help\]\n" | ||
+ | puts "Usage:" | ||
+ | puts "Name Description" | ||
+ | puts "-------------------------------------------------------------------------" | ||
+ | puts "\[--origin_dir <path>\] Determine source file paths wrt this path. Default" | ||
+ | puts " origin_dir path value is \".\", otherwise, the value" | ||
+ | puts " that was set with the \"-paths_relative_to\" switch" | ||
+ | puts " when this script was generated.\n" | ||
+ | puts "\[--help\] Print help information for this script" | ||
+ | puts "-------------------------------------------------------------------------\n" | ||
+ | exit 0 | ||
+ | } | ||
+ | |||
+ | if { $::argc > 0 } { | ||
+ | for {set i 0} {$i < [llength $::argc]} {incr i} { | ||
+ | set option [string trim [lindex $::argv $i]] | ||
+ | switch -regexp -- $option { | ||
+ | "--origin_dir" { incr i; set origin_dir [lindex $::argv $i] } | ||
+ | "--help" { help } | ||
+ | default { | ||
+ | if { [regexp {^-} $option] } { | ||
+ | puts "ERROR: Unknown option '$option' specified, please type '$script_file -tclargs --help' for usage info.\n" | ||
+ | return 1 | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | |||
+ | # Create project | ||
+ | create_project $prj_name ./$prj_dir_name | ||
+ | |||
+ | # Set the directory path for the new project | ||
+ | set proj_dir [get_property directory [current_project]] | ||
+ | |||
+ | # Set project properties | ||
+ | set obj [get_projects $prj_name] | ||
+ | set_property "default_lib" "xil_defaultlib" $obj | ||
+ | set_property "part" "xc7z045fbg676-2" $obj | ||
+ | set_property "sim.ip.auto_export_scripts" "1" $obj | ||
+ | set_property "simulator_language" "Mixed" $obj | ||
+ | set_property "source_mgmt_mode" "DisplayOnly" $obj | ||
+ | |||
+ | # Create 'sources_1' fileset (if not found) | ||
+ | if {[string equal [get_filesets -quiet sources_1] ""]} { | ||
+ | create_fileset -srcset sources_1 | ||
+ | } | ||
+ | |||
+ | # Set 'sources_1' fileset object | ||
+ | set obj [get_filesets sources_1] | ||
+ | set files [list \ | ||
+ | "[file normalize "$origin_dir/verilog/top/$topmodule_name.v"]"\ | ||
+ | "[file normalize "$origin_dir/verilog/imitator.v"]"\ | ||
+ | "[file normalize "$origin_dir/verilog/imitator_channel.v"]"\ | ||
+ | "[file normalize "$origin_dir/verilog/imichnl_regfile.v"]"\ | ||
+ | "[file normalize "$origin_dir/verilog/imichnl_param.v"]"\ | ||
+ | "[file normalize "$origin_dir/verilog/imichnl_delay_reg.v"]"\ | ||
+ | "[file normalize "$origin_dir/verilog/imichnl_sin_table.v"]"\ | ||
+ | "[file normalize "$origin_dir/verilog/imichnl_cos_table.v"]"\ | ||
+ | "[file normalize "$origin_dir/verilog/imichnl_synthesizer.v"]"\ | ||
+ | "[file normalize "$origin_dir/$sub_dir/correlator/verilog/flag_sync.v"]"\ | ||
+ | "[file normalize "$origin_dir/$sub_dir/correlator/verilog/flag_sync_n.v"]"\ | ||
+ | "[file normalize "$origin_dir/$sub_dir/correlator/verilog/channel_shift_reg.v"]"\ | ||
+ | "[file normalize "$origin_dir/$sub_dir/correlator/verilog/time_generator.v"]"\ | ||
+ | "[file normalize "$origin_dir/$sub_dir/sync/verilog/signal_sync.v"]"\ | ||
+ | "[file normalize "$origin_dir/$sub_dir/sync/verilog/level_sync.v"]"\ | ||
+ | ] | ||
+ | add_files -norecurse -fileset $obj $files | ||
+ | |||
+ | # Set 'sources_1' fileset file properties for remote files | ||
+ | # None | ||
+ | |||
+ | |||
+ | # Set 'sources_1' fileset properties | ||
+ | set obj [get_filesets sources_1] | ||
+ | set_property "include_dirs" "$origin_dir/verilog $origin_dir/verilog/top" $obj | ||
+ | set_property "top" "$topmodule_name" $obj | ||
+ | |||
+ | # Create 'constrs_1' fileset (if not found) | ||
+ | if {[string equal [get_filesets -quiet constrs_1] ""]} { | ||
+ | create_fileset -constrset constrs_1 | ||
+ | } | ||
+ | |||
+ | # Set 'constrs_1' fileset object | ||
+ | set obj [get_filesets constrs_1] | ||
+ | |||
+ | # Create 'sim_1' fileset (if not found) | ||
+ | # It should exist! If Vivado doesn't found it, once will be generated | ||
+ | if {[string equal [get_filesets -quiet sim_1] ""]} { | ||
+ | create_fileset -simset sim_1 | ||
+ | } | ||
+ | |||
+ | # Set 'sim_sim_1' fileset properties | ||
+ | set obj [get_filesets sim_1] | ||
+ | set_property "source_set" "" $obj | ||
+ | set_property "top" "$topmodule_name" $obj | ||
+ | set_property "xelab.nosort" "1" $obj | ||
+ | set_property "xelab.unifast" "" $obj | ||
+ | |||
+ | |||
+ | # =============== imichnl_synthesizer module test bench ==================== | ||
+ | # Create 'sim_imichnl_synthesizer' fileset (if not found) | ||
+ | if {[string equal [get_filesets -quiet sim_imichnl_synthesizer] ""]} { | ||
+ | create_fileset -simset sim_imichnl_synthesizer | ||
+ | } | ||
+ | |||
+ | set obj [get_filesets sim_imichnl_synthesizer] | ||
+ | set files [list \ | ||
+ | "[file normalize "$origin_dir/tb/imichnl_synthesizer_tb.v"]"\ | ||
+ | "[file normalize "$origin_dir/tb/imichnl_synthesizer_tb_behav.wcfg"]"\ | ||
+ | "[file normalize "$origin_dir/verilog/imichnl_synthesizer.v"]"\ | ||
+ | ] | ||
+ | add_files -norecurse -fileset $obj $files | ||
+ | |||
+ | # Set 'sim_imichnl_synthesizer' fileset properties | ||
+ | set obj [get_filesets sim_imichnl_synthesizer] | ||
+ | set_property "source_set" "" $obj | ||
+ | set_property "top" "imichnl_synthesizer_tb" $obj | ||
+ | set_property "xelab.nosort" "1" $obj | ||
+ | set_property "xelab.unifast" "" $obj | ||
+ | set_property "xsim.view" "$origin_dir/tb/imichnl_synthesizer_tb_behav.wcfg" $obj | ||
+ | # ============ End of imichnl_synthesizer module test bench ==================== | ||
+ | |||
+ | |||
+ | |||
+ | # =============== imitator_channel module test bench ==================== | ||
+ | # Create 'sim_imitator_channel' fileset (if not found) | ||
+ | if {[string equal [get_filesets -quiet sim_imitator_channel] ""]} { | ||
+ | create_fileset -simset sim_imitator_channel | ||
+ | } | ||
+ | |||
+ | set obj [get_filesets sim_imitator_channel] | ||
+ | set files [list \ | ||
+ | "[file normalize "$origin_dir/tb/imitator_channel_tb.v"]"\ | ||
+ | "[file normalize "$origin_dir/verilog/top/global_param.v"]"\ | ||
+ | "[file normalize "$origin_dir/verilog/imitator_channel.v"]"\ | ||
+ | "[file normalize "$origin_dir/verilog/imichnl_synthesizer.v"]"\ | ||
+ | "[file normalize "$origin_dir/verilog/imichnl_sin_table.v"]"\ | ||
+ | "[file normalize "$origin_dir/verilog/imichnl_param.v"]"\ | ||
+ | "[file normalize "$origin_dir/verilog/imichnl_regfile.v"]"\ | ||
+ | "[file normalize "$origin_dir/verilog/imichnl_cos_table.v"]"\ | ||
+ | "[file normalize "$origin_dir/verilog/imichnl_delay_reg.v"]"\ | ||
+ | "[file normalize "$origin_dir/$sub_dir/correlator/verilog/flag_sync.v"]"\ | ||
+ | "[file normalize "$origin_dir/$sub_dir/correlator/verilog/flag_sync_n.v"]"\ | ||
+ | "[file normalize "$origin_dir/$sub_dir/correlator/verilog/time_generator.v"]"\ | ||
+ | "[file normalize "$origin_dir/$sub_dir/correlator/verilog/channel_shift_reg.v"]"\ | ||
+ | "[file normalize "$origin_dir/$sub_dir/sync/verilog/level_sync.v"]"\ | ||
+ | "[file normalize "$origin_dir/$sub_dir/sync/verilog/signal_sync.v"]"\ | ||
+ | "[file normalize "$origin_dir/tb/imitator_channel_tb_behav.wcfg"]"\ | ||
+ | ] | ||
+ | add_files -norecurse -fileset $obj $files | ||
+ | |||
+ | # Set 'sim_imitator_channel' fileset properties | ||
+ | set obj [get_filesets sim_imitator_channel] | ||
+ | set_property "include_dirs" "$origin_dir/verilog $origin_dir/verilog/top" $obj | ||
+ | set_property "runtime" "3000000ns" $obj | ||
+ | set_property "source_set" "" $obj | ||
+ | set_property "top" "imitator_channel_tb" $obj | ||
+ | set_property "xelab.nosort" "1" $obj | ||
+ | set_property "xelab.unifast" "" $obj | ||
+ | set_property "xsim.simulate.runtime" "3000000ns" $obj | ||
+ | set_property "xsim.view" "$origin_dir/tb/imitator_channel_tb_behav.wcfg" $obj | ||
+ | # ============ End of imitator_channel module test bench ==================== | ||
+ | |||
+ | |||
+ | current_fileset -simset [ get_filesets sim_imitator_channel ] | ||
+ | |||
+ | |||
+ | # Create 'synth_1' run (if not found) | ||
+ | if {[string equal [get_runs -quiet synth_1] ""]} { | ||
+ | create_run -name synth_1 -part xc7z045fbg676-2 -flow {Vivado Synthesis 2014} -strategy "Vivado Synthesis Defaults" -constrset constrs_1 | ||
+ | } else { | ||
+ | set_property strategy "Vivado Synthesis Defaults" [get_runs synth_1] | ||
+ | set_property flow "Vivado Synthesis 2014" [get_runs synth_1] | ||
+ | } | ||
+ | set obj [get_runs synth_1] | ||
+ | set_property "part" "xc7z045fbg676-2" $obj | ||
+ | |||
+ | # set the current synth run | ||
+ | current_run -synthesis [get_runs synth_1] | ||
+ | |||
+ | # Create 'impl_1' run (if not found) | ||
+ | if {[string equal [get_runs -quiet impl_1] ""]} { | ||
+ | create_run -name impl_1 -part xc7z045fbg676-2 -flow {Vivado Implementation 2015} -strategy "Performance_Explore" -constrset constrs_1 -parent_run synth_1 | ||
+ | } else { | ||
+ | set_property strategy "Performance_Explore" [get_runs impl_1] | ||
+ | set_property flow "Vivado Implementation 2015" [get_runs impl_1] | ||
+ | } | ||
+ | set obj [get_runs impl_1] | ||
+ | set_property "part" "xc7z045fbg676-2" $obj | ||
+ | set_property "steps.opt_design.args.directive" "Explore" $obj | ||
+ | set_property "steps.place_design.args.directive" "Explore" $obj | ||
+ | set_property "steps.phys_opt_design.is_enabled" "1" $obj | ||
+ | set_property "steps.phys_opt_design.args.directive" "Explore" $obj | ||
+ | set_property "steps.route_design.args.directive" "Explore" $obj | ||
+ | set_property "steps.write_bitstream.args.readback_file" "0" $obj | ||
+ | set_property "steps.write_bitstream.args.verbose" "0" $obj | ||
+ | |||
+ | # set the current impl run | ||
+ | current_run -implementation [get_runs impl_1] | ||
+ | |||
+ | puts "INFO: Project created:$prj_name" | ||
+ | </source> | ||
+ | |hidden = 1 | ||
+ | }} | ||
+ | |||
+ | |||
+ | Добавляем файл регенерации проекта prj_imitator.tcl и файлы в каталоге tb в коммит. | ||
+ | |||
+ | == У другого пользователя == | ||
+ | |||
+ | Теперь оба TB'а будут храниться в системе контроля версий. При запуске скрипта регенерации у нового пользователя они будут разворачиваться и настраиваться. Пользователю останется их только запустить. | ||
+ | |||
+ | <source lang="bash"> | ||
+ | korogodin@Diod:~/Oryx/src/fpga/sub/imitator$ /opt/Xilinx/Vivado/2015.3/bin/vivado -source prj_imitator.tcl | ||
+ | </source> | ||
+ | |||
+ | [[file:20160404_vivado_revolution18.png|center]] | ||
== Ссылки == | == Ссылки == | ||
− | [http://we.easyelectronics.ru/plis/testbench-na-verilog-dlya-novichkov.html Easyelectronics:TestBench на Verilog для новичков] | + | *[http://we.easyelectronics.ru/plis/testbench-na-verilog-dlya-novichkov.html Easyelectronics:TestBench на Verilog для новичков] |
+ | *[http://www.xilinx.com/support/documentation/sw_manuals/xilinx2014_2/ug900-vivado-logic-simulation.pdf Xilinx UG900: Logic Simulation] | ||
+ | *[http://www.xilinx.com/support/answers/64000.html AR64000: Understanding Waveform Database file (WDB) and Wave Configuration File (WCFG)] | ||
+ | *[http://www.compitech.ru/html.cgi/arhiv/01_02/stat_86.htm Verilog — инструмент разработки цифровых электронных схем: О типах данных] | ||
+ | *[http://www.compitech.ru/html.cgi/arhiv/01_03/stat_134.htm Verilog — инструмент разработки цифровых электронных схем: Операторы] | ||
+ | *[http://www.compitech.ru/html.cgi/arhiv/01_04/stat_76.htm Verilog — инструмент разработки цифровых электронных схем: О моделируемых конструкциях] | ||
+ | *[http://compitech.ru/html.cgi/arhiv/01_05/stat_66.htm Verilog — инструмент разработки цифровых электронных схем: О синтезируемых конструкциях] | ||
+ | *[https://inst.eecs.berkeley.edu/~cs150/fa06/Labs/verilog-ieee.pdf Verilog-2001] | ||
+ | *[http://www.uccs.edu/~gtumbush/published_papers/Tumbush%20DVCon%2005.pdf Signed Arithmetic in Verilog 2001 – Opportunities and Hazards] | ||
[[Категория:HOWTO]] | [[Категория:HOWTO]] | ||
+ | [[Категория:Git]] | ||
+ | [[Категория:Xilinx]] | ||
+ | [[Категория:Vivado]] | ||
+ | [[Category:FPGA]] | ||
+ | [[Category:Verilog]] |
Текущая версия на 15:54, 9 ноября 2016
|
Пусть у нас есть дизайн для Vivado, проект которого разворачивается в соответствии со статьей Vivado и Git. Это может быть как конечный дизайн, так и чей-то сабмодуль. Процедура добавления test bench'ей (далее TB) отличаться не будет, поэтому рассмотрим всё на примере сабмодуля imitator.
Задача - добавить TB'и для модулей дизайна, причем
- они должны храниться в СКВ и быть доступны всем разработчикам,
- имеются в виду TB'и на языке Verilog для симуляторов типа Vivado Simulator, ModelSim и т.д., а не тесты на языках Си или Matlab для Verilator'а.
Для конкретики, будем добавлять в дизайн imitator TB'и для двух модулей:
- imichnl_synthesizer, отвечающий за фазу несущей,
- imitator_channel, являющийся топ-модулем для одного канала имитатора и включающий в себя первый модуль.
Наша конечная цель - файлы TB'ей и правильно написанный скрипт регенерации проекта, включающий раскладывание TB'ей по полочкам. Будем считать, что пользователь по-максимуму хочет использовать GUI и по-минимуму консоль и TCL. Тогда вырисовывается следующий workflow:
- средствами GUI создать новый набор файлов для моделирования (включающий код TB'а, тестируемые модули и т.п.),
- через GUI настроить этот набор,
- через GUI выгрузить код регенерации,
- подправить существующий скрипт регенерации проекта так, чтобы TB'и разворачивались и настраивался вместе с проектом.
[править] Добавление TB через GUI
[править] Создание нового набора для симуляции
Создадим через GUI новый TB, а потом перенесем его в tcl-скрипт! Начнем с TB для модуля imichnl_synthesizer.
В Flow Navigator (это панель слева в Vivado) в разделе Simulation выбираем Simulation Settings
В открывшемся окне в разделе Simulation в графе Simulation top modulw name создаем новый файлсет, выбирая Create Simulation Set
ВНИМАНИЕ Не занимайте и не удаляйте файлсет sim_1. Vivado его очень любит и будет создавать заново, делая при этим активным. Лучше оставить sim_1 пустым.
Новому файлсету даем осмысленное название, например, sim_imichnl_synthesizer
Очищаем графу Simulation top module name, т.к. файл с кодом TB'а у нас ещё не создан.
На вкладке Advanced запрещаем включать в TB все файлы проекта, снимая галку с Include all design sources for simulation. Иначе он добавит все наши файлы в файлсет этого TB'а, что нам не нужно.
Закрываем окно, нажимая Ok. Vivado задает вопрос, сделать ли данный TB активным. Можно соглашаться. В итоге в Source проекта появился новый пустой файлсет для симуляции sim_imichnl_synthesizer
[править] Добавляем файлы в набор для симуляции
В контекстном меню файлсета sim_imichnl_synthesizer, выпадающем при нажатии правой кнопкой мыши, выбираем добавление новых файлов Add Sources
Далее Add or create simulation sources
Добавляем новый файл TB'а, нажимая кнопку Create File в открывшемся окне. Даем файлу осмысленное имя с суффиксом _tb, например, imichnl_synthesizer_tb.v и обязательно указываем в качестве пути каталог tb дизайна imitator. Иначе он будет создан в дебрях песочницы (в prj_imitator) и не будет виден системе контроля версий.
С помощью кнопки Add Files добавляем уже существующие файлы, которые потребуются для работы тестируемого модуля. В данном случае это сам модуль imichnl_synthesizer из каталога verilog
После добавления требуемых файлов нажимаем кнопку Finish. Открывается окно Define module для нашего TB'а imichnl_synthesizer_tb.v. Порты нам добавлять не нужно, просто нажимаем Ok. Теперь у нас в файлсете sim_imichnl_synthesizer два файла - код исследуемого модуля и код TB'а.
Возвращаемся в настройки симуляции (Flow Navigator -> Simulation -> Simulation Settings) и указываем в качестве топового модуль imichnl_synthesizer_tb
[править] Код TB'а
Пришло время наполнить imichnl_synthesizer_tb смысловым содержанием. Общий сброс, после чего каждую эпоху PHASE_RATE увеличивается на 500:
module imichnl_synthesizer_tb();
reg pclk; // [in]
reg reset_n;
reg [32-1:0] phase_rate;
reg doinit;
reg fix_pulse;
reg dly_epoch;
wire [32-1:0] phase_rate_int; // [out]
wire [32-1:0] phase_int;
wire [32-1:0] phase_cycles_int;
wire [5-1:0] phase_addr;
// Генератор фазы несущей,
// отображает phase_rate в phase_addr
// по задержанной эпохе dly_epoch защелкивает счетчики циклов и фазы, а также регистр phase_rate
// по задержанной эпохе dly_epoch применяет записанное значение phase_rate
//
imichnl_synthesizer CHSYN (
.clk (pclk), // [in]
.reset_n (reset_n),
.phase_rate (phase_rate),
.doinit (doinit),
.fix_pulse (fix_pulse),
.epoch_pulse (dly_epoch),
.phase_rate_int (phase_rate_int), // [out]
.phase_int (phase_int),
.phase_cycles_int (phase_cycles_int),
.phase_addr (phase_addr)
);
initial begin
pclk = 0;
reset_n = 1;
phase_rate = 0;
doinit = 0;
fix_pulse = 0;
dly_epoch = 0;
end
always // 105.6 MHz
#47 pclk = !pclk;
event reset;
event epoch;
event fix;
initial begin
forever begin
@ (reset)
@ (negedge pclk)
reset_n = 0;
@ (negedge pclk)
reset_n = 1;
end
end
initial begin
forever begin
@ (epoch)
@ (negedge pclk)
dly_epoch = 1;
@ (negedge pclk)
dly_epoch = 0;
end
end
initial begin
forever begin
@ (fix)
@ (negedge pclk)
fix_pulse = 1;
@ (negedge pclk)
fix_pulse = 0;
end
end
initial begin
forever begin
#10000500 -> epoch;
end
end
initial begin
#2000000
forever begin
#10000000 -> fix;
end
end
initial begin: TEST_CASE
#10 -> reset;
forever begin
#3000000
phase_rate = phase_rate + 500;
@ (epoch);
end
end
endmodule
[править] Моделирование
После того как TB написан, запускаем симуляцию через контекстное меню файлсета:
Моделируем, настраиваем wave-форму
Cохраняем настройки wave-формы в каталог tb через меню File->Save Waveform Configuration, автоматом получая имя файла типа imichnl_synthesizer_tb_behav.wcfg
[править] Добавление TB'а через скрипт регенерации проекта
Сейчас все настройки TB'а, т.е. файлсета sim_imichnl_synthesizer, хранятся в песочнице, которая у нас не находится под системой контроля версий. Нужно добавить соответствующий код в скрипт регенерации проекта (традиционно его место до объявления настроек синтеза synth_1)
# Create 'sim_imichnl_synthesizer' fileset (if not found)
if {[string equal [get_filesets -quiet sim_imichnl_synthesizer] ""]} {
create_fileset -simset sim_imichnl_synthesizer
}
set obj [get_filesets sim_imichnl_synthesizer]
set files [list \
"[file normalize "$origin_dir/tb/imichnl_synthesizer_tb.v"]"\
"[file normalize "$origin_dir/tb/imichnl_synthesizer_tb_behav.wcfg"]"\
"[file normalize "$origin_dir/verilog/imichnl_synthesizer.v"]"\
]
add_files -norecurse -fileset $obj $files
# Set 'sim_imichnl_synthesizer' fileset properties
set obj [get_filesets sim_imichnl_synthesizer]
set_property "source_set" "" $obj
set_property "top" "imichnl_synthesizer_tb" $obj
set_property "xelab.nosort" "1" $obj
set_property "xelab.unifast" "" $obj
set_property "xsim.view" "$origin_dir/tb/imichnl_synthesizer_tb_behav.wcfg" $obj
# ============ End of imichnl_synthesizer module test bench ====================
Как я получил этот код? Я просто выгрузил через File -> Write Project Tcl новый скрипт регенерации проекта и вычленил из него блок, отвечающий за наш новый файлсет.
Ниже мы подробнее рассмотрим команды, используемые для регенерации TB'а. Сделаем мы это на примере второго TB'а, т.к. он немного сложнее.
[править] Добавляем второй TB
Проделываем аналогичные действия для второго TB'а, получаем набор для моделирования sim_imitator_channel, включающий, помимо прочего, imitator_channel_tb.v.
`include "global_param.v"
`include "imichnl_param.v"
module imitator_channel_tb();
parameter BASE_ADDR = `ADDR_WIDTH'h8000;
// [in]
reg clk;
reg pclk;
reg reset_n;
reg wr_en;
reg rd_en;
reg [`ADDR_WIDTH - 1 : 0] reg_addr;
reg [31 : 0] wdata;
reg intr_pulse;
reg fix_pulse;
// [out]
wire [31 : 0] rdata;
wire [`IMI_CHNLOUTWIDTH - 1 : 0] i_ch; // Синфазная компонента i-го канала
wire [`IMI_CHNLOUTWIDTH - 1 : 0] q_ch; // Квадратурная компонента i-го канала
`define chNum 0
imitator_channel
#(BASE_ADDR + (`chNum << 6)) IMI_CH (
.clk (clk), // In
.pclk (pclk),
.reset_n (reset_n),
.wr_en (wr_en),
.rd_en (rd_en),
.reg_addr (reg_addr),
.wdata (wdata),
.intr_pulse (intr_pulse),
.fix_pulse (fix_pulse),
.rdata (rdata), // Out
.i (i_ch),
.q (q_ch)
);
initial begin
clk = 0;
pclk = 0;
reset_n = 1;
wr_en = 0;
rd_en = 0;
reg_addr = 0;
wdata = 0;
intr_pulse = 0;
fix_pulse = 0;
end
always // 105.6 MHz
#47 pclk = !pclk;
always // 60 MHz
#83 clk = !clk;
event reset;
event irq;
event fix;
event write;
event writeDone;
event read;
event readDone;
initial begin
forever begin
@ (reset)
@ (negedge pclk)
reset_n = 0;
@ (negedge pclk)
reset_n = 1;
end
end
initial begin
forever begin
@ (irq)
@ (negedge pclk)
intr_pulse = 1;
@ (negedge pclk)
intr_pulse = 0;
end
end
initial begin
forever begin
@ (fix)
@ (negedge pclk)
fix_pulse = 1;
@ (negedge pclk)
fix_pulse = 0;
end
end
initial begin
fork // Распараллеливание блоков
forever begin
#6000000 -> irq;
end
forever begin
#10000000 -> fix;
end
join
end
initial begin
forever begin
@ (write)
@ (negedge clk)
wr_en = 1;
@ (negedge clk)
@ (negedge clk)
@ (negedge clk)
wr_en = 0;
-> writeDone;
end
end
initial begin
forever begin
@ (read)
@ (negedge clk)
rd_en = 1;
@ (negedge clk)
@ (negedge clk)
@ (negedge clk)
rd_en = 0;
-> readDone;
end
end
initial begin: TEST_CASE
#10 -> reset;
#500
// Write PHASE_RATE
reg_addr = (`chNum << 6) + `PHASE_RATE_OFFSET;
wdata = 32'd1000000;
-> write;
@ (writeDone);
// Configure GLONASS ST
reg_addr = (`chNum << 6) + `CODE_STATE1_OFFSET;
wdata = 32'hFFFFFFFF;
-> write;
@ (writeDone);
reg_addr = (`chNum << 6) + `CODE_BITMASK1_OFFSET;
wdata = 32'h08800000;
-> write;
@ (writeDone);
reg_addr = (`chNum << 6) + `CODE_OUT_BITMASK1_OFFSET;
wdata = 32'h0x02000000;
-> write;
@ (writeDone);
reg_addr = (`chNum << 6) + `CODE_STATE2_OFFSET;
wdata = 32'h00000000;
-> write;
@ (writeDone);
reg_addr = (`chNum << 6) + `CODE_BITMASK2_OFFSET;
wdata = 32'h00000000;
-> write;
@ (writeDone);
reg_addr = (`chNum << 6) + `CODE_OUT_BITMASK2_OFFSET;
wdata = 32'h0x00000000;
-> write;
@ (writeDone);
reg_addr = (`chNum << 6) + `PRN_LENGTH_OFFSET;
wdata = 511-1;
-> write;
@ (writeDone);
reg_addr = (`chNum << 6) + `PRN_LENGTH1_OFFSET;
wdata = 511-1;
-> write;
@ (writeDone);
reg_addr = (`chNum << 6) + `CHIP_MAX_OFFSET;
wdata = 511-1;
-> write;
@ (writeDone);
reg_addr = (`chNum << 6) + `PRN_INIT_OFFSET;
wdata = 0;
-> write;
@ (writeDone);
reg_addr = (`chNum << 6) + `PRN_INIT1_OFFSET;
wdata = 0;
-> write;
@ (writeDone);
reg_addr = (`chNum << 6) + `BOC_REGS_OFFSET;
wdata = 0;
-> write;
@ (writeDone);
reg_addr = (`chNum << 6) + `CODE_RATE_OFFSET;
wdata = 20783411;
-> write;
@ (writeDone);
reg_addr = (`chNum << 6) + `CODE_PHASE_OFFSET;
wdata = 0;
-> write;
@ (writeDone);
reg_addr = (`chNum << 6) + `EPOCH_AND_TOW_OFFSET;
wdata = 0;
-> write;
@ (writeDone);
reg_addr = (`chNum << 6) + `EPOCH_AND_SYMB_MAX_OFFSET;
wdata = 1000-1;
-> write;
@ (writeDone);
reg_addr = (`chNum << 6) + `CODE_DOINIT_OFFSET;
wdata = {16'h12AB, 16'b0};
-> write;
@ (writeDone);
end
endmodule
TB задает два типа тактовых сигналов - один процессора, другой от РЧБ. В бесконечном цикле генерируются импульс эпохи и импульс снятия измерений. В TEST CASE дается сигнал сброса, затем канал имитатора конфигурируется под сигнал ГЛОНАСС СТ.
А вот что мы добавляем в prj_imitator.tcl, чтобы этот набор для моделирования разворачивался вместе с проектом:
# Create 'sim_imitator_channel' fileset (if not found)
if {[string equal [get_filesets -quiet sim_imitator_channel] ""]} {
create_fileset -simset sim_imitator_channel
}
set obj [get_filesets sim_imitator_channel]
set files [list \
"[file normalize "$origin_dir/tb/imitator_channel_tb.v"]"\
"[file normalize "$origin_dir/verilog/top/global_param.v"]"\
"[file normalize "$origin_dir/verilog/imitator_channel.v"]"\
"[file normalize "$origin_dir/verilog/imichnl_synthesizer.v"]"\
"[file normalize "$origin_dir/verilog/imichnl_sin_table.v"]"\
"[file normalize "$origin_dir/verilog/imichnl_param.v"]"\
"[file normalize "$origin_dir/verilog/imichnl_regfile.v"]"\
"[file normalize "$origin_dir/verilog/imichnl_cos_table.v"]"\
"[file normalize "$origin_dir/verilog/imichnl_delay_reg.v"]"\
"[file normalize "$origin_dir/$sub_dir/correlator/verilog/flag_sync.v"]"\
"[file normalize "$origin_dir/$sub_dir/correlator/verilog/flag_sync_n.v"]"\
"[file normalize "$origin_dir/$sub_dir/correlator/verilog/time_generator.v"]"\
"[file normalize "$origin_dir/$sub_dir/correlator/verilog/channel_shift_reg.v"]"\
"[file normalize "$origin_dir/$sub_dir/sync/verilog/level_sync.v"]"\
"[file normalize "$origin_dir/$sub_dir/sync/verilog/signal_sync.v"]"\
"[file normalize "$origin_dir/tb/imitator_channel_tb_behav.wcfg"]"\
]
add_files -norecurse -fileset $obj $files
# Set 'sim_imitator_channel' fileset properties
set obj [get_filesets sim_imitator_channel]
set_property "include_dirs" "$origin_dir/verilog $origin_dir/verilog/top" $obj
set_property "runtime" "3000000ns" $obj
set_property "source_set" "" $obj
set_property "top" "imitator_channel_tb" $obj
set_property "xelab.nosort" "1" $obj
set_property "xelab.unifast" "" $obj
set_property "xsim.simulate.runtime" "3000000ns" $obj
set_property "xsim.view" "$origin_dir/tb/imitator_channel_tb_behav.wcfg" $obj
# ============ End of imitator_channel module test bench ====================
Обсудим команды, которые добавляются в скрипт. В первую очередь создается новый набор для симуляции, ему присваивается название sim_imitator_channel
create_fileset -simset sim_imitator_channel
}
Далее в этот набор добавляются файлы:
set files [list \
"[file normalize "$origin_dir/tb/imitator_channel_tb.v"]"\
"[file normalize "$origin_dir/verilog/top/global_param.v"]"\
"[file normalize "$origin_dir/verilog/imitator_channel.v"]"\
"[file normalize "$origin_dir/verilog/imichnl_synthesizer.v"]"\
"[file normalize "$origin_dir/verilog/imichnl_sin_table.v"]"\
"[file normalize "$origin_dir/verilog/imichnl_param.v"]"\
"[file normalize "$origin_dir/verilog/imichnl_regfile.v"]"\
"[file normalize "$origin_dir/verilog/imichnl_cos_table.v"]"\
"[file normalize "$origin_dir/verilog/imichnl_delay_reg.v"]"\
"[file normalize "$origin_dir/$sub_dir/correlator/verilog/flag_sync.v"]"\
"[file normalize "$origin_dir/$sub_dir/correlator/verilog/flag_sync_n.v"]"\
"[file normalize "$origin_dir/$sub_dir/correlator/verilog/time_generator.v"]"\
"[file normalize "$origin_dir/$sub_dir/correlator/verilog/channel_shift_reg.v"]"\
"[file normalize "$origin_dir/$sub_dir/sync/verilog/level_sync.v"]"\
"[file normalize "$origin_dir/$sub_dir/sync/verilog/signal_sync.v"]"\
"[file normalize "$origin_dir/tb/imitator_channel_tb_behav.wcfg"]"\
]
add_files -norecurse -fileset $obj $files
Далее указываются директории, в которых будет производиться поиск файл, подключенных с помощью директивы `include
:
set_property "include_dirs" "$origin_dir/verilog $origin_dir/verilog/top" $obj
Указывается топовый модуль для моделирования:
Указывается топовый модуль для моделирования:
set_property "xsim.simulate.runtime" "3000000ns" $obj
Указывается wave-форма:
Также в скрипте регенерации мы можем указать, какой набор симуляции считать активным по-умолчанию:
[править] Итоговый скрипт регенерации проекта
Итоговый скрипт регенерации проекта imitator будет выглядеть так:
#
# Vivado (TM) v2015.3 (64-bit)
#
# prj_imitator.tcl: Tcl script for re-creating project 'imitator'
#
# Generated by Vivado on Tue Mar 22 10:11:05 +0300 2016
# IP Build 1367837 on Mon Sep 28 08:56:14 MDT 2015
#
# This file contains the Vivado Tcl commands for re-creating the project to the state*
# when this script was generated. In order to re-create the project, please source this
# file in the Vivado Tcl Shell.
#
# * Note that the runs in the created project will be configured the same way as the
# original project, however they will not be launched automatically. To regenerate the
# run results please launch the synthesis/implementation runs as needed.
#
# Set the reference directory for source file relative paths (by default the value is script directory path)
set origin_dir "."
set sub_dir "sub"
set prj_name "imitator"
set prj_dir_name "prj_imitator"
set topmodule_name "imitator_top"
# Use origin directory path location variable, if specified in the tcl shell
if { [info exists ::origin_dir_loc] } {
set origin_dir $::origin_dir_loc
}
variable script_file
set script_file "prj_$prj_name.tcl"
# Help information for this script
proc help {} {
variable script_file
puts "\nDescription:"
puts "Recreate a Vivado project from this script. The created project will be"
puts "functionally equivalent to the original project for which this script was"
puts "generated. The script contains commands for creating a project, filesets,"
puts "runs, adding/importing sources and setting properties on various objects.\n"
puts "Syntax:"
puts "$script_file"
puts "$script_file -tclargs \[--origin_dir <path>\]"
puts "$script_file -tclargs \[--help\]\n"
puts "Usage:"
puts "Name Description"
puts "-------------------------------------------------------------------------"
puts "\[--origin_dir <path>\] Determine source file paths wrt this path. Default"
puts " origin_dir path value is \".\", otherwise, the value"
puts " that was set with the \"-paths_relative_to\" switch"
puts " when this script was generated.\n"
puts "\[--help\] Print help information for this script"
puts "-------------------------------------------------------------------------\n"
exit 0
}
if { $::argc > 0 } {
for {set i 0} {$i < [llength $::argc]} {incr i} {
set option [string trim [lindex $::argv $i]]
switch -regexp -- $option {
"--origin_dir" { incr i; set origin_dir [lindex $::argv $i] }
"--help" { help }
default {
if { [regexp {^-} $option] } {
puts "ERROR: Unknown option '$option' specified, please type '$script_file -tclargs --help' for usage info.\n"
return 1
}
}
}
}
}
# Create project
create_project $prj_name ./$prj_dir_name
# Set the directory path for the new project
set proj_dir [get_property directory [current_project]]
# Set project properties
set obj [get_projects $prj_name]
set_property "default_lib" "xil_defaultlib" $obj
set_property "part" "xc7z045fbg676-2" $obj
set_property "sim.ip.auto_export_scripts" "1" $obj
set_property "simulator_language" "Mixed" $obj
set_property "source_mgmt_mode" "DisplayOnly" $obj
# Create 'sources_1' fileset (if not found)
if {[string equal [get_filesets -quiet sources_1] ""]} {
create_fileset -srcset sources_1
}
# Set 'sources_1' fileset object
set obj [get_filesets sources_1]
set files [list \
"[file normalize "$origin_dir/verilog/top/$topmodule_name.v"]"\
"[file normalize "$origin_dir/verilog/imitator.v"]"\
"[file normalize "$origin_dir/verilog/imitator_channel.v"]"\
"[file normalize "$origin_dir/verilog/imichnl_regfile.v"]"\
"[file normalize "$origin_dir/verilog/imichnl_param.v"]"\
"[file normalize "$origin_dir/verilog/imichnl_delay_reg.v"]"\
"[file normalize "$origin_dir/verilog/imichnl_sin_table.v"]"\
"[file normalize "$origin_dir/verilog/imichnl_cos_table.v"]"\
"[file normalize "$origin_dir/verilog/imichnl_synthesizer.v"]"\
"[file normalize "$origin_dir/$sub_dir/correlator/verilog/flag_sync.v"]"\
"[file normalize "$origin_dir/$sub_dir/correlator/verilog/flag_sync_n.v"]"\
"[file normalize "$origin_dir/$sub_dir/correlator/verilog/channel_shift_reg.v"]"\
"[file normalize "$origin_dir/$sub_dir/correlator/verilog/time_generator.v"]"\
"[file normalize "$origin_dir/$sub_dir/sync/verilog/signal_sync.v"]"\
"[file normalize "$origin_dir/$sub_dir/sync/verilog/level_sync.v"]"\
]
add_files -norecurse -fileset $obj $files
# Set 'sources_1' fileset file properties for remote files
# None
# Set 'sources_1' fileset properties
set obj [get_filesets sources_1]
set_property "include_dirs" "$origin_dir/verilog $origin_dir/verilog/top" $obj
set_property "top" "$topmodule_name" $obj
# Create 'constrs_1' fileset (if not found)
if {[string equal [get_filesets -quiet constrs_1] ""]} {
create_fileset -constrset constrs_1
}
# Set 'constrs_1' fileset object
set obj [get_filesets constrs_1]
# Create 'sim_1' fileset (if not found)
# It should exist! If Vivado doesn't found it, once will be generated
if {[string equal [get_filesets -quiet sim_1] ""]} {
create_fileset -simset sim_1
}
# Set 'sim_sim_1' fileset properties
set obj [get_filesets sim_1]
set_property "source_set" "" $obj
set_property "top" "$topmodule_name" $obj
set_property "xelab.nosort" "1" $obj
set_property "xelab.unifast" "" $obj
# =============== imichnl_synthesizer module test bench ====================
# Create 'sim_imichnl_synthesizer' fileset (if not found)
if {[string equal [get_filesets -quiet sim_imichnl_synthesizer] ""]} {
create_fileset -simset sim_imichnl_synthesizer
}
set obj [get_filesets sim_imichnl_synthesizer]
set files [list \
"[file normalize "$origin_dir/tb/imichnl_synthesizer_tb.v"]"\
"[file normalize "$origin_dir/tb/imichnl_synthesizer_tb_behav.wcfg"]"\
"[file normalize "$origin_dir/verilog/imichnl_synthesizer.v"]"\
]
add_files -norecurse -fileset $obj $files
# Set 'sim_imichnl_synthesizer' fileset properties
set obj [get_filesets sim_imichnl_synthesizer]
set_property "source_set" "" $obj
set_property "top" "imichnl_synthesizer_tb" $obj
set_property "xelab.nosort" "1" $obj
set_property "xelab.unifast" "" $obj
set_property "xsim.view" "$origin_dir/tb/imichnl_synthesizer_tb_behav.wcfg" $obj
# ============ End of imichnl_synthesizer module test bench ====================
# =============== imitator_channel module test bench ====================
# Create 'sim_imitator_channel' fileset (if not found)
if {[string equal [get_filesets -quiet sim_imitator_channel] ""]} {
create_fileset -simset sim_imitator_channel
}
set obj [get_filesets sim_imitator_channel]
set files [list \
"[file normalize "$origin_dir/tb/imitator_channel_tb.v"]"\
"[file normalize "$origin_dir/verilog/top/global_param.v"]"\
"[file normalize "$origin_dir/verilog/imitator_channel.v"]"\
"[file normalize "$origin_dir/verilog/imichnl_synthesizer.v"]"\
"[file normalize "$origin_dir/verilog/imichnl_sin_table.v"]"\
"[file normalize "$origin_dir/verilog/imichnl_param.v"]"\
"[file normalize "$origin_dir/verilog/imichnl_regfile.v"]"\
"[file normalize "$origin_dir/verilog/imichnl_cos_table.v"]"\
"[file normalize "$origin_dir/verilog/imichnl_delay_reg.v"]"\
"[file normalize "$origin_dir/$sub_dir/correlator/verilog/flag_sync.v"]"\
"[file normalize "$origin_dir/$sub_dir/correlator/verilog/flag_sync_n.v"]"\
"[file normalize "$origin_dir/$sub_dir/correlator/verilog/time_generator.v"]"\
"[file normalize "$origin_dir/$sub_dir/correlator/verilog/channel_shift_reg.v"]"\
"[file normalize "$origin_dir/$sub_dir/sync/verilog/level_sync.v"]"\
"[file normalize "$origin_dir/$sub_dir/sync/verilog/signal_sync.v"]"\
"[file normalize "$origin_dir/tb/imitator_channel_tb_behav.wcfg"]"\
]
add_files -norecurse -fileset $obj $files
# Set 'sim_imitator_channel' fileset properties
set obj [get_filesets sim_imitator_channel]
set_property "include_dirs" "$origin_dir/verilog $origin_dir/verilog/top" $obj
set_property "runtime" "3000000ns" $obj
set_property "source_set" "" $obj
set_property "top" "imitator_channel_tb" $obj
set_property "xelab.nosort" "1" $obj
set_property "xelab.unifast" "" $obj
set_property "xsim.simulate.runtime" "3000000ns" $obj
set_property "xsim.view" "$origin_dir/tb/imitator_channel_tb_behav.wcfg" $obj
# ============ End of imitator_channel module test bench ====================
current_fileset -simset [ get_filesets sim_imitator_channel ]
# Create 'synth_1' run (if not found)
if {[string equal [get_runs -quiet synth_1] ""]} {
create_run -name synth_1 -part xc7z045fbg676-2 -flow {Vivado Synthesis 2014} -strategy "Vivado Synthesis Defaults" -constrset constrs_1
} else {
set_property strategy "Vivado Synthesis Defaults" [get_runs synth_1]
set_property flow "Vivado Synthesis 2014" [get_runs synth_1]
}
set obj [get_runs synth_1]
set_property "part" "xc7z045fbg676-2" $obj
# set the current synth run
current_run -synthesis [get_runs synth_1]
# Create 'impl_1' run (if not found)
if {[string equal [get_runs -quiet impl_1] ""]} {
create_run -name impl_1 -part xc7z045fbg676-2 -flow {Vivado Implementation 2015} -strategy "Performance_Explore" -constrset constrs_1 -parent_run synth_1
} else {
set_property strategy "Performance_Explore" [get_runs impl_1]
set_property flow "Vivado Implementation 2015" [get_runs impl_1]
}
set obj [get_runs impl_1]
set_property "part" "xc7z045fbg676-2" $obj
set_property "steps.opt_design.args.directive" "Explore" $obj
set_property "steps.place_design.args.directive" "Explore" $obj
set_property "steps.phys_opt_design.is_enabled" "1" $obj
set_property "steps.phys_opt_design.args.directive" "Explore" $obj
set_property "steps.route_design.args.directive" "Explore" $obj
set_property "steps.write_bitstream.args.readback_file" "0" $obj
set_property "steps.write_bitstream.args.verbose" "0" $obj
# set the current impl run
current_run -implementation [get_runs impl_1]
puts "INFO: Project created:$prj_name"
Добавляем файл регенерации проекта prj_imitator.tcl и файлы в каталоге tb в коммит.
[править] У другого пользователя
Теперь оба TB'а будут храниться в системе контроля версий. При запуске скрипта регенерации у нового пользователя они будут разворачиваться и настраиваться. Пользователю останется их только запустить.
[править] Ссылки
- Easyelectronics:TestBench на Verilog для новичков
- Xilinx UG900: Logic Simulation
- AR64000: Understanding Waveform Database file (WDB) and Wave Configuration File (WCFG)
- Verilog — инструмент разработки цифровых электронных схем: О типах данных
- Verilog — инструмент разработки цифровых электронных схем: Операторы
- Verilog — инструмент разработки цифровых электронных схем: О моделируемых конструкциях
- Verilog — инструмент разработки цифровых электронных схем: О синтезируемых конструкциях
- Verilog-2001
- Signed Arithmetic in Verilog 2001 – Opportunities and Hazards