이 페이지는 timing에 대한 일련의 페이지 에 속합니다. 이전 페이지에서는 timing 계산의 이론을 설명하고, clock period constraint를 논의하고, timing closure의 원리를 보여주고, Tcl 환경을 살펴보기 시작했습니다. 이 페이지에서는 timing constraints가 구체적으로 될 수 있도록 하는 commands를 설명합니다.
개요
timing constraints 의 목적은 design 에 있는 모든 paths 의 timing 요구 사항이 충족되도록 하는 것입니다. 다른 paths 에는 다른 요구 사항이 있을 수 있으므로 각 timing constraint는 관련 paths그룹으로 지정되어야 하며 다른 항목은 포함하지 않아야 합니다.
paths를 정의하는 유일한 방법은 이러한 paths와 관련된 logic elements를 참조하는 것입니다. 따라서 logic elements의 올바른 그룹을 선택하는 정확한 표현식을 작성할 수 있는 능력이 중요합니다. 즉, get_clocks, get_ports 및 get_cells와 같은 commands를 올바르게 사용하여 결과가 정확히 필요한 대로 되도록 해야 합니다.
이 페이지는 logic elements그룹을 설명하는 기본 기술을 살펴봅니다. 여기의 거의 모든 내용은 SDC 구문에 특화되어 있습니다. 또한 Tcl command-line 인터페이스도 사용할 수 있다고 가정하겠습니다. 이는 Vivado 와 Quartus, 그리고 최근의 대부분의 FPGA tools 에도 해당합니다.
일부 FPGA 공급업체는 Synopsys의 소프트웨어가 자사 도구에 통합되어 있다고 공개적으로 선언하므로 자연스럽게 이러한 도구는 동일한 Tcl commands를 사용합니다. 반면 Vivado는 Synopsys에서 파생된 것으로 간주되지 않습니다. 그럼에도 불구하고 두 가지 사이에는 몇 가지 눈에 띄는 유사점이 있으며, 특히 Tcl 인터페이스와 관련하여 그렇습니다. Quartus는 독립적으로 개발된 것으로 보이며, 따라서 Tcl 인터페이스가 약간 다릅니다.
언뜻 보기에 이 페이지가 Tcl scripting의 세부 사항에 너무 많이 들어가는 것처럼 보일 수 있습니다. 사실은 그 반대입니다. 정확성은 매우 중요하며, 이는 commands가 어떻게 해석되는지 정확히 이해해야만 달성할 수 있습니다. 사실, 이 페이지는 기본 원리만 설명합니다. 설명서를 읽는 것만큼 좋은 것은 없습니다.
FPGA tools로부터 안내 받기
timing constraints를 쓰기 시작하는 것은 종종 어렵습니다. 처리해야 할 세부 사항이 너무 많기 때문입니다. FPGA tools가 이를 도울 수 있습니다.
"help" command는 Tcl command에서 문서를 보는 데 Tcl console 에서 사용할 수 있습니다. 이는 종종 공식 문서(예: pdf 형식)와 정확히 동일한 정보입니다.
대부분의 FPGA tools는 timing constraints를 자동으로 생성하기 위한 GUI 인터페이스를 가지고 있습니다. 작업 방법은 일반적으로 필요한 timing constraints 유형을 선택하는 데 사용됩니다. 다음 단계는 목록에서 관련 logic elements를 선택하는 것입니다. 그 결과 SDC 파일에 추가되는 하나 또는 여러 개의 timing constraints가 생성됩니다.
이러한 종류의 wizard를 사용하면 Tcl 구문에 대한 힌트를 얻을 수 있습니다. 경우에 따라 자동으로 생성된 constraints를 그대로 사용할 수도 있습니다. 그러나 대부분의 경우 wizard의 출력을 사용하려는 유혹을 뿌리치고 대신 timing constraint 의 목적을 가장 잘 달성하는 방법을 신중하게 생각해 볼 가치가 있습니다. 프로젝트가 어떻게 발전할 것으로 예상되는지 고려하고 시간이 지나도 timing constraints가 올바른 상태를 유지하는지 확인하는 것도 중요합니다. GUI wizard 와의 빠른 세션으로는 이를 달성할 수 없습니다.
일부 FPGA tools 에는 design에서 logic elements를 찾기 위한 GUI interface 도 있습니다. 이 인터페이스를 사용하면 요청된 검색에 해당하는 Tcl command가 종종 표시됩니다. 이는 특정 logic elements를 찾기 위한 Tcl 표현식을 얻는 편리한 방법입니다. 다시 한 번, 이러한 표현식은 추가 작업의 시작점으로 취급해야 합니다.
대부분의 FPGA tools 의 세 번째 기능은 commands를 입력(또는 Copy-Paste사용)하고 화면에서 결과를 볼 수 있는 Tcl command-line console 입니다. 이를 통해 commands 와 search patterns를 테스트하고 어떤 objects가 발견되는지 확인할 수 있습니다. 이는 search pattern이 올바른지 확인하는 데 도움이 될 수 있습니다.
결론적으로, FPGA tools는 Tcl command를 만드는 데 도움이 될 수 있습니다. 하지만 이미 말했듯이, 도구로 만든 Tcl commands는 시간이 지나도 제대로 작동하도록 보장되는 정확한 search patterns를 작성하기 위한 기반에 불과해야 합니다.
이제 timing constraints를 만드는 게으른 방법을 알았으니 이제 이를 제대로 수행하는 방법을 배울 차례입니다.
netlist: 짧은 알림
Tcl 환경에 대해 더 구체적으로 알아보기 전에 netlists에 대해 간략하게 상기시켜 드리고자 합니다.
netlists 의 가장 일반적인 파일 형식은 EDIF가 지만 많은 FPGA tools 도 자체 특정 형식을 가지고 있습니다. 일반적으로 synthesizer는 netlist를 생성하지만 도구가 나중에 변경할 수도 있습니다. 이 파일은 기본 구성 요소와 이러한 구성 요소 간의 연결 측면에서 logic design을 설명합니다. 그래픽 이미지가 아닌 텍스트 표현을 사용하는 배선도와 같습니다.
netlist 의 구성 요소를 "cells"라고 합니다. 대부분의 cells는 LUT, combinatorial logic 또는 flip-flop의 또 다른 작은 요소입니다. 또한 Verilog 코드(예: IP cores)에서 black boxes 의 instantiations는 netlist에서 cell 로 표시됩니다. 다른 cells는 PLLs, block RAMs및 대형 logic elements ("hard IPs")입니다. PCIe blocks, MGT transceivers, processors 등
각 cell 에는 여러 개의 pins 가 있습니다. 이 pins는 물리적 전자 부품의 외부 연결 지점과 같습니다. 그러나 이것을 FPGA의 외부 I/O와 혼동하지 마십시오. cells 와 pins는 모두 FPGA내부에 있습니다.
netlist 의 상호 연결은 nets로 구성됩니다. 이들은 물리적 전선과 같습니다. 예를 들어, signal이 Verilog에서 "wire"로 정의되면 net이 됩니다. net은 2개 이상의 pins를 연결하며, 그렇게 함으로써 이러한 pins가 항상 동일한 logic level을 갖도록 보장합니다.
logic elements를 objects로 표현
FPGA tools가 프로젝트의 implementation을 통과할 때 실제로 일어나는 일은 Tcl scripts가 실행된다는 것입니다. 이는 Vivado 와 Quartus 및 여러 다른 FPGA tools에 해당합니다. 다르게 작동하는 소프트웨어에서도 여전히 다음과 같은 가정을 하는 것이 옳습니다. 모든 것이 하나의 큰 Tcl script 라는 환상은 constraints 및 기타 script 파일에 대한 API 에 의해 생성됩니다.
이 Tcl script 의 환경에서(상상적이든 아니든) 모든 logic elements는 다른 classes에서 생성된 objects 로 표현됩니다. 이러한 objects는 SDC 파일(또는 Xilinx의 XDC 파일)에서 timing constraints 에 의해 액세스될 수 있습니다. 마찬가지로 Tcl command-line console 와 Tcl scripts 의 Tcl commands는 이러한 objects에 액세스할 수 있습니다.
이것들은 SDC 구문으로 작동하는 모든 FPGA tools 에서 지원하는 5개의 Tcl commands 입니다. 이 commands는 다른 유형(즉, 다른 classes)의 objects를 찾는 데 사용됩니다. 저는 이미 이전 timing constraints예제에서 이것들을 사용했습니다. 사실, 이 commands없이는 의미 있는 timing constraints를 작성하는 것은 불가능합니다.
arguments가 하나도 없는 경우, 이 commands는 관련 유형의 모든 objects를 찾습니다. 나중에 검색을 세분화하는 방법을 살펴보겠습니다.
- get_cells: 이 command는 cells ( netlist의 구성 요소)를 나타내는 objects를 찾습니다.
- get_pins: 이 command는 pins ( cells의 연결 지점)를 나타내는 objects를 찾습니다.
- get_nets: 이 command는 nets ( netlist의 "와이어")를 나타내는 objects를 찾습니다.
- get_ports: 이 command는 FPGA design의 외부 I/O ports를 나타내는 objects를 찾습니다. 이것들은 toplevel module의 ports 입니다.
- get_clocks: 이 command는 clock objects를 찾습니다. 여기에 언급된 objects 중에서 clock objects는 design의 logic element 에 해당하지 않는 유일한 objects 입니다. 오히려 clock objects는 앞서 설명한 대로 clocks에 대한 정보를 포함하는 데 사용됩니다.
이 다섯 개의 commands를 제외하고, 각 FPGA tool 에는 자체 추가 commands 와 추가 objects가 있습니다. 예를 들어, Vivado 에는 all_ffs, all_registers, all_inputs, all_outputs, all_rams 및 이와 유사한 여러 다른 commands가 있습니다. Quartus는 이 중 일부를 지원하고 get_registers, get_keepers, get_nodes, get_fanins 및 get_fanouts 등도 있습니다.
이러한 objects 의 중요성은 FPGA design에서 logic elements를 참조하기 위해 timing constraints 에서 사용된다는 것입니다. 또한 Tcl scripts 에서 정보를 얻기 위해 사용될 수 있습니다(예: clock의 frequency). 각 FPGA tool 에는 Tcl scripts에서 이러한 objects 에 액세스하기 위한 자체 API가 있습니다. 예를 들어, 이 Tcl command는 Vivado 에서 clock period를 얻기 위해 사용될 수 있습니다.
> get_property PERIOD [get_clocks clk] 4.000
Quartus에서도 마찬가지입니다.
> get_clock_info -period [get_clocks clk] 4.000
이러한 차이점에도 불구하고 대부분의 FPGA tools는 SDC 형식의 timing constraints 구문과 의미에 동의합니다. 각 도구가 지원하는 API 에 대한 정보는 일반적으로 Tcl scripting 또는 Timing Closure와 관련된 제목이 있는 user guides 에서 찾을 수 있습니다.
달리 명시되지 않는 한 이 페이지의 예제는 Vivado를 기반으로 합니다.
Tcl에 대한 몇 가지 참고 사항
Tcl은 고대 언어이지만 logic design분야에서 이미 자리를 잡고 있기 때문에 이 언어가 곧 사라지지는 않을 것으로 예상됩니다. 운 좋게도 Tcl을 잘 알지 못하더라도 유용한 작업을 수행할 수 있습니다.
첫 번째는 이미 간략하게 언급한 대괄호("["와 "]")입니다. Tcl에서 이는 대괄호에서 command를 실행하고 결과를 해당 위치에 넣는 것을 의미합니다. shell scripting 또는 Perl에 익숙한 사람들에게는 backticks와 동일합니다. 예를 들어, 이 command에서 get_port는 이름이 "clk"인 port object 로 대체됩니다.
create_clock -period 4.000 -name clk [get_ports clk]
마찬가지로 이것은 다음과 같이 작성할 수 있습니다.
set the_clk_port [get_ports clk] create_clock -period 4.000 -name clk $the_clk_port
이 두 번째 예에서 보듯이, variables는 "set" 명령으로 정의되고 값이 할당됩니다. variable의 값에 액세스하려면 dollar sign ($)를 사용합니다. 다시 말하지만, shell script 및 Perl와 비슷합니다.
curly braces ("{" 및 "}")에 대해서는 이야기가 다릅니다. 다른 여러 언어와 마찬가지로 그 의미는 문맥에 따라 많이 달라집니다. Tcl에서 curly braces 의 덜 기대되는 의미 중 하나는 동봉된 string이 그대로 유지되어야 한다는 것입니다. 즉, 대체가 없어야 하며 whitespaces는 모든 character와 같은 것으로 간주되어야 합니다. 예를 들어 동일한 timing constraint를 다음과 같이 작성할 수 있습니다.
create_clock -period {4.000} -name {clk} [get_ports {clk}]
이 예에서 curly braces는 완전히 불필요하고, 이 command는 이전과 정확히 같은 것을 의미합니다. 불필요한 curly braces는 불행히도 흔하고, 종종 이 예에서와 정확히 마찬가지로 아무 의미가 없습니다.
Tcl console사용 팁
발견된 objects 의 수가 많은 경우가 종종 발생하여 검색 명령의 출력을 읽기 어렵습니다. 이는 간단한 Tcl commands로 해결할 수 있습니다. 이를 수행하는 방법은 사용하는 도구에 따라 달라집니다. Vivado를 사용하면 이 command는 design에 있는 모든 cells를 출력합니다. 각 cell은 별도의 줄에 인쇄되므로 cells가 많더라도 출력을 읽을 수 있습니다.
> join [get_cells -hierarchical] \n
GND
VCC
bar__0_i_1
bar_reg_OBUF_inst
bar_reg__0
[ ... ]
"join" 명령은 get_cell이 생성하는 array 의 각 요소 사이에 newline을 넣습니다.
Quartus를 사용하면 다음과 같은 결과를 얻을 수 있습니다.
join [query_collection -all [get_cells -hierarchical] ] \n
또는 query_collection을 보다 현명하게 사용하여:
query_collection -all -report_format [get_cells -hierarchical]
특정 요소 찾기
긴 소개가 끝나고 마침내 정말 흥미로운 것에 대해 이야기할 시간입니다. 아래 예제를 위해 나중에 사용 되는 다음 Verilog 코드를 참조하십시오.
module top(
input clk,
input foo,
output reg bar_reg,
output reg baz
);
reg foo_reg;
reg bar;
reg baz_metaguard;
wire pll_clk_8, pll_clk_6;
clk_wiz_1 pll_i
(.clk_in1(clk),
.clk_out1(pll_clk_8),
.clk_out2(pll_clk_6));
always @(posedge pll_clk_8)
foo_reg <= foo;
always @(posedge pll_clk_6)
begin
bar <= !foo_reg;
bar_reg <= bar;
end
always @(posedge clk)
begin
baz_metaguard <= bar;
baz <= baz_metaguard;
end
이 페이지 맨 위에 언급했듯이, timing constraints 의 정확도는 올바른 logic elements그룹을 선택하는 데 달려 있습니다. 따라서 위에 언급된 5개의 get_* commands 에서 검색 결과를 좁히는 것이 가능하고 필요합니다. 이를 수행하는 방법에는 여러 가지가 있지만 가장 일반적인 방법은 object의 이름을 기반으로 하는 것입니다. 가장 간단한 pattern은 우리가 찾고 있는 정확한 이름을 가진 단일 object를 찾는 것입니다. 예를 들어, Vivado의 Tcl console에서:
> get_ports clk clk
마찬가지로 특정 pattern와 일치하는 이름을 가진 모든 objects를 찾을 수 있습니다.
> get_pins pll_i/* pll_i/clk_in1 pll_i/clk_out1 pll_i/clk_out2
이 두 예의 출력은 objects입니다. Vivado의 Tcl console에서는 이러한 objects 의 이름이 편의상 인쇄되어 있습니다.
더욱 중요한 점은 각 FPGA tool이 이 search patterns와 관련하여 약간 다르게 동작한다는 것입니다. 여기의 예에서는 Vivado가 사용되었습니다. 다른 도구에도 동일한 원칙이 적용됩니다.
별표("*")는 wildcard character가 며 임의 개수의 characters를 대체합니다. 물음표("?")는 하나의 character를 대체합니다. 이것은 파일 이름이 있는 wildcards 와 동일하게 작동합니다.
파일 이름과 마찬가지로 wildcards는 hierarchy separator 와 일치하지 않습니다(예: "/"는 Vivado 및 "|"는 Quartus).
hierarchical path 와 파일 디렉토리 사이에도 유사점이 있습니다. 검색은 file system의 root directory 와 유사한 top-level hierarchy와 관련하여 이루어집니다. 예를 들면 다음과 같습니다.
> get_pins */clk_* pll_i/clk_in1 pll_i/clk_out1 pll_i/clk_out2 > get_pins pll_i/clk_out? pll_i/clk_out1 pll_i/clk_out2
hierarchy 에서 각 logic element 의 정확한 위치를 구체적으로 지정해야 하는 필요성은 종종 중요한 결점입니다. 우리가 찾고자 하는 logic elements는 종종 다른 위치에 있습니다. 이것은 "-hierarchical"로 해결됩니다. 이 flag이 있으면 hierarchy의 모든 위치에서 pattern을 검색합니다.
일반적으로 wildcards를 사용하여 logic elements를 찾는 것은 권장되지 않습니다. 유일한 예외는 search pattern이 매우 단순하거나 다른 선택이 없는 경우입니다. wildcards 와 "-hierarchical"를 사용하는 방법을 설명하고 이 방법의 한계를 보여주는 별도의 페이지 가 있습니다.
-filter사용
wildcards를 기반으로 하는 search patterns를 사용하면 몇 가지 단점이 있습니다. 가장 중요한 단점은 hierarchy를 정확하게 정의하거나 전혀 정의하지 않아야 한다는 것입니다. 한 가지 문제는 검색을 sub-hierarchy에 속한 objects 로 제한하는 것이 종종 바람직하다는 것입니다. 그러나 이것은 wildcards에서는 불가능하며 "-hierarchical" 옵션은 이 문제를 해결하지 못합니다.
이러한 이유 때문에 search patterns를 정의하는 기본 방법은 -filter 옵션을 사용하는 것입니다. 이 옵션은 boolean expression와 함께 제공됩니다. 이 옵션을 사용하면 이 expression이 true 인 검색 결과만 남습니다.
예를 들어,
> get_pins */clk_* pll_i/clk_in1 pll_i/clk_out1 pll_i/clk_out2 > get_pins */clk_* -filter {name =~ *2*} pll_i/clk_out2
이 예에서는 "name"라는 property가 wildcard덕분에 발견된 각 objects 에서 검사되었습니다. object는 이 property가 "*2*"와 일치하는 경우에만 검색 결과에 남아 있습니다. 즉, object 의 이름에 "2"가 포함된 경우에만 해당됩니다.
이 예는 실용적인 관점에서 흥미롭지 않습니다. "-hierarchical"를 사용하면 훨씬 더 흥미로워집니다. search pattern이 하나도 없으면 모든 objects가 발견됩니다. 다시 말해, 이 command는 모든 hierarchies에서 모든 pins를 발견합니다.
get_pins -hierarchical
이 시점에서 -filter로 검색 결과를 좁힐 수 있습니다.
> get_pins -hierarchical -filter {name =~ pll_i/*/*out1 } pll_i/inst/clk_out1 > get_pins -hierarchical -filter {name =~ pll_i/*out1 } pll_i/clk_out1 pll_i/inst/clk_out1 > get_pins -hierarchical -filter {name =~ *out1 } pll_i/clk_out1 pll_i/inst/clk_out1
curly braces ("{" 및 "}")의 의미는 단지 그 안에 있는 부분을 Tcl interpreter로 수정해서는 안된다는 것입니다.
또한 search pattern은 -filter 옵션에 속하며 다르게 작동합니다. "name"를 object의 property 로 취급합니다. 따라서 모든 characters는 동일하게 취급됩니다. "/"는 특별한 의미가 없습니다. "/"가 hierarchy separator라는 것은 중요하지 않습니다. "/"를 포함한 모든 문자는 wildcard ("*")와 일치할 수 있습니다. 마찬가지로 "/"를 포함한 모든 문자를 search pattern에서 사용할 수 있습니다. 이것은 물론 -filter없이는 사실이 아닙니다.
모든 character가 "*"와 일치할 수 있다는 사실은 -filter를 더 강력한 도구로 만들지만 이 장점은 실수할 가능성도 있습니다. 위의 예에서 볼 수 있듯이 순진한 "*"가 실수로 "pll_i/clk_" 및 "pll_i/inst/clk_" 모두와 일치할 수 있다는 사실을 잊기 쉽습니다.
이 기능의 올바른 사용은 hierarchy에서 알려진 이름을 가진 logic element를 찾는 것입니다.
> get_pins -hierarchical -filter {name =~ */clkout2_buf/O } pll_i/inst/clkout2_buf/O
design 에 "clkout2_buf"라는 이름을 가진 cell이 하나만 있다고 확신한다면 이는 맞습니다. 이 command를 사용하면 이 logic element를 포함하는 module이 project의 hierarchy에서 옮겨져도 이 cell 의 output pin이 항상 발견됩니다. 실제 상황에서는 "clkout2_buf"보다 더 고유한 이름을 선택하는 것이 좋습니다.
동일한 방법이 get_cells 및 get_nets에서 작동합니다. 예를 들면 다음과 같습니다.
> get_cells -hierarchical -filter {name =~ */clk*_buf} pll_i/inst/clkf_buf pll_i/inst/clkout1_buf pll_i/inst/clkout2_buf
하지만 -filter는 이름뿐만 아니라 모든 properties에서 작동합니다. 따라서 이 command는 이름에 "bar"가 있는 모든 registers를 찾습니다.
get_cells -hier -filter {primitive_type =~ register.*.* && name =~ *bar*}
logical AND를 의미하는 "&&" 연산자에 유의하십시오( Verilog 및 C와 동일).
이 command에서 "primitive_type"와 "name"는 단지 properties의 이름일 뿐입니다. "=~" 연산자는 비교를 하고 wildcards를 허용합니다.
object 의 properties는 "report_property" command ( Vivado)와 함께 나열될 수 있습니다.
따라서 -filter는 작업하기 유연합니다. 안타깝게도 모든 FPGA tools에서 사용할 수 있는 것은 아닙니다.
Vivado 에는 -filter와 동일한 작업을 하는 filter라는 command가 있습니다. 따라서 다음 두 commands는 동등합니다.
set result [get_cells -hierarchical -filter {name =~ *_reg}] set result [filter [get_cells -hierarchical] {name =~ *_reg}]
두 번째 형식은 objects 목록이 variable에 저장될 때 유용합니다. 따라서 위의 두 commands 도 이것과 동일합니다.
set all_cells [get_cells -hierarchical]
set result [filter $all_cells {name =~ *_reg}]
-regex사용
regular expressions 에 익숙한 사람들은 이 옵션을 사용하고 싶을 수 있습니다. 보통 이렇게 하는 것은 좋지 않은데, 주로 다른 사람들이 timing constraints를 이해하기 어렵게 만들기 때문입니다. regular expressions를 지원하는 FPGA tools는 보통 -filter 옵션도 지원하므로 거의 항상 -filter를 사용하는 것이 좋습니다.
일반적인 search pattern 의 주요 문제는 hierarchy separator가 wildcard와 일치하지 않는다는 것입니다.
따라서 -regexp은 다음 몇 가지 예와 같이 이 문제를 해결할 수 있습니다.
> get_pins -hierarchical -regexp {.+/clk_out[123]} pll_i/clk_out1 pll_i/clk_out2 pll_i/inst/clk_out1 pll_i/inst/clk_out2 > get_pins {pll_i/[^/]+/clk[^/]+} -hierarchical -regexp pll_i/inst/clk_in1 pll_i/inst/clk_out1 pll_i/inst/clk_out2
첫 번째 command는 "."가 모든 character와 일치함을 보여줍니다. 여기에는 "/"( hierarchy separator)가 포함됩니다.
두 번째 command는 "[^/]+"가 hierarchy separator를 제외한 모든 것과 일치하는 방법을 보여줍니다. 따라서 검색 결과의 hierarchy 에 대한 정확한 깊이를 제어할 수 있습니다. 이 command는 또한 search pattern이 -regexp의 argument가 아니라 -regexp이 search pattern의 구문을 변경한다는 것을 보여줍니다.
regular expression은 object의 전체 이름과 일치해야 합니다. 즉, 도구는 암시적으로 regular expression의 시작 부분에 "^"를 추가하고 끝에 "$"를 추가합니다.
그러나 동일한 결과를 얻을 수 있는 다른 방법이 있다면 -regex를 사용하지 마십시오. 대부분의 다른 FPGA designers는 search pattern을 이해할 수 없습니다.
-of_object사용
이름에 따라 objects를 찾는 대신 -of_object는 다른 objects와의 관계에 따라 objects를 찾을 수 있습니다. 대부분의 경우 "-of_objects"는 대략 "~에 연결됨"을 의미합니다.
예를 들어, net에 연결된 모든 pins를 찾으려면:
> get_pins -of_objects [get_nets bar] bar_reg_reg/D baz_metaguard_reg/D bar_reg__0/Q
또는 cell의 모든 pins :
> get_pins -of_objects [get_cells bar_reg_reg] bar_reg_reg/Q bar_reg_reg/C bar_reg_reg/CE bar_reg_reg/D bar_reg_reg/R
또는 clock의 기원인 pin :
> get_pins -of_objects [get_clocks clk_out1_clk_wiz_1] pll_i/inst/mmcme3_adv_inst/CLKOUT0
동일한 방법으로 nets를 찾을 수 있습니다. 예를 들어 어떤 nets가 특정 pin에 연결되어 있습니까?
> get_nets -of_objects [get_pins bar_reg_reg/C] pll_clk_6
또는 관련 cell에 연결된 nets는 무엇입니까?
> get_nets -of_objects [get_cells bar_reg_reg] bar_reg_OBUF pll_clk_6 <const1> bar <const0>
마찬가지로 이 방법으로 cells를 검색할 수 있습니다. 예를 들어 어떤 cells가 @pll_clk_6에 연결되어 있습니까?
> get_cells -of_objects [get_nets pll_clk_6]
bar_reg__0 bar_reg_reg pll_i
"pll_i"는 Clock Wizard의 IP의 instantiation name 입니다. 검색 결과가 원하는 것은 아닐 것입니다. 그러니 검색 결과를 flip-flops로만 좁히는 게 어떨까요?
> get_cells -of_objects [get_nets pll_clk_6] -filter {primitive_type =~ register.*.*} bar_reg__0 bar_reg_reg
지금까지 -of_objects를 사용한 위의 예는 pins, nets 및 cells가 서로를 참조할 수 있는 방법을 보여주었습니다. 하지만 다음 옵션을 사용하여 clock objects를 찾을 수도 있습니다.
> get_clocks -of_objects [get_nets pll_clk_6] clk_out2_clk_wiz_1 > get_clocks -of_objects [get_cells bar_reg_reg] clk_out2_clk_wiz_1 > get_clocks -of_objects [get_pins bar_reg_reg/C] clk_out2_clk_wiz_1
이 세 개의 commands는 연결된 logic element 에 따라 clock을 찾는 방법을 보여줍니다. 이 logic element가 cell인 경우 두 개 이상의 결과가 있을 수 있습니다. 예를 들어:
> get_clocks -of_objects [get_cells pll_i] clk clk_out1_clk_wiz_1 clk_out2_clk_wiz_1
"pll_i"는 IP가 므로 pins는 이 module의 ports 입니다.
> get_pins -of_objects [get_cells pll_i] pll_i/clk_in1 pll_i/clk_out1 pll_i/clk_out2
따라서 특정 clock을 찾으려면 get_pins가 더 안전합니다.
> get_clocks -of_objects [get_pins pll_i/clk_out2] clk_out2_clk_wiz_1
물론 외부 I/O port 의 clock object는 다음과 함께 가장 잘 찾을 수 있습니다.
> get_clocks -of_objects [get_ports clk] clk
또는 더 짧은 command를 사용하면 동일합니다.
> get_clocks [get_ports clk] clk
get_ports에 대해 말하자면, -of_objects와도 작동합니다. get_ports에 특정한 가능성에 대한 설명서를 참조하십시오. 다른 commands 와 유사한 가능성은 무의미합니다. 예를 들어:
> get_ports -of_objects [get_nets clk] clk
요약하면 -of_objects는 특정 logic elements를 선택하는 탁월한 방법입니다. 이것은 아래의 다음 주제인 object의 이름에 따른 검색의 어려움 때문에 특히 그렇습니다.
안타깝게도 많은 FPGA tools가 -of_objects를 지원하지 않아 덜 신뢰할 수 있는 방법에 의존할 수밖에 없습니다.
이름으로 검색할 때의 문제
위에서 이미 논의한 바와 같이 timing constraints 의 정확도는 logic elements를 찾는 정확도에 달려 있습니다. 이러한 검색 결과 중 적어도 일부는 object의 이름에 따라 다릅니다. 이것이 어떻게 문제를 일으킬 수 있는지 봅시다.
예를 들어 "get_ports clk"는 clock object 와 특정 I/O pin에 있는 signal을 연결하는 데 사용됩니다. 이 I/O pin은 이름이 "clk"인 port object 로 표시됩니다.
create_clock -period 4.000 -name clk [get_ports clk]
그런데 왜 이 port object 에 "clk"라는 이름이 붙었을까요? 대답은 synthesizer가 netlist를 만든 방법과 관련이 있습니다. Verilog 코드에서 top-level port 의 이름은 netlist의 top-level port 이름으로도 선택되었습니다. 이것은 분명한 선택이므로 적절한 synthesizer 라면 모두 동일하게 작동합니다.
그러나 cells의 이름은 어떻습니까? 위의 Verilog 코드에서 "foo_reg"라는 이름의 register를 살펴보겠습니다. 이 register의 flip-flop을 대표하는 cell object 의 이름은? Vivado의 synthesizer는 이 object에 "foo_reg_reg"라는 이름을 선택했습니다. 따라서 이 synthesizer는 Verilog 코드의 이름에 "_reg" 접미사를 추가하는 경향이 있음이 분명합니다. 그것은 신뢰할 수있는 규칙처럼 들립니다. 그러나 또 다른 synthesizer는 아마도 뭔가 다른 일을 할 것입니다.
그러나 이름이 "bar"인 register는 어떻습니까? 관련 cell object 의 이름은 "bar_reg"였어야 하지만 synthesizer는 다른 선택을 했습니다. "bar_reg__0". Verilog 코드에 "bar_reg"라는 register가 있기 때문이다. 따라서 이름 충돌을 피하기 위해 synthesizer는 약간 다른 이름을 선택했습니다. "_reg" 대신 "_reg__0"를 추가했습니다. 이 간단한 예는 objects라는 이름에 의존하는 문제를 보여줍니다.
설상가상으로, "bar_reg"라는 이름의 register가 Verilog 코드에 추가되기 전에 timing constraint가 작성되었다고 가정합니다. 이 경우 @bar 와 관련된 cell object는 평소와 같이 "bar_reg"라는 이름을 갖게 됩니다. 따라서 timing constraint는 object에 이 이름을 사용합니다. 이후 단계에서 "bar_reg"라는 이름의 register가 design에 추가됩니다. 결과적으로 요청된 cell object 의 이름이 "bar_reg"에서 "bar_reg__0"로 변경됩니다. "bar_reg"라는 이름에 의존하는 timing constraint는 갑자기 올바르지 않습니다. 운이 좋으면 도구에서 이에 대해 warning을 발행할 것입니다.
objects 라는 이름을 잘못 사용할 수 있는 다른 이유가 있습니다. 예를 들어 fan-out가 한도를 초과하면 도구가 register를 자동으로 복제할 수 있습니다. 이 경우 새 register의 이름이 search pattern와 일치하지 않기 때문에 추가 register가 timing constraint에 포함되지 않을 수 있습니다.
더 심각한 문제는 우연히 logic elements가 timing constraints 에 포함된 경우입니다. 예를 들어 IP blocks에 속하는 logic elements 에서 이런 일이 발생할 수 있습니다. 이러한 logic elements의 이름을 제어할 수 없기 때문에 이러한 이름이 실수로 timing constraint의 pattern 와 일치할 가능성이 있습니다.
실수로 timing constraints 에 logic elements를 포함하는 것도 게으름의 결과일 수 있습니다. timing constraints는 일반적으로 logic design에 새로운 기능을 추가하면서 작성됩니다. search pattern이 시행착오를 거쳐 작성된 경우 향후 logic elements 의 이름이 고려되지 않을 수 있습니다. 따라서 새로운 logic이 추가되면 일부 logic elements 의 이름이 의도하지 않게 기존 timing constraints와 일치할 수 있습니다.
timing constraints로 실수를 피하는 방법
첫 번째이자 가장 중요한 규칙은 어떤 logic elements가 timing constraint의 search pattern 와 일치하는지 테스트하는 것만으로는 충분하지 않다는 것입니다. 이러한 logic elements 의 전체 목록을 만들고 이 목록을 주의 깊게 검토하더라도 나중에 추가될 logic 와 관련하여 어떤 것도 보장하지 않습니다. 그러한 검토는 objects 의 이름이 synthesizer 에 의해 변경되거나 implementation의 다른 단계에서 변경되는 경우에도 timing constraints가 예상대로 계속 작동할 것이라고 보장하지 않습니다.
따라서 search patterns를 수학적 표현처럼 취급하는 것이 중요합니다. 이러한 search patterns가 현재 예상대로 작동하는 것만으로는 충분하지 않습니다. 그리고 예상대로 작동하지 않는 경우 작동하도록 약간 수정하는 것만으로는 충분하지 않습니다. 오히려 search pattern이 올바른 이유와 시간이 지나도 계속 올바른 상태로 유지될 가능성이 높은 이유에 대한 논리적 설명이 있어야 합니다.
search patterns가 변경될 가능성이 없는 것에 의존하는 것도 중요합니다. 예를 들어, 도구는 Verilog 코드에서 instantiations 의 이름을 변경하지 않습니다. 이는 modules, IPs 및 primitives의 instantiations 에 해당합니다. 따라서 Verilog 코드에 작성된 instantiations 의 이름으로만 구성된 경우 hierarchical path 에 의존하는 것이 안전합니다. IP block내부에서 생성된 이름을 사용하는 것은 안전하지 않습니다. 이를 설명하기 위해 이 command를 살펴보겠습니다.
get_clocks -of_object [get_pins pll_i/inst/clkout1_buf/O]
clock을 배포하는 global clock buffer 의 output pin을 참고하여 clock object를 구하는 방법입니다. 문제는 이것이 장기적으로 작동할 것이라고 확신할 수 있는지 여부입니다.
이 방법의 문제점은 "inst" 및 "clkout1_buf"가 Clocking Wizard IP내부에서 만들어진 instantiations 의 이름이라는 것입니다. 이러한 이름은 변경되지 않을 것 같지만 변경되지 않는다는 보장은 없습니다.
한 가지 가능한 해결책은 IP를 구현하는 Verilog 코드를 찾아 이 Verilog을 프로젝트에 직접 포함시키는 것입니다. 이렇게 하면 미래에 아무 것도 변경되지 않습니다.
대안은 Verilog에서 IP 의 instantiation을 보는 것입니다. 다음을 기억하십시오.
clk_wiz_1 pll_i
(.clk_in1(clk),
.clk_out1(pll_clk_8),
.clk_out2(pll_clk_6));
이것은 black box의 instantiation이 기 때문에 각 ports 에는 netlist에 pin이 있습니다. IP 의 ports가 식별되는 방식이기 때문에 이름은 변경할 수 없습니다. 따라서 이름이 "pll_i/clk_out1"인 pin이 @pll_clk_8와 연결된다는 것이 보장됩니다. 따라서 이것은 clock object를 확보하는 안전한 방법입니다.
get_clocks -of_object [get_pins pll_i/clk_out1]
clk_wiz_1이 프로젝트의 또 다른 Verilog module 인 경우에는 작동하지 않을 수 있습니다. 이 경우 module의 instantiation을 대신하여 pins가 생성되지 않습니다( synthesizer는 일반적으로 nets를 병합하여 ports 의 연결을 구현하기 때문입니다). 가능한 해결책은 hierarchy의 하위 레벨에 나타나는 이름을 사용하는 것일 수 있습니다.
따라서 신뢰할 수 있는 몇 가지 이름이 있습니다.
- IP가 프로젝트에 black box로 포함되면 instantiation 의 이름과 이 IP 의 pins 의 이름이 안전합니다.
- primitive의 instantiation 도 마찬가지입니다. instantiation 와 pins 의 이름은 안전합니다. 이는 특히 global clock buffers를 언급할 때 유용합니다. 또 다른 시나리오는 FPGA의 관련 primitive덕분에 flip-flops 의 명시적인 instantiation 입니다. 이것은 도구에 의한 조작을 방지합니다.
- FPGA의 I/O ports 이름도 신뢰할 수 있습니다. top-level module의 ports이름입니다.
- registers에 길고 특이한 이름 사용. 예를 들어 모든 metastability guards 의 이름이 "_metastability_do_not_protect"로 끝나는 경우 다음과 같은 false path constraint를 작성하는 것이 상당히 안전합니다.
set_false_path -to [get_cells -hier *_metastability_do_not_protect*]
pattern끝에 있는 wildcard 에 유의하십시오.
이 constraint가 적용되어서는 안 되는 것에 적용될 가능성은 낮습니다. 또한 이름이 너무 많이 변경되어 이 constraint가 registers를 무시할 가능성도 낮습니다. 그러나 이것은 약간 덜 안전한 전략입니다.
크게 실패하는 것이 낫다
최악의 상황은 timing constraint가 거의 정확할 때입니다. 포함되지 않은 paths가 몇 개만 있는 경우. 또는 실수로 timing constraint 에 포함된 paths가 몇 개만 있는 경우. 이러한 종류의 오류는 찾기가 가장 어렵습니다.
이것이 짧고 간결하며 수학적 스타일을 가진 timing constraints가 더 나은 주된 이유입니다. logic elements의 작은 그룹마다 timing constraint가 있는 경우 이 긴 규칙 목록에 실수가 끼어들기 쉽습니다.
이 아이디어를 시연하기 위해 clock object를 찾기 위해 위에 표시된 예제로 돌아가 보겠습니다.
get_clocks -of_object [get_pins pll_i/inst/clkout1_buf/O]
위에서 언급했듯이, 이 expression 의 문제점은 pll_i 의 instantiation이 hierarchy의 다른 위치로 이동하면 clock object를 찾을 수 없다는 것입니다. 얼마나 나쁠까요?
이 clock object가 다음과 같이 Tcl variable 에 저장되어 있다고 가정해 보겠습니다.
set my_clock [get_clocks -of_object [get_pins pll_i/inst/clkout1_buf/O]]
그리고 $my_clock은 많은 timing constraints에서 사용되므로 많은 paths가 관련됩니다. 이 경우 버그로 인해 $my_clock 에 갑자기 clock object가 포함되지 않더라도 실제로 큰 문제는 아닙니다. 많은 일이 잘못될 것이기 때문에 이 실수를 곧 알아차릴 가능성이 높습니다.
그러나 $my_clock이 하나의 timing constraint에만 사용되고 이 constraint가 거의 효과가 없는 작은 문제를 해결하기 위한 것이라면 이는 나쁜 상황입니다. 이 실수는 눈에 띄지 않을 것입니다.
결론적으로: 잘 작성된 timing constraint는 완벽하게 작동하거나 전혀 작동하지 않습니다.
이 페이지는 logic elements를 정확하게 선택하는 방법을 보여줍니다. 다음 페이지 에서 이 지식은 선택적 timing constraints를 정의하는 데 사용됩니다.