.MODEL Medium
IDEAL
STACK 200h
LOCALS @@
P386

DATASEG

 RawFile DB 'PIC.RAW', 0
 PalFile DB 'PIC.PAL', 0

 Pal DB 256*3 DUP(?)

 Msg_NOEMS DB 'Sorry, EMS is required for this proggy!$'
 Msg_NotEnoughEMS DB 'Not enough EMS!$'
 Msg_PalError DB 'Cannot load PAL-File!$'
 Msg_PicError DB 'Cannot load PIC-File!$'

 EMM_Sign DB 'EMMXXXX'

 PageFrame DW ?

 MyHandle DW ?

CODESEG

 ;OUT: CF = 0 : EMS-Treiber gefunden
 ;     CF = 1 : Kein EMS vorhanden
 PROC Detect_EMS NEAR
  xor ax, ax              ; es = 0
  mov es, ax
  mov es, [es:(67h*4)+2]  ; 0:67h*4+2 = Seg-Addy den Interrupt-Handlers
  mov di, 10
  lea si, [EMM_Sign]
  mov cx, 7               ; 7 Bytes l„nge
  repe cmpsb              ; vergleiche cx bytes bei [ds:si] und [es:di]
  jcxz @@EMS_Found
 @@NO_EMS:
  stc
  ret
 @@EMS_Found:
  mov ah, 40h             ; Funktion 40h : read EMM-state
  int 67h
  or ah, ah
  jnz @@NO_EMS
  clc
  ret
 ENDP

 ;OUT: CF = 0 : Page-Frame-Segment in BX
 ;     CF = 1 : EMS-Fehler, Fehlercode in AH
 PROC EMS_GetPageFrame NEAR
  mov ah, 41h
  int 67h
  or ah, ah
  jnz @@Error
  clc
  jmp @@Done
 @@Error:
  stc
 @@Done:
  ret
 ENDP

 ;OUT: EAX = freies, allokierbares EMS in Bytes
 PROC EMS_MemAvail NEAR
  mov ah, 42h
  int 67h
  or ah, ah
  jnz @@Error
                        ; in BX steht nun die Anzahl der freien Pages
  movzx eax, bx         ; EAX = BX * 16386 = Gr”áe in Bytes
  shl eax, 14
  jmp @@Done
 @@Error:
  xor eax, eax
 @@Done:
  ret
 ENDP

 ;IN: EAX = Bytes, die zu allokieren sind
 ;OUT: DX = Handle
 PROC EMS_Alloc NEAR

  mov ebx, eax                 ;Bytes in Pages (zu 16KByte) umrechnen
  shr ebx, 14
  adc ebx, 0

  mov ah, 43h
  int 67h
  ret
 ENDP

 ;IN: DX = Handle
 PROC EMS_Free NEAR
  mov ah, 45h
  int 67h
  ret
 ENDP

 ;IN: DX = Handle
 ;    AL = Nummer der Page im EMS-Page-Frame (0-3)
 ;    BX = Nummer der Page im allokierten EMS-Speicher
 PROC EMS_SetMappings NEAR
  mov ah, 44h
  int 67h
  ret
 ENDP

 ;l„dt die Palette des RAW-Bildes von der Festplatte, und schiebt sie
 ;in die VGA
 PROC LoadRAWPalette NEAR
  mov dx, OFFSET PalFile
  mov ax, 3D00h
  int 21h
  jc @@Done

  mov bx, ax
  mov ax, 3F00h
  mov cx, 256*3
  mov dx, OFFSET Pal
  int 21h
  jc @@Done

  mov ax, 3E00h
  int 21h
  jc @@Done

  mov si, OFFSET Pal
  mov cx, 256*3
  mov dx, 3c8h
  xor al, al
  out dx, al
  inc dx
  rep outsb

 @@Done:
  ret
 ENDP

 PROC LoadRAWPicture NEAR
  mov dx, OFFSET RawFile
  mov ax, 3D00h
  int 21h
  jc @@Done

  mov bx, ax
  mov ax, 3F00h
  mov cx, 64000
  xor dx, dx
  push ds
  mov ds, [PageFrame]              ;direkt in das EMS-Page-Frame lesen
  int 21h
  pop ds
  jc @@Done

  mov ax, 3E00h
  int 21h

 @@Done:
  ret
 ENDP

 PROC ShowPic NEAR
  push ds
  mov ax, 0A000h
  mov es, ax
  xor si, si
  xor di, di
  mov cx, 64000 / 4
  mov ds, [PageFrame]
  rep movsd
  pop ds
  ret
 ENDP

Start:
 mov ax, @DATA                  ;ds mit dem Datensegment laden
 mov ds, ax

 mov ax, 13h                    ;Initialisiere Mode 13h (320x200x256)
 int 10h

 call Detect_EMS                ;check, ob EMS berhaupt verfgbar
 jc @@ERR_NoEMS

 call EMS_GetPageFrame          ;Page-Frame-Adresse holen
 mov [PageFrame], bx

 call EMS_MemAvail
 cmp eax, 64000
 jb @@ERR_NotEnoughEMS

 mov eax, 64000
 call EMS_Alloc
 mov [MyHandle], dx

 xor al, al
 xor bx, bx
 call EMS_SetMappings
 mov ax, 1
 mov bx, ax
 call EMS_SetMappings
 mov ax, 2
 mov bx, ax
 call EMS_SetMappings
 mov ax, 3
 mov bx, ax
 call EMS_SetMappings

 call LoadRAWPalette            ;Palette laden
 jc @@ERR_PAL
 call LoadRAWPicture            ;Bild laden
 jc @@ERR_PIC

                                ;so, jetzt haben wir das Bild im EMS

 call ShowPic                   ;Das Bild aus dem EMS-Page-Frame in den
                                ;Video-Speicher kopieren

 xor ax, ax                     ;Auf Tastendruck warten
 int 16h

 mov dx, [MyHandle]
 call EMS_Free

 mov ax, 3                      ;In den Textmode schalten
 int 10h

 mov ax, 4c00h                  ;Ab ins DOS
 int 21h

@@ERR_NoEMS:
 mov dx, OFFSET Msg_NOEMS
 jmp @@ERR_Exit2DOS

@@ERR_NotEnoughEMS:
 mov dx, OFFSET Msg_NotEnoughEMS
 jmp @@Err_Exit2DOS

@@ERR_PAL:
 mov dx, OFFSET Msg_PalError
 jmp @@Err_Exit2DOS

@@ERR_PIC:
 mov dx, OFFSET Msg_PicError
 jmp @@Err_Exit2DOS

@@ERR_Exit2DOS:
 mov ax, 3                      ;In den Textmode schalten
 int 10h
 mov ah, 09h                    ;Fehlermeldung ausgeben
 int 21h
 mov ax, 4c01h                  ;Zurck ins DOS
 int 21h

END Start