이 페이지는 이 페이지를 읽기 전에 먼저 읽어야 하는 다른 페이지의 부록입니다. 두 페이지 모두 연재 글 모음의 일부이며, 이 연재는 타이밍 계산의 이론을 설명하고, 몇 가지 타이밍 제약 조건(timing constraints)을 작성하는 방법을 보여 주며, 타이밍 클로저(Timing Closure)의 원리를 논의합니다.
꼭 필요한 경우가 아니면 단순 검색 패턴을 사용하지 마세요
이 페이지는 SDC 형식의 타이밍 제약 조건을 작성할 때 와일드카드를 사용하는 방법을 설명합니다. 와일드카드는 여러 Tcl 명령에서 사용할 수 있지만, 이 페이지에서는 대개 "-hierarchical" 옵션을 지원하는 명령, 즉 get_cells, get_pins, get_nets에 초점을 맞춥니다. 이러한 Tcl 명령들은 다른 페이지에서 설명합니다. 다만 일부 FPGA 툴은 이 세 명령 모두에서 "-hierarchical"을 지원하지 않는다는 점에 유의하세요.
안타깝게도 이 세 명령의 검색 기능은 상당히 제한적이고 혼란스러울 수 있습니다. 와일드카드가 정확히 어떻게 동작하는지 이해하지 못하면 검색 결과가 예상과 다를 수 있습니다. 특히 "-hierarchical"을 사용하면 아래에서 보듯이 결과가 뜻밖일 수 있습니다.
따라서 특정 FPGA 툴이 해당 명령에서 "-filter" 옵션을 지원한다면 항상 그 옵션을 사용하는 편이 낫습니다. 그러한 지원이 없으면 단순 와일드카드를 사용할 수밖에 없습니다.
이 페이지의 모든 예는 그 관련 페이지와 같은 Verilog 코드를 기반으로 합니다.
단순 검색 패턴
로직 요소와 기타 객체를 찾는 명령은 검색 패턴을 사용하거나 사용하지 않고 실행할 수 있습니다. 검색 패턴 없이 사용하면 관련된 모든 객체가 검색됩니다. 예를 들어 최상위 계층의 모든 핀을 찾으려면:
get_pins
그리고 FPGA 설계 전체에서 모든 핀을 찾는 명령은 다음과 같습니다.
get_pins -hierarchical
검색 패턴을 사용하면 결과가 그 패턴에 맞는 것으로 제한됩니다. 예를 들어 이름과 계층상 위치를 모두 아는 특정 핀 하나를 찾으려면:
> get_pins foo_reg_reg/Q foo_reg_reg/Q > get_pins pll_i/clk_in1 pll_i/clk_in1 > get_pins pll_i/inst/clk_in1 pll_i/inst/clk_in1
패턴에는 와일드카드도 포함될 수 있습니다. 예를 들어:
> get_pins foo_reg_reg/* foo_reg_reg/Q foo_reg_reg/C foo_reg_reg/CE foo_reg_reg/D foo_reg_reg/R > get_pins pll_i/* pll_i/clk_in1 pll_i/clk_out1 pll_i/clk_out2 > get_pins pll_i/inst/* pll_i/inst/clk_in1 pll_i/inst/clk_out1 pll_i/inst/clk_out2 > get_pins pll_i/*/* pll_i/inst/clk_in1 pll_i/inst/clk_out1 pll_i/inst/clk_out2 > get_pins pll_i/*/clk* pll_i/inst/clk_in1 pll_i/inst/clk_out1 pll_i/inst/clk_out2
와일드카드의 동작
흔히 쓰이는 와일드카드는 두 가지입니다.
- 별표("*")는 임의의 개수의 문자를 대신합니다.
- 물음표("?")는 문자 하나를 대신합니다.
그러나 이 두 와일드카드는 절대 계층 구분자에 적용되지 않습니다. 다시 말해 "*"와 "?"는 "/"(또는 Quartus의 "|")를 대신하지 못합니다. 이것은 "-hierarchical" 옵션을 사용하든 사용하지 않든 와일드카드에서는 항상 그렇습니다(단, "-filter"나 "-regexp"를 사용하면 이야기가 다릅니다).
그 결과 객체의 계층에서 정확한 위치를 명시적으로 써 주어야 합니다.
> get_pins */clk_* pll_i/clk_in1 pll_i/clk_out1 pll_i/clk_out2 > get_pins */*/clk_* pll_i/inst/clk_in1 pll_i/inst/clk_out1 pll_i/inst/clk_out2
툴마다 계층 구분자로 다른 문자를 사용할 수 있다는 점에 유의하세요. 방금 언급했듯이 Quartus는 이 목적에 "/" 대신 파이프 문자("|")를 사용합니다.
"-hierarchical" 옵션은 설계 계층 어디에서든 로직 요소를 찾을 수 있게 해 줍니다. 이것은 계층에서 정확한 위치를 지정할 필요를 없애 주고, 단일 명령으로 FPGA 설계 전체에서 로직 요소를 찾을 수 있게 해 줍니다.
그럼 같은 표현을 "-hierarchical"과 함께 다시 실행해 보겠습니다.
> get_pins -hierarchical */clk_* pll_i/clk_in1 pll_i/clk_out1 pll_i/clk_out2 pll_i/inst/clk_in1 pll_i/inst/clk_out1 pll_i/inst/clk_out2 > get_pins -hierarchical */*/clk_* WARNING: [Vivado 12-508] No pins matched '*/*/clk_*'.
"-hierarchical"은 검색 패턴이 설계 계층의 모든 위치에 적용된다는 뜻입니다. 위 예에서 "*/clk_*"는 먼저 최상위 계층에 적용되어, 예를 들어 "pll_i/clk_in1"이 검색되었습니다. 그런 다음 같은 패턴이 "pll_i/" 내부에도 적용되어 "pll_i/inst/clk_in1"이 검색되었습니다.
그런데 "-hierarchical"을 적용했을 때 "*/*/clk_*"로는 왜 아무것도 찾지 못했을까요? 같은 패턴은 이 옵션 없이도 검색 결과를 주었습니다. "-hierarchical"을 사용하면 항상 검색 결과가 더 많아야 하지 않을까요?
-hierarchical을 사용하면 검색 패턴이 제한된다
이상하게도 "-hierarchical" 옵션은 검색 패턴이 적용되는 위치만 바꾸는 것이 아니라 허용되는 패턴도 제한합니다. 안타깝게도 툴은 허용되지 않는 패턴이 사용되면 오류로 응답하지 않습니다. 대신 아무것도 찾지 못한 것으로 응답합니다.
세 Tcl 명령(get_cells, get_pins, get_nets) 각각은 검색 패턴을 제한하는 고유한 규칙을 가집니다. 정확한 제한 사항을 알려면 FPGA 툴의 문서를 참조하세요. 표준적인 해석(Synopsys 문서에 자세히 나와 있음)은 아래에 요약되어 있습니다.
"-hier"라는 약어가 "-hierarchical" 대신 자주 쓰인다는 점에 유의하세요. 의미는 정확히 같습니다.
get_cells -hierarchical
get_cells를 -hierarchical과 함께 사용하면, 패턴은 객체의 이름하고만 일치합니다. 패턴에 계층 구분자가 있으면 결과는 항상 비어 있습니다. 예를 들어:
> get_cells -hierarchical *_buf pll_i/inst/clkf_buf pll_i/inst/clkout1_buf pll_i/inst/clkout2_buf > get_cells -hierarchical inst/*_buf WARNING: [Vivado 12-180] No cells matched 'inst/*_buf'.
패턴에 "/"가 있으면 아무것도 찾지 못하므로 오류라는 점에 유의하세요. 그런데도 툴은 오류로 응답하지 않고 그냥 결과가 없을 뿐입니다.
패턴에 계층 구분자가 허용되지 않기 때문에 get_cells는 다음 가능성들로 제한됩니다.
- -hierarchical을 사용하지 않고, 계층의 특정 위치에서 셀을 검색하는 것.
- -hierarchical을 사용하여 FPGA 설계 전체에서 셀을 검색하는 것.
- 대신 -filter나 -regexp가 지원된다면 그것들을 사용하세요. 이 옵션들은 이런 제한이 없습니다.
이 예는 특정한 이름 형식을 가진 모든 셀에 대해 false path(false path)를 선언하는 방법을 보여 줍니다.
set_false_path -to [get_cells -hierarchical *metaguard*]
이런 타이밍 제약 조건이면 메타스태빌리티(metastability) 보호용 레지스터로 쓰는 모든 레지스터의 이름에 "metaguard"라는 단어가 들어가기만 하면 됩니다. 다만 이 타이밍 제약 조건의 위험은, 그 표현식이 FPGA 설계 어딘가에 있는 무관한 로직 요소와 의도치 않게 일치할 수 있다는 점입니다. 따라서 "metaguard"보다 덜 흔한 이름을 고르는 것이 좋습니다.
get_nets -hierarchical
get_nets도 get_cells와 같은 규칙을 따릅니다. -hierarchical 없이 사용하면 최상위 계층에서 패턴과 일치하는 모든 네트(net)를 찾습니다. -hierarchical과 함께 사용하면 패턴은 객체의 이름하고만 일치합니다. 패턴에 계층 구분자가 있으면 결과는 항상 비어 있습니다.
> get_nets pll_i/clk_i* pll_i/clk_in1 > get_nets clk_i* WARNING: [Vivado 12-507] No nets matched 'clk_i*'. > get_nets -hierarchical clk_i* pll_i/clk_in1 pll_i/inst/clk_in1 > get_nets -hierarchical pll_i/clk_i* WARNING: [Vivado 12-507] No nets matched 'pll_i/clk_i*'.
get_pins -hierarchical
get_pins를 -hierarchical과 함께 사용하면, 패턴은 핀의 전체 이름(예: baz_reg/Q, clkout1_buf/I 등)과 일치합니다. "/"는 계층 구분자가 아니라 이름의 일부로 간주됩니다. 다시 말해 셀 이름과 핀 식별자 사이에 있는 문자는 와일드카드로 대체될 수 있습니다. 이것은 마지막 계층 구분자에 대해서만, 그리고 -hierarchical을 사용할 때만 적용됩니다.
예를 들어:
> get_pins -hierarchical clkout1_buf/* pll_i/inst/clkout1_buf/O pll_i/inst/clkout1_buf/CE pll_i/inst/clkout1_buf/I > get_pins -hierarchical clkout1_bu* pll_i/inst/clkout1_buf/O pll_i/inst/clkout1_buf/CE pll_i/inst/clkout1_buf/I > get_pins -hierarchical clkout1_buf WARNING: [Vivado 12-508] No pins matched 'clkout1_buf'.
clkout1_bu*가 (다른 것들과 함께) clkout1_buf/O와 일치했다는 점에 유의하세요. "*"가 "/O"로 대체될 수 있었던 것은 오직 -hierarchical 때문입니다.
get_cells에서와 마찬가지로, 패턴에 계층 구분자가 있으면 결과는 항상 비어 있습니다. 이것은 위의 예와 모순되지 않습니다. 앞서 말했듯이 마지막 "/"는 핀 이름의 일부로 간주되기 때문입니다.
> get_pins pll_i/inst/clkout1*/I pll_i/inst/clkout1_buf/I > get_pins -hierarchical pll_i/inst/clkout1*/I WARNING: [Vivado 12-508] No pins matched 'pll_i/inst/clkout1*/I'. > get_pins -hierarchical pll_i/inst/*/* WARNING: [Vivado 12-508] No pins matched 'pll_i/inst/*/*'. > get_pins -hierarchical pll_i/*/*/* WARNING: [Vivado 12-508] No pins matched 'pll_i/*/*/*'. > get_pins -hierarchical pll_i/*/* WARNING: [Vivado 12-508] No pins matched 'pll_i/*/*'. > get_pins -hierarchical pll_i/* pll_i/clk_in1 pll_i/clk_out1 pll_i/clk_out2 > get_pins pll_i/* pll_i/clk_in1 pll_i/clk_out1 pll_i/clk_out2
-hierarchical을 사용하지 않으면 와일드카드가 계층 구분자와 절대 일치하지 않는다는 점에 유의하세요. 마지막 구분자도 예외가 아닙니다.
> get_pins pll_i/inst/clkout1_buf/I pll_i/inst/clkout1_buf/I > get_pins pll_i/inst/clkout1_buf/* pll_i/inst/clkout1_buf/O pll_i/inst/clkout1_buf/CE pll_i/inst/clkout1_buf/I > get_pins pll_i/inst/clkout1_bu* WARNING: [Vivado 12-508] No pins matched 'pll_i/inst/clkout1_bu*'. > get_pins pll_i/inst/clkout1_bu*/* pll_i/inst/clkout1_buf/O pll_i/inst/clkout1_buf/CE pll_i/inst/clkout1_buf/I
이 예들에서 get_pins가 얼마나 혼란스러운지 분명히 드러납니다. 앞서 말했듯이, -filter나 -regexp가 지원된다면 그것들을 사용하세요.
요약
로직 요소를 찾는 방법으로 와일드카드를 쓸 수 있기는 하지만, 검색 결과가 항상 자연스럽게 기대하는 대로 나오는 것은 아닙니다. 마찬가지로 -hierarchical 옵션은 일부 시나리오에서 도움이 될 수 있지만, 그 기능에는 검색 패턴에 대한 제한이 따르고 동작은 훨씬 더 혼란스럽습니다.
따라서 로직 요소를 선택할 때는 다른 방법을 사용하는 것이 좋습니다. FPGA 툴이 -filter, -regexp, -of_objects를 지원한다면, 그중 하나가 아마 더 나은 해결책입니다. 단순 와일드카드를 쓰는 것은 다른 옵션을 전혀 사용할 수 없거나, 특정 시나리오에서 다른 옵션이 하나도 유용하지 않을 때만 의미가 있습니다. 그런 상황에서는 검색 패턴의 의미에 대해 각별히 주의할 필요가 있습니다.