1. rules 블록은 값입니다
지금까지 쓴 rule은 모두 모듈 본문에 직접 쓴 것이었습니다. BSV에서는 rule을 값으로
만들어 elaboration 중에 주고받다가 모듈에 추가할 수도 있습니다. rules ... endrules
블록의 타입은 Rules이고, addRules가 그 안의 rule을 현재 모듈에 추가합니다.
형식
rules
rule 이름 (조건);
Action;
endrule
endrules
addRules(Rules_식);Rules 값은 설계를 elaboration하는 동안에는 다른 값과 똑같이 다룹니다. 함수가 반환할
수 있고, 변수에 담을 수 있고, 반복문이 반복마다 하나씩 만들 수도 있습니다. 다만 값 자체는
실행되지 않습니다. addRules로 모듈에 추가하기 전까지 Rules 안의 rule은 한 번도
실행되지 않습니다.
| 단계 | Rules 값에 일어나는 일 |
|---|---|
elaboration | rules ... endrules 식이 평가되고, 이 값을 반환하는 함수가 호출되며, addRules가 결과를 elaboration 중인 모듈에 추가합니다 |
| 시뮬레이션 | 추가된 rule은 모듈 본문에 직접 쓴 rule과 똑같이 동작합니다. 매 사이클 조건이 참인 rule이 실행될 수 있습니다 |
이 구분 때문에 함수 호출 한 번이 여러 사이클에 걸쳐 동작하는 하드웨어가 됩니다. 호출은 한
번 일어나고, 반환된 rule은 그때부터 모듈의 일부입니다.
확인 문제
함수가 Rules 값을 반환하고 모듈이 그 값으로 addRules를 호출합니다. 이 함수는 몇 번 실행될까요?
2. 증가 rule 추가하기
RuleExpression.bsv의 incrementRules는 레지스터를 3까지 증가시키는 rule을 반환합니다.
incrementRules에서 인자로 받는 레지스터와 반환되는 Rules 안의 조건을 먼저 확인하세요.
그다음 rule을 추가하고 별도의 finish를 가진 mkTop을 읽으세요.
시뮬레이션은 count = 0에서 시작합니다. 추가된 rule은 시작 상태가 0, 1, 2인 사이클에
실행되어 1, 2, 3을 예약합니다. 시작 상태가 3이 되면 count < 3이 거짓이 되고 finish가
실행될 수 있습니다.
실행하기 전에 예측해 보세요.
finish는count를 얼마로 출력할까요?incrementRules는 몇 번 호출되고, 반환된rule은 몇 번 실행될까요?
package RuleExpression;
function Rules incrementRules(Reg#(UInt#(4)) count);
// 이 함수는 elaboration 중에 재사용할 수 있는 Rules 값을 만든다.
return rules
rule increment (count < 3);
count <= count + 1;
endrule
endrules;
endfunction
(* synthesize *)
module mkTop(Empty);
Reg#(UInt#(4)) count <- mkReg(0);
// addRules가 반환된 rule을 이 모듈에 추가한다.
addRules(incrementRules(count));
rule finish (count == 3);
$display("count=%0d", count);
$finish(0);
endrule
endmodule
endpackage이 개념 실습하기
다음 단계로 짧은 BSV 문제에 이 개념을 적용해 보세요.
결과 확인. finish는 count=3을 출력합니다. 이 한 줄에 시간 단위 두 개가 드러납니다.
incrementRules(count)는 모듈을 elaboration할 때 한 번 실행되었고, 반환된 rule은 세
사이클에 걸쳐 실행되었습니다.
직접 바꿔 보세요.
- 조건을
count < 2로 바꾸어 보세요.rule은 2에서 멈추고finish는 정확히 3을 기다리므로 실행할 수 있는rule이 남지 않습니다. 아무것도 출력되지 않고$finish에도 도달하지 않으므로, 실행 시간 제한에 걸려야 실행이 끝납니다. - 조건을
count <= 3으로 바꾸어 보세요. 시작 상태 3에서 두rule이 같은 사이클에 실행됩니다.finish가 3을 출력하고 시뮬레이션을 끝내는 동안increment는 4를 예약합니다. 출력은 여전히count=3이므로 이 테스트벤치로는 초과를 볼 수 없습니다. 한 사이클 더 관찰하는 테스트가 있어야 드러납니다.
함수가 반환한 rule도 모듈의 나머지 상태를 함께 사용하므로, 모듈에 직접 쓴 rule과 같은
방식으로 스케줄링됩니다. 어떤 rule이 한 사이클을 공유하는지는
상태를 공유하는 rule 장의 관계표를 보세요.
레지스터마다 rule을 하나씩 추가하는 반복문에 두 시간 축을 적용해 보세요.
Vector#(3, Reg#(UInt#(4))) counts <- replicateM(mkReg(0));
Reg#(UInt#(8)) cycle <- mkReg(0);
for (Integer i = 0; i < 3; i = i + 1)
addRules(incrementRules(counts[i]));
rule tick;
cycle <= cycle + 1;
endrule
rule finish (counts[0] == 3 && counts[1] == 3 && counts[2] == 3);
$display("cycle=%0d counts=%0d %0d %0d", cycle, counts[0], counts[1], counts[2]);
$finish(0);
endrule확인 문제
모듈에는 증가 rule이 몇 개 있고, finish는 무엇을 출력할까요?
3. 자주 하는 실수
3.1 Rules를 만들고 추가하지 않기
// 잘못된 코드: Rules 값을 만들고 버립니다
Rules r = incrementRules(count);
// 바른 코드: 모듈에 rule을 추가합니다
addRules(incrementRules(count));확인 문제
RuleExpression.bsv의 addRules 줄을 Rules r = incrementRules(count); 로 바꾸면 bsc와 시뮬레이션에서 무엇이 보일까요?
잘못된 코드도 컴파일되지만 증가 rule이 존재하지 않으므로 count는 바뀌지 않습니다.
카운터가 멈춰 있으면 조건, 호출한 method의 준비 조건, addRules 호출 여부를 차례로
확인하세요.
4. 정리
| 질문 | 답 |
|---|---|
rules ... endrules의 타입은 무엇인가요? | Rules |
| 무엇이 모듈에 추가하나요? | elaboration 중인 모듈에서 호출한 addRules(Rules_식) |
Rules를 만드는 함수는 언제 실행되나요? | elaboration 중에 한 번 |
그 안의 rule은 언제 실행되나요? | 시뮬레이션에서 guard, method의 준비 조건, 스케줄링이 허용할 때 |
addRules를 빠뜨리면 어떻게 되나요? | 값이 버려집니다. 컴파일은 되지만 그 rule은 존재하지 않습니다 |
5. 확인 문제
-
Rules식 예제에서elaboration중에 일어나는 일과 시뮬레이션 중에 일어나는 일은 각각 무엇일까요?정답 보기
elaboration중에는incrementRules(count)가 한 번 실행되고addRules가 반환된rule을 추가합니다. 시뮬레이션 중에는 그rule이 조건count < 3이 참인 사이클마다 실행됩니다. -
조건을
count <= 3으로 바꾸어도 3이 출력됩니다. 이 결과로 알 수 있는 테스트벤치의 한계는 무엇일까요?정답 보기
finish가 3을 출력하고 멈추는 사이클에 증가rule도 한 번 더 실행되어 4를 예약합니다. 테스트벤치가 너무 일찍 끝나서 초과를 관찰하지 못하므로, 출력이 맞아 보여도 경계 조건이 옳다는 증거가 되지 않습니다. -
한 모듈에서 레지스터를 달리하여
incrementRules를 두 번 호출하고 각 결과를addRules에 넘기면 모듈에는rule이 몇 개 있을까요?정답 보기
두 개입니다. 호출마다
elaboration중에 자기Rules값이 만들어지고,addRules가 각각 그 안의rule을 추가합니다. 같은 함수에서 나왔을 뿐 서로 다른rule입니다.