수색…


소개

이 주제에서는 VHDL로 간단한 디지털 회로를 올바르게 설계하는 간단한 방법을 제안합니다. 이 방법은 그래픽 블록 다이어그램과 기억하기 쉬운 원칙을 기반으로합니다.

하드웨어를 먼저 생각하고 VHDL 코드를 작성하십시오.

VHDL을 사용하는 디지털 하드웨어 설계의 초보자를 대상으로하며 언어의 합성 의미에 대한 이해가 제한적입니다.

비고

VHDL을 사용한 디지털 하드웨어 디자인은 초보자에게도 간단하지만, 알아야 할 몇 가지 중요한 사항과 준수해야 할 작은 규칙이 있습니다. 디지털 하드웨어에서 VHDL 설명을 변환하는 데 사용되는 도구는 논리 합성기입니다. 논리 합성기가 사용하는 VHDL 언어의 의미는 언어 참조 설명서 (LRM)에 설명 된 시뮬레이션 의미와는 다소 다릅니다. 더 나쁜 것은 표준화되지 않았고 합성 도구에 따라 다르다는 것입니다.

제안 된 방법은 단순화를 위해 몇 가지 중요한 제한 사항을 도입합니다.

  • 레벨 트리거 래치가 없습니다.
  • 회로는 단일 클럭의 상승 에지에서 동기식입니다.
  • 비동기 재설정 또는 설정이 없습니다.
  • 해결 된 신호에는 다중 드라이브가 없습니다.

블록 다이어그램 예제 (일련의 3 번 시리즈 중 첫 번째)는 디지털 하드웨어의 기본을 간략하게 소개하고 디지털 회로의 블록 다이어그램을 디자인하기위한 간단한 규칙 목록을 제안합니다. 이 규칙은 예상대로 시뮬레이트하고 합성하는 VHDL 코드로의 직접적인 변환을 보장합니다.

코딩 예제는 블록 다이어그램에서 VHDL 코드로의 변환을 설명하고 간단한 디지털 회로에서이를 보여줍니다.

마지막으로 John Cooley의 디자인 컨테스트 예제는 디지털 회로의보다 복잡한 예제에서 제안 된 방법을 적용하는 방법을 보여줍니다. 또한 소개 된 제한 사항을 자세히 설명하고 일부는 완화합니다.

블록 다이어그램

디지털 하드웨어는 두 가지 유형의 하드웨어 기본 요소로 구성됩니다.

  • 조합 게이트 (인버터, 및 / 또는 xor, 1 비트 전체 덧셈기, 1 비트 멀티플렉서 ...)이 논리 게이트는 입력에 간단한 부울 연산을 수행하고 출력을 생성합니다. 입력 중 하나가 변경 될 때마다 전기 신호가 전파되기 시작하고 잠시 후 출력이 결과 값으로 안정화됩니다. 전파 지연은 디지털 회로가 동작 할 수있는 속도, 즉 최대 클럭 주파수와 강하게 관련되기 때문에 중요합니다.
  • 메모리 요소 (래치, D- 플립 플롭, RAM ...). 조합 논리 게이트와는 달리, 메모리 요소는 입력의 변화에 ​​즉시 반응하지 않는다. 그들은 데이터 입력, 제어 입력 및 데이터 출력을 가지고 있습니다. 그들은 데이터 입력의 변화가 아닌 제어 입력의 특정 조합에 반응합니다. 예를 들어, 상승 에지 트리거 D- 플립 플롭 (DFF)에는 클록 입력 및 데이터 입력이 있습니다. 클럭의 모든 상승 에지에서 데이터 입력이 샘플링되어 데이터 출력으로 복사됩니다. 데이터 출력은 데이터 입력이 중간에 변경 되더라도 클럭의 다음 상승 에지까지 안정 상태를 유지합니다.

디지털 하드웨어 회로는 조합 논리와 메모리 요소의 조합입니다. 메모리 요소에는 여러 가지 역할이 있습니다. 그 중 하나는 동일한 데이터를 여러 데이터에 대해 여러 번 연속적으로 재사용 할 수 있도록하는 것입니다. 이를 사용하는 회로는 종종 순차 회로 라고합니다. 아래 그림은 상승 에지 트리거 레지스터 덕분에 동일한 조합 가산기를 사용하여 정수 값을 누적하는 순차 회로의 예를 보여줍니다. 또한 블록 다이어그램의 첫 번째 예제이기도합니다.

순차 회로

파이프 라이닝은 메모리 요소의 또 다른 일반적인 사용이며 많은 마이크로 프로세서 아키텍처의 기초입니다. 이것은 일련의 단순한 연산에서 복잡한 처리를 분할하고 여러 연속 처리의 실행을 병렬화하여 회로의 클럭 주파수를 높이는 것을 목표로합니다.

복잡한 콤비네이션 처리의 파이프 라이닝

블록 다이어그램은 디지털 회로의 그래픽 표현입니다. 올바른 의사 결정을 내리고 코딩하기 전에 전체 구조를 잘 이해하는 데 도움이됩니다. 이는 많은 소프트웨어 설계 방법에서 권장되는 예비 분석 단계와 동일합니다. 숙련 된 설계자는 최소한 간단한 회로의 경우이 설계 단계를 자주 건너 뜁니다. 그러나 디지털 하드웨어 설계의 초보자이고 VHDL로 디지털 회로를 코딩하려면 아래의 10 가지 간단한 규칙을 사용하여 블록 다이어그램을 그려야합니다.

  1. 큰 직사각형으로 그림을 둘러 쌉니다. 이것은 회로의 경계입니다. 이 경계를 넘는 모든 것은 입력 또는 출력 포트입니다. VHDL 엔티티가이 경계를 설명합니다.
  2. 조합 로직 (예 : 라운드 블록)에서 에지 트리거 레지스터 (예 : 사각형 블록)를 명확하게 분리합니다. VHDL에서는 프로세스로 변환되지만 동기식 및 조합형의 두 가지 매우 다른 종류로 변환됩니다.
  3. 레벨 트리거 래치를 사용하지 말고 상승 에지 트리거 레지스터 만 사용하십시오. 이 제약은 모델 래치에 완벽하게 사용할 수있는 VHDL에서 비롯된 것이 아닙니다. 그것은 초보자들에게 합리적인 조언 일뿐입니다. 래치는 자주 필요하지 않으며 최소한 첫 번째 설계에서는 사용하지 않아야하는 많은 문제점이 있습니다.
  4. 모든 상승 에지 트리거 레지스터에 동일한 단일 클럭을 사용하십시오. 다시 한번,이 제약은 간결함을 위해 여기에 있습니다. VHDL은 다중 클럭 시스템을 모델링하는 데 완벽하게 사용할 수 없습니다. 시계의 이름을 clock . 그것은 외부에서 오는 모든 정사각형 블록의 입력이며 오직 그들입니다. 원한다면 시계를 표현하지 마십시오. 모든 사각형 블록에 대해 동일하며 다이어그램에 내포되어있을 수 있습니다.
  5. 명명 된 방향성있는 화살표로 블록 간의 통신을 나타냅니다. 블록의 경우 화살표가 나타나고 화살표는 출력입니다. 화살표가가는 블록의 경우 화살표는 입력입니다. 이 모든 화살표는 VHDL 엔티티의 포트가됩니다 (대형 직사각형 또는 VHDL 아키텍처의 신호를 넘는 경우).
  6. 화살표는 하나의 단일 원점을 갖지만 여러 목적지를 가질 수 있습니다. 실제로 화살표가 여러 기원을 가지고 있다면 우리는 여러 드라이버로 VHDL 신호를 생성 할 것입니다. 이것은 완전히 불가능하지는 않지만 단락을 피하기 위해 특별한주의가 필요합니다. 따라서 우리는 지금 이것을 피할 것입니다. 화살표에 여러 목적지가있는 경우 화살표를 필요한만큼 여러 번 건너 뜁니다. 점을 사용하여 연결된 교차점과 연결되지 않은 교차점을 구별합니다.
  7. 일부 화살표는 큰 직사각형 바깥 쪽에서옵니다. 이들은 엔티티의 입력 포트입니다. 입력 화살표는 블록의 출력이 될 수 없습니다. 이것은 VHDL 언어에 의해 시행됩니다. 엔티티의 입력 포트는 읽을 수는 있지만 쓰지는 못합니다. 이는 다시 단락을 방지하기위한 것입니다.
  8. 일부 화살표가 바깥쪽으로 나옵니다. 이들은 출력 포트입니다. 2008 년 이전의 VHDL 버전에서는 엔티티의 출력 포트를 쓸 수는 있지만 읽을 수는 없습니다. 출력 화살표는 하나의 단일 원점과 하나의 단일 대상을 가져야합니다. 출력 화살표에 포크가 없으면 출력 화살표는 블록 중 하나의 입력이 될 수 없습니다. 출력 화살표를 블록의 일부 입력으로 사용하려면 새 라운드 블록을 삽입하여 두 개의 부분으로 나누십시오. 하나는 내부 포크, 원하는 포크는 여러 개, 새로운 화살표는 출력 화살표입니다. 차단하고 밖으로 나간다. 새로운 블록은 VHDL에서 단순 연속 할당이됩니다. 투명하게 이름을 바꾸는 것. VHDL 2008 포트도 읽을 수 있기 때문에.
  9. 외부 / 외부로 오르거나 가지 않는 모든 화살표는 내부 신호입니다. VHDL 아키텍처에서 모두 선언 할 것입니다.
  10. 다이어그램의 모든주기는 적어도 하나의 정사각형 블록을 포함해야합니다. 이것은 VHDL로 인한 것이 아닙니다. 이는 디지털 하드웨어 설계의 기본 원칙에서 비롯됩니다. 조합 루프는 절대 피해야합니다. 드문 경우를 제외하고는 유용한 결과를 산출하지 못합니다. 그리고 라운드 블록만을 포함하는 블록 다이어그램의 사이클은 조합 루프입니다.

신중하게 마지막 규칙을 확인하는 것을 잊지 마라. 다른 규칙들만큼이나 필수적이지만 확인하기가 조금 더 어려울 수도있다.

래치, 멀티 클럭 또는 여러 드라이버가있는 신호와 같이 지금 제외 된 기능이 절대적으로 필요한 경우가 아니라면 10 가지 규칙을 준수하는 회로의 블록 다이어그램을 쉽게 그려야합니다. 그렇지 않은 경우 VHDL 또는 로직 합성기가 아닌 원하는 회로가 문제 일 수 있습니다. 아마도 원하는 회로가 디지털 하드웨어가 아님을 의미합니다.

순차 회로의 예제에 10 개의 규칙을 적용하면 다음과 같은 블록 다이어그램이 생성됩니다.

순차 회로의 재구성 된 블록 다이어그램

  1. 다이어그램 주변의 큰 사각형에는 VHDL 엔터티의 입력 및 출력 포트를 나타내는 3 개의 화살표가 교차됩니다.
  2. 블록 다이어그램에는 가산기와 출력 이름 변경 블록 인 두 개의 라운드 (조합) 블록과 레지스터 인 사각 (동기) 블록이 있습니다.
  3. 에지 트리거 레지스터 만 사용합니다.
  4. 클럭이라는 이름의 clock 하나뿐입니다. 우리는 상승 에지만을 사용합니다.
  5. 블록 다이어그램에는 다섯 개의 화살표가 있으며 하나에는 포크가 있습니다. 두 개의 내부 신호, 두 개의 입력 포트 및 한 개의 출력 포트에 해당합니다.
  6. 모든 화살표에는 두 개의 대상이있는 Sum 이라는 화살표를 제외하고 하나의 시작점과 하나의 대상이 있습니다.
  7. Data_inClock 화살표는 두 개의 입력 포트입니다. 그들은 우리 자신의 블록을 출력하지 않습니다.
  8. Data_out 화살표는 우리의 출력 포트입니다. 2008 년 이전의 VHDL 버전과 호환되도록 SumData_out 사이에 여분의 이름 바꾸기 (둥근) 블록을 추가 Data_out . 따라서 Data_out 에는 정확히 하나의 소스와 하나의 목적지가 있습니다.
  9. SumNext_sum 은 두 개의 내부 신호입니다.
  10. 그래프에는 정확히 하나의 사이클이 있으며, 하나의 사각형 블록으로 구성됩니다.

우리의 블록 다이어그램은 10 가지 규칙을 준수합니다. 코딩 예제에서는 VHDL에서 이러한 유형의 블록 다이어그램을 변환하는 방법을 자세히 설명합니다.

코딩

이 예제는 일련의 3 중 두 번째 예제입니다. 아직 작성하지 않았다면 먼저 블록 다이어그램 예제를 읽어보십시오.

10 가지 규칙 ( 블록 다이어그램 예제 참조)을 준수하는 블록 다이어그램을 사용하면 VHDL 코딩이 간단 해집니다.

  • 큰 주변 사각형은 VHDL 개체가되고,
  • 내부 화살표는 VHDL 신호가되고 아키텍처에서 선언되며,
  • 모든 사각형 블록은 아키텍처 본문에서 동기 프로세스가되며,
  • 매 라운드 블록은 아키텍처 본문에서 결합 프로세스가됩니다.

순차 회로의 블록 다이어그램에서이를 설명해 보겠습니다.

순차 회로

회로의 VHDL 모델은 두 개의 컴파일 단위로 구성됩니다.

  • 회로의 이름과 인터페이스 (포트 이름, 방향 및 유형)를 설명하는 엔티티. 블록 다이어그램의 큰 주변 직사각형을 직접 번역합니다. 데이터가 정수이고 clock 이 VHDL 유형 bit (두 값만 '0''1' )를 사용한다고 가정하면 순차 회로의 엔티티는 다음과 같을 수 있습니다.
entity sequential_circuit is
  port(
    Data_in:  in  integer;
    Clock:    in  bit;
    Data_out: out integer
  );
end entity sequential_circuit;
  • 회로의 내부 구조를 설명하는 아키텍처입니다. 내부 신호가 선언되고 모든 프로세스가 인스턴스화되는 위치입니다. 우리의 순차 회로 아키텍처의 골격은 다음과 같습니다.
architecture ten_rules of sequential_circuit is
  signal Sum, Next_sum: integer;
begin
  <...processes...>
end architecture ten_rules;

아키텍처 본문에 추가 할 프로세스는 세 개의 동기식 (사각 블록)과 두 개의 조합형 (라운드 블록)입니다.

동기식 프로세스는 다음과 같습니다.

process(clock)
begin
  if rising_edge(clock) then
    o1 <= i1;
    ...
    ox <= ix;
  end if;
end process;

여기서 i1, i2,..., ix 는 다이어그램의 해당 사각형 블록에 들어가는 모든 화살표이고 o1, ..., ox 는 다이어그램의 해당 사각형 블록을 출력하는 모든 화살표입니다. 물론 신호의 이름을 제외하고는 아무 것도 변경되지 않습니다. 아무것도. 한 문자조차도 아닙니다.

이 예제의 동기식 프로세스는 다음과 같습니다.

  process(clock)
  begin
    if rising_edge(clock) then
      Sum <= Next_sum;
    end if;
  end process;

비공식적으로 번역 할 수있는 것은 다음과 같습니다. clock 바뀌면 변경이 상승 에지 ( '0' 에서 '1' )이면 신호 Next_sum 의 값을 신호 Sum 할당합니다.

조합 프로세스는 다음과 같습니다.

process(i1, i2,... , ix)
  variable v1: <type_of_v1>;
  ...
  variable vy: <type_of_vy>;
begin
  v1 := <default_value_for_v1>;
  ...
  vy := <default_value_for_vy>;
  o1 <= <default_value_for_o1>;
  ...
  oz <= <default_value_for_oz>;
  <statements>
end process;

여기서 i1, i2,..., in 은 다이어그램의 해당 라운드 블록에 들어가는 모든 화살표입니다. 모두 와 더 이상. 우리는 어떤 화살도 잊지 않을 것이며 우리는 목록에 다른 것을 추가하지 않을 것입니다.

v1, ..., vy 는 프로세스의 코드를 단순화하는 데 필요한 변수입니다. 그들은 다른 필수 프로그래밍 언어와 똑같은 역할을합니다 : 일시적인 가치를 유지하십시오. 그들은 읽히기 전에 절대적으로 모두 배정되어야합니다. 우리가이를 보장하지 못한다면 프로세스는 하나의 프로세스 실행에서 다음 프로세스 실행으로 일부 변수의 값을 유지하기 위해 메모리 요소의 종류를 모델링 할 것이므로 더 이상 조합 적이 지 않을 것입니다. 이것이 프로세스의 시작 부분에있는 vi := <default_value_for_vi> 구문의 이유입니다. <default_value_for_vi> 는 상수 여야합니다. 그렇지 않다면 표현식이라면 실수로 표현식에서 변수를 사용하고 할당하기 전에 변수를 읽을 수 있습니다.

o1, ..., om 은 다이어그램의 해당 라운드 블록을 출력하는 모든 화살표입니다. 모두 와 더 이상. 프로세스 실행 중에 반드시 한 번 이상 할당해야합니다. VHDL 제어 구조 ( if , case ...)는 출력 신호가 할당되는 것을 매우 쉽게 막을 수 있으므로 프로세스 초기에 무조건적으로 각 변수를 상수 값 <default_value_for_oi> 에 할당하는 것이 좋습니다. 이렇게하면 if 문이 신호 할당을 마스크하더라도 어쨌든 값을 수신하게됩니다.

변수의 이름 (있는 경우), 입력 이름, 출력 이름, <default_value_for_..> 상수 및 <statements> 의 값을 제외하고는이 VHDL 스켈레톤으로 변경되지 않아야합니다. 당신은 합성 (대부분 래치를) 원치 않는 메모리 요소를 추론 할 할 경우, 하나의 기본 값 할당을 잊지 마세요 그 결과는 당신이 처음에 원하는 것을하지 않습니다.

예제 순차 회로에서 결합 가산기 프로세스는 다음과 같습니다.

  process(Sum, Data_in)
  begin
    Next_sum <= 0;
    Next_sum <= Sum + Data_in;
  end process;

비공식적으로 다음과 같이 변환 할 수 있습니다 : Sum 또는 Data_in (또는 둘 다)이 변경되면 Next_sum 신호에 값 0을 할당 한 다음 Sum + Data_in 값을 다시 할당합니다.

첫 번째 할당 (상수 기본값이 0 )에 즉시 덮어 쓰기되는 다른 할당이 있기 때문에 다음과 같이 단순화 할 수 있습니다.

  process(Sum, Data_in)
  begin
    Next_sum <= Sum + Data_in;
  end process;

두 번째 조합 프로세스는 2008 년 이전의 VHDL 버전을 준수하기 위해 두 개 이상의 대상이있는 출력 화살표에 추가 한 라운드 블록에 해당합니다. 코드는 간단합니다.

  process(Sum)
  begin
    Data_out <= 0;
    Data_out <= Sum;
  end process;

다른 조합 프로세스와 같은 이유로, 우리는 다음과 같이 단순화 할 수 있습니다.

  process(Sum)
  begin
    Data_out <= Sum;
  end process;

순차 회로의 전체 코드는 다음과 같습니다.

-- File sequential_circuit.vhd
entity sequential_circuit is
  port(
    Data_in:  in  integer;
    Clock:    in  bit;
    Data_out: out integer
  );
end entity sequential_circuit;

architecture ten_rules of sequential_circuit is
  signal Sum, Next_sum: integer;
begin
  process(clock)
  begin
    if rising_edge(clock) then
      Sum <= Next_sum;
    end if;
  end process;

  process(Sum, Data_in)
  begin
    Next_sum <= Sum + Data_in;
  end process;

  process(Sum)
  begin
    Data_out <= Sum;
  end process;
end architecture ten_rules;

참고 : 세 가지 프로세스를 순서에 상관없이 작성할 수 있으며 시뮬레이션 또는 합성의 최종 결과를 변경하지는 않습니다. 이것은 세 개의 프로세스가 동시성 문이고 VHDL이 그것들이 실제로 병렬 인 것처럼 처리하기 때문입니다.

존 쿨리의 디자인 콘테스트

이 예는 SNUG'95 (Synopsys Users Group 회의)의 John Cooley 디자인 콘테스트에서 직접 파생되었습니다. 이 콘테스트는 VHDL과 Verilog 설계자가 같은 디자인 문제에 반대하는 것을 목표로했습니다. John이 염두에 두었던 것은 아마 어떤 언어가 가장 효율적인지를 결정하는 것이 었습니다. 그 결과 9 명의 Verilog 설계자 중 8 명이 디자인 공모전을 마칠 수 있었지만 5 명의 VHDL 설계자 중 누구도 설계 공모를 완료 할 수 없었습니다. 잘하면, 제안 된 방법을 사용하여, 우리는 훨씬 더 잘할 것입니다.

명세서

우리의 목표는 일반 합성 VHDL (엔티티 및 아키텍처)에서 캐리 출력, 차용 출력 및 패리티 출력과 함께 동기식 업 - 바이 - 3, 다운 - 투 - 5,로드 가능한 모듈러스 512 카운터를 설계하는 것입니다. 카운터는 9 비트 부호없는 카운터이므로 0과 511 사이의 값을 갖습니다. 카운터의 인터페이스 사양은 다음 표에 나와 있습니다.

이름 비트 너비 방향 기술
시계 1 입력 마스터 클럭; 카운터는 CLOCK의 상승 에지에서 동기화됩니다.
DI 9 입력 데이터 입력 버스; UP과 DOWN이 모두 낮을 때 카운터에 DI가로드됩니다.
쪽으로 1 입력 최대 3 카운트 명령; UP이 하이이고 DOWN이 로우 일 때 카운터는 3을 증가시키고 최대 값 (511)을 감싼다.
내려가는 1 입력 아래로 5 카운트 명령; DOWN이 높고 UP이 낮 으면 카운터가 5 씩 감소하고 최소값 (0)을 감 쌉니다.
콜로라도 주 1 산출 신호를 수행하십시오. 최대 값 (511)을 초과하여 카운트 업했을 때만 하이가되어
1 산출 신호를 빌려 라. 최소값 (0) 아래로 카운트 다운 할 때만 하이가되어 랩 어라운드
해야 할 것 9 산출 출력 버스; 카운터의 현재 값. UP과 DOWN이 모두 높으면 카운터는 값을 유지합니다.
PO 1 산출 패리티 아웃 신호; 카운터의 현재 값이 1의 짝수를 포함 할 때 하이

최대 값을 초과하여 카운트 할 때 또는 카운터의 최소값 아래로 카운트 할 때 카운터가 래핑됩니다.

카운터 현재 값 위아래 다음 값 카운터 다음 CO 다음 보 다음 PO
엑스 00 DI 0 0 패리티 (DI)
엑스 11 엑스 0 0 패리티 (x)
0 ≤ x ≤ 508 10 x + 3 0 0 패리티 (x + 3)
509 10 0 1 0 1
510 10 1 1 0 0
511 10 2 1 0 0
5 ≤ x ≤ 511 01 x-5 0 0 패리티 (x-5)
4 01 511 0 1 0
01 510 0 1 1
2 01 509 0 1 1
1 01 508 0 1 0
0 01 507 0 1 1

블록 다이어그램

이러한 사양을 기반으로 블록 다이어그램을 설계 할 수 있습니다. 우선 인터페이스를 나타냅니다.

외부 인터페이스

우리의 회로는 4 개의 입력 (클럭 포함)과 4 개의 출력을 가지고 있습니다. 다음 단계는 우리가 사용할 레지스터와 조합 블록의 수와 역할을 결정하는 것입니다. 이 간단한 예제에서 우리는 하나의 조합 블록을 카운터의 다음 값 계산, 수행 및 차용 계산에 할당합니다. 또 다른 조합 블록은 패리티의 다음 값을 계산하는 데 사용됩니다. 카운터의 현재 값, 실행 및 차용은 레지스터에 저장되며 패리티의 현재 값은 별도의 레지스터에 저장됩니다. 결과는 아래 그림과 같습니다.

2 개의 조합 블록과 2 개의 레지스터

블록 다이어그램이 10 가지 디자인 룰을 준수하는지 확인하는 작업은 신속하게 수행됩니다.

  1. 우리의 외부 인터페이스는 큰 주변 사각형으로 적절하게 표현됩니다.
  2. 두 개의 조합 블록 (둥근)과 두 개의 레지스터 (사각형)가 명확하게 분리되어 있습니다.
  3. 우리는 상승 에지 트리거 레지스터만을 사용합니다.
  4. 우리는 하나의 시계만을 사용합니다.
  5. 4 개의 내부 화살표 (신호), 4 개의 입력 화살표 (입력 포트) 및 4 개의 출력 화살표 (출력 포트)가 있습니다.
  6. 우리의 화살 중 어느 것도 몇 가지 기원을 가지고 있지 않습니다. 3 개의 목적지 ( clock , ncnt , do )가 있습니다.
  7. 4 개의 입력 화살표 중 어느 것도 내부 블록의 출력이 아닙니다.
  8. 우리 출력 화살표 중 세 개는 정확히 원점과 목적지가 각각 하나씩 있습니다. 그러나 do 에는 2 개의 목적지가 있습니다 : 외부와 우리의 조합 블록 중 하나. 이는 규칙 번호 8을 위반하며 2008 년 이전의 VHDL 버전을 준수하려면 새로운 조합 블록을 삽입하여 수정해야합니다.

여분의 콤비네이션 블럭 1 개

  1. 이제 정확히 5 개의 내부 신호 ( cnt , nco , nbo , ncntnpo )가 있습니다.
  2. 다이어그램에는 cntncnt 의해 형성된 사이클이 하나만 있습니다. 사이클에 사각형 블록이 있습니다.

2008 년 이전의 VHDL 버전 코딩

블록 다이어그램을 VHDL로 변환하는 것은 간단합니다. 카운터의 현재 값 범위는 0에서 511까지이므로 9 비트의 bit_vector 신호를 사용하여이를 나타냅니다. 유일한 미묘한 점은 동일한 데이터에 대해 비트 단위 (예 : 패리티 계산)와 산술 연산을 수행해야하기 때문입니다. 표준 numeric_bit 라이브러리의 패키지 ieee 해결할 수있는 문제는이 : 그것은 선언 unsigned 과 정확히 같은 선언 유형 bit_vector 그들이 어떤 혼합물 수행하는 산술 연산자는 오버로드 unsigned 및 정수. 캐리 아웃과 빌리 아웃을 계산하기 위해 우리는 10 비트의 unsigned 임시 값을 사용할 것입니다.

라이브러리 선언과 엔티티 :

library ieee;
use ieee.numeric_bit.all;

entity cooley is
  port(
        clock: in  bit;
        up:    in  bit;
        down:  in  bit;
        di:    in  bit_vector(8 downto 0);
        co:    out bit;
        bo:    out bit;
        po:    out bit;
        do:    out bit_vector(8 downto 0)
      );
end entity cooley;

아키텍처의 골격은 다음과 같습니다.

architecture arc1 of cooley is
  signal cnt:  unsigned(8 downto 0);
  signal ncnt: unsigned(8 downto 0);
  signal nco:  bit;
  signal nbo:  bit;
  signal npo:  bit;
begin
    <...processes...>
end architecture arc1;

각 블록은 프로세스로 모델링됩니다. 우리의 두 레지스터에 해당하는 동기식 프로세스는 매우 쉽게 코딩 할 수 있습니다. 우리는 단순히 코딩 예제에서 제안 된 패턴을 사용합니다. 예를 들어, 패리티 아웃 플래그를 저장하는 레지스터는 다음과 같이 코딩됩니다.

  poreg: process(clock)
  begin
    if rising_edge(clock) then
      po <= npo;
    end if;
  end process poreg;

co , bocnt 를 저장하는 다른 레지스터 :

  cobocntreg: process(clock)
  begin
    if rising_edge(clock) then
      co  <= nco;
      bo  <= nbo;
      cnt <= ncnt;
    end if;
  end process cobocntreg;

이름 바꾸기 조합 프로세스도 매우 간단합니다.

  rename: process(cnt)
  begin
    do <= (others => '0');
    do <= bit_vector(cnt);
  end process rename;

패리티 계산은 변수와 간단한 루프를 사용할 수 있습니다.

  parity: process(ncnt)
    variable tmp: bit;
  begin
    tmp := '0';
    npo <= '0';
    for i in 0 to 8 loop
      tmp := tmp xor ncnt(i);
    end loop;
    npo <= not tmp;
  end process parity;

마지막 조합 프로세스는 가장 복잡하지만 제안 된 번역 방법을 엄격하게 적용하면 쉽게 수행 할 수 있습니다.

  u3d5: process(up, down, di, cnt)
    variable tmp: unsigned(9 downto 0);
  begin
    tmp  := (others => '0');
    nco  <= '0';
    nbo  <= '0';
    ncnt <= (others => '0');
    if up = '0' and down = '0' then
      ncnt <= unsigned(di);
    elsif up = '1' and down = '1' then
      ncnt <= cnt;
    elsif up = '1' and down = '0' then
      tmp   := ('0' & cnt) + 3;
      ncnt  <= tmp(8 downto 0);
      nco   <= tmp(9);
    elsif up = '0' and down = '1' then
      tmp   := ('0' & cnt) - 5;
      ncnt  <= tmp(8 downto 0);
      nbo   <= tmp(9);
    end if;
  end process u3d5;

두 개의 동기식 프로세스가 병합 될 수 있고 우리의 결합 프로세스 중 하나가 단순한 동시 신호 할당에서 단순화 될 수 있음에 유의하십시오. 라이브러리 및 패키지 선언과 제안 된 단순화가 포함 된 전체 코드는 다음과 같습니다.

library ieee;
use ieee.numeric_bit.all;

entity cooley is
  port(
        clock: in  bit;
        up:    in  bit;
        down:  in  bit;
        di:    in  bit_vector(8 downto 0);
        co:    out bit;
        bo:    out bit;
        po:    out bit;
        do:    out bit_vector(8 downto 0)
      );
end entity cooley;

architecture arc2 of cooley is
  signal cnt:  unsigned(8 downto 0);
  signal ncnt: unsigned(8 downto 0);
  signal nco:  bit;
  signal nbo:  bit;
  signal npo:  bit;
begin
  reg: process(clock)
  begin
    if rising_edge(clock) then
      co  <= nco;
      bo  <= nbo;
      po  <= npo;
      cnt <= ncnt;
    end if;
  end process reg;

  do <= bit_vector(cnt);

  parity: process(ncnt)
    variable tmp: bit;
  begin
    tmp := '0';
    npo <= '0';
    for i in 0 to 8 loop
      tmp := tmp xor ncnt(i);
    end loop;
    npo <= not tmp;
  end process parity;

  u3d5: process(up, down, di, cnt)
    variable tmp: unsigned(9 downto 0);
  begin
    tmp  := (others => '0');
    nco  <= '0';
    nbo  <= '0';
    ncnt <= (others => '0');
    if up = '0' and down = '0' then
      ncnt <= unsigned(di);
    elsif up = '1' and down = '1' then
      ncnt <= cnt;
    elsif up = '1' and down = '0' then
      tmp   := ('0' & cnt) + 3;
      ncnt  <= tmp(8 downto 0);
      nco   <= tmp(9);
    elsif up = '0' and down = '1' then
      tmp   := ('0' & cnt) - 5;
      ncnt  <= tmp(8 downto 0);
      nbo   <= tmp(9);
    end if;
  end process u3d5;
end architecture arc2;

조금 더 가다.

제안 된 방법은 간단하고 안전하지만 완화 할 수있는 몇 가지 제약 조건에 의존합니다.

블록 다이어그램 건너 뛰기

숙련 된 설계자는 단순한 설계를 위해 블록 다이어그램을 건너 뛸 수 있습니다. 그러나 그들은 여전히 ​​하드웨어를 먼저 생각합니다. 그들은 종이 대신에 머리를 쓰지 만, 어떻게 든 그리기를 계속합니다.

비동기식 재설정 사용

비동기식 리셋 (또는 세트)이 디자인의 품질을 향상시킬 수있는 상황이 있습니다. 제안 된 방법은 동기식 리셋 (즉, 클럭의 상승 에지에서 고려되는 리셋) 만 지원합니다.

  process(clock)
  begin
    if rising_edge(clock) then
      if reset = '1' then
        o <= reset_value_for_o;
      else
        o <= i;
      end if;
    end if;
  end process;

비동기식 재설정 버전은 민감도 목록에 재설정 신호를 추가하고 가장 우선 순위를 지정하여 템플릿을 수정합니다.

  process(clock, reset)
  begin
    if reset = '1' then
      o <= reset_value_for_o;
    elsif rising_edge(clock) then
      o <= i;
    end if;
  end process;

몇 가지 간단한 프로세스 병합

우리는 예제의 최종 버전에서 이미 이것을 사용했습니다. 시계가 같은 경우 여러 개의 동기식 프로세스를 병합하는 것은 간단합니다. 여러 조합 프로세스를 하나의 프로세스로 병합하는 것도 간단하며 블록 다이어그램을 단순하게 재구성하는 것입니다.

또한 일부 조합 프로세스를 동기 프로세스와 병합 할 수도 있습니다. 그러나 이것을하기 위해서는 우리의 블록 다이어그램으로 돌아가서 11 번째 규칙을 추가해야합니다 :

  1. 여러 개의 둥근 블록과 하나 이상의 사각형 블록을 둘러 싸서 둘러 쌉니다. 또한 화살표를 동봉 할 수 있습니다. 화살표가 인클로저의 경계를 넘지 않도록주의하십시오. 이 작업이 완료되면 인클로저의 모든 출력 화살표를 살펴보십시오. 이 중 하나가 인클로저의 둥근 블록에서 나온 것이거나 인클로저의 입력이기도하면 이러한 프로세스를 동기식 프로세스로 병합 할 수 없습니다. 그렇지 않으면 우리가 할 수 있습니다.

예를 들어 우리의 카운터 예에서 다음 그림의 빨간색 인클로저에 두 프로세스를 그룹화 할 수 없습니다.

병합 할 수없는 프로세스

왜냐하면 ncnt 는 엔클로저의 출력이고 원점은 둥근 (조합) 블록이기 때문입니다. 그러나 그룹화 할 수 있습니다.

병합 할 수있는 프로세스

내부 신호 npo 는 쓸모 없게되고 결과 프로세스는 다음과 같습니다.

  poreg: process(clock)
    variable tmp: bit;
  begin
    if rising_edge(clock) then
      tmp := '0';
      for i in 0 to 8 loop
        tmp := tmp xor ncnt(i);
      end loop;
      po <= not tmp;
    end if;
  end process poreg;

다른 동기 프로세스와 병합 될 수도 있습니다.

  reg: process(clock)
    variable tmp: bit;
  begin
    if rising_edge(clock) then
      co  <= nco;
      bo  <= nbo;
      cnt <= ncnt;
      tmp := '0';
      for i in 0 to 8 loop
        tmp := tmp xor ncnt(i);
      end loop;
      po <= not tmp;
    end if;
  end process reg;

그룹화는 다음과 같을 수도 있습니다.

더 많은 그룹화

훨씬 단순한 아키텍처로 이어진다.

architecture arc5 of cooley is
  signal cnt: unsigned(8 downto 0);
begin
  process(clock)
    variable ncnt: unsigned(9 downto 0);
    variable tmp:  bit;
  begin
    if rising_edge(clock) then
      ncnt := '0' & cnt;
      co   <= '0';
      bo   <= '0';
      if up = '0' and down = '0' then
        ncnt := unsigned('0' & di);
      elsif up = '1' and down = '0' then
        ncnt := ncnt + 3;
        co   <= ncnt(9);
      elsif up = '0' and down = '1' then
        ncnt := ncnt - 5;
        bo   <= ncnt(9);
      end if;
      tmp := '0';
      for i in 0 to 8 loop
        tmp := tmp xor ncnt(i);
      end loop;
      po  <= not tmp;
      cnt <= ncnt(8 downto 0);
    end if;
  end process;

  do <= bit_vector(cnt);
end architecture arc5;

두 개의 프로세스가 있습니다 ( do 의 동시 신호 지정은 동등한 프로세스의 약식입니다). 프로세스 하나만있는 솔루션은 연습으로 남겨 둡니다. 주의 깊고 흥미롭고 미묘한 질문을 제기합니다.

더 나아가 라.

레벨 트리거 래치, 클럭 에지의 하강, 클록 (클록 도메인 간 재 동기화), 동일한 신호에 대한 여러 드라이버 등은 악의가 없습니다. 때로는 유용합니다. 그러나 VHDL을 사용하는 디지털 하드웨어 설계에 대한 간략한 소개를 넘어서서 이들을 사용하는 방법과 관련 함정을 피하는 방법을 배우게됩니다.

VHDL 2008 코딩

VHDL 2008에는 코드를 더 단순화하기 위해 사용할 수있는 몇 가지 수정 사항이 추가되었습니다. 이 예제에서 우리는 2 가지 수정의 이점을 누릴 수 있습니다.

  • 출력 포트를 읽을 수 있으므로 더 이상 cnt 신호가 필요하지 않습니다.
  • unary xor 연산자를 사용하여 패리티를 계산할 수 있습니다.

VHDL 2008 코드는 다음과 같습니다.

library ieee;
use ieee.numeric_bit.all;

entity cooley is
  port(
        clock: in  bit;
        up:    in  bit;
        down:  in  bit;
        di:    in  bit_vector(8 downto 0);
        co:    out bit;
        bo:    out bit;
        po:    out bit;
        do:    out bit_vector(8 downto 0)
      );
end entity cooley;

architecture arc6 of cooley is
begin
  process(clock)
    variable ncnt: unsigned(9 downto 0);
  begin
    if rising_edge(clock) then
      ncnt := unsigned('0' & do);
      co   <= '0';
      bo   <= '0';
      if up = '0' and down = '0' then
        ncnt := unsigned('0' & di);
      elsif up = '1' and down = '0' then
        ncnt := ncnt + 3;
        co   <= ncnt(9);
      elsif up = '0' and down = '1' then
        ncnt := ncnt - 5;
        bo   <= ncnt(9);
      end if;
      po <= not (xor ncnt(8 downto 0));
      do <= bit_vector(ncnt(8 downto 0));
    end if;
  end process;
end architecture arc6;


Modified text is an extract of the original Stack Overflow Documentation
아래 라이선스 CC BY-SA 3.0
와 제휴하지 않음 Stack Overflow