산업 제조
산업용 사물 인터넷 | 산업자재 | 장비 유지 보수 및 수리 | 산업 프로그래밍 |
home  MfgRobots >> 산업 제조 >  >> Industrial programming >> VHDL

VHDL 코드 잠금 모듈을 위한 Tcl 기반 테스트벤치를 만드는 방법

대부분의 VHDL 시뮬레이터는 Tcl(Tool Command Language)을 스크립팅 언어로 사용합니다. 시뮬레이터의 콘솔에 명령을 입력하면 Tcl을 사용하고 있습니다. 또한 시뮬레이터에서 실행되고 VHDL 코드와 상호 작용하는 Tcl로 스크립트를 생성할 수 있습니다.

이 기사에서는 VHDL 모듈이 올바르게 작동하는지 확인하기 위해 VHDL 대신 Tcl을 사용하는 자체 검사 테스트벤치를 만들 것입니다.

참조:
Tcl을 배워야 하는 이유
Tcl을 사용한 대화형 테스트벤치

아래 양식을 사용하여 이 문서 및 ModelSim 프로젝트에서 코드를 다운로드할 수 있습니다.

DUT:VHDL의 코드 잠금 모듈

테스트 벤치를 시작하기 전에 테스트 중인 장치(DUT)를 소개하겠습니다. PIN 패드에 올바른 숫자 시퀀스를 입력하면 금고의 잠금을 해제하는 코드 잠금 모듈이 될 것입니다.

사람들은 종종 코드 잠금을 조합 잠금이라고 부릅니다. . 그러나 나는 이 용어가 정확하지 않다고 생각합니다. 잠금을 해제하기 위해 올바른 숫자 조합을 입력하는 것만으로는 충분하지 않습니다. 또한 올바른 순서로 입력해야 합니다. 엄밀히 말하면 조합 잠금은 실제로 순열 잠금입니다. 하지만 이를 코드 잠금이라고 부르겠습니다. .

위의 이미지는 호텔 금고 형태의 코드 잠금 장치를 보여줍니다. 단순화를 위해 이 예제에서는 "CLEAR" 및 "LOCK" 버튼이 아닌 숫자 키만 사용합니다.

코드 잠금 모듈의 작동 방식

우리 모듈은 잠금 위치에서 시작되며, 비밀 PIN 코드와 일치하는 4자리 숫자를 연속으로 입력하면 금고가 잠금 해제됩니다. 다시 잠그기 위해 다른 잘못된 번호를 입력할 수 있습니다. 따라서 VHDL에서 시퀀스 검출기를 생성해야 합니다.

위의 파형은 코드 잠금 모듈이 어떻게 작동하는지 보여줍니다. 클록과 리셋 외에 두 가지 입력 신호가 있습니다. input_digitinput_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;

VHDL 테스트벤치

우선 검증을 위해 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 테스트벤치

이 예제의 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

ModelSim에서 텍스트 인쇄

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
}

N 클럭 사이클에 대한 시뮬레이션

DUT는 클럭 모듈이므로 상승 클럭 에지 사이에는 아무 일도 일어나지 않습니다. 따라서 우리는 클록 주기의 지속 시간을 기반으로 단계적으로 시뮬레이션하려고 합니다. 아래의 Tcl 절차는 clockPeriod를 사용합니다. 및 timeUnits 이를 달성하기 위해 이전에 VHDL 코드에서 제거한 변수입니다.

proc runClockCycles { count } {
  variable clockPeriod
  variable timeUnits

  set t [expr {$clockPeriod * $count}]
  run $t $timeUnits
}

프로시저는 count 매개변수를 사용합니다. . N 클록 사이클의 지속 시간을 얻기 위해 한 클록 주기의 길이와 곱합니다. 마지막으로 ModelSim run을 사용합니다. 정확히 그 시간 동안 시뮬레이션하는 명령입니다.

Tcl의 신호 값 확인

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
  }
}

PIN 시퀀스 테스트

코드 잠금 모듈의 출력은 현재 입력뿐만 아니라 이전 값에도 의존합니다. 따라서 출력 확인은 최소한 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

  1. VHDL에서 문자열 목록을 만드는 방법
  2. VHDL 테스트벤치에서 시뮬레이션을 중지하는 방법
  3. VHDL에서 PWM 컨트롤러를 만드는 방법
  4. VHDL에서 링 버퍼 FIFO를 만드는 방법
  5. Tcl을 사용한 대화형 테스트벤치
  6. 자가 점검 테스트벤치를 만드는 방법
  7. VHDL에서 연결 목록을 만드는 방법
  8. VHDL에서 불순 함수를 사용하는 방법
  9. VHDL에서 함수를 사용하는 방법
  10. VHDL 시뮬레이터 및 편집기를 무료로 설치하는 방법