728x90

현황

- 방금전 C언어에서 직접 메모리 번지를 지정하는 방법이 없다고 하여 write_mem8 함수를 직접 어셈블리어로 구현

- 하지만 포인터를 이용하면 메모리 접근 가능

 

 

 

문제

- 어셈블리어의 문제 : 데이터가 byte인지 word인지, dword인지 알수 없음.

- c언어에서는 공간의 크기에 따라 다양한 자료형 제공

 ex. char 1바이트, short 2바이트, int 4바이트

 

 

 

 

포인터로 메모리 접근하자

- write_mem8로 i번째 주소에 접근했다면

- 지금은 포인터 변수 p에다가 주소를 담아 접근해서 사용

=> naskfunc.nas에서 wirte_mem8은 필요없으므로 지우기

 

 

 

 

색번호 설정하기

- 이제 포인터로 VRAM에 접근해서 값을 읽고 쓸수 있다. 하지만 단색은 재미없으니 색상도 바꿔보자

- 8비트 컬러 모드에서 0~255색을 표현 가능 -> 색번호 지정하는 구조를 팔레트라 부름

- 우리가 사용할 OS에서 16색만 있으면 충분할것같으니 다음과 같이 색들을 지정해주자

#000000 : 검은색 #00ffff : 밝은 청색 #000084 : 군청색
#ff0000 : 밝은 적색 #ffffff : 흰색 #840084 : 어두운 보라색
#00ff00 : 밝은 녹색 #c6c6c6 : 밝은 회색 #008484 : 어두운 청색
#ffff00 : 밝은 노란색 #840000 : 어두운 적색 #848484 : 어두운 회색
#0000ff : 밝은 청색 #008400 : 어두운 녹색  
#ff00ff : 밝은 보라색 #848400 : 어두운 노란색  

 

c언어 코드

- 맨앞의 함수들은 어셈블리어에서 정의함

void io_hlt(void);
void io_cli(void);
void io_out8(int port, int data);
int io_load_eflags(void);
void io_store_eflags(int eflags);

/* 같은 소스 내에 있어도 C언어에서 사용하기 위해선 우선 선언 필요 */

void init_palette(void);
void set_palette(int start, int end, unsigned char *rgb);

void HariMain(void)
{
	int i;
	char *p;

	init_palette(); /*팔래트 초기화 */

	p = (char *) 0xa0000; /* 번지대입 */

	for (i = 0; i <= 0xffff; i++) {
		p[i] = i & 0x0f;
	}

	for (;;) {
		io_hlt();
	}
}

void init_palette(void)
{
	static unsigned char table_rgb[16 * 3] = {
		0x00, 0x00, 0x00,	/*  0:검은색 */
		0xff, 0x00, 0x00,	/*  1:밝은 적색 */
		0x00, 0xff, 0x00,	/*  2:밝은 녹색 */
		0xff, 0xff, 0x00,	/*  3:밝은 노란색 */
		0x00, 0x00, 0xff,	/*  4:밝은 청색 */
		0xff, 0x00, 0xff,	/*  5:밝은 보라색 */
		0x00, 0xff, 0xff,	/*  6:밝은 청색*/
		0xff, 0xff, 0xff,	/*  7:흰색 */
		0xc6, 0xc6, 0xc6,	/*  8:밝은 회색 */
		0x84, 0x00, 0x00,	/*  9:어두운 적색 */
		0x00, 0x84, 0x00,	/* 10:어두운 녹색 */
		0x84, 0x84, 0x00,	/* 11:어두운 노란색 */
		0x00, 0x00, 0x84,	/* 12:군청색 */
		0x84, 0x00, 0x84,	/* 13:어두운 보라색 */
		0x00, 0x84, 0x84,	/* 14:어두운 청색 */
		0x84, 0x84, 0x84	/* 15:어두운 회색 */
	};
	set_palette(0, 15, table_rgb);
	return;

	/* static char 명령은 (주소가 아니라)데이터밖에 쓰지 못하지만, DB명령과 동일함 */
}

void set_palette(int start, int end, unsigned char *rgb)
{
	int i, eflags;
	eflags = io_load_eflags();	/* 인터럽트 허가 플래그 값을 로드함 */
	io_cli(); 					/* 허가 플래그를 0으로 하여 인터럽트 금지 */
	io_out8(0x03c8, start);
	for (i = start; i <= end; i++) {
		io_out8(0x03c9, rgb[0] / 4);
		io_out8(0x03c9, rgb[1] / 4);
		io_out8(0x03c9, rgb[2] / 4);
		rgb += 3;
	}
	io_store_eflags(eflags);	/* 인터럽트 허가 플래그를 본래 값으로 되돌린다. */
	return;
}

 

 

 

c언어와 어셈블리어 문법 잠깐 보기

- char a[3] a라는 이름의 길이가 3인 배열 공간 생성( 값들은 0)

 => 아래와 동일

     a :

           RESB 3

 

- 색상 테이블은 어셈블리어 상에서 아래와 같이 값을 대입해주는게 경제적임

 => static char로 선언한 변수에 값을 넣는게, DB 명령어로 대입하는것과 동일함

   table_rgb:

      DB 0x00, 0x00, 0x00, 0xff, 0x00, 0xff ....

 

 

 

set_palette 보기

- io_out8 함수 : 장치 번호로 지정한 장치에 데이터를 보내는 함수

- CPU와 메모리만 연결되어있으면 계산과 기억밖에 하지못함.

 => 하드디스크, 그래픽, 사운드 카드 등과 연결되어 다양한 입출력이 가능해짐

 

 

out/in 명령어

- out 명령어 : 특정 장치로 전기 신호를 보내기 위한 명령어

- in 명령어 : 특정 장치로부터 신호를 받기 위한 명령

 

 

그래픽 관련 장치 번호

- 0x03c8, 0x03c9는 그래픽 관련 장치번호

- 팔레트 액세스 순서

- 액세스 중에는 인터럽트 발생해선 안됨 ex. CLI

- 0x03c08에 사용할 팔레트 번호를 쓰고, RGB 순서대로 0x03c9에 입력

  * 다음 팔레트도 같이 설정한다면 팔레트 번호 설정 생략하고 계속 RGB순서로 쓰면됨.

- 팔레트 상태 읽을때 0x03c7에 팔레트 번호 쓰고, 0x03c9를 3번 읽음 => RGB순서대로 처리됨.

- 최초 CLI(인터럽트 금지)를 한경우 마지막에 STI(io_store_eflags, 인터럽트 허가 플래그 원위치)를 한다.

 

 

CLI와 STI

- CLI : 인터럽트 플래그 interrupt flag를 0으로 만듬( clear interrupt flag)

- STI : 인터럽트 플래그를 1로 만드는 명령 (set interrupt flag)

=> 인터럽트 플래그가 0이면 인터럽트 반응 회로가 동작 안함, 1이면 동작함

 

 

EFLAGS

- 16비트 레지스터인 FLAGS가 32비트로 레지스터로 확장된 레지스터.

- FGLAS는 캐리 플래그, 인터럽트 플래그 등으로 구성됨.

- 아래의 그림은 16비트 8086 아키택처의 FLAGS 레지스터

http://mmrcse.blogspot.com/2018/12/write-function-of-segment-register-and.html

 

 

 

set_palette에서 하는일

- 팔레트 설정하기전에 CLI실행. 

- 팔레트 설정후

- 인터럽트 플래그 허용 STI

 

 

 

naskfunc.nas

- PUSHFD : push flags double-word : vmfformfmf ejqmf dnjemfh alfdjsjgsmsek.

- POPFD : pop EFLAGS라는 뜻

=> EFLAGS를 읽거나 쓰는데 ㅏ용.

 

; naskfunc
; TAB=4

[FORMAT "WCOFF"]				; 오브젝트 파일 만드는 모드
[INSTRSET "i486p"]				; 이 프로그램이 486 아키텍처 용 프로그램임을 nask에 알림
[BITS 32]						; 32비트 모드용 기계어 만듬
[FILE "naskfunc.nas"]			; 소스 파일명 정보

		GLOBAL	_io_hlt, _io_cli, _io_sti, _io_stihlt
		GLOBAL	_io_in8,  _io_in16,  _io_in32
		GLOBAL	_io_out8, _io_out16, _io_out32
		GLOBAL	_io_load_eflags, _io_store_eflags

[SECTION .text]

_io_hlt:	; void io_hlt(void);
		HLT
		RET

_io_cli:	; void io_cli(void);
		CLI
		RET

_io_sti:	; void io_sti(void);
		STI
		RET

_io_stihlt:	; void io_stihlt(void);
		STI
		HLT
		RET

_io_in8:	; int io_in8(int port);
		MOV		EDX,[ESP+4]		; port
		MOV		EAX,0
		IN		AL,DX
		RET

_io_in16:	; int io_in16(int port);
		MOV		EDX,[ESP+4]		; port
		MOV		EAX,0
		IN		AX,DX
		RET

_io_in32:	; int io_in32(int port);
		MOV		EDX,[ESP+4]		; port
		IN		EAX,DX
		RET

_io_out8:	; void io_out8(int port, int data);
		MOV		EDX,[ESP+4]		; port
		MOV		AL,[ESP+8]		; data
		OUT		DX,AL
		RET

_io_out16:	; void io_out16(int port, int data);
		MOV		EDX,[ESP+4]		; port
		MOV		EAX,[ESP+8]		; data
		OUT		DX,AX
		RET

_io_out32:	; void io_out32(int port, int data);
		MOV		EDX,[ESP+4]		; port
		MOV		EAX,[ESP+8]		; data
		OUT		DX,EAX
		RET

_io_load_eflags:	; int io_load_eflags(void);
		PUSHFD		; PUSH EFLAGS 라는 뜻
		POP		EAX
		RET

_io_store_eflags:	; void io_store_eflags(int eflags);
		MOV		EAX,[ESP+4]
		PUSH	EAX
		POPFD		; POP EFLAGS 라는 뜻
		RET

 

 

실행 결과

- 색상있는 줄무늬들이 출력됨

 

 

300x250

+ Recent posts