diff --git a/doc/MEMORY_MAP.md b/doc/MEMORY_MAP.md index c7d310e..5f4d658 100644 --- a/doc/MEMORY_MAP.md +++ b/doc/MEMORY_MAP.md @@ -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` | | **`0x00400`** | **`0x004FF`** | 256 B | **BDA** (BIOS Data Area) Standard | `0x0040` | `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` | -| **`0x18000`** | **`0x18FFF`** | ~4 KB | **GUI RAM** (Widget Allocation) | `0x0A00` | `gui/lib.asm` | -| **`0x19000`** | **`0x9FBFF`** | 539 KB | **Free** (Conventional RAM) | | | +| **`0x18000`** | **`0x9FBFF`** | 543 KB | **Free** (Conventional RAM) | | | | **`0x9FC00`** | **`0x9FFFF`** | 1 KB | **EBDA** (Extended BIOS Data Area) | `0x9FC0` | `memory.asm` | | **`0xA0000`** | **`0xAFFFF`** | 64 KB | **VGA RAM** (Graphics Modes) | `0xA000` | `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**: Segment `0x0800`, SP `0xFFFE`. Grows downwards from physical address `0x17FFE`. -* **GUI RAM**: Segment `0x0A00` (Physical `0x0A000`). -* **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. +* **GUI RAM**: Segment `0x0060` (Physical `0x00600`). +* **Layout**: Located in low memory (`0x00600`) to avoid any collision with the Stack (`0x08000`). #### Video RAM (CGA High-Res) * **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` | | **`0x00400`** | **`0x004FF`** | 256 o | **BDA** (BIOS Data Area) Standard | `0x0040` | `memory.asm` | | **`0x00500`** | **`0x005FF`** | ~256 o | **Custom BDA** (Données Drivers) | `0x0050` | `memory.asm` | -| **`0x00600`** | **`0x07FFF`** | 30.5 Ko | **Libre** (Mémoire Basse) | | | -| **`0x08000`** | **`0x17FFF`** | 64 KB | **Stack** (Grows downwards) | `0x0800` | `memory.asm` | -| **`0x18000`** | **`0x18FFF`** | ~4 KB | **GUI RAM** (Widget Allocation) | `0x0A00` | `gui/lib.asm` | -| **`0x19000`** | **`0x9FBFF`** | 539 Ko | **Libre** (RAM Conventionnelle) | | | +| **`0x00600`** | **`0x00AFF`** | 1.25 Ko | **GUI RAM** (Allocation Widgets) | `0x0060` | `gui/lib.asm` | +| **`0x00B00`** | **`0x07FFF`** | 29 Ko | **Libre** (Mémoire Basse) | | | +| **`0x08000`** | **`0x17FFF`** | 64 Ko | **Pile** (Stack) | `0x0800` | `memory.asm` | +| **`0x18000`** | **`0x9FBFF`** | 543 Ko | **Libre** (RAM Conventionnelle) | | | | **`0x9FC00`** | **`0x9FFFF`** | 1 Ko | **EBDA** (Extended BIOS Data Area) | `0x9FC0` | `memory.asm` | | **`0xA0000`** | **`0xAFFFF`** | 64 Ko | **VGA RAM** (Modes Graphiques) | `0xA000` | `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** : Segment `0x0800`, SP `0xFFFE`. Grandit vers le bas depuis l'adresse physique `0x17FFE`. -* **GUI RAM** : Segment `0x0A00` (Physique `0x0A000`). -* **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. + * **GUI RAM** : Segment `0x0060` (Physique `0x00600`). +* **Organisation** : Située en mémoire basse (`0x00600`) pour éviter toute collision avec la Pile (`0x08000`). #### Video RAM (CGA High-Res) * **Segment** : `0xB800` diff --git a/src/common/memory.asm b/src/common/memory.asm index e65675a..f02278c 100644 --- a/src/common/memory.asm +++ b/src/common/memory.asm @@ -27,25 +27,25 @@ ; --- 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 + %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 + 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) + .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 ; ----------------------------------------------------------------------------- @@ -54,28 +54,28 @@ endstruc ; Crée un seul gros bloc libre couvrant tout le segment. ; ----------------------------------------------------------------------------- mem_init: - push ax - push es - push di + push ax + push es + push di - mov ax, MEM_HEAP_SEG - mov es, ax - xor di, 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 + ; 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 + ; 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 + mov word [es:di + mem_block.next], 0 - pop di - pop es - pop ax - ret + pop di + pop es + pop ax + ret ; ----------------------------------------------------------------------------- ; mem_alloc @@ -84,156 +84,157 @@ mem_init: ; Stack: [BP+4] = Taille demandée (word) ; 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: - push bp - mov bp, sp - sub sp, 2 + 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 - push bx - push cx - push es - push di + mov .curr_ptr, 0 ; On commence la recherche à l'offset 0 - 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: - mov di, .curr_ptr ; DI = Ptr courant + 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 + ; 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 + ; 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 + 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 + ; 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 + ; 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 + ; 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 + 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 + ; 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 + ; 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 + ; 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 + ; --- 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 + ; 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 + 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 + 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 + ; 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 + jmp .success .allocate_full: - ; On prend tout le bloc sans le couper - mov byte [es:di + mem_block.status], MEM_STATUS_USED + ; 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 + ; 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 + ; 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 + ; É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 + pop di + pop es + pop cx + pop bx + leave ; Restaure SP et BP + ret +%undef .curr_ptr +%undef .size_requested ; ----------------------------------------------------------------------------- ; mem_free ; Libère un bloc mémoire. ; Stack: [BP+4] = Handle (word) ; ----------------------------------------------------------------------------- +%define .handle word [bp+4] mem_free: - push bp - mov bp, sp + 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 + push es + push di + push bx - mov bx, MEM_HEAP_SEG - mov es, bx + mov ax, .handle ; Handle + test ax, ax + jz .done ; Sécurité Handle NULL - ; Retrouver le header (Handle - HeaderSize) - mov di, ax - sub di, mem_block_size + mov bx, MEM_HEAP_SEG + mov es, bx - ; Marquer simplement comme libre (le coalescing se fera au prochain alloc) - mov byte [es:di + mem_block.status], MEM_STATUS_FREE + ; 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 + pop bx + pop di + pop es + leave + ret +%undef .handle ; ----------------------------------------------------------------------------- ; mem_get_size @@ -241,36 +242,35 @@ mem_free: ; Stack: [BP+4] = Handle (word) ; Output: AX = Taille ; ----------------------------------------------------------------------------- +%define .handle word [bp+4] mem_get_size: - push bp - mov bp, sp + push bp + mov bp, sp - %define .handle word [bp+4] + push es + push di - push es - push di + mov ax, .handle ; Handle + test ax, ax + jz .error - mov ax, .handle ; Handle - test ax, ax - jz .error + mov bx, MEM_HEAP_SEG + mov es, bx - mov bx, MEM_HEAP_SEG - mov es, bx + mov di, ax + sub di, mem_block_size - mov di, ax - sub di, mem_block_size - - mov ax, [es:di + mem_block.size] - jmp .done + mov ax, [es:di + mem_block.size] + jmp .done .error: - xor ax, ax + xor ax, ax .done: - pop di - pop es - %undef .handle - leave - ret + pop di + pop es + leave + ret +%undef .handle ; ----------------------------------------------------------------------------- ; mem_resolve @@ -279,16 +279,18 @@ mem_get_size: ; Output: DX:AX = Segment:Offset ; ES:DI = Segment:Offset (pour utilisation immédiate avec stos/movs) ; ----------------------------------------------------------------------------- +%define .handle word [bp+4] mem_resolve: - push bp - mov bp, sp + 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 + mov ax, .handle ; 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 + ; DX contient déjà le segment, AX contient déjà l'offset - leave - ret + leave + ret +%undef .handle \ No newline at end of file diff --git a/src/gui/lib.asm b/src/gui/lib.asm index d966b2f..677714f 100644 --- a/src/gui/lib.asm +++ b/src/gui/lib.asm @@ -21,7 +21,7 @@ ; ============================================================================= ; --- 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 ; Dimensions @@ -94,6 +94,7 @@ struc widget alignb 2 ; Alignement mémoire pour performance endstruc +; actuellement 34 octets %macro GUI 1-* %rep %0 - 1