]> 4ch.mooo.com Git - 16.git/blob - src/lib/exmm/XMEM.ALL
cleanup and consolidate some mode-X code modesetting.
[16.git] / src / lib / exmm / XMEM.ALL
1 This file contains 3 files:\r
2 xmem.h   : c include file\r
3 xmem.asm : low level basic XMS acess\r
4 xmemc.c  : super easy C access via functions like fopen, fread, fwrite\r
5            xopen, xread, xwrite, xseek etc...\r
6 \r
7 FOR DOS REAL mode programs, requires HIMEM.SYS to be loaded in\r
8 config.sys.\r
9 \r
10 XMEM.H ------------- START --------------------------------------------------\r
11 #if !defined(_XMEM_H)\r
12 #define _XMEM_H\r
13 \r
14 typedef struct xms_node\r
15    {\r
16    long start, size, off;\r
17    short used;\r
18    struct xms_node *next;\r
19    }\r
20 xms_node_t;\r
21 \r
22 typedef struct\r
23    {\r
24    int handle;\r
25    unsigned long total;\r
26    unsigned long avail;\r
27    unsigned long next_off;\r
28    xms_node_t *next;\r
29    }\r
30 xms_head_t;\r
31 \r
32 #define XMSBLOCK 16384u\r
33 #define XMSBLOCKSHIFT 14\r
34 \r
35 extern void LSHL( unsigned long far *SHLnumber, unsigned short n );\r
36 \r
37 extern unsigned short XMS_available( void );\r
38 \r
39 extern unsigned short XMSblk_available( void );\r
40 \r
41 extern short XMS_alloc(unsigned short rsrvd,\r
42                        unsigned short far *size\r
43                       );\r
44 extern short XMS_dealloc(unsigned short Hdl );\r
45 extern short XMStoMem(unsigned short Handle,   // XMS handle returned by XMS_alloc()\r
46                       unsigned short blk,      // which 16k block to copy to\r
47                       unsigned short blkAdr,   // offset within 16k block\r
48                       unsigned short Bytes,    // bytes to copy\r
49                       void   far *memAdr\r
50                      );\r
51 extern short MemToXMS(unsigned short Handle,\r
52                       unsigned short blk,\r
53                       unsigned short blkAdr,\r
54                       unsigned short Bytes,\r
55                       void   far *memAdr\r
56                      );\r
57 \r
58 // call these for ease\r
59 short alloc_xms(unsigned short far *size);  // size in 16k blocks\r
60 // NOTE size is changed to the amount block size was altered by!\r
61 // normaly this is zero\r
62 \r
63 short xms_to_mem(unsigned short handle, void far *p, unsigned long off, unsigned short n);\r
64 short mem_to_xms(unsigned short handle, void far *p, unsigned long off, unsigned short n);\r
65 void deinit_xms(void);\r
66 short init_xms(unsigned short min_blocks);\r
67 void qfree_xms(xms_node_t *node);\r
68 xms_node_t *qalloc_xms(unsigned long size);\r
69 xms_node_t *xms_open(char *file);\r
70 short xms_read(void far *buffer, unsigned short n, xms_node_t *node);\r
71 short xms_write(void far *buffer, unsigned short n, xms_node_t *node);\r
72 long xms_tell(xms_node_t *node);\r
73 short xms_seek(xms_node_t *node, long off, short whence);\r
74 void xms_close(xms_node_t *node);\r
75 \r
76 extern xms_head_t xms_head;\r
77 \r
78 #endif\r
79 /* ---------------------------------- end of file --------------------- */\r
80 \r
81 XMEM.H ------------- END --------------------------------------------------\r
82 \r
83 xmem.asm --------------------- START --------------------------------------\r
84 ;-----------------------------------------------------------------------\r
85 ;\r
86 .MODEL MEDIUM\r
87 \r
88         EXTmemError     EQU     7\r
89         XMSmemError     EQU     8\r
90 \r
91 \r
92         ShortAdr        EQU     0\r
93         LongAdr         EQU     1\r
94 \r
95 procname        MACRO  Pnam\r
96         PUBLIC  _&Pnam&\r
97 _&Pnam&  PROC    FAR\r
98 ENDM\r
99 \r
100 endproc         MACRO  Pnam\r
101 \r
102 _&Pnam&  ENDP\r
103 \r
104 ENDM\r
105 \r
106 pwrlolvl_TEXT   SEGMENT WORD PUBLIC 'CODE'\r
107 \r
108         ASSUME  CS:pwrlolvl_TEXT, DS:pwrlolvl_TEXT, ES:pwrlolvl_TEXT\r
109 \r
110 SUBTTL  (Local Procedure) XMS_setup - find a XMS driver.\r
111 PAGE+\r
112 \r
113                 EVEN\r
114 XMSwordByte     LABEL BYTE\r
115 XMSword         DW      0\r
116 \r
117 XMSmoveSTRUC    STRUC\r
118 \r
119 Length          DW      0\r
120 LengthX         DW      0\r
121 SrcHandle       DW      0\r
122 SrcOffset       DW      0\r
123 SrcOffsetX      DW      0\r
124 DestHandle      DW      0\r
125 DestOffset      DW      0\r
126 DestOffsetX     DW      0\r
127 \r
128 XMSmoveSTRUC    ENDS\r
129 \r
130 XMSmainGET      XMSmoveSTRUC  <>\r
131 XMSmainPUT      XMSmoveSTRUC  <>\r
132 XMSwordGET      XMSmoveSTRUC  <2,,,,,,OFFSET XMSword>\r
133 XMSwordPUT      XMSmoveSTRUC  <2,,,OFFSET XMSword>\r
134 \r
135 XMSfunctAdr     DW      0, 0\r
136 \r
137 ; Don't try to call this from your programs\r
138 \r
139 XMS_setup               PROC NEAR\r
140 \r
141         PUSH    DS\r
142         PUSH    ES\r
143         PUSH    BX\r
144 \r
145         MOV     AX,CS                   ; Set Data segment to the code segment.\r
146         MOV     DS,AX                   ;\r
147         MOV     [XMSwordGET.DestOffsetX],AX  ; Set up the move data structures.\r
148         MOV     [XMSwordPUT.SrcOffsetX],AX   ;\r
149 \r
150         MOV     AX,4300H                ; See if a XMS Driver Exists.\r
151         INT     2FH                     ;\r
152         CMP     AL,80H                  ;\r
153         MOV     AX,0                    ;\r
154         JNE     XMS_setup01             ; Return 0 if not.\r
155 \r
156         MOV     AX,4310H                ; If so, set the driver's function\r
157         INT     2FH                     ;  address.\r
158         MOV     [XMSfunctAdr],BX        ;\r
159         MOV     [XMSfunctAdr+2],ES      ;\r
160 \r
161         MOV     AX,1                    ; Return 1.\r
162 \r
163   XMS_setup01:\r
164         POP     BX\r
165         POP     ES\r
166         POP     DS\r
167 \r
168         RET\r
169 \r
170 XMS_setup               ENDP\r
171 \r
172 SUBTTL  LSHL - Shift an unsigned long left\r
173 PAGE+\r
174 \r
175  ;****************************************************************************\r
176  ;* \r
177  ;* Shift an unsigned long integer left n number of bits.\r
178  ;*\r
179  ;****************************************************************************\r
180 \r
181  ;\r
182  ; Stack frame definition for void LSHL( unsigned long *SHLnumber, unsigned n );\r
183  ;\r
184 \r
185 LSHLparms STRUC\r
186 \r
187         DW      0, 0\r
188         DW      0\r
189 SHLadr   DD      ?\r
190 SHLn     DW      ?\r
191 \r
192 LSHLparms ENDS\r
193 \r
194 procname  LSHL\r
195 \r
196         PUSH    BP\r
197         MOV     BP,SP\r
198 \r
199         PUSH    BX\r
200         PUSH    CX\r
201         PUSH    DX\r
202 \r
203         PUSH    DS\r
204         LDS     BX,SHLadr[BP]\r
205         MOV     CX,SHLn[BP]\r
206 \r
207         MOV     AX,[BX]                 ; Get the long integer.\r
208         MOV     DX,[BX+2]               ; \r
209 \r
210  LSHL_01:\r
211         SHL     AX,1                    ; Do the long shift.\r
212         RCL     DX,1                    ; \r
213         LOOP    LSHL_01                 ; \r
214 \r
215         MOV     [BX],AX                 ; Replace the addressed number.\r
216         MOV     [BX+2],DX               ; \r
217 \r
218         POP     DS\r
219         POP     DX\r
220         POP     CX\r
221         POP     BX\r
222 \r
223         POP     BP\r
224         RET                             ; Exit\r
225 \r
226 endproc   LSHL\r
227 \r
228 \r
229 SUBTTL  Extended Memory - Stack template for EXTget, EXTput\r
230 PAGE+\r
231 \r
232 EXTgpparms STRUC\r
233 \r
234         DW      0, 0\r
235         DW      0\r
236 extgpBase    DW      ?\r
237 extgpblk     DW      ?\r
238 extgpblkAdr  DW      ?\r
239 extgpBytes   DW      ?\r
240 extgpmemAdr  DW      ?\r
241              DW      ?\r
242 \r
243 EXTgpparms ENDS\r
244 \r
245 \r
246 \r
247 SUBTTL  Extended Memory - XMS - Return total XMS memory.\r
248 PAGE+\r
249 \r
250  ; Use this function to detect wether or not XMS driver installed\r
251  ;\r
252  ; Stack frame definition for unsigned XMS_available( void );\r
253  ;\r
254  ;  The total XMS memory available (in 16k blocks) is returned.\r
255  ;\r
256 procname  XMS_available\r
257 \r
258         PUSH    BX\r
259         PUSH    CX\r
260         PUSH    DX\r
261 \r
262         CALL    XMS_setup               ; Ensure XMS memory is set.\r
263         TEST    AX,AX                   ;\r
264         JZ      XMS_available01         ; Return zero if not.\r
265 \r
266         MOV     AH,08H                  ; Set the size function code.\r
267         CALL    DWORD PTR CS:[XMSfunctAdr] ; Get the size.\r
268         TEST    AX,AX                   ;\r
269         JZ      XMS_available01         ;\r
270 \r
271         MOV     AX,DX                   ; Set available Kbytes.\r
272         SUB     AX,64                   ; Subtract out the HMA (HIMEM.SYS bug).\r
273         JNC     XMS_available01         ;\r
274         XOR     AX,AX                   ; Set zero if underflow.\r
275 \r
276   XMS_available01:\r
277         MOV     CL,4                    ; Divide Kbytes by 16 for blocks.\r
278         SHR     AX,CL                   ;\r
279 \r
280         POP     DX\r
281         POP     CX\r
282         POP     BX\r
283 \r
284         RET                             ; Exit\r
285 \r
286 endproc   XMS_available\r
287 \r
288 SUBTTL  Extended Memory - XMS - Return largest block XMS mem.\r
289 PAGE+\r
290 \r
291  ;\r
292  ; Stack frame definition for unsigned XMSblk_available( void );\r
293  ;\r
294  ;  The size of the largest block of XMS memory available,\r
295  ;  (in 16Kbyte blocks) is returned.\r
296  ;\r
297 procname  XMSblk_available\r
298 \r
299         PUSH    BX\r
300         PUSH    CX\r
301         PUSH    DX\r
302 \r
303         CALL    XMS_setup               ; Ensure XMS memory is set.\r
304         TEST    AX,AX                   ;\r
305         JZ      XMSblk_available01      ; Return zero if not.\r
306 \r
307         MOV     AH,08H                  ; Set the size function code.\r
308         CALL    DWORD PTR CS:[XMSfunctAdr] ; Get the size.\r
309         TEST    AX,AX                   ;\r
310         JZ      XMSblk_available01      ;\r
311 \r
312         SUB     DX,64                   ; Subtract out the HMA (HIMEM.SYS bug).\r
313         JNC     XMSblk_available0X      ;\r
314         XOR     DX,DX                   ; Set zero if underflow.\r
315 \r
316  XMSblk_available0X:\r
317         CMP     AX,DX                   ;\r
318         JBE     XMSblk_available01      ;\r
319         MOV     AX,DX                   ; Set available Kbytes.\r
320 \r
321   XMSblk_available01:\r
322         MOV     CL,4                    ; Divide Kbytes by 16 for blocks.\r
323         SHR     AX,CL                   ;\r
324 \r
325         POP     DX\r
326         POP     CX\r
327         POP     BX\r
328 \r
329         RET                             ; Exit\r
330 \r
331 endproc   XMSblk_available\r
332 \r
333 SUBTTL  Extended Memory - XMS De-allocate a memory block.\r
334 PAGE+\r
335 \r
336  ;\r
337  ; Stack frame definition for int XMS_dealloc( int Hdl );\r
338  ;\r
339  ; Zero is returned if the operation fails, non-zero if success.\r
340  ;\r
341  ; its really important to do this, only other way to recover\r
342  ; XMS blocks is to re-boot\r
343 \r
344 XMSdealparms STRUC\r
345 \r
346         DW      0, 0\r
347         DW      0\r
348 xmsdealHdl  DW      ?\r
349 \r
350 XMSdealparms ENDS\r
351 \r
352 \r
353 procname  XMS_dealloc\r
354 \r
355         PUSH    BP\r
356         MOV     BP,SP\r
357 \r
358         PUSH    BX\r
359         PUSH    DX\r
360 \r
361 ;        CALL    XMS_setup               ; Ensure XMS memory is set.\r
362 ;        TEST    AX,AX                   ;\r
363 ;        JZ      XMS_dealloc01           ; Return zero if not.\r
364 \r
365         MOV     DX,xmsdealHdl[BP]       ; Get the handle to de-allocate.\r
366         MOV     AH,0AH                  ;\r
367 \r
368         CALL    DWORD PTR CS:[XMSfunctAdr] ; De-allocate it.\r
369 \r
370   XMS_dealloc01:\r
371         POP     DX\r
372         POP     BX\r
373 \r
374         POP     BP\r
375         RET                             ; Exit\r
376 \r
377 endproc   XMS_dealloc\r
378 \r
379 SUBTTL  Extended Memory - XMS Allocate a memory block.\r
380 PAGE+\r
381 \r
382  ;\r
383  ; Stack frame definition for int XMS_alloc( unsigned rsrvd, *size );\r
384  ;\r
385  ;     rsrved and size are in 16K byte blocks.\r
386  ;     rsrved is mem set aside for EMS, generaly zero\r
387  ;\r
388  ;  Zero is returned if the operation fails.\r
389  ;  Block (XMS) handle is returned if success.\r
390  ;\r
391  ;  size - is reduced by the amount of XMS memory actually allocated.\r
392  ;\r
393 \r
394 XMSalparms STRUC\r
395 \r
396         DW      0, 0\r
397         DW      0\r
398 xmsalrsrvd DW      ?\r
399 xmsalsize  DD      ?\r
400 \r
401 XMSalparms ENDS\r
402 \r
403 procname  XMS_alloc\r
404 \r
405         PUSH    BP\r
406         MOV     BP,SP\r
407 \r
408         PUSH    BX\r
409         PUSH    CX\r
410         PUSH    DX\r
411         PUSH    DI\r
412         PUSH    ES\r
413         PUSH    DS\r
414 \r
415         MOV     AX,CS                   ; Set the data segment to the code\r
416         MOV     DS,AX                   ;  segment.\r
417 \r
418         MOV     CX,4                    ;\r
419         ADD     xmsalrsrvd[BP],CX       ; Subtract out the HMA (HIMEM.SYS bug).\r
420         SHL     xmsalrsrvd[BP],CL       ; Convert reserved blocks to K-bytes.\r
421 \r
422         LES     DI,xmsalsize[BP]        ; Load size address.\r
423         XOR     AX,AX                   ;\r
424         MOV     BX,ES:[DI]              ; Get the requested size in blocks.\r
425 \r
426         TEST    BX,0F000H               ; Check for more than 64 Megabytes.\r
427         JZ      XMS_alloc01             ;\r
428         MOV     BX,00FFFH               ;\r
429 \r
430   XMS_alloc01:\r
431         MOV     CL,4                    ;\r
432         SHL     BX,CL                   ; Convert to K-Bytes.\r
433         MOV     CX,BX                   ; In CX.\r
434         JZ      XMS_alloc05             ; Return zero if no size requested.\r
435 \r
436 ;        CALL    XMS_setup               ; Ensure XMS memory is set.\r
437 ;        TEST    AX,AX                   ;\r
438 ;        JZ      XMS_alloc05             ; Return zero if not.\r
439 \r
440         XOR     BX,BX                   ;\r
441         MOV     AH,08H                  ; Set to Query Free XMS Memory.\r
442         CALL    DWORD PTR [XMSfunctAdr] ;\r
443 \r
444         SUB     DX,xmsalrsrvd[BP]       ; Subtract out reserved blocks.\r
445         JB      XMS_alloc03             ; Ensure no borrow.\r
446         CMP     AX,DX                   ;\r
447         JBE     XMS_alloc02             ;\r
448         MOV     AX,DX                   ;\r
449 \r
450   XMS_alloc02:\r
451         MOV     DX,AX                   ;\r
452         CMP     AX,68                   ; Ensure enough memory to allocate.\r
453 \r
454   XMS_alloc03:\r
455         MOV     AX,0                    ;\r
456         JB      XMS_alloc05             ; Exit if not.\r
457 \r
458         CMP     BL,80H                  ; Check for errors.\r
459         JE      XMS_alloc05             ;\r
460         CMP     BL,81H                  ;\r
461         JE      XMS_alloc05             ;\r
462 \r
463         CMP     CX,DX                   ; Check actual against requested size.\r
464         JBE     XMS_alloc04             ;\r
465         MOV     CX,DX                   ; Set if actual < requested.\r
466 \r
467   XMS_alloc04:\r
468         MOV     DX,CX                   ; Set requested size.\r
469         MOV     AH,09H                  ;\r
470         CALL    DWORD PTR [XMSfunctAdr] ; Allocate it.\r
471         DEC     AX                      ; Check for errors.\r
472         MOV     AX,0                    ;\r
473         JNZ     XMS_alloc05             ;\r
474 \r
475 \r
476         MOV     AX,CX                   ; Convert allocated size in KBytes\r
477         MOV     CL,4                    ; to allocated blocks.\r
478         SHR     AX,CL                   ;\r
479 \r
480         SUB     ES:[DI],AX              ; Subtract the blocks allocated.\r
481         MOV     AX,DX                   ; Set to return the handle.\r
482 \r
483   XMS_alloc05:\r
484         POP     DS\r
485         POP     ES\r
486         POP     DI\r
487         POP     DX\r
488         POP     CX\r
489         POP     BX\r
490 \r
491         POP     BP\r
492         RET                             ; Exit\r
493 \r
494 endproc  XMS_alloc\r
495 \r
496 SUBTTL  Extended Memory - XMS get, put Stack Frame definition\r
497 PAGE+\r
498 \r
499 \r
500 XMSgpparms STRUC\r
501 \r
502         DW      0, 0\r
503         DW      0\r
504 xmsgpHdl     DW      ?\r
505 xmsgpblk     DW      ?\r
506 xmsgpblkAdr  DW      ?\r
507 xmsgpBytes   DW      ?\r
508 xmsgpmemAdr  DD      ?\r
509 \r
510 XMSgpparms ENDS\r
511 \r
512 SUBTTL  Extended Memory - XMStoMem\r
513 PAGE+\r
514 \r
515 \r
516  ;\r
517  ; Stack frame definition for int XMStoMem( unsigned Handle,\r
518  ;                                          unsigned blk,\r
519  ;                                          unsigned blkAdr,\r
520  ;                                          unsigned Bytes,\r
521  ;                                          char     *memAdr\r
522  ;                                        );\r
523  ;\r
524  ;  XMSmemError is returned if the operation fails, Zero if success.\r
525  ;\r
526 \r
527 procname  XMStoMem\r
528 \r
529         PUSH    BP\r
530         MOV     BP,SP\r
531 \r
532         PUSH    BX\r
533         PUSH    CX\r
534         PUSH    DX\r
535         PUSH    SI\r
536         PUSH    DI\r
537         PUSH    ES\r
538         PUSH    DS\r
539 \r
540         MOV     AX,CS                   ; Set Data Segment to Code Segment.\r
541         MOV     DS,AX                   ;\r
542 \r
543         MOV     CX,xmsgpBytes[BP]       ; Get the number of bytes to transfer.\r
544         LES     BX,xmsgpmemAdr[BP]      ; Get the memory address.\r
545         MOV     DX,xmsgpHdl[BP]         ; Get the XMS handle.\r
546         MOV     [XMSmainGET.SrcHandle],DX ; Set it in the move structures.\r
547         MOV     [XMSwordGET.SrcHandle],DX ;\r
548 \r
549         XOR     DX,DX                   ;\r
550         MOV     DI,xmsgpblk[BP]         ; Get the block number.\r
551         SHR     DI,1                    ; Form the 32 bit XMS address in\r
552         RCR     DX,1                    ;  DI:DX.\r
553         SHR     DI,1                    ;\r
554         RCR     DX,1                    ;\r
555         ADD     DX,xmsgpblkAdr[BP]      ;\r
556 \r
557         TEST    CX,1                    ; Check for an odd number of bytes\r
558         JZ      XMStoMem02              ;  to transfer.\r
559 \r
560         DEC     CX                      ; Decrement to an even number of bytes.\r
561 \r
562         TEST    DX,1                    ; Check for an odd XMS address.\r
563         JZ      XMStoMem01              ;\r
564 \r
565                                         ; XMS address is odd.\r
566                                         ; -------------------\r
567         DEC     DX                      ;\r
568         MOV     [XMSwordGET.SrcOffset],DX   ; Set the XMS address.\r
569         MOV     [XMSwordGET.SrcOffsetX],DI  ;\r
570 \r
571         MOV     AH,0BH                  ; Set the XMS move, function code.\r
572         MOV     SI,OFFSET XMSwordGET    ; Set address of the move structure.\r
573 \r
574         PUSH    BX                      ;\r
575         CALL    DWORD PTR [XMSfunctAdr] ; Call the XMS handler.\r
576         POP     BX                      ;\r
577         DEC     AX                      ; Check for errors.\r
578         JNZ     XMStoMem03              ; Error out if error.\r
579 \r
580         MOV     AX,[XMSword]            ; Get the moved word.\r
581 \r
582         MOV     ES:[BX],AH              ; Move the odd byte to memory.\r
583 \r
584         INC     BX                      ; Reset the memory address.\r
585         ADD     DX,2                    ; And the XMS address.\r
586 \r
587         JMP     XMStoMem02              ; Move the block.\r
588 \r
589 \r
590   XMStoMem01:\r
591                                         ; XMS address is even.\r
592                                         ; --------------------\r
593         ADD     DX,CX                   ;\r
594         MOV     [XMSwordGET.SrcOffset],DX   ; Set the XMS address.\r
595         SUB     DX,CX                       ;\r
596         MOV     [XMSwordGET.SrcOffsetX],DI  ;\r
597 \r
598         MOV     AH,0BH                  ; Set the XMS move, function code.\r
599         MOV     SI,OFFSET XMSwordGET    ; Set address of the move structure.\r
600 \r
601         PUSH    BX                      ;\r
602         CALL    DWORD PTR [XMSfunctAdr] ; Call the XMS handler.\r
603         POP     BX                      ;\r
604         DEC     AX                      ; Check for errors.\r
605         JNZ     XMStoMem03              ; Error out if error.\r
606 \r
607         MOV     AX,[XMSword]            ; Get the moved word.\r
608 \r
609         XCHG    DI,CX                   ;\r
610         MOV     ES:[BX+DI],AL           ; Move the odd byte to memory.\r
611         XCHG    DI,CX                   ;\r
612 \r
613   XMStoMem02:\r
614         JCXZ    XMStoMem04              ; Avoid a zero byte move.\r
615 \r
616         MOV     XMSmainGET.Length,CX    ; Set length for the move.\r
617 \r
618         MOV     XMSmainGET.DestOffset,BX   ; Set Memory address.\r
619         MOV     XMSmainGET.DestOffsetX,ES  ;\r
620 \r
621         MOV     XMSmainGET.SrcOffset,DX    ; Set XMS address.\r
622         MOV     XMSmainGET.SrcOffsetX,DI   ;\r
623 \r
624         MOV     AH,0BH                  ; Set the XMS move, function code.\r
625         MOV     SI,OFFSET XMSmainGET    ; Set address of the move structure.\r
626 \r
627         CALL    DWORD PTR [XMSfunctAdr] ; Call the XMS handler.\r
628         DEC     AX                      ; Check for errors.\r
629         JZ      XMStoMem05\r
630 \r
631   XMStoMem03:\r
632         MOV     AX,XMSmemError          ; Set error code if error.\r
633         JMP     XMStoMem05              ;\r
634 \r
635   XMStoMem04:\r
636         XOR     AX,AX                   ;\r
637 \r
638   XMStoMem05:\r
639         POP     DS\r
640         POP     ES\r
641         POP     DI\r
642         POP     SI\r
643         POP     DX\r
644         POP     CX\r
645         POP     BX\r
646 \r
647         POP     BP\r
648         RET                             ; Exit\r
649 \r
650 endproc  XMStoMem\r
651 \r
652 SUBTTL  Extended Memory - MemToXMS\r
653 PAGE+\r
654 \r
655 \r
656  ;\r
657  ; Stack frame definition for int MemToXMS( unsigned Handle,\r
658  ;                                        unsigned blk,\r
659  ;                                        unsigned blkAdr,\r
660  ;                                        unsigned Bytes,\r
661  ;                                        char     *memAdr\r
662  ;                                       );\r
663  ;\r
664  ;  XMSmemError is returned if the operation fails, Zero if success.\r
665  ;\r
666 \r
667 procname  MemToXMS\r
668 \r
669         PUSH    BP\r
670         MOV     BP,SP\r
671 \r
672         PUSH    BX\r
673         PUSH    CX\r
674         PUSH    DX\r
675         PUSH    SI\r
676         PUSH    DI\r
677         PUSH    ES\r
678         PUSH    DS\r
679 \r
680         MOV     AX,CS                   ;\r
681         MOV     DS,AX                   ;\r
682 \r
683         MOV     CX,xmsgpBytes[BP]       ; Get the number of bytes to transfer.\r
684         LES     BX,xmsgpmemAdr[BP]      ; Get the memory address.\r
685         MOV     DX,xmsgpHdl[BP]         ; Get the XMS handle.\r
686         MOV     [XMSmainPUT.DestHandle],DX ; Set it in the move structures.\r
687         MOV     [XMSwordPUT.DestHandle],DX ;\r
688         MOV     [XMSwordGET.SrcHandle],DX  ;\r
689 \r
690         XOR     DX,DX                   ;\r
691         MOV     DI,xmsgpblk[BP]         ; Get the block number.\r
692         SHR     DI,1                    ; Form the 32 bit XMS address in\r
693         RCR     DX,1                    ;  DI:DX.\r
694         SHR     DI,1                    ;\r
695         RCR     DX,1                    ;\r
696         ADD     DX,xmsgpblkAdr[BP]      ;\r
697 \r
698         TEST    CX,1                    ; Check for an odd number of bytes\r
699         JZ      MemToXMS02              ;  to transfer.\r
700 \r
701         DEC     CX                      ; Decrement to an even number of bytes.\r
702 \r
703         TEST    DX,1                    ; Check for an odd XMS address.\r
704         JZ      MemToXMS01              ;\r
705 \r
706                                         ; XMS address is odd.\r
707                                         ; -------------------\r
708         DEC     DX                      ;\r
709         MOV     [XMSwordGET.SrcOffset],DX   ; Set the XMS address.\r
710         MOV     [XMSwordGET.SrcOffsetX],DI  ;\r
711         MOV     [XMSwordPUT.DestOffset],DX  ;\r
712         MOV     [XMSwordPUT.DestOffsetX],DI ;\r
713 \r
714         MOV     AH,0BH                  ; Set the XMS move, function code.\r
715         MOV     SI,OFFSET XMSwordGET    ; Set address of the move structure.\r
716 \r
717         PUSH    BX                      ;\r
718         CALL    DWORD PTR [XMSfunctAdr] ; Call the XMS handler.\r
719         POP     BX                      ;\r
720         DEC     AX                      ; Check for errors.\r
721         JNZ     MemToXMS03              ; Error out if error.\r
722 \r
723         MOV     AH,ES:[BX]              ; Get the odd memory byte.\r
724 \r
725         MOV     [XMSwordByte+1],AH      ; Put it in the moved word.\r
726 \r
727         MOV     AH,0BH                  ; Set the XMS move, function code.\r
728         MOV     SI,OFFSET XMSwordPUT    ; Set address of the move structure.\r
729 \r
730         PUSH    BX                      ;\r
731         CALL    DWORD PTR [XMSfunctAdr] ; Call the XMS handler.\r
732         POP     BX                      ;\r
733         DEC     AX                      ; Check for errors.\r
734         JNZ     MemToXMS03              ; Error out if error.\r
735 \r
736         INC     BX                      ; Reset the memory address.\r
737         ADD     DX,2                    ; And the XMS address.\r
738 \r
739         JMP     MemToXMS02              ; Move the block.\r
740 \r
741   MemToXMS01:\r
742                                         ; XMS address is even.\r
743                                         ; --------------------\r
744         ADD     DX,CX                   ;\r
745         MOV     [XMSwordGET.SrcOffset],DX   ; Set the XMS address.\r
746         MOV     [XMSwordPUT.DestOffset],DX  ;\r
747         SUB     DX,CX                       ;\r
748         MOV     [XMSwordGET.SrcOffsetX],DI  ;\r
749         MOV     [XMSwordPUT.DestOffsetX],DI ;\r
750 \r
751         MOV     AH,0BH                  ; Set the XMS move, function code.\r
752         MOV     SI,OFFSET XMSwordGET    ; Set address of the move structure.\r
753 \r
754         PUSH    BX                      ;\r
755         CALL    DWORD PTR [XMSfunctAdr] ; Call the XMS handler.\r
756         POP     BX                      ;\r
757         DEC     AX                      ; Check for errors.\r
758         JNZ     MemToXMS03              ; Error out if error.\r
759 \r
760         XCHG    DI,CX                   ;\r
761         MOV     AL,ES:[BX+DI]           ; Get the odd memory byte.\r
762         XCHG    DI,CX                   ;\r
763 \r
764         MOV     [XMSwordByte],AL        ; Set the moved word.\r
765 \r
766         MOV     AH,0BH                  ; Set the XMS move, function code.\r
767         MOV     SI,OFFSET XMSwordPUT    ; Set address of the move structure.\r
768 \r
769         PUSH    BX                      ;\r
770         CALL    DWORD PTR [XMSfunctAdr] ; Call the XMS handler.\r
771         POP     BX                      ;\r
772         DEC     AX                      ; Check for errors.\r
773         JNZ     MemToXMS03              ; Error out if error.\r
774 \r
775   MemToXMS02:\r
776         JCXZ    MemToXMS04              ; Avoid a zero byte move.\r
777 \r
778         MOV     XMSmainPUT.Length,CX    ; Set length for the move.\r
779 \r
780         MOV     XMSmainPUT.SrcOffset,BX    ; Set Memory address.\r
781         MOV     XMSmainPUT.SrcOffsetX,ES   ;\r
782 \r
783         MOV     XMSmainPUT.DestOffset,DX   ; Set XMS address.\r
784         MOV     XMSmainPUT.DestOffsetX,DI  ;\r
785 \r
786         MOV     AH,0BH                  ; Set the XMS move, function code.\r
787         MOV     SI,OFFSET XMSmainPUT    ; Set address of the move structure.\r
788 \r
789         CALL    DWORD PTR [XMSfunctAdr] ; Call the XMS handler.\r
790         DEC     AX                      ; Check for errors.\r
791         JZ      MemToXMS05\r
792 \r
793   MemToXMS03:\r
794         MOV     AX,XMSmemError          ; Set error code if error.\r
795         JMP     MemToXMS05              ;\r
796 \r
797   MemToXMS04:\r
798         XOR     AX,AX                   ;\r
799 \r
800   MemToXMS05:\r
801         POP     DS\r
802         POP     ES\r
803         POP     DI\r
804         POP     SI\r
805         POP     DX\r
806         POP     CX\r
807         POP     BX\r
808 \r
809         POP     BP\r
810         RET                             ; Exit\r
811 \r
812 endproc  MemToXMS\r
813 \r
814 \r
815 SUBTTL  Last Page\r
816 PAGE+\r
817 \r
818 pwrlolvl_TEXT   ENDS\r
819 \r
820         END\r
821 \r
822 \r
823 xmem.asm --------------------- END --------------------------------------\r
824 \r
825 xmemc.c ---------------------------- START -------------------------\r
826 \r
827 /*\r
828 \r
829    Copyright 1994 Alec Russell, ALL rights reserved\r
830         Permission granted to use as you wish.\r
831 \r
832    Slightly higher level xms calls than xmem.asm\r
833 \r
834 */\r
835 \r
836 #include <stdio.h>\r
837 #include <io.h>\r
838 #include <string.h>\r
839 #include <malloc.h>\r
840 \r
841 #include <xmem.h>\r
842 \r
843 xms_head_t xms_head={0};  // set handle to zero\r
844 \r
845 \r
846 /* ---------------------- alloc_xms() ----------------- February 19,1994 */\r
847 short alloc_xms(unsigned short far *size)  // size in 16k blocks\r
848 {\r
849    return(XMS_alloc(0, size));\r
850 }\r
851 \r
852 /* ---------------------- xms_to_mem() ---------------- February 19,1994 */\r
853 short xms_to_mem(unsigned short handle, void far *p, unsigned long off, unsigned short n)\r
854 {\r
855    unsigned short block, boff;\r
856 \r
857    block=off >> XMSBLOCKSHIFT;\r
858    boff=off - (block << XMSBLOCKSHIFT);\r
859 \r
860    return(XMStoMem(handle, block, boff, n, p));\r
861 }\r
862 \r
863 /* ---------------------- mem_to_xms() ---------------- February 19,1994 */\r
864 short mem_to_xms(unsigned short handle, void far *p, unsigned long off, unsigned short n)\r
865 {\r
866    unsigned short block, boff;\r
867 \r
868    block=off >> XMSBLOCKSHIFT;\r
869    boff=off - (block << XMSBLOCKSHIFT);\r
870 \r
871    return(MemToXMS(handle, block, boff, n, p));\r
872 }\r
873 \r
874 /* ---------------------- qalloc_xms() -------------------- March 8,1994 */\r
875 xms_node_t *qalloc_xms(unsigned long size)\r
876 {\r
877    xms_node_t *node=NULL;\r
878    xms_node_t *t1;\r
879 \r
880    if ( size <= xms_head.avail )\r
881       {\r
882       // look for existing node\r
883       t1=xms_head.next;\r
884       while ( t1 )\r
885          {\r
886          if ( t1->used == 0 && t1->size >= size )\r
887             {\r
888             t1->off=0;\r
889             t1->used=1;\r
890             node=t1;\r
891             break;\r
892             }\r
893          else\r
894             t1=t1->next;\r
895          }\r
896 \r
897       if ( node == NULL ) // didn't find existing node\r
898          {\r
899          node=malloc(sizeof(xms_node_t));\r
900          if ( node )\r
901             {\r
902             node->off=0;\r
903             node->used=1;\r
904             node->size=size;\r
905             node->next=NULL;\r
906             node->start=xms_head.next_off;\r
907             xms_head.avail-=size;\r
908             xms_head.next_off+=size;\r
909             if ( xms_head.next == NULL )\r
910                {\r
911                xms_head.next=node;\r
912                }\r
913             else\r
914                {\r
915                t1=xms_head.next;\r
916                while ( t1->next )\r
917                   t1=t1->next;\r
918                t1->next=node;\r
919                }\r
920             }\r
921          else\r
922             pr2("out of near mem in qalloc_xms");\r
923          }\r
924       }\r
925    else\r
926       pr2("out of xms mem in qalloc size %lu avail %lu", size, xms_head.avail);\r
927 \r
928    return(node);\r
929 }\r
930 \r
931 /* ---------------------- qfree_xms() --------------------- March 8,1994 */\r
932 void qfree_xms(xms_node_t *node)\r
933 {\r
934    xms_node_t *t1;\r
935 \r
936    if ( xms_head.next )\r
937       {\r
938       t1=xms_head.next;\r
939       while ( t1 != node && t1 )\r
940          t1=t1->next;\r
941 \r
942       if ( t1 )\r
943          {\r
944          t1->used=0;\r
945          }\r
946       else\r
947          pr2("ERROR didn't find node qfree");\r
948       }\r
949    else\r
950       {\r
951       pr2("ATTEMPTED to qfree empty list");\r
952       }\r
953 }\r
954 \r
955 /* ---------------------- xms_open() ---------------------- March 8,1994 */\r
956 xms_node_t *xms_open(char *file)\r
957 {\r
958    int i;\r
959    xms_node_t *node=NULL;\r
960    FILE *fp;\r
961    char *buffer;\r
962    unsigned long off;\r
963 \r
964    fp=fopen(file, "rb");\r
965    if ( fp )\r
966       {\r
967       node=qalloc_xms(filelength(fileno(fp)));\r
968       if ( node )\r
969          {\r
970          buffer=malloc(4096);\r
971          if ( buffer )\r
972             {\r
973             off=0l;\r
974             while ( (i=fread(buffer, 1, 4096, fp)) )\r
975                {\r
976                mem_to_xms(xms_head.handle, (char far *)buffer, off+node->start, i);\r
977                off+=i;\r
978                }\r
979 \r
980             free(buffer);\r
981             }\r
982          else\r
983             pr2("out of mem in xms_open 1");\r
984          }\r
985 \r
986       fclose(fp);\r
987       }\r
988    else\r
989       pr2("ERROR opening %s in xms_open", file);\r
990 \r
991    return(node);\r
992 }\r
993 \r
994 /* ---------------------- xms_read() ---------------------- March 8,1994 */\r
995 short xms_read(void far *buffer, unsigned short n, xms_node_t *node)\r
996 {\r
997 \r
998    if ( node->off >= node->size )\r
999       return 0;\r
1000 \r
1001    if ( n+node->off > node->size )\r
1002       n=node->size - node->off;\r
1003 \r
1004    xms_to_mem(xms_head.handle, buffer, node->start+node->off, n);\r
1005    node->off+=n;\r
1006 \r
1007    return(n);\r
1008 }\r
1009 \r
1010 /* ---------------------- xms_write() ---------------------- March 8,1994 */\r
1011 short xms_write(void far *buffer, unsigned short n, xms_node_t *node)\r
1012 {\r
1013 \r
1014    if ( node->off >= node->size )\r
1015       return 0;\r
1016 \r
1017    if ( n+node->off > node->size )\r
1018       n=node->size - node->off;\r
1019 \r
1020    mem_to_xms(xms_head.handle, buffer, node->start+node->off, n);\r
1021    node->off+=n;\r
1022 \r
1023    return(n);\r
1024 }\r
1025 \r
1026 \r
1027 /* ---------------------- xms_tell() ---------------------- March 8,1994 */\r
1028 long xms_tell(xms_node_t *node)\r
1029 {\r
1030    return node->off;\r
1031 }\r
1032 \r
1033 /* ---------------------- xms_seek() ---------------------- March 8,1994 */\r
1034 short xms_seek(xms_node_t *node, long off, short whence)\r
1035 {\r
1036    short err=0;\r
1037 \r
1038    switch ( whence )\r
1039       {\r
1040       case SEEK_SET:\r
1041          if ( off < 0l || off > node->size )\r
1042             err=1;\r
1043          else\r
1044             node->off=off;\r
1045          break;\r
1046 \r
1047       case SEEK_END:\r
1048          if ( off > 0l || (node->size + off) < 0l )\r
1049             err=1;\r
1050          else\r
1051             node->off=node->size + off;\r
1052          break;\r
1053 \r
1054       case SEEK_CUR:\r
1055          if ( node->off + off < 0l || node->off + off > node->size )\r
1056             err=1;\r
1057          else\r
1058             node->off+=off;\r
1059          break;\r
1060       }\r
1061 \r
1062    return(err);\r
1063 }\r
1064 \r
1065 /* ---------------------- xms_close() --------------------- March 8,1994 */\r
1066 void xms_close(xms_node_t *node)\r
1067 {\r
1068    qfree_xms(node);\r
1069 }\r
1070 \r
1071 /* ---------------------- init_xms() ---------------------- March 8,1994 */\r
1072 short init_xms(unsigned short min_blocks)\r
1073 {\r
1074    unsigned short blocks;\r
1075 \r
1076    blocks=XMSblk_available();\r
1077    if ( blocks >= min_blocks )\r
1078       {\r
1079       memset(&xms_head, 0, sizeof(xms_head_t));\r
1080       if ( (xms_head.handle=alloc_xms(&blocks)) )\r
1081          {\r
1082          pr2("blocks minus by = %u", blocks);\r
1083          min_blocks-=blocks;\r
1084          xms_head.avail=xms_head.total=(unsigned long)min_blocks*XMSBLOCK;\r
1085          blocks=min_blocks;\r
1086          }\r
1087       else\r
1088          blocks=0;\r
1089       }\r
1090    else\r
1091       blocks=0;\r
1092 \r
1093    return(blocks);\r
1094 }\r
1095 \r
1096 /* ---------------------- deinit_xms() -------------------- March 8,1994 */\r
1097 void deinit_xms(void)\r
1098 {\r
1099    xms_node_t *t1, *t2;\r
1100 \r
1101    if ( xms_head.handle )\r
1102       {\r
1103       XMS_dealloc(xms_head.handle);\r
1104       if ( xms_head.next )\r
1105          {\r
1106          t1=xms_head.next;\r
1107          t2=t1->next;\r
1108          while ( t1 )\r
1109             {\r
1110             free(t1);\r
1111             t1=t2;\r
1112             t2=t1->next;\r
1113             }\r
1114          }\r
1115 \r
1116       memset(&xms_head, 0, sizeof(xms_head_t));\r
1117       }\r
1118 }\r
1119 /* --------------------------- end of file ------------------------- */\r
1120 \r
1121 /*\r
1122 \r
1123 Not sure how to use this?\r
1124 \r
1125 call init_xms(x) to allocate a big chunk of xms.\r
1126 x is in 'blocks' of 16Kb. Pick X big enough to buffer all the files\r
1127 you want to place in xms.\r
1128 \r
1129 call xms_open("filename); for each file to be buffered. This copies the file\r
1130 int xms.\r
1131 \r
1132 then use xms_read(), xms_write(), and xms_seek() to read the file from\r
1133 xms instead of disk.\r
1134 \r
1135 call deinit_xms() just before exit to clean up.\r
1136 \r
1137 You can also use the lower level calls directly.\r
1138 \r
1139 */\r
1140 xmemc.c ---------------------------- END -------------------------\r