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

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

uiop1716 2025. 4. 24. 11:38

어제 진행했던 과제를 처음부터 짜보고, 교수님과 함께 짜 보았습니다.

확실히 처음부터 혼자 짜려니 아직은 익숙치 않아 어려움이 많았습니다. 특히, reference model을 설계하여 검증을 하는 부분이 어려웠습니다. 이론은 이해했지만, 아직 손이 따라가지 못하는 것 같습니다...ㅠ

더 많이, 더 열심히 하여 눈을 감고도(?) 설계할 수 있도록 해보겠습니다ㅎㅎ

 

어제 진행하던, FND으 ㅣ각 자리에 숫자를 표현하기를 진행하였습니다. FND Controller라는 IP는 0 또는 1의 enable 신호를 지니는 FCR register의 영향과, 자릿수를 나타내는 FMR, FND에 표시될 FDR에서 값을 받아 FndComm과 FNDFont를 활성화하여 값을 출력합니다.

APB Bus + FND 출력

 

 

이를 테스트하기 위해, System Verilog의 Testbench 형식을 따라 검증을 진행하였습니다. System Verilog의 Testbench의 가장 큰 장점으로, random한 transaction 생성으로 다양한 변수로 검증 작업을 진행할 수 있다는 점이 있습니다.

 

 

먼저 transaction 입니다. transacion은 메모리의 heap영역에서 생성되어 generator, mailbox, monitor, driver, scoreboard등을 거치는 변수라고 생각하면 됩니다. 사용자가 변화시킬 수 있는 값을 generator를 통해 random한 값을 지니게 하고, DUT에 들어갔다가 나오며 DUT에 대한 출력값과, 처음 생성되었던 random한 값들을 비교하여 검증을 진행합니다.

 

아래의 코드에서는, constraint라는 제약사항을 만들어, reigster의 주소인 Write Address를 0,4,8만 갖도록 합니다. 이는 저희가 FCR, FMR, FDR의 3개의 register를 사용할 것이기 때문입니다. 또한, Address에 작성될 Write Data 또한 10000 이하로 설정합니다. 그리고, 위에 언급했던 3개의 레지스터를 구분하도록 c_paddr_0를 통해, 각 register에 접근했을 때의 조건들을 걸어 놓았습니다. 이때, inside { } 함수는 { } 내부의 값 중 랜덤하게 선택되게 합니다. 

Transaction Code

 

Generator 입니다. Generator는 위에서 설명 했듯이, transaction을 heap영역에서 random한 값을 갖고 생성되게 합니다. 그래서 코드를 살펴 보면, transaction fnd_tr을 통해 transaction을 불러와 new()를 통해, instance화 하고 randomize()합니다. 그리고, 이 값을 Gen2Drv_mbox라는 mailbox에 put()합니다. 이 mailbox는 Generator와 Driver 사이에 존재하며, 값을 주고 받고 할 수 있게 합니다. 또한, repeat_counter를 설정하여 random한 transaction을 몇번 반복하여 생성할 지도 설정할 수 있습니다. 한번의 동작이 끝나면, scoreboard로부터 event가 올 때 까지 동작하지 않으며, 신호가 들어오면 새로운 transaction을 생성합니다. 

Generator Code

 

Driver 입니다. Driver는 SW 신호들을 HW의 신호들로 변환해 주는 녀석입니다. 맨 위에서 두번째 그림의 Testbench를 보시게 되면, Interface를 기준으로 상단에 존재하는 Generator, Driver, Mailbox, Monitor, ScoreBoard 들은 SW의 영역에 있다고 보시면 됩니다. 그 아래의 DUT는 HW의 영역이죠. 저희가 테스트할 현재의 transaction들은 SW의 값들인데, 이들을 HW인 DUT에 넣기 위해 Driver가 필요합니다.

Driver는 Generator가 Mailbox에 넣어 두었던 transaction을 가져와서 변환을 진행합니다. 그리하여, 아래 코드에서 fnd_tr의 transaction의 값들이 fnd_intf로 변환되며 interface와 DUT에 들어갈 준비를 합니다. 또한, 이 부분에서 APB_Master, Slave를 구성할 때, Slave가 Master로부터 값들을 받으면 확인의 신호로 PREADY를 기다리게 됩니다. 이곳에서도 동일하게 처리해 주어 APB BUS Protocol을 구현해 줍니다.

Driver Code

 

Interface 코드입니다. Interface는 HW인 DUT와 SW인 Driver, Monitor 사이에 존재하며, 신호들을 다발로 묶어주는 역할을 합니다. 그리하여 instance화하여 나온 신호들과 DUT를 거쳐 나오는 결과값들을 하나의 다발로 묶어 Monitor에 전송합니다.

Interface Code

 

 

아래는 저희가 테스트하고자 하는 FND Controller의 Testbench입니다. 설계한 모듈을 저희가 늘 작성하던 Testbench와 동일하게 작성하되, 값들을 Interface에서 만들어내는 값들을 입력하여 주어 테스트를 진행합니다. 그리하여, Generator가 생성한 Random한 trasaction이 Driver에 의해 HW 신호로 변경되어 들어오게 되는 것 입니다. 이때, run을 1000번으로 하여 테스트를 진행했습니다.

DUT Code

 

Environment입니다. Generator, Mailbox, Driver, Monitor, Scoreboard 등 변수에 대한 환경을 만들고 처리를 하는 부분입니다. Interface, DUT와 연결되어 전체적인 Testbench를 생성합니다. fork join_any를 통해, 각 클래스들의 run 동작을 실행하고, 하나라도 종료되면 나머지 동작들은 background로 실행하고 다음 동작들을 실행합니다.

Environment Code

 

 

Monitor 코드입니다. Monitor은 Driver의 데칼코마니이지만, 반대의 역할을 합니다.

Monitor의 경우 HW 신호를 받아, ScoreBoard 내부에 존재하는 SW성격의 testbench인 Reference Model에 사용될 수 있도록 SW 신호로 변경해 줍니다. 그리하여, Interface를 통해 직접 받은 다발들의 값을 SW 성격인 fnd_tr의 값으로 변경해 줍니다. 그리고 이 값을 Mailbox에 넣어둡니다.

Monitor Code

 

ScoreBoard입니다. Mailbox를 통해 SW로 변환된 transaction값을 내장된 Reference Model에서 테스트합니다. 입력값인 random한 transaction과 출력값을 비교합니다. 이번에는, 입력된 random한 값을 FND로 출력하기 때문에 FNDComm과 FNDFont가 결과값으로 하고 입력되는 FDR 값을 비교합니다.

또한, FND의 각 자리별 숫자 표현을 위해 FDR 값을 Digit Splitter를 통해 4bit의 값을 쪼개 놓았는데, 이를 활용하여, BCD to Seg 모듈의 logic의 값들을 refFndFont로 두어 7bit로 쪼개어 합친 후, 실제 출력된 FND Font와 값 비교를 진행하였습니다.

 

 

또한, 저희가 random한 값으로 넣었던 모듈 동작에 대한 enable 신호인 FCR_en도 검증하였습니다. FCR_en이 0이라면 7segment가 출력되지 않기에, FNDComm은 4'b1111일 것 입니다. 만약 FCR_en이 1이라면 값이 FND로 출력되었을 것이기 때문에 0001을 선택한 자리 수를 의미하는 fnd_tr.digit_sel만큼 shift하여, 만약 두번째 자리수라면 2번 shift를 통한 선택을 통해, 실제 출력된 FND Comm의 반전한 값과 동일한지 확인합니다. 7-segment의 Annode Type을 사용하므로 이와 같이 설계하였습니다. 

 

또한, Write 모드에 대한 검증을 했다면, Read 모드에 대한 검증도 필요합니다. Read의 경우, 실제 출력된 PRDATA 값과 APB Slave의 Register 0x04 즉, FDR 값을 갖는 register의 값을 비교합니다. 이를 통해, 입력된 값과 출력된 값을 비교합니다. 또한, 모든 Test가 종료되면 체크하고자 하는 값들에 counter를 증가시켜 횟수를 세도록 합니다. 

Scoreboard Code

 

 

그리고, count한 값들을 최종적으로 report하여 출력합니다.

ScoreBoard 내부의 report() 함수

 

 

결과입니다.

저희가 비교해보고자 했던 값들이 Random하게 만들어져 여러 class들을 지나는 모습입니다. 이를 통해 입력값과 출력값에 대한 비교를 통해 검증을 진행합니다. 모든 검증이 종료되면 총 횟수, 성공한 횟수, 원하는 값을 얻은 횟수등을 출력하며 Test를 종료합니다. 이를 통해, 모듈에 대한 확실한 검증을 진행할 수 있었고, 직접 설계해보고 교수님의 코드를 배우며 System Verilog를 활용한 검증에 한발짝 더 가까워 진 것 같습니다.

결과 TCI Console

 

 

코드:

https://github.com/Heeju99/Code_Verilog_SystemVerilog/blob/main/workspace/250424_testbench_practice/250424_testbench_practice.srcs/sim_1/new/tb_fnd_practice.sv

 

Code_Verilog_SystemVerilog/workspace/250424_testbench_practice/250424_testbench_practice.srcs/sim_1/new/tb_fnd_practice.sv at ma

Contribute to Heeju99/Code_Verilog_SystemVerilog development by creating an account on GitHub.

github.com