본문으로 건너뛰기
code0.HDL

타입·폭·명시적 변환

크기가 정해진 값이 스스로 폭을 바꾸지 않는 이유, 크기 없는 리터럴이 대상의 폭을 받는 규칙, 0 확장·부호 확장·절단·재해석에 쓰는 함수를 다룹니다.

이 장에서 배울 내용

  • 양쪽의 폭으로 대입이 타입 검사를 통과할지 예측하고 T0020, T0060, T0051을 읽습니다
  • 의도한 폭 변경에 맞게 truncate, zeroExtend, signExtend, extend를 고르고, 폭은 대상 타입에서 받습니다
  • 비트 패턴 하나를 Bit, UInt, Int로 읽고, 부호 있는 값을 넓힐 때 unpack을 signExtend보다 먼저 둡니다
  • 타입 단언과 변환, Integer와 하드웨어 값을 구분합니다
이 장에서 배우는 개념
  • 타입 폭·명시적 변환
먼저 알아야 할 개념

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비트입니다.

Narrowing.bsv
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를 씁니다

타입 결정 과정은 다음과 같습니다.

  1. 크기 지정 리터럴 5'b10101의 타입은 Bit#(5)입니다.
  2. 선언은 Bit#(4)를 요구합니다.
  3. 두 타입이 같으려면 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'b101015. 리터럴이 고정대상 폭과 정확히 같아야 합니다
12대상에서 받음그 폭으로 표현 가능해야 합니다

두 종류의 리터럴은 다르게 실패합니다. 폭이 다른 크기 지정 리터럴은 타입 불일치이고, 너무 큰 크기 없는 리터럴은 범위 오류입니다. 둘 다 컴파일 시점입니다. 진법, 밑줄, 채움 리터럴 '0과 '1을 포함한 리터럴 표기법은 어휘 요소 장에 있습니다.

확인 문제

Bit#(4) x = 16; 에 대해 bsc는 어떻게 합니까?

답

3. 연결에서는 폭이 더해지고 선언은 검사만 합니다

BitWidth.bsv는 4비트 nibble과 8비트 octet을 { nibble, octet }으로 이어 Bit#(12)에 저장합니다. 연결식에서는 처음 쓴 항목이 상위 비트를 차지합니다. 12는 선언이 고른 수가 아닙니다. 식이 이미 가진 폭 4 + 8입니다. 선언이 그 폭과 일치하므로 컴파일됩니다.

BitWidth.bsv
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 }의 폭은 몇 비트입니까?

실행해서 출력된 세 벡터를 읽으세요.

출력 줄확인할 내용
nibble1100, 4비트입니다
octet00111111, 8비트입니다
joined110000111111, 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부호 있는 산술과 비교됩니다
int32Int#(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비트로 truncatebit 7..4를 버립니다5
12비트로 zeroExtend위쪽에 0 네 개를 붙입니다0a5
12비트로 signExtend최상위 비트 1을 네 번 복사합니다fa5
Bit에 extendzeroExtend와 같습니다0a5
함수효과예
zeroExtend(x)넓힘. 새 상위 비트는 0Bit#(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);       // 다시 1101

6.2 예제: 한 비트 패턴을 두 타입으로 읽기

Signedness.bsv는 raw = 4'b1101을 UInt#(4)와 Int#(4)로 각각 unpack해 출력합니다.

Signedness.bsv
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)로 무엇이 출력됩니까?

출력 줄확인할 내용
raw1101
as UInt#(4)8 + 4 + 1 = 13
as Int#(4)최상위 비트의 자릿값이 -8이므로 -8 + 4 + 1 = -3

두 변수에는 같은 네 비트가 들어 있습니다. 값이 달라진 것은 타입이 달라서입니다. unpack만으로는 변환 회로가 추가되지 않습니다.

직접 바꿔 보세요.

raw 값UInt#(4)Int#(4)
4'b10008-8, Int#(4)의 최솟값
4'b011177, 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)리터럴처럼 타입이 정해지지 않은 식의 타입을 단언할 뿐 변환하지 않습니다
Integerelaboration 중에만 존재하며 하드웨어가 되지 않습니다

12. 확인 문제

  1. 5비트 값을 Bit#(4)에 대입하면 시뮬레이션 중 overflow가 아니라 컴파일 오류가 발생하는 이유는 무엇일까요?

    정답 보기

    폭은 타입의 일부이고, 타입 검사는 elaboration보다 먼저 수행됩니다. Bit#(5)와 Bit#(4)는 다른 타입이므로 회로를 만들기 전에 T0060 오류로 멈춥니다.

  2. 1101을 UInt#(4)와 Int#(4)로 unpack하면 무엇이 바뀌고 무엇이 그대로일까요?

    정답 보기

    네 비트 1101은 그대로입니다. 해석만 바뀌어 UInt#(4)로는 13, Int#(4)로는 -3이 됩니다.

  3. -91을 담은 Int#(8) 값 x를 Int#(12)로 extend하면 결과는 무엇일까요?

    정답 보기

    -91입니다. 부호 있는 타입에서 extend는 부호 확장을 하므로 값이 보존됩니다. Bit나 UInt였다면 0을 채웁니다.

확인 지점

실습 문제를 제출해 채점을 받습니다

채점은 서버의 비공개 테스트로 진행되며, 결과는 이 브라우저에만 기록됩니다.

참고 자료

참고한 자료의 라이선스와 고지