add memory lib + maps

This commit is contained in:
Frater 2026-02-07 16:03:29 +01:00
commit 4b62e01e82
10 changed files with 521 additions and 411 deletions

View file

@ -8,18 +8,20 @@ The processor starts in Real Mode, addressing 1 MB of memory.
| Physical Start | Physical End | Size | Description | Segment | Source File | | Physical Start | Physical End | Size | Description | Segment | Source File |
| :--- | :--- | :--- | :--- | :--- | :--- | | :--- | :--- | :--- | :--- | :--- | :--- |
| **`0x00000`** | **`0x003FF`** | 1 KB | **IVT** (Interrupt Vector Table) | `0x0000` | `boot.asm` / `generic.asm` | | **`0x00000`** | **`0x003FF`** | 1 KB | **IVT** (Interrupt Vector Table) | `0x0000` | `memory.asm` |
| **`0x00400`** | **`0x004FF`** | 256 B | **BDA** (BIOS Data Area) Standard | `0x0040` | `common/bda.asm` | | **`0x00400`** | **`0x004FF`** | 256 B | **BDA** (BIOS Data Area) Standard | `0x0040` | `memory.asm` |
| **`0x00500`** | **`0x005FF`** | ~256 B | **Custom BDA** (Driver Data) | `0x0050` | `common/bda.asm` | | **`0x00500`** | **`0x005FF`** | ~256 B | **Custom BDA** (Driver Data) | `0x0050` | `memory.asm` |
| ... | ... | ... | *Free / Reserved* | | | | **`0x00600`** | **`0x07FFF`** | 30.5 KB | **Free** (Low Memory) | | |
| **`0x08000`** | **`0x09FFF`** | 8 KB | **Stack Bottom** | `0x0800` | `boot.asm` | | **`0x08000`** | **`0x17FFF`** | 64 KB | **Stack** (Grows downwards) | `0x0800` | `memory.asm` |
| **`0x0A000`** | **`0x0AFFF`** | ~4 KB | **GUI RAM** (Widget Allocation) | `0x0A00` | `gui/lib.asm` | | **`0x18000`** | **`0x18FFF`** | ~4 KB | **GUI RAM** (Widget Allocation) | `0x0A00` | `gui/lib.asm` |
| **`0x0B000`** | **`0x17FFE`** | ~52 KB | **Stack Top** (Grows downwards) | `0x0800` | `boot.asm` | | **`0x19000`** | **`0x9FBFF`** | 539 KB | **Free** (Conventional RAM) | | |
| ... | ... | ... | *Conventional RAM Free* | | | | **`0x9FC00`** | **`0x9FFFF`** | 1 KB | **EBDA** (Extended BIOS Data Area) | `0x9FC0` | `memory.asm` |
| **`0xB8000`** | **`0xBFFFF`** | 32 KB | **VRAM** (CGA / MCGA) | `0xB800` | `drivers/gfx_cgam.asm` | | **`0xA0000`** | **`0xAFFFF`** | 64 KB | **VGA RAM** (Graphics Modes) | `0xA000` | `Hardware` |
| **`0xC0000`** | **`0xDFFFF`** | 128 KB | **Option ROMs** (e.g., VGA BIOS) | `0xC000` | `boot.asm` | | **`0xB0000`** | **`0xB7FFF`** | 32 KB | **MDA RAM** (Monochrome Text) | `0xB000` | `Hardware` |
| ... | ... | ... | *System Reserved* | | | | **`0xB8000`** | **`0xBFFFF`** | 32 KB | **VRAM** (CGA / MCGA) | `0xB800` | `memory.asm` |
| **`0xF0000`** | **`0xFFFFF`** | 64 KB | **System BIOS ROM** (Code) | `0xF000` | `boot.asm` | | **`0xC0000`** | **`0xDFFFF`** | 128 KB | **Option ROMs** (e.g., VGA BIOS) | `0xC000` | `memory.asm` |
| **`0xE0000`** | **`0xEFFFF`** | 64 KB | **System Reserved** (BIOS Extension) | `0xE000` | `Hardware` |
| **`0xF0000`** | **`0xFFFFF`** | 64 KB | **System BIOS ROM** (Code) | `0xF000` | `memory.asm` |
### Detailed Zones ### Detailed Zones
@ -50,6 +52,10 @@ The project separates the standard IBM BDA from its own variables to avoid confl
* **Even Lines (0, 2, 4...)**: Offset `0x0000` - `0x1F3F` (Bank 0). * **Even Lines (0, 2, 4...)**: Offset `0x0000` - `0x1F3F` (Bank 0).
* **Odd Lines (1, 3, 5...)**: Offset `0x2000` - `0x3F3F` (Bank 1). * **Odd Lines (1, 3, 5...)**: Offset `0x2000` - `0x3F3F` (Bank 1).
#### VGA RAM & System Reserved
* **VGA RAM (`0xA0000`)**: Standard 64 KB memory window for VGA graphics modes. Although this project primarily uses the CGA memory at `0xB8000`, this area is physically present when the VGA hardware is emulated.
* **System Reserved (`0xE0000`)**: Reserved memory area, typically used for motherboard BIOS extensions or specific hardware mapping.
#### ROM #### ROM
* **Option ROMs (`0xC0000`)**: Scanned by `setup_load_rom` to initialize the VGA BIOS. * **Option ROMs (`0xC0000`)**: Scanned by `setup_load_rom` to initialize the VGA BIOS.
* **System ROM (`0xF0000`)**: Contains the compiled binary code. The Reset Vector is at `0xFFFF0`. * **System ROM (`0xF0000`)**: Contains the compiled binary code. The Reset Vector is at `0xFFFF0`.
@ -64,18 +70,20 @@ Le processeur démarre en mode réel, adressant 1 Mo de mémoire.
| Adresse Physique (Début) | Adresse Physique (Fin) | Taille | Description | Segment | Fichier Source | | Adresse Physique (Début) | Adresse Physique (Fin) | Taille | Description | Segment | Fichier Source |
| :--- | :--- | :--- | :--- | :--- | :--- | | :--- | :--- | :--- | :--- | :--- | :--- |
| **`0x00000`** | **`0x003FF`** | 1 Ko | **IVT** (Interrupt Vector Table) | `0x0000` | `boot.asm` / `generic.asm` | | **`0x00000`** | **`0x003FF`** | 1 Ko | **IVT** (Interrupt Vector Table) | `0x0000` | `memory.asm` |
| **`0x00400`** | **`0x004FF`** | 256 o | **BDA** (BIOS Data Area) Standard | `0x0040` | `common/bda.asm` | | **`0x00400`** | **`0x004FF`** | 256 o | **BDA** (BIOS Data Area) Standard | `0x0040` | `memory.asm` |
| **`0x00500`** | **`0x005FF`** | ~256 o | **Custom BDA** (Données Drivers) | `0x0050` | `common/bda.asm` | | **`0x00500`** | **`0x005FF`** | ~256 o | **Custom BDA** (Données Drivers) | `0x0050` | `memory.asm` |
| ... | ... | ... | *Mémoire Libre / Réservée* | | | | **`0x00600`** | **`0x07FFF`** | 30.5 Ko | **Libre** (Mémoire Basse) | | |
| **`0x08000`** | **`0x09FFF`** | 8 Ko | **Bas de la Pile** (Stack Bottom) | `0x0800` | `boot.asm` | | **`0x08000`** | **`0x17FFF`** | 64 KB | **Stack** (Grows downwards) | `0x0800` | `memory.asm` |
| **`0x0A000`** | **`0x0AFFF`** | ~4 Ko | **GUI RAM** (Allocation Widgets) | `0x0A00` | `gui/lib.asm` | | **`0x18000`** | **`0x18FFF`** | ~4 KB | **GUI RAM** (Widget Allocation) | `0x0A00` | `gui/lib.asm` |
| **`0x0B000`** | **`0x17FFE`** | ~52 Ko | **Haut de la Pile** (Stack Top) | `0x0800` | `boot.asm` | | **`0x19000`** | **`0x9FBFF`** | 539 Ko | **Libre** (RAM Conventionnelle) | | |
| ... | ... | ... | *RAM Conventionnelle Libre* | | | | **`0x9FC00`** | **`0x9FFFF`** | 1 Ko | **EBDA** (Extended BIOS Data Area) | `0x9FC0` | `memory.asm` |
| **`0xB8000`** | **`0xBFFFF`** | 32 Ko | **VRAM** (CGA / MCGA) | `0xB800` | `drivers/gfx_cgam.asm` | | **`0xA0000`** | **`0xAFFFF`** | 64 Ko | **VGA RAM** (Modes Graphiques) | `0xA000` | `Matériel` |
| **`0xC0000`** | **`0xDFFFF`** | 128 Ko | **Option ROMs** (ex: VGA BIOS) | `0xC000` | `boot.asm` | | **`0xB0000`** | **`0xB7FFF`** | 32 Ko | **MDA RAM** (Texte Monochrome) | `0xB000` | `Matériel` |
| ... | ... | ... | *Réservé Système* | | | | **`0xB8000`** | **`0xBFFFF`** | 32 Ko | **VRAM** (CGA / MCGA) | `0xB800` | `memory.asm` |
| **`0xF0000`** | **`0xFFFFF`** | 64 Ko | **System BIOS ROM** (Code) | `0xF000` | `boot.asm` | | **`0xC0000`** | **`0xDFFFF`** | 128 Ko | **Option ROMs** (ex: VGA BIOS) | `0xC000` | `memory.asm` |
| **`0xE0000`** | **`0xEFFFF`** | 64 Ko | **Réservé Système** (Extension BIOS) | `0xE000` | `Matériel` |
| **`0xF0000`** | **`0xFFFFF`** | 64 Ko | **System BIOS ROM** (Code) | `0xF000` | `memory.asm` |
### Détails des Zones ### Détails des Zones
@ -106,6 +114,10 @@ Le projet sépare la BDA standard IBM de ses propres variables pour éviter les
* **Lignes Paires (0, 2, 4...)** : Offset `0x0000` à `0x1F3F` (Bank 0). * **Lignes Paires (0, 2, 4...)** : Offset `0x0000` à `0x1F3F` (Bank 0).
* **Lignes Impaires (1, 3, 5...)** : Offset `0x2000` à `0x3F3F` (Bank 1). * **Lignes Impaires (1, 3, 5...)** : Offset `0x2000` à `0x3F3F` (Bank 1).
#### VGA RAM & Réservé Système
* **VGA RAM (`0xA0000`)** : Fenêtre mémoire standard de 64 Ko pour les modes graphiques VGA. Bien que ce projet utilise principalement la mémoire CGA à `0xB8000`, cette zone est physiquement présente lorsque le matériel VGA est émulé.
* **Réservé Système (`0xE0000`)** : Zone mémoire réservée, typiquement utilisée pour les extensions du BIOS de la carte mère ou le mappage de matériel spécifique.
#### ROM #### ROM
* **Option ROMs (`0xC0000`)** : Espace scanné par `setup_load_rom` pour initialiser le BIOS VGA. * **Option ROMs (`0xC0000`)** : Espace scanné par `setup_load_rom` pour initialiser le BIOS VGA.
* **System ROM (`0xF0000`)** : Contient le code binaire compilé. Le Vecteur de Reset est situé à `0xFFFF0`. * **System ROM (`0xF0000`)** : Contient le code binaire compilé. Le Vecteur de Reset est situé à `0xFFFF0`.

View file

@ -38,10 +38,11 @@
; times 0xFFFF - ($ - $$) db 0xFF ; times 0xFFFF - ($ - $$) db 0xFF
section .text section .text
bits 16 bits 16
%include "./common/chartable.asm" %include "./common/chartable.asm"
%include "./common/cursor.asm" %include "./common/cursor.asm"
%include "./common/patterns.asm"
%include "./common/generic.asm" %include "./common/generic.asm"
; definition du BDA ; definition du BDA
@ -52,6 +53,8 @@ section .text
%include "./drivers/mouse_ps2.asm" %include "./drivers/mouse_ps2.asm"
%include "./drivers/keyboard_ps2.asm" %include "./drivers/keyboard_ps2.asm"
%include "./common/debug_cga.asm"
; GUI ; GUI
%include "./gui/lib.asm" %include "./gui/lib.asm"
%include "./gui/draw.asm" %include "./gui/draw.asm"
@ -102,123 +105,123 @@ reset:
push cs push cs
pop ds pop ds
; Init du système GUI ; Init du système GUI
call gui_init_system call gui_init_system
call build_interface call build_interface
main_loop: main_loop:
; 2. Moteur GUI (Gère tout : Loop, HitTest, Draw, Callbacks) call gui_process_all
; DS pointe déjà sur GUI_RAM_SEG
call gui_process_all
; 3. Afficher souris GUI GUI_GET_VAL, 5 ; slider
; GFX MOUSE_MOVE
jmp main_loop ;GFX GOTOXY, 5, 20
;call print_word_hex
jmp main_loop
; --- Callbacks (Fonctions appelées par le moteur) --- ; --- Callbacks (Fonctions appelées par le moteur) ---
on_click_quit: on_click_quit:
hlt hlt
jmp on_click_quit jmp on_click_quit
build_interface: build_interface:
; --- CRÉATION DYNAMIQUE DES BOUTONS --- ; --- CRÉATION DYNAMIQUE DES BOUTONS ---
; On reste dans CS pour lire les arguments, ; On reste dans CS pour lire les arguments,
; mais on configure DS=GUI_RAM_SEG pour l'allocation ; mais on configure DS=GUI_RAM_SEG pour l'allocation
; Créer Bouton 1 "QUITTER" ; Créer Bouton 1 "QUITTER"
call gui_alloc_widget ; Retourne SI = Pointeur nouveau slot call gui_alloc_widget ; Retourne SI = Pointeur nouveau slot
jc .mem_full jc .mem_full
; Remplir les propriétés ; Remplir les propriétés
mov word [gs:si + widget.x], 10 mov word [gs:si + widget.x], 10
mov word [gs:si + widget.y], 10 mov word [gs:si + widget.y], 10
mov word [gs:si + widget.w], 80 mov word [gs:si + widget.w], 80
mov word [gs:si + widget.h], 16 mov word [gs:si + widget.h], 16
mov word [gs:si + widget.text_ofs], str_quit mov word [gs:si + widget.text_ofs], str_quit
; mov byte [gs:si + widget.user_id], 1 ; Style "Bouton par défaut" (OK) ; mov byte [gs:si + widget.user_id], 1 ; Style "Bouton par défaut" (OK)
mov word [gs:si + widget.text_seg], cs ; Texte est dans la ROM mov word [gs:si + widget.text_seg], cs ; Texte est dans la ROM
mov word [gs:si + widget.event_click], on_click_quit ; Fonction à appeler mov word [gs:si + widget.event_click], on_click_quit ; Fonction à appeler
mov byte [gs:si + widget.type], WIDGET_TYPE_ROUND_BUTTON mov byte [gs:si + widget.type], WIDGET_TYPE_ROUND_BUTTON
; Créer Bouton 2 "HELLO" ; Créer Bouton 2 "HELLO"
call gui_alloc_widget call gui_alloc_widget
jc .mem_full jc .mem_full
mov word [gs:si + widget.x], 100 mov word [gs:si + widget.x], 100
mov word [gs:si + widget.y], 50 mov word [gs:si + widget.y], 50
mov word [gs:si + widget.w], 80 mov word [gs:si + widget.w], 80
mov word [gs:si + widget.h], 16 mov word [gs:si + widget.h], 16
mov word [gs:si + widget.text_ofs], str_hello mov word [gs:si + widget.text_ofs], str_hello
mov word [gs:si + widget.text_seg], cs mov word [gs:si + widget.text_seg], cs
mov byte [gs:si + widget.type], WIDGET_TYPE_ROUND_BUTTON mov byte [gs:si + widget.type], WIDGET_TYPE_ROUND_BUTTON
; Créer checkbox 3 "option 1" ; Créer checkbox 3 "option 1"
call gui_alloc_widget call gui_alloc_widget
jc .mem_full jc .mem_full
mov word [gs:si + widget.x], 200 mov word [gs:si + widget.x], 200
mov word [gs:si + widget.y], 50 mov word [gs:si + widget.y], 50
mov word [gs:si + widget.w], 100 mov word [gs:si + widget.w], 100
mov word [gs:si + widget.h], 15 mov word [gs:si + widget.h], 15
mov word [gs:si + widget.text_ofs], str_option1 mov word [gs:si + widget.text_ofs], str_option1
mov word [gs:si + widget.text_seg], cs mov word [gs:si + widget.text_seg], cs
mov byte [gs:si + widget.type], WIDGET_TYPE_CHECKBOX mov byte [gs:si + widget.type], WIDGET_TYPE_CHECKBOX
; Pas de callback ; Pas de callback
; Créer checkbox 3 "option 2" ; Créer checkbox 3 "option 2"
call gui_alloc_widget call gui_alloc_widget
jc .mem_full jc .mem_full
mov word [gs:si + widget.x], 200 mov word [gs:si + widget.x], 200
mov word [gs:si + widget.y], 50+16 mov word [gs:si + widget.y], 50+16
mov word [gs:si + widget.w], 100 mov word [gs:si + widget.w], 100
mov word [gs:si + widget.h], 15 mov word [gs:si + widget.h], 15
mov word [gs:si + widget.text_ofs], str_option2 mov word [gs:si + widget.text_ofs], str_option2
mov word [gs:si + widget.text_seg], cs mov word [gs:si + widget.text_seg], cs
mov byte [gs:si + widget.type], WIDGET_TYPE_CHECKBOX mov byte [gs:si + widget.type], WIDGET_TYPE_CHECKBOX
; Créer checkbox 3 "option 2" ; Créer checkbox 3 "option 2"
call gui_alloc_widget call gui_alloc_widget
jc .mem_full jc .mem_full
mov word [gs:si + widget.x], 200 mov word [gs:si + widget.x], 200
mov word [gs:si + widget.y], 50+16*2 mov word [gs:si + widget.y], 50+16*2
mov word [gs:si + widget.w], 100 mov word [gs:si + widget.w], 100
mov word [gs:si + widget.h], 15 mov word [gs:si + widget.h], 15
mov word [gs:si + widget.text_ofs], str_option3 mov word [gs:si + widget.text_ofs], str_option3
mov word [gs:si + widget.text_seg], cs mov word [gs:si + widget.text_seg], cs
mov byte [gs:si + widget.type], WIDGET_TYPE_CHECKBOX mov byte [gs:si + widget.type], WIDGET_TYPE_CHECKBOX
; Créer Slider (Drag) ; Créer Slider (Drag)
call gui_alloc_widget call gui_alloc_widget
jc .mem_full jc .mem_full
mov word [gs:si + widget.x], 10 mov word [gs:si + widget.x], 10
mov word [gs:si + widget.y], 100 mov word [gs:si + widget.y], 100
mov word [gs:si + widget.w], 150 mov word [gs:si + widget.w], 150
mov word [gs:si + widget.h], 12 mov word [gs:si + widget.h], 12
mov byte [gs:si + widget.type], WIDGET_TYPE_SLIDER mov byte [gs:si + widget.type], WIDGET_TYPE_SLIDER
mov byte [gs:si + widget.attr_mode], SLIDER_HORIZONTAL mov byte [gs:si + widget.attr_mode], SLIDER_HORIZONTAL
mov word [gs:si + widget.attr_min], 10 ; X Min mov word [gs:si + widget.attr_min], 10 ; X Min
mov word [gs:si + widget.attr_max], 140 ; X Max (Widget.x + W - ThumbW) mov word [gs:si + widget.attr_max], 140 ; X Max (Widget.x + W - ThumbW)
mov word [gs:si + widget.attr_val], 10 ; Position initiale mov word [gs:si + widget.attr_val], 10 ; Position initiale
mov byte [gs:si + widget.thumb_pct], 15 ; Curseur fait 15% de la largeur mov byte [gs:si + widget.thumb_pct], 15 ; Curseur fait 15% de la largeur
; mov word [gs:si + widget.event_drag], on_drag_slider ; mov word [gs:si + widget.event_drag], on_drag_slider
; Créer Slider (Drag) ; Créer Slider (Drag)
call gui_alloc_widget call gui_alloc_widget
jc .mem_full jc .mem_full
mov word [gs:si + widget.x], 400 mov word [gs:si + widget.x], 400
mov word [gs:si + widget.y], 10 mov word [gs:si + widget.y], 10
mov word [gs:si + widget.w], 16 mov word [gs:si + widget.w], 16
mov word [gs:si + widget.h], 150 mov word [gs:si + widget.h], 150
mov byte [gs:si + widget.type], WIDGET_TYPE_SLIDER mov byte [gs:si + widget.type], WIDGET_TYPE_SLIDER
mov byte [gs:si + widget.attr_mode], SLIDER_VERTICAL mov byte [gs:si + widget.attr_mode], SLIDER_VERTICAL
mov word [gs:si + widget.attr_min], 10 ; X Min mov word [gs:si + widget.attr_min], 10 ; X Min
mov word [gs:si + widget.attr_max], 140 ; X Max (Widget.x + W - ThumbW) mov word [gs:si + widget.attr_max], 140 ; X Max (Widget.x + W - ThumbW)
mov word [gs:si + widget.attr_val], 140 ; Position initiale mov word [gs:si + widget.attr_val], 140 ; Position initiale
mov byte [gs:si + widget.thumb_pct], 25 ; Curseur fait 15% de la largeur mov byte [gs:si + widget.thumb_pct], 25 ; Curseur fait 15% de la largeur
; mov word [gs:si + widget.event_drag], on_drag_slider ; mov word [gs:si + widget.event_drag], on_drag_slider
.mem_full: .mem_full:

View file

@ -29,29 +29,29 @@
; ============================================================================= ; =============================================================================
dump_ram_words: dump_ram_words:
jcxz .done ; Sécurité : si CX=0, on sort jcxz .done ; Sécurité : si CX=0, on sort
.loop: .loop:
lodsw ; Charge [DS:SI] dans AX et incrémente SI de 2 lodsw ; Charge [DS:SI] dans AX et incrémente SI de 2
; Note: x86 est Little Endian. Si RAM = 12 34, ; Note: x86 est Little Endian. Si RAM = 12 34,
; AX vaudra 0x3412. ; AX vaudra 0x3412.
push cx ; Sauvegarde le compteur de boucle principal push cx ; Sauvegarde le compteur de boucle principal
push si ; Sauvegarde le pointeur (si cga_putc le modifie) push si ; Sauvegarde le pointeur (si cga_putc le modifie)
call print_word_hex ; Affiche AX sous forme "XXXX" call print_word_hex ; Affiche AX sous forme "XXXX"
; (Optionnel) Ajouter un espace entre chaque mot pour la lisibilité ; (Optionnel) Ajouter un espace entre chaque mot pour la lisibilité
mov al, ' ' mov al, ' '
call cga_putc call cga_putc
pop si ; Restaure SI pop si ; Restaure SI
pop cx ; Restaure CX pop cx ; Restaure CX
loop .loop ; Décrémente CX et boucle si != 0 loop .loop ; Décrémente CX et boucle si != 0
.done: .done:
ret ret
; ============================================================================= ; =============================================================================
; Fonction : print_word_hex ; Fonction : print_word_hex
@ -60,31 +60,30 @@ dump_ram_words:
; Sortie : Affiche "1A2B" via cga_putc ; Sortie : Affiche "1A2B" via cga_putc
; ============================================================================= ; =============================================================================
print_word_hex: print_word_hex:
pusha pusha
mov dx, ax mov dx, ax
mov cx, 4 ; 4 caractères hex dans un mot de 16 bits mov cx, 4 ; 4 caractères hex dans un mot de 16 bits
.next_digit: .next_digit:
; On veut afficher les bits 12-15 d'abord. ; On veut afficher les bits 12-15 d'abord.
; L'astuce est de faire une rotation à gauche de 4 bits. ; L'astuce est de faire une rotation à gauche de 4 bits.
; Le quartet de poids fort se retrouve en bas (bits 0-3). ; Le quartet de poids fort se retrouve en bas (bits 0-3).
rol dx, 4 rol dx, 4
mov ax, dx ; Copie temporaire mov ax, dx ; Copie temporaire
and al, 0x0F ; On isole les 4 derniers bits (0 à 15) and al, 0x0F ; On isole les 4 derniers bits (0 à 15)
call nibble_to_ascii ; Convertit AL en caractère ASCII call nibble_to_ascii ; Convertit AL en caractère ASCII
; call cga_putc ; Affiche le caractère xor bx, bx
xor bx, bx mov bl, al
mov bl, al push bx
push bx call cga_putc
call cga_putc add sp, 2
add sp, 2 loop .next_digit ; Répète 4 fois
loop .next_digit ; Répète 4 fois
popa popa
ret ret
; ============================================================================= ; =============================================================================
; Fonction : nibble_to_ascii ; Fonction : nibble_to_ascii
@ -93,12 +92,12 @@ print_word_hex:
; Sortie : AL (caractère '0'-'9' ou 'A'-'F') ; Sortie : AL (caractère '0'-'9' ou 'A'-'F')
; ============================================================================= ; =============================================================================
nibble_to_ascii: nibble_to_ascii:
cmp al, 9 cmp al, 9
ja .letter ; Si > 9, c'est une lettre (A-F) ja .letter ; Si > 9, c'est une lettre (A-F)
; Sinon c'est un chiffre : 0x0 -> '0'
add al, '0'
ret
add al, '0' ; Sinon c'est un chiffre : 0x0 -> '0' .letter: ; Convertit 10 -> 'A', 11 -> 'B', etc.
ret add al, 'A' - 10
ret
.letter:
add al, 'A' - 10 ; Convertit 10 -> 'A', 11 -> 'B', etc.
ret

294
src/common/memory.asm Normal file
View file

@ -0,0 +1,294 @@
; =============================================================================
; Project : Custom BIOS / ROM
; File : memory.asm
; Author : Gemini
;
; Description :
; Gestionnaire de mémoire dynamique (Heap) simple pour mode réel.
; Utilise un algorithme "First-Fit" avec fusion des blocs libres (coalescing).
;
; Layout Mémoire :
; [STATUS (1b)] [SIZE (2b)] [NEXT (2b)] [ DATA ... ]
;
; =============================================================================
%define MEM_HEAP_SEG 0x2000 ; Segment du tas (Phys: 0x20000)
%define MEM_HEAP_SIZE 0x8000 ; Taille totale (32 Ko)
%define MEM_STATUS_FREE 0
%define MEM_STATUS_USED 1
; --- API Codes ---
%define MEM_ALLOC 0
%define MEM_GET_SIZE 1
%define MEM_FREE 2
%define MEM_RESOLVE 3
; --- Macro API ---
; Usage: MEM FUNCTION, [ARG1], [ARG2]...
%macro MEM 1-*
%rep %0 - 1
%rotate -1
push %1
%endrep
%rotate -1
call word [cs:mem_api_table + ((%1)*2)]
add sp, (%0 - 1) * 2
%endmacro
mem_api_table:
dw mem_alloc
dw mem_get_size
dw mem_free
dw mem_resolve
struc mem_block
.status resb 1 ; État du bloc (0=Libre, 1=Occupé)
.size resw 1 ; Taille des données (sans le header)
.next resw 1 ; Offset du prochain bloc (0 = Fin)
endstruc
; -----------------------------------------------------------------------------
; mem_init
; Initialise le gestionnaire de mémoire.
; Crée un seul gros bloc libre couvrant tout le segment.
; -----------------------------------------------------------------------------
mem_init:
push ax
push es
push di
mov ax, MEM_HEAP_SEG
mov es, ax
xor di, di
; Initialisation du premier bloc (Header)
mov byte [es:di + mem_block.status], MEM_STATUS_FREE
; Taille disponible = Total - TailleHeader
mov ax, MEM_HEAP_SIZE
sub ax, mem_block_size
mov word [es:di + mem_block.size], ax
mov word [es:di + mem_block.next], 0
pop di
pop es
pop ax
ret
; -----------------------------------------------------------------------------
; mem_alloc
; Alloue un bloc de mémoire.
;
; Stack: [BP+4] = Taille demandée (word)
; Output: AX = Handle (Offset du bloc de données) ou 0 si échec
; -----------------------------------------------------------------------------
mem_alloc:
push bp
mov bp, sp
sub sp, 2
%define .curr_ptr word [bp-2]
%define .size_requested word [bp+4]
push bx
push cx
push es
push di
mov .curr_ptr, 0 ; On commence la recherche à l'offset 0
mov ax, MEM_HEAP_SEG
mov es, ax
.scan_loop:
mov di, .curr_ptr ; DI = Ptr courant
; 1. Le bloc est-il LIBRE ?
cmp byte [es:di + mem_block.status], MEM_STATUS_FREE
jne .next_block
; 2. Tentative de FUSION (Coalescing) avec les blocs suivants
.try_merge:
mov bx, [es:di + mem_block.next]
cmp bx, 0
je .check_size ; Pas de suivant, on vérifie la taille
; Si le suivant est aussi libre, on fusionne
cmp byte [es:bx + mem_block.status], MEM_STATUS_FREE
jne .check_size
; Nouvelle Taille = TailleActuelle + Header + TailleSuivant
mov ax, [es:bx + mem_block.size]
add ax, mem_block_size
add [es:di + mem_block.size], ax
; Mise à jour du chainage (saute le bloc fusionné)
mov ax, [es:bx + mem_block.next]
mov [es:di + mem_block.next], ax
jmp .try_merge ; On boucle pour voir si le suivant du suivant est libre
.check_size:
; 3. Vérifier si la taille est suffisante
mov ax, .size_requested ; Taille demandée (Argument)
cmp [es:di + mem_block.size], ax
jb .next_block ; Trop petit
; 4. Allocation (Split si possible)
; Calculer l'espace restant
mov cx, [es:di + mem_block.size]
sub cx, ax ; CX = Reste
; Peut-on créer un nouveau bloc dans le reste ? (Header + au moins 1 octet)
cmp cx, mem_block_size + 1
jb .allocate_full
; --- SPLIT ---
; Marquer le bloc actuel comme utilisé avec la taille demandée
mov byte [es:di + mem_block.status], MEM_STATUS_USED
mov [es:di + mem_block.size], ax
; Créer le nouveau header dans l'espace restant
mov bx, di
add bx, mem_block_size
add bx, ax ; BX = Offset du nouveau bloc
mov byte [es:bx + mem_block.status], MEM_STATUS_FREE
sub cx, mem_block_size ; Taille utile du nouveau bloc
mov [es:bx + mem_block.size], cx
; Insérer dans la liste chainée
mov dx, [es:di + mem_block.next]
mov [es:bx + mem_block.next], dx
mov [es:di + mem_block.next], bx
jmp .success
.allocate_full:
; On prend tout le bloc sans le couper
mov byte [es:di + mem_block.status], MEM_STATUS_USED
.success:
; Retourner le handle (Offset des DONNÉES = DI + Header)
mov ax, di
add ax, mem_block_size
jmp .done
.next_block:
; Passer au bloc suivant
mov di, .curr_ptr
mov ax, [es:di + mem_block.next]
mov .curr_ptr, ax
cmp ax, 0
jne .scan_loop
; Échec : Plus de mémoire ou fragmentation trop élevée
xor ax, ax
.done:
pop di
pop es
pop cx
pop bx
%undef .curr_ptr
%undef .size_requested
leave ; Restaure SP et BP
ret
; -----------------------------------------------------------------------------
; mem_free
; Libère un bloc mémoire.
; Stack: [BP+4] = Handle (word)
; -----------------------------------------------------------------------------
mem_free:
push bp
mov bp, sp
%define .handle word [bp+4]
push es
push di
push bx
mov ax, .handle ; Handle
test ax, ax
jz .done ; Sécurité Handle NULL
mov bx, MEM_HEAP_SEG
mov es, bx
; Retrouver le header (Handle - HeaderSize)
mov di, ax
sub di, mem_block_size
; Marquer simplement comme libre (le coalescing se fera au prochain alloc)
mov byte [es:di + mem_block.status], MEM_STATUS_FREE
.done:
pop bx
pop di
pop es
%undef .handle
leave
ret
; -----------------------------------------------------------------------------
; mem_get_size
; Retourne la taille utile d'un bloc.
; Stack: [BP+4] = Handle (word)
; Output: AX = Taille
; -----------------------------------------------------------------------------
mem_get_size:
push bp
mov bp, sp
%define .handle word [bp+4]
push es
push di
mov ax, .handle ; Handle
test ax, ax
jz .error
mov bx, MEM_HEAP_SEG
mov es, bx
mov di, ax
sub di, mem_block_size
mov ax, [es:di + mem_block.size]
jmp .done
.error:
xor ax, ax
.done:
pop di
pop es
%undef .handle
leave
ret
; -----------------------------------------------------------------------------
; mem_resolve
; Convertit un handle en pointeur complet Segment:Offset.
; Stack: [BP+4] = Handle (word)
; Output: DX:AX = Segment:Offset
; ES:DI = Segment:Offset (pour utilisation immédiate avec stos/movs)
; -----------------------------------------------------------------------------
mem_resolve:
push bp
mov bp, sp
mov ax, [bp+4] ; Handle
mov dx, MEM_HEAP_SEG
mov es, dx
mov di, ax ; L'offset est le handle lui-même
; DX contient déjà le segment, AX contient déjà l'offset
leave
ret

21
src/common/patterns.asm Normal file
View file

@ -0,0 +1,21 @@
; =============================================================================
; SECTION : PATTERNS & FILL
; https://paulsmith.github.io/classic-mac-patterns/
; =============================================================================
;
; pattern ID
%define PATTERN_BLACK 0
%define PATTERN_GRAY_DARK 1
%define PATTERN_GRAY_MID 2
%define PATTERN_GRAY_LIGHT 3
%define PATTERN_WHITE_LIGHT 4
%define PATTERN_WHITE 5
align 8
pattern_8x8:
dq 0x0000000000000000 ; pattern_black (Tout à 0 = Noir)
dq 0x2200880022008800 ; pattern_gray_dark (Majorité de 0)
dq 0x2288228822882288 ; pattern_gray_mid
dq 0xAA55AA55AA55AA55 ; pattern_gray_light (50/50)
dq 0x77DD77DD77DD77DD ; pattern_white_light (Majorité de 1 = Clair)
dq 0xFFFFFFFFFFFFFFFF ; pattern_white (Tout à 1 = Blanc)

View file

@ -106,29 +106,6 @@ graph_driver:
dw cga_mouse_show ; déplacement du curseur dw cga_mouse_show ; déplacement du curseur
dw cga_mouse_cursor_move ; déplacement du curseur dw cga_mouse_cursor_move ; déplacement du curseur
; =============================================================================
; SECTION : PATTERNS & FILL
; https://paulsmith.github.io/classic-mac-patterns/
; =============================================================================
;
; pattern ID
%define PATTERN_BLACK 0
%define PATTERN_GRAY_DARK 1
%define PATTERN_GRAY_MID 2
%define PATTERN_GRAY_LIGHT 3
%define PATTERN_WHITE_LIGHT 4
%define PATTERN_WHITE 5
align 8
pattern_8x8:
dq 0x0000000000000000 ; pattern_black (Tout à 0 = Noir)
dq 0x2200880022008800 ; pattern_gray_dark (Majorité de 0)
dq 0x2288228822882288 ; pattern_gray_mid
dq 0xAA55AA55AA55AA55 ; pattern_gray_light (50/50)
dq 0x77DD77DD77DD77DD ; pattern_white_light (Majorité de 1 = Clair)
dq 0xFFFFFFFFFFFFFFFF ; pattern_white (Tout à 1 = Blanc)
; ------------------------------------------------------------ ; ------------------------------------------------------------
; initialise le mode graphique (via l'int 10h) ; initialise le mode graphique (via l'int 10h)
; ;

View file

@ -1,196 +0,0 @@
; =======================
; API
; =======================
%define MEM_INIT 0
%define MEM_DETECT 2
%define MEM_ALLOC 4
%define MEM_FREE 6
%define MEM_DUMP_RESET 8
%define MEM_DUMP_NEXT 10
memory_api:
dw mem_init
dw mem_detect
dw mem_alloc
dw mem_free
dw mem_dump_reset
dw mem_dump_next
; =======================
; Contexte en RAM (DS = CTX_SEG)
; =======================
heap_seg dw 0
heap_start dw 0
heap_end dw 0
free_head dw 0
dump_cursor dw 0
; =======================
; Constantes
; =======================
%define HDR_SIZE 8
%define FTR_SIZE 2
%define MIN_BLK 12 ; aligné (>= HDR+FTR)
%define FLAG_USED 1
%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
; ---------------------------------------------------------------------------
; Détection RAM conventionnelle
; Teste la RAM de MEM_SEG_DEB -> MEM_SEG_END (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 jusquau “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 MEM_SEG_END (0xA000: début VGA/vidéo).
; ---------------------------------------------------------------------------
memory_setup:
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 d1KB
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
; -----------------------
; mem_detect
; AX=conv_kb, DX=ebda_seg, CF=0
; -----------------------
mem_detect:
push ds
xor ax, ax
int 12h ; AX = KiB conventionnelle
mov bx, ax ; conv_kb -> BX
; Lire EBDA segment depuis BDA:040Eh
; On suppose DS peut être changé temporairement
mov ax, 0x0040
mov ds, ax
mov dx, [0x000E] ; EBDA segment (souvent 0x9FC0 etc), 0 si absent
pop ds
mov ax, bx ; AX=conv_kb
clc
ret
; -----------------------
; mem_init
; Entrée (proposée) :
; AX = HEAP_SEG (0 => auto)
; BX = heap_start_offset (0 => défaut 0x0200)
; Sortie:
; CF=0 ok, CF=1 err
; -----------------------
mem_init:
; 1) déterminer heap_seg et heap_end en évitant EBDA
; 2) créer 1 seul bloc libre [heap_start..heap_end)
; Implémentation typique:
; - si AX=0 : choisir un segment RAM “safe” (ex: 0x7000) OU segment du contexte
; - heap_start = (BX!=0 ? BX : 0x0200)
; - heap_end = 0xFFFE (ou plus petit selon usage)
; Puis initialiser le 1er bloc libre:
; [heap_start+0] size = heap_end-heap_start
; [heap_start+2] flags=0
; [heap_start+4] next_free=0
; [heap_start+6] prev_free=0
; footer à (heap_start+size-2)
clc
ret
; -----------------------
; mem_alloc
; CX = bytes demandés
; Sortie: ES=heap_seg, DI=payload, CF=0 si ok sinon CF=1
; -----------------------
mem_alloc:
; need = align2(CX) + HDR_SIZE + FTR_SIZE
; parcourir free list (first-fit)
; split si reste >= MIN_BLK
; marquer alloué, unlink free list
; ES=heap_seg, DI=blk_off + HDR_SIZE
ret
; -----------------------
; mem_free
; Entrée: ES:DI = payload
; Sortie: CF=0 ok sinon CF=1
; -----------------------
mem_free:
; blk_off = DI - HDR_SIZE
; vérifier, marquer libre
; coalescer prev/next via footer/header
; relinker dans free list
ret
; -----------------------
; mem_dump_reset / mem_dump_next
; -----------------------
mem_dump_reset:
mov ax, [heap_start]
mov [dump_cursor], ax
clc
ret
mem_dump_next:
; si dump_cursor >= heap_end => CF=1
; lire size/flags à dump_cursor
; renvoyer AL état, CX taille payload, DI=offset header, ES=heap_seg
; dump_cursor += size
ret

View file

@ -1,6 +1,6 @@
; ============================================================================= ; =============================================================================
; Project : Custom BIOS / ROM ; Project : Custom BIOS / ROM
; File : gui_lib.asm ; File : gui/draw.asm
; Author : frater ; Author : frater
; ;
; License : GNU General Public License v3.0 or later (GPL-3.0+) ; License : GNU General Public License v3.0 or later (GPL-3.0+)

View file

@ -1,6 +1,6 @@
; ============================================================================= ; =============================================================================
; Project : Custom BIOS / ROM ; Project : Custom BIOS / ROM
; File : gui_lib.asm ; File : gui/lib.asm
; Author : frater ; Author : frater
; ;
; License : GNU General Public License v3.0 or later (GPL-3.0+) ; License : GNU General Public License v3.0 or later (GPL-3.0+)
@ -21,7 +21,7 @@
; ============================================================================= ; =============================================================================
; --- Configuration --- ; --- Configuration ---
%define GUI_RAM_SEG 0x0A00 ; Segment de données UI %define GUI_RAM_SEG 0x1800 ; Segment de données UI (Safe: après Stack, avant Heap)
%define GUI_MAX_WIDGETS 32 ; Nombre max de widgets simultanés %define GUI_MAX_WIDGETS 32 ; Nombre max de widgets simultanés
; Dimensions ; Dimensions
@ -47,6 +47,23 @@
%define SLIDER_HORIZONTAL 1 %define SLIDER_HORIZONTAL 1
%define SLIDER_VERTICAL 2 %define SLIDER_VERTICAL 2
; =============================================================================
; SECTION : API ACTIONS
; =============================================================================
%define GUI_CREATE 0
%define GUI_DESTROY 1
%define GUI_GET_STATE 2
%define GUI_GET_TYPE 3
%define GUI_GET_VAL 4
gui_api_table:
dw gui_api_create
dw gui_api_destroy
dw gui_api_get_state
dw gui_api_get_type
dw gui_api_get_val
; --- Structure d'un OBJET (Bouton, etc) --- ; --- Structure d'un OBJET (Bouton, etc) ---
struc widget struc widget
.state resb 1 ; État (0=libre, >0=utilisé) .state resb 1 ; État (0=libre, >0=utilisé)
@ -78,10 +95,6 @@ struc widget
alignb 2 ; Alignement mémoire pour performance alignb 2 ; Alignement mémoire pour performance
endstruc endstruc
; =============================================================================
; SECTION : API ACTIONS
; =============================================================================
%macro GUI 1-* %macro GUI 1-*
%rep %0 - 1 %rep %0 - 1
%rotate -1 %rotate -1
@ -92,19 +105,6 @@ endstruc
add sp, (%0 - 1) * 2 add sp, (%0 - 1) * 2
%endmacro %endmacro
%define GUI_CREATE 0
%define GUI_DESTROY 1
%define GUI_GET_STATE 2
%define GUI_GET_TYPE 3
%define GUI_GET_VAL 4
gui_api_table:
dw gui_api_create
dw gui_api_destroy
dw gui_api_get_state
dw gui_api_get_type
dw gui_api_get_val
; ----------------------------------------------------------------------------- ; -----------------------------------------------------------------------------
; gui_api_create ; gui_api_create
; Crée un widget et retourne son ID ; Crée un widget et retourne son ID

View file

@ -1,6 +1,6 @@
; ============================================================================= ; =============================================================================
; Project : Custom BIOS / ROM ; Project : Custom BIOS / ROM
; File : gui_window.asm ; File : gui/window.asm
; Author : frater ; Author : frater
; ;
; License : GNU General Public License v3.0 or later (GPL-3.0+) ; License : GNU General Public License v3.0 or later (GPL-3.0+)