[베릴로그 RTL 예제] 탁구 게임기 -4편: 움직이는 탁구공-
목차:
1. RTL 베릴로그로 "탁구대" 그리기
2. 그래픽 LCD 구동 칩의 시뮬레이션 모델
3. "탁구대"의 그래픽 테스트 벤치
4. 움직이는 탁구공
----------------------------------------------------------------------------------------------------------------
오픈-소스 반도체 설계 도구가 설치된 "내 칩 디자인 킷"의 WSL 가상 디스크 이미지 [링크]
----------------------------------------------------------------------------------------------------------------
4. 움직이는 탁구공
고정된 "탁구대" 그리기는 쉬웠다. 조금 난이도를 높여 움직이는 탁구공이다. 이 공은 사방의 벽에 부딪쳐 방향을 바꾼다. 단순한 비트-맵으로 탁구공 이미지를 임의의 좌표상에 표시할 것이다. 이는 흔히 문자 단말기(text terminal)에서 문자 이미지를 표시하는 기법과 같다.
4-1. 탁구공 이미지 비트-맵
탁구공 이미지의 비트-맵은 베릴로그의 case 문으로 기술하면 다음과 같다. 이는 ROM 메모리를 기술하는 기법이기도 하다. 또는 값을 주고 출력을 얻어오는 룩-업 테이블(LUT, Look-Up Table)이라고 한다.
// Ball Image ROM -----------------------------------------------
reg [7:0] rom_data;
always @*
begin
case(rom_addr)
3'b000 : rom_data = 8'b00111100; // ****
3'b001 : rom_data = 8'b01111110; // ******
3'b010 : rom_data = 8'b11000011; // ** **
3'b011 : rom_data = 8'b11000011; // ** **
3'b100 : rom_data = 8'b11000011; // ** **
3'b101 : rom_data = 8'b11000011; // ** **
3'b110 : rom_data = 8'b01111110; // ******
3'b111 : rom_data = 8'b00111100; // ****
endcase
end
연산장치가 LUT로 구현 되기도 한다. 예를 들어 A+B=C 라고 할 경우 주소로 [A+B] 를 주고 해당 주소에 C 에 해당하는 값을 저장해 두면 바로 덧셈 연산기가 된다. LUT의 장점은 임의의 연산기를 쉽게 만들 수 있지만 경우에 따라 메모리 용량이 불필요하게 커질 수 있다는 점이다. 논리식에서 돈-캐어(Don't-Care) 조건을 적용하여 최적화를 수행할 있지만 고정된 비트폭을 가지는 입력을 가지게 되므로 논리식 최적화의 의미가 없다. 미리 하드웨어가 정해져 있는 프로그래머블(programmable 또는 configurable) 반도체(FPGA, PLA, ROM 등)에서 조합 논리식은 LUT 로 구현한다.
4-2. 임의 위치에 탁구공 그리기
임의의 그래픽 좌표 x_ball과 와 y_ball에 탁구공 이미지를 그려보자. 그래픽 화면을 연속적으로 훓는 좌표가 탁구공 이미지 좌표에 이르면 이미지 비트를 표시할 수 있다.
이미지 ROM에서 읽은 8비트 데이타 중 조건에 맞는 픽셀 값을 얻어 화면에 출력하기를 베릴로그로 표현하면 다음과 같다. 모든 입력 신호가 always의 감응 리스트에 적용 하였다. 따라서 아래 구문의 always 구역에 감응되는 신호는 x_pos, y_pos, x_ball, y_ball 그리고 rom_bit와 rom_data다. 아울러 출력 pixel이 if ~ else 문에 모두 할당(완결된 if 문)되었다. 따라서 조합회로다.
always @*
if ((x_ball<=x_pos) && ((x_ball+7)>=x_pos) &&
(y_ball<=y_pos) && ((y_ball+7)>=y_pos))
pixel = rom_data[rom_bit];
else
pixel = 0;
4-3. 움직이는 탁구공
탁구공의 죄표를 변경하여 움직임을 표현할 수 있다. 탁구공 좌표는 화면 훓기가 새로 시작될 때마다 갱신되어야 한다. 수직선 y_pos 가 63에 이르면 새로 화면이 갱신 되었음을 표시하는 v_sync 를 제어기 FSM 에 추가한다.
// FSM //////////////////////////////////////////////////////////
reg [1:0] State;
parameter sWait = 2'b01;
parameter sPixel = 2'b10;
reg v_sync;
always @(posedge clk or posedge reset)
begin
if (reset)
begin
x_pos <= 127;
y_pos <= 63;
p_tick <= 0;
v_sync <= 0;
State <= sWait;
end
else
case(State)
sWait:
begin
if (!busy)
begin
x_pos <= x_pos + 1;
if (x_pos==127)
begin
y_pos <= y_pos + 1;
if(y_pos==63)
v_sync <= 1;
end
p_tick <= 1'b1;
State <= sPixel;
end
end
sPixel:
begin
v_sync <= 0;
if (busy)
begin
p_tick <= 1'b0;
State <= sWait;
end
end
default:
State <= sWait;
endcase
end
화면 훓기가 새로 시작되기 전에 탁구공의 좌표를 수정한다. 벽에 부딪칠 때 좌표의 변위만큼 더하거나 빼주므로써 탁구공의 위치를 변경하면 새로 화면이 그려질 때마다 탁구공이 움직이는 것처럼 보일 것이다.
// Update Ball position -----------------------------------------
reg [6:0] x_ball;
reg [5:0] y_ball;
always @(posedge clk or posedge reset)
begin
if (reset)
begin
x_ball <= 0;
y_ball <= 50;
end
else
begin
if (v_sync)
begin
if (sign_x) x_ball <= x_ball - 1;
else x_ball <= x_ball + 1;
if (sign_y) y_ball <= y_ball - 1;
else y_ball <= y_ball + 1;
end;
end
end
탁구공이 벽에 부딪쳤음을 아는 방법은 간단하다. 공의 죄표가 벽의 상하좌우 벽을 넘어가는지 알아내서 그에 따라 다음 화면 갱신때 변위 만큼 가감해준다. 공이 화면영역 내에 있는지 검사하는 베릴로그는 다음과 같다. 완결된 if~else 가 아니므로 x_ball과 y_ball 은 1비트 플립플롭 레지스터로서 always 구역은 순차회로가 된다.
reg sign_x;
reg sign_y;
always @(posedge clk or posedge reset)
begin
if (reset)
begin
sign_x <= 0;
sign_y <= 0;
end
else if (v_sync)
begin
if (x_ball==119) sign_x <= 1;
else if (x_ball==0) sign_x <= 0;
if (y_ball==55) sign_y <= 1;
else if (y_ball==0) sign_y <= 0;
end
end
4-4. 실습 및 과제
움직이는 "탁구공"의 실습 예제 소스 구성은 다음과 같다.
a. 실습
예제의 시뮬레이터 빌드와 실행은 모두 make 유틸리티로 수행한다. 소스 파일의 구성은 앞장에서와 동일하므로 Makefile의 변화는 없다.
$ make build
시뮬레이터를 실행해보자.
$ make run
b. 과제
시뮬레이션 속도가 매우 느리다. 화면을 한번 갱신하는데 수초가 걸린다. 실습으로 얻은 파형을 관찰해 보라. 그리고 사건 구동 시뮬레이터(event-driven simulator)에서 수행 속도가 느린 이유에 대하여 토론해보자. 시뮬레이션 속도는 곧 개발 지연을 초래한다. 이를 극복할 수 있는 방법으로 버스 기능 모델(BFM, Bus Functional Modeling)또는 트랜잭션 모델링(TLM, Transaction Level Modeling)기법이 동원된다.
* 시뮬레이션 파형을 관찰해 보면 불필요하게 rom_bit 가 계산되고 있다. 저전력 설계의 여지를 찾아보자.
* FPGA의 구조에서 LUT의 역할에 대하여 토론해 보자.
[출처] The HLS Book: Parallel Programing for FPGA , https://github.com/KastnerRG/pp4fpgas.git





댓글 없음:
댓글 쓰기