프로그램에서 화면에 문자를 출력하는 메커니즘은 다음과 같다. 상세한 부분은 필요에 따
라 참고서적을 살펴보기 바란다. 화면에 출력하려는 데이터(문자)는 VGA 카드에 있는 `비
디오 메모리'에 저장되어 있다. 프로그램은 화면에 출력하는 문자를 비디오 메모리에 기록
함으로 VGA에 의해서 화면에 출력된다. VGA 비디오 메모리의 영역은 RAM의 0xa0000000
~ 0xb000ffff까지의 128Kbyte 크기로 할당되어 있으며, 실제 프로그램에서는 VGA 표준
Text 모드에서는 RAM의 0xb8000000 ~ 0xb000ffff까지의 32Kbyte 크기의 영역을 사용
하고 있다. 이 영역들의 데이터들은 디바이스 드라이브(VGA 카드)에 의하여 그대로 VGA
비디오 메모리로 맵핑에 의해 전달된다. 그러므로 우리는 VGA 표준 Text 모드에서 화면
출력을 하고자 할 때, RAM의 0xb8000000 ~ 0xb000ffff까지의 32Kbyte 크기의 영역에
출력하려는 데이터를 적어주기만 하면 된다. 그러면 이 데이터가 VGA 비디오 메모리로 그
대로 전달되고, 그에 따라 모니터의 출력이 자동적으로 이루어진다.
표준 Text 모드가 4K byte로 한 화면의 내용을 저장할 수 있다는 것을 감안할 때,
32Kbyte는 8개의 화면 내용을 저장할 수 있다. 이 과제에서는 8개의 화면 중 첫 번째 화
면만을 사용한다.
화면 1 점에 2byte 가 배정 되는데 이것은 글자의 데이터 뿐만 아니라 속성(글자색 배경색 등)에 대한 정보 또한 가지고 있기 때문이다.
비디오 램의 시작 주소는 컬러 VGA 카드의 경우 B8000,0000h 이고 흑백 인 경우 B000,0000h 이다.
영역 0000,0449h 영역을 조사하면 알 수 있다. 값이 7 이면 컬러 이다. 요즘은 그냥 다 컬러 ;;
아래 코드는 터보C 컴파일러에서 동작함
#include<stdio.h>
#define OFF_SET(x,y) (((x)*2)+((y)*160))
#define VRAM_ASCLL(x,y) *(Video_address+OFF_SET(x,y))
#define VARM_ATTR(x,y) *(Video_address+(x)*2+1+(y)*160)
char far* Video_address;
void vcharxy(int x, int y, char ch, int attr)
{
VRAM_ASCLL(x, y) = ch; // offset 계산
VARM_ATTR(x, y) = attr; // 글자 특성 입력
}
int main()
{
unsigned x, y;
if (peekb(0, 0x449) == 7)
{
Video_address = (char far*)0xB0000000L;
}
else
{
Video_address = (char far*)0xB8000000L;
}
for (x = 20; x < 30; x++)
{
for (y = 0; y < 10; y++)
{
vcharxy(x, y, 'A', 0x70);
}
}
getch();
return 0;
}
심화 예제
#include<stdio.h>
#include<conio.h>
#define UP 0x48
#define DOWN 0x50
#define LEFT 0x4B
#define RIGHT 0x4D
#define OFF_SET(x,y) (((x)*2)+((y)*160))
#define VRAM_ASCLL(x,y) *(Video_address+OFF_SET(x,y))
#define VARM_ATTR(x,y) *(Video_address+(x)*2+1+(y)*160)
char far* Video_address;
typedef struct MENU_FRAME
{
char* item;
int x, y;
}MENU;
void vcharxy(int x, int y, char ch, int attr);
void vputs(char* str, int x, int y, int attr);
void display_menu();
MENU menu[4] = {
{"NEW Game Alt-N",0,3},
{"Load Game Alt-L",0,4},
{"Options Alt-O",0,5},
{"Quit Alt-X",0,6},
};
int main()
{
int sno = 0;
char ch;
char quit = 0;
if (peekb(0, 0x449) == 7)
{
Video_address = (char far*)0xB0000000L;
}
else
{
Video_address = (char far*)0xB8000000L;
}
display_menu();
while (1)
{
if ((ch = getch()) == 0) // 확장키 입력시 0;
{
switch (getch())
{
case UP:
vputs(menu[sno].item, menu[sno].x, menu[sno].y, 0x07);
sno--; // 메뉴 하나 줄임
if (sno<0)
{
sno = 3; // 메뉴가 0 보다 작으면 마지막 메뉴 보여줌
}
vputs(menu[sno].item, menu[sno].x, menu[sno].y, 0x70);
break;
case DOWN:
vputs(menu[sno].item, menu[sno].x, menu[sno].y, 0x07);
sno++; // 메뉴 하나 줄임
if (sno > 3)
{
sno = 0; // 메뉴가 3 보다 크면 처음 항목으로 설정
}
vputs(menu[sno].item, menu[sno].x, menu[sno].y, 0x70);
break;
default:
break;
}
}
else if (ch == '\r') // 엔터키 입력
{
switch (sno)
{
case 0:
vputs("the first menu is slected ..", 0, 10, 0x07);
break;
case 1:
vputs("the second menu is slected ..", 0, 10, 0x07);
break;
case 2:
vputs("the third menu is slected ..", 0, 10, 0x07);
break;
case 3:
vputs("thank you for useing ..", 0, 10, 0x07);
quit = 1;
break;
default:
break;
}
}
if (quit)
{
break;
}
}
getch();
return 0;
}
void vcharxy(int x, int y, char ch, int attr) // 비디오 램에 글자 1 자 씩 씀
{
VRAM_ASCLL(x, y) = ch; // offset 계산
VARM_ATTR(x, y) = attr; // 글자 특성 입력
}
void vputs(char* str, int x, int y, int attr) // str 안에 있는 글자 다 쓰는 함수
{
while (*str != 0)
{
vcharxy(x++, y, *str++, attr);
}
}
void display_menu()
{
clrscr();
vputs("-------------", 0, 0, 0x07);
vputs(" MENU SYSTEM ", 0, 1, 0x07);
vputs("-------------", 0, 2, 0x07);
vputs(menu[0].item, menu[0].x, menu[0].y, 0x70);
vputs(menu[1].item, menu[1].x, menu[1].y, 0x07);
vputs(menu[2].item, menu[2].x, menu[2].y, 0x07);
vputs(menu[3].item, menu[3].x, menu[3].y, 0x07);
vputs("-------------", 0, 7, 0x07);
}
'공부,일 > c언어' 카테고리의 다른 글
간단한 메모리 접근 (0) | 2021.06.18 |
---|---|
간단한 키보드 제어 (0) | 2021.06.17 |
룸 바이오스 데이터 영역 접근 (0) | 2021.06.16 |
터보C 설치 사용 (0) | 2021.06.15 |
Linked List 구현 (0) | 2021.06.14 |
댓글