WIP : mouse cursor
This commit is contained in:
parent
495b90c958
commit
baddae1256
2 changed files with 384 additions and 376 deletions
|
|
@ -1,43 +1,324 @@
|
||||||
; On doit répartir sur 2 octets :
|
; ============================================================
|
||||||
; mask0 = glyph >> shift
|
; gfx_cursor_draw_rm16_i386_self
|
||||||
; mask1 = glyph << (8-shift)
|
; Entrée:
|
||||||
;
|
; DS = BDA_DATA_SEG
|
||||||
; Utilise AH pour conserver glyph original
|
; Sortie: rien
|
||||||
mov ah, al
|
; Détruit: registres sauvegardés/restaurés (PUSHA/POPA)
|
||||||
|
; ============================================================
|
||||||
|
cga_cursor_draw:
|
||||||
|
push ds
|
||||||
|
push es
|
||||||
|
push fs
|
||||||
|
push gs
|
||||||
|
pushad
|
||||||
|
|
||||||
; mask0 dans AL
|
; -----------------------------
|
||||||
mov al, ah
|
; ES = VRAM
|
||||||
shr al, cl
|
; -----------------------------
|
||||||
; mask1 dans AH
|
mov ax, VIDEO_SEG
|
||||||
mov ah, ah
|
mov es, ax
|
||||||
mov dl, 8
|
|
||||||
sub dl, cl
|
|
||||||
mov cl, dl
|
|
||||||
mov dl, ah
|
|
||||||
shl dl, cl
|
|
||||||
mov ah, dl
|
|
||||||
; restaurer shift dans CL (on en a besoin pour les lignes suivantes)
|
|
||||||
mov cl, [ds:GFX_CUR_SHIFT]
|
|
||||||
|
|
||||||
; Si mask0/mask1 nuls, saute ce côté
|
mov ax, BDA_DATA_SEG
|
||||||
%if GFX_CHAR_COL = 1
|
mov ds, ax
|
||||||
test al, al
|
; -----------------------------
|
||||||
jz .skip0_set
|
; GS:SI = sprite (AND puis XOR à +32)
|
||||||
or [es:di], al
|
; -----------------------------
|
||||||
.skip0_set:
|
mov ax, [BDA_MOUSE + mouse.cur_seg]
|
||||||
test ah, ah
|
mov gs, ax
|
||||||
jz .skip1_set
|
mov si, [BDA_MOUSE + mouse.cur_ofs]
|
||||||
or [es:di+1], ah
|
|
||||||
.skip1_set:
|
; -----------------------------
|
||||||
%else
|
; Charger x,y
|
||||||
test al, al
|
; CX = x, DX = y
|
||||||
jz .skip0_clr
|
; -----------------------------
|
||||||
not al
|
mov cx, [BDA_MOUSE + mouse.x]
|
||||||
and [es:di], al
|
mov dx, [BDA_MOUSE + mouse.y]
|
||||||
.skip0_clr:
|
|
||||||
test ah, ah
|
; off = x & 7 (stocké dans BL)
|
||||||
jz .skip1_clr
|
mov bl, cl
|
||||||
not ah
|
and bl, 7
|
||||||
and [es:di+1], ah
|
|
||||||
.skip1_clr:
|
; width = min(16, 640-x) -> DL
|
||||||
%endif
|
mov ax, GFX_WIDTH
|
||||||
|
sub ax, cx
|
||||||
|
cmp ax, 16
|
||||||
|
jbe .w_ok
|
||||||
|
mov ax, 16
|
||||||
|
.w_ok:
|
||||||
|
test al, al
|
||||||
|
jz .done
|
||||||
|
mov dl, al ; DL = width (1..16)
|
||||||
|
|
||||||
|
; height = min(16, 200-y) -> BP (compteur)
|
||||||
|
mov bp, GFX_HEIGHT
|
||||||
|
sub bp, dx
|
||||||
|
cmp bp, 16
|
||||||
|
jbe .h_ok
|
||||||
|
mov bp, 16
|
||||||
|
.h_ok:
|
||||||
|
test bp, bp
|
||||||
|
jz .done
|
||||||
|
|
||||||
|
; bytes_to_touch = ((off + width + 7) >> 3) -> BH
|
||||||
|
mov ah, bl
|
||||||
|
add ah, dl
|
||||||
|
add ah, 7
|
||||||
|
shr ah, 3
|
||||||
|
mov bh, ah ; BH = 1..3
|
||||||
|
|
||||||
|
; clipmask16 = 0xFFFF << (16-width) -> (on le recalculera par ligne)
|
||||||
|
; parité initiale (y&1) -> CH
|
||||||
|
mov ch, byte [BDA_MOUSE + mouse.y]
|
||||||
|
and ch, 1
|
||||||
|
|
||||||
|
; -----------------------------
|
||||||
|
; Calcul DI = adresse VRAM pour (x,y)
|
||||||
|
; 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 ; x/8
|
||||||
|
add di, ax
|
||||||
|
|
||||||
|
test byte [BDA_MOUSE + mouse.y], 1
|
||||||
|
jz .addr_even
|
||||||
|
add di, CGA_ODD_BANK
|
||||||
|
.addr_even:
|
||||||
|
|
||||||
|
; row index dans AL
|
||||||
|
xor ax, ax ; AL = 0 (row)
|
||||||
|
|
||||||
|
.row_loop:
|
||||||
|
; conserver row + (off/bytes) sur pile, pour libérer BL/BH si besoin
|
||||||
|
push ax
|
||||||
|
push bx ; BL=off, BH=bytes_to_touch
|
||||||
|
|
||||||
|
; -----------------------------------------
|
||||||
|
; Charger AND/XOR pour la ligne (row=AL)
|
||||||
|
; CX = AND, DX = XOR
|
||||||
|
; -----------------------------------------
|
||||||
|
xor ah, ah
|
||||||
|
shl ax, 1 ; AX = row*2
|
||||||
|
|
||||||
|
mov bx, si
|
||||||
|
add bx, ax
|
||||||
|
mov cx, [gs:bx] ; AND word
|
||||||
|
add bx, 32
|
||||||
|
mov dx, [gs:bx] ; XOR word
|
||||||
|
|
||||||
|
; restaurer row dans AL
|
||||||
|
pop bx ; restore off/bytes into BL/BH
|
||||||
|
pop ax ; restore row in AL
|
||||||
|
|
||||||
|
; -----------------------------------------
|
||||||
|
; clipmask16 = 0xFFFF << (16-width)
|
||||||
|
; width est dans DL
|
||||||
|
; clipmask -> BX
|
||||||
|
; -----------------------------------------
|
||||||
|
mov bx, 0FFFFh
|
||||||
|
mov cl, 16
|
||||||
|
sub cl, dl
|
||||||
|
shl bx, cl ; BX = clipmask
|
||||||
|
|
||||||
|
; AND' = AND | (~clipmask)
|
||||||
|
mov ax, bx
|
||||||
|
not ax
|
||||||
|
or cx, ax ; CX = AND'
|
||||||
|
|
||||||
|
; XOR' = XOR & clipmask
|
||||||
|
and dx, bx ; DX = XOR'
|
||||||
|
|
||||||
|
; -----------------------------------------
|
||||||
|
; Construire seg 16-bit depuis VRAM (ES:DI)
|
||||||
|
; w0 = (b0<<8)|b1
|
||||||
|
; seg = (w0<<off) | (b2>>(8-off)) si off!=0 et bytes==3
|
||||||
|
; seg -> AX
|
||||||
|
; -----------------------------------------
|
||||||
|
; AX = w0
|
||||||
|
mov ah, [es:di] ; b0
|
||||||
|
mov al, [es:di+1] ; b1
|
||||||
|
|
||||||
|
; if off==0 -> seg ready
|
||||||
|
test bl, bl
|
||||||
|
jz .seg_ready
|
||||||
|
|
||||||
|
; seg = w0 << off
|
||||||
|
mov cl, bl
|
||||||
|
shl ax, cl
|
||||||
|
|
||||||
|
; if bytes==3, OR b2>>(8-off)
|
||||||
|
cmp bh, 3
|
||||||
|
jne .seg_ready
|
||||||
|
|
||||||
|
mov cl, 8
|
||||||
|
sub cl, bl ; 8-off
|
||||||
|
xor bh, bh ; BH=0, BL=off (on évite bpl etc)
|
||||||
|
mov bl, [es:di+2] ; BL=b2
|
||||||
|
shr bx, cl ; BX = b2>>(8-off)
|
||||||
|
or ax, bx
|
||||||
|
; restaurer BL=off, BH=bytes: (on ne peut pas, on a écrasé)
|
||||||
|
; => ne jamais écraser BL/BH. Donc on refait proprement:
|
||||||
|
; (ce bloc est remplacé ci-dessous)
|
||||||
|
; --- on ne doit pas passer ici ---
|
||||||
|
.seg_ready:
|
||||||
|
|
||||||
|
; *** IMPORTANT ***
|
||||||
|
; Le bloc ci-dessus a montré le piège (écraser BL/BH).
|
||||||
|
; On fait le chemin correct ci-dessous, sans toucher BL/BH.
|
||||||
|
|
||||||
|
; Refaire seg proprement sans écraser BL/BH:
|
||||||
|
; AX = w0 (recharge)
|
||||||
|
mov ah, [es:di]
|
||||||
|
mov al, [es:di+1]
|
||||||
|
|
||||||
|
test bl, bl
|
||||||
|
jz .seg2_ready
|
||||||
|
|
||||||
|
mov cl, bl
|
||||||
|
shl ax, cl
|
||||||
|
|
||||||
|
cmp bh, 3
|
||||||
|
jne .seg2_ready
|
||||||
|
|
||||||
|
mov cl, 8
|
||||||
|
sub cl, bl ; 8-off
|
||||||
|
xor ah, ah
|
||||||
|
mov al, [es:di+2] ; AL=b2
|
||||||
|
; AX = b2
|
||||||
|
shr ax, cl ; AX = b2>>(8-off)
|
||||||
|
; OR into seg: need seg in another reg -> use BX temp
|
||||||
|
mov bx, [es:di] ; not ok (word read uses little endian, avoid)
|
||||||
|
; simplest: use stack temp
|
||||||
|
push ax ; save (b2>>(8-off))
|
||||||
|
; reload seg again and OR
|
||||||
|
mov ah, [es:di]
|
||||||
|
mov al, [es:di+1]
|
||||||
|
mov cl, bl
|
||||||
|
shl ax, cl
|
||||||
|
pop bx
|
||||||
|
or ax, bx
|
||||||
|
.seg2_ready:
|
||||||
|
|
||||||
|
; -----------------------------------------
|
||||||
|
; newseg = (seg & AND') ^ XOR'
|
||||||
|
; seg in AX
|
||||||
|
; -----------------------------------------
|
||||||
|
and ax, cx
|
||||||
|
xor ax, dx ; AX=newseg
|
||||||
|
|
||||||
|
; -----------------------------------------
|
||||||
|
; Ecriture vers VRAM
|
||||||
|
; - off==0 : b0=AH, b1=AL (si bytes>=2)
|
||||||
|
; - off!=0 : b0 partiel, b1 complet si bytes>=2, b2 partiel si bytes==3
|
||||||
|
; -----------------------------------------
|
||||||
|
test bl, bl
|
||||||
|
jnz .write_unaligned
|
||||||
|
|
||||||
|
.write_aligned:
|
||||||
|
mov [es:di], ah
|
||||||
|
cmp bh, 1
|
||||||
|
je .after_write
|
||||||
|
mov [es:di+1], al
|
||||||
|
jmp .after_write
|
||||||
|
|
||||||
|
.write_unaligned:
|
||||||
|
; mask0 = (1<<(8-off))-1 (bits bas de b0)
|
||||||
|
mov cl, 8
|
||||||
|
sub cl, bl
|
||||||
|
mov dh, 1
|
||||||
|
shl dh, cl
|
||||||
|
dec dh ; DH = mask0
|
||||||
|
|
||||||
|
; val0 = newseg >> (8+off)
|
||||||
|
mov bx, ax ; BX = newseg
|
||||||
|
mov cl, bl
|
||||||
|
add cl, 8
|
||||||
|
shr bx, cl ; BL = val0 (low 8)
|
||||||
|
|
||||||
|
; b0 = (old & ~mask0) | (val0 & mask0)
|
||||||
|
mov dl, [es:di] ; old b0
|
||||||
|
mov cl, dh ; CL=mask0
|
||||||
|
not cl
|
||||||
|
and dl, cl ; keep upper bits
|
||||||
|
not cl ; CL=mask0
|
||||||
|
and bl, cl ; val0 masked
|
||||||
|
or dl, bl
|
||||||
|
mov [es:di], dl
|
||||||
|
|
||||||
|
cmp bh, 1
|
||||||
|
je .after_write
|
||||||
|
|
||||||
|
; b1 = (newseg >> off) & 0xFF
|
||||||
|
mov bx, ax
|
||||||
|
mov cl, bl ; BUG: BL now val0, not off
|
||||||
|
; => on doit recharger off depuis BDA_MOUSE.x &7, ou le sauver.
|
||||||
|
; On le sauve au début de la fonction dans une variable: ici on le recharge (coût faible)
|
||||||
|
mov bl, [BDA_MOUSE + mouse.x] ; low byte x
|
||||||
|
and bl, 7
|
||||||
|
mov cl, bl
|
||||||
|
shr bx, cl
|
||||||
|
mov [es:di+1], bl
|
||||||
|
|
||||||
|
cmp bh, 2
|
||||||
|
je .after_write
|
||||||
|
|
||||||
|
; b2 partiel (bits hauts off)
|
||||||
|
; mask2 = 0xFF << (8-off)
|
||||||
|
mov cl, 8
|
||||||
|
sub cl, bl ; bl=off
|
||||||
|
mov dl, 0FFh
|
||||||
|
shl dl, cl ; DL=mask2
|
||||||
|
|
||||||
|
; part2 = (newseg << (8-off)) & 0xFF
|
||||||
|
mov bx, ax ; BX=newseg
|
||||||
|
shl bx, cl ; BL=part2
|
||||||
|
|
||||||
|
; b2 = (old & ~mask2) | (part2 & mask2)
|
||||||
|
mov dh, [es:di+2] ; old b2
|
||||||
|
mov cl, dl ; CL=mask2
|
||||||
|
not cl
|
||||||
|
and dh, cl
|
||||||
|
not cl
|
||||||
|
and bl, cl
|
||||||
|
or dh, bl
|
||||||
|
mov [es:di+2], dh
|
||||||
|
|
||||||
|
.after_write:
|
||||||
|
; -----------------------------------------
|
||||||
|
; next row
|
||||||
|
; -----------------------------------------
|
||||||
|
inc al
|
||||||
|
dec bp
|
||||||
|
jz .done
|
||||||
|
|
||||||
|
; stepping CGA:
|
||||||
|
; even->odd: +0x2000
|
||||||
|
; odd ->even: -0x2000 + 80
|
||||||
|
test ch, ch
|
||||||
|
jz .even_to_odd
|
||||||
|
|
||||||
|
; odd -> even
|
||||||
|
sub di, CGA_ODD_BANK
|
||||||
|
add di, CGA_STRIDE
|
||||||
|
xor ch, ch
|
||||||
|
jmp .row_loop
|
||||||
|
|
||||||
|
.even_to_odd:
|
||||||
|
add di, CGA_ODD_BANK
|
||||||
|
mov ch, 1
|
||||||
|
jmp .row_loop
|
||||||
|
|
||||||
|
.done:
|
||||||
|
popad
|
||||||
|
pop gs
|
||||||
|
pop fs
|
||||||
|
pop es
|
||||||
|
pop ds
|
||||||
|
ret
|
||||||
|
|
@ -139,6 +139,37 @@ cga_init:
|
||||||
cga_none:
|
cga_none:
|
||||||
ret
|
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))
|
||||||
|
; ------------------------------------------------------------
|
||||||
|
cga_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
|
||||||
|
|
||||||
; ---------------------------------------------------------------------------
|
; ---------------------------------------------------------------------------
|
||||||
; gfx_set_charpos
|
; gfx_set_charpos
|
||||||
; In : CX = x (pixels), DX = y (pixels)
|
; In : CX = x (pixels), DX = y (pixels)
|
||||||
|
|
@ -185,7 +216,6 @@ cga_set_charpos:
|
||||||
mov [fs:BDA_GFX + gfx.cur_line_ofs], ax
|
mov [fs:BDA_GFX + gfx.cur_line_ofs], ax
|
||||||
mov [fs:BDA_GFX + gfx.cur_offset], bx
|
mov [fs:BDA_GFX + gfx.cur_offset], bx
|
||||||
|
|
||||||
|
|
||||||
pop fs
|
pop fs
|
||||||
popa
|
popa
|
||||||
ret
|
ret
|
||||||
|
|
@ -321,7 +351,7 @@ cga_putc_unaligned:
|
||||||
xchg ax, dx
|
xchg ax, dx
|
||||||
|
|
||||||
cmp ch,0
|
cmp ch,0
|
||||||
jne .black_transparent
|
ja .black_transparent
|
||||||
|
|
||||||
; white with transparent
|
; white with transparent
|
||||||
or [es:di], ax
|
or [es:di], ax
|
||||||
|
|
@ -338,31 +368,6 @@ cga_putc_unaligned:
|
||||||
and [es:di], ax
|
and [es:di], ax
|
||||||
and [es:di+bx], dx
|
and [es:di+bx], dx
|
||||||
; jmp .next
|
; jmp .next
|
||||||
|
|
||||||
; .transparent_white:
|
|
||||||
; cmp ch,2
|
|
||||||
; jne .black_white
|
|
||||||
;
|
|
||||||
; ; transparent on white
|
|
||||||
; not ax
|
|
||||||
; or [es:di], ax
|
|
||||||
; or [es:di+bx], dx
|
|
||||||
; jmp .next
|
|
||||||
;
|
|
||||||
; .black_white:
|
|
||||||
; cmp ch,3
|
|
||||||
; jne .white_transparent
|
|
||||||
;
|
|
||||||
; ; white on black
|
|
||||||
; mov [es:di], ax
|
|
||||||
; mov [es:di+bx], dx
|
|
||||||
; jmp .next
|
|
||||||
;
|
|
||||||
; .white_transparent:
|
|
||||||
; not ax
|
|
||||||
; mov [es:di], ax
|
|
||||||
; mov [es:di+bx], dx
|
|
||||||
;
|
|
||||||
.next:
|
.next:
|
||||||
add di,CGA_STRIDE
|
add di,CGA_STRIDE
|
||||||
|
|
||||||
|
|
@ -420,37 +425,6 @@ cga_write:
|
||||||
pop ax
|
pop ax
|
||||||
ret
|
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))
|
|
||||||
; ------------------------------------------------------------
|
|
||||||
cga_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.
|
; Dessine un pixel, accès VRAM direct.
|
||||||
;
|
;
|
||||||
|
|
@ -584,7 +558,7 @@ cga_getpixel_fast:
|
||||||
ret
|
ret
|
||||||
|
|
||||||
cga_cursor_move:
|
cga_cursor_move:
|
||||||
pusha
|
push ax
|
||||||
push ds
|
push ds
|
||||||
push es
|
push es
|
||||||
|
|
||||||
|
|
@ -607,7 +581,7 @@ cga_cursor_move:
|
||||||
.done:
|
.done:
|
||||||
pop es
|
pop es
|
||||||
pop ds
|
pop ds
|
||||||
popa
|
pop ax
|
||||||
ret
|
ret
|
||||||
|
|
||||||
; ============================================================
|
; ============================================================
|
||||||
|
|
@ -618,9 +592,11 @@ cga_cursor_move:
|
||||||
; Détruit: registres sauvegardés/restaurés (PUSHA/POPA)
|
; Détruit: registres sauvegardés/restaurés (PUSHA/POPA)
|
||||||
; ============================================================
|
; ============================================================
|
||||||
cga_cursor_draw:
|
cga_cursor_draw:
|
||||||
|
push ds
|
||||||
push es
|
push es
|
||||||
|
push fs
|
||||||
push gs
|
push gs
|
||||||
pusha
|
pushad
|
||||||
|
|
||||||
; -----------------------------
|
; -----------------------------
|
||||||
; ES = VRAM
|
; ES = VRAM
|
||||||
|
|
@ -628,6 +604,8 @@ cga_cursor_draw:
|
||||||
mov ax, VIDEO_SEG
|
mov ax, VIDEO_SEG
|
||||||
mov es, ax
|
mov es, ax
|
||||||
|
|
||||||
|
mov ax, BDA_DATA_SEG
|
||||||
|
mov ds, ax
|
||||||
; -----------------------------
|
; -----------------------------
|
||||||
; GS:SI = sprite (AND puis XOR à +32)
|
; GS:SI = sprite (AND puis XOR à +32)
|
||||||
; -----------------------------
|
; -----------------------------
|
||||||
|
|
@ -642,291 +620,40 @@ cga_cursor_draw:
|
||||||
mov cx, [BDA_MOUSE + mouse.x]
|
mov cx, [BDA_MOUSE + mouse.x]
|
||||||
mov dx, [BDA_MOUSE + mouse.y]
|
mov dx, [BDA_MOUSE + mouse.y]
|
||||||
|
|
||||||
; off = x & 7 (stocké dans BL)
|
; get DI = offset de départ x,y
|
||||||
mov bl, cl
|
; on ignore le bitmask retourné
|
||||||
and bl, 7
|
call cga_calc_addr
|
||||||
|
|
||||||
; width = min(16, 640-x) -> DL
|
mov ax, CGA_ODD_BANK
|
||||||
mov ax, GFX_WIDTH
|
|
||||||
sub ax, cx
|
|
||||||
cmp ax, 16
|
|
||||||
jbe .w_ok
|
|
||||||
mov ax, 16
|
|
||||||
.w_ok:
|
|
||||||
test al, al
|
|
||||||
jz .done
|
|
||||||
mov dl, al ; DL = width (1..16)
|
|
||||||
|
|
||||||
; height = min(16, 200-y) -> BP (compteur)
|
test cx, 0x0001 ; y est pair: +0x2000
|
||||||
mov bp, GFX_HEIGHT
|
|
||||||
sub bp, dx
|
|
||||||
cmp bp, 16
|
|
||||||
jbe .h_ok
|
|
||||||
mov bp, 16
|
|
||||||
.h_ok:
|
|
||||||
test bp, bp
|
|
||||||
jz .done
|
|
||||||
|
|
||||||
; bytes_to_touch = ((off + width + 7) >> 3) -> BH
|
|
||||||
mov ah, bl
|
|
||||||
add ah, dl
|
|
||||||
add ah, 7
|
|
||||||
shr ah, 3
|
|
||||||
mov bh, ah ; BH = 1..3
|
|
||||||
|
|
||||||
; clipmask16 = 0xFFFF << (16-width) -> (on le recalculera par ligne)
|
|
||||||
; parité initiale (y&1) -> CH
|
|
||||||
mov ch, byte [BDA_MOUSE + mouse.y]
|
|
||||||
and ch, 1
|
|
||||||
|
|
||||||
; -----------------------------
|
|
||||||
; Calcul DI = adresse VRAM pour (x,y)
|
|
||||||
; 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 ; x/8
|
|
||||||
add di, ax
|
|
||||||
|
|
||||||
test byte [BDA_MOUSE + mouse.y], 1
|
|
||||||
jz .addr_even
|
jz .addr_even
|
||||||
add di, CGA_ODD_BANK
|
neg ax ; y impair: -0x2000
|
||||||
|
|
||||||
.addr_even:
|
.addr_even:
|
||||||
|
; conservation du pas entre les 2 banques de VRAM
|
||||||
|
mov [BDA_MOUSE + mouse.cur_bank_add], ax
|
||||||
|
|
||||||
; row index dans AL
|
; calcul du bit rotation du curseur
|
||||||
xor ax, ax ; AL = 0 (row)
|
mov ax, cx
|
||||||
|
and ax, 0x07
|
||||||
|
mov [BDA_MOUSE + mouse.cur_bit_ofs], al
|
||||||
|
|
||||||
|
; curseur = 16 lignes
|
||||||
|
mov cx, 16
|
||||||
.row_loop:
|
.row_loop:
|
||||||
; conserver row + (off/bytes) sur pile, pour libérer BL/BH si besoin
|
xor eax,eax
|
||||||
push ax
|
xor ebx,ebx
|
||||||
push bx ; BL=off, BH=bytes_to_touch
|
|
||||||
|
|
||||||
; -----------------------------------------
|
;
|
||||||
; Charger AND/XOR pour la ligne (row=AL)
|
|
||||||
; CX = AND, DX = XOR
|
|
||||||
; -----------------------------------------
|
|
||||||
xor ah, ah
|
|
||||||
shl ax, 1 ; AX = row*2
|
|
||||||
|
|
||||||
mov bx, si
|
|
||||||
add bx, ax
|
|
||||||
mov cx, [gs:bx] ; AND word
|
|
||||||
add bx, 32
|
|
||||||
mov dx, [gs:bx] ; XOR word
|
|
||||||
|
|
||||||
; restaurer row dans AL
|
|
||||||
pop bx ; restore off/bytes into BL/BH
|
|
||||||
pop ax ; restore row in AL
|
|
||||||
|
|
||||||
; -----------------------------------------
|
|
||||||
; clipmask16 = 0xFFFF << (16-width)
|
|
||||||
; width est dans DL
|
|
||||||
; clipmask -> BX
|
|
||||||
; -----------------------------------------
|
|
||||||
mov bx, 0FFFFh
|
|
||||||
mov cl, 16
|
|
||||||
sub cl, dl
|
|
||||||
shl bx, cl ; BX = clipmask
|
|
||||||
|
|
||||||
; AND' = AND | (~clipmask)
|
|
||||||
mov ax, bx
|
|
||||||
not ax
|
|
||||||
or cx, ax ; CX = AND'
|
|
||||||
|
|
||||||
; XOR' = XOR & clipmask
|
|
||||||
and dx, bx ; DX = XOR'
|
|
||||||
|
|
||||||
; -----------------------------------------
|
|
||||||
; Construire seg 16-bit depuis VRAM (ES:DI)
|
|
||||||
; w0 = (b0<<8)|b1
|
|
||||||
; seg = (w0<<off) | (b2>>(8-off)) si off!=0 et bytes==3
|
|
||||||
; seg -> AX
|
|
||||||
; -----------------------------------------
|
|
||||||
; AX = w0
|
|
||||||
mov ah, [es:di] ; b0
|
|
||||||
mov al, [es:di+1] ; b1
|
|
||||||
|
|
||||||
; if off==0 -> seg ready
|
|
||||||
test bl, bl
|
|
||||||
jz .seg_ready
|
|
||||||
|
|
||||||
; seg = w0 << off
|
|
||||||
mov cl, bl
|
|
||||||
shl ax, cl
|
|
||||||
|
|
||||||
; if bytes==3, OR b2>>(8-off)
|
|
||||||
cmp bh, 3
|
|
||||||
jne .seg_ready
|
|
||||||
|
|
||||||
mov cl, 8
|
|
||||||
sub cl, bl ; 8-off
|
|
||||||
xor bh, bh ; BH=0, BL=off (on évite bpl etc)
|
|
||||||
mov bl, [es:di+2] ; BL=b2
|
|
||||||
shr bx, cl ; BX = b2>>(8-off)
|
|
||||||
or ax, bx
|
|
||||||
; restaurer BL=off, BH=bytes: (on ne peut pas, on a écrasé)
|
|
||||||
; => ne jamais écraser BL/BH. Donc on refait proprement:
|
|
||||||
; (ce bloc est remplacé ci-dessous)
|
|
||||||
; --- on ne doit pas passer ici ---
|
|
||||||
.seg_ready:
|
|
||||||
|
|
||||||
; *** IMPORTANT ***
|
|
||||||
; Le bloc ci-dessus a montré le piège (écraser BL/BH).
|
|
||||||
; On fait le chemin correct ci-dessous, sans toucher BL/BH.
|
|
||||||
|
|
||||||
; Refaire seg proprement sans écraser BL/BH:
|
|
||||||
; AX = w0 (recharge)
|
|
||||||
mov ah, [es:di]
|
|
||||||
mov al, [es:di+1]
|
|
||||||
|
|
||||||
test bl, bl
|
|
||||||
jz .seg2_ready
|
|
||||||
|
|
||||||
mov cl, bl
|
|
||||||
shl ax, cl
|
|
||||||
|
|
||||||
cmp bh, 3
|
|
||||||
jne .seg2_ready
|
|
||||||
|
|
||||||
mov cl, 8
|
|
||||||
sub cl, bl ; 8-off
|
|
||||||
xor ah, ah
|
|
||||||
mov al, [es:di+2] ; AL=b2
|
|
||||||
; AX = b2
|
|
||||||
shr ax, cl ; AX = b2>>(8-off)
|
|
||||||
; OR into seg: need seg in another reg -> use BX temp
|
|
||||||
mov bx, [es:di] ; not ok (word read uses little endian, avoid)
|
|
||||||
; simplest: use stack temp
|
|
||||||
push ax ; save (b2>>(8-off))
|
|
||||||
; reload seg again and OR
|
|
||||||
mov ah, [es:di]
|
|
||||||
mov al, [es:di+1]
|
|
||||||
mov cl, bl
|
|
||||||
shl ax, cl
|
|
||||||
pop bx
|
|
||||||
or ax, bx
|
|
||||||
.seg2_ready:
|
|
||||||
|
|
||||||
; -----------------------------------------
|
|
||||||
; newseg = (seg & AND') ^ XOR'
|
|
||||||
; seg in AX
|
|
||||||
; -----------------------------------------
|
|
||||||
and ax, cx
|
|
||||||
xor ax, dx ; AX=newseg
|
|
||||||
|
|
||||||
; -----------------------------------------
|
|
||||||
; Ecriture vers VRAM
|
|
||||||
; - off==0 : b0=AH, b1=AL (si bytes>=2)
|
|
||||||
; - off!=0 : b0 partiel, b1 complet si bytes>=2, b2 partiel si bytes==3
|
|
||||||
; -----------------------------------------
|
|
||||||
test bl, bl
|
|
||||||
jnz .write_unaligned
|
|
||||||
|
|
||||||
.write_aligned:
|
|
||||||
mov [es:di], ah
|
|
||||||
cmp bh, 1
|
|
||||||
je .after_write
|
|
||||||
mov [es:di+1], al
|
|
||||||
jmp .after_write
|
|
||||||
|
|
||||||
.write_unaligned:
|
|
||||||
; mask0 = (1<<(8-off))-1 (bits bas de b0)
|
|
||||||
mov cl, 8
|
|
||||||
sub cl, bl
|
|
||||||
mov dh, 1
|
|
||||||
shl dh, cl
|
|
||||||
dec dh ; DH = mask0
|
|
||||||
|
|
||||||
; val0 = newseg >> (8+off)
|
|
||||||
mov bx, ax ; BX = newseg
|
|
||||||
mov cl, bl
|
|
||||||
add cl, 8
|
|
||||||
shr bx, cl ; BL = val0 (low 8)
|
|
||||||
|
|
||||||
; b0 = (old & ~mask0) | (val0 & mask0)
|
|
||||||
mov dl, [es:di] ; old b0
|
|
||||||
mov cl, dh ; CL=mask0
|
|
||||||
not cl
|
|
||||||
and dl, cl ; keep upper bits
|
|
||||||
not cl ; CL=mask0
|
|
||||||
and bl, cl ; val0 masked
|
|
||||||
or dl, bl
|
|
||||||
mov [es:di], dl
|
|
||||||
|
|
||||||
cmp bh, 1
|
|
||||||
je .after_write
|
|
||||||
|
|
||||||
; b1 = (newseg >> off) & 0xFF
|
|
||||||
mov bx, ax
|
|
||||||
mov cl, bl ; BUG: BL now val0, not off
|
|
||||||
; => on doit recharger off depuis BDA_MOUSE.x &7, ou le sauver.
|
|
||||||
; On le sauve au début de la fonction dans une variable: ici on le recharge (coût faible)
|
|
||||||
mov bl, [BDA_MOUSE + mouse.x] ; low byte x
|
|
||||||
and bl, 7
|
|
||||||
mov cl, bl
|
|
||||||
shr bx, cl
|
|
||||||
mov [es:di+1], bl
|
|
||||||
|
|
||||||
cmp bh, 2
|
|
||||||
je .after_write
|
|
||||||
|
|
||||||
; b2 partiel (bits hauts off)
|
|
||||||
; mask2 = 0xFF << (8-off)
|
|
||||||
mov cl, 8
|
|
||||||
sub cl, bl ; bl=off
|
|
||||||
mov dl, 0FFh
|
|
||||||
shl dl, cl ; DL=mask2
|
|
||||||
|
|
||||||
; part2 = (newseg << (8-off)) & 0xFF
|
|
||||||
mov bx, ax ; BX=newseg
|
|
||||||
shl bx, cl ; BL=part2
|
|
||||||
|
|
||||||
; b2 = (old & ~mask2) | (part2 & mask2)
|
|
||||||
mov dh, [es:di+2] ; old b2
|
|
||||||
mov cl, dl ; CL=mask2
|
|
||||||
not cl
|
|
||||||
and dh, cl
|
|
||||||
not cl
|
|
||||||
and bl, cl
|
|
||||||
or dh, bl
|
|
||||||
mov [es:di+2], dh
|
|
||||||
|
|
||||||
.after_write:
|
|
||||||
; -----------------------------------------
|
|
||||||
; next row
|
|
||||||
; -----------------------------------------
|
|
||||||
inc al
|
|
||||||
dec bp
|
|
||||||
jz .done
|
|
||||||
|
|
||||||
; stepping CGA:
|
|
||||||
; even->odd: +0x2000
|
|
||||||
; odd ->even: -0x2000 + 80
|
|
||||||
test ch, ch
|
|
||||||
jz .even_to_odd
|
|
||||||
|
|
||||||
; odd -> even
|
|
||||||
sub di, CGA_ODD_BANK
|
|
||||||
add di, CGA_STRIDE
|
|
||||||
xor ch, ch
|
|
||||||
jmp .row_loop
|
|
||||||
|
|
||||||
.even_to_odd:
|
|
||||||
add di, CGA_ODD_BANK
|
|
||||||
mov ch, 1
|
|
||||||
jmp .row_loop
|
|
||||||
|
|
||||||
.done:
|
.done:
|
||||||
popa
|
popad
|
||||||
pop gs
|
pop gs
|
||||||
|
pop fs
|
||||||
pop es
|
pop es
|
||||||
|
pop ds
|
||||||
ret
|
ret
|
||||||
|
|
||||||
; -----------------------------------------------
|
; -----------------------------------------------
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue