1. 폭은 타입의 일부입니다
Bit#(4)와 Bit#(8)은 크기가 다른 한 타입이 아니라 서로 다른 두 타입입니다. BSV는 크기가
정해진 값의 폭을 어느 방향으로도 스스로 바꾸지 않습니다. 4비트 값을 8비트 이름에 대입하면
컴파일 오류이고, 8비트 값을 4비트 이름에 대입해도 컴파일 오류입니다. 조용히 0을 채우는 일도,
조용히 상위 비트를 버리는 일도 없습니다. 컴파일러는 T0020(기대 타입과 추론 타입이 다름)이나
T0060(bit-size mismatch)으로 멈추고, 회로는 만들어지지 않습니다.
Verilog의 규칙과 정반대입니다. Verilog는 식을 문맥에 맞게 확장하거나 절단합니다. 두 규칙을 섞지 마세요. BSV에서는 폭 변경을 명시해야 합니다.
1.1 타입 검사의 시점
BSV 컴파일은 여러 단계로 진행됩니다. 타입 검사는 하드웨어 구조를 만드는 elaboration보다
먼저 수행됩니다.
| 단계 | 하는 일 |
|---|---|
| 구문 분석 | 토큰을 선언, 식, 문장으로 묶는 단계 |
| 타입 검사 | 모든 식의 타입과 폭이 맞는지 확인하는 단계 |
elaboration | 모듈과 인스턴스를 하드웨어 구조로 변환하는 단계 |
| 시뮬레이션 | 만들어진 하드웨어를 사이클 단위로 실행하는 단계 |
타입 오류가 있으면 회로가 생성되지 않습니다. 따라서 타입 오류는 "잘못 동작하는 회로"가 아니라 "회로를 만들기 전에 멈췄다"는 뜻입니다.
1.2 타입 선언에서 구분할 네 가지
| 항목 | 확인할 내용 | 예 |
|---|---|---|
| 표현 | 비트가 몇 개인가 | Bit#(4)는 4비트입니다 |
| 해석 | 비트가 어떤 값을 뜻하는가 | UInt#(4)와 Int#(4)는 같은 비트를 다른 수로 읽습니다 |
| 연산 조건 | 어떤 연산을 쓸 수 있는가 | Eq#(t)가 있으면 t에 ==를 쓸 수 있습니다 |
| 처리 단계 | 타입인가 값인가 | Bit#(8)의 8은 값이 아니라 numeric type입니다 |
네 항목 모두 컴파일 시점에 정해지며 사이클마다 바뀌지 않습니다. 그래서 이 장의 추적표는
레지스터 상태 변화가 아니라 타입과 값이 결정되는 과정을 따라갑니다. 연산 조건과, 타입 변수에
그 조건을 선언하는 proviso는 타입클래스와
proviso 장에서 다룹니다.
1.3 매개변수가 있는 타입
매개변수가 있는 타입은 타입 생성자 뒤에 #(...)를 붙여 씁니다.
형식
타입_생성자#(매개변수1, 매개변수2, ...)Bit#(8) // 8비트 값
Vector#(4, Bit#(8)) // 8비트 원소 네 개
Bit#(n) // 폭을 numeric type 변수 n으로 지정| 부분 | 규칙 |
|---|---|
| 타입 생성자 | Bit, Vector처럼 대문자로 시작합니다. Verilog 호환 타입 int, bit만 예외입니다 |
| 고정된 수 | Bit#(8)의 8은 고정된 numeric type입니다 |
| 타입 변수 | Bit#(n)의 n처럼 소문자로 시작하며, 사용하는 문맥에서 결정됩니다 |
Verilog 호환 표기 bit[m:0]도 m + 1비트 벡터를 뜻합니다. 현재는 두 번째 인덱스에 0만 쓸
수 있습니다.
1.4 폭 변환은 명시해야 합니다
좁히는 대입도, 넓히는 대입도 컴파일 오류입니다. 크기 미지정 정수 리터럴만 대상의 폭을
받으므로 Bit#(8) x = 5;는 올바른 코드입니다.
Bit#(4) nibble = 4'b1100;
Bit#(8) wide = nibble; // 오류 T0020: Bit#(8)이 필요한데 Bit#(4)
Bit#(4) narrow = 5'b10101; // 오류 T0060: 비트 폭 불일치폭을 바꾸려면 의도를 나타내는 함수를 씁니다. 그 함수들은 5절에 있습니다.
1.5 예제: 암묵적 폭 축소
다음 예제는 일부러 컴파일 오류를 발생시킵니다. narrow는 4비트로 선언되었지만 대입하는
리터럴 5'b10101은 5비트입니다.
package Narrowing;
(* synthesize *)
module mkTop(Empty);
rule show;
// 5비트를 4비트 변수에 대입하므로 회로가 생성되기 전에 컴파일 오류가 발생한다.
Bit#(4) narrow = 5'b10101;
$display("%b", narrow);
$finish(0);
endrule
endmodule
endpackage이 개념 실습하기
다음 단계로 짧은 BSV 문제에 이 개념을 적용해 보세요.
실행 전에 예측하세요. bsc가 상위 비트 하나를 버리고 시뮬레이션을 시작할까요, 아니면 컴파일
단계에서 멈출까요?
확인 문제
Narrowing.bsv를 실행하면 어떻게 됩니까?
실행을 누르고 메시지를 읽으세요.
| 확인 항목 | 내용 |
|---|---|
| 잘못된 코드 | 5비트 리터럴을 Bit#(4) 변수에 대입했습니다 |
| 실패 단계 | bsc의 타입 검사 단계입니다. elaboration과 시뮬레이션은 시작하지 않습니다 |
| 오류 메시지 | T0060과 bit-size mismatch |
| 고치는 방법 | 모든 비트가 필요하면 목적지를 Bit#(5)로, 소스가 4비트여야 하면 리터럴을 4'b0101로, 상위 비트를 버리는 것이 의도라면 truncate를 씁니다 |
타입 결정 과정은 다음과 같습니다.
- 크기 지정 리터럴
5'b10101의 타입은Bit#(5)입니다. - 선언은
Bit#(4)를 요구합니다. - 두 타입이 같으려면 5와 4가 같아야 하므로 타입 검사가 실패합니다.
리터럴의 값이 4비트에 들어가는지는 관계없습니다. 5'b00101도 타입은 Bit#(5)이므로 같은
오류가 발생합니다. 타입 오류는 잘못 동작하는 회로를 설명하지 않습니다. 회로가 만들어지지
않았다는 뜻입니다.
직접 바꿔 보세요. 목적지를 Bit#(3)로 바꾼다면 리터럴의 숫자만 작게 바꿔서는 해결되지
않습니다. 3'b101처럼 리터럴 폭을 3비트로 쓰거나 truncate로 변환을 명시해야 합니다.
2. 크기 없는 리터럴은 대상의 폭을 받습니다
12처럼 크기를 적지 않은 리터럴에는 자체 폭이 없습니다. 쓰이는 자리의 타입이 폭을 정합니다.
Bit#(4) a = 12;에서 리터럴은 4비트가 됩니다. 단, 값은 그 폭에 들어가야 합니다.
Bit#(4) a = 16;은 T0051 오류 Literal 16 is not a valid Bit#(4)로 거절됩니다. 4비트는
0부터 15까지만 표현합니다.
| 리터럴 | 폭 | 규칙 |
|---|---|---|
5'b10101 | 5. 리터럴이 고정 | 대상 폭과 정확히 같아야 합니다 |
12 | 대상에서 받음 | 그 폭으로 표현 가능해야 합니다 |
두 종류의 리터럴은 다르게 실패합니다. 폭이 다른 크기 지정 리터럴은 타입 불일치이고, 너무 큰
크기 없는 리터럴은 범위 오류입니다. 둘 다 컴파일 시점입니다. 진법, 밑줄, 채움 리터럴 '0과
'1을 포함한 리터럴 표기법은 어휘 요소 장에 있습니다.
확인 문제
Bit#(4) x = 16; 에 대해 bsc는 어떻게 합니까?
3. 연결에서는 폭이 더해지고 선언은 검사만 합니다
BitWidth.bsv는 4비트 nibble과 8비트 octet을 { nibble, octet }으로 이어 Bit#(12)에
저장합니다. 연결식에서는 처음 쓴 항목이 상위 비트를 차지합니다. 12는 선언이 고른 수가
아닙니다. 식이 이미 가진 폭 4 + 8입니다. 선언이 그 폭과 일치하므로 컴파일됩니다.
package BitWidth;
(* synthesize *)
module mkTop(Empty);
rule show;
// Bit#(n)의 수는 폭이며 타입의 일부다.
Bit#(4) nibble = 4'b1100;
Bit#(8) octet = 8'h3f;
// 결합은 폭을 더한다. 이 타입은 선언이 아니라 4 + 8이 정한다.
Bit#(12) joined = { nibble, octet };
$display("nibble = %b", nibble);
$display("octet = %b", octet);
$display("joined = %b", joined);
$finish(0);
endrule
endmodule
endpackage이 개념 실습하기
다음 단계로 짧은 BSV 문제에 이 개념을 적용해 보세요.
실행 전에 예측하세요. 연결 결과는 몇 비트이고, joined의 상위 4비트는 무엇일까요?
확인 문제
nibble을 Bit#(5)로 선언하면 { nibble, octet }의 폭은 몇 비트입니까?
실행해서 출력된 세 벡터를 읽으세요.
| 출력 줄 | 확인할 내용 |
|---|---|
nibble | 1100, 4비트입니다 |
octet | 00111111, 8비트입니다 |
joined | 110000111111, 12비트입니다. 상위 4비트가 nibble, 하위 8비트가 octet입니다 |
결과 폭 12는 4 + 8로 계산됩니다. Bit#(12) 선언은 계산된 폭을 검사할 뿐, 폭을 12로 만들지
않습니다.
직접 바꿔 보세요.
| 바꿀 곳 | 예상 결과 |
|---|---|
{ nibble, octet }을 { octet, nibble }로 | 폭은 그대로 12비트이므로 컴파일되고, joined가 001111111100이 됩니다 |
nibble 선언을 Bit#(5) nibble = 5'b11000;으로 | 결과 폭 12에 맞추려면 octet이 7비트여야 하므로 T0020 오류가 발생합니다. 메시지는 octet에 Bit#(7)이 필요하다고 표시합니다 |
타입은 전체 폭을 검사하고, 연결 순서는 필드 배치를 정합니다.
4. 수를 담는 네 가지 타입
BSV는 값의 비트 수와 그 비트를 해석하는 방법을 따로 정합니다. 폭은 항상 타입에 포함되므로, 폭을 잘못 쓰면 회로가 조용히 바뀌지 않고 타입 오류가 발생합니다.
형식
Bit#(폭) 이름 = 값; // 비트 패턴. 산술과 비교는 부호 없는 수로 처리합니다
UInt#(폭) 이름 = 값; // 부호 없는 수
Int#(폭) 이름 = 값; // 2의 보수로 표현한 부호 있는 수
Integer 이름 = 값; // 폭 제한 없음, elaboration 중에만 존재Bit#(8) raw = 8'hA5;
UInt#(8) count = 200;
Int#(8) offset = -3;
Integer depth = 16;| 타입 | 폭 | 의미 | 하드웨어가 되는가 |
|---|---|---|---|
Bit#(n) | 정확히 n | 비트 배치 자체가 중요한 값 | 됩니다 |
UInt#(n) | 정확히 n | 부호 없는 산술과 비교 | 됩니다 |
Int#(n) | 정확히 n | 부호 있는 산술과 비교 | 됩니다 |
int | 32 | Int#(32)의 타입 동의어 | 됩니다 |
Integer | 없음 | 설계를 elaboration하는 동안 쓰는 정수 | 되지 않습니다 |
프레임의 필드처럼 비트의 위치가 중요하면 Bit#(n)을 쓰고, 수의 의미가 중요하면 UInt#(n)이나
Int#(n)을 쓰세요. 타입에 따라 >>, <, /, %의 결과가 어떻게 달라지는지는
Bool·Bit와 순수 함수
장의 실행 예제로 확인할 수 있습니다.
참고. Integer는 반복 횟수, FIFO 깊이 같은 매개변수에 씁니다. 하드웨어를 생성할 때는
이미 상수로 바뀌어 있으므로 Integer 값을 레지스터에 저장할 수는 없습니다.
5. 폭 변경은 함수 호출입니다
폭을 정말 바꿔야 할 때는 방법을 말하는 함수를 호출합니다. 결과의 폭은 대입받는 쪽의 타입이 정합니다.
형식
좁은_값 = truncate(넓은_값); // 상위 비트를 버린다
넓은_값 = zeroExtend(좁은_값); // 새 상위 비트를 0으로 채운다
넓은_값 = signExtend(좁은_값); // 원래 최상위 비트를 복사해 채운다
넓은_값 = extend(좁은_값); // Bit와 UInt는 0 확장, Int는 부호 확장Bit#(8) a = 8'hA5; // 1010_0101
Bit#(4) t = truncate(a); // 4'h5
Bit#(12) z = zeroExtend(a); // 12'h0a5
Bit#(12) s = signExtend(a); // 12'hfa5
Bit#(12) e = extend(a); // a가 Bit이므로 12'h0a5| 호출 | 8'hA5에 일어나는 일 | 결과 |
|---|---|---|
4비트로 truncate | bit 7..4를 버립니다 | 5 |
12비트로 zeroExtend | 위쪽에 0 네 개를 붙입니다 | 0a5 |
12비트로 signExtend | 최상위 비트 1을 네 번 복사합니다 | fa5 |
Bit에 extend | zeroExtend와 같습니다 | 0a5 |
| 함수 | 효과 | 예 |
|---|---|---|
zeroExtend(x) | 넓힘. 새 상위 비트는 0 | Bit#(8) w = zeroExtend(4'hC);는 8'h0C |
signExtend(x) | 넓힘. 새 상위 비트는 최상위 비트의 복사 | Int#(8) w = signExtend(Int#(4)'(-3));는 -3 |
truncate(x) | 줄임. 하위 비트를 남김 | Bit#(4) t = truncate(8'hA5);는 4'h5 |
extend(x) | 타입이 정하는 방식으로 넓힘 | -91을 담은 Int#(8)을 Int#(12)로 extend하면 값은 그대로 -91 |
어느 함수도 비트 수를 인자로 받지 않습니다. 대상 타입, 보통 왼쪽의 선언이 몇 비트를 만들지
알려 줍니다. 같은 truncate 호출도 대상이 Bit#(3)이면 3비트를 만듭니다.
주의. 8비트 a로 Bit#(4) b = a;를 쓰면 컴파일 오류 T0020이 발생합니다. 오류 메시지는
기대한 타입이 Bit#(4)이고 추론한 타입이 Bit#(8)이라고 알려 줍니다. a를 바꾸지 말고
truncate로 남길 비트를 지정하세요.
6. 같은 비트를 두 가지로 읽습니다
Bit#(n), UInt#(n), Int#(n)은 모두 n비트를 차지하지만 서로 다른 타입입니다. Bit는
비트 패턴을 나타내고, UInt는 이를 부호 없는 수로, Int는 2의 보수로 해석합니다.
| 타입 | 해석 | 4비트일 때 범위 |
|---|---|---|
Bit#(n) | 해석 없는 비트 벡터 | 0000부터 1111까지 |
UInt#(n) | 부호 없는 정수 | 0부터 15까지 |
Int#(n) | 2의 보수 부호 있는 정수 | -8부터 7까지 |
6.1 pack과 unpack
pack은 값을 같은 폭의 Bit#(n)으로, unpack은 Bit#(n)을 목적지 타입의 값으로 바꿉니다.
두 함수는 비트를 옮기지 않고 해석만 바꿉니다.
형식
Bit#(n) bits = pack(값);
목적지_타입 v = unpack(bits);Bit#(4) raw = 4'b1101;
UInt#(4) u = unpack(raw); // 13
Int#(4) s = unpack(raw); // -3
Bit#(4) b = pack(s); // 다시 11016.2 예제: 한 비트 패턴을 두 타입으로 읽기
Signedness.bsv는 raw = 4'b1101을 UInt#(4)와 Int#(4)로 각각 unpack해 출력합니다.
package Signedness;
(* synthesize *)
module mkTop(Empty);
rule show;
Bit#(4) raw = 4'b1101;
// 같은 네 비트를 두 타입으로 읽는다. unpack은 해석만 바꾼다.
UInt#(4) asUnsigned = unpack(raw);
Int#(4) asSigned = unpack(raw);
$display("raw = %b", raw);
$display("as UInt#(4) = %0d", asUnsigned);
$display("as Int#(4) = %0d", asSigned);
$finish(0);
endrule
endmodule
endpackage이 개념 실습하기
다음 단계로 짧은 BSV 문제에 이 개념을 적용해 보세요.
실행 전에 예측하세요. 1101을 부호 없는 수와 2의 보수로 계산해 보세요.
확인 문제
1101은 Int#(4)로 무엇이 출력됩니까?
| 출력 줄 | 확인할 내용 |
|---|---|
raw | 1101 |
as UInt#(4) | 8 + 4 + 1 = 13 |
as Int#(4) | 최상위 비트의 자릿값이 -8이므로 -8 + 4 + 1 = -3 |
두 변수에는 같은 네 비트가 들어 있습니다. 값이 달라진 것은 타입이 달라서입니다. unpack만으로는
변환 회로가 추가되지 않습니다.
직접 바꿔 보세요.
raw 값 | UInt#(4) | Int#(4) |
|---|---|---|
4'b1000 | 8 | -8, Int#(4)의 최솟값 |
4'b0111 | 7 | 7, Int#(4)의 최댓값 |
6.3 부호 있는 값 넓히기
부호 있는 4비트 값을 8비트에서도 같은 값으로 유지하려면 순서가 결과를 정합니다. 먼저
Int#(4)로 해석하고, 그다음 signExtend로 넓혀야 합니다.
Bit#(4) raw = 4'b1101;
Int#(8) good = signExtend(unpack(raw)); // -3: 부호 비트를 복사합니다
Int#(8) bad = unpack(zeroExtend(raw)); // 13: 새 최상위 비트가 0입니다주의. bad처럼 원시 비트를 먼저 0으로 확장하면 새 최상위 비트가 0이 되어 양수로
해석됩니다. 두 줄 모두 컴파일됩니다. 이 실수는 최상위 비트가 1인 입력에서만 드러나고, 0111
같은 양수 입력에서는 정상처럼 보입니다. 1000과 0111을 함께 시험하면 이런 오류를 확실히
찾을 수 있습니다.
7. 변환 함수 한 표와, 변환이 아닌 타입 단언
7.1 타입 사이의 변환
비트의 해석이나 개수를 바꾸려면 변환 함수를 명시해야 합니다.
| 함수 | 동작 | 예 | 결과 |
|---|---|---|---|
pack(x) | 값을 Bit#(n) 표현으로 바꿉니다 | pack(True) | 1'b1 |
unpack(b) | 비트를 기대되는 타입의 값으로 바꿉니다 | UInt#(8) u = unpack(8'hff); | 255 |
zeroExtend(x) | 상위에 0을 채워 넓힙니다 | Bit#(8) w = zeroExtend(4'b1101); | 8'h0d |
signExtend(x) | 부호 비트를 복사해 넓힙니다 | Int#(8) w = signExtend(Int#(4)'(-3)); | -3 |
truncate(x) | 하위 비트만 남깁니다 | Bit#(4) t = truncate(8'hab); | 4'hb |
결과 폭은 기대되는 타입, 대개 왼쪽 선언이 정합니다.
7.2 정적 타입 단언은 변환이 아닙니다
C의 형변환처럼 보이는 다음 문법은 정적 타입 단언입니다.
형식
타입'(식)UInt#(8) ok = UInt#(8)'(255); // 리터럴의 타입을 알려 줍니다
UInt#(8) no = UInt#(8)'(bits); // bits가 Bit#(8)이면 오류입니다타입 단언은 식이 가져야 할 타입을 타입 검사에 알려 줄 뿐입니다. 리터럴처럼 타입이 정해지지
않은 식에는 쓸모가 있고, 변환 표의 Int#(4)'(-3)이 그 용례입니다. 그러나 Bit#(8)을
UInt#(8)로 바꾸지는 못합니다. 두 번째 줄은 기대 타입 UInt#(8), 추론된 타입 Bit#(8)이라는
T0020 오류가 됩니다. 이런 변환에는 unpack을 사용하세요.
8. 자주 쓰는 타입의 분류
표준 프렐류드와 Foundation 라이브러리가 제공하는 타입은 쓰임에 따라 다음과 같이 나눌 수 있습니다.
| 분류 | 대표 타입 | 쓰임 |
|---|---|---|
| packed 값 | Bit#(n), UInt#(n), Int#(n), Bool, Maybe#(t), Tuple2#(a, b) | Bits 인스턴스가 있어 비트 표현이 정해진 값 |
elaboration·시뮬레이션 값 | Integer, Real, String, Char, Fmt | 컴파일 중 계산과 출력. 일부는 합성할 수 없습니다 |
| 하드웨어 인터페이스 | Reg#(t), FIFO#(t), Clock, Reset, Inout#(t) | 상태 소자와 하드웨어 연결 |
| 프로그램 구조 | Action, ActionValue#(t), Rules, Module#(ifc) | 상태 변경, rule 집합, 모듈 생성 |
Action과 ActionValue#(t)는 특별한 method 문법이 아니라 보통의 타입입니다. 인터페이스와
scheduling에서의 역할은 method:
value·Action·ActionValue 장에서 다룹니다.
9. 적용: 모든 변환을 명시하세요
이 장의 규칙마다 하나씩, 채점 문제 세 개가 이어집니다.
| 문제 | 잘못된 점 | 고칠 곳 하나 |
|---|---|---|
| 바이트를 명시적으로 줄이기 | lowNibble은 Bit#(8)의 하위 4비트를 반환해야 하는데 입력을 그대로 반환합니다. 1절에서 본 이유로 컴파일되지 않습니다 | 반환 식을 "상위 비트를 버린다"는 뜻을 가진 변환 하나로 바꿉니다. 몇 비트를 남길지는 반환 타입이 알려 줍니다 |
| 니블을 0으로 확장하기 | zeroExtendNibble은 이미 8비트인 { upper, lower }를 반환하지만 두 지역 값이 모두 ?입니다 | 각 지역 값에 역할을 줍니다. upper는 4비트 0, lower는 입력입니다. 문제는 전체 폭이 아니라 필드 순서입니다 |
| 4비트 정수의 부호 확장하기 | asSignedByte는 zeroExtend로 먼저 넓히고 그 뒤에 Int#(8)로 읽으므로 1101이 -3이 아니라 13으로 출력됩니다 | 6.3절의 순서로 되돌립니다. 값이 아직 4비트일 때 unpack하고, 그다음 signExtend로 반환 폭까지 넓힙니다 |
세 번째 문제에서는 수정이 끝났다고 판단하기 전에 0111과 1000의 경계 양쪽을 모두
시험하세요. 0 확장은 모든 양수 입력에서 올바른 것처럼 보입니다.
10. 자주 하는 실수
10.1 폭이 다른 값을 그대로 대입하기
Bit#(8) octet = 8'hA5;
Bit#(4) nibble = 4'hC;
// 잘못된 코드
Bit#(4) low = octet; // 8비트를 4비트에: T0020, 기대한 타입 Bit#(4), 추론한 타입 Bit#(8)
Bit#(8) wide = nibble; // 4비트를 8비트에: T0020
// 바른 코드
Bit#(4) low = truncate(octet);
Bit#(8) wide = zeroExtend(nibble);BSV는 좁히는 쪽도 넓히는 쪽도 자동으로 맞추지 않고, 비트를 조용히 버리지도 않습니다.
truncate, zeroExtend, signExtend, extend 가운데 하나를 써서 폭이 바뀌는 지점을 코드에
드러내세요.
10.2 부호 있는 값을 0으로 확장하기
// 잘못된 코드: 1101(-3)이 13이 됩니다
Int#(8) v = unpack(zeroExtend(raw));
// 바른 코드: 먼저 부호 있는 값으로 해석하고 부호 확장합니다
Int#(8) v = signExtend(unpack(raw));컴파일은 두 코드 모두 통과합니다. 최상위 비트가 1인 입력으로 시험해야 차이가 드러납니다.
10.3 타입 단언을 변환으로 쓰기
// 잘못된 코드: Bit#(8)은 UInt#(8)이 아닙니다
UInt#(8) x = UInt#(8)'(bits);
// 바른 코드: 비트를 다시 해석합니다
UInt#(8) x = unpack(bits);타입 단언은 값을 바꾸지 않습니다. 타입이나 폭을 실제로 바꿔야 하면 unpack, pack,
zeroExtend, signExtend, truncate를 사용하세요.
10.4 선언이 결과 폭을 정한다고 생각하기
// 잘못된 기대: Bit#(12)로 선언하면 연결 결과가 12비트로 맞춰진다
Bit#(12) joined = { nibble5, octet }; // 5 + 8 = 13비트: T0020
// 바른 이해: 식의 폭은 피연산자 폭으로 계산되고, 선언은 그것을 검사합니다
Bit#(13) joined = { nibble5, octet };11. 정리
| 규칙 | 결과 |
|---|---|
타입 검사는 elaboration 전에 수행 | 오류가 있으면 회로가 생성되지 않습니다 |
| 폭은 타입의 일부 | Bit#(4)와 Bit#(8)은 변환 없이 섞이지 않습니다 |
| 크기 지정 리터럴 | 폭이 대상과 같아야 합니다. 다르면 T0060 또는 T0020 |
| 크기 없는 리터럴 | 대상 폭을 받습니다. 범위를 벗어나면 T0051 |
| 연결 | 폭은 피연산자의 합. 선언은 검사만 합니다 |
zeroExtend, signExtend, truncate, extend | 표준 폭 변환 함수. 결과 폭은 문맥에서 정합니다 |
pack, unpack | 비트가 아니라 해석을 바꿉니다. Bit, UInt, Int는 같은 비트를 다르게 읽습니다 |
| 부호 확장 | 먼저 Int로 해석한 뒤 signExtend합니다 |
T'(e) | 리터럴처럼 타입이 정해지지 않은 식의 타입을 단언할 뿐 변환하지 않습니다 |
Integer | elaboration 중에만 존재하며 하드웨어가 되지 않습니다 |
12. 확인 문제
-
5비트 값을
Bit#(4)에 대입하면 시뮬레이션 중 overflow가 아니라 컴파일 오류가 발생하는 이유는 무엇일까요?정답 보기
폭은 타입의 일부이고, 타입 검사는
elaboration보다 먼저 수행됩니다.Bit#(5)와Bit#(4)는 다른 타입이므로 회로를 만들기 전에T0060오류로 멈춥니다. -
1101을UInt#(4)와Int#(4)로unpack하면 무엇이 바뀌고 무엇이 그대로일까요?정답 보기
네 비트
1101은 그대로입니다. 해석만 바뀌어UInt#(4)로는 13,Int#(4)로는 -3이 됩니다. -
-91을 담은Int#(8)값x를Int#(12)로extend하면 결과는 무엇일까요?정답 보기
-91입니다. 부호 있는 타입에서extend는 부호 확장을 하므로 값이 보존됩니다.Bit나UInt였다면 0을 채웁니다.