assembly 用x86汇编语言制作鼠标处理程序

dfty9e19  于 2022-12-19  发布在  其他
关注(0)|答案(1)|浏览(352)

我正在写一个操作系统在NASM汇编和我有一个问题,使鼠标处理程序(指向设备BIOS接口处理程序)。我曾试图搜索互联网上如何做到这一点,但我没有成功。
下面是设置这些内容的代码:

call checkPS2 ;PS2 routines
jc NOMOUSE
call enablePS2
jc NOMOUSE

以下是PS2的功能:

;PS2 mouse routines
NOMOUSE:
    ;Prompt error
ret

checkPS2:
    int 11h         ; get equipment list
    test al, 3
    jz  noPS2       ; jump if PS/2-Mouse not indicated
    mov  bh,3
    mov  ax, 0C205h
    int 15h             ; initialize mouse, bh=datasize
    jc noPS2
    mov bh,3
    mov ax, 0C203h
    int 15h             ; set mouse resolution bh
    jc noPS2
    mov ax, cs
    mov es, ax
    mov bx, PS2dummy
    mov ax, 0C207h
    int 15h             ; mouse, es:bx=ptr to handler
    jc noPS2
    xor bx, bx
    mov es, bx      ; mouse, es:bx=ptr to handler
    mov ax, 0C207h
    int 15h
ret

noPS2:
    stc
ret

PS2dummy:
retf

enablePS2:
    call disablePS2
    mov ax, cs
    mov es, ax
    mov bx, IRQhandler
    mov ax, 0C207h  ; es:bx=ptr to handler
    int 15h
    mov bh,1        ; set mouse on
    mov ax, 0C200h
    int 15h
ret

disablePS2:
    xor bx, bx      ; set mouse off
    mov ax, 0C200h
    int 15h
    xor bx, bx
    mov es, bx
    mov ax, 0C207h  ; es:bx=ptr to handler
    int 15h
ret

IRQhandler:
    ;assume  ds:nothing,es:nothing
    cld
    push ds
    push es
    pusha
    mov ax, cs
    mov ds, ax
    mov bp,sp
    mov al,[bp+24+6]    ; buttons
    mov bl,al
    shl al,3        ; CF=Y sign bit
    sbb ch,ch       ; signed extension 9->16 bit
    cbw         ; extend X sign bit
    mov al,[bp+24+4]    ; AX=X movement
    mov cl,[bp+24+2]    ; CX=Y movement
    xchg bx,ax
    neg cx              ; reverse Y movement
    popa
    pop es
    pop ds
retf

调用这些函数的循环:

mov ax, 0xc209 ;Reads from the mouse
int 15h        ;-||- 
mov dl, bl ;first byte(bl)
mov bl, 02h ;Color Green
call printhex ;prints dl in hex

mov ax, 0xc209 ;Reads from the mouse
int 15h        ;-||- 
mov dl, cl ;second byte(bl)
mov bl, 02h ;Color Green
call printhex ;prints dl in hex

mov ax, 0xc209 ;Reads from the mouse
int 15h        ;-||-
mov bl, 02h ;Color Green
call printhex ;prints dl(3rd byte read)

我注意到的第一件事是屏幕上有无数的白色像素只是随机出现的。
代码应该只给予鼠标的位置,而鼠标光标应该保持隐藏。我已经测试了我的printhex函数,我知道它工作,我看到的数字是:

0x02
0x00
0x00

当我移动鼠标时,所有的值都没有改变。我的配置是带有PS/2鼠标的VirtualBox。

kognpnkq

kognpnkq1#

您没有提供一个完整的示例,但是我终于有时间来研究这个问题。主要问题之一是Int 15h/AX=0C209h是一个可选特性。
注意:IBM将此功能归类为可选功能
我发现在很多模拟器上(QEMU,BOCHs,VirtualBox)这个BIOS函数似乎没有实现。调用它不会产生你要找的数据。你可以使用鼠标处理程序读取X和Y移动和状态字节,并更新你的主例程可以轮询的全局变量。你的鼠标处理程序IRQhandler实际上不是IRQ处理程序,而是BIOS鼠标中断处理程序将调用的FAR函数。在该处理程序中有一些现有代码,用于检索X和Y移动,但不对其做任何操作。如果您维护X和Y的两个全局变量,并将移动值添加到它们中,则可以维护主循环可以查询的绝对坐标。也可以创建一个全局变量来存储读取的状态字节。
使用您的代码作为模板,我生成了这个简单的引导装载程序来测试这个代码。引导装载程序包含一个BIOS Parameter Block,以防您打算在真实的的硬件上从USB using Floppy Disk Emulation引导。如果不需要它,它可以被删除。我还提供了一些例程来显示十六进制的无符号字节和字。视频模式可以调整,但我使用模式13h(320x200x256)作为默认值:

英国石油公司

global bpb_disk_info

    jmp boot_start
    TIMES 3-($-$$) DB 0x90   ; Support 2 or 3 byte encoded JMPs before BPB.

bpb_disk_info:
    ; Dos 4.0 EBPB 1.44MB floppy
    OEMname:           db    "mkfs.fat"  ; mkfs.fat is what OEMname mkdosfs uses
    bytesPerSector:    dw    512
    sectPerCluster:    db    1
    reservedSectors:   dw    1
    numFAT:            db    2
    numRootDirEntries: dw    224
    numSectors:        dw    2880
    mediaType:         db    0xf0
    numFATsectors:     dw    9
    sectorsPerTrack:   dw    18
    numHeads:          dw    2
    numHiddenSectors:  dd    0
    numSectorsHuge:    dd    0
    driveNum:          db    0
    reserved:          db    0
    signature:         db    0x29
    volumeID:          dd    0x2d7e5a1a
    volumeLabel:       db    "NO NAME    "
    fileSysType:       db    "FAT12   "

** Boot .asm**:

HW_EQUIP_PS2     equ 4          ; PS2 mouse installed?
MOUSE_PKT_BYTES  equ 3          ; Number of bytes in mouse packet
MOUSE_RESOLUTION equ 3          ; Mouse resolution 8 counts/mm

VIDEO_MODE       equ 0x13

bits 16
cpu 8086
ORG 0x7c00

; Include a BPB (1.44MB floppy with FAT12) to be more compatible with USB floppy media
%include "bpb.inc"

boot_start:
    xor ax, ax                  ; DS=SS=ES=0
    mov ds, ax
    mov ss, ax                  ; Stack at 0x0000:0x7c00
    mov sp, 0x7c00
    cld                         ; Set string instructions to use forward movement

    ; FAR JMP to ensure set CS to 0
    jmp 0x0000:.setcs
.setcs:

    mov ax, VIDEO_MODE
    int 0x10                    ; Set video mode

    call mouse_initialize
    jc .no_mouse                ; If CF set then error, inform user and end
    call mouse_enable           ; Enable the mouse

    sti
.main_loop:
    hlt                         ; Halt processor until next interrupt
    call poll_mouse             ; Poll mouse and update display with coordintes & status
    jmp .main_loop              ; Endless main loop

.no_mouse:
    mov si, noMouseMsg          ; Error enabling mouse
    call print_string           ; Display message and enter infinite loop

.err_loop:
    hlt
    jmp .err_loop

; Function: mouse_initialize
;           Initialize the mouse if present
;
; Inputs:   None
; Returns:  CF = 1 if error, CF=0 success
; Clobbers: AX

mouse_initialize:
    push es
    push bx

    int 0x11                    ; Get equipment list
    test ax, HW_EQUIP_PS2       ; Is a PS2 mouse installed?
    jz .no_mouse                ;     if not print error and end

    mov ax, 0xC205              ; Initialize mouse
    mov bh, MOUSE_PKT_BYTES     ; 3 byte packets
    int 0x15                    ; Call BIOS to initialize
    jc .no_mouse                ;    If not successful assume no mouse

    mov ax, 0xC203              ; Set resolution
    mov bh, MOUSE_RESOLUTION    ; 8 counts / mm
    int 0x15                    ; Call BIOS to set resolution
    jc .no_mouse                ;    If not successful assume no mouse

    push cs
    pop es                      ; ES = segment where code and mouse handler reside

    mov bx, mouse_callback_dummy
    mov ax, 0xC207              ; Install a default null handler (ES:BX)
    int 0x15                    ; Call BIOS to set callback
    jc .no_mouse                ;    If not successful assume no mouse

    clc                         ; CF=0 is success
    jmp .finished
.no_mouse:
    stc                         ; CF=1 is error
.finished:
    pop bx
    pop es
    ret

; Function: mouse_enable
;           Enable the mouse
;
; Inputs:   None
; Returns:  None
; Clobbers: AX

mouse_enable:
    push es
    push bx

    call mouse_disable          ; Disable mouse before enabling

    push cs
    pop es
    mov bx, mouse_callback
    mov ax, 0xC207              ; Set mouse callback function (ES:BX)
    int 0x15                    ; Call BIOS to set callback

    mov ax, 0xC200              ; Enable/Disable mouse
    mov bh, 1                   ; BH = Enable = 1
    int 0x15                    ; Call BIOS to disable mouse

    pop bx
    pop es
    ret

; Function: mouse_disable
;           Disable the mouse
;
; Inputs:   None
; Returns:  None
; Clobbers: AX

mouse_disable:
    push es
    push bx

    mov ax, 0xC200              ; Enable/Disable mouse
    xor bx, bx                  ; BH = Disable = 0
    int 0x15                    ; Call BIOS to disable mouse

    mov es, bx
    mov ax, 0xC207              ; Clear callback function (ES:BX=0:0)
    int 0x15                    ; Call BIOS to set callback

    pop bx
    pop es
    ret

; Function: mouse_callback (FAR)
;           called by the interrupt handler to process a mouse data packet
;           All registers that are modified must be saved and restored
;           Since we are polling manually this handler does nothing
;
; Inputs:   SP+4  = Unused (0)
;           SP+6  = MovementY
;           SP+8  = MovementX
;           SP+10 = Mouse Status
;
; Returns:  None
; Clobbers: None

ARG_OFFSETS      equ 6          ; Offset of args from BP

mouse_callback:
    push bp                     ; Function prologue
    mov bp, sp
    push ds                     ; Save registers we modify
    push ax
    push bx
    push cx
    push dx

    push cs
    pop ds                      ; DS = CS, CS = where our variables are stored

    mov al,[bp+ARG_OFFSETS+6]
    mov bl, al                  ; BX = copy of status byte
    mov cl, 3                   ; Shift signY (bit 5) left 3 bits
    shl al, cl                  ; CF = signY
                                ; Sign bit of AL = SignX
    sbb dh, dh                  ; CH = SignY value set in all bits
    cbw                         ; AH = SignX value set in all bits
    mov dl, [bp+ARG_OFFSETS+2]  ; CX = movementY
    mov al, [bp+ARG_OFFSETS+4]  ; AX = movementX

    ; new mouse X_coord = X_Coord + movementX
    ; new mouse Y_coord = Y_Coord + (-movementY)
    neg dx
    mov cx, [mouseY]
    add dx, cx                  ; DX = new mouse Y_coord
    mov cx, [mouseX]
    add ax, cx                  ; AX = new mouse X_coord

    ; Status
    mov [curStatus], bl         ; Update the current status with the new bits
    mov [mouseX], ax            ; Update current virtual mouseX coord
    mov [mouseY], dx            ; Update current virtual mouseY coord

    pop dx                      ; Restore all modified registers
    pop cx
    pop bx
    pop ax
    pop ds
    pop bp                      ; Function epilogue

mouse_callback_dummy:
    retf                        ; This routine was reached via FAR CALL. Need a FAR RET

; Function: poll_mouse
;           Poll the mouse state and display the X and Y coordinates and the status byte
;
; Inputs:   None
; Returns:  None
; Clobbers: None

poll_mouse:
    push ax
    push bx
    push dx

    mov bx, 0x0002              ; Set display page to 0 (BH) and color green (BL)

    cli
    mov ax, [mouseX]            ; Retrieve current mouse coordinates. Disable interrupts
    mov dx, [mouseY]            ; So that these two variables are read atomically
    sti

    call print_word_hex         ; Print the mouseX coordinate
    mov si, delimCommaSpc
    call print_string

    mov ax, dx
    call print_word_hex         ; Print the mouseY coordinate
    mov si, delimCommaSpc
    call print_string

    mov al, [curStatus]
    call print_byte_hex         ; Print the last read mouse state byte

    mov al, 0x0d
    call print_char             ; Print carriage return to return to beginning of line

    pop dx
    pop bx
    pop ax
    ret

; Function: print_string
;           Display a string to the console on the specified page and in a
;           specified color if running in a graphics mode
;
; Inputs:   SI = Offset of address to print
;           BH = Page number
;           BL = foreground color (graphics modes only)
; Clobbers: SI

print_string:
    push ax
    mov ah, 0x0e                ; BIOS TTY Print
    jmp .getch
.repeat:
    int 0x10                    ; print character
.getch:
    lodsb                       ; Get character from string
    test al,al                  ; Have we reached end of string?
    jnz .repeat                 ;     if not process next character
.end:
    pop ax
    ret

; Function: print_char
;           Print character on specified page and in a specified color
;           if running in a graphics mode
;
; Inputs:   AL = Character to print
;           BH = Page number
;           BL = foreground color (graphics modes only)
; Returns:  None
; Clobbers: AX

print_char:
    mov ah, 0x0e                ; TTY function to display character in AL
    int 0x10                    ; Make BIOS call
    ret

; Function: print_word_hex
;           Print a 16-bit unsigned integer in hexadecimal on specified
;           page and in a specified color if running in a graphics mode
;
; Inputs:   AX = Unsigned 16-bit integer to print
;           BH = Page number
;           BL = foreground color (graphics modes only)
; Returns:  None
; Clobbers: Mone

print_word_hex:
    xchg al, ah                 ; Print the high byte first
    call print_byte_hex
    xchg al, ah                 ; Print the low byte second
    call print_byte_hex
    ret

; Function: print_byte_hex
;           Print a 8-bit unsigned integer in hexadecimal on specified
;           page and in a specified color if running in a graphics mode
;
; Inputs:   AL = Unsigned 8-bit integer to print
;           BH = Page number
;           BL = foreground color (graphics modes only)
; Returns:  None
; Clobbers: Mone

print_byte_hex:
    push ax
    push cx
    push bx

    lea bx, [.table]            ; Get translation table address

    ; Translate each nibble to its ASCII equivalent
    mov ah, al                  ; Make copy of byte to print
    and al, 0x0f                ;     Isolate lower nibble in AL
    mov cl, 4
    shr ah, cl                  ; Isolate the upper nibble in AH
    xlat                        ; Translate lower nibble to ASCII
    xchg ah, al
    xlat                        ; Translate upper nibble to ASCII

    pop bx                      ; Restore attribute and page
    mov ch, ah                  ; Make copy of lower nibble
    mov ah, 0x0e
    int 0x10                    ; Print the high nibble
    mov al, ch
    int 0x10                    ; Print the low nibble

    pop cx
    pop ax
    ret
.table: db "0123456789ABCDEF", 0

; Uncomment these lines if not using a BPB (via bpb.inc)
; numHeads:        dw 2         ; 1.44MB Floppy has 2 heads & 18 sector per track
; sectorsPerTrack: dw 18

align 2
mouseX:       dw 0              ; Current mouse X coordinate
mouseY:       dw 0              ; Current mouse Y coordinate
curStatus:    db 0              ; Current mouse status
noMouseMsg:   db "Error setting up & initializing mouse", 0x0d, 0x0a, 0
delimCommaSpc:db ", ", 0

bootDevice:   db 0x00

; Pad boot sector to 510 bytes and add 2 byte boot signature for 512 total bytes
TIMES 510-($-$$) db  0
dw 0xaa55

代码可以通过以下方式构建到磁盘映像中:

nasm -f bin boot.asm -o boot.bin

# Build 1.44MB disk image
dd if=/dev/zero of=disk.img bs=1024 count=1440
dd if=boot.bin of=disk.img conv=notrunc

我提供这段代码是因为我不知道为什么你的代码偶尔会显示不需要的像素。这类问题可能与你没有提供的代码有关。当在VirtualBox中运行时,它应该看起来像这样:

相关问题