HDLBits Vectors 마지막편

강정윤·2024년 9월 21일
post-thumbnail

안녕하세요 오늘은 HDLBits의 Vectors 나머지 부분을 다루어 볼까 합니다.
오늘은 토요일인데요, 오전이라 정말로 피곤하군요...
취준라이프 1달차 되어가는 학부4학년 막학기...
잘 마무리가 되었으면 하는 마음입니다.
자 그럼 시작해보도록 합시다.

Vector part select

이번 문제는 32bit Vector는 4bytes 정보를 담고 있는 것으로 볼 수 있는데,
여기서 잠깐 1byte는 8bits이랍니다.
이 문제에서는 Byte ordering인 Endianness에 대해 너는 다룰 수 있냐 것을 물어봅니다.

Byte Ordering(Endianness)

나온김에 Byte Ordering에 대해 설명하고 넘어가야겠군요.
Byte Ordering을 알아야 Data가 어떻게 쓰이고 읽히는지 잘 알 수 있답니다.

Big Endian 구조 이미지 그림 1: Big Endian 구조 설명

Big Endian은 MSB(여기서는 Most Significant Byte)가 가장 작은 메모리 주소에 저장되는 방식입니다.
여기서 MSB는 0x1a군요, 그렇다면 4byte주소공간에서 주소가 가장 작은 0x1000에 쓰이게 됩니다.

Little Endian 구조 이미지 그림 2: Little Endian 구조 설명

Little Endian 은 LSB(여기서는 Least Significant Byte가 가장 작은 메모리 주소에 저장되는 방식입니다.
여기서 LSB는 0x4d이군요, 그렇다면 4byte주소공간에서 주소가 가장 작은 0x1000에 쓰이게 됩니다.
(사실 저도 가끔씩 헷갈립니다...)

하지만 저는 이걸 헷갈리지 않고 기억하기 위해 해당 주소에서 가장 작은 주소 위치에 어떤 Byte가 쓰이는가로 구분합니다.

Big Endian은 MSB가 Base address에 쓰인다.
Little Endian은 LSB가 Base address에 쓰인다.

네 Base address는 또 뭐냐....흑흑 왜 갑자기 뭔가 하나 둘 계속 나오냐...
하실 수 있습니다.
Base address가 데이터를 쓰고자 하는 부분의 가장 작은 주소를 뜻한다라고 생각하면 좋을 거 같습니다.
나중에는 Base address + offset으로 SoC에 있는 IP에 있는 register에 접근하는데, 네 일단 여기까지만 말하겠습니다..
얘기가 다른 곳으로 세는 것 같군요..
(제가 뭔가 하나 설명하면 주변에 있는 관련 모든 것을 설명하려는 설명충입니다...흑흑)

module top_module( 
    input [31:0] in,
    output [31:0] out );//
    
    assign out[31:24] = in[7:0];
    assign out[23:16] = in[15:8];
    assign out[15:8] = in[23:16];
    assign out[7:0] = in[31:24];

endmodule

이렇게 작성하면 이번 문제를 간단하게 해결할 수 있습니다.
어때요 쉽나요?
우리가 지금 작성한 이 circuit을 사용한다면 Big Endian <=> Little Endian conversion을 할 수 있답니다.

Bitwise operators

이 문제에서는 Bitwise vs Logical operators를 다루는데요, 이 둘의 차이를 명확하게 알고 가는 것을 강조하고 있습니다.

사실 이건 Verilog뿐만 아니라 Firmware를 작성할 때 주로 C를 사용하는데, 이 때 bitwise opertor를 정말로 많이 사용한답니다.
하지만 이걸 작성하는 사람이 Bitwise vs logical operator 의 차이를 모른다?
개같이 멸망합니다.

이 내용은 Verilog로 HDL을 작성할 때뿐만 아니라 다른 곳에서도 정말로 중요한 개념입니다. 헷갈리면 멸망입니다.

자... 그럼 본론으로 들어가봅시다.
Bitwise가 무엇이냐? 각 Bit별로 연산을 취해준다 이 말입니다.
그럼 n-bit인 2개의 이진수를 bitwise 연산을 한다? 그 결과는 n-bit가 나온다는 말입니다.

그럼 Logical하게 operation한다는 무엇이냐?
이건 피연산자(계산 되어야 할 대상)가 True냐 False냐를 따집니다.
False는 0인 것이고 True는 False가 아닌 모든 것이니, 사실 0b1도 되고 0b11도 되고 0b10도 됩니다.
여기서 잘 이해가 안되는 사람을 위해 True가 되는 조건이 피연산자가 0이 아닌 모든 수라는 것입니다.

그럼 Logical operation은 1bit 결과가 나오겠지요? 왜냐?
피연산자가 일단 True냐 False를 따지고 그 두 개를 연산하는 것이니...
애초에 True or False가 1bit 신호이지요?
그래서 Logical operation은 출력이 1bit가 나옵니다.

자 그럼 서론에서 말한 것처럼 이 둘을 혼동해서 작성한다?
동작이 이상하게 될 것입니다.
예를 들어 32bit 출력이 나와야 하는데 && 이렇게 logical opertion을 취해버려서 1bit 신호가 출력으로 나오면 당연히 오동작할 가능성이 99.99999999999%겠지요?

그림 3 : Bitwise vs Logical Operators
module top_module( 
    input [2:0] a,
    input [2:0] b,
    output [2:0] out_or_bitwise,
    output out_or_logical,
    output [5:0] out_not
);
	assign out_or_bitwise = a|b;
    assign out_or_logical = a||b;
    assign out_not = {~b,~a};
endmodule

이 문제에서 마지막에 6bit짜리에서

assign out_not = {~a,~b};

라고 작성하면 mismatch가 나옵니다. 이건 아마 문제에 내장된 Testbench때문에 그런거니, 신경쓰지말고 위에 제가 한 것처럼 작성하시면 됩니다.
(저도 mismatch가 나서 당황했습니다. 어쩌라는 거야)

Four-input gates

이 문제는 4개의 Input을 가지는 gate를 기술하는 겁니다.
a&b&c&d 이런식으로 묶어서 작성하시면 되겠습니다.
이건 easy하니까 pass하겠습니다.

module top_module( 
    input [3:0] in,
    output out_and,
    output out_or,
    output out_xor
);
    assign out_and = in[3]&in[2]&in[1]&in[0];
    assign out_or = in[3]|in[2]|in[1]|in[0];
    assign out_xor = in[3]^in[2]^in[1]^in[0];
endmodule

Vector concatenation operator

네, 이번 문제는 vector concatenation operator에 대한 것입니다.
concatenation은 여러 bits을 묶는 연산자인데요, 위에서 제가 문제를 풀 때, 사용했었습니다.

assign out_not = {~a,~b};
이 부분을 concatenation을 사용하지 않고 한다면,
assign out_not[5:3] = ~a;
assign out_not[2:0] = ~b;

바로 위에 제가 적어둔 것처럼 concatenation을 사용하지 않으면 하나하나 assign해줘야 합니다.
귀찮아요 이러면
그래서 사용하면 좋은 것이 concatenation입니다. 나중에 adder를 다룰 때, carry를 {}로 포함해서 연산 결과를 한번에 묶기도 하고요, 다양하게 사용되는 녀석입니다.

자 그럼 문제로 바로 들어가봅시다.

그림4 : Vector concat
module top_module (
    input [4:0] a, b, c, d, e, f,
    output [7:0] w, x, y, z );//

    
    assign {w,x,y,z} = {a,b,c,d,e,f,2'b11};

endmodule

네 이렇게 한줄로 가능합니다.
어때요 깔끔하지요?
(사실 문제 solution칸에 약간의 hint를 보면 금방합니다.)

Vector reversal

자 이번 문제는 bit ordering입니다.
위에서는 byte ordering을 다루었지요?
그걸 잘 생각한다면 금방합니다.
바로 문제로 가봅시다.

module top_module( 
    input [7:0] in,
    output [7:0] out
);
    assign out = in[0:7];
endmodule

만약 이렇게 한다면 error가 발생할 것입니다.
그 이유는 Verilog는 뒤집는 bit ordering을 허용하지 않는다고 합니다.
네, 혹시나 이런 에러를 만난 분들도 있을까봐 미리 말씀드립니다.
(저도 이 에러를 만났습니다.ㅋㅋㅋㅋ)

module top_module( 
    input [7:0] in,
    output [7:0] out
);
    assign out = {in[0],in[1],in[2],in[3],in[4],in[5],in[6],in[7]};
endmodule

귀찮아도 이렇게 작성해야합니다.

Replication operator

이번에는 Replication에 대해 다루는 문제인데요,

assign a = 9'b111111111;

이렇게 1을 9번 적는건 사실 그렇게 어려운 일은 아닙니다만,
실수로 1을 9번 적어야하는데, 8번만 적는다면...?
이것때문에 문제가 생겨서 디버깅을 해야하는데, 코드가 1000줄이라면...?
네 정말로 끔찍합니다..
으악 내 눈... 이러면서 눈물을 흘리며 잘못된 부분을 찾아야겠지요.

그래서 사실 제 생각에는

assign a = {9{1'b1}};

이렇게 작성하면 실수를 덜 할 것 같습니다.

이런 경우가 거의 없을 것 같다 하시겠지만, 오산입니다.

우리 이진수 세상에서는 2의 보수로 숫자를 표현하죠.
MSB(Most Significant Bit)가 0이면 양수, 1이면 음수를 나타냅니다.
2의 보수 관련해서 다루면 얘기가 길어지니, 이건 생략하도록 하겠습니다.

만약 4'b1111(십진수로 -1)을 32bit으로 표현해야한다면 4'b1111_1111_1111_1111_1111_1111_1111_1111 이렇게 작성해야겠지요.

MSB를 replication operator를 이용하여서 sign extend를 진행해주면 정말로 편리하겠지요.

이번 문제가 Sign extend를 해주는 circuit을 작성하는 것입니다.

module top_module (
    input [7:0] in,
    output [31:0] out );//

    // assign out = { replicate-sign-bit , the-input };
    
    assign out = {{24{in[7]}},in};

endmodule

이렇게 작성하면 MSB인 in[7]에 따라 나머지 Bits가 자동으로 맞추어지겠지요.
정말로 편합니다.

More replication

이번 문제는 이전 문제를 잘 풀었다면, 코멘트를 할 필요가 없습니다.
그 말을 easy하다 이 말입니다.

module top_module (
    input a, b, c, d, e,
    output [24:0] out );//
    
    assign out = {{5{a}},{5{b}},{5{c}},{5{d}},{5{e}}}~^{5{a,b,c,d,e}};

endmodule

마무리

네 이렇게 지금까지 HDLBits의 Basics와 Vectors에 대한 문제를 풀어보았습니다.
어떤가요?
쉽게 설명하려고 풀어서 말하려 했지만, 그게 잘 전달되었는지 모르겠군요.
배경을 설명하기 위해 다른 개념을 중간중간에 짧게 소개하기도 했는데요, 나중에 이 내용들에 기회가 된다면 심도있게 포스팅해보겠습니다.

앞으로 modules, procedures, ... Verification 등등 아직 남은 것들이 많으니, 계속해서 작성해보겠습니다.

이 후에는 제가 지금하고 있는 FPGA Project에 대해서도 다루어 보겠습니다.

감사합니다~

profile
muscle brain

0개의 댓글