     1                                  ;*********************************************************************
     2                                  ;*   MLMEMORY.ASM                                                    *
     3                                  ;*                                                                   *
     4                                  ;*   By:            Michael Devore                                   *
     5                                  ;*   Date:          08/09/92                                         *
     6                                  ;*   Model:         Small                                            *
     7                                  ;*   Version:       2.5                                              *
     8                                  ;*   Assembler:     MASM 5.0                                         *
     9                                  ;*   Environment:   MS-DOS 2.x+                                      *
    10                                  ;*                                                                   *
    11                                  ;*   memory, file i/o buffer manipulation routines for linker        *
    12                                  ;*                                                                   *
    13                                  ;*********************************************************************
    14                                  
    15                                  ;TITLE   WARPLINK mlmemory
    16                                  ;PAGE    50,80
    17                                  
    18                                  ;.MODEL  SMALL
    19                                  
    20                                  ;*****************************
    21                                  ;* Include files             *
    22                                  ;*****************************
    23                                  
    24                                  [list -]
    29                                       
    30                                  ;*****************************
    31                                  ;* Public declarations       *
    32                                  ;*****************************
    33                                       
    34                                  PUBLIC  get_memory,alloc_memory,free_memory,load_buffer,shrink_buffer
    35                                  PUBLIC  give_load_size
    36                                  PUBLIC  map_ems_page,restore_ems_map,alloc_ems_trans,read_to_ems
    37                                  PUBLIC  ems_trans_block
    38                                  PUBLIC	mod_alloc_base
    39                                  
    40                                  ;*****************************
    41                                  ;* Data begins               *
    42                                  ;*****************************
    43                                  
    44                                  .DATA
    45                                  
    46                                  ;*****************************
    47                                  ;* External declarations     *
    48                                  ;*****************************
    49                                  
    50                                  ; variables
    51                                  EXTRN   filename:BYTE,temp_file_name:BYTE
    52                                  EXTRN   temp_file_pages:BYTE,temp_page_ptr:WORD
    53                                  
    54                                  ; initialized local variables
    55                                  
    56                                  ; byte values
    57                                  EVEN
    58 00000000 00                      rollout_flag    DB  0       ; nonzero if memory image rolled out to disk during pass 2
    59                                  
    60                                  .DATA?
    61                                  
    62                                  ; uninitialized local variables
    63                                  
    64                                  ; word values
    65                                  EVEN
    66 00000000 ????                    free_start      DW  ?       ; start of memory to free in free_memory routine if pass 2 roll-out occurred
    67 00000002 ????                    ems_trans_block DW  ?       ; segment of EMS transfer block
    68 00000004 ????                    mod_alloc_base  DW  ?       ; base of memory allocation made for module
    69                                  
    70                                  ;*****************************
    71                                  ;* Constant data             *
    72                                  ;*****************************
    73                                  
    74                                  .CONST
    75                                  
    76                                  tbuff:
    77 00000000 202020204B69420D0A      .:	DB  '    KiB',CR,LF	; buffer for exe load image size feedback
    78                                  .size: equ $ - .
    79                                  
    80 00000009 17                      image_tlen  DB  image_tstop-image_text
    81 0000000A 0D0A455845206C6F61-     image_text  DB  CR,LF,'EXE load image size: '
    81 00000013 6420696D6167652073-
    81 0000001C 697A653A20         
    82                                  image_tstop equ   $
    83                                  
    84                                  ;*****************************
    85                                  ;* Code begins               *
    86                                  ;*****************************
    87                                  
    88                                  .CODE
    89                                  
    90                                  ;*****************************
    91                                  ;* External declarations     *
    92                                  ;*****************************
    93                                  
    94                                  ; procedures
    95                                  EXTRN   link_error:NEAR,dos_error:NEAR,make_temp_fbk:NEAR
    96                                  
    97                                  %IFNDEF JUNIOR
    98                                  EXTRN   ems_tempfile_create:NEAR,ems_tempfile_write:NEAR
    99                                  %ENDIF
   100                                  
   101                                  ;*****************************
   102                                  ;* GET_MEMORY                *
   103                                  ;*****************************
   104                                  
   105                                  ; allocate memory for linker for use with control blocks and file buffers
   106                                  ; destroys ax,bx,cx,dx
   107                                  
   108                                  get_memory      PROC
   109                                  
   110                                  gm_1:
   111 00000000 B448                        mov ah,48h              ; allocate memory
   112 00000002 BBFFFF                      mov bx,0ffffh           ; force request to fail, function will return largest available block
   113 00000005 CD21                        int 21h
   114 00000007 83F808                      cmp ax,8                ; insufficient memory error is expected
   115 0000000A 7403                        je gm_2
   116 0000000C E9(0000)                    jmp NEAR PTR dos_error  ; other errors are fatal
   117                                  
   118                                  ; real memory allocation attempt with bx preset to largest available block size
   119                                  gm_2:
   120 0000000F B448                        mov ah,48h              ; allocate memory
   121 00000011 CD21                        int 21h
   122 00000013 7303                        jnc gm_3                ; no errors
   123 00000015 E9(0000)                    jmp NEAR PTR dos_error  ; any error is fatal
   124                                  
   125                                  gm_3:
   126 00000018 891E[0000]                  mov [memory_blk_size],bx  ; save size of memory block allocated in paras
   127 0000001C A3[0000]                    mov [memory_blk_base],ax  ; save segment of allocated block
   128 0000001F A3[0000]                    mov [allocation_base],ax  ; init block allocation block to initial allocation segment
   129                                  
   130                                  %IFNDEF JUNIOR
   131 00000022 31C0                        xor ax,ax
   132 00000024 3806[0000]                  cmp [is_no_ems],al        ; see if EMS is useable
   133 00000028 7553                        jne gm_chkblk           ; no
   134 0000002A 3906[0000]                  cmp [ems_handle],ax       ; see if EMS already allocated
   135 0000002E 754D                        jne gm_chkblk           ; yes
   136                                  
   137                                  ; allocate EMS if possible
   138                                  ;*** COMMENT # temporary for 1.60f
   139 00000030 B442                        mov ah,42h              ; get number of pages
   140 00000032 CD67                        int 67h
   141 00000034 08E4                        or  ah,ah
   142 00000036 7540                        jne gm_no_ems           ; error occurred, don't use EMS
   143 00000038 83FB04                      cmp bx,4                ; see if at least 4 unused EMS pages
   144 0000003B 723B                        jb  gm_no_ems           ; no
   145                                  
   146 0000003D 83FB09                      cmp bx,9                ; see if at least nine pages
   147 00000040 7303                        jae gm_em2              ; yes, allocate them all
   148 00000042 BB0400                      mov bx,4                ; can only use 4 pages if 8 or less
   149                                  
   150                                  gm_em2:
   151 00000045 891E[0000]                  mov [ems_pagecount],bx    ; save unallocated pages
   152 00000049 89D8                        mov ax,bx
   153 0000004B 83E804                      sub ax,4                ; 4 pages allocated for i/o buffer
   154 0000004E A3[0000]                    mov [ems_page_avail],ax   ; save rest available for use by WarpLink for other purposes
   155 00000051 B443                        mov ah,43h              ; allocate handle and pages
   156 00000053 CD67                        int 67h
   157 00000055 8916[0000]                  mov [ems_handle],dx       ; save handle, if successful
   158 00000059 08E4                        or  ah,ah
   159 0000005B 751B                        jne gm_no_ems           ; error occurred
   160                                  
   161                                  ; map in pages to use logical page 0->0, 1->1, 2->2, 3->3
   162 0000005D 31DB                        xor bx,bx
   163 0000005F 88D8                        mov al,bl
   164 00000061 E8BB02                      call    map_ems_page    ; map page 0
   165 00000064 43                          inc bx
   166 00000065 88D8                        mov al,bl
   167 00000067 E8B502                      call    map_ems_page    ; map page 1
   168 0000006A 43                          inc bx
   169 0000006B 88D8                        mov al,bl
   170 0000006D E8AF02                      call    map_ems_page    ; map page 2
   171 00000070 43                          inc bx
   172 00000071 88D8                        mov al,bl
   173 00000073 E8A902                      call    map_ems_page    ; map page 3
   174 00000076 EB05                        jmp SHORT gm_chkblk
   175                                  
   176                                  ; failed to get at least 4 EMS 16K pages successfully
   177                                  gm_no_ems:
   178 00000078 C606[0000]01                mov byte [is_no_ems],1         ; set no EMS page
   179                                  
   180                                  ;*** END COMMENT #
   181                                  
   182                                  %ENDIF
   183                                  
   184                                  gm_chkblk:
   185 0000007D A1[0000]                    mov ax,[memory_blk_base]
   186 00000080 8B1E[0000]                  mov bx,[memory_blk_size]
   187                                  
   188 00000084 803E[0000]00                cmp byte [is_no_ems],0         ; see if EMS i/o buffer allocated
   189 00000089 7508                        jne gm_chk16            ; no, must have 16K block
   190 0000008B 81FB0005                    cmp bx,1280             ; block size must be >=20K with EMS buffer (16K for transfer buffer)
   191 0000008F 732E                        jae gm_3a               ; large enough
   192 00000091 EB06                        jmp SHORT gm_tryroll    ; not large enough
   193                                  
   194                                  gm_chk16:
   195 00000093 81FB0004                    cmp bx,1024             ; block size must be >=16K (1024 paragraphs) if no EMS i/o buffer
   196 00000097 7326                        jae gm_3a               ; large enough
   197                                  
   198                                  ; not enough memory free, see if can roll memory image out to disk
   199                                  gm_tryroll:
   200 00000099 803E[0000]00                cmp byte [is_ondisk],0         ; see if memory image on disk (no roll-out possibilities)
   201 0000009E 7519                        jne gm_oom              ; already on disk
   202 000000A0 803E[0000]00                cmp byte [is_inmem],0          ; see if memory image is in memory (if memory image exists)
   203 000000A5 7412                        je  gm_oom              ; memory image not built yet
   204                                  
   205 000000A7 E8FE01                      call    free_memory     ; free too-small memory block back to DOS
   206 000000AA E8B600                      call    mem_roll_out    ; roll memory image to disk
   207 000000AD A1[0000]                    mov ax,[image_mem_ptr]    ; get segment of memory image
   208 000000B0 A3[0000]                    mov [memory_blk_base],ax  ; save as segment of memory block allocated
   209 000000B3 E8F201                      call    free_memory     ; free up unused memory (memory image size less file block allocations)
   210 000000B6 E947FF                      jmp NEAR PTR gm_1       ; retry DOS memory allocation
   211                                  
   212                                  gm_oom:
   213 000000B9 B80800                      mov ax,8                ; force DOS out of memory error
   214 000000BC E9(0000)                    jmp NEAR PTR dos_error
   215                                  
   216                                  ; ax holds base of allocated memory block (memory_blk_base)
   217                                  ; bx holds size of memory block in paras (memory_blk_size)
   218                                  gm_3a:
   219 000000BF 803E[0000]00                cmp byte [is_no_ems],0         ; see if EMS i/o buffer allocated
   220 000000C4 7518                        jne gm_membuff          ; no
   221                                  
   222                                  ; set up for EMS i/o buffer
   223 000000C6 0306[0000]                  add ax,[memory_blk_size]  ; compute end of memory block
   224 000000CA A3[0000]                    mov [memory_blk_end],ax   ; and save it
   225 000000CD A3[0000]                    mov [allocation_top],ax   ; save end of memory block as allocation ceiling
   226 000000D0 A1[0000]                    mov ax,[ems_base]
   227 000000D3 A3[0000]                    mov [buffer_base],ax      ; buffer i/o base is EMS page frame
   228 000000D6 B8FF0F                      mov ax,0fffh
   229 000000D9 A3[0000]                    mov [buffer_size],ax      ; EMS i/o buffer size is 64K-16 bytes, 4095 paragraphs
   230 000000DC EB46                        jmp SHORT gm_buffend    ; bypass memory i/o buffer code
   231                                  
   232                                  gm_membuff:
   233 000000DE 803E[0000]00                cmp byte [any_ddl],0           ; see if using DDL's
   234 000000E3 7408                        je  gm_noddl            ; no
   235 000000E5 81FBFF0F                    cmp bx,0fffh            ; using DDL's, allocate 64K-16 for buffer
   236 000000E9 72CE                        jb  gm_oom              ; no enough memory
   237 000000EB EB06                        jmp SHORT gm_0fffh      ; allocate memory for 64K-16 buffer
   238                                  
   239                                  gm_noddl:
   240 000000ED 81FB0020                    cmp bx,2000h            ; if block size >=128K only use 64K-16 for file buffer
   241 000000F1 7206                        jb  gm_4                ; available memory less than 128K
   242                                  
   243                                  gm_0fffh:
   244 000000F3 81EBFF0F                    sub bx,0fffh            ; back off 64K-16 for file buffer, offset in memory block
   245 000000F7 EB15                        jmp SHORT gm_5          ; bypass buffer setup for <128K block code
   246                                  
   247                                  gm_4:
   248 000000F9 81FB0006                    cmp bx,1536             ; see if block size smaller than 24K
   249 000000FD 7306                        jae gm_4a               ; no, larger or equal to 24K
   250                                  
   251                                  ; allocate 12K for file buffer, remainder for available memory
   252 000000FF 81EB0003                    sub bx,768              ; back off 12K for file buffer
   253 00000103 EB09                        jmp SHORT gm_5
   254                                  
   255                                  ; split file buffer and available memory 50-50
   256                                  gm_4a:
   257 00000105 89D9                        mov cx,bx               ; block size into cx
   258 00000107 D1E9                        shr cx,1                ; divide block size by 2
   259 00000109 83D100                      adc cx,0                ; odd values add back
   260 0000010C 29CB                        sub bx,cx               ; back off memory for file buffer
   261                                  
   262                                  gm_5:
   263 0000010E 01C3                        add bx,ax               ; compute base of buffer by adding memory block base to offset
   264 00000110 891E[0000]                  mov [buffer_base],bx      ; and save it
   265 00000114 891E[0000]                  mov [allocation_top],bx   ; save base of buffer as allocation ceiling
   266 00000118 0306[0000]                  add ax,[memory_blk_size]  ; compute end of memory block
   267 0000011C A3[0000]                    mov [memory_blk_end],ax   ; and save it
   268 0000011F 29D8                        sub ax,bx               ; compute size of file buffer
   269 00000121 A3[0000]                    mov [buffer_size],ax      ; and save it
   270                                  
   271                                  ; convert paragraphs in ax to bytes for buffer end, buffer tail, offset
   272                                  gm_buffend:
   273 00000124 D1E0                        shl ax,1                ; x2
   274 00000126 D1E0                        shl ax,1                ; x4
   275 00000128 D1E0                        shl ax,1                ; x8
   276 0000012A D1E0                        shl ax,1                ; x16, converted to bytes
   277 0000012C A3[0000]                    mov [buffer_end],ax       ; offset from memory block base to end
   278 0000012F A3[0000]                    mov [buffer_tail],ax      ; init buffer tail to end
   279 00000132 C3                          ret
   280                                  get_memory      ENDP
   281                                  
   282                                  ;*****************************
   283                                  ;* ALLOC_MEMORY              *
   284                                  ;*****************************
   285                                  
   286                                  ; allocate memory for control block
   287                                  ; bx holds size of block in paragraphs upon entry
   288                                  ; destroys ax,bx
   289                                  ; returns ax -> allocated control block
   290                                  
   291                                  alloc_memory    PROC
   292                                  
   293                                  am_1:
   294 00000133 A1[0000]                    mov ax,[allocation_base]  ; get previous base to allocate from
   295 00000136 50                          push    ax              ; save it
   296 00000137 01D8                        add ax,bx               ; compute new base
   297 00000139 A3[0000]                    mov [allocation_base],ax  ; save it
   298 0000013C 3B06[0000]                  cmp ax,[allocation_top]   ; must be less than allocation ceiling
   299 00000140 761F                        jbe am_ret              ; control block allocation fits into memory
   300 00000142 803E[0000]00                cmp byte [is_ondisk],0         ; see if memory image on disk (no roll-out possibilities)
   301 00000147 7515                        jne am_2                ; already on disk
   302 00000149 803E[0000]00                cmp byte [is_inmem],0          ; see if memory image is in memory (if memory image exists)
   303 0000014E 740E                        je  am_2                ; memory image not built yet
   304 00000150 58                          pop ax                  ; get previous base value
   305 00000151 A3[0000]                    mov [free_start],ax       ; save as start of memory to free (new allocation base/top below old)
   306 00000154 C606[0000]01                mov byte [rollout_flag],1      ; flag that memory was rolled out to disk during pass 2 (for free_memory proc)
   307 00000159 E80700                      call    mem_roll_out    ; roll memory image to disk
   308 0000015C EBD5                        jmp SHORT am_1          ; retry memory allocation with new base and top from old memory image
   309                                  
   310                                  am_2:
   311 0000015E E8A902                      call    shrink_buffer   ; doesn't fit, try shrinking file buffer
   312                                  
   313                                  am_ret:
   314 00000161 58                          pop ax                  ; restore previous base as allocate control block pointer
   315 00000162 C3                          ret
   316                                  alloc_memory    ENDP
   317                                  
   318                                  ;*****************************
   319                                  ;* MEM_ROLL_OUT              *
   320                                  ;*****************************
   321                                  
   322                                  ; roll memory image out to disk
   323                                  ; destroys ax
   324                                  
   325                                  mem_roll_out    PROC
   326 00000163 53                          push    bx              ; save critical register
   327 00000164 51                          push    cx
   328 00000165 52                          push    dx
   329 00000166 56                          push    si
   330 00000167 57                          push    di
   331 00000168 06                      	push	es
   332                                  
   333 00000169 C606[0000]01                mov byte [is_ondisk],1         ; flag that executable image is now on disk
   334 0000016E C606[0000]00                mov byte [is_inmem],0          ; reset executable in memory flag
   335                                  
   336 00000173 E8(0000)                    call    ems_tempfile_create ; create temporary file in EMS/XMS, if possible
   337 00000176 803E[0000]00                cmp byte [tmp_in_emsxms],0     ; see if temporary file in EMS/XMS
   338 0000017B 7503                        jne mro_out             ; yes, bypass disk file creation
   339                                  
   340 0000017D E8(0000)                    call    make_temp_fbk   ; make temporary file and give feedback
   341                                  
   342                                  ; write image_size bytes starting at segment image_mem_ptr to disk or EMS
   343                                  mro_out:
   344 00000180 8B36[0000]                  mov si,WORD PTR [image_size]  ; get low word
   345 00000184 8B3E[0200]                  mov di,WORD PTR [image_size+2]    ; get high word
   346 00000188 8B1E[0000]                  mov bx,[image_handle]
   347                                  
   348                                  ; transfer program to disk in 64K-16 chunks
   349                                  ; di:si contain number of bytes to write, bx == file handle
   350 0000018C FF36[0000]                  push    word [image_mem_ptr]   ; save original memory pointer value
   351                                  
   352                                  wp_mem_write:
   353 00000190 31D2                        xor dx,dx               ; zero offset of write buffer
   354 00000192 09FF                        or  di,di               ; see if byte count to write is 64K or more
   355 00000194 7505                        jne mro_2               ; yes, write a 64K-16 chunk
   356 00000196 83FEF0                      cmp si,0fff0h           ; see if byte count is at least 64-16
   357 00000199 723D                        jb mro_4                ; no, exit 64K-16 writing loop
   358                                  
   359                                  mro_2:
   360 0000019B B9F0FF                      mov cx,0fff0h           ; number of bytes to write (64K-16)
   361 0000019E A1[0000]                    mov ax,[image_mem_ptr]
   362 000001A1 1E                          push    ds              ; save ds, critical register
   363                                  
   364 000001A2 803E[0000]00                cmp byte [tmp_in_emsxms],0     ; see if temporary file in EMS/XMS
   365 000001A7 7408                        je  mro_noems           ; no
   366 000001A9 8ED8                        mov ds,ax               ; ds -> segment to start write
   367 000001AB E8(0000)                    call    ems_tempfile_write
   368 000001AE 1F                          pop ds                  ; restore ds -> warplink data
   369 000001AF EB19                        jmp SHORT mro_3
   370                                  
   371                                  mro_noems:
   372 000001B1 8ED8                        mov ds,ax               ; ds -> segment to start write
   373 000001B3 B440                        mov ah,40h              ; write to file
   374 000001B5 CD21                        int 21h
   375                                  %IFNDEF JUNIOR
   376 000001B7 E89101                      call    restore_ems_map
   377                                  %ENDIF
   378                                  
   379 000001BA 1F                          pop ds                  ; restore ds -> warplink data
   380 000001BB 7306                        jnc .checkspace               ; no errors
   381                                  .error:
   382 000001BD BA[0000]                    mov dx,OFFSET temp_file_name wrt DGROUP
   383 000001C0 E9(0000)                    jmp NEAR PTR dos_error  ; error writing to file
   384                                  
   385                                  .checkspace:
   386 000001C3 39C8                    	cmp ax, cx
   387 000001C5 B82700                  	mov ax, 27h			; insufficient disk space error
   388 000001C8 75F3                    	jne .error
   389                                  
   390                                  mro_3:
   391 000001CA 8106[0000]FF0F              add word [image_mem_ptr],0fffh ; adjust segment pointer past 64K-16 written (4K-1 paragraphs)
   392 000001D0 83EEF0                      sub si,0fff0h           ; back off number of bytes written from bytes to write
   393 000001D3 83DF00                      sbb di,0                ; borrow to high word
   394 000001D6 EBB8                        jmp SHORT wp_mem_write  ; loop for next write
   395                                  
   396                                  ; transfer leftover bytes (file size modulo 64K-16)
   397                                  mro_4:
   398 000001D8 89F1                        mov cx,si               ; cx holds bytes to write
   399 000001DA E32C                        jcxz    mro_rollout_done    ; no bytes to write, done
   400 000001DC A1[0000]                    mov ax,[image_mem_ptr]
   401 000001DF 1E                          push    ds              ; save ds, critical register
   402                                  
   403 000001E0 803E[0000]00                cmp byte [tmp_in_emsxms],0     ; see if temporary file in EMS/XMS
   404 000001E5 7408                        je  mro_noems2          ; no
   405 000001E7 8ED8                        mov ds,ax               ; ds -> segment to start write
   406 000001E9 E8(0000)                    call    ems_tempfile_write
   407 000001EC 1F                          pop ds                  ; restore ds -> warplink data
   408 000001ED EB19                        jmp SHORT mro_rollout_done
   409                                  
   410                                  mro_noems2:
   411 000001EF 8ED8                        mov ds,ax               ; ds -> segment to start write
   412 000001F1 B440                        mov ah,40h              ; write to file
   413 000001F3 CD21                        int 21h
   414                                  %IFNDEF JUNIOR
   415 000001F5 E85301                      call    restore_ems_map
   416                                  %ENDIF
   417 000001F8 1F                          pop ds                  ; restore ds -> warplink data
   418 000001F9 7306                        jnc .checkspace    ; no errors, all done
   419                                  .error:
   420 000001FB BA[0000]                    mov dx,OFFSET temp_file_name wrt DGROUP
   421 000001FE E9(0000)                    jmp NEAR PTR dos_error  ; error writing to file
   422                                  
   423                                  .checkspace:
   424 00000201 39C8                    	cmp ax, cx
   425 00000203 B82700                  	mov ax, 27h			; insufficient disk space error
   426 00000206 75F3                    	jne .error
   427                                  
   428                                  mro_rollout_done:
   429 00000208 8F06[0000]                  pop word [image_mem_ptr]       ; restore original memory pointer value
   430                                  
   431 0000020C A1[0000]                    mov ax,WORD PTR [image_size]  ; get low word of image size
   432 0000020F 83C00F                      add ax,15               ; round up for paragraph computation
   433 00000212 8B16[0200]                  mov dx,WORD PTR [image_size+2]    ; get high word of image size
   434 00000216 83D200                      adc dx,0                ; carry to high word
   435                                  
   436                                  ; convert image size in dx:ax to paragraphs
   437 00000219 D1EA                        shr dx,1
   438 0000021B D1D8                        rcr ax,1                ; /2
   439 0000021D D1EA                        shr dx,1
   440 0000021F D1D8                        rcr ax,1                ; /4
   441 00000221 D1EA                        shr dx,1
   442 00000223 D1D8                        rcr ax,1                ; /8
   443 00000225 D1EA                        shr dx,1                ; dx should be zero by the final shift
   444 00000227 D1D8                        rcr ax,1                ; /16
   445 00000229 89C3                        mov bx,ax               ; bx holds paragraphs freed by roll-out
   446                                  
   447 0000022B A1[0000]                    mov ax,[image_mem_ptr]
   448 0000022E A3[0000]                    mov [allocation_base],ax  ; old image pointer is new base, temporary before adding file blocks
   449 00000231 01D8                        add ax,bx               ; compute new allocation ceiling
   450 00000233 A3[0000]                    mov [allocation_top],ax   ; save to global memory variable
   451                                  
   452 00000236 81FB0005                    cmp bx,500h             ; must be at least 20K free memory
   453 0000023A 7306                        jae mro_5               ; okay
   454                                  
   455                                  mro_mem_err:
   456 0000023C B80800                      mov ax,8                ; force insufficient memory error
   457 0000023F E9(0000)                    jmp NEAR PTR dos_error
   458                                  
   459                                  mro_5:
   460 00000242 81EB0004                    sub bx,400h             ; subtract off 16K for use by other procedures
   461                                  
   462                                  ; bh holds count of 4K blocks available
   463 00000246 80FF03                      cmp bh,3                ; if 3 or less blocks available use all of them
   464 00000249 7615                        jbe mro_6
   465 0000024B 88F8                        mov al,bh               ; get count of available 4K blocks
   466 0000024D B703                        mov bh,3                ; default blocks to 3
   467 0000024F D0E8                        shr al,1                ; /2
   468 00000251 D0E8                        shr al,1                ; /4, only allocate up to 25% of blocks available
   469 00000253 3C03                        cmp al,3                ; allocate larger of 25% of blocks available or 3
   470 00000255 7609                        jbe mro_6               ; 3 blocks or less
   471 00000257 88C7                        mov bh,al               ; more than 3 blocks
   472 00000259 80FF0F                      cmp bh,15               ; don't allocate more than 15 4K blocks (60K, 0f00h paragraphs)
   473 0000025C 7602                        jbe mro_6               ; 15 or fewer 4K blocks available
   474 0000025E B70F                        mov bh,15               ; set at maximum
   475                                  
   476                                  mro_6:
   477 00000260 883E[0000]                  mov [temp_file_pages],bh  ; save count of 4K blocks
   478 00000264 A1[0000]                    mov ax,[allocation_base]  ; get allocation base (old memory image pointer)
   479 00000267 A3[0000]                    mov [temp_page_ptr],ax    ; save pointer to block
   480 0000026A 30DB                        xor bl,bl               ; zero low byte of paragraphs used
   481 0000026C 011E[0000]                  add [allocation_base],bx  ; update base past allocated 4K blocks
   482 00000270 A1[0000]                    mov ax,[allocation_base]  ; get new allocation base
   483 00000273 3B06[0000]                  cmp ax,[allocation_top]   ; make sure not past top
   484 00000277 77C3                        ja  mro_mem_err         ; out of memory
   485 00000279 A3[0400]                	mov	[mod_alloc_base],ax	; save new base of allocations prior to any allocations
   486                                  
   487 0000027C 07                      	pop	es					; restore critical register
   488 0000027D 5F                          pop di
   489 0000027E 5E                          pop si
   490 0000027F 5A                          pop dx
   491 00000280 59                          pop cx
   492 00000281 5B                          pop bx
   493 00000282 C3                          ret
   494                                  mem_roll_out    ENDP
   495                                  
   496                                  ;*****************************
   497                                  ;* LOAD_BUFFER               *
   498                                  ;*****************************
   499                                  
   500                                  ; load from file into i/o buffer
   501                                  ; bx holds file handle upon entry
   502                                  ; destroys ax,cx,dx
   503                                  
   504                                  load_buffer     PROC
   505 00000283 31C0                    	xor ax, ax
   506 00000285 A2[0000]                    mov byte [eof_flag], al          ; init end of file flag
   507 00000288 1E                          push    ds              ; save critical register
   508 00000289 A3[0000]                    mov word [buffer_head], ax       ; set buffer head equal to offset zero from buffer base
   509 0000028C A1[0000]                    mov ax,[buffer_end]       ; get physical end of buffer
   510 0000028F A3[0000]                    mov [buffer_tail],ax      ; set tail to physical end of buffer
   511 00000292 89C1                        mov cx,ax               ; get number of bytes to read
   512 00000294 31D2                        xor dx,dx
   513 00000296 8E1E[0000]                  mov ds,[buffer_base]      ; DS:DX -> segment:offset of buffer area
   514                                  
   515 0000029A E8EA00                      call    read_to_ems     ; read file, transfer to EMS if necessary
   516                                  
   517                                  lb_exit:
   518 0000029D 1F                          pop ds                  ; restore critical register
   519 0000029E 39C1                        cmp cx,ax               ; see if all bytes were read
   520 000002A0 7405                        je  lb_ret              ; yes
   521                                  
   522 000002A2 C606[0000]01                mov byte [eof_flag],1          ; set end of file flag
   523                                  
   524                                  ;***    push    ds              ; save critical registers
   525                                  ;***    push    bx
   526                                  ;***    mov bx,ax
   527                                  ;***    mov ds,buffer_base      ; DS:BX -> first byte past last read
   528                                  ;***    mov BYTE PTR [bx],0     ; zero it out, so multi-module check will fail there
   529                                  ;***    pop bx                  ; restore critical registers
   530                                  ;***    pop ds
   531                                  
   532                                  lb_ret:
   533 000002A7 C3                          ret
   534                                  load_buffer     ENDP
   535                                  
   536                                  ;*****************************
   537                                  ;* FREE_MEMORY               *
   538                                  ;*****************************
   539                                  
   540                                  ; free memory allocated for linker unused by control blocks
   541                                  ; destroys ax,bx,cx,es
   542                                  
   543                                  free_memory     PROC
   544 000002A8 803E[0000]00                cmp byte [rollout_flag],0      ; see if memory rolled out to disk during pass 2
   545 000002AD 7406                        je  fm_noroll           ; no
   546 000002AF 8B1E[0000]                  mov bx,[free_start]       ; get start of memory to free (old base prior to rollout)
   547 000002B3 EB04                        jmp SHORT fm_1
   548                                  
   549                                  fm_noroll:
   550 000002B5 8B1E[0000]                  mov bx,[allocation_base]  ; get first free (nonallocated to control block) space in memory block
   551                                  
   552                                  fm_1:
   553 000002B9 A1[0000]                    mov ax,[memory_blk_base]  ; segment of memory block allocated
   554 000002BC 29C3                        sub bx,ax               ; compute difference == amount of memory used by control blocks
   555 000002BE 8EC0                        mov es,ax               ; es holds segment of allocated memory block
   556 000002C0 7409                        je  fm_2                ; if memory use is zero then free all of memory
   557 000002C2 B44A                        mov ah,4ah              ; modify memory allocation function
   558                                  
   559                                  fm_intcall:
   560 000002C4 CD21                        int 21h
   561 000002C6 7307                        jnc fm_ret              ; no errors
   562 000002C8 E9(0000)                    jmp NEAR PTR dos_error  ; error occurred
   563                                  
   564                                  fm_2:
   565 000002CB B449                        mov ah,49h              ; release memory function
   566 000002CD EBF5                        jmp SHORT fm_intcall    ; perform the function
   567                                  
   568                                  fm_ret:
   569 000002CF C3                          ret
   570                                  free_memory     ENDP
   571                                  
   572                                  ;*****************************
   573                                  ;* GIVE_LOAD_SIZE            *
   574                                  ;*****************************
   575                                  
   576                                  ; feedback EXE load image size if EXE file
   577                                  ; destroys ax,bx,cx,dx,si
   578                                  
   579                                  give_load_size  PROC
   580 000002D0 803E[0000]00                cmp byte [is_comfile],0        ; see if COM file
   581 000002D5 7547                        jne gls_ret             ; yes, no feedback
   582                                  
   583 000002D7 BB[0A00]                    mov bx,OFFSET image_text wrt DGROUP
   584 000002DA 8A4FFF                      mov cl,[bx-1]           ; get length of string
   585 000002DD 89DA                        mov dx,bx               ; ds:dx -> string
   586 000002DF 30ED                        xor ch,ch               ; zap high byte of cx
   587 000002E1 BB0100                      mov bx,STDOUT           ; write to standard output device
   588 000002E4 B440                        mov ah,40h              ; write to device
   589 000002E6 CD21                        int 21h
   590                                  
   591 000002E8 A1[0000]                    mov ax,WORD PTR [image_size]  ; get low word of image size
   592 000002EB 05FF03                      add ax,1023             ; round up to next 1K boundary
   593 000002EE B000                        mov al,0                ; zero low byte
   594 000002F0 1206[0200]                  adc al,BYTE PTR [image_size+2]    ; get high word low byte with overflow (ignore highest byte, unused)
   595 000002F4 86C4                        xchg    al,ah           ; al holds low word high byte, ah holds high word low byte
   596 000002F6 D1E8                        shr ax,1                ; /512
   597 000002F8 D1E8                        shr ax,1                ; /1024, ax holds 1K pages of image size, rounded up
   598                                  
   599 000002FA BB[0300]                    mov bx,OFFSET tbuff+3 wrt DGROUP    ; bx -> end of buffer to hold ax value
   600 000002FD BE0A00                      mov si,10               ; divisor
   601 00000300 B90300                      mov cx,3                ; 3 digits total
   602                                  
   603                                  gls_divloop:
   604 00000303 4B                          dec bx                  ; point to next most significant digit
   605 00000304 31D2                        xor dx,dx               ; extend dividend in ax to unsigned 32-bit dx:ax
   606 00000306 F7F6                        div si
   607 00000308 80C230                      add dl,'0'              ; convert digit to ASCII
   608 0000030B 8817                        mov [bx],dl             ; save it
   609 0000030D 85C0                    	test ax, ax
   610 0000030F E0F2                    	loopne gls_divloop	; loop until complete
   611                                  
   612                                  gls_2:
   613 00000311 BA[0000]                	mov dx, tbuff		; ds:dx -> string to print
   614 00000314 B90900                  	mov cx, tbuff.size	; # bytes to print
   615 00000317 BB0100                      mov bx,STDOUT           ; write to standard output device
   616 0000031A B440                        mov ah,40h              ; write to device
   617 0000031C CD21                        int 21h
   618                                  
   619                                  gls_ret:
   620 0000031E C3                          ret
   621                                  give_load_size  ENDP
   622                                  
   623                                  %IFNDEF JUNIOR
   624                                  
   625                                  ;*****************************
   626                                  ;* MAP_EMS_PAGE              *
   627                                  ;*****************************
   628                                  
   629                                  ; map expanded memory page into memory
   630                                  ; upon entry al holds physical page, bx holds logical page
   631                                  ; destroys ax,dx
   632                                  
   633                                  map_ems_page    PROC
   634 0000031F 53                          push    bx              ; save critical register
   635 00000320 1E                          push    ds
   636 00000321 50                          push    ax              ; save physical page
   637 00000322 BA[ssss]                    mov dx,DGROUP
   638 00000325 8EDA                        mov ds,dx               ; make sure ds -> warplink data
   639 00000327 8B16[0000]                  mov dx,[ems_handle]
   640 0000032B B444                        mov ah,44h              ; map expanded memory page
   641 0000032D CD67                        int 67h
   642 0000032F 08E4                        or  ah,ah               ; see if error occurred
   643 00000331 7510                        jne mep_error           ; yes
   644 00000333 89D8                        mov ax,bx               ; get logical page
   645 00000335 5B                          pop bx
   646 00000336 30FF                        xor bh,bh               ; bx holds physical page
   647 00000338 D1E3                        shl bx,1                ; bx is word offset
   648 0000033A 81C3[0000]                  add bx,OFFSET ems_currmap wrt DGROUP    ; bx -> physical page entry just mapped
   649 0000033E 8907                        mov [bx],ax             ; save logical page at physical page
   650 00000340 1F                          pop ds                  ; restore critical registers
   651 00000341 5B                          pop bx
   652 00000342 C3                          ret
   653                                  
   654                                  ; EMS error occurred
   655                                  mep_error:
   656 00000343 88E1                        mov cl,ah               ; get 8 bit error code in cl
   657 00000345 B84600                      mov ax,EMS_EMM_ERR
   658 00000348 E9(0000)                    jmp NEAR PTR link_error ; transfer control to error handler
   659                                  map_ems_page    ENDP
   660                                  
   661                                  ;*****************************
   662                                  ;* RESTORE_EMS_MAP           *
   663                                  ;*****************************
   664                                  
   665                                  ; restore EMS mappings to stored values, in case of RAM disk or cache
   666                                  ; messing them up during a DOS function call
   667                                  ; destroys no registers or flags
   668                                  
   669                                  restore_ems_map PROC
   670 0000034B 9C                          pushf
   671 0000034C 50                          push    ax
   672 0000034D 1E                          push    ds
   673 0000034E B8[ssss]                    mov ax,DGROUP
   674 00000351 8ED8                        mov ds,ax               ; ensure ds -> warplink data
   675 00000353 803E[0000]00                cmp byte [is_no_ems],0         ; see if EMS was used
   676 00000358 7529                        jne rem_ret             ; no
   677                                  
   678 0000035A 52                          push    dx
   679 0000035B 51                          push    cx
   680 0000035C 53                          push    bx
   681 0000035D 8B16[0000]                  mov dx,[ems_handle]
   682 00000361 B90400                      mov cx,4
   683                                  
   684                                  rem_maploop:
   685 00000364 89CB                        mov bx,cx
   686 00000366 4B                          dec bx                  ; bx holds physical page
   687 00000367 88D8                        mov al,bl               ; ax holds physical page
   688 00000369 D1E3                        shl bx,1                ; make word offset into mapped pages array
   689 0000036B 81C3[0000]                  add bx,OFFSET ems_currmap wrt DGROUP
   690 0000036F 8B1F                        mov bx,[bx]             ; get logical page at physical page
   691 00000371 83FBFF                      cmp bx,-1               ; see if illegal page (not set yet)
   692 00000374 740A                        je  rem_done            ; yes, don't map in pages
   693 00000376 B444                        mov ah,44h              ; map expanded memory page
   694 00000378 CD67                        int 67h
   695 0000037A 08E4                        or  ah,ah               ; see if error occurred
   696 0000037C 75C5                        jne mep_error           ; yes
   697 0000037E E2E4                        loop    rem_maploop     ; map in all four pages
   698                                  
   699                                  rem_done:
   700 00000380 5B                          pop bx
   701 00000381 59                          pop cx
   702 00000382 5A                          pop dx
   703                                  
   704                                  rem_ret:
   705 00000383 1F                          pop ds
   706 00000384 58                          pop ax
   707 00000385 9D                          popf
   708 00000386 C3                          ret
   709                                  restore_ems_map ENDP
   710                                  
   711                                  ;*****************************
   712                                  ;* READ_TO_EMS               *
   713                                  ;*****************************
   714                                  
   715                                  ; read from file to EMS transfer buffer, transfer to EMS, if EMS used
   716                                  ; upon entry ds:dx-> EMS area to transfer to, bx == file handle,
   717                                  ; cx holds byte count
   718                                  ; destroys NO registers other than typical function 3fh return values
   719                                  
   720                                  read_to_ems PROC
   721 00000387 1E                          push    ds
   722 00000388 B8[ssss]                    mov ax,DGROUP
   723 0000038B 8ED8                        mov ds,ax    
   724 0000038D 803E[0000]00                cmp byte [is_no_ems],0         ; see if EMS used
   725 00000392 1F                          pop ds
   726 00000393 7407                        je  rte_ems             ; yes
   727 00000395 B43F                        mov ah,3fh
   728 00000397 CD21                        int 21h
   729 00000399 7251                        jc  rte_doserr          ; error reading file
   730 0000039B C3                          ret
   731                                  
   732                                  rte_ems:
   733 0000039C 56                          push    si              ; save critical registers
   734 0000039D 57                          push    di
   735 0000039E 06                          push    es
   736 0000039F 51                          push    cx
   737 000003A0 52                          push    dx
   738 000003A1 55                          push    bp
   739 000003A2 1E                          push    ds
   740                                  
   741 000003A3 89D7                        mov di,dx
   742 000003A5 07                          pop es                  ; es:di -> destination (EMS) block
   743 000003A6 06                          push    es              ; restore stack
   744 000003A7 31ED                        xor bp,bp               ; bp holds total bytes read
   745                                  
   746                                  rte_readloop:
   747 000003A9 51                          push    cx              ; save bytes to read
   748 000003AA 81F90040                    cmp cx,16384            ; write only 16K chunk max
   749 000003AE 7603                        jbe rte_2
   750 000003B0 B90040                      mov cx,16384
   751                                  
   752                                  rte_2:
   753 000003B3 B8[ssss]                    mov ax,DGROUP
   754 000003B6 8ED8                        mov ds,ax               ; ds -> warplink data
   755 000003B8 8E1E[0200]                  mov ds,[ems_trans_block]  ; ds -> EMS transfer area
   756 000003BC 31D2                        xor dx,dx
   757 000003BE B43F                        mov ah,3fh              ; read file (no short read error ?)
   758 000003C0 CD21                        int 21h
   759 000003C2 E886FF                      call    restore_ems_map
   760 000003C5 7225                        jc  rte_doserr          ; error reading file
   761                                  
   762 000003C7 01C5                        add bp,ax               ; update total bytes read
   763 000003C9 89C1                        mov cx,ax               ; get bytes read in cx
   764 000003CB 31F6                        xor si,si               ; ds:si -> source (transfer) block
   765                                  
   766                                  ; transfer from transfer block to EMS block
   767 000003CD D1E9                        shr cx,1                ; convert byte count to write to words
   768 000003CF F3A5                        rep movsw               ; move the string
   769 000003D1 D1D1                        rcl cx,1                ; pick up carry
   770 000003D3 F3A4                        rep movsb               ; transfer leftover byte, if any
   771                                  
   772 000003D5 59                          pop cx                  ; get bytes to read
   773 000003D6 81E90040                    sub cx,16384            ; subtract maximum read
   774 000003DA 7605                        jbe rte_ret             ; all read
   775 000003DC 3D0040                      cmp ax,16384            ; see if actual bytes read matched requested
   776 000003DF 74C8                        je  rte_readloop        ; yes, not at end of file
   777                                  
   778                                  rte_ret:
   779 000003E1 89E8                        mov ax,bp               ; get total bytes read in ax
   780 000003E3 1F                          pop ds
   781 000003E4 5D                          pop bp
   782 000003E5 5A                          pop dx
   783 000003E6 59                          pop cx
   784 000003E7 07                          pop es
   785 000003E8 5F                          pop di
   786 000003E9 5E                          pop si
   787 000003EA F8                      	clc						; clear carry for carry on file read is error checks
   788 000003EB C3                          ret
   789                                  
   790                                  rte_doserr:
   791 000003EC BA[0000]                    mov dx,OFFSET filename wrt DGROUP
   792 000003EF E9(0000)                    jmp NEAR PTR dos_error  ; error writing to file
   793                                  
   794                                  read_to_ems ENDP
   795                                  
   796                                  ;*****************************
   797                                  ;* ALLOC_EMS_TRANS           *
   798                                  ;*****************************
   799                                  
   800                                  ; allocate buffer for EMS transfer in 16K chunks for better compatibility
   801                                  ; or for XMS transfer
   802                                  ; destroys ax,bx
   803                                  
   804                                  alloc_ems_trans PROC
   805 000003F2 803E[0000]00                cmp byte [is_xms],0            ; see if XMS  used
   806 000003F7 7507                        jne aet_alloc           ; yes
   807 000003F9 803E[0000]00                cmp byte [is_no_ems],0         ; see if EMS used
   808 000003FE 7509                        jne aet_ret             ; no
   809                                  
   810                                  aet_alloc:
   811 00000400 BB0004                      mov bx,400h             ; 1K paragraphs
   812 00000403 E82DFD                      call    alloc_memory
   813 00000406 A3[0200]                    mov [ems_trans_block],ax  ; save segment of EMS transfer block
   814                                  
   815                                  aet_ret:
   816 00000409 C3                          ret
   817                                  alloc_ems_trans ENDP
   818                                  
   819                                  %ENDIF
   820                                  
   821                                  ;*****************************
   822                                  ;* SHRINK_BUFFER             *
   823                                  ;*****************************
   824                                  
   825                                  ; dynamically shrink memory allocated to file buffer
   826                                  
   827                                  ;*** this is a royal pain and may not be implemented for a while
   828                                  
   829                                  shrink_buffer   PROC
   830                                  
   831                                  ;*** temporary
   832 0000040A B80800                      mov ax,8                ; force DOS out of memory error
   833 0000040D E9(0000)                    jmp NEAR PTR dos_error
   834                                  
   835                                  ;*** code goes here
   836                                  
   837 00000410 C3                          ret
   838                                  shrink_buffer   ENDP
   839                                  
   840                                  END
