[HARMAN] 세미콘 아카데미/SystemVerilog

[Harman 세미콘 아카데미] Day_63(System Verilog)

uiop1716 2025. 5. 14. 10:14

-  MicroBlaze : CPU
-  Local Memory : Memory
-  MDM : Debugging Tool
-  InterConnector : AXI Protocol을 위한 교환원
-  CLK : System Clock 

MicroBalze & 기본 구성 요소
UART & GPIO추가

 
Peripheral을 위한 GPIO와 UART를 추가하고 이들을 HDL로 Wrapping을 하게 되면, Application을 동작하기 위한 플랫폼이 생성이 되는 것입니다. HDL Wrapping 후 생성되는 Top Module의 Instance들을 Constraints에 적용을 시켜 (ex. GPIOA에 대한 0~8번은 Switch로, 8~16번은 LED에 할당) BitStream을 만들어 사용하면 됩니다.

Wrapping한 결과의 Top Module
GPIOA를 Switch, LED 제어를 위해 Constraint 할당

 
 
플랫폼은 Application을 동작하기 위한 준비 단계입니다. CPU, Memory, IO 등의 하드웨어와 그 위에 얹어지는 GPIO, UART, I2C, Device Driver 그리고 운영체제인 OS까지를 합쳐 플랫폼이라고 합니다. 이러한 구성들이 Application이 잘 동작할 수 있도록 합니다.

플랫폼 이미지


 
이를 Hardware Export한 후, 생성된 .xsa 파일에 Vitis를 연결하여 SW를 작성합니다.

 
 
기본으로 있는 Hello World 파일을 UART를 9600의 Baudrate로 연결시켜 Terminal 창을 통해 확인합니다. Reset 버튼을 누를때마다 "Successfully ran Hello World application"이 뜨며 UART 통신이 잘 되는 것을 확인할 수 있습니다.

UART 확인

 
 
또한, GPIO에 대한 확인을 위해 아래와 같이 코드를 구성합니다. GPIO_CR이라는 input/output 모드 설정을 통해 상위 bit는 input 모드, 하위 bit는 output mode로 설정하여 하위 비트의 LED를 깜빡입니다. GPIO_DR의 값을 ff와 00을 0.3초의 Delay를 넣어 동작시키면, 0.3초마다 0~8번 LED가 깜빡이는 것을 확인할 수 있습니다. 

0.3초마다 LED를 깜빡이도록 설계

 
 
아래의 코드와 같이 깜빡이는 횟수도 Terminal을 통해 출력할 수 있습니다.

깜빡이는 횟수를 Count함

 
 
 
아래의 코드와 같이, 동일한 코드를 구조체를 활용하여 만들수도 있습니다. GPIO_BASEADDR을 기준으로 하여 4byte의 DR, CR이 각각 0x4000_0000, 0x4000_0004의 주소를 갖으며 생성됩니다.

구조체 설계

 
 
Masking 방식을 활용(Shift Register)를 사용하여, 13번 Switch가 "HIGH"가 되면 LED를 깜빡이도록 설정할 수 있습니다.

Switch로 LED 제어

 
 
13번 스위치로는 상위 4개의 LED를 깜빡이고, 8번스위치로는 하위 4개의 LED를 깜빡이도록 제어하는 코드입니다. Shift Register를 통해, Switch를 선택하여 값을 입력할 수 있습니다.

Switch로 LED 제어하기 위함

 
 
 
이제는 저희가 만든 IP를 활용해 보겠습니다. 저번에 만들어 두었던 GPIO IP를 추가합니다. AXI Interface와 전체 Top Module에 GPIO에 대해 연결을 하여, AXI Protocol을 활용해 저희가 만든 GPIO를 Peripheral로 연결하여 동작시킬 수 있습니다.

GPIO IP 추가

 
 
*** 이때, 생성되는 MakeFile에 아래와 같은 코드 수정을 통해 오류를 해결해야 합니다. (수정을 하지 않으면, Compile 시 오류가 발생합니다)
 
ip_repo -> File명 -> driver -> file명 - > Makefile 수정

 
 
그래서 저희가 만든 GPIO IP를 MicroBlaze와 연결하여 GPIOB 라는 Peripheral을 하나 더 만들어 주었습니다. io_port에 관해서 make external port를 해주어, io_port 선을 만들어 주었습니다.

내가 만든 GPIO IP 추가

 
 
아래의 그림과 같이 MemoryMap에도 잘 할당되어 있는 모습을 확인할 수 있습니다.

MemoryMap

 
 
다 연결하였으면 Generate Block Design에서 Synthesis Options를 Global로 바꿔 주어야 합니다. 이는 IO_Port의 Input과 Output을 모두 사용하기 위한 설정입니다.

IO Global 설정

 
 
이렇게 생성한(저희가 만든 GPIO IP가 추가된) 플랫폼에서 Vitis에 SW를 구성해 봅니다. 이때, Constraint 설정을 통해 GPIOB의 하위 0~3는 LED를, 상위 4~7은 Switch를 사용하도록 설계하였습니다.

Constraint 설정

 
 
저희가 생성한 GPIO는 Memory Map의 0x44a0_0000의 위치에 할당되어있기 때문에 이를 BaseAddress로 잡고 구조체를 설정해 주었습니다. Shift Register를 통해 GPIO[4]번 즉, 첫번째 스위치를 ON 시키면 상위 LED[15] ~ [12]  4개가 점멸하도록 설계하였습니다.

해당 Code

 
 
그리고, synopsys를 통해 UVM 검증에 대해 알아 보았습니다. 운이 좋게도, 이번 교육에 synopsys를 사용해볼 기회가 생겼습니다. 먼저, mobaxterm을 통해 메인 서버에 ssh 접속을 하여 교육을 진행하였습니다.
오늘은 시간이 많지 않아 linux 기본 명령어에 대한 설명과 간단한 uvm 검증을 진행하였습니다. 아래는 유용한 간단한 linux 기본 명령어들입니다.

                  - mkdir : make directory
                  - ls , ll   : 파일 확인
                  - cd      : Change directory
                  - rm      : Remove directory
                  - cp      : Copy directory
                  - mv     : move
                  - vcs     : compiler

그래서, 새로운 디렉토리를 만들고 systemverilog 언어로 hello_world.sv 파일을 만들고 아래와 같은 코드를 작성해 주었습니다.
코드 설명을 간략히 하면, uvm_test라는 부모 객체와 검증하고자 하는 hello_world를 생성합니다. 이들을 불러와 objection.raise/drop을 통해 테스트를 진행하는 동안 다른 Interrupt가 들어오지 못하도록 막습니다.

hello_world.sv

 

###### 코드 설명 #####

import uvm_pkg::* :    Accellera에서 제공하는 uvm 클래스 라이브러리 전체 패키지를 적용

class hello_world extends uvm_test :    
extends 상속,
uvm_test : 부모 class (uvm의 최상위 시나리오(test)용 베이스 클래스), run_test(); 실행하면 Factory가 가장 먼저 생성하는 객체

`uvm_component_utils(hello_world) : Factory에 클래스를 등록하는 매크로

function new(string name, uvm_component parent)  : Class instance를 만들기 위한 생성자
super.new(name,parent)        : super - 부모 class = uvm_test 


virtual task run_phase(uvm_phase phase);    : 동작 시뮬레이션 task, 동작 시뮬레이션 구간 phase
          phase.raise_objection(this);              : objection 메커니즘, 프로그램 종료 불가하게 함(interrupt 금지)
          `uvm_info("TEST", "hello world!", UVM_MEDIUM);   : (표시, string/Message, UVM_MEDIUM -verbosity)
          phase.drop_objection(this);              : 프로그램 종료해도 됨(interrupt 해도됨) 
endtask

####################


아래 그림은 UVM Test 결과입니다. 코드에 작성한 설명 부분처럼 UVM_INFO에  [TEST] hello_world! 가 뜨는 것을 확인할 수 있습니다. 저번 SystemVerilog로 Testbech를 설계했던 때의 결과처럼 4번 검증하고 Report로 나타내주는 것을 확인할 수 있습니다.

UVM Test 결과

 


아래의 UVM diagram의 구조와 같이 test를 진행한 것입니다. 온전한 테스트는 아니지만 앞으로 이러한 방식으로 Synopsys를 활용한 UVM 검증에 대해 더 경험하고 배울 수 있을것 같습니다.

Basix UVM Diagram