0x04_My-OS實現自定義顏色

2023-02-21 21:01:45

前言:

0x03我們提到:

把12(紅色)用迴圈寫入視訊記憶體,每個畫素點怎麼顯示都要看對應的視訊記憶體地址,比如0xa0000到0xaffff就是每一個畫素點的視訊記憶體

你問為什麼12就是紅色,這些東西在主機板出廠的時候就是規定好的,就是有點呼叫主機板api的味道,這是我的猜測,具體為什麼還要你們來查

你會發現12是紅色,11就是另一種顏色,有沒有辦法可以自定義顏色呢

 

自定義顏色的原因是:

  顏色豐富度不夠,因此使用調色盤功能來增強顏色顯示,使用RGB模式,表示一個RGB顏色需要24位元數

修改class01名字為class02,把我給出的程式碼對原來的內容進行替換,當然你也可以找不同,如果你有這個耐心的話

程式碼:

naskfunc.asm

; naskfunc
; TAB=4

[FORMAT "WCOFF"]                ; 製作目標檔案的模式    
[INSTRSET "i486p"]                ; 使用到486為止的指令
[BITS 32]                        ; 3製作32位元模式用的機器語言
[FILE "naskfunc.asm"]            ; 檔名
    GLOBAL _io_hlt,_write_mem8,_io_cli,_io_sti,_io_get8,_io_set8,_io_stihlt
    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_get8:    ; int io_get8(int port);
        MOV        EDX,[ESP+4]        ; port
        MOV        EAX,0
        IN        AL,DX
        RET

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

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

_write_mem8: ; void write_mem8(int addr, int data);
        MOV ECX,[ESP+4] ; taking content of add
        MOV AL,[ESP+8] ; taking content of data
        MOV [ECX],AL ; *ecx=al
        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

 

這裡增加了一些函數,看不懂沒關係,我等下呼叫他們的時候講一下是幹嘛的

新建一個檔案graphic.c

#include "include/head.h"


void init_palette(void)
{
    static unsigned char table_rgb[18 * 3] = {
        0x24, 0x86, 0xb9,    /*  0:寶石藍(#2486b9) */
        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:暗紫 */
        0x33, 0x33, 0x33,    /* 14:淺暗藍 */
        0x84, 0x84, 0x84,    /* 15:暗灰 */
        0xD0, 0xD0, 0xD0,
        0x20, 0x20, 0x20
    };
    set_palette(0, 17, table_rgb);
    return;

    /* C語言中的static char語句只能用於資料,相當於組合中的DB指令 */
}

void set_palette(int start, int end, unsigned char *rgb)
{
    int i, eflags;
    eflags = io_load_eflags();    /* 記錄中斷許可標誌的值 */
    io_cli();                     /* 將中斷許可標誌置為0,禁止中斷 */
    io_set8(0x03c8, start);
    for (i = start; i <= end; i++) {
        io_set8(0x03c9, rgb[0] / 4);
        io_set8(0x03c9, rgb[1] / 4);
        io_set8(0x03c9, rgb[2] / 4);
        rgb += 3;
    }
    io_store_eflags(eflags);    /* 復原中斷許可標誌 */
    return;
}
void boxfill8(unsigned char *vram, int xsize, unsigned char c, int x0, int y0, int x1, int y1)
{
    int x, y;
    for (y = y0; y <= y1; y++) {
        for (x = x0; x <= x1; x++)
            vram[y * xsize + x] = c;
    }
    return;
}

前兩個函數是用來實現調色盤的,具體原理我解釋不了,Ctrl+CV大佬不需要知道原理,你懂我意思吧,裡面呼叫了很多asm裡的函數

第三個函數是繪製方塊的引數意思分別是:視訊記憶體地址,顯示寬度,顏色代號,從x0到x1,y0到y1進行繪製一個矩形

head.h

/*naskfunc.asm*/
void io_stihlt();
void io_hlt(void);
void io_cli(void);
void io_sti(void);
int io_get8(int port);
void io_set8(int port, int data);
void write_mem8(int addr, int data);
int io_load_eflags(void);
void io_store_eflags(int eflags);

/* asmhead.nas */
struct BOOTINFO { /* 0x0ff0-0x0fff */
    char cyls; /* 啟動區讀磁碟讀到此為止 */
    char leds; /* 啟動時鍵盤的LED的狀態 */
    char vmode; /* 顯示卡模式為多少位彩色 */
    char reserve;
    short scrnx, scrny; /* 畫面解析度 */
    char *vram;
};
#define ADR_BOOTINFO 0x00000ff0

/*graphic.c*/
void init_palette(void);
void set_palette(int start, int end, unsigned char *rgb);
void boxfill8(unsigned char *vram, int xsize, unsigned char c, int x0, int y0, int x1, int y1);

我們主要看第二個asmhead.asm的函數宣告,這個BOOTINFO結構體,是涵蓋了顯示器的資訊,資訊的位置在0x0ff0-0x0ffff

main.c

#include "include/head.h"

struct BOOTINFO *binfo = (struct BOOTINFO *) ADR_BOOTINFO;

void Main(void){
    int i;
    init_palette();
    boxfill8(binfo->vram, binfo->scrnx, 0,0,0,binfo->scrnx, binfo->scrny);
    for (;;) {
        io_hlt();
    }
}

第一句是獲取這個顯示器資訊的結構體,呼叫boxfill8填充整個螢幕,顏色代號是調色盤中的0號寶石藍

最後在make指令碼中增加graphic.obj

 執行:

cd class02
..\z_tools\make.exe run

自制作業系統合集
原文地址:https://www.cnblogs.com/Frank-dev-blog/category/2249116.html
專案github地址rick521/My-OS (github.com)給我點顆star