initial commit
This commit is contained in:
commit
08f66b73e1
10 changed files with 783 additions and 0 deletions
7
build.bat
Normal file
7
build.bat
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
@echo off
|
||||
|
||||
cd src
|
||||
"c:\program files\NASM\nasm" -f bin boot.asm -o ..\build\bios.bin
|
||||
cd ..
|
||||
|
||||
qemu-system-x86_64 -bios build/bios.bin -device loader,file=build/vgabios.bin,addr=0xC0000,force-raw=on -device isa-debugcon,chardev=myconsole -chardev stdio,id=myconsole -k be -display sdl
|
||||
123
readme.md
Normal file
123
readme.md
Normal file
|
|
@ -0,0 +1,123 @@
|
|||
# Custom BIOS / ROM Project
|
||||
## Projet BIOS / ROM personnalisé
|
||||
|
||||
---
|
||||
|
||||
## 🇬🇧 English
|
||||
|
||||
### Overview
|
||||
|
||||
This project aims to design and implement a **PC-compatible BIOS/ROM from scratch**, primarily targeted for **QEMU emulation**, with a strong focus on **low-level PC architecture** and **x86 real-mode assembly programming**.
|
||||
|
||||
Rather than booting an operating system from disk, the PC starts **directly from the ROM** into a **minimalist graphical interface**, using **CGA High-Resolution Monochrome (640×200)** mode.
|
||||
|
||||
The project is intentionally educational, experimental, and minimalist.
|
||||
|
||||
---
|
||||
|
||||
### Objectives
|
||||
|
||||
- **Write a PC-compatible BIOS from scratch**
|
||||
- No reuse of existing BIOS code
|
||||
- Minimal but functional implementation
|
||||
- Compatible with QEMU
|
||||
- Target architecture: **8086 → 80486**
|
||||
|
||||
- **Boot directly from ROM**
|
||||
- No DOS, no bootloader, no disk dependency
|
||||
- Execution starts at reset vector (F000:FFF0)
|
||||
- ROM is responsible for full system initialization
|
||||
|
||||
- **Provide a minimalist graphical interface**
|
||||
- Graphics mode: **CGA High-Resolution Monochrome (640×200)**
|
||||
- Direct video memory access
|
||||
- Custom cursor and basic UI primitives
|
||||
|
||||
- **Deep understanding of PC architecture**
|
||||
- CPU reset behavior
|
||||
- Memory map (RAM, ROM, EBDA, IVT, BDA)
|
||||
- Interrupt Vector Table
|
||||
- Hardware initialization (PIC, PIT, keyboard, video)
|
||||
- Real-mode execution constraints
|
||||
|
||||
- **Improve mastery of x86 assembly**
|
||||
- Real-mode x86 assembly (8086-compatible)
|
||||
- Performance-oriented routines
|
||||
- Hardware-near programming
|
||||
- Clear separation between hardware-specific drivers and core logic
|
||||
|
||||
---
|
||||
|
||||
### Non-Goals
|
||||
|
||||
- Full IBM BIOS compatibility
|
||||
- Protected mode or modern CPUs
|
||||
- Advanced OS services
|
||||
- DOS or legacy OS support
|
||||
|
||||
This is a **learning and exploration project**, not a drop-in BIOS replacement.
|
||||
|
||||
---
|
||||
|
||||
## 🇫🇷 Français
|
||||
|
||||
### Présentation
|
||||
|
||||
Ce projet consiste à concevoir et développer un **BIOS/ROM PC compatible entièrement écrit “from scratch”**, destiné principalement à l’émulation **QEMU**, avec pour objectif principal l’**apprentissage approfondi de l’architecture PC** et de la **programmation assembleur x86 en mode réel**.
|
||||
|
||||
Au lieu de charger un système d’exploitation depuis un disque, le PC **démarre directement depuis la ROM** vers une **interface graphique minimaliste**, utilisant le mode **CGA Haute Résolution Monochrome (640×200)**.
|
||||
|
||||
Le projet est volontairement **éducatif, expérimental et minimaliste**.
|
||||
|
||||
---
|
||||
|
||||
### Objectifs
|
||||
|
||||
- **Écrire un BIOS PC depuis zéro**
|
||||
- Aucun code BIOS existant réutilisé
|
||||
- Implémentation minimale mais fonctionnelle
|
||||
- Compatible avec QEMU
|
||||
- Architecture ciblée : **8086 jusqu’au 486**
|
||||
|
||||
- **Démarrer directement depuis la ROM**
|
||||
- Sans DOS, sans bootloader, sans disque
|
||||
- Exécution depuis le vecteur de reset (F000:FFF0)
|
||||
- La ROM initialise entièrement la machine
|
||||
|
||||
- **Fournir une interface graphique minimaliste**
|
||||
- Mode graphique : **CGA Hi-Res Monochrome (640×200)**
|
||||
- Accès direct à la mémoire vidéo
|
||||
- Curseur personnalisé et primitives graphiques simples
|
||||
|
||||
- **Approfondir la compréhension de l’architecture PC**
|
||||
- Séquence de reset CPU
|
||||
- Cartographie mémoire (RAM, ROM, EBDA, IVT, BDA)
|
||||
- Table des vecteurs d’interruptions
|
||||
- Initialisation matérielle (PIC, PIT, clavier, vidéo)
|
||||
- Contraintes du mode réel
|
||||
|
||||
- **Perfectionner la maîtrise de l’assembleur**
|
||||
- Assembleur x86 en mode réel (compatible 8086)
|
||||
- Routines optimisées pour la performance
|
||||
- Programmation proche du matériel
|
||||
- Séparation claire entre cœur du BIOS et drivers matériels
|
||||
|
||||
---
|
||||
|
||||
### Hors périmètre
|
||||
|
||||
- Compatibilité BIOS IBM complète
|
||||
- Mode protégé ou CPU modernes
|
||||
- Services système avancés
|
||||
- Support DOS ou OS legacy
|
||||
|
||||
Ce projet est avant tout un **laboratoire d’apprentissage et d’exploration**, et non un BIOS de production.
|
||||
|
||||
---
|
||||
|
||||
### Status
|
||||
|
||||
🚧 **Work in progress**
|
||||
Designed for experimentation, learning, and documentation.
|
||||
|
||||
---
|
||||
3
run.bat
Normal file
3
run.bat
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
@echo off
|
||||
|
||||
qemu-system-x86_64 -bios build/bios.bin -device loader,file=build/vgabios.bin,addr=0xC0000,force-raw=on -device isa-debugcon,chardev=myconsole -chardev stdio,id=myconsole -k be -display sdl
|
||||
29
src/bda.asm
Normal file
29
src/bda.asm
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
;
|
||||
; https://wiki.nox-rhea.org/back2root/ibm-pc-ms-dos/hardware/informations/bios_data_area
|
||||
;
|
||||
%define BDA_SEGMENT 0x0040 ; segment BDA
|
||||
|
||||
; custom var
|
||||
%define BDA_INFO_MEM_SIZE 0x0014 ; Memory size in Kbytes
|
||||
%define BDA_INFO_MEM_SEG BDA_INFO_MEM_SIZE+2 ; highest Memory Segment
|
||||
|
||||
|
||||
%define BDA_MOUSE_BUFFER 0x0068 ; dword
|
||||
%define BDA_MOUSE_IDX BDA_MOUSE_BUFFER+4 ; byte
|
||||
%define BDA_MOUSE_X BDA_MOUSE_BUFFER+5 ; word
|
||||
%define BDA_MOUSE_Y BDA_MOUSE_BUFFER+7 ; word
|
||||
|
||||
; video related information (compatible with VGA bios)
|
||||
%define BDA_VIDEO_CURR_MODE 0x0049
|
||||
%define BDA_VIDEO_COLUMNS 0x004A
|
||||
%define BDA_VIDEO_BUF_SIZE 0x004C
|
||||
%define BDA_VIDEO_OFS_PAGE 0x004E
|
||||
|
||||
|
||||
; 40:50 8 words Cursor position of pages 1-8, high order byte=row low order byte=column; changing this data isn't reflected immediately on the display
|
||||
; 40:60 byte Cursor ending (bottom) scan line (don't modify)
|
||||
; 40:61 byte Cursor starting (top) scan line (don't modify)
|
||||
; 40:62 byte Active display page number
|
||||
; 40:63 word Base port address for active 6845 CRT controller 3B4h = mono, 3D4h = color
|
||||
; 40:65 byte 6845 CRT mode control register value (port 3x8h) ; EGA/VGA values emulate those of the MDA/CGA
|
||||
; 40:66 byte CGA current color palette mask setting (port 3d9h) ; EGA and VGA values emulate the CGA
|
||||
261
src/boot.asm
Normal file
261
src/boot.asm
Normal file
|
|
@ -0,0 +1,261 @@
|
|||
;
|
||||
;
|
||||
;
|
||||
;
|
||||
BITS 16
|
||||
org 0
|
||||
|
||||
;
|
||||
; configuration du bios
|
||||
;
|
||||
%define DEBUG_PORT 0xe9 ; 0x402 ou 0xe9
|
||||
|
||||
%define VIDEO_SEG 0xB800 ; ou 0xB000
|
||||
%define VIDEO_ATTR 0x07
|
||||
|
||||
; initial stack
|
||||
%define STACK_SEG 0x0030
|
||||
%define STACK_TOP 0x0100 ; choix commun en RAM basse (pile descend)
|
||||
|
||||
%define MEM_SEG_DEB 0x0800 ; 0x0800:0000 = 0x8000 (32KB) évite IVT/BDA + stack 7C00
|
||||
%define MEM_SEG_END 0xA000 ; 0xA000:0000 = 0xA0000 (début zone vidéo)
|
||||
%define MEM_SEG_STEP 0x0040 ; 1KB = 0x400 bytes = 0x40 paragraphs
|
||||
|
||||
; definition du BDA
|
||||
%include ".\bda.asm"
|
||||
|
||||
|
||||
jmp reset
|
||||
|
||||
%include ".\drivers\debug.asm"
|
||||
%include ".\drivers\gfx_cgam.asm"
|
||||
%include ".\drivers\mouse_ps2.asm"
|
||||
|
||||
err_novga db 'No VGA Card BIOS',0
|
||||
err_vganok db 'VGA Not Initialized',0
|
||||
err_end db 'code completed successfully',0
|
||||
|
||||
reset:
|
||||
cli
|
||||
; il n'existe aucun 'stack' par défaut
|
||||
mov ax, STACK_SEG
|
||||
mov ss, ax
|
||||
mov sp, STACK_TOP ; haut du segment, mot-aligné
|
||||
|
||||
; detection de la mémoire totale
|
||||
call setup_ram
|
||||
; modification du stack en "haut" de la RAM
|
||||
mov ax, dx
|
||||
sub ax, 0x0400 ; réserver les 16 dernier KB
|
||||
mov ss, ax
|
||||
mov sp, 0x1000 ; sommet de pile
|
||||
|
||||
; installé une table d'interruption "dummy"
|
||||
call setup_ivt
|
||||
sti
|
||||
|
||||
; load other Rom
|
||||
call setup_load_rom
|
||||
|
||||
; on vérifie que le BIOS VGA a installer l'INT 10h
|
||||
call setup_check_vga
|
||||
|
||||
call gfx_init
|
||||
|
||||
call mouse_init
|
||||
|
||||
mov ax,cs
|
||||
mov ds,ax
|
||||
|
||||
mov si, err_end
|
||||
call debug_puts
|
||||
|
||||
endless: nop
|
||||
jmp endless
|
||||
|
||||
; ---------------------------------------------------------------------------
|
||||
; Détection les ROM supplementaires
|
||||
; Teste la RAM de 0xC000 jusqu’à 0xE000, par pas de 2KB.
|
||||
;
|
||||
; Si une ROM est détectée, le code de la ROM sera appelé.
|
||||
; ---------------------------------------------------------------------------
|
||||
setup_check_vga:
|
||||
; vérification de l'offset 0x0000:0x0040 qui DOIT etre différent de @default_isr
|
||||
xor ax,ax
|
||||
mov es,ax
|
||||
; Lire INT10: offset+segment depuis 0000:0040
|
||||
mov bx, [es:0x0040] ; BX = offset INT10
|
||||
mov cx, [es:0x0042] ; CX = segment INT10
|
||||
mov ax, cs
|
||||
|
||||
; Comparer avec default_isr (offset) et CS (segment)
|
||||
mov dx, default_isr ; DX = offset default_isr (dans notre CS)
|
||||
cmp bx, dx
|
||||
jne .init_ok ; interrupt different
|
||||
cmp cx, ax
|
||||
jne .init_ok
|
||||
|
||||
; no VGA init
|
||||
mov ax,cs
|
||||
mov ds,ax
|
||||
|
||||
mov si, err_vganok
|
||||
call debug_puts
|
||||
.init_ok:
|
||||
ret
|
||||
|
||||
; ---------------------------------------------------------------------------
|
||||
; Détection les ROM supplementaires
|
||||
; Teste la RAM de 0xC000 jusqu’à 0xE000, par pas de 2KB.
|
||||
;
|
||||
; Si une ROM est détectée, le code de la ROM sera appelé.
|
||||
; ---------------------------------------------------------------------------
|
||||
setup_load_rom:
|
||||
mov bx, 0xC000
|
||||
mov al,'*'
|
||||
.scanloop:
|
||||
mov ds, bx
|
||||
cmp word[0x0000],0xAA55 ; ROM signature
|
||||
jne .norom
|
||||
|
||||
; Debug
|
||||
mov al,'.'
|
||||
call debug_putc
|
||||
|
||||
; appel le code (en 0x0003) de la ROM
|
||||
push cs
|
||||
push word .norom ; address de retour
|
||||
|
||||
push ds
|
||||
push 0x0003
|
||||
retf ; call far ds:0x0003
|
||||
.norom:
|
||||
add bx, 0x80 ; add 2kb
|
||||
cmp bx, 0xE000
|
||||
jbe .scanloop
|
||||
|
||||
cmp al,'.'
|
||||
je .end
|
||||
; no rom found :
|
||||
mov bx,cs
|
||||
mov ds,bx
|
||||
|
||||
mov si, err_novga
|
||||
call debug_puts
|
||||
.end:
|
||||
ret
|
||||
|
||||
; ---------------------------------------------------------------------------
|
||||
; Détection RAM conventionnelle (8088, BIOS maison) — sans BIOS
|
||||
; Teste la RAM de MEM_SEG_DEB jusqu’à 0xA000 (640KB), par pas de 1KB.
|
||||
; Méthode: sauvegarde 1 mot, écrit 2 patterns, relit, restaure.
|
||||
;
|
||||
; Résultats:
|
||||
; AX = taille détectée en Ko (KB) à partir de 0 jusqu’au “top conventionnel”
|
||||
; DX = top_segment (segment du premier Ko NON valide) (optionnel)
|
||||
;
|
||||
; Précautions:
|
||||
; - Ne testez PAS une zone où se trouve votre pile / variables.
|
||||
; - Si votre pile est à 0000:7C00 (phys 0x7C00), commencez au moins à 0x0800.
|
||||
; - Ne testez pas au-delà de 0xA000 (début VGA/vidéo).
|
||||
; ---------------------------------------------------------------------------
|
||||
setup_ram:
|
||||
xor ax, ax ; AX = compteur KB trouvés
|
||||
mov dx, MEM_SEG_DEB ; DX = segment courant testé
|
||||
mov cx, MEM_SEG_END ; CX = segment fin (exclu)
|
||||
xor di, di ; tester au début du bloc 1KB: ES:0000
|
||||
|
||||
.loop_seg:
|
||||
cmp dx, cx
|
||||
jae .done
|
||||
mov es, dx
|
||||
|
||||
; sauvegarder le mot existant
|
||||
mov bx, [es:di]
|
||||
|
||||
; pattern 1
|
||||
mov word [es:di], 0x55AA
|
||||
cmp word [es:di], 0x55AA
|
||||
jne .fail_restore
|
||||
|
||||
; pattern 2 (inverse)
|
||||
mov word [es:di], 0xAA55
|
||||
cmp word [es:di], 0xAA55
|
||||
jne .fail_restore
|
||||
|
||||
; restaurer
|
||||
mov [es:di], bx
|
||||
|
||||
; OK: avancer d’1KB
|
||||
inc ax ; +1KB valide
|
||||
add dx, MEM_SEG_STEP
|
||||
jmp .loop_seg
|
||||
|
||||
.fail_restore:
|
||||
; restaurer avant de sortir
|
||||
mov [es:di], bx
|
||||
|
||||
.done:
|
||||
; AX contient le nb de KB valides *à partir de MEM_SEG_DEB*.
|
||||
; Si vous voulez une taille “depuis 0KB”, ajoutez MEM_SEG_DEB*16/1024 = MEM_SEG_DEB/64.
|
||||
;
|
||||
; base_kb = MEM_SEG_DEB / 0x0040 (car 1KB = 0x40 segments)
|
||||
mov bx, MEM_SEG_DEB
|
||||
shr bx, 6 ; /64 = /0x40 => KB de base
|
||||
add ax, bx ; AX = taille conventionnelle totale en KB (approx. 0..640)
|
||||
; DX = segment du premier bloc NON valide (top)
|
||||
; DX est déjà positionné (segment courant)
|
||||
|
||||
; stocker l'information dans le BDA
|
||||
mov bx, BDA_SEGMENT
|
||||
mov ds, bx
|
||||
mov [BDA_INFO_MEM_SIZE], ax
|
||||
mov [BDA_INFO_MEM_SEG],dx
|
||||
|
||||
ret
|
||||
|
||||
|
||||
; ---------------------------------------------------------------------------
|
||||
; IVT install (8088, mode réel) - remplit les 256 vecteurs avec un handler IRET
|
||||
; Hypothèses:
|
||||
; - code en ROM (CS typiquement = 0xF000), handler réside dans ce même segment
|
||||
; - interruptions désactivées (CLI) pendant l'installation
|
||||
; ---------------------------------------------------------------------------
|
||||
setup_ivt:
|
||||
; installation de la table d'interrupts
|
||||
xor ax, ax
|
||||
mov es, ax ; ES = 0000h -> base IVT
|
||||
xor di, di ; DI = 0000h -> offset IVT
|
||||
|
||||
mov ax, default_isr ; offset du handler
|
||||
mov dx, cs ; segment du handler (ROM)
|
||||
|
||||
mov cx, 256 ; 256 vecteurs
|
||||
.fill:
|
||||
stosw ; write offset (AX) -> [ES:DI], DI += 2
|
||||
xchg ax, dx ; AX = segment, DX = offset
|
||||
stosw ; write segment (AX) -> [ES:DI], DI += 2
|
||||
xchg ax, dx ; AX = offset, DX = segment
|
||||
loop .fill
|
||||
; fin de la table d'interrupt
|
||||
ret
|
||||
|
||||
; ---------------------------------------------------------------------------
|
||||
; Handler par défaut: fait juste IRET
|
||||
; IMPORTANT: doit être FAR (appelé par le CPU via IVT), et terminer par IRET
|
||||
; ---------------------------------------------------------------------------
|
||||
default_isr:
|
||||
iret
|
||||
|
||||
; ------------------------------------------------------------------
|
||||
; Padding jusqu'au reset vector
|
||||
; ------------------------------------------------------------------
|
||||
times 0xFFF0 - ($ - $$) db 0xFF
|
||||
|
||||
; ------------------------------------------------------------------
|
||||
; RESET VECTOR (exécuté par le CPU)
|
||||
; ------------------------------------------------------------------
|
||||
reset_vector:
|
||||
jmp far 0xF000:reset
|
||||
builddate db '06/01/2026',0
|
||||
|
||||
20
src/drivers/debug.asm
Normal file
20
src/drivers/debug.asm
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
|
||||
|
||||
debug_puts:
|
||||
.next:
|
||||
lodsb ; AL = *SI++
|
||||
test al, al
|
||||
jz .done
|
||||
|
||||
mov dx, DEBUG_PORT
|
||||
|
||||
out dx, al
|
||||
jmp .next
|
||||
.done:
|
||||
ret
|
||||
|
||||
debug_putc:
|
||||
.next:
|
||||
mov dx, DEBUG_PORT
|
||||
out dx, al
|
||||
ret
|
||||
62
src/drivers/gfx.asm
Normal file
62
src/drivers/gfx.asm
Normal file
|
|
@ -0,0 +1,62 @@
|
|||
%define GFX_MODE 0x06 ; MCGA HiRes (B/W)
|
||||
%define GFX_WIDTH 640
|
||||
%define GFX_HEIGHT 200
|
||||
|
||||
gfx_init:
|
||||
; init graphics mode
|
||||
mov ah, 0x00 ; AH=00h set video mode
|
||||
mov al, GFX_MODE
|
||||
int 0x10
|
||||
|
||||
call gfx_background
|
||||
|
||||
ret
|
||||
|
||||
; PutPixel(x=cx, y=dx, color=al) sur page bh
|
||||
gfx_putpixel:
|
||||
mov ah, 0Ch
|
||||
;mov al, 0Fh ; couleur (0..15)
|
||||
;mov bh, 00h ; page
|
||||
;mov cx, 100 ; x
|
||||
;mov dx, 50 ; y
|
||||
int 10h
|
||||
ret
|
||||
|
||||
gfx_background:
|
||||
mov ax,VIDEO_SEG
|
||||
mov es,ax
|
||||
xor di,di
|
||||
mov ax,0xaaaa
|
||||
mov cx,0x1000
|
||||
rep stosw
|
||||
mov ax,0x5555
|
||||
mov cx,0x1000 ; 640/8/2
|
||||
rep stosw
|
||||
ret
|
||||
|
||||
; gfx_background:
|
||||
xor dx,dx ; Y
|
||||
|
||||
.loop_y:
|
||||
test dl,1
|
||||
jnz .pair
|
||||
|
||||
mov cx,0 ; X = 0
|
||||
jmp .loop_x
|
||||
.pair:
|
||||
mov cx,1 ; X = 1
|
||||
|
||||
.loop_x:
|
||||
mov ah,0x0c ; putpixel
|
||||
mov al,0x0f ; blanc
|
||||
xor bh,bh
|
||||
int 10h
|
||||
|
||||
add cx,2 ; x=x+2
|
||||
cmp cx,GFX_WIDTH
|
||||
jb .loop_x
|
||||
|
||||
inc dx
|
||||
cmp dx,GFX_HEIGHT
|
||||
jb .loop_y
|
||||
ret
|
||||
45
src/drivers/gfx_cgam.asm
Normal file
45
src/drivers/gfx_cgam.asm
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
;
|
||||
; graphics drivers for CGA 640x200x2
|
||||
;
|
||||
%define GFX_MODE 0x06 ; MCGA HiRes (B/W)
|
||||
%define GFX_WIDTH 640
|
||||
%define GFX_HEIGHT 200
|
||||
|
||||
%define CGA_STRIDE 80
|
||||
%define CGA_ODD_BANK 0x2000
|
||||
%define BG16_SIZE 48
|
||||
|
||||
; ce mode est entrelacé, un bit/pixel, 8 pixels par octet
|
||||
|
||||
gfx_init:
|
||||
; init graphics mode
|
||||
mov ah, 0x00 ; AH=00h set video mode
|
||||
mov al, GFX_MODE
|
||||
int 0x10
|
||||
|
||||
call gfx_background
|
||||
|
||||
ret
|
||||
|
||||
; PutPixel(x=cx, y=dx, color=al) sur page bh
|
||||
gfx_putpixel:
|
||||
mov ah, 0Ch
|
||||
;mov al, 0Fh ; couleur (0..15)
|
||||
;mov bh, 00h ; page
|
||||
;mov cx, 100 ; x
|
||||
;mov dx, 50 ; y
|
||||
int 10h
|
||||
ret
|
||||
|
||||
; draw background pattern
|
||||
gfx_background:
|
||||
mov ax,VIDEO_SEG
|
||||
mov es,ax
|
||||
xor di,di
|
||||
mov ax,0xaaaa
|
||||
mov cx,0x1000
|
||||
rep stosw
|
||||
mov ax,0x5555
|
||||
mov cx,0x1000 ; 640/8/2
|
||||
rep stosw
|
||||
ret
|
||||
127
src/drivers/mouse_ps2.asm
Normal file
127
src/drivers/mouse_ps2.asm
Normal file
|
|
@ -0,0 +1,127 @@
|
|||
;
|
||||
; controlleur de souris via le i8042 (PC Classique)
|
||||
;
|
||||
|
||||
%define PS2_PORT_BUFFER 0x60
|
||||
%define PS2_PORT_CTRL 0x64
|
||||
|
||||
%define MOUSE_CMD_RESET 0xff
|
||||
%define MOUSE_CMD_DEFAULT 0xf6
|
||||
%define MOUSE_EN_STREAM 0xf4
|
||||
%define MOUSE_DIS_STREAM 0xf5
|
||||
|
||||
mouse_arrow:
|
||||
dw 1001111111111111b ; 0x9FFF
|
||||
dw 1000111111111111b ; 0x8FFF
|
||||
dw 1000011111111111b ; 0x87FF
|
||||
dw 1000001111111111b ; 0x83FF
|
||||
dw 1000000111111111b ; 0x81FF
|
||||
dw 1000000011111111b ; 0x80FF
|
||||
dw 1000000001111111b ; 0x807F
|
||||
dw 1000000000111111b ; 0x803F
|
||||
dw 1000000000011111b ; 0x801F
|
||||
dw 1000000000001111b ; 0x800F
|
||||
dw 1000000011111111b ; 0x80FF
|
||||
dw 1000100001111111b ; 0x887F
|
||||
dw 1001100001111111b ; 0x987F
|
||||
dw 1111110000111111b ; 0xFC3F
|
||||
dw 1111110000111111b ; 0xFC3F
|
||||
dw 1111111000111111b ; 0xFE3F
|
||||
dw 0000000000000000b ; 0x0000
|
||||
dw 0010000000000000b ; 0x2000
|
||||
dw 0011000000000000b ; 0x3000
|
||||
dw 0011100000000000b ; 0x3800
|
||||
dw 0011110000000000b ; 0x3C00
|
||||
dw 0011111000000000b ; 0x3E00
|
||||
dw 0011111100000000b ; 0x3F00
|
||||
dw 0011111110000000b ; 0x3F80
|
||||
dw 0011111111000000b ; 0x3FC0
|
||||
dw 0011111000000000b ; 0x3E00
|
||||
dw 0011011000000000b ; 0x3600
|
||||
dw 0010001100000000b ; 0x2300
|
||||
dw 0000001100000000b ; 0x0300
|
||||
dw 0000000110000000b ; 0x0180
|
||||
dw 0000000110000000b ; 0x0180
|
||||
dw 0000000000000000b ; 0x0000
|
||||
|
||||
mouse_init:
|
||||
; Activer le port souris
|
||||
mov ax, BDA_SEGMENT
|
||||
mov ds,ax
|
||||
|
||||
; effacer les variables du drivers
|
||||
mov [BDA_MOUSE_IDX],0
|
||||
mov dword [BDA_MOUSE_BUFFER],0
|
||||
|
||||
mov al, 0xA8
|
||||
out PS2_PORT_CTRL, al
|
||||
|
||||
; Lire le command byte
|
||||
mov al, 0x20
|
||||
out PS2_PORT_CTRL, al
|
||||
in al, PS2_PORT_BUFFER
|
||||
|
||||
; Activer IRQ12 (bit 1)
|
||||
or al, 0x02
|
||||
|
||||
; Réécrire le command byte
|
||||
mov ah, al
|
||||
mov al, PS2_PORT_BUFFER
|
||||
out PS2_PORT_CTRL, al
|
||||
mov al, ah
|
||||
out PS2_PORT_BUFFER, al
|
||||
ret
|
||||
|
||||
; envoyer une commande souris
|
||||
mouse_sendcmd:
|
||||
.wait:
|
||||
in al, PS2_PORT_CTRL
|
||||
test al, 2
|
||||
jnz .wait
|
||||
mov al, 0xD4
|
||||
out PS2_PORT_CTRL, al
|
||||
|
||||
.wait2:
|
||||
in al, PS2_PORT_CTRL
|
||||
test al, 2
|
||||
jnz .wait2
|
||||
mov al, bl ; BL = commande souris
|
||||
out PS2_PORT_BUFFER, al
|
||||
ret
|
||||
|
||||
mouse_handler:
|
||||
push ax
|
||||
push bx
|
||||
|
||||
; use BDA segment
|
||||
push ds
|
||||
mov ax,BDA_SEGMENT
|
||||
mov ds,ax
|
||||
xor bx,bx
|
||||
|
||||
in al, PS2_PORT_BUFFER ; lire octet souris
|
||||
mov [BDA_MOUSE_BUFFER + BDA_MOUSE_IDX], al
|
||||
inc [BDA_MOUSE_IDX]
|
||||
|
||||
cmp [BDA_MOUSE_IDX], 3
|
||||
jne .done
|
||||
|
||||
mov [BDA_MOUSE_IDX], 0
|
||||
; decode buffer
|
||||
mov al, [BDA_MOUSE_BUFFER+1]
|
||||
cbw
|
||||
add [BDA_MOUSE_X], ax
|
||||
|
||||
mov al, [BDA_MOUSE_BUFFER+2]
|
||||
cbw
|
||||
sub [BDA_MOUSE_Y], ax
|
||||
|
||||
.done:
|
||||
mov al, 0x20
|
||||
out 0xA0, al ; EOI PIC esclave
|
||||
out 0x20, al ; EOI PIC maître
|
||||
|
||||
pop ds
|
||||
pop bx
|
||||
pop ax
|
||||
iret
|
||||
106
src/drivers/textmode.asm
Normal file
106
src/drivers/textmode.asm
Normal file
|
|
@ -0,0 +1,106 @@
|
|||
;
|
||||
; text mod functions
|
||||
;
|
||||
;
|
||||
|
||||
vid_seg dw VIDEO_SEG
|
||||
cursor_ofs dw 0
|
||||
txt_attr db VIDEO_ATTR
|
||||
|
||||
|
||||
; -----------------------------------------------------------------------------
|
||||
; cls : efface l'écran en remplissant txtmode_CELLS cellules par " " + ATTR
|
||||
; -----------------------------------------------------------------------------
|
||||
txtmode_clear:
|
||||
mov ax,0xB800 ; select video segment
|
||||
mov es,ax
|
||||
xor ax,ax ; 0
|
||||
; mov [cursor_ofs],ax ; reset 'virtual' cursor
|
||||
mov di,ax
|
||||
; default attr + space
|
||||
mov ah, [txt_attr]
|
||||
mov al, ' '
|
||||
;
|
||||
mov cx,2000 ; 25x80
|
||||
rep stosw ; attr + char
|
||||
ret
|
||||
|
||||
; -----------------------------------------------------------------------------
|
||||
; puts : imprime une chaîne ASCIIZ (DS:SI) en VRAM (ES:cursor_ofs)
|
||||
; - gère '\n' (LF=10) comme nouvelle ligne
|
||||
; - ignore '\r' (CR=13)
|
||||
; -----------------------------------------------------------------------------
|
||||
txtmode_puts:
|
||||
.next:
|
||||
lodsb ; AL = *SI++
|
||||
test al, al
|
||||
jz .done
|
||||
|
||||
cmp al, 10 ; '\n'
|
||||
je .lf
|
||||
cmp al, 13 ; '\r'
|
||||
je .next
|
||||
|
||||
call txtmode_putc
|
||||
jmp .next
|
||||
|
||||
.lf:
|
||||
call txtmode_newline
|
||||
jmp .next
|
||||
.done:
|
||||
ret
|
||||
|
||||
; -----------------------------------------------------------------------------
|
||||
; putc : imprime le caractère AL à la position du curseur logiciel
|
||||
; -----------------------------------------------------------------------------
|
||||
txtmode_putc:
|
||||
push ax
|
||||
push bx
|
||||
push di
|
||||
|
||||
mov di, [cursor_ofs]
|
||||
; écrire char + attr
|
||||
mov ah, txt_attr
|
||||
stosw ; écrit AX à ES:DI, puis DI += 2
|
||||
|
||||
; mettre à jour cursor_ofs
|
||||
mov [cursor_ofs], di
|
||||
|
||||
; si fin d'écran, on “reboucle” au début (simple)
|
||||
; (vous pouvez remplacer par un scroll si besoin)
|
||||
mov bx, 4000 ; 80x25x2
|
||||
cmp di, bx
|
||||
jb .ok
|
||||
mov word [cursor_ofs], 0
|
||||
.ok:
|
||||
pop di
|
||||
pop bx
|
||||
pop ax
|
||||
ret
|
||||
|
||||
; -----------------------------------------------------------------------------
|
||||
; newline : avance le curseur au début de la ligne suivante (80 colonnes)
|
||||
; -----------------------------------------------------------------------------
|
||||
txtmode_newline:
|
||||
push ax
|
||||
push dx
|
||||
|
||||
mov ax, [cursor_ofs] ; offset en octets
|
||||
xor dx, dx
|
||||
mov cx, 160 ; taille d'une ligne en octets = 160
|
||||
div cx ; AX = ligne, DX = reste (offset dans la ligne)
|
||||
|
||||
inc ax ; ligne suivante
|
||||
cmp ax, 25
|
||||
jb .set
|
||||
xor ax, ax ; si dépasse, revient en haut (simple)
|
||||
.set:
|
||||
|
||||
mov cx, 160 ; cursor_ofs = ligne * 160
|
||||
mul cx ; DX:AX = AX*CX ; ici AX suffit
|
||||
mov [cursor_ofs], ax
|
||||
|
||||
pop dx
|
||||
pop ax
|
||||
ret
|
||||
|
||||
Loading…
Reference in a new issue