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

VHDL에서 문자열 목록을 만드는 방법

VHDL의 텍스트 문자열은 일반적으로 고정 길이 문자 배열로 제한됩니다. VHDL은 하드웨어를 설명하고 일반 길이 문자열에는 동적 메모리가 필요하기 때문에 이는 의미가 있습니다.

문자열 배열을 정의하려면 저장하려는 최대 문자열 수에 대해 컴파일 타임에 공간을 할당해야 합니다. 그리고 더 나쁜 것은 문자열의 최대 길이를 결정하고 모든 항목을 해당 문자 수로 채워야 한다는 것입니다. 아래 코드는 이러한 구문의 사용 예를 보여줍니다.

  type arr_type is array (0 to 3) of string(1 to 10);
  signal arr : arr_type;

begin

  arr(0) <= "Amsterdam ";
  arr(1) <= "Bangkok   ";
  arr(2) <= "Copenhagen";
  arr(3) <= "Damascus  ";

하드웨어 관점에서는 말이 되지만 VHDL 테스트벤치에서 문자열 배열을 사용하는 것은 번거롭습니다. 따라서 이 기사에서 설명할 동적 문자열 목록 패키지를 만들기로 결정했습니다.

아래 양식을 사용하여 전체 코드를 다운로드할 수 있습니다.

Python의 목록 클래스

잘 알려진 목록 구현 후에 동적 VHDL 목록을 모델링해 보겠습니다. VHDL 문자열 목록은 Python의 내장 목록 클래스의 동작을 모방합니다. 우리는 append()를 채택할 것입니다. , 삽입()팝() Python 목록의 메소드.

무슨 말인지 보여드리기 위해 바로 들어가서 대화형 Python 셸을 열어 몇 가지 실험을 실행하겠습니다.

먼저 아래와 같이 목록을 선언하고 4개의 문자열을 추가하여 시작하겠습니다.

IPython 7.19.0 -- An enhanced Interactive Python. Type '?' for help.

In [1]: l = []
In [2]: l.append("Amsterdam")
In [3]: l.append("Bangkok")
In [4]: l.append("Copenhagen")
In [5]: l.append("Damascus")

추가() 방법은 간단합니다. 목록 끝에 개체를 추가합니다.

pop()으로 확인할 수 있습니다. 요소를 제거하고 호출자에게 반환하는 메서드입니다. 인수는 검색할 요소의 위치를 ​​지정합니다. 목록이 비어 있을 때까지 0을 팝하면 가장 낮은 인덱스에서 가장 높은 인덱스 순으로 콘텐츠가 정렬됩니다.

In [6]: for _ in range(len(l)): print(l.pop(0))
Amsterdam
Bangkok
Copenhagen
Damascus

좋아, 목록을 다시 채우자. 이번에는 insert() 목록 요소를 순서 없이 추가하는 방법:

In [7]: l.insert(0, "Bangkok")
In [8]: l.insert(1, "Copenhagen")
In [9]: l.insert(0, "Amsterdam")
In [10]: l.insert(3, "Damascus")

삽입() 함수를 사용하면 새 항목을 삽입할 인덱스를 지정할 수 있습니다. 위의 예에서는 이전과 동일한 목록을 만들었습니다. 배열처럼 목록을 탐색하여 확인해 보겠습니다.

In [11]: for i in range(len(l)): print(l[i])
Amsterdam
Bangkok
Copenhagen
Damascus

Python 대괄호 [] 목록 연산자는 항목을 삭제하지 않습니다. 목록이 배열처럼 작동하도록 합니다. 위의 목록에서 볼 수 있듯이 대괄호 안의 숫자로 색인화된 슬롯 콘텐츠를 가져옵니다.

팝핑으로 리스트를 비우자. 이번에는 리스트의 끝부터. Python 목록의 특징은 음수 인덱스를 사용하여 목록의 시작 대신 마지막 항목부터 계산할 수 있다는 것입니다. 대괄호 연산자 및 insert()와 함께 작동합니다. 또는 팝() 방법.

인덱스 -1을 팝하면 항상 목록에서 마지막 항목을 가져옵니다. For 루프에 넣으면 목록이 역순으로 비워집니다.

In [12]: for _ in range(len(l)): print(l.pop(-1))
Damascus
Copenhagen
Bangkok
Amsterdam

음수 인덱스를 사용하여 삽입할 수도 있습니다. 아래 예의 마지막 줄에서 인덱스 -1에 "Copenhagen"을 삽입하고 있습니다.

In [13]: l.append("Amsterdam")
In [14]: l.append("Bangkok")
In [15]: l.append("Damascus")
In [16]: l.insert(-1, "Copenhagen") # insert at the second last position

목록을 탐색하면 "Copenhagen"이 이제 두 번째 마지막 요소임을 알 수 있습니다.

In [17]: for i in range(len(l)): print(l[i])
Amsterdam
Bangkok
Copenhagen
Damascus

이제 핵심이 나옵니다(하지만 이해가 됩니다).

-1에 삽입할 때 새 항목이 두 번째 마지막 항목이 되지만 -1에서 삽입할 때 마지막 항목을 가져옵니다.

-1이 현재 목록에 있는 마지막 요소의 위치를 ​​나타내기 때문에 의미가 있습니다. 그리고 팝업할 때 마지막 요소를 요청합니다. 그러나 삽입할 때 현재 목록의 마지막 요소 위치에 새 항목을 삽입하도록 요청합니다. 따라서 새 항목은 최종 요소를 한 슬롯만큼 이동합니다.

"Copenhagen"이 아닌 "Damascus"를 반환하는 요소 -1을 팝핑하여 이를 확인할 수 있습니다.

In [18]: l.pop(-1) # pop from the last position
Out[18]: 'Damascus'

목록에는 이제 세 가지 요소가 포함됩니다.

In [19]: for i in range(len(l)): print(l[i])
Amsterdam
Bangkok
Copenhagen

다음과 같이 목록 길이를 계산할 수도 있습니다.

In [20]: len(l)
Out[20]: 3

clear()을 호출하여 목록을 비울 수 있습니다. :

In [21]: l.clear()
In [22]: len(l)
Out[22]: 0

보시다시피 Python 목록은 다재다능하며 많은 프로그래머가 이를 이해합니다. 그렇기 때문에 이 성공 공식을 기반으로 VHDL 목록을 구현하겠습니다.

문자열 목록 VHDL 서브프로그램 프로토타입

멤버 메서드가 있는 개체처럼 문자열 목록을 사용하려면 보호된 형식으로 선언해야 합니다. 그리고 우리는 같은 이름의 패키지에 보호된 유형을 배치할 것입니다:string_list .

아래 코드는 서브프로그램 프로토타입을 나열하는 보호된 유형의 "공개" 부분을 보여줍니다.

package string_list is

  type string_list is protected

    procedure append(str : string);

    procedure insert(index : integer; str : string);

    impure function get(index : integer) return string;

    procedure delete(index : integer);

    procedure clear;

    impure function length return integer;

  end protected;

end package;

append() 동안 , 삽입()clear() 절차는 Python 대응과 동일하므로 pop()을 이식할 수 없습니다. VHDL에 직접 기능합니다. 문제는 VHDL의 보호된 유형에서 동적 개체를 쉽게 전달할 수 없다는 것입니다.

이 한계를 극복하기 위해 pop() 두 개의 하위 프로그램으로 기능:get() 그리고 delete() . 그러면 배열처럼 요소를 먼저 인덱싱한 다음 더 이상 필요하지 않을 때 삭제할 수 있습니다. 예를 들어 시뮬레이터 콘솔에 문자열을 출력한 후입니다.

길이() 불순한 함수는 Python의 내장 len()처럼 작동합니다. 기능. 목록의 문자열 수를 반환합니다.

문자열 목록 VHDL 구현

보호된 형식은 선언적 부분과 본문의 두 섹션으로 구성됩니다. 선언적 부분은 사용자에게 표시되지만 본문에는 하위 프로그램 구현 및 모든 개인 변수가 포함됩니다. 이제 문자열 목록의 내부 작동을 공개할 시간입니다.

받은 편지함에서 전체 코드와 ModelSim 프로젝트를 받으려면 아래 양식에 이메일 주소를 남겨주세요!

내부 데이터 구조로 단일 연결 목록을 사용합니다.

또한 읽기:VHDL에서 연결 목록을 만드는 방법

뒤에 오는 모든 코드는 보호된 형식의 본문에 있으므로 이러한 구문은 이 패키지 외부에서 직접 액세스할 수 없습니다. 모든 통신은 이전 섹션에서 논의한 선언 영역에 나열된 하위 프로그램을 거쳐야 합니다.

데이터 저장 유형 및 변수

아래 코드에서 볼 수 있듯이 먼저 동적 메모리의 문자열에 대한 VHDL 포인터인 액세스 유형을 선언합니다. 동적 메모리에 대해 이야기할 때 이 코드는 합성할 수 없기 때문에 FPGA의 DRAM이 아닙니다. 문자열 목록은 순전히 시뮬레이션 구성 요소이며 시뮬레이션을 실행하는 컴퓨터의 동적 메모리를 사용합니다.

type str_ptr is access string;
type item;
type item_ptr is access item;
type item is record
  str : str_ptr;
  next_item : item_ptr;
end record;

str_ptr 뒤 , 우리는 항목을 선언합니다. 불완전한 유형으로. 다음 줄에서 item을 참조하기 때문에 그렇게 해야 합니다. item_ptr을 만들 때 .

마지막으로 item의 전체 선언을 지정합니다. 유형, 문자열 포인터와 다음 요소에 대한 포인터를 포함하는 레코드. item->item_ptr->item 유형 간에 순환 종속성이 있습니다. , 먼저 불완전한 항목을 선언함으로써 유형을 입력하면 컴파일 오류가 발생하지 않습니다.

보호된 유형에는 아래에 표시된 두 개의 변수가 있습니다. 루트길이_i . 루트가 가리키는 항목 목록의 첫 번째 요소, 배열 인덱스 0이 됩니다. 그리고 length_i 변수는 항상 목록의 문자열 수를 반영합니다.

variable root : item_ptr;
variable length_i : integer := 0;

프로시저 추가

추가() 아래의 절차는 목록의 마지막 위치에 문자열을 삽입하는 약식 표기법입니다.

procedure append(str : string) is
begin
  insert(length_i, str);
end procedure;

Python 예제에서 논의한 것처럼 인덱스 -1을 사용하여 두 번째 마지막 위치에 쉽게 삽입할 수 있습니다. insert(-1, str) . 그러나 마지막 위치에 삽입하려면 인덱스 인수로 목록의 길이가 필요합니다. 이것이 아마도 Python의 목록에 전용 append()가 있는 이유일 것입니다. 방법이 있으며 우리도 하나를 갖게 될 것입니다.

삽입 절차

아래 표시된 삽입 절차는 4단계로 작동합니다.

먼저 VHDL new를 사용하여 동적 항목 개체를 만듭니다. 예어. 먼저 목록 항목 개체를 만든 다음 여기에 저장할 동적 문자열 개체를 만듭니다.

procedure insert(index : integer; str : string) is
  variable new_item : item_ptr;
  variable node : item_ptr;
  variable index_v : integer;
begin

  -- Create the new object
  new_item := new item;
  new_item.str := new string'(str);

  -- Restrict the index to the list range
  if index >= length_i then
    index_v := length_i;
  elsif index <= -length_i then
    index_v := 0;
  else
    index_v := index mod length_i;
  end if;

  if index_v = 0 then

    -- The new object becomes root when inserting at position 0
    new_item.next_item := root;
    root := new_item;

  else

    -- Find the node to insert after
    node := root;
    for i in 2 to index_v loop
      node := node.next_item;
    end loop;

    -- Insert the new item
    new_item.next_item := node.next_item;
    node.next_item := new_item;

  end if;

  length_i := length_i + 1;

end procedure;

두 번째 단계는 인덱스 인수를 목록의 범위에 맞는 인덱스로 변환하는 것입니다. 파이썬의 list.insert() 구현은 범위를 벗어난 인덱스를 허용하고 VHDL 목록도 허용합니다. 사용자가 너무 높거나 낮은 인덱스를 참조하면 기본적으로 가장 높은 인덱스 또는 요소 0이 사용됩니다. 또한 모듈로 연산자를 사용하여 범위 내 음수 인덱스를 양수 배열 위치로 변환합니다.

3단계에서 목록을 탐색하여 다음에 삽입할 노드를 찾습니다. 항상 그렇듯이 연결 목록에서는 루트에 삽입하는 특정 경우를 명시적으로 처리해야 합니다.

네 번째이자 마지막 단계는 length_i를 증가시키는 것입니다. 부기가 최신 상태인지 확인하기 위한 변수입니다.

내부 get_index 및 get_node 함수

VHDL의 객체 전달 제한 때문에 pop()을 분할하기로 결정했습니다. 두 개의 하위 프로그램으로:get() 그리고 delete() . 첫 번째 함수는 항목을 가져오고 두 번째 프로시저는 목록에서 제거합니다.

그러나 인덱스 또는 객체를 찾는 알고리즘은 get()과 동일합니다. 그리고 delete() , 그래서 우리는 그것을 두 개의 private 함수에서 별도로 구현할 수 있습니다:get_index()get_node() .

insert()와 달리 , 파이썬의 pop() 함수는 범위를 벗어난 색인을 허용하지 않으며 get_index()도 허용하지 않습니다. 기능. 사용자 오류를 방지하기 위해 아래와 같이 요청된 인덱스가 범위를 벗어나면 어설션 실패를 발생시킵니다.

impure function get_index(index : integer) return integer is
begin
  assert index >= -length_i and index < length_i
    report "get index out of list range"
    severity failure;

  return index mod length_i;
end function;

get_node() 아래에 표시된 함수는 한 단계 더 나아가 지정된 인덱스에서 실제 객체를 찾습니다. get_index()를 사용합니다. 올바른 노드를 찾고 항목에 대한 포인터를 반환합니다. 개체.

impure function get_node(index : integer) return item_ptr is
  variable node : item_ptr;
begin

  node := root;
  for i in 1 to get_index(index) loop
    node := node.next_item;
  end loop;

  return node;

end function;

기능 가져오기

비공개 get_node() 때문에 함수, 공개 get() 기능이 다소 단순해집니다. 올바른 노드를 가져오고 문자열 내용의 압축을 풀고 호출자에게 반환하는 한 줄짜리입니다.

impure function get(index : integer) return string is
begin
  return get_node(index).str.all;
end function;

삭제 절차

delete() 프로시저는 get_index()도 사용합니다. 및 get_node() 알고리즘을 단순화합니다. 먼저 get_index()를 사용합니다. index_c에 표시된 대로 제거할 개체의 인덱스를 찾습니다. 아래 상수 선언.

procedure delete(index : integer) is
  constant index_c : integer := get_index(index);
  variable node : item_ptr;
  variable parent_node : item_ptr;
begin

  if index_c = 0 then
    node := root;
    root := root.next_item;
  else
    parent_node := get_node(index_c - 1);
    node := parent_node.next_item;
    parent_node.next_item := node.next_item;
  end if;

  deallocate(node.str);
  deallocate(node);

  length_i := length_i - 1;

end procedure;

그런 다음 목록에서 노드의 연결을 해제합니다. 루트 개체인 경우 다음 항목을 루트로 설정합니다. 그렇지 않으면 get_node()를 사용합니다. 상위 항목을 찾고 목록을 다시 연결하여 현재 항목을 분리합니다.

마지막으로 VHDL 키워드 deallocate를 호출하여 메모리를 해제합니다. length_i 업데이트 부기 변수.

명확한 절차

모든 항목을 삭제하려면 clear() 프로시저는 delete()를 호출하여 While 루프를 사용하여 목록을 탐색합니다. 아무것도 남지 않을 때까지 각 요소에서.

procedure clear is
begin
  while length_i > 0 loop
    delete(0);
  end loop;
end procedure;

길이 기능

좋은 프로그래밍 관행을 준수하기 위해 사용자가 length_i에 직접 액세스하도록 허용하지 않고 getter 함수를 제공합니다. 변수.

impure function length return integer is
begin
  return length_i;
end function;

매개변수가 없는 함수를 호출하기 위해 괄호가 필요하지 않기 때문에 사용자는 그 차이를 알아차리지 못할 것입니다(my_list.length ). 그러나 사용자는 내부 부기 변수를 변경할 수 없으며 이는 오용을 방지하기 위한 것입니다.

테스트벤치에서 문자열 목록 사용

이제 목록 구현이 완료되었으므로 테스트벤치에서 실행할 차례입니다. 먼저 아래 코드의 첫 번째 줄과 같이 패키지에서 보호된 유형을 가져와야 합니다.

use work.string_list.string_list;

entity string_list_tb is
end string_list_tb;

architecture sim of string_list_tb is

  shared variable l : string_list;
...

보호된 유형은 VHDL의 클래스와 유사한 구성이며 string_list 유형의 공유 변수를 선언하여 해당 유형의 개체를 만들 수 있습니다. , 위의 마지막 줄에 표시된 대로. 이 기사의 시작 부분에서 제시한 Python 예제를 복제하기 위해 "목록"의 이름을 'l'로 지정하겠습니다.

이제부터 소프트웨어 접근 방식을 사용하여 목록의 데이터에 액세스할 수 있습니다. 아래 테스트벤치 프로세스에서 볼 수 있듯이 공유 변수(l.append("Amsterdam"))에 점 표기법을 사용하여 공개 서브프로그램을 참조할 수 있습니다. ).

begin
  SEQUENCER_PROC : process
  begin

    print("* Append four strings");
    print("  l.append(Amsterdam)"); l.append("Amsterdam");
    print("  l.append(Bangkok)"); l.append("Bangkok");
    print("  l.append(Copenhagen)"); l.append("Copenhagen");
    print("  l.append(Damascus)"); l.append("Damascus");
...

이 기사의 길이를 줄이기 위해 전체 테스트 벤치 및 실행 스크립트를 생략했지만 아래 양식에 이메일 주소를 남겨두면 요청할 수 있습니다. 몇 분 안에 받은 편지함에서 완전한 VHDL 코드와 ModelSim 프로젝트가 포함된 Zip 파일을 받게 됩니다.

테스트벤치 실행

위의 양식을 사용하여 예제 프로젝트를 다운로드한 경우 다음 출력을 복제할 수 있습니다. 정확한 지침은 Zip 파일의 "실행 방법.txt"를 참조하십시오.

수동 검사 테스트벤치이며 테스트 케이스를 내 Python 예제와 최대한 유사하게 만들었습니다. pop() 대신 Python 방법, 우리는 VHDL 목록의 get()을 사용합니다. 함수 다음에 delete() 호출 . 동일한 작업을 수행합니다.

아래에 표시된 ModelSim 콘솔의 출력물에서 볼 수 있듯이 VHDL 목록은 Python 목록과 유사하게 작동합니다.

# * Append four strings
#   l.append(Amsterdam)
#   l.append(Bangkok)
#   l.append(Copenhagen)
#   l.append(Damascus)
# * Pop all strings from the beginning of the list
#   l.get(0): Amsterdam
#   l.get(1): Bangkok
#   l.get(2): Copenhagen
#   l.get(3): Damascus
# * Insert four strings in shuffled order
#   l.insert(0, Bangkok)
#   l.insert(1, Copenhagen)
#   l.insert(0, Amsterdam)
#   l.insert(3, Damascus)
# * Traverse the list like an array
#   l.get(0): Amsterdam
#   l.get(1): Bangkok
#   l.get(2): Copenhagen
#   l.get(3): Damascus
# * Pop all strings from the end of the list
#   l.get(0): Damascus
#   l.get(1): Copenhagen
#   l.get(2): Bangkok
#   l.get(3): Amsterdam
# * Append and insert at the second last position
#   l.append(Amsterdam)
#   l.append(Bangkok)
#   l.append(Damascus)
#   l.insert(-1, Copenhagen)
# * Pop from the last position
#   l.get(-1): Damascus
# * Traverse the list like an array
#   l.get(0): Amsterdam
#   l.get(1): Bangkok
#   l.get(2): Copenhagen
# * Check the list length
#   l.length: 3
# * Clear the list
# * Check the list length
#   l.length: 0
# * Done

최종 생각

VHDL의 상위 수준 프로그래밍 기능이 과소 평가되었다고 생각합니다. 합성할 수 없기 때문에 RTL 설계에는 유용하지 않지만 검증 목적으로 유용할 수 있습니다.

구현하기가 복잡할 수 있지만 보호 유형을 사용하는 테스트벤치를 작성하는 최종 사용자에게는 더 간단할 것입니다. 보호된 유형은 사용자에게 모든 복잡성을 숨깁니다.

보호된 유형을 사용하려면 패키지 가져오기, 공유 변수 선언, 테스트벤치 프로세스에서 하위 프로그램 호출의 세 줄만 있으면 됩니다. VHDL 구성 요소를 인스턴스화하는 것보다 간단합니다.

참조:VHDL에서 연결 목록을 만드는 방법

기사 아래의 댓글 섹션에 어떻게 생각하는지 알려주세요!


VHDL

  1. VHDL 코드 잠금 모듈을 위한 Tcl 기반 테스트벤치를 만드는 방법
  2. VHDL 테스트벤치에서 시뮬레이션을 중지하는 방법
  3. VHDL에서 PWM 컨트롤러를 만드는 방법
  4. VHDL에서 난수를 생성하는 방법
  5. VHDL에서 링 버퍼 FIFO를 만드는 방법
  6. 자가 점검 테스트벤치를 만드는 방법
  7. VHDL에서 연결 목록을 만드는 방법
  8. VHDL의 프로세스에서 프로시저를 사용하는 방법
  9. VHDL에서 불순 함수를 사용하는 방법
  10. VHDL에서 함수를 사용하는 방법