UVM objection: 마지막 요청을 보낸 순간에 테스트가 끝난다면
마지막 요청을 보낸 뒤 테스트가 종료되어 PASS라고 나온다. 응답은 아직 도착하지 않았다. 반대로 모든 응답을 비교했는데도 시뮬레이션이 끝나지 않는 경우도 있다. 두 문제는 DUT의 계산보다 테스트의 수명을 관리하는 방식에서 시작할 수 있다.
UVM objection은 ‘이 phase를 아직 끝내면 안 된다’는 상태를 전달한다. 무엇이 끝나야 objection을 내릴 수 있는지 정하는 것이 핵심이다.
sequence의 종료와 검사의 종료는 다를 수 있다
UVM User’s Guide는 완료되어야 할 활동을 시작할 때 phase objection을 올리고, 활동을 끝낼 때 내리는 방식을 설명한다. 모든 objection이 내려가면 phase 종료 절차가 진행된다. 살아 있는 task가 있다는 사실만으로 phase가 계속 유지되는 것은 아니다. Accellera UVM User’s Guide 1.1, §3.11 Managing End of Test
가상의 테스트에서 10번째 사이클에 마지막 요청이 수락되고 11번째에 sequence가 반환한다고 하자. driver는 입력 전달 완료를 기준으로 item을 끝냈다. DUT의 응답은 18번째에 도착하고 monitor가 보낸 항목의 최종 비교는 19번째에 끝난다.
| 사건 | 사이클 | 끝난 활동 |
|---|---|---|
| 마지막 요청 수락 | 10 | 입력 전달 |
| sequence 반환 | 11 | 자극 생성 |
| 마지막 응답 관측 | 18 | 응답 전달 |
| 마지막 결과 비교 | 19 | 해당 작업 검증 |
11번째에 유일한 objection을 내리면 뒤의 응답 검사까지 기다린다는 보장이 없다. sequence가 blocking으로 실행되었다는 사실도 sequence 자체가 어떤 완료 기준을 사용하는지에 달려 있다. ‘start가 반환했다’를 무조건 ‘DUT와 비교기가 모두 끝났다’로 바꾸면 안 된다.
종료 조건을 일의 상태로 표현한다
다음은 종료 책임을 테스트 한곳에 두는 간단한 구조다. wait_for_all_checked()는 UVM의 기본 API가 아니라 이 예제의 환경이 제공하는 task다. 실제 수락된 요청의 응답을 모두 비교하고, 분석 큐와 진행 중 비교 작업도 비었을 때만 반환하도록 정의한다.
task run_phase(uvm_phase phase);
phase.raise_objection(this, "stimulus and checks pending");
seq.start(env.agent.sequencer);
env.wait_for_all_checked();
phase.drop_objection(this, "all requested work checked");
endtask
예제는 seq.start가 반환한 뒤 새 요청을 만드는 다른 background sequence가 없다고 가정한다. 수락 기록이 늦게 도착하는 경로가 있다면 그 기록까지 반영했는지도 기다림의 조건에 포함해야 한다. pending 개수 하나가 순간적으로 0이라는 이유만으로 아직 전달 중인 정보까지 사라졌다고 판단할 수는 없다.
다른 구성요소가 별도 objection을 올렸다면 위의 drop만으로 phase가 끝나지는 않는다. 그래서 누가 어떤 활동을 위해 올렸는지 기록하고 같은 책임자가 대응하는 drop을 수행하도록 한다. 부모와 자식에서 같은 일의 수명을 겹쳐 관리할 때도 불필요한 중복이나 누락을 점검해야 한다.
고정 지연은 남은 작업을 대신 세지 않는다
‘마지막 입력 뒤에 100ns를 기다리면 된다’는 방식은 간단하다. 하지만 응답 지연이 혼잡도나 설정에 따라 바뀌면 부족할 수 있고, 대부분의 경우에는 불필요한 대기가 된다. 기다린 시간이 길다는 사실 자체는 모든 정답을 비교했다는 증거가 아니다.
UVM 가이드는 마지막 transaction을 scoreboard에 전달하는 데 시간이 더 필요할 수 있어 phase_ready_to_end()에서 objection을 다시 올리거나 drain time을 사용하는 방법도 설명한다. drain time은 환경에 맞는 종료 여유를 제공하지만, 미완료 요청이 남았는지를 확인하는 논리를 자동으로 만든 것은 아니다. Accellera UVM User’s Guide 1.1, §3.11의 종료 조정
시간 기반의 조용한 구간을 쓰는 환경도 가능하다. 다만 ‘그동안 버스에 움직임이 없었다’와 ‘응답이 반드시 모두 돌아왔다’는 같지 않다. 영원히 응답하지 않는 DUT도 조용할 수 있다. 마지막에는 기대 항목과 관측 큐가 비었는지를 별도로 확인해야 한다.
영원히 관찰하는 task가 영원히 붙잡지는 않는다
monitor나 reactive slave는 보통 계속 인터페이스를 기다린다. 이런 활동은 자체적으로 끝내야 할 고정된 작업 목록이 없을 수 있다. 시작하면서 objection을 올리고 forever loop가 끝나면 내리도록 작성하면 drop에 도달하지 못해 테스트를 붙잡는다.
반대로 phase 종료를 막지 않는 background task가 있다고 해서 그 task가 잘못된 것은 아니다. 필요한 요청과 검사를 완료할 책임이 있는 주체가 종료 조건을 관리하고, background 관찰은 그 기간 동안 동작하게 한다.
응답이 오지 않거나 objection이 누락되어도 무한히 기다리지 않도록 timeout을 둔다. timeout은 성공 조건이 아니라 실패를 유한한 시간 안에 보고하는 장치다. 종료 직전에 강제로 objection을 모두 내려 PASS로 만드는 것은 미완료 작업을 해결하지 않는다. 남은 요청 ID와 마지막 진행 시점을 보고하면 실제 DUT 정지와 수명 관리 오류를 구별하는 데 도움이 된다.
UVM objection을 제대로 내리는 순간은 ‘더 보낼 것이 없다’만으로 정해지지 않는다. 검증해야 할 응답과 비교 작업까지 완료되었는지 확인해야 한다. 활동의 시작과 끝에 책임을 붙이고 미완료 상태를 명시하면, 너무 이른 PASS와 끝나지 않는 테스트를 같은 원칙으로 다룰 수 있다.