From 91881695fbad3567363f24ff25bf21e42f3023b0 Mon Sep 17 00:00:00 2001 From: Frater <13979047+saintfrater@users.noreply.github.com> Date: Sat, 10 Jan 2026 17:25:59 +0100 Subject: [PATCH] add mouse support (WIP) --- .gitignore | 3 + build-elf.bat | 11 + roms/qemu-vgabios.bin | Bin 0 -> 38912 bytes roms/vgabios.bin | Bin 0 -> 32768 bytes src/bda.asm | 39 +-- src/boot.asm | 43 ++-- src/drivers/gfx_cgam.asm | 495 +++++++++++++++++++++++++++++++++++--- src/drivers/mouse_ps2.asm | 219 +++++++++++------ src/services/generic.asm | 15 +- src/services/macros.asm | 45 ++++ 10 files changed, 714 insertions(+), 156 deletions(-) create mode 100644 .gitignore create mode 100644 build-elf.bat create mode 100644 roms/qemu-vgabios.bin create mode 100644 roms/vgabios.bin create mode 100644 src/services/macros.asm diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..b03b847 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +build/ +.vscode +.vscode/tasks.json diff --git a/build-elf.bat b/build-elf.bat new file mode 100644 index 0000000..6f66a3a --- /dev/null +++ b/build-elf.bat @@ -0,0 +1,11 @@ +@echo off + +if not exist build mkdir build +cd src +echo compiling +"C:\Program Files\NASM\nasm.exe" -f elf32 -g -F dwarf boot.asm -o ..\build\bios.o +echo LD +ld -m elf_i386 -T link.ld -o build\bios.elf build\bios.o +echo ObjectCopy +objcopy -O binary build\bios.elf build\bios.bin +cd .. diff --git a/roms/qemu-vgabios.bin b/roms/qemu-vgabios.bin new file mode 100644 index 0000000000000000000000000000000000000000..3f71aae1715b2f3082fc973297d8193fd5163526 GIT binary patch literal 38912 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 J{Qv6ye*x7>5B>lE literal 0 HcmV?d00001 diff --git a/roms/vgabios.bin b/roms/vgabios.bin new file mode 100644 index 0000000000000000000000000000000000000000..9adefccc7c357144bc9c2b17f785b855b46e4116 GIT binary patch literal 32768 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 <3GEQ0!Qo*6DzCr*p&v45aX&2s&=v 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 literal 0 HcmV?d00001 diff --git a/src/bda.asm b/src/bda.asm index 9f586bf..5f73483 100644 --- a/src/bda.asm +++ b/src/bda.asm @@ -2,7 +2,6 @@ ; Project : Custom BIOS / ROM ; File : bda.asm ; Author : frater -; Created : 06 jan 2026 ; ; License : GNU General Public License v3.0 or later (GPL-3.0+) ; @@ -21,32 +20,31 @@ ; ; ============================================================================= - -; +; compatible with IBM PC BIOS Data Area (BDA): ; https://wiki.nox-rhea.org/back2root/ibm-pc-ms-dos/hardware/informations/bios_data_area ; %define BDA_SEGMENT 0x0040 ; segment BDA -; custom var +; custom vars %define BDA_INFO_MEM_SIZE 0x0014 ; Memory size in Kbytes %define BDA_INFO_MEM_SEG BDA_INFO_MEM_SIZE+2 ; highest Memory Segment ; video related information (compatible with VGA bios) %define BDA_VIDEO_CURR_MODE 0x0049 -%define BDA_VIDEO_COLUMNS 0x004A +%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 - +; 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 ; ; information relative à la souris @@ -57,7 +55,18 @@ %define BDA_MOUSE_BUFFER 0x0000 ; dword; buffer (jusqu'à 4 octets) %define BDA_MOUSE_IDX 0x0004 ; byte 0..3 %define DBA_MOUSE_PACKETLEN 0x0005 -; 0x0006 +%define DBA_CURSOR_MASK 0x0006 ; byte pixels mask (bit per pixel) %define BDA_MOUSE_STATUS 0x0007 ; byte %define BDA_MOUSE_X 0x0008 ; word -%define BDA_MOUSE_Y 0x000A ; word \ No newline at end of file +%define BDA_MOUSE_Y 0x000A ; word +%define BDA_MOUSE_WHEEL 0x000C ; word + +%define BDA_CURSOR_VISIBLE 0x000E ; byte (0/1) +%define BDA_CURSOR_OLDX 0x000F ; word +%define BDA_CURSOR_OLDY 0x0011 ; word +%define BDA_CURSOR_NEWX 0x0013 ; word +%define BDA_CURSOR_NEWY 0x0015 ; word +%define BDA_CURSOR_BITOFF 0x0017 ; byte 0..7 bits d'offset (x&7) +%define BDA_CURSOR_BYTES 0x0019 ; byte 2 ou 3 bytes as source for cursor image +%define BDA_CURSOR_SAVED 0x001A ; flag if image saved +%define BDA_CURSOR_BG 0x001B ; 48 bytes max (3*16) diff --git a/src/boot.asm b/src/boot.asm index da5ec0b..c367df1 100644 --- a/src/boot.asm +++ b/src/boot.asm @@ -2,7 +2,6 @@ ; Project : Custom BIOS / ROM ; File : boot.asm ; Author : frater -; Created : 06 jan 2026 ; ; License : GNU General Public License v3.0 or later (GPL-3.0+) ; @@ -32,7 +31,7 @@ org 0 %define DEBUG_PORT 0xe9 ; 0x402 ou 0xe9 -; initial stack +; initial stack %define STACK_SEG 0x0030 ; compatible avec le BMM (Bios Memory Maps) %define STACK_TOP 0x0100 ; choix commun en RAM basse (pile descendante) @@ -45,12 +44,14 @@ org 0 jmp reset ; ce jump n'est pas sensé être executer, il est présent uniquement pour le debug ; definition du BDA -%include ".\bda.asm" +%include "./bda.asm" -%include ".\drivers\debug.asm" -%include ".\drivers\gfx_cgam.asm" -%include ".\drivers\mouse_ps2.asm" -%include ".\services\generic.asm" +%include "./services/macros.asm" + +%include "./drivers/debug.asm" +%include "./drivers/gfx_cgam.asm" +%include "./drivers/mouse_ps2.asm" +%include "./services/generic.asm" err_vganok db 'VGA Not Initialized',0 err_end db 'code completed successfully',0 @@ -61,27 +62,29 @@ reset: 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 + call ram_setup ; modification du stack en "haut" de la RAM mov ax, dx - sub ax, 0x0400 ; réserver les 16 dernier KB + 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 + call ivt_setup sti ; load other Rom call setup_load_rom - + ; on vérifie que le BIOS VGA a installer l'INT 10h call setup_check_vga - + + ; on active le mode graphique call gfx_init - + +; test a line mov cx,50 .bcl: ; mov dx,cx mov bl,0 @@ -91,16 +94,16 @@ reset: inc cx cmp cx,150 jle .bcl - + call mouse_init - + mov ax,cs mov ds,ax mov si, err_end call debug_puts - -endless: hlt + +endless: nop jmp endless ; ------------------------------------------------------------------ @@ -113,6 +116,6 @@ times 0xFFF0 - ($ - $$) db 0xFF ; ------------------------------------------------------------------ reset_vector: jmp far 0xF000:reset -; filling +; filling builddate db '06/01/2026',0 diff --git a/src/drivers/gfx_cgam.asm b/src/drivers/gfx_cgam.asm index bdb6b05..028ae9c 100644 --- a/src/drivers/gfx_cgam.asm +++ b/src/drivers/gfx_cgam.asm @@ -2,7 +2,6 @@ ; Project : Custom BIOS / ROM ; File : gfx_cgam.asm ; Author : frater -; Created : 06 jan 2026 ; ; License : GNU General Public License v3.0 or later (GPL-3.0+) ; @@ -32,11 +31,10 @@ %define CGA_STRIDE 80 %define CGA_ODD_BANK 0x2000 -%define BG16_SIZE 48 ; ------------------------------------------------------------ ; initialise le mode graphique (via l'int 10h) -; +; ; ce mode est entrelacé, un bit/pixel, 8 pixels par octet ; ------------------------------------------------------------ gfx_init: @@ -45,59 +43,65 @@ gfx_init: mov al, GFX_MODE int 0x10 + mov [BDA_CURSOR_SAVED],0 ; flag image saved + + ; dessine un background "check-board" call gfx_background ret +; ------------------------------------------------------------ +; Calcule DI + AH=mask pour (CX=x, DX=y) en mode CGA 640x200 +; +; Out: ES=VIDEO_SEG, DI=offset, AH=bitmask (0x80 >> (x&7)) +; ------------------------------------------------------------ +gfx_calc_addr: + ; calcul de l'offset 'y': + ; si y est impaire, DI+=0x2000 + ; DI = (y>>1)*80 + (x>>3) + (y&1)*0x2000 + mov ax, dx + shr ax, 1 ; ax = y/2 + + mov di, ax + shl di, 4 ; (y/2)*16 + shl ax, 6 ; (y/2)*64 + add di, ax ; *80 + + mov ax, cx + shr ax, 3 + add di, ax + + test dl, 1 + jz .even + add di, CGA_ODD_BANK +.even: + ; masque bit = 0x80 >> (x&7) + push cx + and cl, 7 + mov ah, 080h + shr ah, cl + pop cx + ret + ; ------------------------------------------------------------ ; Dessine un pixel, accès VRAM direct. ; -; In: ; CX = x (0..639) ; DX = y (0..199) ; BL = color (0=black, !=0=white) -; ; ------------------------------------------------------------ gfx_putpixel: - push ax + PUSH_ABCD push di push es - + mov ax, VIDEO_SEG mov es,ax - - ; calcul de l'offset 'y': - ; si y est impaire, DI+=0x2000 - - ; DI = (y>>1)*80 + (x>>3) + (y&1)*0x2000 - mov ax, dx - shr ax, 1 ; ax = y/2 - - mov di, ax ; di = y/2 - shl di, 4 ; di = (y/2)*16 - - shl ax, 6 ; ax = (y/2)*64 - add di, ax ; di = (y/2)*(16+64) = *80 - - mov ax, cx ; x - shr ax, 3 ; AX = x/8 - add di, ax - - ; ligne paire/impaire - test dl, 1 - jz .ligne_paire - add di, CGA_ODD_BANK -.ligne_paire: - - ; masque bit = 0x80 >> (x&7) - and cl, 7 ; cl = x&7 - mov ah, 080h - shr ah, cl ; AH = bitmask + call gfx_calc_addr ; write cmp bl, 0 je .clear - .set: or byte [es:di], ah jmp .done @@ -109,6 +113,25 @@ gfx_putpixel: .done: pop es pop di + POP_ABCD + ret + +; ------------------------------------------------------------ +; Lit un pixel (CX=x, DX=y) +; Out: AL=0/1 +; ------------------------------------------------------------ +gfx_getpixel: + push ax + push di + push es + + call gfx_calc_addr + mov al, [es:di] + and al, ah + setnz al + + pop es + pop di pop ax ret @@ -127,3 +150,403 @@ gfx_background: mov cx,0x1000 ; 640/8/2 rep stosw ret + +; ------------------------------------------------------------ +; Calcule les infos de l'alignement du curseur, basé sur cx=X +; il est important que DS pointe sur le BDA_MOUSE_SEG +; Out: BDA_CURSOR_BITOFF, BDA_CURSOR_BYTES +; ------------------------------------------------------------ +gfx_cursor_calc_align: + mov al, cl + and al, 7 ; offset = x&7 + mov [BDA_CURSOR_BITOFF], al + cmp al, 0 + jne .unaligned + mov byte [BDA_CURSOR_BYTES], 2 + ret +.unaligned: + mov byte [BDA_CURSOR_BYTES], 3 + ret + +; ------------------------------------------------------------ +; Sauvegarde le background (24x16) sous le curseur (cx=X,dx=Y) +; +; utilise les variables du BDA pour stocker +; ------------------------------------------------------------ +gfx_cursor_savebg: + pusha ; sauvegarde registres + + mov ax, BDA_MOUSE_SEG + mov ds, ax + + mov ax, VIDEO_SEG + mov es, ax + + cmp [BDA_CURSOR_SAVED], 0 + jne .done ; déjà sauvé + + mov [BDA_CURSOR_SAVED], 1 ; flag image saved + + mov [BDA_CURSOR_NEWX], cx ; sauvegarde la nouvelle position + mov [BDA_CURSOR_NEWY], dx + + call gfx_calc_addr ; ES:DI = byteaddr pour (X,Y) + mov dx,0x2000 ; offset pour lignes impaire + cmp di,dx + jl .no_odd_bank + neg dx ; Y est déja une ligne impaire, on retire l'offset +.no_odd_bank: + + mov si, BDA_CURSOR_BG ; DS:SI = buffer de sauvegarde + mov bx, 8 + + and cx,0x0007 ; alignement X + jnz .row3 + +.row3: ; sauve 3 bytes/ligne + mov [BDA_CURSOR_BYTES], 3 ; 3 bytes/ligne + ; ligne 'y', peut etre paire ou impaire + mov ax, word [es:di] ; charge first word + mov word [ds:si], ax ; sauvegarde + mov al, byte [es:di+2] ; charge 3ème byte + mov byte [ds:si+2], al + add si, 3 + + ; ligne 'y'+1; si paire +0x2000, si impaire -0x2000 + add di, dx ; charge first word other bank (+0x2000 ou -0x2000) + mov ax, word [es:di] + mov word [ds:si], ax + mov al, byte [es:di+2] + mov byte [ds:si+2], al + add si, 3 + sub di, dx + add di, CGA_STRIDE + dec bx + jnz .row3 + jmp .done + +.row2: ; sauve 2 bytes/ligne + mov [BDA_CURSOR_BYTES], 2 ; par défaut + ; ligne 'y', peut etre paire ou impaire + mov ax, word [es:di] ; charge first word + mov word [ds:si], ax ; sauvegarde + add si, 2 + + ; ligne 'y'+1; si paire +0x2000, si impaire -0x2000 + add di, dx ; charge first word other bank (+0x2000 ou -0x2000) + mov ax, word [es:di] + mov word [ds:si], ax + add si, 2 + sub di, dx + add di, CGA_STRIDE + dec bx + jnz .row3 +.done: + popa + ret + +; ------------------------------------------------------------ +; restore le background (24x16) +; +; utilise les variables du BDA pour stocker +; ------------------------------------------------------------ +gfx_cursor_restorebg: + pusha ; sauvegarde registres + + mov ax, BDA_MOUSE_SEG + mov ds, ax + + mov ax, VIDEO_SEG + mov es, ax + + cmp [BDA_CURSOR_SAVED], 0 ; pas de background sauvé + je .done + + mov cx,[BDA_CURSOR_OLDX] ; restore de la position + mov dx,[BDA_CURSOR_OLDY] + mov [BDA_CURSOR_SAVED], 0 ; le background a été restauré + + call gfx_calc_addr ; ES:DI = byteaddr pour (X,Y) + mov dx,0x2000 ; offset pour lignes impaire + cmp di,dx + jl .no_odd_bank + neg dx ; Y est déja une ligne impaire, on retire l'offset +.no_odd_bank: + mov si, BDA_CURSOR_BG ; DS:SI = buffer de sauvegarde + mov bx, 8 + + cmp [BDA_CURSOR_BYTES], 2 ; si la sauvegarde est en 2 bytes/ligne + je .row2 + +.row3: ; restore en 3 bytes/ligne + ; ligne 'y', peut etre paire ou impaire + mov ax,word [ds:si] ; recupère le 1er word + mov word [es:di],ax + mov al,byte [ds:si+2] ; charge 3ème byte + mov byte [es:di+2],al + add si, 3 + + ; ligne 'y'+1; si paire +0x2000, si impaire -0x2000 + add di, dx ; charge first word other bank (+0x2000 ou -0x2000) + mov ax,word [ds:si] ; recupère le 1er word + mov word [es:di],ax + mov al,byte [ds:si+2] ; charge 3ème byte + mov byte [es:di+2],al + add si, 3 + sub di, dx + add di, CGA_STRIDE + dec bx + jnz .row3 + jmp .done + +.row2: ; restore en 2 bytes/ligne + ; ligne 'y', peut etre paire ou impaire + mov ax,word [ds:si] ; recupère le 1er word + mov word [es:di],ax + add si, 2 + + ; ligne 'y'+1; si paire +0x2000, si impaire -0x2000 + add di, dx ; charge first word other bank (+0x2000 ou -0x2000) + mov ax,word [ds:si] ; recupère le 1er word + mov word [es:di],ax + add si, 2 + sub di, dx + add di, CGA_STRIDE + dec bx + jnz .row2 +.done: + popa + ret + +; ------------------------------------------------------------ +; Dessine un pixel, en [ES:DI] accès VRAM direct. +; +; CX = x (0..639) +; DX = y (0..199) +; BL = color (0=black, !=0=white) +; ------------------------------------------------------------ +gfx_putpixel_fast: + cmp bl, 0 + je .clear +.set: + or byte [es:di], ah + jmp .done +.clear: + not ah + and byte [es:di], ah +.done: + ret + +; ------------------------------------------------------------ +; Lit un pixel, en [ES:DI] accès VRAM direct. +; +; ------------------------------------------------------------ +gfx_getpixel_fast: + mov al, [es:di] + and al, ah + setnz al + ret + +; ------------------------------------------------------------ +; Dessine le curseur 16x16 AND/XOR à [BDA_CURSOR_NEWX],[BDA_CURSOR_NEWY] +; +; CS:SI = base du sprite (AND[16] suivi de XOR[16] à +32 bytes) +; Uses: BDA_CURSOR_BITOFF/BDA_CURSOR_BYTES (via gfx_cursor_calc_align) +; ------------------------------------------------------------ +gfx_cursor_draw: + pusha + + mov ax, BDA_MOUSE_SEG + mov ds, ax + mov ax, VIDEO_SEG + mov es, ax + + mov cx, [BDA_CURSOR_NEWX] + mov dx, [BDA_CURSOR_NEWY] + + ; calcule offset et bytes/ligne (2 ou 3) + call gfx_cursor_calc_align + mov bl, [BDA_CURSOR_BITOFF] ; 0..7 + + ; calcule DI de départ (attention: gfx_calc_addr modifie CL) + push cx + call gfx_calc_addr ; DI ok, AH ignoré + pop cx + + ; dxbank = +0x2000 si DI < 0x2000, sinon dxbank = -0x2000 + mov bp, 02000h + cmp di, bp + jl .bank_ok + neg bp ; bp = -0x2000 +.bank_ok: + + ; on va dessiner 16 lignes: 8 paires (ligne dans bank courant + ligne dans autre bank) + mov bx, 0 ; row index (0..15) + + mov dh, 8 +.pair: + ; ----- ligne row (bank courant) ----- + push di + push si + call .draw_line ; utilise DI, row=BX + pop si + pop di + + ; ----- ligne row+1 (autre bank) ----- + add di, bp + inc bx + push di + push si + call .draw_line + pop si + pop di + sub di, bp + + ; avancer de 2 lignes (dans le bank courant): +80 bytes + add di, CGA_STRIDE + + inc bx + dec dh + jnz .pair + + popa + ret + +; ------------------------------------------------------------ +; .draw_line: applique AND/XOR sur une ligne de 16 pixels à ES:DI +; row index dans BX (0..15) +; offset dans BL (0..7) +; sprite base CS:SI +; ------------------------------------------------------------ +.draw_line: + push ax + push cx + push dx + push bp + push di + + ; charger masks de la ligne: AND = [SI + row*2], XOR = [SI + 32 + row*2] + mov ax, bx + shl ax, 1 ; row*2 + + push si + add si, ax + mov cx, [cs:si] ; AND mask + add si, 32 + mov dx, [cs:si] ; XOR mask + pop si + + ; lire bytes source + mov al, [es:di] ; b0 + inc di + mov ah, [es:di] ; b1 + dec di + ; w0 = (b0<<8)|b1 dans AX déjà + + cmp bl, 0 + je .aligned + + ; unaligned: besoin b2 et w1 = (b1<<8)|b2 + add di, 2 + mov dl, [es:di] ; b2 + sub di, 2 + mov dh, ah ; b1 + ; DX = w1 (b1<<8)|b2 + + ; seg = (w0<>(8-off)) + ; off = BL, rshift = (8-BL) + push bx ; sauvegarde row/off + mov cl, bl + shl ax, cl ; AX = w0<>(8-off) + + or ax, dx ; AX = seg (16 bits alignés) + pop bx + + jmp .apply_masks + +.aligned: + ; seg = w0 déjà dans AX +.apply_masks: + ; newseg = (seg & AND) ^ XOR + and ax, cx + xor ax, dx ; AX = newseg + + cmp bl, 0 + je .write_aligned + + ; --- write unaligned: impact sur b0 (bas 8-off bits), b1 (tout), b2 (haut off bits) --- + ; n = 8-off + mov cl, 8 + sub cl, bl ; cl = n (1..7) + + ; val0 = newseg >> (8+off) + ; (8+off) = 8 + BL + mov dx, ax + mov cl, bl + add cl, 8 + shr dx, cl ; DL = val0 (0..(2^(8-off)-1)) + + ; mask0 = (1<> off) & 0xFF + mov dx, ax + mov cl, bl + shr dx, cl + inc di + mov [es:di], dl + dec di + + ; b2 high off bits = (newseg & ((1< ID - mov bl, MOUSE_GET_ID - call mouse_sendcmd - call ps2_read ; AL = ID + ; Get ID + mov bl, MOUSE_GET_ID + call mouse_sendcmd + call ps2_read ; AL = ID - cmp al, 03h - je .is4 - cmp al, 04h - je .is4 + cmp al, 03h + je .is4 + cmp al, 04h + je .is4 ret .is4: - mov byte [DBA_MOUSE_PACKETLEN], 4 + mov byte [DBA_MOUSE_PACKETLEN], 4 ret - + ; ------------------------------------------------------------ ; fonction de gestion du i8042 ; @@ -190,25 +228,25 @@ ps2_wait_ready_write: in al, PS2_PORT_CTRL test al, 02h ; IBF jnz .wait - ret + ret -; attendre que le 8042 soit pret a lire de l'information +; attendre que le 8042 soit pret a lire de l'information ps2_wait_ready_read: -.wait: +.wait: in al, PS2_PORT_CTRL test al, 01h ; OBF jz .wait - ret - + ret + ; lire de l'information depuis le 8042 -ps2_read: +ps2_read: call ps2_wait_ready_read in al, PS2_PORT_BUFFER - ret + ret -; vide le buffer interne du 8042 (information(s) ignorée(s)) +; vide le buffer interne du 8042 (information(s) ignorée(s)) ps2_flush_output: -.flush: +.flush: in al, PS2_PORT_CTRL test al, 01h jz .done @@ -216,14 +254,12 @@ ps2_flush_output: jmp .flush .done: ret - - ; ------------------------------------------------------------ -; envoye une commande souris +; envoye une commande souris et attends le ACK ; ; BL = commande souris (ou data après une commande F3) -; +; ; renvoi CF=0 si ACK, CF=1 sinon ; ------------------------------------------------------------ mouse_sendcmd: @@ -231,11 +267,11 @@ mouse_sendcmd: mov al, I8042_CMD_WRITE_AUX out PS2_PORT_CTRL, al - + call ps2_wait_ready_write mov al, bl out PS2_PORT_BUFFER, al - + call ps2_wait_ready_read ; AL = réponse cmp al, MOUSE_ACK jne .bad @@ -244,48 +280,75 @@ mouse_sendcmd: .bad: stc ret - + ; ------------------------------------------------------------ ; interrupt handler -; +; ; buffer[0] = status ; buffer[1] = déplacement x ; buffer[2] = déplacement y (inversé) -; +; buffer[4] = molette (si PacketLen = 4) +; +; status byte : +; bit 0 = bouton gauche +; bit 1 = bouton droit +; bit 2 = bouton milieu +; bit 3 = toujours 1 +; bit 4 = X sign +; bit 5 = Y sign +; bit 6 = X overflow +; bit 7 = Y overflow ; ------------------------------------------------------------ mouse_handler: - push ax - push bx - - ; use BDA segment + PUSH_ABCD push ds - mov ax,BDA_SEGMENT + + ; use BDA segment + mov ax,BDA_MOUSE_SEG 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 + + mov al, [DBA_MOUSE_PACKETLEN] + cmp [BDA_MOUSE_IDX], al jne .done mov [BDA_MOUSE_IDX], 0 - ; decode buffer + + ; decode buffer manuallement + mov al, [BDA_MOUSE_BUFFER] + mov [BDA_MOUSE_STATUS], al + mov al, [BDA_MOUSE_BUFFER+1] cbw add [BDA_MOUSE_X], ax - + mov al, [BDA_MOUSE_BUFFER+2] cbw sub [BDA_MOUSE_Y], ax + ; si packetlen = 4, gérer la molette; experimental + mov al, [BDA_MOUSE_BUFFER+3] + cbw + sub [BDA_MOUSE_WHEEL], ax + + ; restaurer l'ancien arrière plan du curseur + call gfx_cursor_restorebg + + ; sauvegarder le nouvel arrière plan du curseur + mov cx, [BDA_MOUSE_X] + mov dx, [BDA_MOUSE_Y] + call gfx_cursor_savebg + + call gfx_cursor_draw + .done: mov al, 0x20 out 0xA0, al ; EOI PIC esclave out 0x20, al ; EOI PIC maître - + pop ds - pop bx - pop ax + POP_ABCD iret \ No newline at end of file diff --git a/src/services/generic.asm b/src/services/generic.asm index 50ee15a..0f3d3fd 100644 --- a/src/services/generic.asm +++ b/src/services/generic.asm @@ -2,7 +2,6 @@ ; Project : Custom BIOS / ROM ; File : generic.asm ; Author : frater -; Created : 06 jan 2026 ; ; License : GNU General Public License v3.0 or later (GPL-3.0+) ; @@ -23,7 +22,7 @@ ; --------------------------------------------------------------------------- ; Détection RAM conventionnelle -; Teste la RAM de MEM_SEG_DEB jusqu’à 0xA000 (640KB), par pas de 1KB. +; 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: @@ -33,9 +32,9 @@ ; 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). +; - Ne testez pas au-delà de MEM_SEG_END (0xA000: début VGA/vidéo). ; --------------------------------------------------------------------------- -setup_ram: +ram_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) @@ -155,7 +154,7 @@ setup_check_vga: ; --------------------------------------------------------------------------- ; IVT install (8088, mode réel) - remplit les 256 vecteurs avec un handler IRET ; --------------------------------------------------------------------------- -setup_ivt: +ivt_setup: ; installation de la table d'interrupts xor ax, ax mov es, ax ; ES = 0000h -> base IVT @@ -177,11 +176,11 @@ setup_ivt: ; --------------------------------------------------------------------------- ; IVT install (8088, mode réel) - installe un handler a une interrupt calculée ; -; ax = int ide +; ax = int id ; dx = segment handler ; bx = offset handler ; --------------------------------------------------------------------------- -setup_setvector: +ivt_setvector: push es push di @@ -192,9 +191,11 @@ setup_setvector: mov es, ax ; ES = 0000h -> base IVT mov ax, bx ; offset du handler + cli stosw ; write offset (AX) -> [ES:DI], DI += 2 xchg ax, dx ; AX = segment, DX = offset stosw ; write segment (AX) -> [ES:DI], DI += 2 + sti pop di pop es diff --git a/src/services/macros.asm b/src/services/macros.asm new file mode 100644 index 0000000..d8cc324 --- /dev/null +++ b/src/services/macros.asm @@ -0,0 +1,45 @@ +; ============================================================================= +; Project : Custom BIOS / ROM +; File : macros.asm +; Author : frater +; +; License : GNU General Public License v3.0 or later (GPL-3.0+) +; +; This program is free software: you can redistribute it and/or modify +; it under the terms of the GNU General Public License as published by +; the Free Software Foundation, either version 3 of the License, or +; (at your option) any later version. +; +; This program is distributed in the hope that it will be useful, +; but WITHOUT ANY WARRANTY; without even the implied warranty of +; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +; GNU General Public License for more details. +; +; You should have received a copy of the GNU General Public License +; along with this program. If not, see . +; +; ============================================================================= + +%macro PUSH_ABCD 0 + push ax + push bx + push cx + push dx +%endmacro + +%macro PUSH_ID 0 + push di + push si +%endmacro + +%macro POP_ABCD 0 + pop dx + pop cx + pop bx + pop ax +%endmacro + +%macro POP_ID 0 + pop si + pop di +%endmacro