1. 요구사항이 먼저이고, 설계는 그것을 구현하고 테스트벤치는 그것을 검사합니다
하드웨어 설계와 검증에는 요구사항, 설계 코드, 테스트벤치가 필요합니다. 요구사항은 회로가 해야 할 동작을 정하고, 설계 코드는 그 동작을 구현합니다. 테스트벤치는 입력을 구동하고 출력을 기대값과 비교합니다. 검사 대상 회로를 DUT(design under test)라고 부릅니다.
| 역할 | 하는 일 | 답해야 하는 질문 |
|---|---|---|
| 요구사항 | 입력, 출력, 사이클 단위 동작을 말로 정합니다 | 무엇을 만들어야 하는가 |
| DUT | 요구사항을 회로로 서술합니다 | 어떻게 만드는가 |
| 테스트벤치 | 클록과 리셋을 만들고, 입력을 구동하고, 출력을 관찰해 기대값과 비교하고, 끝나면 시뮬레이션을 멈춥니다 | 요구사항대로 동작하는가 |
테스트벤치의 기대값은 DUT 코드가 아니라 요구사항에서 계산합니다. 둘을 같은 오해로 쓰면 테스트는 통과하고 설계는 틀립니다.
참고. 테스트벤치의 작성법은 언어마다 다르며 각 언어 과정에서 실제 코드를 다룹니다. Verilog는
initial 블록과 시스템 태스크로 된 모듈, BSV는 입력을 구동하고 결과를 출력하는 테스트벤치
rule, Chisel은 poke로 입력을 구동하고 step으로 클록을 진행하며 peek로 출력을 읽거나
expect로 기대값을 검사하는
Scala 테스트입니다. 이 단원은 문법 없이 역할만 다룹니다.
2. 컴파일·elaboration·시뮬레이션·합성을 구분합니다
네 작업은 목적과 검출하는 문제가 다릅니다. 도구에 따라 컴파일과 elaboration을
함께 수행하기도 합니다. 합성은 시뮬레이션 다음에 반드시 거치는 단계가 아니라,
실제 하드웨어 구현으로 이어지는 별도 작업입니다.
| 단계 | 하는 일 | 여기서 드러나는 문제 |
|---|---|---|
| 컴파일 | 문법과 타입을 검사하고 내부 표현으로 바꿉니다 | 문법 오류, 타입 오류, 선언되지 않은 이름 |
| 생성(elaborate) | 모듈 인스턴스를 전개하고 파라미터와 폭을 확정합니다 | 연결되지 않은 포트, 맞지 않는 폭 |
| 시뮬레이션 | 테스트벤치가 정한 순서로 시간을 진행하며 값을 계산합니다 | 요구사항과 다른 출력, 끝나지 않는 실행 |
| 합성 | 회로를 게이트나 FPGA 자원으로 옮깁니다 | 합성할 수 없는 구문, 타이밍 |
이 사이트는 시뮬레이션까지만 실행합니다. Verilog는 Icarus Verilog 11, BSV는 bsc 2026.01, Chisel은 Chisel 6.7.0과 chiseltest 6.0.0, firtool 1.154.0으로 실행합니다. 게이트나 FPGA 자원으로 매핑하는 합성은 하지 않습니다. 실행 성공은 요청한 명령이 정상 종료했다는 뜻이지, 모든 요구사항을 검사했다는 증거는 아닙니다. 어떤 조건을 확인했는지 테스트벤치의 검사와 관찰 결과를 읽어야 합니다. 합성 가능성도 별도로 확인할 문제입니다.
실행에서 기대한 결과를 얻지 못했을 때는 다음 네 가지 문제를 구분합니다.
| 결과 | 뜻 | 먼저 볼 곳 |
|---|---|---|
| 컴파일 오류 | 컴파일이나 생성 단계에서 멈췄습니다. 시뮬레이션은 시작되지 않았습니다 | 오류 메시지의 파일과 줄 번호 |
| 실행 시간 오류 | 시뮬레이션이 시작되었지만 정상 종료하지 못했습니다 | 시뮬레이터의 마지막 출력 |
| 테스트 불일치 | 시뮬레이션은 끝났고 출력이 기대값과 다릅니다 | 처음 다른 사이클 |
| 결과 미수신 | 요청이 실패했거나 응답을 받지 못했습니다 | 표시된 서비스·연결 오류를 확인한 뒤 다시 실행합니다 |
확인 문제
4비트 신호에 Bool 값을 대입해 타입 오류가 났습니다. 이 오류를 보고하는 단계는 어느 것입니까?
3. 사례는 정상·경계·리셋 세 종류로 나눕니다
요구사항을 테스트 사례로 바꿉니다. 사례 하나는 입력 순서와 그때 기대하는 출력, 그리고 그 기대값이 요구사항의 어느 문장에서 나왔는지로 이루어집니다. 사례는 세 종류로 나누어 빠진 곳을 찾습니다.
| 종류 | 뜻 |
|---|---|
| 정상 | 요구사항의 본문이 말하는 일반적인 동작 |
| 경계 | 규칙의 모양이 바뀌는 지점. 최댓값, 되감기, 두 입력이 동시에 1인 경우 |
| 리셋 | 시작 값과 되돌리기 동작 |
counter4의 요구사항은 다음과 같습니다. "4비트 카운터입니다. 에지에서 clear가 1이면 q는 0이
됩니다. clear가 0이고 enable이 1이면 q는 1 증가하고, 15 다음은 0입니다. clear와 enable이
모두 0이면 q를 유지합니다. 시작 값은 0입니다." 이 문장들에서 다음 표가 나옵니다.
| 사례 | 종류 | 입력 | 기대 q | 이유 |
|---|---|---|---|---|
| 시작 값 | 리셋 | 첫 에지 전 | 0 | "시작 값은 0" |
| 하나 증가 | 정상 | clear 0, enable 1을 한 사이클 | 1 | "1 증가" |
| 유지 | 정상 | q = 1에서 enable 0을 두 사이클 | 1 | "모두 0이면 유지" |
| 되감기 | 경계 | enable 1을 열여섯 사이클 | 0 | "15 다음은 0" |
| 카운트 중 clear | 리셋 | q = 5에서 clear 1을 한 사이클 | 0 | "clear가 1이면 0" |
| clear와 enable 동시 | 경계 | 둘 다 1을 한 사이클 | 0 | "clear가 1이면" 문장이 "enable이 1이면" 문장보다 먼저 적용 |
| clear 뒤 재시작 | 정상 | clear 0, enable 1을 한 사이클 | 1 | 0에서 다시 "1 증가" |
아래 표는 되감기와 카운트 중 clear를 한 번에 담은 입력 순서입니다. 사이클 0부터 15까지는 enable만
1이므로 q는 1씩 올라가고, 사이클 15의 에지에서 15 다음 값이 됩니다. 사이클 17은 카운트 중에
clear와 enable이 함께 1인 에지입니다. 에지 직후 q를 모두 적으세요.
예측한 뒤 비교 · counter4
비교하기 전에 모든 칸을 채우세요. 빈칸도 불일치로 처리합니다.
| 사이클 | clear에지에서 샘플링한 입력 | enable에지에서 샘플링한 입력 | q에지 직후 |
|---|---|---|---|
| 0 | 0 | 1 | |
| 1 | 0 | 1 | |
| 2 | 0 | 1 | |
| 3 | 0 | 1 | |
| 4 | 0 | 1 | |
| 5 | 0 | 1 | |
| 6 | 0 | 1 | |
| 7 | 0 | 1 | |
| 8 | 0 | 1 | |
| 9 | 0 | 1 | |
| 10 | 0 | 1 | |
| 11 | 0 | 1 | |
| 12 | 0 | 1 | |
| 13 | 0 | 1 | |
| 14 | 0 | 1 | |
| 15 | 0 | 1 | |
| 16 | 0 | 1 | |
| 17 | 1 | 1 | |
| 18 | 0 | 0 |
4. 약한 테스트는 경계 사례를 더해 강하게 만듭니다
다음은 counter4를 검사하는 테스트벤치의 순서입니다.
clear = 1, enable = 0으로 한 사이클 → q == 0 검사 clear = 0, enable = 1로 세 사이클 → q == 3 검사 enable = 0으로 한 사이클 → q == 3 검사 종료
세 검사가 모두 통과하는 설계도 요구사항을 어길 수 있습니다. 이 테스트는 q가 3을 넘는 일이 없고,
clear와 enable이 동시에 1인 에지도 없습니다. 15에서 멈추는 카운터, enable을 clear보다
우선하는 카운터가 모두 통과합니다. 테스트를 강하게 만드는 방법은 표의 경계 사례를 순서에 넣는
것입니다. 먼저 0으로 클리어한 뒤 clear = 0, enable = 1로 열여섯 사이클을 진행해
q == 0인지 검사합니다. 두 입력이 모두 1인 에지 뒤에도 q == 0인지 검사합니다.
아래 모델에서 테스트벤치 역할을 직접 해 보세요. 먼저 약한 테스트의 다섯 에지를 그대로 누르고
q가 3인지 확인합니다. 이어서 enable만 1로 두고 에지를 열여섯 번 더 눌러 q가 0으로 돌아가는
행을, 마지막으로 clear와 enable을 함께 1로 두고 에지를 한 번 눌러 q가 0인 행을 확인합니다.
약한 테스트가 끝난 뒤의 행들이 바로 추가해야 할 사례입니다.
개념 실험 · counter4
컴파일한 설계가 아니라 브라우저 안의 회로 모델입니다. 실제 도구 체인은 예제에서 실행됩니다.
입력
출력
- q
- 0
아직 에지가 없습니다. 입력을 정한 뒤 클록 에지를 인가하세요.
확인 문제
위 테스트가 검사하지 않는 사례는 어느 것입니까?
5. 첫 불일치에서 원인을 추정합니다
시뮬레이션이 끝났는데 출력이 기대값과 다르면 다음 순서로 봅니다.
| 순서 | 할 일 |
|---|---|
| 1 | 처음 다른 사이클을 찾습니다 |
| 2 | 그 에지에서 DUT가 본 입력을 파형이나 출력으로 확인합니다 |
| 3 | 그 입력에 요구사항의 어느 문장이 적용되어야 했는지 적습니다 |
| 4 | 관찰값을 만들 수 있는 원인을 나열하고, 입력 확인으로 지울 수 있는 것을 지웁니다 |
주의. 테스트벤치가 보낸 값과 DUT 포트에 도착한 값은 다를 수 있습니다. 포트 연결이 틀리면
테스트벤치는 enable = 1을 보냈다고 믿지만 DUT는 0을 봅니다. 2단계에서 확인하는 것은 DUT 포트의
값입니다.
확인 문제
시작 값 0에서 clear = 0, enable = 1로 세 사이클을 보냈는데 q가 여전히 0입니다. 파형에서 DUT의 clear 포트는 세 에지 모두 0이었습니다. 가장 가능성이 큰 원인은 무엇입니까?
6. 변형: 상승 검출기의 요구사항에서 사례 뽑기
같은 방법을 앞 장의 사이클 단위 rise-detect 모델에 적용합니다. 입력은 각 사이클 동안
일정하게 유지한다고 가정합니다. 요구사항은 "in이 0에서 1로 바뀔 때마다
rise가 정확히 한 사이클 동안 1이고, 그 밖에는 0이다"입니다.
| 사례 | 종류 | 입력 | 기대 rise |
|---|---|---|---|
| 한 번 상승 | 정상 | in 0, 0, 1, 0 | 사이클 2에서만 1 |
| 길게 유지 | 경계 | in 1을 다섯 사이클 | 첫 사이클에서만 1 |
| 첫 사이클부터 1 | 리셋 | 사이클 0에 in 1 | 사이클 0에서 1 (prev의 시작 값이 0) |
| 두 번 상승 | 정상 | in 1, 0, 1 | 사이클 0과 2에서 1 |
"길게 유지" 사례가 없는 테스트는 rise를 in에 그대로 연결한 설계를 통과시킵니다.
확인 문제
in이 0에서 1로 바뀐 뒤 다섯 사이클 동안 1을 유지합니다. 이 다섯 사이클 가운데 rise가 1인 사이클은 몇 개입니까?
7. 정리
- 요구사항이 먼저입니다. DUT는 그것을 구현하고 테스트벤치는 요구사항에서 계산한 기대값으로 DUT를 검사합니다.
- 컴파일·elaboration·시뮬레이션·합성은 목적이 다릅니다. 이 사이트는 컴파일과 시뮬레이션 명령을 실행하며 게이트나 FPGA 자원으로 매핑하지 않습니다.
- 기대한 결과를 얻지 못하면 컴파일 오류·실행 시간 오류·테스트 불일치·서비스나 연결 문제를 구분합니다. 정상 종료만으로 설계가 옳다고 판단하지 않습니다.
- 사례는 정상, 경계, 리셋으로 나누고, 약한 테스트에는 경계 사례를 더합니다.
- 불일치는 처음 다른 사이클에서 시작해 DUT 포트의 입력을 확인하고 원인을 지워 나갑니다.
공통 기초는 여기까지입니다. 이제 BSV, Verilog, Chisel 가운데 한 과정을 골라 첫 장을 시작하세요. 각 과정에서는 DUT와 테스트벤치를 실행 가능한 코드로 익힙니다.