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
|
||||
; mask1 = glyph << (8-shift)
|
||||
;
|
||||
; Utilise AH pour conserver glyph original
|
||||
mov ah, al
|
||||
; ============================================================
|
||||
; gfx_cursor_draw_rm16_i386_self
|
||||
; Entrée:
|
||||
; DS = BDA_DATA_SEG
|
||||
; Sortie: rien
|
||||
; 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
|
||||
shr al, cl
|
||||
; mask1 dans AH
|
||||
mov ah, ah
|
||||
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]
|
||||
; -----------------------------
|
||||
; ES = VRAM
|
||||
; -----------------------------
|
||||
mov ax, VIDEO_SEG
|
||||
mov es, ax
|
||||
|
||||
; Si mask0/mask1 nuls, saute ce côté
|
||||
%if GFX_CHAR_COL = 1
|
||||
test al, al
|
||||
jz .skip0_set
|
||||
or [es:di], al
|
||||
.skip0_set:
|
||||
test ah, ah
|
||||
jz .skip1_set
|
||||
or [es:di+1], ah
|
||||
.skip1_set:
|
||||
%else
|
||||
test al, al
|
||||
jz .skip0_clr
|
||||
not al
|
||||
and [es:di], al
|
||||
.skip0_clr:
|
||||
test ah, ah
|
||||
jz .skip1_clr
|
||||
not ah
|
||||
and [es:di+1], ah
|
||||
.skip1_clr:
|
||||
%endif
|
||||
mov ax, BDA_DATA_SEG
|
||||
mov ds, ax
|
||||
; -----------------------------
|
||||
; GS:SI = sprite (AND puis XOR à +32)
|
||||
; -----------------------------
|
||||
mov ax, [BDA_MOUSE + mouse.cur_seg]
|
||||
mov gs, ax
|
||||
mov si, [BDA_MOUSE + mouse.cur_ofs]
|
||||
|
||||
; -----------------------------
|
||||
; Charger x,y
|
||||
; CX = x, DX = y
|
||||
; -----------------------------
|
||||
mov cx, [BDA_MOUSE + mouse.x]
|
||||
mov dx, [BDA_MOUSE + mouse.y]
|
||||
|
||||
; off = x & 7 (stocké dans BL)
|
||||
mov bl, cl
|
||||
and bl, 7
|
||||
|
||||
; width = min(16, 640-x) -> DL
|
||||
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:
|
||||
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
|
||||
; 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_offset], bx
|
||||
|
||||
|
||||
pop fs
|
||||
popa
|
||||
ret
|
||||
|
|
@ -321,7 +351,7 @@ cga_putc_unaligned:
|
|||
xchg ax, dx
|
||||
|
||||
cmp ch,0
|
||||
jne .black_transparent
|
||||
ja .black_transparent
|
||||
|
||||
; white with transparent
|
||||
or [es:di], ax
|
||||
|
|
@ -338,31 +368,6 @@ cga_putc_unaligned:
|
|||
and [es:di], ax
|
||||
and [es:di+bx], dx
|
||||
; 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:
|
||||
add di,CGA_STRIDE
|
||||
|
||||
|
|
@ -420,37 +425,6 @@ cga_write:
|
|||
pop ax
|
||||
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.
|
||||
;
|
||||
|
|
@ -584,7 +558,7 @@ cga_getpixel_fast:
|
|||
ret
|
||||
|
||||
cga_cursor_move:
|
||||
pusha
|
||||
push ax
|
||||
push ds
|
||||
push es
|
||||
|
||||
|
|
@ -607,7 +581,7 @@ cga_cursor_move:
|
|||
.done:
|
||||
pop es
|
||||
pop ds
|
||||
popa
|
||||
pop ax
|
||||
ret
|
||||
|
||||
; ============================================================
|
||||
|
|
@ -618,9 +592,11 @@ cga_cursor_move:
|
|||
; Détruit: registres sauvegardés/restaurés (PUSHA/POPA)
|
||||
; ============================================================
|
||||
cga_cursor_draw:
|
||||
push ds
|
||||
push es
|
||||
push fs
|
||||
push gs
|
||||
pusha
|
||||
pushad
|
||||
|
||||
; -----------------------------
|
||||
; ES = VRAM
|
||||
|
|
@ -628,6 +604,8 @@ cga_cursor_draw:
|
|||
mov ax, VIDEO_SEG
|
||||
mov es, ax
|
||||
|
||||
mov ax, BDA_DATA_SEG
|
||||
mov ds, ax
|
||||
; -----------------------------
|
||||
; GS:SI = sprite (AND puis XOR à +32)
|
||||
; -----------------------------
|
||||
|
|
@ -642,291 +620,40 @@ cga_cursor_draw:
|
|||
mov cx, [BDA_MOUSE + mouse.x]
|
||||
mov dx, [BDA_MOUSE + mouse.y]
|
||||
|
||||
; off = x & 7 (stocké dans BL)
|
||||
mov bl, cl
|
||||
and bl, 7
|
||||
; get DI = offset de départ x,y
|
||||
; on ignore le bitmask retourné
|
||||
call cga_calc_addr
|
||||
|
||||
; width = min(16, 640-x) -> DL
|
||||
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)
|
||||
mov ax, CGA_ODD_BANK
|
||||
|
||||
; 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
|
||||
test cx, 0x0001 ; y est pair: +0x2000
|
||||
|
||||
; 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
|
||||
neg ax ; y impair: -0x2000
|
||||
|
||||
.addr_even:
|
||||
; conservation du pas entre les 2 banques de VRAM
|
||||
mov [BDA_MOUSE + mouse.cur_bank_add], ax
|
||||
|
||||
; row index dans AL
|
||||
xor ax, ax ; AL = 0 (row)
|
||||
; calcul du bit rotation du curseur
|
||||
mov ax, cx
|
||||
and ax, 0x07
|
||||
mov [BDA_MOUSE + mouse.cur_bit_ofs], al
|
||||
|
||||
; curseur = 16 lignes
|
||||
mov cx, 16
|
||||
.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
|
||||
xor eax,eax
|
||||
xor ebx,ebx
|
||||
|
||||
; -----------------------------------------
|
||||
; 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:
|
||||
popa
|
||||
popad
|
||||
pop gs
|
||||
pop fs
|
||||
pop es
|
||||
pop ds
|
||||
ret
|
||||
|
||||
; -----------------------------------------------
|
||||
|
|
|
|||
Loading…
Reference in a new issue