fix memory map doc

This commit is contained in:
Frater 2026-02-07 16:53:16 +01:00
commit 24a59171e5
3 changed files with 179 additions and 176 deletions

View file

@ -11,10 +11,10 @@ The processor starts in Real Mode, addressing 1 MB of memory.
| **`0x00000`** | **`0x003FF`** | 1 KB | **IVT** (Interrupt Vector Table) | `0x0000` | `memory.asm` | | **`0x00000`** | **`0x003FF`** | 1 KB | **IVT** (Interrupt Vector Table) | `0x0000` | `memory.asm` |
| **`0x00400`** | **`0x004FF`** | 256 B | **BDA** (BIOS Data Area) Standard | `0x0040` | `memory.asm` | | **`0x00400`** | **`0x004FF`** | 256 B | **BDA** (BIOS Data Area) Standard | `0x0040` | `memory.asm` |
| **`0x00500`** | **`0x005FF`** | ~256 B | **Custom BDA** (Driver Data) | `0x0050` | `memory.asm` | | **`0x00500`** | **`0x005FF`** | ~256 B | **Custom BDA** (Driver Data) | `0x0050` | `memory.asm` |
| **`0x00600`** | **`0x07FFF`** | 30.5 KB | **Free** (Low Memory) | | | | **`0x00600`** | **`0x00AFF`** | 1.25 KB | **GUI RAM** (Widget Allocation) | `0x0060` | `gui/lib.asm` |
| **`0x00B00`** | **`0x07FFF`** | 29 KB | **Free** (Low Memory) | | |
| **`0x08000`** | **`0x17FFF`** | 64 KB | **Stack** (Grows downwards) | `0x0800` | `memory.asm` | | **`0x08000`** | **`0x17FFF`** | 64 KB | **Stack** (Grows downwards) | `0x0800` | `memory.asm` |
| **`0x18000`** | **`0x18FFF`** | ~4 KB | **GUI RAM** (Widget Allocation) | `0x0A00` | `gui/lib.asm` | | **`0x18000`** | **`0x9FBFF`** | 543 KB | **Free** (Conventional RAM) | | |
| **`0x19000`** | **`0x9FBFF`** | 539 KB | **Free** (Conventional RAM) | | |
| **`0x9FC00`** | **`0x9FFFF`** | 1 KB | **EBDA** (Extended BIOS Data Area) | `0x9FC0` | `memory.asm` | | **`0x9FC00`** | **`0x9FFFF`** | 1 KB | **EBDA** (Extended BIOS Data Area) | `0x9FC0` | `memory.asm` |
| **`0xA0000`** | **`0xAFFFF`** | 64 KB | **VGA RAM** (Graphics Modes) | `0xA000` | `Hardware` | | **`0xA0000`** | **`0xAFFFF`** | 64 KB | **VGA RAM** (Graphics Modes) | `0xA000` | `Hardware` |
| **`0xB0000`** | **`0xB7FFF`** | 32 KB | **MDA RAM** (Monochrome Text) | `0xB000` | `Hardware` | | **`0xB0000`** | **`0xB7FFF`** | 32 KB | **MDA RAM** (Monochrome Text) | `0xB000` | `Hardware` |
@ -42,8 +42,8 @@ The project separates the standard IBM BDA from its own variables to avoid confl
#### Stack & GUI RAM #### Stack & GUI RAM
* **Stack**: Segment `0x0800`, SP `0xFFFE`. Grows downwards from physical address `0x17FFE`. * **Stack**: Segment `0x0800`, SP `0xFFFE`. Grows downwards from physical address `0x17FFE`.
* **GUI RAM**: Segment `0x0A00` (Physical `0x0A000`). * **GUI RAM**: Segment `0x0060` (Physical `0x00600`).
* **Layout**: The GUI RAM sits at the "bottom" of the stack segment's physical range, but since the stack starts at the top (`0x17FFE`) and grows down, there is approximately **56 KB** of safe space before collision. * **Layout**: Located in low memory (`0x00600`) to avoid any collision with the Stack (`0x08000`).
#### Video RAM (CGA High-Res) #### Video RAM (CGA High-Res)
* **Segment**: `0xB800` * **Segment**: `0xB800`
@ -73,10 +73,10 @@ Le processeur démarre en mode réel, adressant 1 Mo de mémoire.
| **`0x00000`** | **`0x003FF`** | 1 Ko | **IVT** (Interrupt Vector Table) | `0x0000` | `memory.asm` | | **`0x00000`** | **`0x003FF`** | 1 Ko | **IVT** (Interrupt Vector Table) | `0x0000` | `memory.asm` |
| **`0x00400`** | **`0x004FF`** | 256 o | **BDA** (BIOS Data Area) Standard | `0x0040` | `memory.asm` | | **`0x00400`** | **`0x004FF`** | 256 o | **BDA** (BIOS Data Area) Standard | `0x0040` | `memory.asm` |
| **`0x00500`** | **`0x005FF`** | ~256 o | **Custom BDA** (Données Drivers) | `0x0050` | `memory.asm` | | **`0x00500`** | **`0x005FF`** | ~256 o | **Custom BDA** (Données Drivers) | `0x0050` | `memory.asm` |
| **`0x00600`** | **`0x07FFF`** | 30.5 Ko | **Libre** (Mémoire Basse) | | | | **`0x00600`** | **`0x00AFF`** | 1.25 Ko | **GUI RAM** (Allocation Widgets) | `0x0060` | `gui/lib.asm` |
| **`0x08000`** | **`0x17FFF`** | 64 KB | **Stack** (Grows downwards) | `0x0800` | `memory.asm` | | **`0x00B00`** | **`0x07FFF`** | 29 Ko | **Libre** (Mémoire Basse) | | |
| **`0x18000`** | **`0x18FFF`** | ~4 KB | **GUI RAM** (Widget Allocation) | `0x0A00` | `gui/lib.asm` | | **`0x08000`** | **`0x17FFF`** | 64 Ko | **Pile** (Stack) | `0x0800` | `memory.asm` |
| **`0x19000`** | **`0x9FBFF`** | 539 Ko | **Libre** (RAM Conventionnelle) | | | | **`0x18000`** | **`0x9FBFF`** | 543 Ko | **Libre** (RAM Conventionnelle) | | |
| **`0x9FC00`** | **`0x9FFFF`** | 1 Ko | **EBDA** (Extended BIOS Data Area) | `0x9FC0` | `memory.asm` | | **`0x9FC00`** | **`0x9FFFF`** | 1 Ko | **EBDA** (Extended BIOS Data Area) | `0x9FC0` | `memory.asm` |
| **`0xA0000`** | **`0xAFFFF`** | 64 Ko | **VGA RAM** (Modes Graphiques) | `0xA000` | `Matériel` | | **`0xA0000`** | **`0xAFFFF`** | 64 Ko | **VGA RAM** (Modes Graphiques) | `0xA000` | `Matériel` |
| **`0xB0000`** | **`0xB7FFF`** | 32 Ko | **MDA RAM** (Texte Monochrome) | `0xB000` | `Matériel` | | **`0xB0000`** | **`0xB7FFF`** | 32 Ko | **MDA RAM** (Texte Monochrome) | `0xB000` | `Matériel` |
@ -104,8 +104,8 @@ Le projet sépare la BDA standard IBM de ses propres variables pour éviter les
#### Stack & GUI RAM #### Stack & GUI RAM
* **Stack** : Segment `0x0800`, SP `0xFFFE`. Grandit vers le bas depuis l'adresse physique `0x17FFE`. * **Stack** : Segment `0x0800`, SP `0xFFFE`. Grandit vers le bas depuis l'adresse physique `0x17FFE`.
* **GUI RAM** : Segment `0x0A00` (Physique `0x0A000`). * **GUI RAM** : Segment `0x0060` (Physique `0x00600`).
* **Organisation** : La RAM GUI se trouve "en bas" de la plage physique du segment de pile, mais comme la pile commence tout en haut (`0x17FFE`) et descend, il y a environ **56 Ko** d'espace libre avant collision. * **Organisation** : Située en mémoire basse (`0x00600`) pour éviter toute collision avec la Pile (`0x08000`).
#### Video RAM (CGA High-Res) #### Video RAM (CGA High-Res)
* **Segment** : `0xB800` * **Segment** : `0xB800`

View file

@ -27,25 +27,25 @@
; --- Macro API --- ; --- Macro API ---
; Usage: MEM FUNCTION, [ARG1], [ARG2]... ; Usage: MEM FUNCTION, [ARG1], [ARG2]...
%macro MEM 1-* %macro MEM 1-*
%rep %0 - 1 %rep %0 - 1
%rotate -1 %rotate -1
push %1 push %1
%endrep %endrep
%rotate -1 %rotate -1
call word [cs:mem_api_table + ((%1)*2)] call word [cs:mem_api_table + ((%1)*2)]
add sp, (%0 - 1) * 2 add sp, (%0 - 1) * 2
%endmacro %endmacro
mem_api_table: mem_api_table:
dw mem_alloc dw mem_alloc
dw mem_get_size dw mem_get_size
dw mem_free dw mem_free
dw mem_resolve dw mem_resolve
struc mem_block struc mem_block
.status resb 1 ; État du bloc (0=Libre, 1=Occupé) .status resb 1 ; État du bloc (0=Libre, 1=Occupé)
.size resw 1 ; Taille des données (sans le header) .size resw 1 ; Taille des données (sans le header)
.next resw 1 ; Offset du prochain bloc (0 = Fin) .next resw 1 ; Offset du prochain bloc (0 = Fin)
endstruc endstruc
; ----------------------------------------------------------------------------- ; -----------------------------------------------------------------------------
@ -54,28 +54,28 @@ endstruc
; Crée un seul gros bloc libre couvrant tout le segment. ; Crée un seul gros bloc libre couvrant tout le segment.
; ----------------------------------------------------------------------------- ; -----------------------------------------------------------------------------
mem_init: mem_init:
push ax push ax
push es push es
push di push di
mov ax, MEM_HEAP_SEG mov ax, MEM_HEAP_SEG
mov es, ax mov es, ax
xor di, di xor di, di
; Initialisation du premier bloc (Header) ; Initialisation du premier bloc (Header)
mov byte [es:di + mem_block.status], MEM_STATUS_FREE mov byte [es:di + mem_block.status], MEM_STATUS_FREE
; Taille disponible = Total - TailleHeader ; Taille disponible = Total - TailleHeader
mov ax, MEM_HEAP_SIZE mov ax, MEM_HEAP_SIZE
sub ax, mem_block_size sub ax, mem_block_size
mov word [es:di + mem_block.size], ax mov word [es:di + mem_block.size], ax
mov word [es:di + mem_block.next], 0 mov word [es:di + mem_block.next], 0
pop di pop di
pop es pop es
pop ax pop ax
ret ret
; ----------------------------------------------------------------------------- ; -----------------------------------------------------------------------------
; mem_alloc ; mem_alloc
@ -84,156 +84,157 @@ mem_init:
; Stack: [BP+4] = Taille demandée (word) ; Stack: [BP+4] = Taille demandée (word)
; Output: AX = Handle (Offset du bloc de données) ou 0 si échec ; Output: AX = Handle (Offset du bloc de données) ou 0 si échec
; ----------------------------------------------------------------------------- ; -----------------------------------------------------------------------------
%define .size_requested word [bp+4]
; variables
%define .curr_ptr word [bp-2]
mem_alloc: mem_alloc:
push bp push bp
mov bp, sp mov bp, sp
sub sp, 2 sub sp, 2
%define .curr_ptr word [bp-2] push bx
%define .size_requested word [bp+4] push cx
push es
push di
push bx mov .curr_ptr, 0 ; On commence la recherche à l'offset 0
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
mov ax, MEM_HEAP_SEG
mov es, ax
.scan_loop: .scan_loop:
mov di, .curr_ptr ; DI = Ptr courant mov di, .curr_ptr ; DI = Ptr courant
; 1. Le bloc est-il LIBRE ? ; 1. Le bloc est-il LIBRE ?
cmp byte [es:di + mem_block.status], MEM_STATUS_FREE cmp byte [es:di + mem_block.status], MEM_STATUS_FREE
jne .next_block jne .next_block
; 2. Tentative de FUSION (Coalescing) avec les blocs suivants ; 2. Tentative de FUSION (Coalescing) avec les blocs suivants
.try_merge: .try_merge:
mov bx, [es:di + mem_block.next] mov bx, [es:di + mem_block.next]
cmp bx, 0 cmp bx, 0
je .check_size ; Pas de suivant, on vérifie la taille je .check_size ; Pas de suivant, on vérifie la taille
; Si le suivant est aussi libre, on fusionne ; Si le suivant est aussi libre, on fusionne
cmp byte [es:bx + mem_block.status], MEM_STATUS_FREE cmp byte [es:bx + mem_block.status], MEM_STATUS_FREE
jne .check_size jne .check_size
; Nouvelle Taille = TailleActuelle + Header + TailleSuivant ; Nouvelle Taille = TailleActuelle + Header + TailleSuivant
mov ax, [es:bx + mem_block.size] mov ax, [es:bx + mem_block.size]
add ax, mem_block_size add ax, mem_block_size
add [es:di + mem_block.size], ax add [es:di + mem_block.size], ax
; Mise à jour du chainage (saute le bloc fusionné) ; Mise à jour du chainage (saute le bloc fusionné)
mov ax, [es:bx + mem_block.next] mov ax, [es:bx + mem_block.next]
mov [es:di + mem_block.next], ax mov [es:di + mem_block.next], ax
jmp .try_merge ; On boucle pour voir si le suivant du suivant est libre jmp .try_merge ; On boucle pour voir si le suivant du suivant est libre
.check_size: .check_size:
; 3. Vérifier si la taille est suffisante ; 3. Vérifier si la taille est suffisante
mov ax, .size_requested ; Taille demandée (Argument) mov ax, .size_requested ; Taille demandée (Argument)
cmp [es:di + mem_block.size], ax cmp [es:di + mem_block.size], ax
jb .next_block ; Trop petit jb .next_block ; Trop petit
; 4. Allocation (Split si possible) ; 4. Allocation (Split si possible)
; Calculer l'espace restant ; Calculer l'espace restant
mov cx, [es:di + mem_block.size] mov cx, [es:di + mem_block.size]
sub cx, ax ; CX = Reste sub cx, ax ; CX = Reste
; Peut-on créer un nouveau bloc dans le reste ? (Header + au moins 1 octet) ; Peut-on créer un nouveau bloc dans le reste ? (Header + au moins 1 octet)
cmp cx, mem_block_size + 1 cmp cx, mem_block_size + 1
jb .allocate_full jb .allocate_full
; --- SPLIT --- ; --- SPLIT ---
; Marquer le bloc actuel comme utilisé avec la taille demandée ; Marquer le bloc actuel comme utilisé avec la taille demandée
mov byte [es:di + mem_block.status], MEM_STATUS_USED mov byte [es:di + mem_block.status], MEM_STATUS_USED
mov [es:di + mem_block.size], ax mov [es:di + mem_block.size], ax
; Créer le nouveau header dans l'espace restant ; Créer le nouveau header dans l'espace restant
mov bx, di mov bx, di
add bx, mem_block_size add bx, mem_block_size
add bx, ax ; BX = Offset du nouveau bloc add bx, ax ; BX = Offset du nouveau bloc
mov byte [es:bx + mem_block.status], MEM_STATUS_FREE mov byte [es:bx + mem_block.status], MEM_STATUS_FREE
sub cx, mem_block_size ; Taille utile du nouveau bloc sub cx, mem_block_size ; Taille utile du nouveau bloc
mov [es:bx + mem_block.size], cx mov [es:bx + mem_block.size], cx
; Insérer dans la liste chainée ; Insérer dans la liste chainée
mov dx, [es:di + mem_block.next] mov dx, [es:di + mem_block.next]
mov [es:bx + mem_block.next], dx mov [es:bx + mem_block.next], dx
mov [es:di + mem_block.next], bx mov [es:di + mem_block.next], bx
jmp .success jmp .success
.allocate_full: .allocate_full:
; On prend tout le bloc sans le couper ; On prend tout le bloc sans le couper
mov byte [es:di + mem_block.status], MEM_STATUS_USED mov byte [es:di + mem_block.status], MEM_STATUS_USED
.success: .success:
; Retourner le handle (Offset des DONNÉES = DI + Header) ; Retourner le handle (Offset des DONNÉES = DI + Header)
mov ax, di mov ax, di
add ax, mem_block_size add ax, mem_block_size
jmp .done jmp .done
.next_block: .next_block:
; Passer au bloc suivant ; Passer au bloc suivant
mov di, .curr_ptr mov di, .curr_ptr
mov ax, [es:di + mem_block.next] mov ax, [es:di + mem_block.next]
mov .curr_ptr, ax mov .curr_ptr, ax
cmp ax, 0 cmp ax, 0
jne .scan_loop jne .scan_loop
; Échec : Plus de mémoire ou fragmentation trop élevée ; Échec : Plus de mémoire ou fragmentation trop élevée
xor ax, ax xor ax, ax
.done: .done:
pop di pop di
pop es pop es
pop cx pop cx
pop bx pop bx
%undef .curr_ptr leave ; Restaure SP et BP
%undef .size_requested ret
leave ; Restaure SP et BP %undef .curr_ptr
ret %undef .size_requested
; ----------------------------------------------------------------------------- ; -----------------------------------------------------------------------------
; mem_free ; mem_free
; Libère un bloc mémoire. ; Libère un bloc mémoire.
; Stack: [BP+4] = Handle (word) ; Stack: [BP+4] = Handle (word)
; ----------------------------------------------------------------------------- ; -----------------------------------------------------------------------------
%define .handle word [bp+4]
mem_free: mem_free:
push bp push bp
mov bp, sp mov bp, sp
%define .handle word [bp+4]
push es
push di
push bx
mov ax, .handle ; Handle push es
test ax, ax push di
jz .done ; Sécurité Handle NULL push bx
mov bx, MEM_HEAP_SEG mov ax, .handle ; Handle
mov es, bx test ax, ax
jz .done ; Sécurité Handle NULL
; Retrouver le header (Handle - HeaderSize) mov bx, MEM_HEAP_SEG
mov di, ax mov es, bx
sub di, mem_block_size
; Marquer simplement comme libre (le coalescing se fera au prochain alloc) ; Retrouver le header (Handle - HeaderSize)
mov byte [es:di + mem_block.status], MEM_STATUS_FREE 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: .done:
pop bx pop bx
pop di pop di
pop es pop es
%undef .handle leave
leave ret
ret %undef .handle
; ----------------------------------------------------------------------------- ; -----------------------------------------------------------------------------
; mem_get_size ; mem_get_size
@ -241,36 +242,35 @@ mem_free:
; Stack: [BP+4] = Handle (word) ; Stack: [BP+4] = Handle (word)
; Output: AX = Taille ; Output: AX = Taille
; ----------------------------------------------------------------------------- ; -----------------------------------------------------------------------------
%define .handle word [bp+4]
mem_get_size: mem_get_size:
push bp push bp
mov bp, sp mov bp, sp
%define .handle word [bp+4] push es
push di
push es mov ax, .handle ; Handle
push di test ax, ax
jz .error
mov ax, .handle ; Handle mov bx, MEM_HEAP_SEG
test ax, ax mov es, bx
jz .error
mov bx, MEM_HEAP_SEG mov di, ax
mov es, bx sub di, mem_block_size
mov di, ax mov ax, [es:di + mem_block.size]
sub di, mem_block_size jmp .done
mov ax, [es:di + mem_block.size]
jmp .done
.error: .error:
xor ax, ax xor ax, ax
.done: .done:
pop di pop di
pop es pop es
%undef .handle leave
leave ret
ret %undef .handle
; ----------------------------------------------------------------------------- ; -----------------------------------------------------------------------------
; mem_resolve ; mem_resolve
@ -279,16 +279,18 @@ mem_get_size:
; Output: DX:AX = Segment:Offset ; Output: DX:AX = Segment:Offset
; ES:DI = Segment:Offset (pour utilisation immédiate avec stos/movs) ; ES:DI = Segment:Offset (pour utilisation immédiate avec stos/movs)
; ----------------------------------------------------------------------------- ; -----------------------------------------------------------------------------
%define .handle word [bp+4]
mem_resolve: mem_resolve:
push bp push bp
mov bp, sp mov bp, sp
mov ax, [bp+4] ; Handle mov ax, .handle ; Handle
mov dx, MEM_HEAP_SEG mov dx, MEM_HEAP_SEG
mov es, dx mov es, dx
mov di, ax ; L'offset est le handle lui-même mov di, ax ; L'offset est le handle lui-même
; DX contient déjà le segment, AX contient déjà l'offset ; DX contient déjà le segment, AX contient déjà l'offset
leave leave
ret ret
%undef .handle

View file

@ -21,7 +21,7 @@
; ============================================================================= ; =============================================================================
; --- Configuration --- ; --- Configuration ---
%define GUI_RAM_SEG 0x1800 ; Segment de données UI (Safe: après Stack, avant Heap) %define GUI_RAM_SEG 0x0600 ; 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
@ -94,6 +94,7 @@ struc widget
alignb 2 ; Alignement mémoire pour performance alignb 2 ; Alignement mémoire pour performance
endstruc endstruc
; actuellement 34 octets
%macro GUI 1-* %macro GUI 1-*
%rep %0 - 1 %rep %0 - 1