home *** CD-ROM | disk | FTP | other *** search
/ Liren Large Software Subsidy 7 / 07.iso / c / c220 / 7.ddi / EXAMPLES / DOSEXT / TAIL.ASM < prev    next >
Encoding:
Assembly Source File  |  1990-10-18  |  15.3 KB  |  607 lines

  1. ;************************************************************************/
  2. ;*    Copyright (C) 1986-1988 Phar Lap Software, Inc.            */
  3. ;*    Unpublished - rights reserved under the Copyright Laws of the    */
  4. ;*    United States.  Use, duplication, or disclosure by the         */
  5. ;*    Government is subject to restrictions as set forth in         */
  6. ;*    subparagraph (c)(1)(ii) of the Rights in Technical Data and     */
  7. ;*    Computer Software clause at 252.227-7013.            */
  8. ;*    Phar Lap Software, Inc., 60 Aberdeen Ave., Cambridge, MA 02138    */
  9. ;************************************************************************/
  10. ;
  11. ; TAIL.ASM - This is an example program that uses
  12. ; the Microsoft mouse driver, and also demonstrates
  13. ; several techniques for mixing real and protected
  14. ; mode code in the same program.
  15. ;
  16. ; FUNCTIONALITY - The program is used to draw rough
  17. ; pictures on the screen using the mouse.  The 
  18. ; program is always in one of two modes - character
  19. ; output mode, or toggle mode.  When in character
  20. ; output mode pressing the right mouse button will
  21. ; output a character at the current cursor position.
  22. ; Pressing the left mouse button causes the program
  23. ; to enter toggle mode.  When in toggle mode, 
  24. ; pressing the right mouse button will cause the
  25. ; character that gets output to be toggled between 
  26. ; a '*' and a ' ' (space).  Pressing the left mouse 
  27. ; button in toggle mode causes the program to exit. 
  28. ; The program starts up in character output mode, 
  29. ; with the output character set to '*'.  The program 
  30. ; is used to draw rudimentary pictures with '*'s,
  31. ; toggling the output character to a space to 
  32. ; erase mistakes.
  33. ;
  34. ; IMPLEMENTATION - The program demonstrates mixing
  35. ; real and protected mode code in a single EXP
  36. ; file (in this instance, in a single source code
  37. ; file).  The real mode code and data is linked at
  38. ; the beginning of the program, and the -REALBREAK
  39. ; switch is used at link time to specify how much
  40. ; of the program must be loaded in conventional
  41. ; MS-DOS memory.  The program has three routines
  42. ; that run in real mode - a setup routine that calls
  43. ; the mouse driver to specify the initial mouse
  44. ; interrupt handler, and two mouse interrupt
  45. ; which correspond to the two program states,
  46. ; character input mode and toggle mode.  The
  47. ; program demonstrates how to make intermode
  48. ; procedure calls passing data both on the stack
  49. ; and in registers, and how to issue real mode
  50. ; interrupts from protected mode with arbitrary
  51. ; real mode segment register values.
  52.  
  53. ;
  54. ; Segment ordering and attributes.  We make sure the
  55. ; real mode code and data comes first.  The real and
  56. ; prot mode data are together so they can be grouped.
  57. ;
  58. rmcode    segment byte public use16
  59. rmcode    ends
  60. rmdata    segment dword public use16
  61. rmdata    ends
  62. pmdata    segment dword public use32
  63. pmdata    ends
  64. pmcode    segment byte public use32
  65. pmcode    ends
  66. stack    segment dword stack use32
  67. stack    ends
  68. dgroup    group    rmdata,pmdata
  69.  
  70. ;
  71. ; Constants
  72. ;
  73. TRUE    equ    1
  74. FALSE    equ    0
  75.  
  76. ;
  77. ; Make entry points and data global so they
  78. ; can be accessed by the debugger
  79. ;
  80. public    main,init,cleanup,rm_setup,ch_hndlr
  81. public    tog_hndlr,print_ch
  82. public    donef,call_prot,vid_mode
  83.  
  84. ;
  85. ; Give program a 4K stack
  86. ;
  87. stack    segment
  88.     db    4096 dup(?)
  89. stack    ends
  90.  
  91. ;
  92. ; Data that needs to be accessed in both real
  93. ; mode and protected mode
  94. ;
  95. rmdata    segment
  96.  
  97. donef    dd    ?    ; flags when done
  98. outp_ch    db    ?    ; current output char
  99.             ; ('*' or ' ')
  100. call_prot dd    ?    ; addr of routine to
  101.             ; call thru to prot mode
  102. code_sel dw    ?    ; prot mode code selector for this pgm
  103.  
  104. chndlrmsg db    'Output char at cursor error'
  105.     db    0Dh,0Ah,'$'
  106.  
  107. ;
  108. ; Symbol marking end of real mode code & data,
  109. ; used at link time to specify the real mode
  110. ; code & data size
  111. ;
  112.     public    end_real
  113. end_real label    byte
  114.  
  115. rmdata    ends
  116.  
  117. ;
  118. ; Data that is only accessed in prot mode
  119. ;
  120. pmdata    segment
  121.  
  122. rm_seg    dw    ?    ; real mode segment addr
  123.                 ; of start of
  124.                 ; pgm segment
  125. vid_mode db    ?    ; saved video mode
  126.  
  127. drivmsg    db    'Mouse driver not present'
  128.     db    0Dh,0Ah,'$'
  129. b2msg    db    'Mouse must have 2 buttons'
  130.     db    0Dh,0Ah,'$'
  131. realmsg    db    'Real mode code not addressable'
  132.     db    0Dh,0Ah,'$'
  133. callmsg    db    'Call to real mode failed'
  134.     db    0Dh,0Ah,'$'
  135. setupmsg db    'Real mode setup routine error'
  136.     db    0Dh,0Ah,'$'
  137.  
  138. pmdata    ends
  139.  
  140. ;
  141. ; Because of data grouping, this ASSUME will 
  142. ; allow the assembler to correctly reference
  143. ; data in both real mode and prot mode code
  144. ;
  145.     assume    ds:dgroup
  146. page
  147. ;
  148. ; Protected mode code
  149. ;
  150.     assume    cs:pmcode
  151. pmcode    segment    
  152.  
  153. ;***************************************************
  154. ; main - sets up the mouse handler, then just loops,
  155. ;    processing mouse button hits until the left
  156. ;    one is pressed twice.
  157. ;***************************************************
  158. main    proc    near        ; program entry point
  159.  
  160.     call    init        ; init mouse
  161.     cmp    eax,TRUE    ; branch if error
  162.     je    short #err        ;
  163.  
  164.     mov    donef,FALSE    ; init done flag
  165.     mov    outp_ch,'*'    ; init output char
  166. #wait:
  167.     cmp    donef,FALSE    ; loop until handler
  168.     je    #wait            ; sets flag
  169.  
  170.     call    cleanup        ; clean up mouse
  171.     mov    al,0        ; return success
  172.  
  173. #exit:
  174.     mov    ah,4Ch        ; exit to DOS
  175.     int    21h            ;
  176.  
  177. #err:
  178.     mov    al,1        ; return error
  179.     jmp    #exit            ;
  180.  
  181. main    endp
  182.  
  183. ;***************************************************
  184. ; init - This routine checks for the presence
  185. ;    of the mouse driver, and if it is present,
  186. ;    initializes it and sets up the real mode
  187. ;    handler to get control when a mouse button
  188. ;    is pressed.  It also sets up an appropriate
  189. ;    video mode, and gets the address of the
  190. ;    real mode DOS-Extender routine which is
  191. ;    used to call through to protected mode.
  192. ;
  193. ; Returns:    TRUE if error
  194. ;        FALSE if success
  195. ;***************************************************
  196. init proc near
  197.  
  198.     push    es        ; save regs
  199.  
  200. ;
  201. ; Get code segment selector for this program
  202. ;
  203.     mov    code_sel,cs
  204.  
  205. ;
  206. ; Save the current video mode, and set the video mode 
  207. ; to 80x25 B&W (8x8 cell size).
  208. ;
  209.     mov    ah,0Fh        ; get video state
  210.     int    10h            ;
  211.     mov    vid_mode,al        ;
  212.     mov    ax,0002h    ; set video state
  213.     int    10h            ;
  214.  
  215. ;
  216. ; Get address of DOS-Extender routine to use to
  217. ; call through from real mode to protected mode
  218. ;
  219.     mov    ax,250Dh    ; get real mode link
  220.     int    21h            ; info
  221.     mov    call_prot,eax    ; save proc address
  222.  
  223. ;
  224. ; Check for presence of mouse driver, take error
  225. ; exit if not present, initialize it if present
  226. ;
  227.     mov    cl,33h        ; get mouse real mode
  228.     mov    ax,2503h        ; int vector
  229.     int    21h            ;
  230.     cmp    ebx,0        ; branch if null
  231.     je    #no_driver        ;
  232.     xor    eax,eax        ; branch if vector
  233.     mov    ax,bx            ; just points
  234.     and    ebx,0FFFF0000h        ; to an IRET
  235.     shr    ebx,12            ;
  236.     add    ebx,eax            ;
  237.     mov    ax,0034h        ;
  238.     mov    es,ax            ;
  239.     cmp    byte ptr es:[ebx],0CFh    ;
  240.     je    short #no_driver    ;
  241.     mov    ax,0        ; Initialize mouse
  242.     int    33h            ; driver
  243.     cmp    ax,0        ; branch if not
  244.     je    short #no_driver    ; installed
  245.     cmp    bx,2        ; pgm requires 2 
  246.     jne    short #buttons        ; buttons
  247.  
  248. ;
  249. ; Call through to real mode to set up interrupt
  250. ; handler for mouse driver.  This call demonstrates
  251. ; passing data both on the stack and in registers,
  252. ; and getting back a value in a register.
  253. ;
  254.     mov    ax,ds        ; get real mode para
  255.     mov    es,ax            ; address of
  256.     xor    ebx,ebx            ; program
  257.     lea    ecx,end_real        ; segment
  258.     mov    ax,250Fh        ;
  259.     int    21h            ;
  260.     jc    short #not_real    ; branch if error
  261.     test    ecx,0FFFFh    ; branch if not on
  262.     jnz    short #not_real        ; para boundary
  263.     mov    ebx,ecx        ; EBX = real mode addr
  264.     lea    bx,rm_setup        ; of rm_setup
  265.     shr    ecx,16        ; pass hndlr seg addr
  266.     push    cx            ; on stack
  267.     mov    rm_seg,cx    ; save seg addr
  268.     lea    dx,ch_hndlr    ; pass offset in DX
  269.     mov    ecx,1        ; 1 WORD on stack
  270.     mov    ax,250Eh    ; call rm_setup
  271.     int    21h            ;
  272.     jnc    short #ok    ; branch if success
  273.     add    esp,2        ; pop args and take
  274.     jmp    short #bad_call        ; error exit
  275. #ok:
  276.     add    esp,2        ; pop args off stack
  277.     cmp    ax,FALSE    ; branch if error
  278.     jne    short #setup_err    ;
  279.  
  280. ;
  281. ; OK, all initialized - display mouse cursor and exit
  282. ;
  283.     mov    ax,1        ; display mouse cursor
  284.     int    33h            ;
  285.     mov    eax,FALSE    ; return success
  286.  
  287. #exit:
  288.     pop    es        ; restore regs 
  289.     ret                ; & exit
  290.  
  291. #buttons:
  292.     lea    edx,b2msg
  293.     jmp    short #err
  294. #no_driver:
  295.     lea    edx,drivmsg
  296.     jmp    short #err
  297. #not_real:
  298.     lea    edx,realmsg
  299.     jmp    short #err
  300. #setup_err:
  301.     lea    edx,setupmsg
  302.     jmp    short #err
  303. #bad_call:
  304.     lea    edx,callmsg
  305. #err:
  306.     mov    ah,0        ; restore video mode
  307.     mov    al,vid_mode        ;
  308.     int    10h            ;
  309.     mov    ah,9        ; output error msg
  310.     int    21h            ;
  311.     mov    eax,TRUE    ; return error
  312.     jmp    #exit            ;
  313.  
  314. init endp
  315.  
  316. ;***************************************************
  317. ; cleanup - This routine resets the mouse driver to 
  318. ;    set the interrupt call mask to 0 and hide 
  319. ;    the cursor, and restores the original video
  320. ;    mode.
  321. ;***************************************************
  322. cleanup proc near
  323.     mov    ax,0        ; reset mouse 
  324.     int    33h            ;
  325.     mov    ah,0        ; restore video mode
  326.     mov    al,vid_mode        ;
  327.     int    10h            ;
  328. #exit:
  329.     ret
  330. cleanup endp
  331.  
  332. ;***************************************************
  333. ; print_ch(cond_msk)
  334. ; WORD cond_msk;
  335. ;
  336. ;    This routine is called from real mode
  337. ;    when either mouse button is pressed and we
  338. ;    are in character input mode.
  339. ;
  340. ;    If the left button was pressed, this proc
  341. ;    puts us in toggle mode by setting the 
  342. ;    mouse handler routine to be tog_hndlr.
  343. ;
  344. ;    If the right button was pressed, this proc
  345. ;    outputs the current output character at 
  346. ;    the specified cursor position.
  347. ;
  348. ;    This routine illustrates how to issue a
  349. ;    real mode interrupt with arbitrary segment
  350. ;    register values.
  351. ;
  352. ; Inputs:
  353. ;    1st stack param = mouse condition mask
  354. ;    CX = horizontal cursor coord
  355. ;    DX = vertical cursor coord
  356. ;
  357. ; Outputs:
  358. ;    AX = TRUE if error, FALSE if success
  359. ;    BX-DX = destroyed
  360. ;    High word of all 32-bit registers preserved
  361. ;***************************************************
  362. ;
  363. ; Data structure passed to system call 2511h, issue
  364. ; real mode interrupt with arbitrary seg reg values
  365. ;
  366. RMINT    struc
  367.     RMI_INUM dw    ?    ; interrupt number
  368.     RMI_DS    dw    ?    ; real mode DS
  369.     RMI_ES    dw    ?    ; real mode ES
  370.     RMI_FS    dw    ?    ; real mode FS
  371.     RMI_GS    dw    ?    ; real mode GS
  372.     RMI_EAX    dd    ?    ; EAX value
  373.     RMI_EDX    dd    ?    ; EDX value
  374. RMINT    ends
  375.  
  376. print_ch proc    far
  377. ;
  378. ; Stack frame
  379. ;
  380. #COND_MSK equ    (word ptr 12[ebp])
  381. #RMI    equ    (dword ptr [ebp - (size RMINT)])
  382.  
  383.     push    ebp        ; Set up stack frame
  384.     mov    ebp,esp            ;
  385.     sub    esp,size RMINT    ; allocate local vars
  386.  
  387.     test    #COND_MSK,2    ; branch if left button
  388.     jz    short #right        ; not pressed
  389.  
  390. ;
  391. ; Left mouse button was pressed.  Issue a real mode
  392. ; interrupt to set up the mouse handler routine to
  393. ; be tog_hndlr.  The interrupt takes a function number
  394. ; in AX, an interrupt mask in CX, and the real mode 
  395. ; addr of the handler in ES:DX.  We don't bother to
  396. ; initialize the values in the struct for DS,FS, or
  397. ; GS, and just let them get loaded with garbage.
  398. ;
  399.     mov    ax,rm_seg    ; ES:DX = addr of
  400.     mov    #RMI.RMI_ES,ax        ; handler
  401.     lea    eax,tog_hndlr        ;
  402.     mov    #RMI.RMI_EDX,eax    ;
  403.     mov    cx,0Ah        ; interrupt mask
  404.     mov    #RMI.RMI_EAX,12    ; EAX = function #
  405.     mov    #RMI.RMI_INUM,33h ; interrupt number
  406.     push    ds        ; issue real mode
  407.     mov    ax,ss            ; interrupt
  408.     mov    ds,ax            ;
  409.     lea    edx,#RMI        ;
  410.     mov    ax,2511h        ;
  411.     int    21h            ;
  412.     pop    ds            ;
  413.     mov    ax,FALSE    ; return success
  414.     jmp    short #exit        ;
  415.  
  416. #right:
  417. ;
  418. ; Right mouse button was pressed.  Set up ES to point 
  419. ; to screen segment.
  420. ;
  421.     mov    ax,001Ch    
  422.     mov    es,ax    
  423.  
  424. ;
  425. ; Get offset in screen segment of 1st character on
  426. ; the line the cursor is on
  427. ;
  428.     shr    dx,3        ; convert pixel to line
  429.     imul    dx,160        ; 160 bytes/line
  430.  
  431. ;
  432. ; Add in the column number * 2 (2 bytes/char)
  433. ;
  434.     shr    cx,2
  435.     add    cx,dx
  436.     mov    bx,cx
  437.  
  438. ;
  439. ; Output the character at the cursor.
  440. ;
  441.     mov    ah,7        ; normal attribute
  442.     mov    al,outp_ch    ; character
  443.     mov    word ptr es:[bx],ax ; output it
  444.  
  445.     mov    ax,FALSE    ; return success
  446.  
  447. #exit:
  448.     add    esp,size RMINT    ; pop local vars
  449.     pop    ebp        ; restore regs &
  450.     ret                ; exit
  451. print_ch endp
  452.  
  453. pmcode    ends
  454.  
  455. page
  456. ;
  457. ; Real mode code
  458. ;
  459. rmcode    segment
  460.  
  461. ;***************************************************
  462. ; rm_setup(hndlr_seg)
  463. ; WORD hndlr_seg;
  464. ;
  465. ;    This routine is called from protected
  466. ;    mode.  It calls the mouse driver to set up
  467. ;    the specified address as the mouse interrupt 
  468. ;     handler when either mouse button is pressed.
  469. ;    This call is made in real mode because
  470. ;    it passes a value in ES.
  471. ;
  472. ; Inputs:
  473. ;    1st stack param = segment addr of handler
  474. ;    DX = offset of handler
  475. ;
  476. ; Outputs:
  477. ;    AX = TRUE if error, FALSE if success
  478. ;    ES,BX-DX = destroyed
  479. ;    all other registers unchanged
  480. ;***************************************************
  481.     assume    cs:rmcode,ds:dgroup
  482. rm_setup proc    far
  483. ;
  484. ; Stack frame
  485. ;
  486. #HNDLR_SEG equ    (word ptr 6[bp])
  487.  
  488.     push    bp        ; set up stack frame
  489.     mov    bp,sp            ;
  490.  
  491.     mov    ax,#HNDLR_SEG    ; ES:DX = addr of
  492.     mov    es,ax            ; handler
  493.     mov    cx,0Ah        ; interrupt mask
  494.     mov    ax,12        ; set up handler
  495.     int    33h            ;
  496.  
  497.     mov    ax,FALSE    ; return success
  498.  
  499.     pop    bp        ; restore regs &
  500.     ret                ; exit
  501. rm_setup endp
  502.  
  503. ;***************************************************
  504. ; ch_hndlr - This routine is invoked by the mouse
  505. ;    driver when either mouse button is pressed,
  506. ;    and when we are in character output mode.
  507. ;    This handler just calls a protected mode
  508. ;    routine to process the interrupt.  Since
  509. ;    this is a hardware interrupt handler, it is 
  510. ;     obligated to preserve all 32-bit registers.
  511. ;
  512. ;    This routine demonstrates passing values
  513. ;    both on the stack and in registers to a
  514. ;    protected mode subroutine.
  515. ;***************************************************
  516.     assume    nothing,cs:rmcode
  517. ch_hndlr proc    far
  518.     push    ds        ; save regs
  519.     push    eax            ;
  520.  
  521. ;
  522. ; To call a prot mode routine, all we do is push
  523. ; any params to the routine onto the stack, then
  524. ; push the FAR addr of the desired prot mode 
  525. ; routine, then call the 386|DOS-Extender routine
  526. ; to switch modes and transfer control to the prot
  527. ; mode routine.
  528. ;
  529.     push    cs        ; set up data segment
  530.     pop    ds            ;
  531.     assume    ds:dgroup        ;
  532.  
  533.     push    ax        ; param = cond. mask
  534.     push    dword ptr 0    ; no seg reg param blk
  535.     push    code_sel    ; prot mode addr of 
  536.     lea    eax,print_ch        ; display
  537.     push    eax            ; routine
  538.     call    call_prot    ; call it
  539.     add    sp,12        ; pop arguments
  540.     cmp    ax,TRUE        ; branch if error
  541.     je    short #err        ;
  542.  
  543. #exit:
  544.     pop    eax        ; restore regs &
  545.     pop    ds            ; exit
  546.     ret                ; 
  547.  
  548. #err:
  549.     lea    dx,chndlrmsg    ; output error msg
  550.     mov    ah,9            ;
  551.     int    21h            ;
  552.     jmp    #exit
  553. ch_hndlr endp
  554.  
  555. ;***************************************************
  556. ; tog_hndlr - This routine is invoked by the mouse
  557. ;    driver when either mouse button is pressed,
  558. ;    and we are in toggle mode (the left mouse
  559. ;    button was the last one pressed).
  560. ;    If the left button has been pressed, we
  561. ;    set the done flag.  If the right button has
  562. ;    been pressed, we toggle the character that
  563. ;    gets output between '*' and ' ', and then
  564. ;    restore ch_hndlr as the mouse interrupt
  565. ;    handler.  Since this is a hardware 
  566. ;    interrupt handler, it is obligated to 
  567. ;    preserve all 32-bit registers.
  568. ;***************************************************
  569.     assume    nothing,cs:rmcode
  570. tog_hndlr proc    far
  571.     push    ds        ; save regs
  572.     push    es            ;
  573.  
  574.     push    cs        ; set up data segment
  575.     pop    ds            ;
  576.     assume    ds:dgroup        ;
  577.  
  578.     test    ax,2        ; branch if left button
  579.     jz    short #right        ; not pressed
  580.     mov    donef,TRUE    ; set done flag & exit
  581.     jmp    short #exit        ;
  582.  
  583. #right:
  584.     mov    al,' '        ; assume char = ' '
  585.     cmp    outp_ch,'*'    ; toggle output char
  586.     je    short #space        ;
  587.     mov    al,'*'            ;
  588. #space:                    ;
  589.     mov    outp_ch,al        ;
  590.     mov    ax,cs        ; Restore ch_hndlr
  591.     mov    es,ax            ; as mouse
  592.     lea    dx,ch_hndlr        ; handler
  593.     mov    cx,0Ah            ;
  594.     mov    ax,12            ;
  595.     int    33h            ;
  596.  
  597. #exit:
  598.     pop    es        ; restore regs &
  599.     pop    ds            ; exit
  600.     ret                ;
  601. tog_hndlr endp
  602.  
  603. rmcode    ends
  604.  
  605.     end main        ; program entry point
  606.