gestion souris OK + clipping x > 639 & y > 199

This commit is contained in:
Frater 2026-01-29 21:08:53 +01:00
commit c5124b35e3
7 changed files with 207 additions and 236 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

View file

@ -12,7 +12,7 @@ Rather than booting an operating system from disk, the PC starts **directly from
The project is intentionally educational, experimental, and minimalist.
![Screenshot of the boot + text test](/doc/assets/Capture-txt-test.png)
![Screenshot of the boot + text test](/doc/assets/Capture-2026-01-29 210122.png)
---
@ -135,7 +135,7 @@ Au lieu de charger un système dexploitation depuis un disque, le PC **démar
Le projet est volontairement **éducatif, expérimental et minimaliste**.
![Screenshot of the boot + text test](/doc/assets/Capture-txt-test.png)
![Screenshot of the boot + text test](/doc/assets/Capture-2026-01-29 210122.png)
---

View file

@ -93,8 +93,6 @@ endstruc
%define BDA_MOUSE 0x0000
%define BDA_GFX (BDA_MOUSE + mouse_size)
%warning offset Mouse: BAD_MOUSE, Gfx : BDA_GFX
;
; memory map
;

View file

@ -58,7 +58,11 @@ err_vganok db 'VGA Not Initialized',0
cpt_txt db '0123456789A123456789B123456789C123456789D123456789E123456789F123456789G123456789',0
helloworld db 'Hello World !',0
centre db 'TEXTEAUCENTR',0
W_T db '1 - TEXT WHITE - TRANSPARENT',0
B_T db '2 - TEXT BLACK - TRANSPARENT',0
W_B db '3 - TEXT WHITE - ON BLACK',0
B_W db '4 - TEXT BLACK - ON WHITE',0
reset:
cli
@ -100,23 +104,54 @@ reset:
; on active le mode graphique
GFX_DRV GFX_INIT
mov cx, 300
mov dx, 102
mov cx, 290
mov dx, 80
GFX_DRV GFX_GOTOXY
GFX_SET_WRTIE_MODE GFX_TXT_WHITE_TRANSPARENT
push cs
pop ds
mov si, centre
mov si, W_T
GFX_DRV GFX_WRITE
mov cx, 290
mov dx, 90
GFX_DRV GFX_GOTOXY
GFX_SET_WRTIE_MODE GFX_TXT_BLACK_TRANSPARENT
push cs
pop ds
mov si, B_T
GFX_DRV GFX_WRITE
mov cx, 290
mov dx, 100
GFX_DRV GFX_GOTOXY
GFX_SET_WRTIE_MODE GFX_TXT_WHITE
push cs
pop ds
mov si, W_B
GFX_DRV GFX_WRITE
mov cx, 290
mov dx, 110
GFX_DRV GFX_GOTOXY
GFX_SET_WRTIE_MODE GFX_TXT_BLACK
push cs
pop ds
mov si, B_W
GFX_DRV GFX_WRITE
; call mouse_reset
call mouse_init
GFX_DRV GFX_CRS_UPDATE
GFX_SET_WRTIE_MODE GFX_TXT_BLACK_ON_WHITE
GFX_SET_WRTIE_MODE GFX_TXT_BLACK
xor cx,cx
mov dx,0
@ -140,6 +175,8 @@ reset:
mov dx,24
GFX_SET_WRTIE_MODE 0
GFX_DRV GFX_CRS_UPDATE
.loopshift:
GFX_DRV GFX_GOTOXY
mov si, helloworld
@ -152,6 +189,7 @@ reset:
mov ax,BDA_DATA_SEG
mov ds,ax
endless:
GFX_SET_WRTIE_MODE GFX_TXT_BLACK
xor cx,cx
mov dx,180
GFX_DRV GFX_GOTOXY

View file

@ -60,31 +60,26 @@ dump_ram_words:
; Sortie : Affiche "1A2B" via cga_putc
; =============================================================================
print_word_hex:
push ax ; Sauvegarde AX car on va le modifier (rotation)
push cx
push bx
pusha
mov dx, ax
mov cx, 4 ; 4 caractères hex dans un mot de 16 bits
.next_digit:
; On veut afficher les bits 12-15 d'abord.
; L'astuce est de faire une rotation à gauche de 4 bits.
; Le quartet de poids fort se retrouve en bas (bits 0-3).
rol ax, 4
rol dx, 4
mov bx, ax ; Copie temporaire
and bl, 0x0F ; On isole les 4 derniers bits (0 à 15)
mov ax, dx ; Copie temporaire
and al, 0x0F ; On isole les 4 derniers bits (0 à 15)
mov al, bl ; AL contient la valeur numérique (0-15)
call nibble_to_ascii ; Convertit AL en caractère ASCII
call cga_putc ; Affiche le caractère
loop .next_digit ; Répète 4 fois
pop bx
pop cx
pop ax ; Restaure l'état original de AX
popa
ret
; =============================================================================

View file

@ -36,12 +36,15 @@
; sinon le code utilisé sera toujours "shifted"
; %define FULL_MODE_ALLIGNED 1
; align putch mode
%define GFX_TXT_WHITE_TRANSPARENT 0
%define GFX_TXT_BLACK_TRANSPARENT 1
%define GFX_TXT_TRANSP_ON_WHITE 2
%define GFX_TXT_WHITE_ON_BLACK 3
%define GFX_TXT_BLACK_ON_WHITE 4
;
; bit : descr
; 0 : text color : 0=black, 1=white
; 1 : transparent : 1=apply background attribut
;
%define GFX_TXT_WHITE_TRANSPARENT 00000000b
%define GFX_TXT_BLACK_TRANSPARENT 00000001b
%define GFX_TXT_WHITE 00000011b
%define GFX_TXT_BLACK 00000010b
%macro GFX_DRV 1
call word [cs:graph_driver + ((%1)*2)]
@ -61,6 +64,21 @@
%define GFX_WRITE 6
%define GFX_CRS_UPDATE 7
; ------------------------------------------------------------
; COMMENTAIRE SUR LA MÉTHODE D'APPEL
;
; Pour appeler une fonction du driver depuis votre GUI :
; 1. Définissez l'adresse de base du driver (ex: GFX_DRIVER_BASE)
; 2. Utilisez un call indirect via l'offset de la table.
;
; Exemple en ASM pour remplir un rectangle :
; call [GFX_DRIVER_BASE + 9] ; Appelle gfx_fill_rect
;
; Cette méthode isole totalement votre bibliothèque GUI du driver.
; Si vous changez le code du driver, tant que la table au début
; ne change pas d'ordre, la GUI n'a pas besoin d'être recompilée.
; ------------------------------------------------------------
graph_driver:
dw cga_init
dw cga_putpixel
@ -77,7 +95,6 @@ graph_driver:
%include "./common/cursor.asm"
%include "./common/chartable.asm"
;
;
; convert al -> AX aligned with "cl"
%macro ALING_BYTE 0
@ -88,7 +105,6 @@ graph_driver:
xchg ah,al
%endmacro
%macro GFX_SET_WRTIE_MODE 1
push fs
@ -101,21 +117,6 @@ graph_driver:
pop ax
%endmacro
; ------------------------------------------------------------
; COMMENTAIRE SUR LA MÉTHODE D'APPEL
;
; Pour appeler une fonction du driver depuis votre GUI :
; 1. Définissez l'adresse de base du driver (ex: GFX_DRIVER_BASE)
; 2. Utilisez un call indirect via l'offset de la table.
;
; Exemple en ASM pour remplir un rectangle :
; call [GFX_DRIVER_BASE + 9] ; Appelle gfx_fill_rect
;
; Cette méthode isole totalement votre bibliothèque GUI du driver.
; Si vous changez le code du driver, tant que la table au début
; ne change pas d'ordre, la GUI n'a pas besoin d'être recompilée.
; ------------------------------------------------------------
; ------------------------------------------------------------
; initialise le mode graphique (via l'int 10h)
;
@ -139,7 +140,6 @@ cga_init:
cga_none:
ret
; ------------------------------------------------------------
; Calcule DI + AH=mask pour (CX=x, DX=y) en mode CGA 640x200
;
@ -243,83 +243,6 @@ get_glyph_offset:
add si, font8x8
ret
; ---------------------------------------------------------------------------
; cga_putc_aligned
; In : AL = char (ASCII)
; Uses: DS:GFX_CUR_* (baseDI, shift, etc.)
; Out: avance le curseur d'un caractère (8 pixels) sans recalcul complet
; Notes:
; - Nécessite une font 8x8 accessible en CS (voir get_glyph8x8_cs_si)
; - Transparent: bits 0 du glyph ne touchent pas le fond
; ---------------------------------------------------------------------------
%ifdef FULL_MODE_ALLIGNED
cga_putc_aligned:
; Base offset VRAM pour la scanline Y
mov di, [fs:BDA_GFX + gfx.cur_offset]
mov bx, [fs:BDA_GFX + gfx.cur_line_ofs]
mov dl, [fs:BDA_GFX + gfx.cur_mode]
mov cx,4
.row_loop:
; AL = byte glyph pour cette scanline
mov ax, [cs:si]
add si,2
cmp dl,0
jne .black_transparent
; white with transparent
or [es:di], al
or [es:di+bx], ah
jmp .next
.black_transparent:
cmp dl,1
jne .transparent_white
; black with transparent
not ax
and [es:di], al
and [es:di+bx], ah
jmp .next
.transparent_white:
cmp dl,2
jne .black_white
; transparent on white
not ax
or [es:di], al
or [es:di+bx], ah
jmp .next
.black_white:
cmp dl,3
jne .white_transparent
; white on black
mov [es:di], al
mov [es:di+bx], ah
jmp .next
.white_transparent:
not ax
mov [es:di], al
mov [es:di+bx], ah
.next:
add di,CGA_STRIDE
loop .row_loop
; Avancer curseur d'un caractère (8 pixels)
inc word [fs:BDA_GFX + gfx.cur_offset]
add word [fs:BDA_GFX + gfx.cur_x], 8
ret
%endif
; ---------------------------------------------------------------------------
; cga_putc_unalign
; In : AL = char (ASCII)
@ -328,61 +251,6 @@ cga_putc_aligned:
; - x non aligné (x&7 != 0)
; - écrit sur 2 bytes (di et di+1) dans chaque banque
; ---------------------------------------------------------------------------
cga_putc_unaligned:
; Base offset VRAM pour la scanline Y
mov di, [fs:BDA_GFX + gfx.cur_offset]
mov bx, [fs:BDA_GFX + gfx.cur_line_ofs]
mov ch, [fs:BDA_GFX + gfx.cur_mode]
mov cl, [fs:BDA_GFX + gfx.cur_shift]
; mov bx, 0x2000 ; Banque +1
mov bp,4
.row_loop:
; ligne "paire" du gylphe
mov al, [cs:si]
inc si
ALING_BYTE
push ax
; ligne "impaire" du gylphe
mov al, [cs:si]
inc si
ALING_BYTE
pop dx
xchg ax, dx
cmp ch,0
ja .black_transparent
; white with transparent
or [es:di], ax
or [es:di+bx], dx
jmp .next
.black_transparent:
; cmp ch,1
; jne .transparent_white
; black with transparent
not ax
not dx
and [es:di], ax
and [es:di+bx], dx
; jmp .next
.next:
add di,CGA_STRIDE
dec bp
jnz .row_loop
; Avancer curseur d'un caractère (8 pixels)
inc word [fs:BDA_GFX + gfx.cur_offset]
add word [fs:BDA_GFX + gfx.cur_x], 8
ret
cga_putc:
pusha
push fs
@ -395,17 +263,76 @@ cga_putc:
call get_glyph_offset
%ifdef FULL_MODE_ALLIGNED
cmp byte [fs:BDA_GFX + gfx.cur_shift], 0
jne .unaligned
; Base offset VRAM pour la scanline Y
mov di, [fs:BDA_GFX + gfx.cur_offset]
mov bx, [fs:BDA_GFX + gfx.cur_line_ofs]
mov ch, [fs:BDA_GFX + gfx.cur_mode]
mov cl, [fs:BDA_GFX + gfx.cur_shift]
mov bp,4
.row_loop:
; gestion du fond de texte
test ch, 00000010b ; transparent background ?
jz .skip_attribut ; oui
call cga_putc_aligned
jmp .done
.unaligned:
%endif
test ch, 00000001b ; background blanc ?
je .bkg_black
; background = white
mov ax, 0xFF00
shr ax, cl
xchg al, ah
or [es:di], ax
or [es:di+bx], ax
jmp .skip_attribut
.bkg_black: ; OK
; background = black
mov ax, 0xFF00
shr ax, cl
xchg al, ah
not ax
and [es:di], ax
and [es:di+bx], ax
.skip_attribut:
; ligne "paire" du gylphe
xor ax, ax
mov al, [cs:si]
inc si
ALING_BYTE
mov dx,ax
; ligne "impaire" du gylphe
mov al, [cs:si]
inc si
ALING_BYTE
xchg ax, dx
test ch,00000001b
jz .black_text
; white text
not ax
not dx
and [es:di], ax
and [es:di+bx], dx
jmp .next
.black_text:
or [es:di], ax
or [es:di+bx], dx
.next:
add di,CGA_STRIDE
dec bp
jnz .row_loop
; Avancer curseur d'un caractère (8 pixels)
inc word [fs:BDA_GFX + gfx.cur_offset]
add word [fs:BDA_GFX + gfx.cur_x], 8
call cga_putc_unaligned
.done:
pop es
pop fs
popa
@ -569,6 +496,9 @@ cga_cursor_move:
mov ax, BDA_DATA_SEG
mov ds, ax
cmp byte [BDA_MOUSE + mouse.cur_visible], 0
je .done
cmp byte [BDA_MOUSE + mouse.cur_drawing],0
jne .done
mov byte [BDA_MOUSE + mouse.cur_drawing],1
@ -594,7 +524,7 @@ cga_cursor_move:
; Stocke 16 DWORDs: chaque DWORD contient (b0|b1<<8|b2<<16) dans les 24 bits bas.
; -----------------------------------------------
cga_cursor_savebg:
cmp byte [BDA_MOUSE + mouse.bkg_saved], 0
cmp byte [BDA_MOUSE + mouse.bkg_saved], 0 ; le buffer n'a pas encore été restauré
jne .done
mov byte [BDA_MOUSE + mouse.bkg_saved], 1
@ -608,38 +538,22 @@ cga_cursor_savebg:
; calcule ES:DI pour (x,y)
call cga_calc_addr
; bank_add = +0x2000 si DI<0x2000 sinon -0x2000
mov bx, 02000h
cmp di, bx
jl .bank_ok
neg bx
.bank_ok:
mov [BDA_MOUSE + mouse.cur_addr_start], di
mov [BDA_MOUSE + mouse.cur_bank_add], bx
; DS:SI = buffer (64 bytes)
lea si, [BDA_MOUSE + mouse.bkg_buffer]
mov bp, 8 ; 8 itérations = 16 lignes (pair/impair via bank)
.rowpair:
mov cx,16
.row_loop:
; ---- ligne bank courant ----
mov eax, [es:di] ; lit b0 b1 b2 b3
and eax, 00FFFFFFh ; ne garder que 3 bytes
mov [ds:si], eax ; stocke 4 bytes (le byte haut sera 0)
add si, 4
; ---- ligne bank opposé ----
add di, bx ; +0x2000 ou -0x2000
mov eax, [es:di]
and eax, 00FFFFFFh
mov [ds:si], eax
add si, 4
sub di, bx
add di, CGA_STRIDE*2 ; avance de 2 lignes dans bank courant
dec bp
jnz .rowpair
xor di, 0x2000
test di, 0x2000
jnz .next_line
add di, CGA_STRIDE ; avance de 2 lignes dans bank courant
.next_line:
loop .row_loop
.done:
ret
@ -657,35 +571,20 @@ cga_cursor_restorebg:
; restaurer depuis la dernière position sauvegardée
mov di, [BDA_MOUSE + mouse.cur_addr_start]
mov bx, [BDA_MOUSE + mouse.cur_bank_add]
lea si, [BDA_MOUSE + mouse.bkg_buffer]
mov bp, 8
.rowpair:
mov cx, 16
.row_loop:
; ---- ligne bank courant ----
mov eax, [ds:si] ; saved (24 bits bas)
mov eax, [ds:si] ; saved (32 bits)
mov [es:di], eax ; restore line
add si, 4
mov ecx, [es:di] ; dst actuel
and ecx, 0FF000000h ; garder b3
and eax, 00FFFFFFh
or eax, ecx
mov [es:di], eax
; ---- ligne bank opposé ----
add di, bx
mov eax, [ds:si]
add si, 4
mov ecx, [es:di]
and ecx, 0FF000000h
and eax, 00FFFFFFh
or eax, ecx
mov [es:di], eax
sub di, bx
add di, CGA_STRIDE*2
dec bp
jnz .rowpair
xor di, 0x2000
test di, 0x2000
jnz .next_line
add di, CGA_STRIDE ; avance de 2 lignes dans bank courant
.next_line:
loop .row_loop
.done:
ret
@ -720,6 +619,38 @@ cga_cursor_draw:
mov bp, ax
.y_ok:
; On calcule si les 4 octets vont dépasser la ligne (80 octets)
; X est en bits (0-639). X >> 3 donne l'octet de départ (0-79).
; Si StartByte >= 77, on déborde.
mov cx, [BDA_MOUSE + mouse.x]
shr cx, 3 ; CX = Byte Offset (0-79)
xor esi, esi ; ESI = Masque de protection (0 = tout dessiner)
cmp cx, 76 ; 76 est le dernier offset sûr (76,77,78,79)
jbe .mask_ready ; Si <= 76, pas de débordement
; Calcul du débordement
; Si CX=77 (Déborde 1 byte) -> Masque 0x000000FF (LSB car bswap)
; Si CX=78 (Déborde 2 bytes)-> Masque 0x0000FFFF
; Si CX=79 (Déborde 3 bytes)-> Masque 0x00FFFFFF
cmp cx, 77
jne .check_78
mov esi, 0x000000FF
jmp .mask_ready
.check_78:
cmp cx, 78
jne .check_79
mov esi, 0x0000FFFF
jmp .mask_ready
.check_79:
mov esi, 0x00FFFFFF ; Cas extrême (bord droit)
.mask_ready:
; On sauvegarde ce masque pour l'utiliser dans la boucle
; On utilise la pile pour libérer les registres
push esi ; [ESP] contient maintenant le masque
; --- ADRESSAGE ---
mov cx, [BDA_MOUSE + mouse.x]
@ -747,18 +678,25 @@ cga_cursor_draw:
; --- MASQUE AND (EAX) ---
mov eax, 0xFFFFFFFF
mov ax, [gs:si] ; masque AND
xchg al, ah ; Redresser pour l'ordre des pixels CGA
mov ax, [gs:si] ; masque AND
xchg al, ah ; Redresser pour l'ordre des pixels CGA
bswap eax
ror eax, cl
or eax, [esp+2] ; Force les bits clippés à 1 (garde le fond)
; --- MASQUE XOR (EBX) ---
xor ebx, ebx
mov bx, [gs:si+32] ; masque XOR
mov bx, [gs:si+32] ; masque XOR
xchg bl, bh
bswap ebx
ror ebx, cl
mov edx, [esp+2] ; charge le masque de protection
not edx ; inverse le masque de protection
and ebx, edx ; applique le masque de protection
; --- LECTURE ET MODIFICATION (EDX) ---
mov edx, [es:di] ; lecture des 16 bits a la position du curseur
bswap edx
@ -780,6 +718,7 @@ cga_cursor_draw:
dec bp
jnz .row_loop
pop esi
.exit_total:
pop es
pop ds

View file

@ -287,9 +287,15 @@ isr_mouse_handler:
; lire un octet depuis le contrôleur et le stocker dans le buffer
in al, i8042_PS2_DATA ; lire octet souris
inc byte [BDA_MOUSE + mouse.blinker]
movzx bx, byte [BDA_MOUSE + mouse.idx]
cmp bl,0
jne .read_packet
; check bit 3 octet 0 pour assurer que le bloc est ok:
test al, 00001000b ; bit 3 = 1
jz .done_eoi ; allignement erroné
.read_packet:
mov byte [BDA_MOUSE + mouse.buffer + bx], al
inc byte [BDA_MOUSE + mouse.idx]
@ -301,11 +307,6 @@ isr_mouse_handler:
; packet complet, on decode les données (ou on jette si c'est incorrect)
mov byte [BDA_MOUSE + mouse.idx], 0 ; reset de l'index de lecture
; check bit 3 octet 0 pour assurer que le bloc est ok:
mov al, byte [BDA_MOUSE + mouse.buffer]
and al, 00001000b ; bit 3 = 1
je .done_eoi ; allignement erroné
; debut du décodage des données
mov bl, [BDA_MOUSE + mouse.buffer] ; status
mov al,bl
@ -331,28 +332,28 @@ isr_mouse_handler:
; --- CLAMPING X ---
; Check minimum (0)
cmp word [fs:BDA_MOUSE + mouse.x], 0
cmp word [BDA_MOUSE + mouse.x], 0
jge .check_x_max
mov word [fs:BDA_MOUSE + mouse.x], 0
mov word [BDA_MOUSE + mouse.x], 0
jmp .done_x
.check_x_max:
; Check maximum (e.g., 639 for graphics, or pixel width)
cmp word [fs:BDA_MOUSE + mouse.x], GFX_WIDTH-1 ; Replace with variable or define
cmp word [BDA_MOUSE + mouse.x], GFX_WIDTH-1 ; Replace with variable or define
jle .done_x
mov word [fs:BDA_MOUSE + mouse.x], GFX_WIDTH-1
mov word [BDA_MOUSE + mouse.x], GFX_WIDTH-1
.done_x:
; --- CLAMPING Y ---
; Check minimum (0)
cmp word [fs:BDA_MOUSE + mouse.y], 0
cmp word [BDA_MOUSE + mouse.y], 0
jge .check_y_max
mov word [fs:BDA_MOUSE + mouse.y], 0
mov word [BDA_MOUSE + mouse.y], 0
jmp .done_y
.check_y_max:
; Check maximum
cmp word [fs:BDA_MOUSE + mouse.y], GFX_HEIGHT-1 ; Replace with variable or define
cmp word [BDA_MOUSE + mouse.y], GFX_HEIGHT-1 ; Replace with variable or define
jle .done_y
mov word [fs:BDA_MOUSE + mouse.y], GFX_HEIGHT-1
mov word [BDA_MOUSE + mouse.y], GFX_HEIGHT-1
.done_y:
; check si il y a un 4eme byte a traiter