본문 바로가기

HW

Xilinx HLS interface에 대하여

 

이전 글 목록

 

[HW] - Xilinx HLS tutorial (1) - VIVADO install & Tutorial Data Download

[HW] - Xilinx HLS tutorial (2) - Creating HLS project

[HW] - Xilinx HLS tutorial (3) - Tcl Command Interface 사용하기

[HW] - Xilinx HLS tutorial (4) - Port 설정

[HW] - [Xilinx] hls::Mat 사용에 대해서 // HLS convolution tutorial 이해를 위해

 


오늘은 HLS interface에 대한 내용을

온라인에 나와있는걸 마음대로 해석하여

적어보도록 하겠습니다.

 

두가지를 참조하여 적습니다.

 

1.

 

https://www.xilinx.com/html_docs/xilinx2017_4/sdaccel_doc/jit1504034365862.html

 

pragma HLS interface

Description In C based design, all input and output operations are performed, in zero time, through formal function arguments. In an RTL design these same input and output operations must be performed through a port in the design interface and typically op

www.xilinx.com

2. ug902 - Vivado-HLS

https://www.xilinx.com/support/documentation/sw_manuals/xilinx2019_2/ug902-vivado-high-level-synthesis.pdf

 

제 영어실력 때문에 제대로

전달되지 않을 가능성이 높으니

확실하게 하고 싶으신 분들은

문서를 직접 보시기 바랍니다.


C 기반의 설계에서 모든 입력과 출력 동작은

formal funciton argument들을 통해

동시에 수행됩니다. 

 

RTL 설계에서 같은 입출력 동작은 반드시

design interface의 port를 통해서 수행되고

명확한 I/O protocol을 사용하여 동작합니다.

 

Vivado HLS는 C/C++을 이용해서 설계를 합니다.

사용되는 I/O protocol을 명확하게 하기위해서

 

Interface Synthesis를 수행합니다.


Interface Synthesis

 

top-level function이 합성될 때,

함수의 arguments(or parameters)는

RTL ports로 합성됩니다.

이 과정을 Interface Synthesis라고 부릅니다.

 

// Vivado HLS interface Synthesis Example Code

#include "sum_io.h"

dout_t sum_io(din_t in1, din_t in2, dio_t *sum) {
	dout_t temp;
    
    *sum = in1 + in2 + *sum;
    temp = in1 + in2;
    
    return temp;
}

 

위 코드는 ug902문서에 있는 코드입니다.

 

코드를 보면

in1, in2라는 두개의 input value가 있고

 

sum이라는 pointer 형태의

read, write 모두 수행하는 value가 있고

 

함수의 return을 통해

temp가 반환되도록 되어 있습니다.

 

Default interface synthesis setting으로

합성을 진행하게 되면

RTL Block의 port는

아래 그림과 같이 나타나게 됩니다.

 

 

위 그림에서 볼수 있는 것은

3가지 type의 Port가 있다는 것인데요

 

 

 

 

1. Clock and Reset port

ap_clk과 ap_rst 를 가지고 있습니다.

 

2. Block-Level interface protocol

ap_ctrl 이란 이름으로

ap_start

ap_done

ap_ready

ap_idle를 가지고 있습니다.

 

3. Port-Level interface protocol

 

top-level function의

각 argument와 function의 return에 의해

생성됩니다.

 

in1,

in2,

sum_i,

sum_o,

sum_o_ap_vld,

ap_return

 

등에 해당합니다.

 

 

이렇게 3가지 type은

각각 어떤 특징을 가지고 있는지

살펴 보겠습니다. 


1. Clock and Reset Port

 

Design이 수행할 동작을 완료하기 위해서

1 cycle 이상이 필요하다면

 

A chip-enable는 전체 block에

선택적으로 추가 될 수 있습니다. 

 

설정은 Solution-> Solution Setting ->General에서

config-interface configuration을

사용하면 된다고 하네요 

 

reset동작은 config_rtl configuration을 통해서

사용가능하다고 합니다.

 

2. Block-Level Interface Protocol

 

설계에 block-level interface protocol은

default로 추가됩니다. 

 

이 signal은 어떤 port-level의 I/O protocol들과

무관하게(독립적으로) block을 컨트롤 합니다.

 

이 포트는 block 여러개의 ports를 가지고 있는데

각각 동작하는 순간들이 정해져 있습니다. 

 

ap_start :

block이 processing data를 시작할 수 있을 때

 

ap_ready :

새로운 input을 받을 준비가 되어 있을때

 

ap_idle :

idle 상태일 때

 

ap_done :

동작이 완료 되었을 때

 

위 4가지 상황에서 동작합니다.

 

3. Port-Level Interface Protocol

 

마지막 신호 그룹은 data ports 입니다.

I/O protocol은 C argument의

type에 따라 생성됩니다.

 

block-Level protocol을 이용하여

작업을 수행한 직후에 

Port-level I/O protocols은 block 밖으로

데이터를 내보낼때 사용합니다

 

Default input pass-by-value

arguments and pointer는 

handshaking signal 없이 데이터가 전달 됩니다.

 

그래서 위 코드예제에서 input port들은

I/O protocol이 없이

data port만을 사용해서 전달됩니다.

 

port가 지금 처럼 I/O protocol이 없는 경우에는

input data가 read 될때까지

반드시 안정적으로 유지되어야 합니다.


Default output pointer들은

output valid signal과 함께 구성되는데

valid signal은 output data가 유효함을 나타냅니다.

 

위 예제코드에서 output port는

sum_o_ap_vld 라고 명명된

output valid port를 가지며

이 포트는 지금 port의 data가 유효하고

읽을 수 있는 값임을 표현해 줍니다.

 

만약에 output port에 I/O protocol이 없다면

언제 데이터를 읽어야 할지를 확인하기 어렵습니다.

그래서 output port에는

항상 I/O protocol을 사용하는 것이 좋습니다.

 

Read와 Write둘다 하는 Function arguments

input 과 output port가 분리됩니다.

 

위 코드예제에서 sum은

 

input은 sum_i로 

output은 sum_o로

valid pin으로 sum_o_ap_vld를 가지는

I/O protocol과 함께 

생성 됩니다.

 

만약에 function이 return valud를 가지고 있다면

return value 전달을 위해서

output port로 ap_return이 생성됩니다.

 

'design이 한번의 transaction을 끝냈을때' 가

C function수행이 한번 끝난 것과 동등하고

block-level protocols에서

함수가 끝난 것을 ap_done으로 표현합니다.

 

즉 ap_done pin은 ap_return의

valid pin 역할을 하게 됩니다.

 

참고. HLS에서 return value는

pointer를 사용 할 수 없습니다.

 

동작 예시로서 하단에 Default로 합성된

RTL Port의 Timing도를 확인해 봅니다.

 

 

1.

Design은 ap_start가 High일때 시작됩니다.

 

2.

ap_idle 신호는 동작과 동시에 Low로 내려갑니다.

 

3.

input data는 first cycle 이후에

어떤 사이클에서도 읽어 집니다.

Vivado HLS가 언제 읽기가 발생하는지를 조정합니다.

ap_ready signal은 입력을 읽는 것이 끝났을 때

high로 됩니다.

(다음 읽을 준비가 완료 되었다는 뜻이겠지요?

 

4.

Output sum이 계산되었을때,

output handshake(sum_o_ap_vld)는

데이터가 유효함을 나타냅니다.

 

5.

function의 동작이 끝났을때 ap_done이 동작하고

이것은 ap_return port의

output이 valid 함을 의미합니다.

 

6.

ap_idle는 다음 시작을 기다릴때

High 상태로 남습니다.

 

 


Interface Synthesis

I/O protocols의 결정

 

C argument,

default interface mode,

INTERFACE optimization directive

 

셋중 하나에 의해서 결정됩니다.

 

어떻게 결정되는지는 뒤에서

좀 더 살펴보도록 하겠습니다. 

 

Interface Synthesis I/O protocols에서 

어떤 type의 C argument를 사용하느냐에 따라서

프로토콜을 설정할 수 있거나 자동 설정 되는데 

그것을 표현한 표가 있습니다!

 

해당 표는

아래의 약어를 보고 보시면 이해하기 좋습니다 


D: 각 type에 따른 기본 interface mode

(Default interface mode for each type)

 

I : 읽기만 하는 input 요소

(Input arguments, which are only read)

 

O : 쓰기만 하는 출력 요소

(Output arguments, which are only written to)

 

I/O : 읽기 쓰기 다하는 요소

(Input/Output argument,

which are both read and written)


연한 회색깔은 Not Supported 입니다.

 

즉,

type에 따라 사용 불가능한 protocols이

있을 수 있다는 의미로 보입니다.

 

interface의 모든 detail한 부분들은

Interface Synthesis Reference 부분에

설명이 되어 있다고합니다.

 

같은 가이드의 466p쯤부터 시작되는데요 

 

각 pin의 의미와 timing도를 보면서 설명해주기 때문에

좀 더 자세한 이해가 필요한 경우에

보기 좋은것 같습니다. 


이제 부터는

Block-Level Interface Protocol,

Port-Level Interface Protocol의

 

선택지에 대해서 알아보게 되는데요 

 

예를들어서 실제로 설정한다고 할때 

이렇게 conv 함수의 Insert Directive를 선택하여

 

conv function의 Directive Editor에서

Interface Directive를 설정하는 경우의 mode의 종류는

 

Block-Level protocol interface로

 

위와 같이

 

ap_ctrl_chain

ap_ctrl_hs

ap_ctrl_none

s_axilite

 

가 선택가능한 것을 볼 수 있고

 

 

conv 함수의 port의 Directive Editor에서

Interface Directive를 설정하는 경우 mode의 종류

 

ap_ack

ap_bus

ap_fifo

ap_hs

ap_memory

ap_none

ap_ovld

ap_stable

ap_vld

axis

m_axi

s_axilite

 

등을 선택할 수 있는것을 볼 수 있습니다. 

 

Block 별 Port별 interface protocols에 대해서 지금부터 알아보겠습니다. 

 


Block-Level Interface Protocols

 

앞서서는 너무 간단하게 정리되었던

Block-Level Interface protocol에 대해서 

좀 더 살펴보는 단계가 나와 있습니다. 

 

Block-level interface는

 

ap_ctrl_none

ap_ctrl_hs

ap_ctrl_chain

s_axilite

 

등이 있다고 합니다.

 

이것들은 function또는 function의 return에 의해서

명확해진다고 하네요!

 

Vivado HLS의 GUI에서 directive를 명확히 할때,

이러한 protocol이 function의

return에 적용된다고 합니다.

 

함수가 return값이 없더라도

다른 protocol도 설정할 수 있다고 합니다. 

 

ap_ctrl_hs mode의 경우

앞서 예제코드에서 보았던

default protocol과 같다고 합니다. 

 

ap_ctrl_chain protocol은

ap_ctrl_hs와 유사한데

input port에 ap_continue가 있다고 합니다.

 

ap_continue는 block으로 부터 back pressure를 제공합니다.

 

함수가 완료 되었을때

ap_continue port가 0 이라면

block는 동작을 멈추고

다음 transaction이 진행되지 않을 것이고

 

다음 transaction은

ap_continue port가 1일 경우에만

동작이 된다 라는 겁니다.

 

ap_ctrl_none mode는 설계에

어떤 block-level I/O protocol도 없이 수행됩니다. 

 

ap_ctrl_chain에 포함되는 ap_continue port에 의한 동작은

ug902 pdf의 469p에 나와있는데 

궁금하신 분들은 해당부분을

자세히 읽어보시면 좋을것 같습니다!

 

해당 페이지에 나와있는 timing도를 첨부 합니다!

 

그림을 보시면

ap_ready지만 ap_continue에 의해서 

 

return 값이 유지되고

ap_done도 유지되는

모습을 볼 수 있습니다.


앞서 나온 ap_xxxx와 약간 다른

s_axilite에 대한 이야기를 보겠습니다. 

 

만약에 함수의 return 또한

AXI4-Lite interface(s_axilite)로 지정되면

block-level interface 내부의 모든 port들은

AXI4-Lite interface로 그룹지어집니다.

 

AXI4-lite interface는

CPU로 block의 start나 stop을 조작하는걸 구성할때 

공통적으로 사용되는 practice 입니다.

 

여기까지 다뤄지고 이어서는

Port-Level Interface protocol에 대해 

다룹니다.


Port-Level Interface

Port-Level Interface에는 여러가지 종류가 있지만

크게 4가지 분류로 나눠 볼 수 있습니다.

 

하나씩 살펴보겠습니다!

 


1. AXI4 interface

 

AXI4 interface는 Vivado HLS에서

 

AXI4-Stream(axis),

AXI4-Lite(s_axilite),

AXI4 master(m_axi),

 

등으로 지원합니다. 

 

AXI4-Stream interface

input argument이나

output argument만

지정할 수 있습니다.

input/output arguments는 사용이 불가 합니다. 

 

AXI4-Lite interface는 stream을 제외한

어떤 type의 argument도

지정할 수 있습니다. 

multiple argument들을

같은 AXI4-interface에 그룹 지을 수 있습니다.

 

AXI4 master interface

array들이나 pointer들만 지정할 수 있습니다. 

lite interface와 마찬가지로

multiple arguments를 같은

AXI4 interface에 group 지을 수 있습니다. 

 

2. No I/O Protocol

 

ap_none 그리고 ap_stable mode를 선택하면

I/O protocol이 없는 port를 추가 할 수 있습니다. 

 

이 mode는 argument가 data port로

부가적인 signal 없이 사용될때 선택합니다.

 

ap_none는 scalar input의 default mode 입니다. 

 

ap_stable은 device가 reset mode일때

input 구성이 달라지는 경우에 사용합니다.

 

3. Wire Handshakes

 

Interface mode인 ap_hs

two-way handshake signal을

data port와 함께 사용합니다.

 

Handshake는 산업계 표준인

valid and acknowledge handshake

입니다.

 

ap_vld mode는 같은 방식이지만

valid port만 가지고 있고 

 

ap_ack는 같은 방식이지만

acknowledge port만 가지고 있습니다. 

 

ap_ovld는 in-out argument들을 위해 사용됩니다.

 

ap_ovld를 사용하면

in-out은

input port와

output port로

분리 됩니다. 

 

ap_none은 input port에 적용되고

ap_vld는 output port에 적용됩니다.

 

이것은 read와 write를 다하는

pointer argument의 default 값입니다.

 

ap_hs mode는 sequntial order에 따라

읽고 써지는 array에 적용 될 수 있습니다.

 

만약에 Vivado HLS가 read 또는 write access를

sequential하지 않게 하도록 할 수 있다면,

에러와 함께 합성이 중단 될겁니다. 

만약 acccess 순서가 결정되어 질 수 없다면

Vivado HLS는 warning을 띄울 것입니다.

 

이게 무슨말인지 생각해봤습니다. 

 

array에 접근하는 port를

handshake방식으로 하게 되면

 

valid pin과 ack pin만 추가 될것입니다.

따라서 데이터를 읽어오는건 당연히

sequential하게 접근하게 되는 것이고

당연히 array의 원소에 random하게

접근하는게 불가능할 것입니다.

 

따라서 array 원소에 random접근해야 한다면

그게 가능한 interface를 사용해야 할것입니다. 

 

그래서 이어서 나오는

Port-Level Interface protocol이 바로 

 

4. Memory Interface

 

Array argument들은

ap_memory interface가 default 입니다.

 

ap_memory interface

standard block RAM interface로

 

data

address

chip-enable

write-enable

 

port로 구성되어 있습니다. 

 

ap_memory interface는 

single-port와

dual-port 방식으로

구성할 수 있습니다.

 

dual-port방식으로 interface를 결정하면

initial interval을 줄일수 있을 것입니다.

그래서 자동으로 dual-port로 수행될겁니다.

 

HLS에서 directive 설정할때

RESOURCE directive에서 array에 적용할

single-port block RAM을 interface로 선택하면

single-port block RAM interface가 적용됩니다.

 

거꾸로,

만약에 dual-port interface를

사용하는 것으로 VIAVDO HLS에서

RESOURCE directive에 명시 했는데

이 결정이 아무런 이점을 주지 못한다면

자동적으로

single-port interface로 수행이 된다고 합니다. 

 

bram interface mode는 기능적으로 

ap_memory interface와 동일하게 작동합니다.

 

유일한 차이점은 Vivado IP Integrator에서

design이 사용될때 뿐입니다.

 

ap_memory interface

multiple and separate ports로 표시됩니다.

 

bram interface는 XIlinx block RAM과

single point-to-point connection 할 수 있는

단일 그룹 포트로 표시됩니다.

 

만약에 array가 sequential하게 접근 된다면

ap_fifo interface를 사용할 수 있습니다. 

 

ap_hs interface와 마찬가지로 

data access가 sequential하지 않다면

Vivado HLS는 중지되고 report에 경고가 나옵니다.

 

ap_fifo interface

reading이나 writing 둘중 하나만 선택할 수 있습니다. 

 

ap_bus interface

bus bridge를 통해서 통신 할 수 있습니다. 

이 interface는  특정 bus standard를 따르지는 않지만

 

시스템 버스와 차례대로 조정되는

버스 브릿지에 사용하기에 충분합니다.

 

The bus bridge must be able to cache all burst writes

 

 

 

우와... 내용이 너무 많네요...

 

오늘은 여기까지 하겠습니다!