๐๏ธ ํจ์๋ก ๋ฌธ์์ด ์ ์ฒด๋ฅผ ํ๋ฉด์ ์ถ๋ ฅํ๋ ์ฝ๋์
๋๋ค.
This is code that outputs the entire string to the screen using a function.
๐๏ธ ์ด์ ์ฝ๋์์ draw_string()ํจ์๊ฐ ์ถ๊ฐ๋์ต๋๋ค.
The draw_string() function has been added to the previous code.
๐๏ธ A~Z๊น์ง ์ฌ์ฉ๊ฐ๋ฅํ๋๋ก ๋ฌธ์๋ฅผ ์ถ๊ฐํ์ต๋๋ค.
We have added characters to support the full range from A to Z.
๐๏ธ ํ์ผ / files
boot.asm kernel.c sector2.asm
๐๏ธ boot.asm๊ณผ sector2.asm์ miniOS-9์ ๋์ผํฉ๋๋ค.
boot.asm and sector2.asm are identical to those of miniOS-9.
๐๏ธ ์ฝ๋ / Code
typedef unsigned char byte;
// ------------------------------------------------------------------------
// 1. ๊ธฐ๋ณธ ๊ทธ๋ํฝ ํจ์ (volatile ์ ์ฉ์ผ๋ก ๋ฉ๋ชจ๋ฆฌ ๊ฐ์ ์ฐ๊ธฐ)
// Basic graphics functions (forced memory write via volatile)
// ------------------------------------------------------------------------
void draw_pixel(int x, int y, byte color) {
volatile byte *vram = (volatile byte *)0xA0000;
vram[(y * 320) + x] = color;
}
void clear_screen(byte color) {
for (int y = 0; y < 200; y++) {
for (int x = 0; x < 320; x++) {
draw_pixel(x, y, color);
}
}
}
// ------------------------------------------------------------------------
// 2. ๊ธ์ ์ถ๋ ฅ ํจ์ (ํฐํธ ๋ฐ์ดํฐ๋ฅผ ํจ์ ๋ด๋ถ๋ก ์ด๋ํ์ฌ ๋งํน ์ค๋ฅ ํด๊ฒฐ)
// Character output function (resolved linking errors by moving font data inside the function)
// ------------------------------------------------------------------------
void draw_char(int start_x, int start_y, char c, byte color) {
// A๋ถํฐ Z๊น์ง ์ด 26๊ฐ์ ์ํ๋ฒณ ๋๋ฌธ์ 8x8 ํฐํธ ๋ฐ์ดํฐ ์ธํธ
byte font_8x8[26][8] = {
{0x18, 0x24, 0x42, 0x7E, 0x42, 0x42, 0x42, 0x00}, // 'A' (index 0)
{0x7C, 0x42, 0x42, 0x7C, 0x42, 0x42, 0x7C, 0x00}, // 'B' (index 1)
{0x3C, 0x42, 0x40, 0x40, 0x40, 0x42, 0x3C, 0x00}, // 'C' (index 2)
{0x78, 0x44, 0x42, 0x42, 0x42, 0x44, 0x78, 0x00}, // 'D' (index 3)
{0x7E, 0x40, 0x40, 0x78, 0x40, 0x40, 0x7E, 0x00}, // 'E' (index 4)
{0x7E, 0x40, 0x40, 0x78, 0x40, 0x40, 0x40, 0x00}, // 'F' (index 5)
{0x3C, 0x42, 0x40, 0x4E, 0x42, 0x42, 0x3C, 0x00}, // 'G' (index 6)
{0x42, 0x42, 0x42, 0x7E, 0x42, 0x42, 0x42, 0x00}, // 'H' (index 7)
{0x3E, 0x08, 0x08, 0x08, 0x08, 0x08, 0x3E, 0x00}, // 'I' (index 8)
{0x03, 0x01, 0x01, 0x01, 0x41, 0x41, 0x3E, 0x00}, // 'J' (index 9)
{0x42, 0x44, 0x48, 0x70, 0x48, 0x44, 0x42, 0x00}, // 'K' (index 10)
{0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x7E, 0x00}, // 'L' (index 11)
{0x42, 0x66, 0x5A, 0x42, 0x42, 0x42, 0x42, 0x00}, // 'M' (index 12)
{0x42, 0x62, 0x52, 0x4A, 0x46, 0x42, 0x42, 0x00}, // 'N' (index 13)
{0x3C, 0x42, 0x42, 0x42, 0x42, 0x42, 0x3C, 0x00}, // 'O' (index 14)
{0x7C, 0x42, 0x42, 0x7C, 0x40, 0x40, 0x40, 0x00}, // 'P' (index 15)
{0x3C, 0x42, 0x42, 0x42, 0x4A, 0x44, 0x3A, 0x00}, // 'Q' (index 16)
{0x7C, 0x42, 0x42, 0x7C, 0x48, 0x44, 0x42, 0x00}, // 'R' (index 17)
{0x3C, 0x40, 0x40, 0x3C, 0x02, 0x02, 0x3C, 0x00}, // 'S' (index 18)
{0x7E, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x00}, // 'T' (index 19)
{0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x3C, 0x00}, // 'U' (index 20)
{0x42, 0x42, 0x42, 0x42, 0x42, 0x24, 0x18, 0x00}, // 'V' (index 21)
{0x42, 0x42, 0x42, 0x42, 0x5A, 0x66, 0x42, 0x00}, // 'W' (index 22)
{0x42, 0x42, 0x24, 0x18, 0x24, 0x42, 0x42, 0x00}, // 'X' (index 23)
{0x42, 0x42, 0x24, 0x18, 0x18, 0x18, 0x18, 0x00}, // 'Y' (index 24)
{0x7E, 0x02, 0x04, 0x08, 0x16, 0x20, 0x7E, 0x00} // 'Z' (index 25)
};
// ๋ฌธ์์ ๋ง๋ ํฐํธ ์ธ๋ฑ์ค ๊ณ์ฐ ('A'๋ฅผ ๋นผ์ 0~25๋ก ๋ณํ)
// Calculate the font index for the character (subtract 'A' to convert to a range of 0โ25)
int font_index = 0;
// 'A'์์ 'Z'๊น์ง ๋ฒ์ ๊ฒ์ฌ
// Check range from 'A' to 'Z'
if (c >= 'A' && c <= 'Z') {
font_index = c - 'A';
} else {
return;
}
for (int y = 0; y < 8; y++) {
byte row_data = font_8x8[font_index][y];
for (int x = 0; x < 8; x++) {
if ((row_data & (0x80 >> x)) != 0) {
draw_pixel(start_x + x, start_y + y, color);
}
}
}
}
// ------------------------------------------------------------------------
// 3. [์๋ก ์ถ๊ฐ] ๋ฌธ์์ด์ ํต์งธ๋ก ๋๊ธฐ๋ฉด ๊ฐ๋ก๋ก ์ ๋ ฌํด ๊ทธ๋ ค์ฃผ๋ ํจ์
// [New Addition] A function that draws a string horizontally when passed as a whole.
// ------------------------------------------------------------------------
void draw_string(int start_x, int start_y, const char *str, byte color) {
int current_x = start_x;
// ๋ฌธ์์ด์ ๋('\0')์ ๋ง๋ ๋๊น์ง ํ ๊ธ์์ฉ ๋ฐ๋ณต์ํ
// Iterate character by character until the end of the string ('\0') is reached
for (int i = 0; str[i] != '\0'; i++) {
// ๊ณต๋ฐฑ ๋ฌธ์(' ') ์ฒ๋ฆฌ: ๊ธ์๋ฅผ ๊ทธ๋ฆฌ์ง๋ ์๊ณ ๊ฐ๋ก๋ก 8ํฝ์
๊ฑด๋๋
// Handle space character (' '): Skip 8 pixels horizontally without drawing a character.
if (str[i] == ' ') {
current_x += 8;
continue;
}
// ํ์ฌ ๊ธ์ ๊ทธ๋ฆฌ๊ธฐ / Drawing current characters
draw_char(current_x, start_y, str[i], color);
// ๋ค์ ๊ธ์๋ ๊ฐ๋ก๋ก 8ํฝ์
๋ค์ ๊ทธ๋ ค์ง๋๋ก ์ขํ ์ด๋ (๊ธ์ ํฌ๊ธฐ๊ฐ 8x8์ด๋ฏ๋ก)
// Shift the coordinates to draw the next character 8 pixels to the right (since the character size is 8x8).
current_x += 8;
}
}
// ------------------------------------------------------------------------
// 4. ์ปค๋ ๋ฉ์ธ ํจ์
// Kernel main function
// ------------------------------------------------------------------------
void kernel_main(void) {
clear_screen(1); // ํ๋ ๋ฐฐ๊ฒฝ / Blue background
// -- ํจ์ ํ ์ค๋ก ๋ฌธ์์ด ํต์งธ๋ก ํ๋ฉด์ ์ถ๋ ฅํ๊ธฐ! (ํ์ฌ ํฐํธ๋ A~F์ ๊ณต๋ฐฑ๋ง ์ธ์ ๊ฐ๋ฅ) -- //
// -- Print an entire string to the screen with a single function call! (The current font only supports AโF and spaces.) -- //
// ๋
ธ๋์(14)์ผ๋ก "I WANT TO" ์ถ๋ ฅ / Output "BAD CAFE" in yellow (14).
draw_string(80, 70, "I WANT TO", 14);
// ํฐ์(15)์ผ๋ก "BREAKE FREE" ์ถ๋ ฅ / Print "DECADE FACE" in white (15).
draw_string(80, 90, "BREAKE FREE", 15);
// ๋นจ๊ฐ์(12)์ผ๋ก "QUEEN" ์ถ๋ ฅ / Output "FADE" in red (12).
draw_string(80, 110, "QUEEN", 12);
while (1) {
__asm__ __volatile__("hlt");
}
}
๐๏ธ ์ฝ๋ ์ค๋ช / Code Explanation
โ๏ธ A~Z๊น์ง ๋ฌธ์ ๋ฒ์ ๊ฒ์ฌ(๋๋ฌธ์)
Check character range from A to Z (uppercase)
๐๏ธ ์ฝ๋ ์ค๋ช / Code Explanation
โ๏ธ A~Z๊น์ง ๋ฌธ์ ๋ฒ์ ๊ฒ์ฌ(๋๋ฌธ์)
Check character range from A to Z (uppercase)
1)draw_charํจ์์ ํ๋ผ๋ฉํฐ๋ก ์
๋ ฅ๋ ๋ณ์(char c)๊ฐ A~Z๊น์ง ๋ฒ์๋ด์ ์๋์ง ๊ฒ์ฌํฉ๋๋ค.
It checks whether the variable (char c) passed as a parameter to the draw_char function falls within the range of A to Z.
2) ๋๋ฌธ์ ์์คํค ์ฝ๋ ‘A’ (65) ~ ‘Z’ (90) ์
๋๋ค.
These are the uppercase ASCII codes ‘A’ (65) through ‘Z’ (90).
3)if (c >= ‘A’ && c <= ‘Z’) { } ๋ if (c >= 65 && c <= 90) {}๊ณผ ๊ฐ์ต๋๋ค.if (c >= 'A' && c <= 'Z') { } is equivalent to if (c >= 65 && c <= 90) {}.
โ๏ธ draw_string()ํจ์ ์คํ
Execute the draw_string() function.
— kernel_mainํจ์์์ ์๋์ ๊ฐ์ด draw_string()ํจ์๋ฅผ ์คํํฉ๋๋ค.
In the kernel_main function, execute the draw_string() function as shown below.
draw_string(80, 70, "I WANT TO", 14);
1) draw_string(x,y,”character”,color number)ํํ์
๋๋ค.
It takes the form draw_string(x, y, "character", color number).
2) kernel_mainํจ์ ๋ด์์ ์๋์ฒ๋ผ draw_stringํจ์๋ฅผ ์คํํ๋ฉด ๋ฌธ์๋ฅผ ์ถ๋ ฅ ํ ์ ์์ต๋๋ค.
You can output characters by calling the draw_string function within the kernel_main function, as shown below.
draw_string(80, 70, "I WANT TO", 14);
โ๏ธ draw_string()ํจ์
draw_string() function
— draw_stringํจ์๋ฅผ ์คํํ๋ฉด ์๋์ ๋ฐ๋ณต๋ฌธ ๋ก์ง์ผ๋ก ์
๋ ฅ๋ ๋ฌธ์๋ฅผ ๋ฐฐ์ด๋ก ๊บผ๋ด์ ์ถ๋ ฅํฉ๋๋ค.
When the draw_string function is executed, the loop logic below extracts the input characters into an array and outputs them.
// ๋ฌธ์์ด์ ๋('\0')์ ๋ง๋ ๋๊น์ง ํ ๊ธ์์ฉ ๋ฐ๋ณต์ํ
// Iterate character by character until the end of the string ('\0') is reached
for (int i = 0; str[i] != '\0'; i++) {
// ๊ณต๋ฐฑ ๋ฌธ์(' ') ์ฒ๋ฆฌ: ๊ธ์๋ฅผ ๊ทธ๋ฆฌ์ง๋ ์๊ณ ๊ฐ๋ก๋ก 8ํฝ์
๊ฑด๋๋
// Handle space character (' '): Skip 8 pixels horizontally without drawing a character.
if (str[i] == ' ') {
current_x += 8;
continue;
}
// ํ์ฌ ๊ธ์ ๊ทธ๋ฆฌ๊ธฐ / Drawing current characters
draw_char(current_x, start_y, str[i], color);
// ๋ค์ ๊ธ์๋ ๊ฐ๋ก๋ก 8ํฝ์
๋ค์ ๊ทธ๋ ค์ง๋๋ก ์ขํ ์ด๋ (๊ธ์ ํฌ๊ธฐ๊ฐ 8x8์ด๋ฏ๋ก)
// Shift the coordinates to draw the next character 8 pixels to the right (since the character size is 8x8).
current_x += 8;
}
1)๋ฐฐ์ด ๋ด์ ๋ฌธ์์ ๊ณต๋ฐฑ์ด ์๋ ๊ฒฝ์ฐ ์ฐ์ธก์ผ๋ก ํ์นธ ๋์ฐ๊ธฐ ์ํด current_x์ 8(ํฝ์
)์ ์ถ๊ฐํฉ๋๋ค.
If there is a space character in the array, 8 (pixels) are added to current_x to shift the position one space to the right.
if (str[i] == ' ') {
current_x += 8;
continue;
}
2)๊ธ์๋ฅผ ๊ทธ๋ฆฝ๋๋ค.
Draw the characters.
draw_char(current_x, start_y, str[i], color);
3)๊ธ์๊ฐ ๊ทธ๋ ค์ง๋ฉด ๋ค์๊ธ์๋ฅผ ๊ทธ๋ฆฌ๊ธฐ ์ํด ์ฐ์ธก์ผ๋ก 8ํฝ์
์ด๋ํฉ๋๋ค.
Once a character is drawn, the position shifts 8 pixels to the right to draw the next character.
current_x += 8;
๐๏ธ ์ปดํ์ผ / Compiling
# 1. ๋ถํธ์นํฐ ๋ฐ ๋ณดํธ๋ชจ๋ ์ง์
๋ถ ์ปดํ์ผ
# Compiling the Boot Sector and Protected Mode Entry Code
nasm -f bin boot.asm -o boot.bin
nasm -f elf32 sector2.asm -o sector2.o
# 2. ์๋ก ์์ ํ kernel.c ์ปดํ์ผ
# Compiling the newly modified kernel.c
gcc -m32 -c kernel.c -o kernel.o -nostdlib -fno-builtin -fno-stack-protector -fno-pic -fno-PIE
# 3. ํ๋์ ๋ฐ์ด๋๋ฆฌ๋ก ๊ฒฐํฉ
# Combining into a single binary
ld -m elf_i386 -Ttext 0x8000 -e start -o sector2.bin sector2.o kernel.o --oformat binary
# 4. ์ด๋ฏธ์ง ์์ฑ ๋ฐ ์คํ
# Image Creation and Execution
cat boot.bin sector2.bin > temp.bin
dd if=temp.bin of=os.img bs=512 count=2880 conv=sync
qemu-system-x86_64 -drive file=os.img,format=raw,if=floppy -boot a
