30天自制操作系統(tǒng)第11天harib08f

轉(zhuǎn)載CSDN:https://blog.csdn.net/zl18206208825/article/details/105597283

第11天 制作窗口

高速計數(shù)器

harib08f

準備材料(windows環(huán)境)
開始實驗
  1. 在tolset文件夾下創(chuàng)建子文件俠harib08f。

  2. 打開記事本,輸入以下代碼并另存為 !cons_nt.bat文件(windows 批處理),存放在harib08f文件夾中。

cmd.exe

ps:當然也可以直接使用 win + r 快捷鍵也可以,不過最好還是創(chuàng)建一個比較好。因為以后打開時不需要再麻煩了。

  1. 打開vc code,輸入以下代碼并保存為 naskfunc.nas,存放在harib08f文件夾中。
; naskfunc
; TAB=4

[FORMAT "WCOFF"]                ; 制作目標文件的模式
[INSTRSET "i486p"]              ; 要使用486指令的語句
[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
        GLOBAL  _load_gdtr, _load_idtr
        GLOBAL  _load_cr0, _store_cr0
        GLOBAL  _asm_inthandler21, _asm_inthandler27, _asm_inthandler2c
        GLOBAL  _memtest_sub
        EXTERN  _inthandler21, _inthandler27, _inthandler2c

[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

_load_gdtr:     ; void load_gdtr(int limit, int addr);
        MOV     AX,[ESP+4]      ; limit
        MOV     [ESP+6],AX
        LGDT    [ESP+6]
        RET

_load_idtr:     ; void load_idtr(int limit, int addr);
        MOV     AX,[ESP+4]      ; limit
        MOV     [ESP+6],AX
        LIDT    [ESP+6]
        RET

_load_cr0:      ; int load_cr0(void);
        MOV     EAX,CR0
        RET

_store_cr0:     ; void store_cr0(int cr0);
        MOV     EAX,[ESP+4]
        MOV     CR0,EAX
        RET

_asm_inthandler21:
        PUSH    ES
        PUSH    DS
        PUSHAD
        MOV     EAX,ESP
        PUSH    EAX
        MOV     AX,SS
        MOV     DS,AX
        MOV     ES,AX
        CALL    _inthandler21
        POP     EAX
        POPAD
        POP     DS
        POP     ES
        IRETD

_asm_inthandler27:
        PUSH    ES
        PUSH    DS
        PUSHAD
        MOV     EAX,ESP
        PUSH    EAX
        MOV     AX,SS
        MOV     DS,AX
        MOV     ES,AX
        CALL    _inthandler27
        POP     EAX
        POPAD
        POP     DS
        POP     ES
        IRETD

_asm_inthandler2c:
        PUSH    ES
        PUSH    DS
        PUSHAD
        MOV     EAX,ESP
        PUSH    EAX
        MOV     AX,SS
        MOV     DS,AX
        MOV     ES,AX
        CALL    _inthandler2c
        POP     EAX
        POPAD
        POP     DS
        POP     ES
        IRETD

_memtest_sub:   ; unsigned int memtest_sub(unsigned int start, unsigned int end)
        PUSH    EDI                     ; (由于還要使用EBX, ESI, EDI)
        PUSH    ESI
        PUSH    EBX
        MOV     ESI,0xaa55aa55          ; pat0 = 0xaa55aa55;
        MOV     EDI,0x55aa55aa          ; pat1 = 0x55aa55aa;
        MOV     EAX,[ESP+12+4]          ; i = start;
mts_loop:
        MOV     EBX,EAX
        ADD     EBX,0xffc               ; p = i + 0xffc;
        MOV     EDX,[EBX]               ; old = *p;
        MOV     [EBX],ESI               ; *p = pat0;
        XOR     DWORD [EBX],0xffffffff  ; *p ^= 0xffffffff;
        CMP     EDI,[EBX]               ; if (*p != pat1) goto fin;
        JNE     mts_fin
        XOR     DWORD [EBX],0xffffffff  ; *p ^= 0xffffffff;
        CMP     ESI,[EBX]               ; if (*p != pat0) goto fin;
        JNE     mts_fin
        MOV     [EBX],EDX               ; *p = old;
        ADD     EAX,0x1000              ; i += 0x1000;
        CMP     EAX,[ESP+12+8]          ; if (i <= end) goto mts_loop;
        JBE     mts_loop
        POP     EBX
        POP     ESI
        POP     EDI
        RET
mts_fin:
        MOV     [EBX],EDX               ; *p = old;
        POP     EBX
        POP     ESI
        POP     EDI
        RET

  1. 打開vc code,輸入以下代碼并保存為 bootpack.c 存放在harib08f文件夾中。
/* bootpack 其他處理 */

#include "bootpack.h"
#include <stdio.h>

void make_window8(unsigned char *buf, int xsize, int ysize, char *title);

void HariMain(void)
{
    struct BOOTINFO *binfo = (struct BOOTINFO *) ADR_BOOTINFO;
    char s[40], keybuf[32], mousebuf[128];
    int mx, my, i;
    unsigned int memtotal, count = 0;
    struct MOUSE_DEC mdec;
    struct MEMMAN *memman = (struct MEMMAN *) MEMMAN_ADDR;
    struct SHTCTL *shtctl;
    struct SHEET *sht_back, *sht_mouse, *sht_win;
    unsigned char *buf_back, buf_mouse[256], *buf_win;    

    init_gdtidt();
    init_pic();
    io_sti(); /* 由于IDT / PIC的初始化已完成,因此請禁用CPU的中斷。 */
    fifo8_init(&keyfifo, 32, keybuf);
    fifo8_init(&mousefifo, 128, mousebuf);
    io_out8(PIC0_IMR, 0xf9); /* 允許PIC1和鍵盤(11111001) */
    io_out8(PIC1_IMR, 0xef); /* 允許鼠標(11101111) */

    init_keyboard();
    enable_mouse(&mdec);
    memtotal = memtest(0x00400000, 0xbfffffff);
    memman_init(memman);
    memman_free(memman, 0x00001000, 0x0009e000); /* 0x00001000 - 0x0009efff */
    memman_free(memman, 0x00400000, memtotal - 0x00400000);

    init_palette();
    shtctl = shtctl_init(memman, binfo->vram, binfo->scrnx, binfo->scrny);
    sht_back  = sheet_alloc(shtctl);
    sht_mouse = sheet_alloc(shtctl);
    sht_win   = sheet_alloc(shtctl);
    buf_back  = (unsigned char *) memman_alloc_4k(memman, binfo->scrnx * binfo->scrny);
    buf_win   = (unsigned char *) memman_alloc_4k(memman, 160 * 52);
    sheet_setbuf(sht_back, buf_back, binfo->scrnx, binfo->scrny, -1); /* 沒有透明色 */
    sheet_setbuf(sht_mouse, buf_mouse, 16, 16, 99); /* 透明色號99 */
    sheet_setbuf(sht_win, buf_win, 160, 52, -1); /* 沒有透明色 這里 */
    init_screen8(buf_back, binfo->scrnx, binfo->scrny);
    init_mouse_cursor8(buf_mouse, 99); /* 背景色號99 */
    make_window8(buf_win, 160, 52, "counter");
    sheet_slide(sht_back, 0, 0);    
    mx = (binfo->scrnx - 16) / 2; /* 按顯示在畫面中央來計算坐標 */
    my = (binfo->scrny - 28 - 16) / 2;
    sheet_slide(sht_mouse, mx, my);
    sheet_slide(sht_win, 80, 72);
    sheet_updown(sht_back,  0);
    sheet_updown(sht_win,   1);
    sheet_updown(sht_mouse, 2);
    sprintf(s, "(%3d, %3d)", mx, my);
    putfonts8_asc(buf_back, binfo->scrnx, 0, 0, COL8_FFFFFF, s);
    sprintf(s, "memory %dMB   free : %dKB",
            memtotal / (1024 * 1024), memman_total(memman) / 1024);
    putfonts8_asc(buf_back, binfo->scrnx, 0, 32, COL8_FFFFFF, s);
    sheet_refresh(sht_back, 0, 0, binfo->scrnx, 48); /* 這里! */

    for (;;) {
        count++;
        sprintf(s, "%010d", count);
        boxfill8(buf_win, 160, COL8_C6C6C6, 40, 28, 119, 43);
        putfonts8_asc(buf_win, 160, 40, 28, COL8_000000, s);
        sheet_refresh(sht_win, 40, 28, 120, 44);

        io_cli();
        if (fifo8_status(&keyfifo) + fifo8_status(&mousefifo) == 0) {
            io_sti();
        } else {
            if (fifo8_status(&keyfifo) != 0) {
                i = fifo8_get(&keyfifo);
            io_sti();
            sprintf(s, "%02X", i);
            boxfill8(buf_back, binfo->scrnx, COL8_008484,  0, 16, 15, 31);
            putfonts8_asc(buf_back, binfo->scrnx, 0, 16, COL8_FFFFFF, s);
            sheet_refresh(sht_back, 0, 16, 16, 32);
            } else if (fifo8_status(&mousefifo) != 0) {
                i = fifo8_get(&mousefifo);
                io_sti();
                 if (mouse_decode(&mdec, i) != 0) {
                    /* 因為已得到3字節(jié)的數(shù)據(jù)所以顯示 */
                    sprintf(s, "[lcr %4d %4d]", mdec.x, mdec.y);
                    if ((mdec.btn & 0x01) != 0) {
                        s[1] = 'L';
                    }
                    if ((mdec.btn & 0x02) != 0) {
                        s[3] = 'R';
                    }
                    if ((mdec.btn & 0x04) != 0) {
                        s[2] = 'C';
                    }
                    boxfill8(buf_back, binfo->scrnx, COL8_008484, 32, 16, 32 + 15 * 8 - 1, 31);
                    putfonts8_asc(buf_back, binfo->scrnx, 32, 16, COL8_FFFFFF, s);
                    sheet_refresh(sht_back, 32, 16, 32 + 15 * 8, 32); /* 這里! */
                    /* 移動光標 */
                    mx += mdec.x;
                    my += mdec.y;
                    if (mx < 0) {
                        mx = 0;
                    }
                    if (my < 0) {
                        my = 0;
                    }
                    if (mx > binfo->scrnx - 1) {
                        mx = binfo->scrnx - 1;
                    }
                    if (my > binfo->scrny - 1) {
                        my = binfo->scrny - 1;
                    }
                    sprintf(s, "(%3d, %3d)", mx, my);
                    boxfill8(buf_back, binfo->scrnx, COL8_008484, 0, 0, 79, 15); /* 消去坐標 */
                    putfonts8_asc(buf_back, binfo->scrnx, 0, 0, COL8_FFFFFF, s); /* 寫出坐標 */
                    sheet_refresh(sht_back, 0, 0, 80, 16); /* 這里! */
                    sheet_slide(sht_mouse, mx, my);
                }
            }
        }
    }
}

void make_window8(unsigned char *buf, int xsize, int ysize, char *title)
{
    static char closebtn[14][16] = {
        "OOOOOOOOOOOOOOO@",
        "OQQQQQQQQQQQQQ$@",
        "OQQQQQQQQQQQQQ$@",
        "OQQQ@@QQQQ@@QQ$@",
        "OQQQQ@@QQ@@QQQ$@",
        "OQQQQQ@@@@QQQQ$@",
        "OQQQQQQ@@QQQQQ$@",
        "OQQQQQ@@@@QQQQ$@",
        "OQQQQ@@QQ@@QQQ$@",
        "OQQQ@@QQQQ@@QQ$@",
        "OQQQQQQQQQQQQQ$@",
        "OQQQQQQQQQQQQQ$@",
        "O$$$$$$$$$$$$$$@",
        "@@@@@@@@@@@@@@@@"
    };
    int x, y;
    char c;
    boxfill8(buf, xsize, COL8_C6C6C6, 0,         0,         xsize - 1, 0        );
    boxfill8(buf, xsize, COL8_FFFFFF, 1,         1,         xsize - 2, 1        );
    boxfill8(buf, xsize, COL8_C6C6C6, 0,         0,         0,         ysize - 1);
    boxfill8(buf, xsize, COL8_FFFFFF, 1,         1,         1,         ysize - 2);
    boxfill8(buf, xsize, COL8_848484, xsize - 2, 1,         xsize - 2, ysize - 2);
    boxfill8(buf, xsize, COL8_000000, xsize - 1, 0,         xsize - 1, ysize - 1);
    boxfill8(buf, xsize, COL8_C6C6C6, 2,         2,         xsize - 3, ysize - 3);
    boxfill8(buf, xsize, COL8_000084, 3,         3,         xsize - 4, 20       );
    boxfill8(buf, xsize, COL8_848484, 1,         ysize - 2, xsize - 2, ysize - 2);
    boxfill8(buf, xsize, COL8_000000, 0,         ysize - 1, xsize - 1, ysize - 1);
    putfonts8_asc(buf, xsize, 24, 4, COL8_FFFFFF, title);
    for (y = 0; y < 14; y++) {
        for (x = 0; x < 16; x++) {
            c = closebtn[y][x];
            if (c == '@') {
                c = COL8_000000;
            } else if (c == '$') {
                c = COL8_848484;
            } else if (c == 'Q') {
                c = COL8_C6C6C6;
            } else {
                c = COL8_FFFFFF;
            }
            buf[(5 + y) * xsize + (xsize - 21 + x)] = c;
        }
    }
    return;
}

  1. 打開vc code,輸入以下代碼并保存為 bootpack.h 存放在harib08f文件夾中。
/* asmhead.nas */
struct BOOTINFO { /* 0xff0-0x0fff */
    char cyls; /* 啟動區(qū)讀硬盤讀到何處為止 */
    char leds; /* 啟動時鍵盤LED的狀態(tài) */
    char vmode; /* 顯卡模式為多少位彩色 */
    char reserve;
    short scrnx, scrny; /* 畫面分辨率 */
    char *vram;
};
#define ADR_BOOTINFO    0x00000ff0

/* naskfunc.nas */
void io_hlt(void);
void io_cli(void);
void io_sti(void);
void io_stihlt(void);
int io_in8(int port);
void io_out8(int port, int data);
int io_load_eflags(void);
void io_store_eflags(int eflags);
void load_gdtr(int limit, int addr);
void load_idtr(int limit, int addr);
int load_cr0(void);
void store_cr0(int cr0);
void asm_inthandler21(void);
void asm_inthandler27(void);
void asm_inthandler2c(void);
unsigned int memtest_sub(unsigned int start, unsigned int end);

/* fifo.c */
struct FIFO8 {
    unsigned char *buf;
    int p, q, size, free, flags;
};
void fifo8_init(struct FIFO8 *fifo, int size, unsigned char *buf);
int fifo8_put(struct FIFO8 *fifo, unsigned char data);
int fifo8_get(struct FIFO8 *fifo);
int fifo8_status(struct FIFO8 *fifo);

/* 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);
void init_screen8(char *vram, int x, int y);
void putfont8(char *vram, int xsize, int x, int y, char c, char *font);
void putfonts8_asc(char *vram, int xsize, int x, int y, char c, unsigned char *s);
void init_mouse_cursor8(char *mouse, char bc);
void putblock8_8(char *vram, int vxsize, int pxsize,
    int pysize, int px0, int py0, char *buf, int bxsize);
#define COL8_000000     0
#define COL8_FF0000     1
#define COL8_00FF00     2
#define COL8_FFFF00     3
#define COL8_0000FF     4
#define COL8_FF00FF     5
#define COL8_00FFFF     6
#define COL8_FFFFFF     7
#define COL8_C6C6C6     8
#define COL8_840000     9
#define COL8_008400     10
#define COL8_848400     11
#define COL8_000084     12
#define COL8_840084     13
#define COL8_008484     14
#define COL8_848484     15

/* dsctbl.c */
struct SEGMENT_DESCRIPTOR {
    short limit_low, base_low;
    char base_mid, access_right;
    char limit_high, base_high;
};
struct GATE_DESCRIPTOR {
    short offset_low, selector;
    char dw_count, access_right;
    short offset_high;
};
void init_gdtidt(void);
void set_segmdesc(struct SEGMENT_DESCRIPTOR *sd, unsigned int limit, int base, int ar);
void set_gatedesc(struct GATE_DESCRIPTOR *gd, int offset, int selector, int ar);
#define ADR_IDT         0x0026f800
#define LIMIT_IDT       0x000007ff
#define ADR_GDT         0x00270000
#define LIMIT_GDT       0x0000ffff
#define ADR_BOTPAK      0x00280000
#define LIMIT_BOTPAK    0x0007ffff
#define AR_DATA32_RW    0x4092
#define AR_CODE32_ER    0x409a
#define AR_INTGATE32    0x008e

/* int.c */
void init_pic(void);
void inthandler27(int *esp);
#define PIC0_ICW1       0x0020
#define PIC0_OCW2       0x0020
#define PIC0_IMR        0x0021
#define PIC0_ICW2       0x0021
#define PIC0_ICW3       0x0021
#define PIC0_ICW4       0x0021
#define PIC1_ICW1       0x00a0
#define PIC1_OCW2       0x00a0
#define PIC1_IMR        0x00a1
#define PIC1_ICW2       0x00a1
#define PIC1_ICW3       0x00a1
#define PIC1_ICW4       0x00a1

/* keyboard.c */
void inthandler21(int *esp);
void wait_KBC_sendready(void);
void init_keyboard(void);
extern struct FIFO8 keyfifo;
#define PORT_KEYDAT     0x0060
#define PORT_KEYCMD     0x0064

/* mouse.c */
struct MOUSE_DEC {
    unsigned char buf[3], phase;
    int x, y, btn;
};
void inthandler2c(int *esp);
void enable_mouse(struct MOUSE_DEC *mdec);
int mouse_decode(struct MOUSE_DEC *mdec, unsigned char dat);
extern struct FIFO8 mousefifo;

/* memory.c */
#define MEMMAN_FREES        4090    /* 大約是32KB */
#define MEMMAN_ADDR         0x003c0000
struct FREEINFO {   /* 可用信息 */
    unsigned int addr, size;
};
struct MEMMAN {     /* 內(nèi)存管理 */
    int frees, maxfrees, lostsize, losts;
    struct FREEINFO free[MEMMAN_FREES];
};
unsigned int memtest(unsigned int start, unsigned int end);
void memman_init(struct MEMMAN *man);
unsigned int memman_total(struct MEMMAN *man);
unsigned int memman_alloc(struct MEMMAN *man, unsigned int size);
int memman_free(struct MEMMAN *man, unsigned int addr, unsigned int size);
unsigned int memman_alloc_4k(struct MEMMAN *man, unsigned int size);
int memman_free_4k(struct MEMMAN *man, unsigned int addr, unsigned int size);

/* sheet.c */
#define MAX_SHEETS      256
struct SHEET {
    unsigned char *buf;
    int bxsize, bysize, vx0, vy0, col_inv, height, flags;
    struct SHTCTL *ctl;
};
struct SHTCTL {
    unsigned char *vram;
    int xsize, ysize, top;
    struct SHEET *sheets[MAX_SHEETS];
    struct SHEET sheets0[MAX_SHEETS];
};
struct SHTCTL *shtctl_init(struct MEMMAN *memman, unsigned char *vram, int xsize, int ysize);
struct SHEET *sheet_alloc(struct SHTCTL *ctl);
void sheet_setbuf(struct SHEET *sht, unsigned char *buf, int xsize, int ysize, int col_inv);
void sheet_updown(struct SHEET *sht, int height);
void sheet_refresh(struct SHEET *sht, int bx0, int by0, int bx1, int by1);
void sheet_slide(struct SHEET *sht, int vx0, int vy0);
void sheet_free(struct SHEET *sht);

  1. 打開vc code,輸入以下代碼并保存為 dsctbl.c 存放在harib08f文件夾中。
/* 關(guān)于GDT,IDT等descriptor table的處理 */

#include "bootpack.h"

void init_gdtidt(void)
{
    struct SEGMENT_DESCRIPTOR *gdt = (struct SEGMENT_DESCRIPTOR *) ADR_GDT;
    struct GATE_DESCRIPTOR    *idt = (struct GATE_DESCRIPTOR    *) ADR_IDT;
    int i;

    /* GDT的初始化 */
    for (i = 0; i <= LIMIT_GDT / 8; i++) {
        set_segmdesc(gdt + i, 0, 0, 0);
    }
    set_segmdesc(gdt + 1, 0xffffffff,   0x00000000, AR_DATA32_RW);
    set_segmdesc(gdt + 2, LIMIT_BOTPAK, ADR_BOTPAK, AR_CODE32_ER);
    load_gdtr(LIMIT_GDT, ADR_GDT);
    
    /* IDT的初始化 */
    for (i = 0; i <= LIMIT_IDT / 8; i++) {
        set_gatedesc(idt + i, 0, 0, 0);
    }
    load_idtr(LIMIT_IDT, ADR_IDT);

    /* IDT的設(shè)定 */
    set_gatedesc(idt + 0x21, (int) asm_inthandler21, 2 * 8, AR_INTGATE32);
    set_gatedesc(idt + 0x27, (int) asm_inthandler27, 2 * 8, AR_INTGATE32);
    set_gatedesc(idt + 0x2c, (int) asm_inthandler2c, 2 * 8, AR_INTGATE32);

    return;
}

void set_segmdesc(struct SEGMENT_DESCRIPTOR *sd, unsigned int limit, int base, int ar)
{
    if (limit > 0xfffff) {
        ar |= 0x8000; /* G_bit = 1 */
        limit /= 0x1000;
    }
    sd->limit_low    = limit & 0xffff;
    sd->base_low     = base & 0xffff;
    sd->base_mid     = (base >> 16) & 0xff;
    sd->access_right = ar & 0xff;
    sd->limit_high   = ((limit >> 16) & 0x0f) | ((ar >> 8) & 0xf0);
    sd->base_high    = (base >> 24) & 0xff;
    return;
}

void set_gatedesc(struct GATE_DESCRIPTOR *gd, int offset, int selector, int ar)
{
    gd->offset_low   = offset & 0xffff;
    gd->selector     = selector;
    gd->dw_count     = (ar >> 8) & 0xff;
    gd->access_right = ar & 0xff;
    gd->offset_high  = (offset >> 16) & 0xffff;
    return;
}

ps: 。

  1. 打vc code,輸入以下代碼并保存為 fifo.c,存放在harib08f文件夾中。
/* FIFO庫 */

#include "bootpack.h"

#define FLAGS_OVERRUN       0x0001

void fifo8_init(struct FIFO8 *fifo, int size, unsigned char *buf)
/* 初始化 FIFO 緩沖區(qū) */
{
    fifo->size = size;
    fifo->buf = buf;
    fifo->free = size; /* 緩沖區(qū)的大小 */
    fifo->flags = 0;
    fifo->p = 0;    /* 下一個數(shù)據(jù)寫入位置 */
    fifo->q = 0;    /* 下一個數(shù)據(jù)讀出位置 */
    return;
}

int fifo8_put(struct FIFO8 *fifo, unsigned char data)
/* 向 FIFO 傳送數(shù)據(jù)并保存 */
{
    if (fifo->free == 0) {
        /* 空余沒有了,溢出 */
        fifo->flags |= FLAGS_OVERRUN;
        return -1;
    }
    fifo->buf[fifo->p] = data;
    fifo->p++;
    if (fifo->p == fifo->size) {
        fifo->p = 0;
    }
    fifo->free--;
    return 0;
}

int fifo8_get(struct FIFO8 *fifo)
/* 從 FIFO 取得一個數(shù)據(jù) */
{
    int data;
    if (fifo->free == fifo->size) {
        /* 如果緩沖區(qū)為空,則返回-1 */
        return -1;
    }
    data = fifo->buf[fifo->q];
    fifo->q++;
    if (fifo->q == fifo->size) {
        fifo->q = 0;
    }
    fifo->free++;
    return data;
}

int fifo8_status(struct FIFO8 *fifo)
/* 報告一下到底積攢了多少數(shù)據(jù) */
{
    return fifo->size - fifo->free;
}

  1. 打vc code,輸入以下代碼并保存為 graphic.c,存放在harib08f文件夾中。
/* u關(guān)于描畫的處理 */

#include "bootpack.h"

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, 0x00, 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;

    /* C語言中的static char語句只能用于數(shù)據(jù), 相當于匯編中的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);    /*  復(fù)原中斷許可標志 */
    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;
}

void init_screen8(char *vram, int x, int y)
{
    boxfill8(vram, x, COL8_008484,  0,     0,      x -  1, y - 29);
    boxfill8(vram, x, COL8_C6C6C6,  0,     y - 28, x -  1, y - 28);
    boxfill8(vram, x, COL8_FFFFFF,  0,     y - 27, x -  1, y - 27);
    boxfill8(vram, x, COL8_C6C6C6,  0,     y - 26, x -  1, y -  1);

    boxfill8(vram, x, COL8_FFFFFF,  3,     y - 24, 59,     y - 24);
    boxfill8(vram, x, COL8_FFFFFF,  2,     y - 24,  2,     y -  4);
    boxfill8(vram, x, COL8_848484,  3,     y -  4, 59,     y -  4);
    boxfill8(vram, x, COL8_848484, 59,     y - 23, 59,     y -  5);
    boxfill8(vram, x, COL8_000000,  2,     y -  3, 59,     y -  3);
    boxfill8(vram, x, COL8_000000, 60,     y - 24, 60,     y -  3);

    boxfill8(vram, x, COL8_848484, x - 47, y - 24, x -  4, y - 24);
    boxfill8(vram, x, COL8_848484, x - 47, y - 23, x - 47, y -  4);
    boxfill8(vram, x, COL8_FFFFFF, x - 47, y -  3, x -  4, y -  3);
    boxfill8(vram, x, COL8_FFFFFF, x -  3, y - 24, x -  3, y -  3);
    return;
}

void putfont8(char *vram, int xsize, int x, int y, char c, char *font)
{
    int i;
    char *p, d; /* date */
    for (i = 0; i < 16; i++) {
        p = vram + (y + i) * xsize + x;
        d = font[i];
        if ((d & 0x80) != 0) { p[0] = c; }
        if ((d & 0x40) != 0) { p[1] = c; }
        if ((d & 0x20) != 0) { p[2] = c; }
        if ((d & 0x10) != 0) { p[3] = c; }
        if ((d & 0x08) != 0) { p[4] = c; }
        if ((d & 0x04) != 0) { p[5] = c; }
        if ((d & 0x02) != 0) { p[6] = c; }
        if ((d & 0x01) != 0) { p[7] = c; }
    }
    return;
}

void putfonts8_asc(char *vram, int xsize, int x, int y, char c, unsigned char *s)
{
    extern char hankaku[4096];
    for (; *s != 0x00; s++) {
    putfont8(vram, xsize, x, y, c, hankaku + *s * 16);
    x += 8;
    }
    return;
}

void init_mouse_cursor8(char *mouse, char bc)
/* 準備鼠標指標 (16 x 16) */
{
    static char cursor[16][16] = {
        "**************..",
        "*OOOOOOOOOOO*...",
        "*OOOOOOOOOO*....",
        "*OOOOOOOOO*.....",
        "*OOOOOOOO*......",
        "*OOOOOOO*.......",
        "*OOOOOOO*.......",
        "*OOOOOOOO*......",
        "*OOOO**OOO*.....",
        "*OOO*..*OOO*....",
        "*OO*....*OOO*...",
        "*O*......*OOO*..",
        "**........*OOO*.",
        "*..........*OOO*",
        "............*OO*",
        ".............***"
    };
    int x, y;

    for (y = 0; y < 16; y++) {
        for (x = 0; x < 16; x++) {
            if (cursor[y][x] == '*') {
                mouse[y * 16 + x] = COL8_000000;
            }
            if (cursor[y][x] == 'O') {
                mouse[y * 16 + x] = COL8_FFFFFF;
            }
            if (cursor[y][x] == '.') {
                mouse[y * 16 + x] = bc;
            }
        }
    }
    return;
}

void putblock8_8(char *vram, int vxsize, int pxsize,
    int pysize, int px0, int py0, char *buf, int bxsize)
{
    int x, y;
    for (y = 0; y < pysize; y++) {
        for (x = 0; x < pxsize; x++) {
            vram[(py0 + y) * vxsize + (px0 + x)] = buf[y * bxsize + x];
        }
    }
    return;
}

  1. 打vc code,輸入以下代碼并保存為 int.c,存放在harib08f文件夾中。
/* 與中斷有關(guān) */

#include "bootpack.h"
#include <stdio.h>

void init_pic(void)
/* PIC的初始化 */
{
    io_out8(PIC0_IMR,  0xff  ); /* 禁止所有中斷 */
    io_out8(PIC1_IMR,  0xff  ); /* 禁止所有中斷 */
    
    io_out8(PIC0_ICW1, 0x11  ); /* 邊沿觸發(fā)模式 (edge trigger mode) */
    io_out8(PIC0_ICW2, 0x20  ); /* IRQ0-7 由 INT20-27 接收 */
    io_out8(PIC0_ICW3, 1 << 2); /* PIC1 由 IRQ2 連接 */
    io_out8(PIC0_ICW4, 0x01  ); /* 無緩沖區(qū)模式 */

    io_out8(PIC1_ICW1, 0x11  ); /* 邊沿觸發(fā)模式 (edge trigger mode) */
    io_out8(PIC1_ICW2, 0x28  ); /* IRQ8-15 由 INT28-2f 接收 */
    io_out8(PIC1_ICW3, 2     ); /* PIC1 由 IRQ2 連接 */
    io_out8(PIC1_ICW4, 0x01  ); /* 無緩沖區(qū)域 */

    io_out8(PIC0_IMR,  0xfb  ); /* 11111011 PIC1 以外全部禁止 */
    io_out8(PIC1_IMR,  0xff  ); /* 11111111 禁止所有中斷 */

    return;
}

void inthandler27(int *esp)
/* 防止來自PIC0的不完整中斷的措施 */
/* 在Athlon64X2機器等中,由于芯片組的便利性,該中斷在PIC初始化時僅發(fā)生一次 */
/* 此中斷處理功能不執(zhí)行中斷 */
/* 您為什么不做任何事情? */
/* 由于此中斷是由PIC初始化期間的電氣噪聲產(chǎn)生的,*/
/* 您不需要認真做任何事情。 */
{
    io_out8(PIC0_OCW2, 0x67); /* 通知PIC IRQ-07已被接受(見7-1)*/
    return;
}

  1. 打vc code,輸入以下代碼并保存為 keyboard.c,存放在harib08f文件夾中。
/* 與鍵盤相關(guān) */

#include "bootpack.h"

struct FIFO8 keyfifo;

void inthandler21(int *esp)
{
    unsigned char data;
    io_out8(PIC0_OCW2, 0x61);   /* 通知PIC“IRQ-01”已經(jīng)受理完畢 */
    data = io_in8(PORT_KEYDAT);
    fifo8_put(&keyfifo, data);
    return;
}

#define PORT_KEYSTA             0x0064
#define KEYSTA_SEND_NOTREADY    0x02
#define KEYCMD_WRITE_MODE       0x60
#define KBC_MODE                0x47

void wait_KBC_sendready(void)
{
    /* 等待鍵盤控制電路準備完畢  */
    for (;;) {
        if ((io_in8(PORT_KEYSTA) & KEYSTA_SEND_NOTREADY) == 0) {
            break;
        }
    }
    return;
}

void init_keyboard(void)
{
    /* 初始化鍵盤控制電路 */
    wait_KBC_sendready();
    io_out8(PORT_KEYCMD, KEYCMD_WRITE_MODE);
    wait_KBC_sendready();
    io_out8(PORT_KEYDAT, KBC_MODE);
    return;
}

  1. 打vc code,輸入以下代碼并保存為 memory.c,存放在harib08f文件夾中。
/* 內(nèi)存管理 */

#include "bootpack.h"

#define EFLAGS_AC_BIT       0x00040000
#define CR0_CACHE_DISABLE   0x60000000

unsigned int memtest(unsigned int start, unsigned int end)
{
    char flg486 = 0;
    unsigned int eflg, cr0, i;

    /* 確認CPU是386還是486以上的 */
    eflg = io_load_eflags();
    eflg |= EFLAGS_AC_BIT; /* AC-bit = 1 */
    io_store_eflags(eflg);
    eflg = io_load_eflags();
    if ((eflg & EFLAGS_AC_BIT) != 0) { /* 如果是386,即使設(shè)定AC=1,AC的值還會自動回到0 */
        flg486 = 1;
    }
    eflg &= ~EFLAGS_AC_BIT; /* AC-bit = 0 */
    io_store_eflags(eflg);

    if (flg486 != 0) {
        cr0 = load_cr0();
        cr0 |= CR0_CACHE_DISABLE; /* 禁止緩存 */
        store_cr0(cr0);
    }

    i = memtest_sub(start, end);

    if (flg486 != 0) {
        cr0 = load_cr0();
        cr0 &= ~CR0_CACHE_DISABLE; /* 允許緩存 */
        store_cr0(cr0);
    }

    return i;
}

void memman_init(struct MEMMAN *man)
{
    man->frees = 0;         /* 可用信息數(shù)目 */
    man->maxfrees = 0;      /* 用于觀察可用狀況:frees的最大值 */
    man->lostsize = 0;      /* 釋放失敗的內(nèi)在的大小總和 */
    man->losts = 0;         /* 釋放失敗次數(shù) */
    return;
}

unsigned int memman_total(struct MEMMAN *man)
/* 報告空余內(nèi)存大小的命令 */
{
    unsigned int i, t = 0;
    for (i = 0; i < man->frees; i++) {
        t += man->free[i].size;
    }
    return t;
}

unsigned int memman_alloc(struct MEMMAN *man, unsigned int size)
/* 分配 */
{
    unsigned int i, a;
    for (i = 0; i < man->frees; i++) {
        if (man->free[i].size >= size) {
            /* 找到了足夠大的內(nèi)存 */
            a = man->free[i].addr;
            man->free[i].addr += size;
            man->free[i].size -= size;
            if (man->free[i].size == 0) {
                /* 如果free[i]變成了0,就減掉一條可用信息 */
                man->frees--;
                for (; i < man->frees; i++) {
                    man->free[i] = man->free[i + 1]; /* 代入結(jié)構(gòu)體 */
                }
            }   
            return a;
        }
    }
    return 0; /* 沒有可用空間 */
}

int memman_free(struct MEMMAN *man, unsigned int addr, unsigned int size)
/* 釋放 */
{
    int i, j;
    /* 為便于歸納內(nèi)存,將free[]放按照addr的順序排列 */
    /* 所以,先決定應(yīng)該放在哪里 */
    for (i = 0; i < man->frees; i++) {
        if (man->free[i].addr > addr) {
            break;
        }
    }
    /* free[i - 1].addr < addr < free[i].addr */
    if (i > 0) {
        /* 前面有可用內(nèi)在 */
        if (man->free[i - 1].addr + man->free[i - 1].size == addr) {
            /* 可以與前面的可用內(nèi)存歸納到一起 */
            man->free[i - 1].size += size;
            if (i < man->frees) {
                /* 后面也有 */
                if (addr + size == man->free[i].addr) {
                    /* 也可以與后面的可用內(nèi)存歸納到一起 */
                    man->free[i - 1].size += man->free[i].size;
                    /* man-free[i]刪除 */
                    /* free[i]變成0后歸納到前面去 */
                    man->frees--;
                    for (; i < man->frees; i++) {
                        man->free[i] = man->free[i + 1]; /* 結(jié)構(gòu)體賦值 */
                    }
                }
            }
            return 0; /* 成功完成 */
        }
    }
    /* 不能與前面的可用空間歸納到一起 */
    if (i < man->frees) {
        /* 后面還有 */
        if (addr + size == man->free[i].addr) {
            /* 可以與后面的內(nèi)容歸納到一起 */
            man->free[i].addr = addr;
            man->free[i].size += size;
            return 0; /* 成功完成 */
        }
    }
    /* 既不能與前面歸納到一起,也不能與后面歸納到一起 */
    if (man->frees < MEMMAN_FREES) {
        /* free[i]之后的,向后移動,騰出一點可用空間 */
        for (j = man->frees; j > i; j--) {
            man->free[j] = man->free[j - 1];
        }
        man->frees++;
        if (man->maxfrees < man->frees) {
            man->maxfrees = man->frees; /* 更新最大值 */
        }
        man->free[i].addr = addr;
        man->free[i].size = size;
        return 0; /* 成功完成 */
    }
    /* 不能往后移動 */
    man->losts++;
    man->lostsize += size;
    return -1; /* 失敗 */
}

unsigned int memman_alloc_4k(struct MEMMAN *man, unsigned int size)
{
    unsigned int a;
    size = (size + 0xfff) & 0xfffff000;
    a = memman_alloc(man, size);
    return a;
}

int memman_free_4k(struct MEMMAN *man, unsigned int addr, unsigned int size)
{
    int i;
    size = (size + 0xfff) & 0xfffff000;
    i = memman_free(man, addr, size);
    return i;
}

  1. 打vc code,輸入以下代碼并保存為 mouse.c,存放在harib08f文件夾中。
/* 與鼠標相關(guān) */

#include "bootpack.h"

struct FIFO8 mousefifo;

void inthandler2c(int *esp)
/* 來自PS/2鍵盤的中斷 */
{
    unsigned char data;
    io_out8(PIC1_OCW2, 0x64);   /* 通知PIC1 IRQ-12的受理已經(jīng)完成 */
    io_out8(PIC0_OCW2, 0x62);   /* 通知PIC0 IRQ-02的受理已經(jīng)完成 */
    data = io_in8(PORT_KEYDAT);
    fifo8_put(&mousefifo, data);
    return;
}

#define KEYCMD_SENDTO_MOUSE     0xd4
#define MOUSECMD_ENABLE         0xf4

void enable_mouse(struct MOUSE_DEC *mdec)
{
    /* 激活鼠標 */
    wait_KBC_sendready();
    io_out8(PORT_KEYCMD, KEYCMD_SENDTO_MOUSE);
    wait_KBC_sendready();
    io_out8(PORT_KEYDAT, MOUSECMD_ENABLE);
    /* 順利的話,ACK(0xfa)會被傳送過來 */
    mdec->phase = 0;    /* 等待0xfa的階段 */
    return;
}

int mouse_decode(struct MOUSE_DEC *mdec, unsigned char dat)
{
    if (mdec->phase == 0) {
        /* 等待鼠標的0xfa的階段 */
        if (dat == 0xfa) {
            mdec->phase = 1;
        }
        return 0;
    }
    if (mdec->phase == 1) {
        /* 等待鼠標第一字節(jié)的階段 */
        if ((dat & 0xc8) == 0x08) {
            /* 如果第一字節(jié)正確 */
            mdec->buf[0] = dat;
            mdec->phase = 2;
        }
        return 0;
    }
    if (mdec->phase == 2) {
        /* 等待鼠標第二字節(jié)的階段 */
        mdec->buf[1] = dat;
        mdec->phase = 3;
        return 0;
    }
    if (mdec->phase == 3) {
        /* 等待鼠標第三字節(jié)的階段 */
        mdec->buf[2] = dat;
        mdec->phase = 1;
        mdec->btn = mdec->buf[0] & 0x07;
        mdec->x = mdec->buf[1];
        mdec->y = mdec->buf[2];
        if ((mdec->buf[0] & 0x10) != 0) {
            mdec->x |= 0xffffff00;
        }
        if ((mdec->buf[0] & 0x20) != 0) {
            mdec->y |= 0xffffff00;
        }
        mdec->y = - mdec->y; /* 鼠標y方向與畫面符號相反 */
        return 1;
    }
    return -1; /* 應(yīng)該不可能到這里來 */
}

  1. 打vc code,輸入以下代碼并保存為 sheet.c,存放在harib08f文件夾中。
/* 畫面疊加處理 */

#include "bootpack.h"

#define SHEET_USE       1

struct SHTCTL *shtctl_init(struct MEMMAN *memman, unsigned char *vram, int xsize, int ysize)
{
    struct SHTCTL *ctl;
    int i;
    ctl = (struct SHTCTL *) memman_alloc_4k(memman, sizeof (struct SHTCTL));
    if (ctl == 0) {
        goto err;
    }
    ctl->vram = vram;
    ctl->xsize = xsize;
    ctl->ysize = ysize;
    ctl->top = -1; /* 一個SHEET都沒有 */
    for (i = 0; i < MAX_SHEETS; i++) {
        ctl->sheets0[i].flags = 0; /* 標記為未使用 */
        ctl->sheets0[i].ctl = ctl; /* 記錄所屬  這里 */
    }
err:
    return ctl;
}

struct SHEET *sheet_alloc(struct SHTCTL *ctl)
{
    struct SHEET *sht;
    int i;
    for (i = 0; i < MAX_SHEETS; i++) {
        if (ctl->sheets0[i].flags == 0) {
            sht = &ctl->sheets0[i];
            sht->flags = SHEET_USE; /* 標記為正在使用 */
            sht->height = -1; /* 隱藏 */
            return sht;
        }
    }
    return 0;   /* 所有的SHEET都處于正在使用狀態(tài) */
}

void sheet_setbuf(struct SHEET *sht, unsigned char *buf, int xsize, int ysize, int col_inv)
{
    sht->buf = buf;
    sht->bxsize = xsize;
    sht->bysize = ysize;
    sht->col_inv = col_inv;
    return;
}

void sheet_refreshsub(struct SHTCTL *ctl, int vx0, int vy0, int vx1, int vy1)
{
    int h, bx, by, vx, vy, bx0, by0, bx1, by1;
    unsigned char *buf, c, *vram = ctl->vram;
    struct SHEET *sht;
    /* 如果refresh的范圍走出了畫面則修正 */
    if (vx0 < 0) { vx0 = 0; }
    if (vy0 < 0) { vy0 = 0; }
    if (vx1 > ctl->xsize) { vx1 = ctl->xsize; }
    if (vy1 > ctl->ysize) { vy1 = ctl->ysize; }
    for (h = 0; h <= ctl->top; h++) {
        sht = ctl->sheets[h];
        buf = sht->buf;
        /* 使用vx0~vy1,對bx0~by1進行轉(zhuǎn)換 */
        bx0 = vx0 - sht->vx0;
        by0 = vy0 - sht->vy0;
        bx1 = vx1 - sht->vx0;
        by1 = vy1 - sht->vy0;
        if (bx0 < 0) { bx0 = 0; }
        if (by0 < 0) { by0 = 0; }
        if (bx1 > sht->bxsize) { bx1 = sht->bxsize; }
        if (by1 > sht->bysize) { by1 = sht->bysize; }
        for (by = by0; by < by1; by++) {
            vy = sht->vy0 + by;
            for (bx = bx0; bx < bx1; bx++) {
                vx = sht->vx0 + bx;
                c = buf[by * sht->bxsize + bx];
                if (c != sht->col_inv) {
                    vram[vy * ctl->xsize + vx] = c;
                }
            }
        }
    }
    return;
}

void sheet_updown(struct SHEET *sht, int height)
{
    struct SHTCTL *ctl = sht->ctl;
    int h, old = sht->height; /* 將設(shè)置前的高度記錄下來 */

    /* 如果指定的高度過高或過低,則進行修正 */
    if (height > ctl->top + 1) {
        height = ctl->top + 1;
    }
    if (height < -1) {
        height = -1;
    }
    sht->height = height; /* 設(shè)定高度 */

    /* 下面主要是進行sheets[]的重新排列 */
    if (old > height) { /* 比以前低 */
        if (height >= 0) {
            /* 把中間的往上提 */
            for (h = old; h > height; h--) {
                ctl->sheets[h] = ctl->sheets[h - 1];
                ctl->sheets[h]->height = h;
            }
            ctl->sheets[height] = sht;
        } else {    /* 隱藏 */
            if (ctl->top > old) {
                /* 把上面的降下來 */
                for (h = old; h < ctl->top; h++) {
                    ctl->sheets[h] = ctl->sheets[h + 1];
                    ctl->sheets[h]->height = h;
                }
            }
            ctl->top--; /* 由于顯示中的圖層減少了一個,所以最上面的圖層高度下降 */
        }
        sheet_refreshsub(ctl, sht->vx0, sht->vy0, sht->vx0 + sht->bxsize, sht->vy0 + sht->bysize);
    } else if (old < height) {  /* 比以前高 */
        if (old >= 0) {
            /* 把中間的拉下來 */
            for (h = old; h < height; h++) {
                ctl->sheets[h] = ctl->sheets[h + 1];
                ctl->sheets[h]->height = h;
            }
            ctl->sheets[height] = sht;
        } else {    /* 由隱藏狀態(tài)轉(zhuǎn)為顯示狀態(tài) */
            /* 獎已在上面的提上來 */
            for (h = ctl->top; h >= height; h--) {
                ctl->sheets[h + 1] = ctl->sheets[h];
                ctl->sheets[h + 1]->height = h + 1;
        }
        ctl->sheets[height] = sht;
        ctl->top++; /* 由于已顯示的圖層增加了1個,所以最上面的圖層高度增加 */
        }
        sheet_refreshsub(ctl, sht->vx0, sht->vy0, sht->vx0 + sht->bxsize, sht->vy0 + sht->bysize);
    }
    return;
}

void sheet_refresh(struct SHEET *sht, int bx0, int by0, int bx1, int by1)
{
    if (sht->height >= 0) { /* 如果正在顯示, 則按新圖層的信息刷新畫面 */
        sheet_refreshsub(sht->ctl, sht->vx0 + bx0, sht->vy0 + by0, sht->vx0 + bx1, sht->vy0 + by1);
    }
    return;
}

void sheet_slide(struct SHEET *sht, int vx0, int vy0)
{
    int old_vx0 = sht->vx0, old_vy0 = sht->vy0;
    sht->vx0 = vx0;
    sht->vy0 = vy0;
    if (sht->height >= 0) { /* 如果正在顯示, 則按新圖層的信息刷新畫面 */
        sheet_refreshsub(sht->ctl, old_vx0, old_vy0, old_vx0 + sht->bxsize, old_vy0 + sht->bysize);
        sheet_refreshsub(sht->ctl, vx0, vy0, vx0 + sht->bxsize, vy0 + sht->bysize);
    }
    return;
}

void sheet_free(struct SHEET *sht)
{
    if (sht->height >= 0) {
        sheet_updown(sht, -1); /* 如果正在顯示,則先設(shè)置為隱藏 */
    }
    sht->flags = 0; /* "未使用"標志 */
    return;
}

  1. 打vc code,輸入以下代碼并保存為 asmhead.nas,存放在harib08f文件夾中。
; haribote-os boot asm
; TAB=4

BOTPAK  EQU     0x00280000      ; bootpack裝載處
DSKCAC  EQU     0x00100000      ; 磁盤緩存的地方
DSKCAC0 EQU     0x00008000      ; 磁盤高速緩存的場所(實時模式)

; 有關(guān)BOOT_INFO
CYLS    EQU     0x0ff0          ; 設(shè)定啟動區(qū)
LEDS    EQU     0x0ff1
VMODE   EQU     0x0ff2          ; 關(guān)于顏色數(shù)目的信息,顏色的位數(shù)
SCRNX   EQU     0x0ff4          ; 分辨率的X(screen x)
SCRNY   EQU     0x0ff6          ; 分辨率的Y(screen y)
VRAM    EQU     0x0ff8          ; 圖像緩沖區(qū)的開始地址

        ORG     0xc200          ; 這個程序要被裝載到內(nèi)存的什么地方呢?

; 畫面模式設(shè)定

        MOV     AL,0x13         ; VGA顯卡,320x200x8位彩色
        MOV     AH,0x00
        INT     0x10
        MOV     BYTE [VMODE],8  ; 記錄畫面模式(C語言參照)
        MOV     WORD [SCRNX],320
        MOV     WORD [SCRNY],200
        MOV     DWORD [VRAM],0x000a0000

; 用BIOS取得鍵盤各種LED指示燈的狀態(tài)

        MOV     AH,0x02
        INT     0x16            ; keyboard BIOS
        MOV     [LEDS],AL

; 使PIC不授受一切中斷
;   如果要初始PIC的話,要在AT兼容的規(guī)范中,
;   如果不把這家伙放在CLI面前,我偶爾會舉起來
;   稍后進行PIC的初始化

        MOV     AL,0xff
        OUT     0x21,AL
        NOP                     ; 如果連續(xù)OUT命令的話,可能會有不太好的機型
        OUT     0xa1,AL

        CLI                     ; 甚至禁止CPU層面插隊

; cpu從1 mb以上的內(nèi)存,a20gate設(shè)定

        CALL    waitkbdout
        MOV     AL,0xd1
        OUT     0x64,AL
        CALL    waitkbdout
        MOV     AL,0xdf         ; enable A20
        OUT     0x60,AL
        CALL    waitkbdout

; 保護模式過渡

[INSTRSET "i486p"]              ; 用于記述想要使用的486命令

        LGDT    [GDTR0]         ; 暫定GDT設(shè)定
        MOV     EAX,CR0
        AND     EAX,0x7fffffff  ; 使bit31為0(為子禁止尋乎)
        OR      EAX,0x00000001  ; 使bit0為1(為子保護模式轉(zhuǎn)移)
        MOV     CR0,EAX
        JMP     pipelineflush
pipelineflush:
        MOV     AX,1*8          ; 可讀區(qū)段32bit
        MOV     DS,AX
        MOV     ES,AX
        MOV     FS,AX
        MOV     GS,AX
        MOV     SS,AX

; bootpack的傳送

        MOV     ESI,bootpack    ; 傳輸源
        MOV     EDI,BOTPAK      ; 傳輸目的地
        MOV     ECX,512*1024/4
        CALL    memcpy

; 順便磁盤數(shù)據(jù)也向原來的位置傳送

; 首先從引導(dǎo)扇區(qū)

        MOV     ESI,0x7c00      ; 傳輸源
        MOV     EDI,DSKCAC      ; 傳輸目的地
        MOV     ECX,512/4
        CALL    memcpy

; 剩下的全部

        MOV     ESI,DSKCAC0+512 ; 傳輸源
        MOV     EDI,DSKCAC+512  ; 傳輸目的地
        MOV     ECX,0
        MOV     CL,BYTE [CYLS]
        IMUL    ECX,512*18*2/4  ; 從柱面數(shù)轉(zhuǎn)換成字節(jié)數(shù) /4
        SUB     ECX,512/4       ; 通過IPL減去
        CALL    memcpy

; 我們已經(jīng)完成了需要使用asmhead 進行的所有操作
; 放到bootpack中

; 啟動bootpack

        MOV     EBX,BOTPAK
        MOV     ECX,[EBX+16]
        ADD     ECX,3           ; ECX += 3;
        SHR     ECX,2           ; ECX /= 4;
        JZ      skip            ; 無需轉(zhuǎn)移
        MOV     ESI,[EBX+20]    ; 傳輸源
        ADD     ESI,EBX
        MOV     EDI,[EBX+12]    ; 傳輸目的地
        CALL    memcpy
skip:
        MOV     ESP,[EBX+12]    ; 堆棧初始值
        JMP     DWORD 2*8:0x0000001b

waitkbdout:
        IN       AL,0x64
        AND      AL,0x02
        JNZ     waitkbdout      ; 如果AND的結(jié)果不為0,請?zhí)D(zhuǎn)至waitkbdou
        RET

memcpy:
        MOV     EAX,[ESI]
        ADD     ESI,4
        MOV     [EDI],EAX
        ADD     EDI,4
        SUB     ECX,1
        JNZ     memcpy          ; 如果減法不為0,則返回memcpy
        RET
; memcpy也可以用字符串指令編寫,除非你忘記了地址大小寫前綴

        ALIGNB  16
GDT0:
        RESB    8               ; 空選擇器
        DW      0xffff,0x0000,0x9200,0x00cf ; 讀/定段32bit
        DW      0xffff,0x0000,0x9a28,0x0047 ; 可執(zhí)行段32bit(用于bootpack)

        DW      0
GDTR0:
        DW      8*3-1
        DD      GDT0

        ALIGNB  16
bootpack:

  1. 打開 VC code 創(chuàng)建 ipl10.nas 文件,輸入以下代碼,也存放的harib08f中。
; haribote-ipl
; TAB=4

CYLS    EQU     10              ; 要讀取到什么程度

        ORG     0x7c00          ; 啟動裝載程序

; 以下記述用于標準FAT12格式軟盤

        JMP     entry
        DB      0x90
        DB      "HARIBOTE"      ; 磁盤名稱(可以是任意字符串)
        DW      512             ; 每個扇區(qū)的大?。ū仨毷?12)
        DB      1               ; 簇的大?。ū仨殲橐粋€扇區(qū))
        DW      1               ; FAT12的起始位置(一般從第一個扇區(qū)開始
        DB      2               ; FAT的個數(shù)(必須為2)
        DW      224             ; 根目錄的大?。ㄒ话阍O(shè)成224項)
        DW      2880            ; 該磁盤的大?。ū仨毷?880扇區(qū))
        DB      0xf0            ; 該磁盤的種類(必須是0xf0
        DW      9               ; FAt的長度(必須是9扇區(qū))
        DW      18              ; 一個磁道有幾個扇區(qū)(必須是18)
        DW      2               ; 磁頭數(shù)(必須是2)
        DD      0               ; 不使用分區(qū),必須是0
        DD      2880            ; 磁盤大小
        DB      0,0,0x29        ; 意義不明固定
        DD      0xffffffff      ; (可能是)卷標號碼
        DB      "HARIBOTEOS "   ; 磁盤的名稱(11字節(jié))
        DB      "FAT12   "      ; 磁盤格式名稱(8字節(jié))
        RESB    18              ; 先空出18字節(jié)

; 程序主體

entry:
        MOV     AX,0            ; 初始化寄存器
        MOV     SS,AX
        MOV     SP,0x7c00
        MOV     DS,AX

; 讀磁盤

        MOV     AX,0x0820
        MOV     ES,AX
        MOV     CH,0            ; 柱面 0
        MOV     DH,0            ; 磁頭 0
        MOV     CL,2            ; 扇區(qū) 2
readloop:
        MOV     SI,0            ; 記錄失敗次數(shù)的寄存器
retry:
        MOV     AH,0x02         ; AH=0x02 : 讀入磁盤
        MOV     AL,1            ; 1 個扇區(qū)
        MOV     BX,0
        MOV     DL,0x00         ; A 驅(qū)動器
        INT     0x13            ; 調(diào)用磁盤BIOS
        JNC     next            ; 沒出錯時跳轉(zhuǎn)到next
        ADD     SI,1            ; SI 加 1
        CMP     SI,5            ; 比較 SI 與 5
        JAE     error           ; SI >= 5 時,跳轉(zhuǎn)到error
        MOV     AH,0x00
        MOV     DL,0x00         ; A 驅(qū)動器
        INT     0x13            ; 重置驅(qū)動器
        JMP     retry
next:
        MOV     AX,ES           ; 把內(nèi)存地址后移0x200
        ADD     AX,0x0020
        MOV     ES,AX           ; 因為沒有 ADD ES,0x020 指令,所以這里稍微繞個彎
        ADD     CL,1            ; CL 加 1
        CMP     CL,18           ; 比較 CL 與 18
        JBE     readloop        ; 如果 CL <= 18,則跳轉(zhuǎn)至readloop 
        MOV     CL,1
        ADD     DH,1
        CMP     DH,2
        JB      readloop        ; 如果 DH < 2, 則跳轉(zhuǎn)到readloop
        MOV     DH,0
        ADD     CH,1
        CMP     CH,CYLS
        JB      readloop        ; 如果 CH < CYLS,則跳轉(zhuǎn)至readloop

; 因為看完了實行haribote.sys

        MOV     [0x0ff0],CH     ; IPL讀到什么地方結(jié)束
        JMP     0xc200

error:
        MOV     SI,msg
putloop:
        MOV     AL,[SI]
        ADD     SI,1            ; SI 加 1
        CMP     AL,0
        JE      fin
        MOV     AH,0x0e         ; 顯示一個文字
        MOV     BX,15           ; 指定字符顏色
        INT     0x10            ; 調(diào)用顯卡BIOS
        JMP     putloop
fin:
        HLT                     ; 讓CPu停止,等待指令
        JMP     fin             ; 無限循環(huán)
msg:
        DB      0x0a, 0x0a      ; 換行兩次
        DB      "load error"
        DB      0x0a            ; 換行
        DB      0

        RESB    0x7dfe-$        ; 重復(fù)0x00一直到0x7dfe

        DB      0x55, 0xaa

  1. 打開記事本,輸入以下代碼,另存為 make.bat, 同樣放到harib08f中。
..\z_tools\make.exe %1 %2 %3 %4 %5 %6 %7 %8 %9
  1. 創(chuàng)建 Makefile,并輸入以下代碼并存放到harib08f中。
OBJS_BOOTPACK = bootpack.obj naskfunc.obj hankaku.obj graphic.obj dsctbl.obj \
        int.obj fifo.obj keyboard.obj mouse.obj memory.obj

TOOLPATH = ../z_tools/
INCPATH  = ../z_tools/haribote/

MAKE     = $(TOOLPATH)make.exe -r
NASK     = $(TOOLPATH)nask.exe
CC1      = $(TOOLPATH)cc1.exe -I$(INCPATH) -Os -Wall -quiet
GAS2NASK = $(TOOLPATH)gas2nask.exe -a
OBJ2BIM  = $(TOOLPATH)obj2bim.exe
MAKEFONT = $(TOOLPATH)makefont.exe
BIN2OBJ  = $(TOOLPATH)bin2obj.exe
BIM2HRB  = $(TOOLPATH)bim2hrb.exe
RULEFILE = $(TOOLPATH)haribote/haribote.rul
EDIMG    = $(TOOLPATH)edimg.exe
IMGTOL   = $(TOOLPATH)imgtol.com
COPY     = copy
DEL      = del

# 默認

default :
    $(MAKE) img

# 文件生成規(guī)則

ipl10.bin : ipl10.nas Makefile
    $(NASK) ipl10.nas ipl10.bin ipl10.lst

asmhead.bin : asmhead.nas Makefile
    $(NASK) asmhead.nas asmhead.bin asmhead.lst

hankaku.bin : hankaku.txt Makefile
    $(MAKEFONT) hankaku.txt hankaku.bin

hankaku.obj : hankaku.bin Makefile
    $(BIN2OBJ) hankaku.bin hankaku.obj _hankaku

bootpack.bim : $(OBJS_BOOTPACK) Makefile
    $(OBJ2BIM) @$(RULEFILE) out:bootpack.bim stack:3136k map:bootpack.map \
        $(OBJS_BOOTPACK)
# 3MB+64KB=3136KB

bootpack.hrb : bootpack.bim Makefile
    $(BIM2HRB) bootpack.bim bootpack.hrb 0

haribote.sys : asmhead.bin bootpack.hrb Makefile
    copy /B asmhead.bin+bootpack.hrb haribote.sys

haribote.img : ipl10.bin haribote.sys Makefile
    $(EDIMG)   imgin:../z_tools/fdimg0at.tek \
        wbinimg src:ipl10.bin len:512 from:0 to:0 \
        copy from:haribote.sys to:@: \
        imgout:haribote.img

# 一般規(guī)則

%.gas : %.c bootpack.h Makefile
    $(CC1) -o $*.gas $*.c

%.nas : %.gas Makefile
    $(GAS2NASK) $*.gas $*.nas

%.obj : %.nas Makefile
    $(NASK) $*.nas $*.obj $*.lst

# 命令

img :
    $(MAKE) haribote.img

run :
    $(MAKE) img
    $(COPY) haribote.img ..\z_tools\qemu\fdimage0.bin
    $(MAKE) -C ../z_tools/qemu

install :
    $(MAKE) img
    $(IMGTOL) w a: haribote.img

clean :
    -$(DEL) *.bin
    -$(DEL) *.lst
    -$(DEL) *.obj
    -$(DEL) bootpack.map
    -$(DEL) bootpack.bim
    -$(DEL) bootpack.hrb
    -$(DEL) haribote.sys

src_only :
    $(MAKE) clean
    -$(DEL) haribote.img

  1. 打開記事本,復(fù)制以下內(nèi)容并保存為 hankaku.txt,且存放在harib08f中;ps:建議這一段代碼直接復(fù)制不要看。
這段代碼過多,無法貼出來,請在網(wǎng)盤資源復(fù)制,projects/05_day/harib02f中hankaku.txt
編譯及運行
  1. 雙擊 !cons_nt.bat,并在打開的命令行中輸入 make run


    在這里插入圖片描述
  2. VMware中運行結(jié)果,如下圖


    在這里插入圖片描述

    ps: 結(jié)果就是這樣,因為本次實驗的目的是高速計數(shù)器(harib08f),現(xiàn)在還只是一個圖層,以后可以操作。以后會有更精彩。敬請期待!
    好的今天到這里harib08f就張結(jié)束了,請大家多多支持!??!

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容