VHDL
대부분의 VHDL 시뮬레이터는 Tcl(Tool Command Language)을 스크립팅 언어로 사용합니다. 시뮬레이터의 콘솔에 명령을 입력하면 Tcl을 사용하고 있습니다. 또한 시뮬레이터에서 실행되고 VHDL 코드와 상호 작용하는 Tcl로 스크립트를 생성할 수 있습니다.
이 기사에서는 VHDL 모듈이 올바르게 작동하는지 확인하기 위해 VHDL 대신 Tcl을 사용하는 자체 검사 테스트벤치를 만들 것입니다.
참조:
Tcl을 배워야 하는 이유
Tcl을 사용한 대화형 테스트벤치
아래 양식을 사용하여 이 문서 및 ModelSim 프로젝트에서 코드를 다운로드할 수 있습니다.
테스트 벤치를 시작하기 전에 테스트 중인 장치(DUT)를 소개하겠습니다. PIN 패드에 올바른 숫자 시퀀스를 입력하면 금고의 잠금을 해제하는 코드 잠금 모듈이 될 것입니다.
사람들은 종종 코드 잠금을 조합 잠금이라고 부릅니다. . 그러나 나는 이 용어가 정확하지 않다고 생각합니다. 잠금을 해제하기 위해 올바른 숫자 조합을 입력하는 것만으로는 충분하지 않습니다. 또한 올바른 순서로 입력해야 합니다. 엄밀히 말하면 조합 잠금은 실제로 순열 잠금입니다. 하지만 이를 코드 잠금이라고 부르겠습니다. .
위의 이미지는 호텔 금고 형태의 코드 잠금 장치를 보여줍니다. 단순화를 위해 이 예제에서는 "CLEAR" 및 "LOCK" 버튼이 아닌 숫자 키만 사용합니다.
우리 모듈은 잠금 위치에서 시작되며, 비밀 PIN 코드와 일치하는 4자리 숫자를 연속으로 입력하면 금고가 잠금 해제됩니다. 다시 잠그기 위해 다른 잘못된 번호를 입력할 수 있습니다. 따라서 VHDL에서 시퀀스 검출기를 생성해야 합니다.
위의 파형은 코드 잠금 모듈이 어떻게 작동하는지 보여줍니다. 클록과 리셋 외에 두 가지 입력 신호가 있습니다. input_digit 및 input_enable . 모듈은 상승 클록 에지에서 활성화가 '1'일 때 입력 숫자를 샘플링해야 합니다.
이 모듈의 출력은 unlock뿐입니다. 신호. 금고나 금고의 잠금 장치를 제어한다고 상상해보십시오. 잠금 해제 신호는 사용자가 올바른 PIN과 일치하는 연속 4자리 숫자를 입력한 경우에만 '1'이어야 합니다. 이 문서에서는 1234를 암호로 사용합니다.
아래 코드는 코드 잠금 모듈의 엔터티를 보여줍니다. 이 모듈의 목적은 TCL 기반 테스트벤치에 대한 간단한 예제 DUT이기 때문에 제네릭을 사용하여 비밀 암호를 하드 코딩하고 있습니다. 4개의 일반 상수는 제한된 범위의 정수로 구현된 이진 코드 십진법(BCD)입니다.
entity code_lock is generic (pin0, pin1, pin2, pin3 : integer range 0 to 9); port ( clk : in std_logic; rst : in std_logic; input_digit : in integer range 0 to 9; input_enable : in std_logic; unlock : out std_logic ); end code_lock;
암호와 마찬가지로 input_digit 신호도 BCD 유형입니다. 다른 입력 및 출력은 std_logics입니다.
이 모듈에는 사용자가 입력한 마지막 4자리 숫자를 포함하는 시프트 레지스터라는 하나의 내부 신호만 있습니다. 그러나 0에서 9까지의 BCD 범위를 사용하는 대신 -1에서 9까지의 숫자를 둡니다. 가능한 값은 11개입니다.
type pins_type is array (0 to 3) of integer range -1 to 9; signal pins : pins_type;
사용자가 입력할 수 있는 숫자가 아닌 재설정 값을 사용해야 하며 이것이 -1입니다. 핀에 대해 0에서 9 사이의 범위를 사용했다면 배열에서 비밀 암호를 0000으로 설정하면 처음에 볼트가 열렸습니다. 이 체계를 사용하면 사용자는 명시적으로 0을 4개 입력해야 합니다.
아키텍처 영역 상단에 고정할 때 볼트를 잠금 해제하는 동시 구문을 추가했습니다. 신호는 일반 상수와 일치합니다. 아래 코드는 조합이지만 핀 신호가 클럭되면 잠금 해제 신호는 클록의 상승 에지에서만 변경됩니다.
unlock <= '1' when pins = (pin3, pin2, pin1, pin0) else '0';
아래 코드는 사용자 입력을 읽는 프로세스를 보여줍니다. 핀에서 시프트 레지스터를 만듭니다. input_enable일 때 모든 값을 이동하여 신호 상승 클럭 에지에서 '1'입니다. 결과는 사용자가 입력한 마지막 네 자리가 핀에 저장된다는 것입니다. 배열.
PINS_PROC : process(clk) begin if rising_edge(clk) then if rst = '1' then pins <= (others => -1); else if input_enable = '1' then pins(0) <= input_digit; pins(1 to 3) <= pins(0 to 2); end if; end if; end if; end process;
우선 검증을 위해 Tcl을 사용하고 있지만 여전히 기본 VHDL 테스트벤치가 필요합니다. 아래 코드는 전체 VHDL 파일을 보여줍니다. DUT를 인스턴스화하고 클럭 신호를 생성했지만 그게 전부입니다. 시계를 생성하는 것 외에 이 테스트벤치는 아무 것도 하지 않습니다.
library ieee; use ieee.std_logic_1164.all; entity code_lock_tb is end code_lock_tb; architecture sim of code_lock_tb is constant clk_hz : integer := 100e6; constant clock_period : time := 1 sec / clk_hz; signal clk : std_logic := '1'; signal rst : std_logic := '1'; signal input_digit : integer range 0 to 9; signal input_enable : std_logic := '0'; signal unlock : std_logic; begin clk <= not clk after clock_period; DUT : entity work.code_lock(rtl) generic map (1,2,3,4) port map ( clk => clk, rst => rst, input_digit => input_digit, input_enable => input_enable, unlock => unlock ); end architecture;
이 예제의 Tcl 코드는 ModelSim VHDL 시뮬레이터에서만 작동합니다. 예를 들어 Vivado에서 사용하려면 몇 가지 변경을 해야 합니다. 이 시뮬레이터에 특정한 몇 가지 명령을 사용하기 때문입니다. 코드가 특정 시뮬레이터 공급업체에 고정된다는 것은 Tcl 사용의 단점입니다.
참고로 Tcl 언어 전반을 다루는 Tcl Developer Xchange와 모든 ModelSim 관련 명령을 설명하는 ModelSim Command Reference Manual을 추천합니다.
ModelSim이 설치되어 있는 경우 아래 양식을 사용하여 예제 프로젝트를 다운로드할 수 있습니다.
가장 먼저 추천하는 것은 Tcl 네임스페이스를 만드는 것입니다. 그렇지 않으면 의도하지 않게 Tcl 스크립트에서 전역 변수를 덮어쓸 수 있기 때문에 좋은 생각입니다. 네임스페이스에 있는 모든 코드를 래핑하면 잠재적인 혼란을 피할 수 있습니다. 우리는 지금부터 작성하는 모든 Tcl 코드를 codelocktb 안에 넣을 것입니다. 네임스페이스는 아래와 같습니다.
namespace eval ::codelocktb { # Put all the Tcl code in here }
네임스페이스 내에서 아래와 같이 시뮬레이션을 시작해야 합니다. 우리는 vsim을 사용합니다. 명령 다음에 VHDL 테스트벤치의 라이브러리 및 엔티티 이름이 옵니다. 그러면 시뮬레이션이 로드되지만 실행되지는 않습니다. run을 사용할 때까지 시뮬레이션 시간은 흐르지 않습니다. 나중에 스크립트에서 명령을 실행합니다. 파형이 있는 경우 이를 로드하는 If 문도 포함하고 싶습니다.
# Load the simulation vsim work.code_lock_tb # Load the waveform if {[file exists wave.do]} { do wave.do }
이제 시뮬레이션을 로드했으므로 VHDL 코드와 상호 작용할 수 있습니다. 먼저 clock_period를 읽고 싶습니다. Tcl 환경에 일반 상수 및 암호.
아래 코드에서는 ModelSim 전용 examine을 사용하고 있습니다. Tcl에서 VHDL 신호 및 상수 값을 읽는 명령. 그런 다음 Tcl string 및 list 명령을 사용하여 시간 값과 시간 단위를 추출합니다. 핀코드 변수는 일반 상수에서 읽은 네 자리 숫자의 목록이 됩니다.
# Read the clock period constant from the VHDL TB variable clockPeriod [examine clock_period] # Strip the braces: "{10 ns}" => "10 ns" variable clockPeriod [string trim $clockPeriod "{}"] # Split the number and the time unit variable timeUnits [lindex $clockPeriod 1] variable clockPeriod [lindex $clockPeriod 0] # Read the correct PIN from the VHDL generics variable pinCode [examine dut.pin0 dut.pin1 dut.pin2 dut.pin3]
VHDL 코드와 Tcl 스크립트에서 다른 코딩 스타일을 사용하고 있다는 점에 유의하십시오. 밑줄 대신 낙타 케이싱을 사용하고 있습니다. Tcl 스타일 가이드를 따르고 있기 때문입니다. 물론 원하는 경우 Tcl 및 VHDL 파일에서 동일한 스타일을 사용하는 것을 막을 수는 없습니다.
또한 네임스페이스 없이 Tcl을 사용했다면 Tcl에서 변수를 정의하는 표준 방법인 set 키워드에 대해 알고 있을 것입니다. 여기서는 newer variable 키워드를 대신 사용하고 있습니다. 전역 범위가 아닌 현재 네임스페이스에 연결된 전역 변수와 같습니다.
마지막으로 errorCount라는 변수를 선언합니다. 아래 그림과 같이 0으로 초기화합니다. 시뮬레이션이 테스트 케이스를 통해 진행됨에 따라 오류를 감지할 때마다 증가시킬 것입니다. 결국, 우리는 그것을 사용하여 모듈이 통과했는지 실패했는지 결정할 수 있습니다.
variable errorCount 0
puts 명령은 Tcl의 콘솔에 텍스트를 인쇄하는 표준 방법입니다. 그러나 이 방법은 ModelSim에서 불행한 방식으로 작동합니다. Windows 버전은 예상대로 작동합니다. 문자열을 콘솔에 출력합니다. 반면에 Linux 버전에서는 텍스트가 GUI 내의 콘솔이 아니라 ModelSim을 시작한 쉘에서 출력됩니다.
아래 이미지는 puts를 입력하면 어떻게 되는지 보여줍니다. ModelSim 콘솔에서 명령. 뒤에 있는 터미널 창에 나타납니다. 설상가상으로 바탕 화면 바로 가기를 사용하여 ModelSim을 시작한 경우 셸이 숨겨져 있기 때문에 출력을 볼 수 없습니다.
put 동작을 변경하는 해결 방법이 있습니다. 명령. 예를 들어 재정의하고(예! Tcl에서 할 수 있습니다) 두 플랫폼에서 모두 작동하도록 할 수 있습니다. 그러나 Linux와 Windows 모두에서 콘솔에 텍스트를 인쇄하는 보다 간단한 방법은 ModelSim 관련 echo를 사용하는 것입니다. 명령.
아래에 표시된 사용자 정의 Tcl 절차를 사용하여 텍스트를 인쇄합니다. 그렇게 하는 동안 메시지 앞에 현재 시뮬레이션 시간도 추가합니다. ModelSim에서는 $now를 사용하여 항상 얻을 수 있습니다. 전역 변수.
proc printMsg { msg } { global now variable timeUnits echo $now $timeUnits: $msg }
DUT는 클럭 모듈이므로 상승 클럭 에지 사이에는 아무 일도 일어나지 않습니다. 따라서 우리는 클록 주기의 지속 시간을 기반으로 단계적으로 시뮬레이션하려고 합니다. 아래의 Tcl 절차는 clockPeriod를 사용합니다. 및 timeUnits 이를 달성하기 위해 이전에 VHDL 코드에서 제거한 변수입니다.
proc runClockCycles { count } { variable clockPeriod variable timeUnits set t [expr {$clockPeriod * $count}] run $t $timeUnits }
프로시저는 count 매개변수를 사용합니다. . N 클록 사이클의 지속 시간을 얻기 위해 한 클록 주기의 길이와 곱합니다. 마지막으로 ModelSim run을 사용합니다. 정확히 그 시간 동안 시뮬레이션하는 명령입니다.
ModelSim에서 examine을 사용하여 Tcl에서 VHDL 신호를 읽을 수 있습니다. 명령. 아래 코드는 신호 값을 읽고 예상대로인지 확인하는 데 사용하는 Tcl 절차를 보여줍니다. 신호가 expectedVal과 일치하지 않는 경우 매개변수를 사용하면 불쾌한 메시지를 출력하고 errorCount를 증가시킵니다. 변수.
proc checkSignal { signalName expectedVal } { variable errorCount set val [examine $signalName] if {$val != $expectedVal} { printMsg "ERROR: $signalName=$val (expected=$expectedVal)" incr errorCount } }
코드 잠금 모듈의 출력은 현재 입력뿐만 아니라 이전 값에도 의존합니다. 따라서 출력 확인은 최소한 4자리 숫자를 DUT로 보낸 후에 이루어져야 합니다. 그런 다음 PIN이 정확하면 잠금 해제 신호가 '0'에서 '1'로 변경되어야 합니다.
아래의 Tcl 절차는 ModelSim force를 사용합니다. Tcl에서 VHDL 신호를 변경하는 키워드. -예금 강제로 전환 키워드는 ModelSim이 값을 변경하지만 다른 엔터티가 테스트벤치에서 DUT 입력을 제어하지 않더라도 나중에 다른 VHDL 드라이버가 값을 제어하도록 하는 것을 의미합니다.
proc tryPin { digits } { variable pinCode set pinStatus "incorrect" if { $digits == $pinCode } { set pinStatus "correct" } printMsg "Entering $pinStatus PIN code: $digits" foreach i $digits { force input_digit $i -deposit force input_enable 1 -deposit runClockCycles 1 force input_enable 0 -deposit runClockCycles 1 } if { $pinStatus == "correct" } { checkSignal unlock 1 } else { checkSignal unlock 0 } }
트라이핀 절차는 printMsg를 사용합니다. 수행 중인 작업, 입력 중인 PIN 코드 및 올바른 암호인지 여부를 알려주는 절차입니다. 또한 runClockCycles를 사용합니다. 사용자가 PIN을 입력하는 것을 시뮬레이션하기 위해 DUT 입력을 조작하면서 정확히 한 클록 기간 동안 실행하는 절차입니다.
마지막으로 checkSignal을 사용합니다. DUT가 예상대로 작동하는지 확인하는 절차입니다. 이미 설명했듯이 checkSignal 프로시저는 오류 메시지를 인쇄하고 errorCount를 증가시킵니다. 잠금 해제하는 경우 변수 신호가 예상 값과 일치하지 않습니다.
위의 Tcl 코드에서 우리는 시뮬레이션을 시작했고 많은 변수와 절차를 정의했지만 전혀 시뮬레이션하지 않았습니다. 시뮬레이션은 여전히 0ns입니다. 시뮬레이션 시간이 경과하지 않았습니다.
커스텀 네임스페이스가 끝나갈 무렵 Tcl 프로시저를 호출하기 시작합니다. 아래 코드에서 볼 수 있듯이 10개의 클록 주기 동안 실행하여 시작합니다. 그런 다음 재설정을 해제하고 잠금 해제 출력의 예상 값은 '0'입니다.
runClockCycles 10 # Release reset force rst '0' -deposit runClockCycles 1 # Check reset value printMsg "Checking reset value" checkSignal unlock 0 # Try a few corner cases tryPin {0 0 0 0} tryPin {9 9 9 9} tryPin $pinCode tryPin [lreverse $pinCode] if { $errorCount == 0 } { printMsg "Test: OK" } else { printMsg "Test: Failure ($errorCount errors)" }
10000개의 다른 PIN 코드를 모두 시도할 수 있지만 상당한 시간이 걸립니다. Tcl 기반 시뮬레이션은 순수한 VHDL 테스트벤치보다 훨씬 느립니다. 시뮬레이터는 시작과 중지를 많이 해야 하고 시간이 많이 걸립니다. 그래서 코너케이스만 확인하기로 했습니다.
우리는 tryPin이라고 부릅니다. 네 번, PIN 코드:0000, 9999, 올바른 PIN, 올바른 PIN의 숫자를 반대 순서로 사용합니다. 이것은 코드 잠금을 생성할 때 숫자의 순서가 아닌 조합만 보고 저지르기 쉬운 실수라고 생각합니다.
마지막으로 Tcl 코드의 맨 끝에 있지만 여전히 네임스페이스 내에서 errorCount 변수를 입력하고 "Test:OK" 또는 "Test Failure"를 인쇄합니다.
이제 재미있는 부분이 나옵니다. 테스트벤치 실행입니다. 아래와 같이 Tcl 소스 명령을 사용하는 것을 선호하지만 ModelSim 관련 do 명령. 사실 ModelSim DO 파일은 실제로 접미사가 다른 Tcl 파일입니다.
source code_lock/code_lock_tb.tcl
내 코드의 최종 버전에는 오류가 없습니다. 아래 목록은 성공적인 시뮬레이션의 출력을 보여줍니다. Tcl 스크립트는 수행 중인 작업에 대해 알려주고 모든 메시지 라인에 타임스탬프가 있음을 알 수 있습니다. 이것이 우리의 printMsg입니다. 직장에서 절차입니다. 마지막으로 테스트 벤치가 중지되고 "Test:OK"가 출력됩니다.
VSIM> source code_lock/code_lock_tb.tcl # vsim ... # 110 ns: Checking reset value # 110 ns: Entering incorrect PIN code: 0 0 0 0 # 190 ns: Entering incorrect PIN code: 9 9 9 9 # 270 ns: Entering correct PIN code: 1 2 3 4 # 350 ns: Entering incorrect PIN code: 4 3 2 1 # 430 ns: Test: OK
그러나 DUT가 테스트에 실패했을 때의 모습을 보여드리고 싶습니다. 이를 위해 코드 잠금 모듈에서 오류를 생성했습니다. pin1의 확인을 교체했습니다. pin2 사용 DUT가 pin1을 무시하도록 값. 아래 코드와 같이 만들기 쉬운 오타입니다.
unlock <= '1' when pins = (pin3, pin2, pin2, pin0) else '0';
이제 테스트벤치를 실행하면 아래 목록에서 결함이 감지되었음을 확인할 수 있습니다. 그리고 마지막으로 테스트벤치는 오류 수와 함께 "Test:Failure"를 출력합니다.
VSIM> source code_lock/code_lock_tb.tcl # vsim ... # 110 ns: Checking reset value # 110 ns: Entering incorrect PIN code: 0 0 0 0 # 190 ns: Entering incorrect PIN code: 9 9 9 9 # 270 ns: Entering correct PIN code: 1 2 3 4 # 350 ns: ERROR: unlock=0 (expected=1) # 350 ns: Entering incorrect PIN code: 4 3 2 1 # 430 ns: Test: Failure (1 errors)
제 경력에 Tcl 기반 테스트벤치를 많이 만들었지만 이에 대한 제 의견은 다소 분분합니다.
한편으로는 VHDL만으로는 불가능한 멋진 일을 할 수 있습니다. 예를 들어 대화형 테스트벤치. 다시 컴파일하지 않고도 테스트벤치를 변경할 수 있다는 점도 좋습니다. 그리고 마지막으로, 매우 다른 언어를 사용한 검증이 유리할 수 있습니다. 감지되지 않고 통과하려면 두 가지 다른 기술에서 동일한 실수를 해야 하며, 그럴 가능성은 거의 없습니다.
반면에 몇 가지 단점도 있습니다. Tcl 기반 테스트벤치는 VHDL 테스트벤치보다 크기가 느립니다. 또 다른 중요한 문제는 공급업체 종속입니다. 완전히 이식 가능한 Tcl 테스트벤치를 만드는 것은 불가능하지만 VHDL 테스트벤치는 모든 가능한 시뮬레이터에서 실행할 수 있습니다.
그리고 Tcl 테스트벤치가 가치가 없을 수도 있는 마지막 이유는 언어 자체입니다. 프로그래밍 오류를 방지하는 훌륭한 기능이 없으며 Tcl 문제를 디버깅하기가 어렵습니다. Python이나 Java와 같이 직관적이거나 관대한 언어가 아닙니다.
그러나 VHDL과 소프트웨어 세계 사이의 접착제 언어로서의 역할을 합니다. 그리고 시뮬레이터 뿐만 아니라 대부분의 FPGA 도구는 Tcl을 지원하므로 학습하는 것이 좋습니다.
이러한 생각은 내 의견일 뿐입니다. 댓글 섹션에서 어떻게 생각하는지 알려주세요!
VHDL
모든 위대한 모험에는 똑같이 훌륭한 팀이 필요하며 자동화도 예외는 아닙니다. 회사에서 자동화 챔피언을 찾으려고 시도한 적이 있습니까? 힘든 일입니다! 자동화로 조직을 개선하고 싶지만 서로 다른 팀 중에서 자동화 지지자를 찾는 데 어려움을 겪는 자동화 우수성 센터(CoE) 리더의 이야기를 많이 듣습니다. 이러한 리더는 올바른 비전과 훌륭한 도구 세트를 가지고 있지만 자동화 CoE의 노력을 지원하고 확장하는 데 도움이 되는 영웅이 필요합니다. 그들은 어벤져스가 필요합니다. 그들의 엑스맨. 자동화 챔피언입니다. 자동화 챔피언을 찾는
STL 파일은 CAM(Computer-Aided Modeling) 프로그램을 통해 형성됩니다. 이 모델링 소프트웨어를 사용하면 원하는 3D 모델을 만들 수 있습니다. 3D 모델을 완성한 후 Cura 또는 파일 슬라이서를 사용하여 STL 파일을 슬라이스할 수 있습니다. 전체 프로세스를 이해하면 효율적이고 명확하게 수행할 수 있습니다. 이 문서에서는 가장 쉬운 방법으로 3D 인쇄용 STL 파일을 만드는 방법에 대한 자세한 단계별 프로세스를 제공합니다. 또한 초보자가 3D 프린팅 STL 파일을 생성할 때 일반적으로 사용하는 소