home *** CD-ROM | disk | FTP | other *** search
/ Phoenix CD 2.0 / Phoenix_CD.cdr / 01e / msjall.zip / MSJV2-1.ZIP / EMS.ALL next >
Text File  |  1987-10-30  |  28KB  |  819 lines

  1. Microsoft Systems Journal
  2. Volume 2; Issue 1; March, 1987
  3.  
  4. Code Listings For:
  5.  
  6.     Expanded Memory
  7.     pp. 21-32
  8.  
  9. Author(s): Marion Hansen, Bill Krueger, Nick Stuecklen
  10. Title:     Expanded Memeory: Writing Programs That Break the 640K Barrier
  11.  
  12.  
  13.  
  14.  
  15. ==============================================================================
  16. ==============================================================================
  17.  
  18.  
  19. Figure 3: Main Program
  20. ==============================================================================
  21.  
  22. #include <dos.h>
  23. #include <stdio.h>
  24.  
  25. #define EMM_INT 0x67                /*  EMM interrupt number  */
  26. #define GET_PAGE_FRAME_BASE 0x41    /*  EMM func = get page frame 
  27.                                         base address  */
  28. #define GET_FREE_COUNT 0x42         /*  EMM Func = get unallocated 
  29.                                         pages count  */
  30. #define ALLOCATE_PAGES 0x43         /*  EMM Func = allocates pages  */
  31. #define MAP_PAGES 0x44              /*  EMM Func = map pages  */
  32. #define DEALLOCATE_PAGES 0x45       /*  EMM Func = deallocate pages  */
  33. #define GET_INT_VECTOR 0x35         /*  DOS func = get interrupt 
  34.                                         vector  */
  35. #define DEVICE_NAME_LEN 8           /*  Number of chars in device 
  36.                                         driver name field  */
  37. #define VIDEO_RAM_SIZE 4000         /*  Total bytes in video RAM 
  38.                                         (char/attr)  */
  39. #define VIDEO_RAM_BASE 0xB0000000   /*  Video RAM start address (MDA) */
  40.  
  41. union REGS input_regs, output_regs; /*  Regs used for calls to EMM 
  42.                                         and DOS  */
  43. struct SREGS segment_regs;
  44. unsigned int emm_status;            /*  Status returned by EMM  */
  45.  
  46. main ()
  47.  
  48. {
  49. unsigned int i;
  50. long target_time, current_time;
  51. char *video_ram_ptr = {VIDEO_RAM_BASE}; /*  Pointer to video RAM  */
  52. unsigned int emm_handle;                /*  EMM handle  */
  53. char *expanded_memory_ptr;              /*  Pointer to expanded 
  54.                                             memory  */
  55.  
  56. /*  Ensure that the Expanded Memory Manager software is installed 
  57.     on the user's system.  */
  58.  
  59.    detect_emm();
  60.  
  61. /*  Get a page of expanded memory.  */
  62.  
  63.    get_expanded_memory_page (&expanded_memory_ptr, &emm_handle);
  64.  
  65. /*  Copy the current video RAM contents to expanded memory.  */
  66.  
  67.    memcpy (expanded_memory_ptr, video_ram_ptr, VIDEO_RAM_SIZE);
  68.  
  69. /*  Clear the screen to nulls.  */
  70.  
  71.    memset (video_ram_ptr, '\0', VIDEO_RAM_SIZE);
  72.  
  73. /*  Delay for 1 second so the user can see the blanked screen.  */
  74.  
  75.    time (¤t_time);
  76.    target_time = current_time + 1;
  77.    while (current_time < target_time)
  78.     {
  79.      time (¤t_time);
  80.     }
  81.  
  82. /*  Restore the video RAM contents from expanded memory.  */
  83.  
  84.    memcpy (video_ram_ptr, expanded_memory_ptr, VIDEO_RAM_SIZE);
  85.  
  86. /*  Deallocate the expanded memory page  */
  87.  
  88.    release_expanded_memory_page (emm_handle);
  89.  
  90.    exit(0);
  91. }
  92. ==============================================================================
  93.  
  94.  
  95.  
  96.  
  97.  
  98.  
  99.  
  100. ==============================================================================
  101. ==============================================================================
  102.  
  103. Figure 4: Detect_EMM Subroutine
  104. ==============================================================================
  105.  
  106. detect_emm ()
  107.  
  108. {
  109. static char EMM_device_name [DEVICE_NAME_LEN] = {"EMMXXXX0"};
  110. char *int_67_device_name_ptr;
  111.  
  112.  
  113. /*  Determine the address of the routine associated with INT 67 hex.  */
  114.  
  115.   input_regs.h.ah = GET_INT_VECTOR;  /*  DOS function  */
  116.   input_regs.h.al = EMM_INT;         /*  EMM interrupt number  */
  117.   intdosx (&input_regs, &output_regs, &segment_regs);
  118.   int_67_device_name_ptr = 
  119.   (segment_regs.es * 65536) + 10;    /*  Create ptr to device name 
  120.                                          field  */
  121.  
  122. /*  Compare the device name with the known EMM device name.  */
  123.  
  124.   if(memcmp(EMM_device_name,int_67_device_name_ptr,DEVICE_NAME_LEN) !=0)
  125.    {
  126.      printf ("\x07Abort: EMM device driver not installed\n");
  127.      exit(0);
  128.    }  
  129. ==============================================================================
  130.  
  131.  
  132.  
  133.  
  134.  
  135.  
  136.  
  137.  
  138.  
  139. ==============================================================================
  140. ==============================================================================
  141.  
  142. Figure 5: Check_Status Subprocedure
  143. ==============================================================================
  144.  
  145. check_status (emm_status)
  146. unsigned int emm_status;
  147. {
  148. static char *emm_error_strings[] = {
  149.   "no error",
  150.   "EMM software malfunction",
  151.   "EMM hardware malfunction",
  152.   "RESERVED",
  153.   "Invalid EMM handle",
  154.   "Invalid EMM function code",
  155.   "All EMM handles being used",
  156.   "Save/restore page mapping context error",
  157.   "Not enough expanded memory pages",
  158.   "Not enough unallocated pages",
  159.   "Can not allocate zero pages",
  160.   "Logical page out of range",
  161.   "Physical page out of range",
  162.   "Page mapping hardware state save area full",
  163.   "Page mapping hardware state save area already has handle",
  164.   "No handle associated with the page mapping hardware state save area",
  165.   "Invalid subfunction"
  166.  };
  167.  
  168. /*  IF EMM error, THEN print error message and EXIT  */
  169.  
  170.    if (emm_status != 0)                    /*  IF EMM error...  */
  171.     {
  172.       emm_status -= 0x7F;                  /*  Make error code 
  173.                                                zero-based  */
  174.       printf ("\x07Abort: EMM error = ");  /*  Issue error prefix  */
  175.       printf ("%s\n", emm_error_strings[emm_status]);
  176.                                            /*  Issue actual error 
  177.                                                message  */
  178.       exit(0);                             /*  And then exit to 
  179.                                                DOS  */
  180.     }
  181. }
  182. ==============================================================================
  183.  
  184.  
  185.  
  186.  
  187.  
  188.  
  189.  
  190.  
  191.  
  192.  
  193. ==============================================================================
  194. ==============================================================================
  195. Figure 6: Get_Expanded_Memory_Page Subprocedure
  196.  
  197. ==============================================================================
  198.  
  199. get_expanded_memory_page (expanded_memory_ptr_ptr, emm_handle_ptr)
  200.  
  201. unsigned int *emm_handle_ptr;     /*  16 bit handle returned by EMM  */
  202. char *(*expanded_memory_ptr_ptr); /*  Pointer to expanded memory 
  203.                                       page  */
  204.  
  205. {
  206. unsigned int page_frame_base;     /*  Expanded memory page frame 
  207.                                       base  */
  208. unsigned int physical_page = {0}; /*  Physical page number  */
  209.  
  210.  
  211. /*  Get unallocated pages count.  */
  212.  
  213. input_regs.h.ah = GET_FREE_COUNT;    /*  EMM function  */
  214. int86x (EMM_INT, &input_regs, &output_regs, &segment_regs);
  215. emm_status = output_regs.h.ah;
  216. check_status(emm_status);            /*  Check for errors  */
  217. if (output_regs.x.bx < 1)            /*  Check unallocated page 
  218.                                          count  */
  219.  {
  220.   printf ("\x07Abort: insufficient unallocated expanded memory pages\n");
  221.   exit(0);
  222.  }
  223.  
  224.  
  225. /*  Allocate the specified number of pages.  */
  226.  
  227. input_regs.h.ah = ALLOCATE_PAGES;     /*  EMM function  */
  228. input_regs.x.bx = 1;                  /*  Number of pages to 
  229.                                           allocate  */
  230. int86x (EMM_INT, &input_regs, &output_regs, &segment_regs);
  231. emm_status = output_regs.h.ah;
  232. check_status(emm_status);             /*  Check for errors  */
  233. *emm_handle_ptr = output_regs.x.dx;   /*  Get EMM handle  */
  234.  
  235.  
  236. /*  Map the logical page into physical page 0.  */
  237.  
  238.    input_regs.h.ah = MAP_PAGES;          /*  EMM function  */
  239.    input_regs.h.al = 0;                  /*  Logical page number  */
  240.    input_regs.x.bx = physical_page;      /*  Physical page number  */
  241.    input_regs.x.dx = *emm_handle_ptr;    /*  EMM handle  */
  242.    int86x (EMM_INT, &input_regs, &output_regs, &segment_regs);
  243.    emm_status = output_regs.h.ah;
  244.    check_status(emm_status);             /*  Check for errors  */
  245.  
  246.  
  247. /*  Determine the page frame address.   */
  248.  
  249.    input_regs.h.ah = GET_PAGE_FRAME_BASE; /*  EMM function  */
  250.    int86x (EMM_INT, &input_regs, &output_regs, &segment_regs);
  251.    emm_status = output_regs.h.ah;
  252.    check_status(emm_status);              /*  Check for errors  */
  253.    *expanded_memory_ptr_ptr = 
  254.      (output_regs.x.bx * 65536)
  255.      + (physical_page * 16 * 1024);       /*  Set the expanded memory 
  256.                                               ptr  */
  257. }
  258. ==============================================================================
  259.  
  260.  
  261.  
  262.  
  263.  
  264.  
  265.  
  266.  
  267.  
  268.  
  269. ==============================================================================
  270. ==============================================================================
  271. Figure 7: Release_Expanded_Memory_Page Subroutine
  272.  
  273. ==============================================================================
  274.  
  275. release_expanded_memory_page (emm_handle)
  276.  
  277. unsigned int emm_handle;      /*  Handle identifying which page 
  278.                                   set to deallocate  */
  279. {
  280.  
  281. /*  Release the expanded memory pages by deallocating the handle 
  282.     associated with those pages.  */
  283.   
  284.    input_regs.h.ah = DEALLOCATE_PAGES;  /*  EMM function  */
  285.    input_regs.x.dx = emm_handle;        /*  EMM handle passed in 
  286.                                             DX  */
  287.    int86x (EMM_INT, &input_regs, &output_regs, &segment_regs);
  288.    emm_status = output_regs.h.ah;
  289.    check_status(emm_status);            /*  Check for errors  */
  290. ==============================================================================
  291.  
  292.  
  293.  
  294.  
  295.  
  296.  
  297.  
  298.  
  299.  
  300.  
  301. ==============================================================================
  302. ==============================================================================
  303. Figure 8: Kernel Module
  304.  
  305. ==============================================================================
  306.  
  307. CODE    SEGMENT PARA PUBLIC 'CODE'
  308. ORG     100h
  309. ASSUME  CS:CODE, DS:DATA, ES:NOTHING, SS:STACK
  310.  
  311. max_proc_entries              EQU        64
  312.                               
  313. pseudo_over_struct            STRUC
  314.       proc_data_segment       DW        ?
  315.       proc_extra_segment      DW        ?
  316.       proc_entry_count        DW        ?
  317.       proc_entry_ptr          DD max_proc_entries DUP (?)
  318. pseudo_over_struct            ENDS
  319.  
  320. main  PROC  NEAR
  321.  
  322.       MOV   AX, DATA                       ; Segment initialization
  323.       MOV   DS, AX
  324.  
  325. check_for_emm_loaded:
  326.       CALL  test_for_EMM                   ; Use the "interrupt vector"
  327.       JE    get_emm_page_frame             ; technique to determine
  328.       JMP   emm_err_exit                   ; whether EMM is loaded
  329.  
  330. get_emm_page_frame:
  331.       MOV   AH, 41h                        ; Get the page frame base
  332.       INT   67h                            ; address from EMM
  333.       OR    AH, AH
  334.       JZ    allocate_64K
  335.       JMP   emm_err_exit
  336.  
  337. allocate_64K:
  338.       MOV   exp_mem_segment, BX            ; Allocate 4 pages of expand-
  339.       MOV   AH, 43h                        ; ed memory for this example.
  340.       MOV   BX, 4                          ; More can be allocated de-
  341.       INT   67h                            ; pending on the number of
  342.       OR    AH, AH                         ; overlays to be loaded.
  343.       JZ    map_64K                        ; Actually, in this case,
  344.       JMP   emm_err_exit                   ; only a single page is re-
  345.                                            ; quired because the example
  346.                                            ; pseudo-overlay is extreme-
  347.                                            ; ly small.
  348. map_64K:
  349.       MOV   handle, DX                     ; Map in the first 4 logical
  350.       MOV   CX, 4                          ; pages at physical pages 0
  351. map_pages_loop:                            ; through 3
  352.       MOV   AH, 44h                        ;    logical page 0 at
  353.       MOV   BX, CX                         ;       physical page 0
  354.       DEC   BX                             ;    logical page 1 at
  355.       MOV   AL, BL                         ;       physical page 1
  356.       MOV   DX, handle                     ;    logical page 2 at
  357.       INT   67h                            ;       physical page 2
  358.       OR    AH, AH                         ;    logical page 3 at 
  359.       LOOPE map_pages_loop                 ;       physical page 3
  360.       JE    init_load_struct               ; If additional overlays were
  361.       JMP   emm_err_exit                   ; required, each overlay 
  362.                                            ; would be loaded after map-
  363.                                            ; ping and a new set of
  364.                                            ; logical pages would be
  365.                                            ; mapped at the same
  366.                                            ; physical pages.
  367.  
  368. init_load_struct:
  369.       MOV   ES, exp_mem_segment            ; Initialize pseudo-overlay
  370.       MOV   DI, 0                          ; environment and procedure
  371.       MOV   CX, (SIZE pseudo_over_struct)  ; pointer area. This struc-
  372.       MOV   AL, 0                          ; ture begins at the page 
  373.       REP   STOSB                          ; frame segment address.
  374.  
  375.       MOV   AX, (SIZE pseudo_over_struct)  ; Compute the load address
  376.       ADD   AX, 000Fh                      ; within expanded memory for
  377.       AND   AX, 0FFF0h                     ; the overlay. The address is
  378.       MOV   CX, 4                          ; rounded up to the next
  379.       SHR   AX, CL                         ; higher paragraph boundary
  380.       ADD   AX, exp_mem_segment            ; immediately following the
  381.       MOV   parm_block.load_segment, AX    ; pseudo-overlay environment
  382.       MOV   parm_block.reloc_factor, AX    ; & procedure pointer
  383.                                            ; structure. This computa-
  384.                                            ; tion takes into account
  385.                                            ; the maximum number of
  386.                                            ; procedure entry points
  387.                                            ; which the pseudo-overlay
  388.                                            ; is going to return to
  389.                                            ; this program.
  390.  
  391.       MOV   WORD PTR entry_point[0], 100h  ; Build .COM file entry
  392.       MOV   WORD PTR entry_point[2], AX    ; point
  393.  
  394.       MOV   AH, 4Bh                        ; Load the pseudo-overlay
  395.       MOV   AL, 03h                        ; using the DOS "load
  396.       LEA   DX, pseudo_over_name           ; overlay" function
  397.       PUSH  DS
  398.       POP   ES
  399.       LEA   BX, parm_block
  400.       INT   21h
  401.       JC    emm_err_exit
  402.  
  403.       PUSH  DS                             ; Transfer control to the
  404.       PUSH  ES                             ; loaded pseudo-overlays
  405.       CALL  DWORD PTR entry_point          ; initialization code
  406.       POP   ES
  407.       POP   DS
  408.       OR    AH, AH
  409.       JZ    call_over_procedures
  410.       JMP   emm_err_exit
  411.  
  412. call_over_procedures:
  413.       MOV   ES, exp_mem_segment            ; As an example of passing
  414.       MOV   BX, 0                          ; control to a procedure
  415.       MOV   DI, 0                          ; existing in expanded
  416.       MOV   CX, ES:[BX].proc_entry_count   ; memory, each procedure con-
  417.       JCXZ  deallocate_exp_memory          ; tained in the overlay will
  418.                                            ; be called in sequence.
  419.                                            ; Obviously, a single pro-
  420.                                            ; cedure could be called
  421.                                            ; just as easily.
  422.  
  423. pseudo_over_call_loop:
  424.       PUSH  BX
  425.       PUSH  CX
  426.       PUSH  DI
  427.       PUSH  ES
  428.       PUSH  DS
  429.  
  430.       LDS   AX, ES:[BX+DI].proc_entry_ptr
  431.       MOV   WORD PTR CS:tp_ent_ptr[0], AX
  432.       MOV   WORD PTR CS:tp_ent_ptr[2], DS
  433.  
  434.       MOV   AX, 123                        ; Pass 2 numbers to
  435.       MOV   DX, 23                         ; the procedures
  436.  
  437.       MOV   DS, ES:[BX].proc_data_segment  ; Set up pseudo-overlays
  438.       MOV   ES, ES:[BX].proc_extra_segment ; segment environment
  439.       CALL  DWORD PTR CS:tp_ent_ptr        ; Call each procedure
  440.  
  441.       POP   DS
  442.       POP   ES
  443.       POP   DI
  444.       POP   CX
  445.       POP   BX
  446.  
  447.       ADD   DI, 4                          ; Adjust index to the next
  448.       LOOP  pseudo_over_call_loop          ; procedure (4 bytes long)
  449.                                            ; pointer & loop till all
  450.                                            ; have been called
  451.  
  452. deallocate_exp_memory:
  453.       MOV   AH, 45h                        ; Return the allocated
  454.       MOV   DX, handle                     ; pages to the expanded
  455.       INT   67h                            ; memory manager
  456.       OR    AH, AH
  457.       JNZ   emm_err_exit
  458.  
  459. exit:
  460.       MOV   AH, 4Ch                        ; Return a normal exit code
  461.       MOV   AL, 0
  462.       INT   21h
  463.  
  464. emm_err_exit:
  465.       MOV   AL, AH                         ; Display the fact that
  466.       MOV   AH, 09h                        ; an EMM error occurred
  467.       LEA   DX, emm_err_msg                ; Go to the normal exit
  468.       INT   21h
  469.       JMP   exit
  470.  
  471.       tp_ent_ptr              DD        ?  ; CS relative far pointer
  472.                                            ; used for transfer to the
  473. main  ENDP                                 ; procedures in the
  474.                                            ; pseudo_overlay
  475. ==============================================================================
  476.  
  477.  
  478.  
  479.  
  480.  
  481.  
  482.  
  483.  
  484.  
  485.  
  486.  
  487.  
  488.  
  489. ==============================================================================
  490. ==============================================================================
  491. Figure 9: Procedure to Test for the Presence of EMM 
  492.  
  493. ==============================================================================
  494.  
  495. test_for_EMM    PROC NEAR
  496.  
  497.        MOV     AX, 3567h              ; Issue "get interrupt vector"
  498.        INT     21h
  499.  
  500.        MOV     DI, 000Ah              ; Use the SEGMENT in ES
  501.                                       ; returned by DOS, place
  502.                                       ; the "device name field"
  503.                                       ; OFFSET in DI.
  504.  
  505.        LEA     SI, EMM_device_name    ; Place the OFFSET of the EMM
  506.                                       ; device name string in SI,
  507.                                       ; the SEGMENT is already in DS.
  508.  
  509.        MOV     CX, 8                  ; Compare the name strings
  510.        CLD                            ; Return the status of the
  511.        REPE    CMPSB                  ; compare in the ZERO flag
  512.        RET
  513.  
  514. test_for_EMM ENDP
  515.  
  516. CODE        ENDS
  517. ==============================================================================
  518.  
  519.  
  520.  
  521.  
  522.  
  523.  
  524.  
  525.  
  526.  
  527.  
  528.  
  529.  
  530. ==============================================================================
  531. ==============================================================================
  532. Figure 10: Pseudo-overlay Module
  533.  
  534. ==============================================================================
  535.  
  536. CODE    SEGMENT PARA PUBLIC 'CODE'
  537. ASSUME  CS:CODE, DS:DATA
  538. ORG     100h
  539.  
  540. actual_proc_entries         EQU         2
  541.  
  542. overlay_entry_struct        STRUC
  543.         proc_data_segment   DW          ?
  544.         proc_extra_segment  DW          ?
  545.         proc_entry_count    DW          ?
  546.         proc_entry_ptr      DD          actual_proc_entries DUP (?)
  547. overlay_entry_struct        ENDS
  548. ==============================================================================
  549.  
  550.  
  551.  
  552.  
  553.  
  554.  
  555.  
  556.  
  557.  
  558.  
  559.  
  560.  
  561.  
  562. ==============================================================================
  563. ==============================================================================
  564. Figure 11: Procedure to Identify Overlay
  565.  
  566. ==============================================================================
  567.  
  568. command_line_entry_point        PROC        NEAR
  569.  
  570.         MOV     AX, DATA                    ; Set up local data
  571.         MOV     DS, AX                      ; segment
  572.  
  573.         LEA     DX, overlay_err_msg         ; Display overlay error
  574.         MOV     AH, 09h                     ; message
  575.         INT     21h                
  576.  
  577.         MOV     AX, 4C00h                   ; Exit back to DOS
  578.         INT     21h
  579.  
  580. command_line_entry_point        ENDP
  581. ==============================================================================
  582.  
  583.  
  584.  
  585.  
  586.  
  587.  
  588.  
  589.  
  590.  
  591.  
  592.  
  593.  
  594.  
  595. ==============================================================================
  596. ==============================================================================
  597. Figure 12: Data Segment for the Pseudo-overlay Module
  598.  
  599. ==============================================================================
  600.  
  601. DATA  SEGMENT PARA PUBLIC 'DATA'
  602.  
  603. sum_msg         DB   0Dh, 0Ah, 'Sum of numbers = ', '$'
  604. diff_msg        DB   0Dh, 0Ah, 'Difference of numbers = ', '$'
  605. overlay_err_msg DB   'Overlay cannot be executed via the command line$'
  606. powers_of_ten   DW   10000, 1000, 100, 10, 1
  607.  
  608. DATA  ENDS
  609.  
  610. END   command_line_entry_point
  611. ==============================================================================
  612.  
  613.  
  614.  
  615.  
  616.  
  617.  
  618.  
  619.  
  620.  
  621.  
  622.  
  623.  
  624.  
  625. ==============================================================================
  626. ==============================================================================
  627. Figure 13: Pseudo-overlay Data Structure Initialization Procedure
  628.  
  629. ==============================================================================
  630.  
  631. initialization  PROC    FAR
  632.  
  633. MOV  AX, DATA                                        ; Set up a local
  634. MOV  DS, AX                                          ; data segment
  635.  
  636. MOV  AH, 41h                                         ; Get the page 
  637. INT  67h                                             ; frame segment
  638. OR   AH, AH                                          ; address from EMM
  639. JNZ  error       
  640.  
  641. MOV  ES, BX                                          ; Create a pointer 
  642. MOV  DI, 0                                           ; to the expanded
  643.                                                      ; memory page frame
  644.                                                      ; segment address
  645.  
  646. MOV  ES:[DI].proc_data_segment, DS                   ; Return local data 
  647. MOV  ES:[DI].proc_extra_segment, DS                  ; & extra segment 
  648.                                                      ; back to the kernel
  649.  
  650. MOV  WORD PTR ES:[DI].proc_entry_count, 2            ; Return the number
  651.                                                      ; of local call-
  652.                                                      ; able procedures
  653.                                                      ; back to kernel
  654. MOV  WORD PTR ES:[DI].proc_entry_ptr[0], OFFSET sum  ; Return a far
  655. MOV  WORD PTR ES:[DI].proc_entry_ptr[2], SEG    sum  ; pointer to each
  656. MOV  WORD PTR ES:[DI].proc_entry_ptr[4], OFFSET diff ; local callable
  657. MOV  WORD PTR ES:[DI].proc_entry_ptr[6], SEG    diff ; procedure in the
  658.                                                      ; pseudo-overlay
  659.                                                      ; back to kernel
  660.  
  661. exit:  MOV   AH, 0                                   ; Set status in AH
  662.                                                      ; = passed
  663. error: RET                                           ; Return status
  664.                                                      ; in AH
  665.  
  666. initialization  ENDP
  667. ==============================================================================
  668.  
  669.  
  670.  
  671.  
  672.  
  673.  
  674.  
  675.  
  676.  
  677.  
  678.  
  679.  
  680.  
  681. ==============================================================================
  682. ==============================================================================
  683. Figure 14: Procedure to Add AX and DX
  684. ==============================================================================
  685.  
  686. sum     PROC    FAR
  687.  
  688.         ADD     AX, DX                 ; Add numbers
  689.         PUSH    AX                     ; Display sum message
  690.         LEA     DX, sum_msg
  691.         MOV     AH, 09h
  692.         INT     21h
  693.         POP     AX
  694.         CALL    display_result         ; Display sum
  695.         RET
  696.  
  697. sum     ENDP
  698. ==============================================================================
  699.  
  700.  
  701.  
  702.  
  703.  
  704.  
  705.  
  706.  
  707.  
  708.  
  709.  
  710.  
  711. ==============================================================================
  712. ==============================================================================
  713. Figure 15: Procedure to Subtract AX and DX
  714.  
  715. ==============================================================================
  716.  
  717. diff    PROC    FAR
  718.  
  719.         SUB     AX, DX               ; Subtract numbers
  720.         PUSH    AX                   ; Display difference message
  721.         LEA     DX, diff_msg
  722.         MOV     AH, 09h
  723.         INT     21h
  724.         POP     AX
  725.         CALL    display_result       ; Display difference
  726.         RET
  727.  
  728. diff    ENDP
  729. ==============================================================================
  730.  
  731.  
  732.  
  733.  
  734.  
  735.  
  736.  
  737.  
  738.  
  739.  
  740.  
  741.  
  742. ==============================================================================
  743. ==============================================================================
  744. Figure 16: Procedure to Display Number in AX in Decimal
  745.  
  746. ==============================================================================
  747.  
  748. display_result  PROC    NEAR
  749.  
  750.         LEA     DI, powers_of_ten
  751.         MOV     CX, 5
  752. display_loop:
  753.         XOR     DX, DX            ; Divide the number passed
  754.         DIV     WORD PTR [DI]     ; in AX by descending powers of ten
  755.         ADD     AL, '0'           ; Convert digit to ASCII
  756.  
  757.         PUSH    DX                ; Output the digit
  758.         MOV     DL, AL
  759.         MOV     AH, 02h
  760.         INT     21h
  761.         POP     AX
  762.  
  763.         ADD     DI, 2
  764.         LOOP    display_loop
  765.         RET
  766.  
  767. display_result        ENDP
  768. ==============================================================================
  769.  
  770.  
  771.  
  772.  
  773.  
  774.  
  775.  
  776.  
  777.  
  778.  
  779.  
  780.  
  781. ==============================================================================
  782. ==============================================================================
  783.  
  784. Figure 17: Data and Stack Segment for the Kernel and the Pseudo-overlay
  785.  
  786. ==============================================================================
  787.  
  788. DATA            SEGMENT PARA PUBLIC 'DATA'
  789.  
  790. emm_err_msg        DB    'EMM error occurred$' ; EMM diagnostic message
  791. pseudo_over_name   DB    'OVERLAY.EXE', 0      ; Name of pseudo-overlay
  792. EMM_device_name    DB    'EMMXXXX0'            ; Standard EMM device name
  793. exp_mem_segment    DW    ?                     ; Temp for expanded
  794.                                                ; memory page frame
  795.                                                ; segment address
  796. handle             DW    ?                     ; Temp for handle allo-
  797.                                                ; cated to the kernel
  798. entry_point  DD          ?                     ; Far pointer to the 
  799.                                                ; entry point for a .COM 
  800.                                                ; file
  801. parm_block_struct  STRUC                       ; Structure definition 
  802.     load_segment   DW    ?                     ; for a "load overlay" 
  803.     reloc_factor   DW    ?                     ; parameter block
  804. parm_block_struct  ENDS
  805. parm_block         parm_block_struct <>        ; The actual parameter
  806.                                                ; block
  807.  
  808. DATA        ENDS
  809.  
  810.  
  811. STACK   SEGMENT PARA STACK 'STACK'
  812.         local_stack     DW 256 DUP ('^^')
  813. STACK   ENDS
  814.  
  815. END        main
  816. ==============================================================================
  817.