     1                                  
     2                                  %if 0
     3                                  
     4                                  lDOS iniload packed payload
     5                                   by C. Masloch, 2018-2020
     6                                  
     7                                  Usage of the works is permitted provided that this
     8                                  instrument is retained with the works, so that any entity
     9                                  that uses the works is notified of this instrument.
    10                                  
    11                                  DISCLAIMER: THE WORKS ARE WITHOUT WARRANTY.
    12                                  
    13                                  
    14                                  Includes one of several depackers, some of which are under
    15                                  separate usage conditions. Refer to the individual depacker
    16                                  source files for the applicable usage conditions.
    17                                  
    18                                  %endif
    19                                  
    20                                  %include "lmacros2.mac"
    21                              <1> [list -]
    34                              <1> [list -]
    21                                  
    22                                  	struc LOADSTACKVARS, -10h
    23 FFFFFFF0 ????????                lsvFirstCluster:	resd 1
    24 FFFFFFF4 ????????                lsvFATSector:		resd 1
    25 FFFFFFF8 ????                    lsvFATSeg:		resw 1
    26 FFFFFFFA ????                    lsvLoadSeg:		resw 1
    27 FFFFFFFC ????????                lsvDataStart:		resd 1
    28                                  	endstruc
    29                                  
    30                                  	struc LOADDATA, LOADSTACKVARS - 10h
    31 FFFFFFE0 ????                    ldMemoryTop:	resw 1
    32 FFFFFFE2 ????                    ldLoadTop:	resw 1
    33 FFFFFFE4 ????                    ldSectorSeg:	resw 1
    34 FFFFFFE6 ??                      ldFATType:	resb 1
    35 FFFFFFE7 ??                      ldHasLBA:	resb 1
    36 FFFFFFE8 ????                    ldClusterSize:	resw 1
    37 FFFFFFEA ????                    ldParaPerSector:resw 1
    38 FFFFFFEC ????                    ldLoadingSeg:	resw 1
    39 FFFFFFEE ????                    ldLoadUntilSeg:	resw 1
    40                                  	endstruc
    41                                  
    42                                  
    43                                  %ifndef _MAP
    44                                  %elifempty _MAP
    45                                  %else	; defined non-empty, str or non-str
    46                                  	[map all _MAP]
    47                                  %endif
    48                                  
    49                                  	defaulting
    50                                  
    51                                  	numdef DEBUG0		; use errordata to generate an error code
    52                                  	numdef DEBUG1		; dump_stack_frame after an error occurred
    53                                  	numdef DEBUG2		; dump_stack_frame before blz_depack_safe call
    54                                  	numdef DEBUG3		; dump_stack_frame at start of blz_depack_safe
    55                                  
    56                                  	numdef ALLOW_OVERLAPPING,	1	; allow overlapping src and dst
    57                                  	numdef TEST_PROGRAM,		0
    58                                  	numdef TEST_PROGRAM_DECOMPRESSED_SIZE,		0,0
    59                                  %if _TEST_PROGRAM && ! _TEST_PROGRAM_DECOMPRESSED_SIZE
    60                                   %error Test program has to learn of decompressed size.
    61                                  %endif
    62                                  	numdef TEST_PROGRESS,	0
    63                                  
    64                                  	numdef EXEC_OFFSET,	0
    65                                  	numdef EXEC_SEGMENT,	0
    66                                  	numdef IMAGE_EXE,	0
    67                                  %if ! _IMAGE_EXE && _TEST_PROGRAM
    68                                   %error Test program can only be used as EXE.
    69                                  %endif
    70                                  	numdef IMAGE_EXE_CS,	-16	; relative-segment for CS
    71                                  	numdef IMAGE_EXE_IP,	256 +64	; value for IP
    72                                  		; The next two are only used if _IMAGE_EXE_AUTO_STACK is 0.
    73                                  	numdef IMAGE_EXE_SS,	-16	; relative-segment for SS
    74                                  	numdef IMAGE_EXE_SP,	0FFFEh	; value for SP (0 underflows)
    75                                  	numdef IMAGE_EXE_AUTO_STACK,	0, 2048	; use stack behind image
    76                                  		; _IMAGE_EXE_AUTO_STACK here differs from iniload's def of
    77                                  		;  the same name. This one is only used as a flag; if non-zero,
    78                                  		;  keep the stack given to us by iniload; if zero, set up the
    79                                  		;  stack specified by _IMAGE_EXE_SS and _IMAGE_EXE_SP.
    80                                  	numdef DEVICE,			0
    81                                  	gendef DEVICE_NAME,		""
    82                                  	numdef DEVICE_ATTRIBUTE,	8000h
    83                                  	numdef DEVICE_ZERO_ENTRYPOINT,	0
    84                                  %if _DEVICE
    85                                   %ifidn _DEVICE_NAME, ""
    86                                    %error Device name must be set
    87                                   %endif
    88                                  %endif
    89                                  
    90                                  	numdef BRIEFLZ,		0
    91                                  	numdef LZ4,		0
    92                                  	numdef SNAPPY,		0
    93                                  	numdef EXODECR,		0
    94                                  	numdef X,		0
    95                                  	numdef HEATSHRINK,	0
    96                                  	numdef LZD,		0
    97                                  	numdef LZO,		0
    98                                  	numdef LZSA2,		0
    99                                  	numdef APL,		0
   100                                  	numdef BZP,		0
   101                                  %if (!!_BRIEFLZ + !!_LZ4 + !!_SNAPPY + !!_EXODECR + !!_X + !!_HEATSHRINK 	+ !!_LZD + !!_LZO + !!_LZSA2 + !!_APL + !!_BZP) != 1
   103                                   %fatal Exactly one compression method must be selected.
   104                                  %endif
   105                                  %assign ADDITIONAL_MEMORY 0
   106                                  %if _BRIEFLZ
   107                                  	strdef PAYLOAD_FILE,	"lDOSLOAD.BLZ"
   108                                  %elif _LZ4
   109                                  	strdef PAYLOAD_FILE,	"lDOSLOAD.LZ4"
   110                                  %elif _SNAPPY
   111                                  	strdef PAYLOAD_FILE,	"lDOSLOAD.SZ"
   112                                  %elif _EXODECR
   113                                  	strdef PAYLOAD_FILE,	"lDOSLOAD.EXO"
   114                                  %elif _X
   115                                  	strdef PAYLOAD_FILE,	"lDOSLOAD.X"
   116                                  %elif _HEATSHRINK
   117                                  	strdef PAYLOAD_FILE,	"lDOSLOAD.HS"
   118                                  %elif _LZD
   119                                  	strdef PAYLOAD_FILE,	"lDOSLOAD.LZ"
   120                                  %elif _LZO
   121                                  	strdef PAYLOAD_FILE,	"lDOSLOAD.LZO"
   122                                  %elif _LZSA2
   123                                  	strdef PAYLOAD_FILE,	"lDOSLOAD.SA2"
   124                                  %elif _APL
   125                                  	strdef PAYLOAD_FILE,	"lDOSLOAD.APL"
   126                                  %elif _BZP
   127                                  	strdef PAYLOAD_FILE,	"lDOSLOAD.BZP"
   128                                  %endif
   129                                  	numdef PAYLOAD_KERNEL_MAX_PARAS,	0, 0
   130                                  %if _PAYLOAD_KERNEL_MAX_PARAS && ! _IMAGE_EXE
   131                                   %error Kernel mode max paras requires building dual-mode executable
   132                                  %endif
   133                                  	numdef COUNTER,		0, 32
   134                                  %if (_COUNTER - 1) & _COUNTER
   135                                   %error COUNTER must be a power of two
   136                                  %endif
   137                                  
   138                                  
   139                                  	cpu 8086
   140                                  	section INIT0 start=0 vstart=0
   141                                  init0_start:
   142                                  %if _DEVICE
   143                                  		; The device header is of a fixed format.
   144                                  		;  For our purposes, the 4-byte code for
   145                                  		;  each the strategy entry and the
   146                                  		;  interrupt entry is part of this format.
   147                                  		; (DOS may read the attributes or entrypoint
   148                                  		;  offsets before calling either, so in the inicomp
   149                                  		;  stage we need to recreate in the entrypoints part
   150                                  		;  exactly what the application has here.)
   151                                  device_header:
   152                                  .next:
   153                                   %if _DEVICE_ZERO_ENTRYPOINT
   154                                  	fill 2, -1, jmp strict short j_zero_entrypoint
   155                                  	dw -1
   156                                   %else
   157                                  	dd -1				; link to next device
   158                                   %endif
   159                                  .attributes:
   160                                  	dw _DEVICE_ATTRIBUTE		; attributes
   161                                  .strategy:
   162                                  	dw .strategy_entry		; -> strategy entry
   163                                  .interrupt:
   164                                  	dw .interrupt_entry		; -> interrupt entry
   165                                  .name:
   166                                  	fill 8, 32, db _DEVICE_NAME	; character device name,
   167                                  					;  or block device number of units
   168                                  					;  + optional name
   169                                  .strategy_entry:
   170                                  	fill 4, 90h, jmp device_entrypoint
   171                                  .interrupt_entry:
   172                                  	fill 4, 90h, retf
   173                                  %endif
   174                                  
   175                                  
   176                                  j_zero_entrypoint:
   177                                  
   178                                  %if _IMAGE_EXE || _DEVICE
   179 00000000 90                      	nop
   180 00000001 90<rep 1Fh>             	align 32, nop
   181                                  init0_kernel_entry:
   182                                  		; cs:ip = load seg : 32 here
   183                                  %if ($ - $$) != 32
   184                                   %error Wrong kernel mode entrypoint
   185                                  %endif
   186                                  %if _TEST_PROGRAM
   187                                  @@:
   188                                  	int3
   189                                  	sti
   190                                  	hlt
   191                                  	jmp @B
   192                                  %endif
   193 00000020 31DB                    	xor bx, bx		; 0 = kernel mode
   194 00000022 50                      	push ax
   195 00000023 8CC8                    	mov ax, cs
   196 00000025 83C00F                  	add ax, (init0_end - init0_start) >> 4
   197 00000028 8B56E2                  	mov dx, word [ bp + ldLoadTop ]	; => after end of available space
   198 0000002B BE6000                  	mov si, 60h		; => destination
   199 0000002E EB20                    	jmp init0_common
   200                                  
   201                                   %if _IMAGE_EXE
   202 00000030 90<rep 10h>             	align 64, nop
   203                                  init0_exe_entry:
   204                                  		; NOTE:	This part is called with ip = 256 + 64, cs = PSP.
   205                                  %if ($ - $$) != 64
   206                                   %error Wrong EXE mode entrypoint
   207                                  %endif
   208 00000040 BB0100                  	mov bx, 1		; EXE mode
   209 00000043 50                      	push ax
   210 00000044 8CD2                    	mov dx, ss		; => after end of available space
   211 00000046 8CC8                    	mov ax, cs
   212 00000048 83C01F                  	add ax, (256 + (init0_end - init0_start)) >> 4	; => source
   213 0000004B 8CCE                    	mov si, cs
   214 0000004D 83C610                  	add si, 256 >> 4	; => destination
   215                                   %endif
   216                                  
   217                                  init0_common:
   218                                  		; NOTE:	This part must be position-independent, as it is
   219                                  		;	 called either with ip = init0_common (kernel mode)
   220                                  		;	 or ip = init0_common + 256 (EXE mode).
   221 00000050 FC                      	cld
   222                                  %if _TEST_PROGRAM
   223                                  	sub dx, ( (payload_end - payload) ) >> 4
   224                                  	jc .error
   225                                  	mov cx, ( (payload_end - payload) 		+ (init1_end - init1_start) 		+ (init2_end - init2_start) 		) >> 4
   229                                  	sub dx, cx
   230                                  	jc .error
   231                                  	cmp dx, ax
   232                                  	jb .error
   233                                  %else
   234 00000051 B98610                  	mov cx, ( (payload_end - payload) 		+ (init1_end - init1_start) 		) >> 4
   237 00000054 29CA                    	sub dx, cx
   238                                  %endif
   239 00000056 56                      	push si
   240 00000057 E80B00                  	call init0_movp
   241 0000005A 5E                      	pop si
   242                                  %else
   243                                  	cld
   244                                  	mov ax, cs
   245                                  	add ax, (init0_end - init0_start) >> 4
   246                                  	mov cx, ( (payload_end - payload) 		+ (init1_end - init1_start) 		) >> 4
   249                                  	mov dx, word [ bp + ldLoadTop ]
   250                                  	sub dx, cx
   251                                  	call init0_movp
   252                                  %endif
   253                                  
   254 0000005B 89D0                    	mov ax, dx
   255                                  %if _TEST_PROGRAM
   256                                  	add ax, ( 		+ (payload_end - payload) 		+ (init1_end - init1_start) 		) >> 4
   260                                  %else
   261 0000005D 054F10                  	add ax, ( 		+ (payload_end - payload) 		) >> 4
   264                                  %endif
   265 00000060 31C9                    	xor cx, cx
   266 00000062 50                      	push ax
   267 00000063 51                      	push cx
   268 00000064 CB                      	retf			; jump to relocated INIT1:init1_start
   269                                  
   270                                  
   271                                  %if _TEST_PROGRAM
   272                                  .error:
   273                                  	push cs
   274                                  	pop ds
   275                                  	mov dx, init0_msg.error_stderr + 256
   276                                  	mov cx, init0_msg.error_stderr.length
   277                                  	mov bx, 2
   278                                  	mov ah, 40h
   279                                  	int 21h
   280                                  	mov dx, init0_msg.error_stdout + 256
   281                                  	mov cx, init0_msg.error_stdout.length
   282                                  	mov bx, 1
   283                                  	mov ah, 40h
   284                                  	int 21h
   285                                  	mov ax, 4CFFh
   286                                  	int 21h
   287                                  %endif
   288                                  
   289                                  
   290                                  %if _DEVICE
   291                                  device_entrypoint:
   292                                  %if _TEST_PROGRAM
   293                                  @@:
   294                                  	int3
   295                                  	sti
   296                                  	hlt
   297                                  	jmp @B
   298                                  %endif
   299                                  	cmp byte [es:bx + 2], 0		; command code 0 (init) ?
   300                                  	je @F
   301                                  
   302                                  	mov word [es:bx + 3], 8103h	; error, done, code: unknown command
   303                                  	retf
   304                                  
   305                                  @@:
   306                                  	or word [cs:device_header.next], -1
   307                                  	push cs
   308                                  	push word [cs:device_header.strategy]
   309                                  					; -> far return to payload's strategy
   310                                  	push bp
   311                                  	push ds
   312                                  	push si
   313                                  	push di
   314                                  	push dx
   315                                  	push cx
   316                                  	push ax
   317                                  	push bx
   318                                  	push es
   319                                  
   320                                  	mov ax, word [es:bx + 14 + 2]
   321                                  	xor dx, dx
   322                                  	mov cx, 4
   323                                  @@:
   324                                  	shl ax, 1
   325                                  	rcl dx, 1
   326                                  	loop @B
   327                                  	add ax, word [es:bx + 14]
   328                                  	adc dx, 0		; dx:ax = linear address behind end
   329                                  
   330                                  	mov cl, 4
   331                                  @@:
   332                                  	shr dx, 1
   333                                  	rcr ax, 1
   334                                  	loop @B			; ax => behind end
   335                                  
   336                                  	mov di, cs
   337                                  image_size: equ  ( (init0_end - init0_start) 		+ (payload_end - payload) 		+ (init1_end - init1_start) 		)
   341                                  	add di, image_size >> 4		; di => end of image
   342                                  
   343                                  	cmp ax, di			; enough memory to hold all of us ?
   344                                  	jae .have_some_memory		; yes -->
   345                                  
   346                                  	push cs
   347                                  	pop ds
   348                                  	mov dx, .msg_no_memory
   349                                  	mov ah, 09h
   350                                  	int 21h
   351                                  
   352                                  	mov ax, 3000h
   353                                  	int 21h
   354                                  	cmp al, 5
   355                                  	jae @F
   356                                  	mov dx, .msg_dos_below_5
   357                                  	mov ah, 09h
   358                                  	int 21h
   359                                  @@:
   360                                  
   361                                  	mov dx, .msg_linebreak
   362                                  	mov ah, 09h
   363                                  	int 21h
   364                                  
   365                                  		; tear down the stack frame and modify the request header
   366                                  	pop es
   367                                  	pop bx
   368                                  	mov word [es:bx + 3], 8103h	; set error, done, invalid command
   369                                  	mov byte [es:bx + 13], 0	; set number of units = 0
   370                                  	mov word [es:bx + 14 + 2], cs
   371                                  	and word [es:bx + 14], 0	; -> after end of memory to allocate
   372                                  	pop ax
   373                                  	pop cx
   374                                  	pop dx
   375                                  	pop di
   376                                  	pop si
   377                                  	pop ds
   378                                  	pop bp
   379                                  	add sp, 4		; discard far return to payload's strategy
   380                                  	retf			; return to DOS
   381                                  
   382                                  .msg_no_memory:		ascic "Load error: Not enough memory."
   383                                  .msg_dos_below_5:	ascic " Note: DOS must be at least version 5."
   384                                  .msg_linebreak:		ascic 13,10
   385                                  
   386                                  
   387                                  .have_some_memory:
   388                                  	mov dx, ax		; => after end of memory
   389                                  	mov bx, 2		; device mode
   390                                  	push ax
   391                                  	mov ax, cs
   392                                  	add ax, (init0_end - init0_start) >> 4
   393                                  	mov si, cs		; => destination
   394                                  	jmp init0_common
   395                                  %endif
   396                                  
   397                                  
   398                                  		; Move paragraphs
   399                                  		;
   400                                  		; INP:	ax => source
   401                                  		;	dx => destination
   402                                  		;	cx = number of paragraphs
   403                                  		; CHG:	cx, ds, si, es, di
   404                                  		; OUT:	ax and dx unchanged
   405                                  		; Note:	Doesn't work correctly on HMA; doesn't always wrap to LMA either.
   406                                  		;	Do not provide a wrapped/HMA source or destination!
   407                                  init0_movp:
   408 00000065 39D0                    	cmp ax, dx		; source above destination ?
   409 00000067 770A                    	ja .up			; yes, move up (forwards) -->
   410 00000069 747B                    	je .return		; same, no need to move -->
   411 0000006B 50                      	push ax
   412 0000006C 01C8                    	add ax, cx		; (expected not to carry)
   413 0000006E 39D0                    	cmp ax, dx		; end of source is above destination ?
   414 00000070 58                      	pop ax
   415 00000071 7730                    	ja .down		; yes, move from top down -->
   416                                  	; Here, the end of source is below-or-equal the destination,
   417                                  	;  so they do not overlap. In this case we prefer moving up.
   418                                  
   419                                  .up:
   420 00000073 50                      	push ax
   421 00000074 52                      	push dx
   422                                  .uploop:
   423 00000075 8ED8                    	mov ds, ax
   424 00000077 8EC2                    	mov es, dx
   425 00000079 31FF                    	xor di, di
   426 0000007B 31F6                    	xor si, si		; -> start of segment
   427 0000007D 81E90010                	sub cx, 1000h		; 64 KiB left ?
   428 00000081 7610                    	jbe .uplast		; no -->
   429 00000083 51                      	push cx
   430 00000084 B90080                  	mov cx, 10000h /2
   431 00000087 F3A5                    	rep movsw		; move 64 KiB
   432 00000089 59                      	pop cx
   433 0000008A 050010                  	add ax, 1000h
   434 0000008D 81C20010                	add dx, 1000h		; -> next segment
   435 00000091 EBE2                    	jmp short .uploop	; proceed for more -->
   436                                  .uplast:
   437 00000093 81C10010                	add cx, 1000h		; restore counter
   438 00000097 D1E1                    	shl cx, 1
   439 00000099 D1E1                    	shl cx, 1
   440 0000009B D1E1                    	shl cx, 1		; *8, paragraphs to words
   441 0000009D F3A5                    	rep movsw		; move last part
   442 0000009F 5A                      	pop dx
   443 000000A0 58                      	pop ax
   444 000000A1 EB43                    	jmp short .return
   445                                  
   446                                  .down:
   447 000000A3 FD                      	std			; _AMD_ERRATUM_109_WORKAROUND as below
   448                                  .dnloop:
   449 000000A4 81E90010                	sub cx, 1000h		; 64 KiB left ?
   450 000000A8 761A                    	jbe .dnlast		; no -->
   451 000000AA 50                      	push ax
   452 000000AB 52                      	push dx
   453 000000AC 01C8                    	add ax, cx
   454 000000AE 01CA                    	add dx, cx
   455 000000B0 8ED8                    	mov ds, ax		; -> 64 KiB not yet moved
   456 000000B2 8EC2                    	mov es, dx
   457 000000B4 5A                      	pop dx
   458 000000B5 58                      	pop ax
   459 000000B6 BFFEFF                  	mov di, -2
   460 000000B9 89FE                    	mov si, di		; moved from last word down
   461 000000BB 51                      	push cx
   462 000000BC B90080                  	mov cx, 10000h /2
   463 000000BF F3A5                    	rep movsw		; move 64 KiB
   464 000000C1 59                      	pop cx
   465 000000C2 EBE0                    	jmp short .dnloop	; proceed for more -->
   466                                  .dnlast:
   467 000000C4 81C10010                	add cx, 1000h		; restore counter
   468 000000C8 D1E1                    	shl cx, 1
   469 000000CA D1E1                    	shl cx, 1
   470 000000CC D1E1                    	shl cx, 1		; *8, paragraphs to words
   471 000000CE 89CF                    	mov di, cx
   472 000000D0 4F                      	dec di
   473 000000D1 D1E7                    	shl di, 1		; words to offset, -> last word
   474 000000D3 89FE                    	mov si, di
   475 000000D5 8ED8                    	mov ds, ax
   476 000000D7 8EC2                    	mov es, dx		; first segment correct
   477                                  
   478                                  
   479                                  	numdef AMD_ERRATUM_109_WORKAROUND, 1
   480                                  %if 0
   481                                  
   482                                  Jack R. Ellis pointed out this erratum:
   483                                  
   484                                  Quoting from https://www.amd.com/system/files/TechDocs/25759.pdf page 69:
   485                                  
   486                                  109   Certain Reverse REP MOVS May Produce Unpredictable Behavior
   487                                  
   488                                  Description
   489                                  
   490                                  In certain situations a REP MOVS instruction may lead to
   491                                  incorrect results. An incorrect address size, data size
   492                                  or source operand segment may be used or a succeeding
   493                                  instruction may be skipped. This may occur under the
   494                                  following conditions:
   495                                  
   496                                  * EFLAGS.DF=1 (the string is being moved in the reverse direction).
   497                                  
   498                                  * The number of items being moved (RCX) is between 1 and 20.
   499                                  
   500                                  * The REP MOVS instruction is preceded by some microcoded instruction
   501                                    that has not completely retired by the time the REP MOVS begins
   502                                    execution. The set of such instructions includes BOUND, CLI, LDS,
   503                                    LES, LFS, LGS, LSS, IDIV, and most microcoded x87 instructions.
   504                                  
   505                                  Potential Effect on System
   506                                  
   507                                  Incorrect results may be produced or the system may hang.
   508                                  
   509                                  Suggested Workaround
   510                                  
   511                                  Contact your AMD representative for information on a BIOS update.
   512                                  
   513                                  %endif
   514                                  
   515                                  %if _AMD_ERRATUM_109_WORKAROUND
   516 000000D9 E308                    	jcxz @FF
   517 000000DB 83F914                  	cmp cx, 20
   518 000000DE 7703                    	ja @FF
   519                                  @@:
   520 000000E0 A5                      	movsw
   521 000000E1 E2FD                    	loop @B
   522                                  @@:
   523                                  %endif
   524 000000E3 F3A5                    	rep movsw		; move first part
   525 000000E5 FC                      	cld
   526                                  .return:
   527 000000E6 C3                      	retn
   528                                  
   529                                  
   530                                  	section PAYLOAD align=16 follows=INIT0
   531                                  payload:
   532 00000000 <bin 104ECh>            	incbin _PAYLOAD_FILE
   533                                  .end:
   534 000104EC 26<rep 4h>              	align 16, db 38
   535                                  payload_end:
   536                                  
   537                                  
   538                                  	section INIT1 align=16 follows=PAYLOAD vstart=0
   539                                  init1_start:
   540                                  		; INP:	ax = cs = INIT1
   541                                  		;	dx = cs - (payload_end - payload) >> 4 => source data
   542                                  		;	if kernel mode:
   543                                  		;	 ss:bp -> LOADDATA and LOADSTACKVARS
   544                                  		;	 ss:sp -> valid stack above [bp + ldLoadTop]
   545                                  		;	 60h => destination
   546                                  		;	any mode:
   547                                  		;	 word [ss:sp] = value for ax
   548                                  		;	 bx = 2 if device mode, 1 if EXE mode, 0 if kernel mode
   549                                  		;	 si => destination (60h for kernel mode,
   550                                  		;		after PSP for EXE mode,
   551                                  		;		at device header for device mode)
   552                                  		;	 if EXE mode:
   553                                  		;	  ss:sp -> valid stack above INIT1
   554                                  		;	  bp = unset
   555                                  		;	 if device mode:
   556                                  		;	  ss:sp -> device entrypoint stack
   557                                  		;	  holds: es, bx, ax, cx, dx, di, si, ds, bp,
   558                                  		;		  far address of payload strategy entrypoint,
   559                                  		;		  far return address to DOS
   560                                  		;	  bp = unset
   561                                  		; STT:	UP
   562                                  		; CHG:	ax, bx, cx, dx, es, ds, si, di
   563                                  %if _IMAGE_EXE || _DEVICE
   564                                  	lframe
   565 00000000 5589E5                  	lenter
   566                                  	lvar word,	exemode		; must be bp - 2!
   567 00000003 53                      	 push bx
   568                                   %if ?exemode != -2
   569                                    %error exemode variable must be directly below bp
   570                                   %endif
   571 00000004 56                      	push si
   572                                  %else
   573                                  	xor bx, bx		; always tell them it is kernel mode
   574                                  %endif
   575                                  
   576                                  %if _IMAGE_EXE
   577 00000005 8EC6                    	mov es, si		; es => destination
   578                                  %else
   579                                  	mov ax, 60h
   580                                  	mov es, ax		; es => destination
   581                                  %endif
   582 00000007 31FF                    	xor di, di		; -> destination
   583                                  
   584 00000009 8EDA                    	mov ds, dx
   585 0000000B 31F6                    	xor si, si		; -> source
   586                                  
   587 0000000D B9EC04                  	mov cx, (payload.end - payload) & 0FFFFh
   588                                  %if (payload.end - payload) >> 16
   589 00000010 BA0100                  	mov dx, (payload.end - payload) >> 16	; = length of source
   590                                  %else
   591                                  	xor dx, dx
   592                                  %endif
   593                                  %if _PAYLOAD_KERNEL_MAX_PARAS
   594                                  	mov ax, _PAYLOAD_KERNEL_MAX_PARAS
   595                                  	test bx, bx
   596                                  	jz @F
   597                                  %endif
   598 00000013 B8FFFF                  	mov ax, -1
   599                                  @@:
   600                                  		; INP:	ds:si -> source
   601                                  		;	dx:cx = length of source
   602                                  		;	es:di -> destination (below source)
   603                                  		;	bx = EXE mode flag
   604                                  		;	 (1 if EXE mode, 0 if kernel mode)
   605                                  		;	 (always 0 if this is a build without EXE mode)
   606                                  		;	if _PAYLOAD_KERNEL_MAX_PARAS:
   607                                  		;	 ax = maximum amount in paragraphs of destination needed
   608                                  		;	 (-1 if full source should be decompressed)
   609                                  		;	else:
   610                                  		;	 ax = -1
   611                                  		; Note:	The destination reaches up to below the source.
   612 00000016 E88300                  	call depack
   613                                  %ifn _TEST_PROGRAM
   614 00000019 721E                    	jc strict short error
   615                                  %endif
   616                                  %if _IMAGE_EXE
   617 0000001B 5E                      	pop si			; si
   618                                   %if _TEST_PROGRAM
   619                                  	pop ax			; (discard ?exemode, leave bx as returned)
   620                                   %else
   621 0000001C 5B                      	pop bx			; ?exemode
   622                                   %endif
   623 0000001D 5D                      	pop bp			; bp
   624 0000001E 58                      	pop ax			; ax
   625                                  	lleave ctx
   626                                  %endif
   627                                  %if _TEST_PROGRAM
   628                                  	retf
   629                                  	nop
   630                                  %endif
   631                                  
   632                                  %if _DEVICE
   633                                  	test bl, 2
   634                                  	jz .jmp_exe_or_kernel_mode
   635                                  
   636                                  .jmp_device_mode:
   637                                  	mov ds, si
   638                                  	or word [device_header.next], -1
   639                                  	pop es
   640                                  	pop bx
   641                                  	pop ax
   642                                  	pop cx
   643                                  	pop dx
   644                                  	pop di
   645                                  	pop si
   646                                  	pop ds
   647                                  	pop bp
   648                                  	retf			; transfer to payload strategy entrypoint
   649                                  				; still on stack: far return address to DOS
   650                                  
   651                                  .jmp_exe_or_kernel_mode:
   652                                  %endif
   653                                  
   654                                  %if _IMAGE_EXE
   655 0000001F F6C301                  	test bl, 1
   656 00000022 7410                    	jz .jmp_kernel_mode
   657                                  
   658                                  .jmp_exe_mode:
   659                                  %if ! _IMAGE_EXE_AUTO_STACK
   660                                  	mov cx, cs
   661                                  	lea dx, [si + _IMAGE_EXE_SS]
   662                                  	push dx			; stack = relocated ss value
   663                                  	add dx, (_IMAGE_EXE_SP + 2 + 15) >> 4
   664                                  	cmp cx, dx		; INIT1 code is above intended stack ?
   665                                  	jae @F			; yes -->
   666                                  
   667                                  	lframe
   668                                  	lenter
   669                                  	lvar	word, exemode
   670                                  	 push bx
   671                                   %if ?exemode != -2
   672                                    %error exemode variable must be directly below bp
   673                                   %endif
   674                                  	mov bx, -1		; unimplemented, return error
   675                                  	jmp error
   676                                  	lleave ctx
   677                                  @@:
   678                                  	cli
   679                                  	pop ss			; = relocated ss value
   680                                  	mov sp, (_IMAGE_EXE_SP + 2) & 0FFFFh	; change stack
   681                                  	sti
   682                                  %endif
   683                                  
   684 00000024 31C9                    	xor cx, cx
   685 00000026 51                      	push cx			; put zero on top of stack
   686                                  
   687                                  %if _IMAGE_EXE_IP < 256
   688                                  	mov cl, _IMAGE_EXE_IP
   689                                  %elif (_IMAGE_EXE_IP & 255) == 0
   690                                  	mov ch, _IMAGE_EXE_IP >> 8
   691                                  %else
   692 00000027 B94001                  	mov cx, _IMAGE_EXE_IP
   693                                  %endif
   694                                  
   695                                  %if _IMAGE_EXE_CS == -16
   696 0000002A 83C6F0                  	add si, -16
   697 0000002D 8EDE                    	mov ds, si
   698 0000002F 8EC6                    	mov es, si
   699                                  %else
   700                                  	lea dx, [si - 10h]	; => PSP
   701                                  	mov ds, dx
   702                                  	mov es, dx		; ds = es => PSP
   703                                  	add si, _IMAGE_EXE_CS	; = relocated cs value
   704                                  %endif
   705 00000031 56                      	push si
   706 00000032 51                      	push cx
   707 00000033 CB                      	retf			; jump to EXE mode of image
   708                                  
   709                                  %endif
   710                                  .jmp_kernel_mode:
   711 00000034 EA20006000              	jmp 60h + _EXEC_SEGMENT:_EXEC_OFFSET
   712                                  
   713                                  
   714                                  error:
   715 00000039 0E                      	push cs
   716 0000003A 1F                      	pop ds
   717                                  %if _DEBUG0
   718                                  	mov si, msg.error_begin
   719                                  	call disp_error
   720                                  	xchg ax, bx			; ax = error code
   721                                  	call disp_ax_hex
   722                                  	mov si, msg.error_end
   723                                  %else
   724 0000003B BE[7700]                	mov si, msg.error
   725                                  %endif
   726 0000003E E81400                  	call disp_error
   727                                  
   728                                  %if _DEVICE
   729                                  	test byte [bp - 2], 2
   730                                  	jz .exit_app_or_kernel
   731                                  
   732                                  	pop si				; => device segment
   733                                  	pop bx				; mode word
   734                                  	pop bp
   735                                  	pop ax
   736                                  	mov es, si
   737                                  	xor di, di			; -> device header
   738                                  	 push cs
   739                                  	 pop ds
   740                                  	mov si, device_header_copy	; -> to reset header
   741                                  	mov cx, words(device_header_copy.length)
   742                                  	rep movsw		; overwrite device header with default
   743                                  				;  (reset to a valid state after unsuccessful
   744                                  				;  decompression, which may have partially
   745                                  				;  written the header already)
   746                                  	 push es
   747                                  	 pop ds				; -> device segment
   748                                  	pop es
   749                                  	pop bx
   750                                  	mov word [es:bx + 3], 8103h	; set error, done, invalid command
   751                                  	mov byte [es:bx + 13], 0	; set number of units = 0
   752                                  	mov word [es:bx + 14 + 2], ds
   753                                  	and word [es:bx + 14], 0	; -> after end of memory to allocate
   754                                  	pop ax
   755                                  	pop cx
   756                                  	pop dx
   757                                  	pop di
   758                                  	pop si
   759                                  	pop ds
   760                                  	pop bp
   761                                  	add sp, 4		; discard far return to payload's strategy
   762                                  	retf			; return to DOS
   763                                  
   764                                  
   765                                  .exit_app_or_kernel:
   766                                  %endif
   767                                  
   768                                  %if _IMAGE_EXE
   769 00000041 F646FE01                	test byte [bp - 2], 1
   770 00000045 7405                    	jz .exit_kernel_mode
   771                                  
   772 00000047 B87F4C                  	mov ax, 4C7Fh
   773 0000004A CD21                    	int 21h
   774                                  
   775                                  .exit_kernel_mode:
   776                                  %endif
   777 0000004C 31C0                    	xor ax, ax
   778 0000004E CD16                    	int 16h
   779 00000050 CD19                    	int 19h
   780                                  
   781                                  
   782                                  %if _DEVICE
   783                                  	align 16
   784                                  device_header_copy:
   785                                  .:
   786                                  .next:
   787                                  	dd -1				; already initialised
   788                                  .attributes:
   789                                  	dw _DEVICE_ATTRIBUTE
   790                                  .strategy:
   791                                  	dw .strategy_entry - .		; -> strategy entry
   792                                  .interrupt:
   793                                  	dw .interrupt_entry - .		; -> interrupt entry
   794                                  .name:
   795                                  	fill 8, 32, db _DEVICE_NAME
   796                                  .strategy_entry:
   797                                  	fill 4, 90h, jmp .set_error	; rel8 or rel16 jump, not minus .
   798                                  .interrupt_entry:
   799                                  	fill 4, 90h, retf
   800                                  
   801                                  .set_error:
   802                                  	mov word [es:bx + 3], 8103h	; set error, done, invalid command
   803                                  	retf
   804                                  .length: equ $ - .
   805                                  %endif
   806                                  
   807                                  
   808                                  disp_error.loop:
   809 00000052 E80600                  	call disp_al
   810                                  disp_error:
   811 00000055 AC                      	lodsb
   812 00000056 84C0                    	test al, al
   813 00000058 75F8                    	jnz .loop
   814 0000005A C3                      	retn
   815                                  
   816                                  %if _DEBUG0 || _DEBUG1 || _DEBUG2 || _DEBUG3
   817                                  disp_ax_hex:			; ax
   818                                  		xchg al,ah
   819                                  		call disp_al_hex		; display former ah
   820                                  		xchg al,ah			;  and fall trough for al
   821                                  disp_al_hex:			; al
   822                                  		push cx
   823                                  		mov cl,4
   824                                  		ror al,cl
   825                                  		call disp_al_lownibble_hex	; display former high-nibble
   826                                  		rol al,cl
   827                                  		pop cx
   828                                  						;  and fall trough for low-nibble
   829                                  disp_al_lownibble_hex:
   830                                  		push ax			 ; save ax for call return
   831                                  		and al,00001111b		; high nibble must be zero
   832                                  		add al,'0'			; if number is 0-9, now it's the correct character
   833                                  		cmp al,'9'
   834                                  		jna .decimalnum		 ; if we get decimal number with this, ok -->
   835                                  		add al,7			;  otherwise, add 7 and we are inside our alphabet
   836                                   .decimalnum:
   837                                  		call disp_al
   838                                  		pop ax
   839                                  		retn
   840                                  %endif
   841                                  
   842                                  disp_al:
   843                                  %if _TEST_PROGRAM
   844                                  	retn
   845                                  %else
   846 0000005B 50                      	push ax
   847                                  %endif
   848 0000005C 53                      	push bx
   849 0000005D 55                      	push bp
   850 0000005E B40E                    	mov ah, 0Eh
   851 00000060 BB0700                  	mov bx, 7
   852                                  %if _IMAGE_EXE || _DEVICE
   853 00000063 52                      	push dx
   854                                  
   855 00000064 F646FE03                	test byte [bp - 2], 1 | 2
   856 00000068 7406                    	jz .display_kernel_mode
   857                                  
   858 0000006A 92                      	xchg dx, ax				; dl = input al
   859 0000006B B402                    	mov ah, 02h
   860 0000006D CD21                    	int 21h
   861 0000006F A9                      	db __TEST_IMM16				; (skip int)
   862                                  
   863                                  .display_kernel_mode:
   864                                  %endif
   865 00000070 CD10                    	int 10h
   866                                  %if _IMAGE_EXE
   867 00000072 5A                      	pop dx
   868                                  %endif
   869 00000073 5D                      	pop bp
   870 00000074 5B                      	pop bx
   871 00000075 58                      	pop ax
   872                                  disp_error.ret:
   873 00000076 C3                      	retn
   874                                  
   875                                  
   876                                  msg:
   877                                  %if _DEBUG0
   878                                  .error_begin:	db "Load error: Decompression failure, code ",0
   879                                  .error_end:	db "h.",13,10,0
   880                                  %else
   881 00000077 4C6F6164206572726F-     .error:		db "Load error: Decompression failure.",13,10,0
   881 00000080 723A204465636F6D70-
   881 00000089 72657373696F6E2066-
   881 00000092 61696C7572652E0D0A-
   881 0000009B 00                 
   882                                  %endif
   883                                  
   884                                  
   885                                  %assign NEED_NORMALISE_POINTER_WITH_DISPLACEMENT 1
   886                                  %assign CHECK_POINTERS_VARIABLE_SRC 1
   887                                  %assign CHECK_POINTERS_VARIABLE_DST 1
   888                                  
   889                                  		; Specific depacker's file is included within label msg.
   890                                  		; In the file, lframe is used and lleave ctx is not used.
   891                                  
   892                                  %if _BRIEFLZ
   893                                  	%include "brieflz.asm"
   894                                  %endif
   895                                  
   896                                  
   897                                  %if _LZ4
   898                                  	%include "lz4.asm"
   899                                  %endif
   900                                  
   901                                  
   902                                  %if _SNAPPY
   903                                  	%include "snappy.asm"
   904                                  %endif
   905                                  
   906                                  
   907                                  %if _EXODECR
   908                                  	%include "exodecr.asm"
   909                              <1> 
   910                              <1> %if 0
   911                              <1> 
   912                              <1> 8086 Assembly lDOS iniload payload exomizer raw depacker
   913                              <1>  by C. Masloch, 2020
   914                              <1> 
   915                              <1> Copyright (c) 2005-2017 Magnus Lind.
   916                              <1> 
   917                              <1> This software is provided 'as-is', without any express or implied warranty.
   918                              <1> In no event will the authors be held liable for any damages arising from
   919                              <1> the use of this software.
   920                              <1> 
   921                              <1> Permission is granted to anyone to use this software for any purpose,
   922                              <1> including commercial applications, and to alter it and redistribute it
   923                              <1> freely, subject to the following restrictions:
   924                              <1> 
   925                              <1>   1. The origin of this software must not be misrepresented * you must not
   926                              <1>   claim that you wrote the original software. If you use this software in a
   927                              <1>   product, an acknowledgment in the product documentation would be
   928                              <1>   appreciated but is not required.
   929                              <1> 
   930                              <1>   2. Altered source versions must be plainly marked as such, and must not
   931                              <1>   be misrepresented as being the original software.
   932                              <1> 
   933                              <1>   3. This notice may not be removed or altered from any distribution.
   934                              <1> 
   935                              <1>   4. The names of this software and/or it's copyright holders may not be
   936                              <1>   used to endorse or promote products derived from this software without
   937                              <1>   specific prior written permission.
   938                              <1> 
   939                              <1> %endif
   940                              <1> 
   941                              <1> 	numdef P, 7, 7
   942                              <1> 
   943                              <1> 
   944                              <1> 	struc exo_table_entry
   945 00000000 ??                  <1> eteBits:	resb 1
   946 00000001 ????                <1> eteBase:	resw 1
   947                              <1> 	endstruc
   948                              <1> 
   949                              <1> 		; INP:	ds:si -> source
   950                              <1> 		;	dx:cx = length of source
   951                              <1> 		;	es:di -> destination (below source)
   952                              <1> 		;	if _IMAGE_EXE:
   953                              <1> 		;	 bx = EXE mode flag (bit 0)
   954                              <1> 		;	else:
   955                              <1> 		;	 bx = 0
   956                              <1> 		;	if _PAYLOAD_KERNEL_MAX_PARAS:
   957                              <1> 		;	 ax = maximum amount in paragraphs of destination needed
   958                              <1> 		;	 (-1 if full source should be decompressed)
   959                              <1> 		;	else:
   960                              <1> 		;	 ax = -1
   961                              <1> 		; OUT:	NC if success
   962                              <1> 		;	CY if error,
   963                              <1> 		;	 bx = ?errordata (if _DEBUG0)
   964                              <1> 		; CHG:	ax, (bx), cx, dx, es, ds, si, di
   965                              <1> 		; STT:	UP
   966                              <1> 		;
   967                              <1> 		; Note:	The destination reaches up to below the source.
   968                              <1> 		; Note:	The input pointers need not be normalised yet.
   969                              <1> 		;	 Normalised means that the offset part is below 16.
   970                              <1> depack:
   971                              <1> 	lframe near
   972 0000009C 5589E5              <1> 	lenter
   973                              <1>  %if _IMAGE_EXE
   974                              <1> 	lvar word,	exemode	; must be bp - 2!
   975 0000009F 53                  <1> 	 push bx
   976                              <1>   %if ?exemode != -2
   977                              <1>    %error exemode variable must be directly below bp
   978                              <1>   %endif
   979                              <1>  %endif
   980 000000A0 31DB                <1> 	xor bx, bx
   981                              <1>  %if _DEBUG0
   982                              <1> 	lvar word,	errordata
   983                              <1> 	 push bx
   984                              <1>  %endif
   985                              <1> 	lvar word, bit_buffer_and_counter
   986                              <1> 	lequ ?bit_buffer_and_counter, bit_buffer
   987                              <1> 	lequ ?bit_buffer_and_counter + 1, counter
   988 000000A2 53                  <1> 	 push bx		; initialise counter (high byte) to zero
   989                              <1> 				; if _P & 8: initialise bit_buffer to zero
   990                              <1> 
   991 000000A3 E84602              <1> 	call normalise_both_pointers
   992                              <1> 
   993                              <1> 	lvar dword,	src
   994 000000A6 1E                  <1> 	 push ds
   995 000000A7 56                  <1> 	 push si
   996                              <1> 	lvar dword,	original_dst
   997 000000A8 06                  <1> 	 push es
   998 000000A9 57                  <1> 	 push di
   999                              <1> 	lvar dword,	dst
  1000 000000AA 06                  <1> 	 push es
  1001 000000AB 57                  <1> 	 push di
  1002                              <1> 	lvar dword,	src_remaining
  1003 000000AC 52                  <1> 	 push dx
  1004 000000AD 51                  <1> 	 push cx
  1005                              <1> 
  1006                              <1> %if _PAYLOAD_KERNEL_MAX_PARAS
  1007                              <1> 	cmp ax, -1		; no maximum specified ?
  1008                              <1> 	je @FF			; retain -1 in ax -->
  1009                              <1> 	test di, di		; do we need an additional paragraph ?
  1010                              <1> 	jz @F			; no -->
  1011                              <1> 	inc ax			; es + ax => paragraph after necessary part
  1012                              <1> @@:
  1013                              <1> 	mov dx, es
  1014                              <1> 	add ax, dx		; => paragraph after necessary part
  1015                              <1> 		; If the normalised destination pointer's segment grows
  1016                              <1> 		;  to this segment then enough has been decompressed.
  1017                              <1> d0	mov byte [bp + ?errordata], 40h
  1018                              <1> 	jc .error		; should not carry
  1019                              <1> @@:
  1020                              <1> 	lvar word,	dst_max_segment
  1021                              <1> 	 push ax
  1022                              <1> %endif
  1023                              <1> 
  1024 000000AE 1E                  <1> 	 push ds
  1025 000000AF 56                  <1> 	 push si
  1026 000000B0 E89302              <1> 	call pointer_to_linear
  1027                              <1> 
  1028 000000B3 89D3                <1> 	mov bx, dx
  1029 000000B5 91                  <1> 	xchg cx, ax		; bx:cx = source linear
  1030                              <1> 
  1031 000000B6 06                  <1> 	 push es
  1032 000000B7 57                  <1> 	 push di
  1033 000000B8 E88B02              <1> 	call pointer_to_linear
  1034                              <1> 
  1035                              <1> %if _ALLOW_OVERLAPPING
  1036 000000BB 034EEC              <1> 	add cx, word [bp + ?src_remaining]
  1037 000000BE 135EEE              <1> 	adc bx, word [bp + ?src_remaining + 2]
  1038                              <1> 		; In case of allowing overlapping source and destination,
  1039                              <1> 		;  the ?dst_remaining variable is set to
  1040                              <1> 		;  ?src + ?src_remaining - ?dst, allowing to write to
  1041                              <1> 		;  all of the source buffer (with the checks already in place
  1042                              <1> 		;  from the default handling). Additional checks are done by
  1043                              <1> 		;  calling check_pointers_not_overlapping. This is done after
  1044                              <1> 		;  every change of ?dst to verify that the write pointer stays
  1045                              <1> 		;  below-or-equal the read pointer.
  1046                              <1> 		; This means the remaining source data may be corrupted by a
  1047                              <1> 		;  write, but nothing after the source data is written to,
  1048                              <1> 		;  so the error handling (in INIT1 after the data) still works.
  1049                              <1> %endif
  1050                              <1> 
  1051 000000C1 29C1                <1> 	sub cx, ax
  1052 000000C3 19D3                <1> 	sbb bx, dx		; bx:cx = source linear - destination linear
  1053                              <1> 
  1054                              <1> 	lvar dword,	dst_remaining
  1055 000000C5 53                  <1> 	 push bx		; push into [bp + ?dst_remaining + 2]
  1056 000000C6 51                  <1> 	 push cx		; push into [bp + ?dst_remaining]
  1057                              <1> 
  1058                              <1> %if _ALLOW_OVERLAPPING
  1059 000000C7 E80402              <1> 	call check_pointers_not_overlapping
  1060                              <1> 		; Note:	We initially check here that the write pointer is
  1061                              <1> 		;	 low enough, ie below-or-equal the read pointer.
  1062                              <1> 		;	 Doing this check here (as well as after any
  1063                              <1> 		;	 copied match) allows us to drop the check done
  1064                              <1> 		;	 after moving literal bytes.
  1065                              <1> d0	mov byte [bp + ?errordata], 1Bh
  1066 000000CA 7303E93B01          <1> 	jc .error
  1067                              <1> %endif
  1068                              <1> 
  1069                              <1> 	lequ fromwords(words(16 * exo_table_entry_size)), 16tablesize
  1070                              <1> 	lvar ?16tablesize, lengths
  1071                              <1> %if _P & 16
  1072                              <1> 	lvar ?16tablesize, offsets4
  1073                              <1> %endif
  1074                              <1> 	lvar ?16tablesize, offsets3
  1075                              <1> 	lvar ?16tablesize, offsets2
  1076                              <1> 	lequ fromwords(words(4 * exo_table_entry_size)), 4tablesize
  1077                              <1> 	lvar ?4tablesize, offsets1
  1078 000000CF 8DA64CFF            <1> 	lreserve
  1079                              <1> 
  1080                              <1> %ifn _P & 8
  1081 000000D3 E85101              <1> 	call read_byte_to_bit_buffer
  1082                              <1> d0	mov byte [bp + ?errordata], 30h
  1083 000000D6 7303E92F01          <1> 	jc .error
  1084                              <1> %endif
  1085                              <1> 
  1086 000000DB BFB8FF              <1> 	mov di, ?lengths
  1087 000000DE E88C01              <1> 	call generate_table_16
  1088                              <1> d0	mov byte [bp + ?errordata], 41h
  1089 000000E1 7303E92401          <1> 	jc .error
  1090                              <1> %if _P & 16
  1091                              <1> 	mov di, ?offsets4
  1092                              <1> 	call generate_table_16
  1093                              <1> d0	mov byte [bp + ?errordata], 49h
  1094                              <1> 	jc .error
  1095                              <1> %endif
  1096 000000E6 BF88FF              <1> 	mov di, ?offsets3
  1097 000000E9 E88101              <1> 	call generate_table_16
  1098                              <1> d0	mov byte [bp + ?errordata], 42h
  1099 000000EC 7303E91901          <1> 	jc .error
  1100 000000F1 BF58FF              <1> 	mov di, ?offsets2
  1101 000000F4 E87601              <1> 	call generate_table_16
  1102                              <1> d0	mov byte [bp + ?errordata], 43h
  1103 000000F7 7303E90E01          <1> 	jc .error
  1104 000000FC BF4CFF              <1> 	mov di, ?offsets1
  1105 000000FF B104                <1> 	mov cl, 4
  1106 00000101 E86C01              <1> 	call generate_table_cx		; cx = 0 if NC
  1107                              <1> d0	mov byte [bp + ?errordata], 44h
  1108 00000104 7303E90101          <1> 	jc .error
  1109                              <1> 
  1110                              <1> %ifn _P & 4
  1111                              <1> 	jmp .STATE_NEXT_BYTE
  1112                              <1> %endif
  1113                              <1> 
  1114                              <1> 		; cx = 0
  1115                              <1> .STATE_IMPLICIT_FIRST_LITERAL_BYTE:
  1116                              <1> 		; ! cx = 0
  1117                              <1> 		; All paths to this label must have cx = 0.
  1118                              <1> .literal:
  1119 00000109 41                  <1> 	inc cx				; cx = 1
  1120                              <1> .STATE_NEXT_LITERAL_BYTE_increment_counter:
  1121 0000010A C576F8              <1> 	lds si, [bp + ?src]
  1122 0000010D 294EEC              <1> 	sub word [bp + ?src_remaining], cx
  1123 00000110 835EEE00            <1> 	sbb word [bp + ?src_remaining + 2], 0
  1124                              <1> d0	mov byte [bp + ?errordata], 45h
  1125 00000114 7303E9F100          <1> 	jc .error
  1126 00000119 E88601              <1> 	call copy_data
  1127                              <1> d0	mov byte [bp + ?errordata], 46h
  1128 0000011C 7303E9E900          <1> 	jc .error
  1129 00000121 8976F8              <1> 	mov word [bp + ?src], si
  1130 00000124 8C5EFA              <1> 	mov word [bp + ?src + 2], ds
  1131                              <1> 
  1132                              <1> 		; cx = 0
  1133                              <1> 	; jmp .STATE_NEXT_BYTE
  1134                              <1> 
  1135                              <1> .STATE_NEXT_BYTE:
  1136                              <1> %if _COUNTER
  1137                              <1> 	inc byte [bp + ?counter]
  1138                              <1> 	test byte [bp + ?counter], _COUNTER - 1
  1139                              <1> 	jnz @F
  1140                              <1> 	mov al, '.'
  1141                              <1> 	call disp_al
  1142                              <1> @@:
  1143                              <1> %endif
  1144 00000127 E80E01              <1> 	call read_bits_1		; cx = 0 if NC
  1145                              <1> d0	mov byte [bp + ?errordata], 32h
  1146 0000012A 7303E9DB00          <1> 	jc .error
  1147 0000012F 85C0                <1> 	test ax, ax
  1148 00000131 75D6                <1> 	jnz .literal			; (cx = 0 still)
  1149                              <1> 
  1150                              <1> 		; cx = ax = 0
  1151                              <1> .not_literal:
  1152                              <1> 
  1153                              <1> 	; call get_gamma_code
  1154                              <1> 		; INP:	-
  1155                              <1> 		; OUT:	CY if error
  1156                              <1> 		;	NC if success,
  1157                              <1> 		;	 bx:dx = gamma
  1158                              <1> 		;	 ax = cx = 0
  1159                              <1> 		; CHG:	ds, si
  1160                              <1> 		; STT:	bp -> depack stack frame
  1161                              <1> 		;	UP
  1162                              <1> .get_gamma_code:
  1163 00000133 31D2                <1> 	xor dx, dx
  1164 00000135 31DB                <1> 	xor bx, bx		; bx:dx = gamma = 0
  1165                              <1> .ggc_loop:
  1166                              <1> 		; cx = 0. ax = 0 initially, else = 1
  1167 00000137 01C2                <1> 	add dx, ax
  1168 00000139 11CB                <1> 	adc bx, cx		; ++gamma (except initially)
  1169 0000013B E8FA00              <1> 	call read_bits_1	; read_bits(1)
  1170                              <1> d0	mov byte [bp + ?errordata], 33h
  1171 0000013E 7303E9C700          <1> 	jc .error
  1172 00000143 3401                <1> 	xor al, 1		; returned == 0 ?
  1173 00000145 75F0                <1> 	jnz .ggc_loop		; yes, loop --> (ax = 1 if looping)
  1174                              <1> 				; no, end of loop
  1175                              <1> 
  1176 00000147 85DB                <1> 	test bx, bx
  1177                              <1> d0	mov byte [bp + ?errordata], 34h
  1178 00000149 7403E9BC00          <1> 	jnz .error
  1179 0000014E 83FA11              <1> 	cmp dx, 17
  1180 00000151 7515                <1> 	jne .not_literal_data_block
  1181                              <1> .literal_data_block:
  1182                              <1> %if _P & 2
  1183 00000153 E8B900              <1> 	call read_byte
  1184                              <1> d0	mov byte [bp + ?errordata], 35h
  1185 00000156 7303E9AF00          <1> 	jc .error
  1186 0000015B 88C4                <1> 	mov ah, al
  1187 0000015D E8AF00              <1> 	call read_byte
  1188                              <1> d0	mov byte [bp + ?errordata], 36h
  1189 00000160 7303E9A500          <1> 	jc .error
  1190                              <1> %else
  1191                              <1> 	mov cx, 16
  1192                              <1> 	call read_bits
  1193                              <1> d0	mov byte [bp + ?errordata], 48h
  1194                              <1> 	jc .error
  1195                              <1> %endif
  1196 00000165 91                  <1> 	xchg ax, cx
  1197 00000166 EBA2                <1> 	jmp .STATE_NEXT_LITERAL_BYTE_increment_counter
  1198                              <1> 
  1199                              <1> .not_literal_data_block:
  1200 00000168 83FA10              <1> 	cmp dx, 16
  1201 0000016B 7503E98D00          <1> 	je .end_check
  1202                              <1> d0	mov byte [bp + ?errordata], 38h
  1203 00000170 7603E99500          <1> 	ja .error
  1204                              <1> 
  1205                              <1> .sequence:
  1206 00000175 89D7                <1> 	mov di, dx
  1207 00000177 01D2                <1> 	add dx, dx
  1208 00000179 01D7                <1> 	add di, dx		; * 3 = * exo_table_entry_size
  1209                              <1> 
  1210 0000017B 8B5BB9              <1> 	mov bx, word [bp + ?lengths + di + eteBase]
  1211                              <1> 	; xor cx, cx		; cx = 0 already after get_gamma_code NC
  1212 0000017E 8A4BB8              <1> 	mov cl, byte [bp + ?lengths + di + eteBits]
  1213 00000181 E8B700              <1> 	call read_bits		; cx = 0 if NC
  1214                              <1> d0	mov byte [bp + ?errordata], 39h
  1215 00000184 7303E98100          <1> 	jc .error
  1216 00000189 01C3                <1> 	add bx, ax		; bx = length
  1217 0000018B 85DB                <1> 	test bx, bx
  1218 0000018D 7413                <1> 	jz .switch_default
  1219 0000018F 83FB02              <1> 	cmp bx, 2
  1220 00000192 7409                <1> 	je .switch_case2
  1221                              <1> %ifn _P & 16
  1222 00000194 770C                <1> 	ja .switch_default
  1223                              <1> %else
  1224                              <1> 	jb .switch_case1
  1225                              <1> 	cmp bx, 4
  1226                              <1> 	jb .switch_case3
  1227                              <1> 	jmp .switch_default
  1228                              <1> %endif
  1229                              <1> .switch_case1:
  1230 00000196 B102                <1> 	mov cl, 2		; cx = 2
  1231 00000198 BA4CFF              <1> 	mov dx, ?offsets1
  1232                              <1> d0	mov byte [bp + ?errordata], 3Ah
  1233 0000019B EB0A                <1> 	jmp .switch_common
  1234                              <1> 
  1235                              <1> .switch_case2:
  1236 0000019D BA58FF              <1> 	mov dx, ?offsets2
  1237                              <1> d0	mov byte [bp + ?errordata], 3Bh
  1238 000001A0 EB03                <1> 	jmp .switch_common_cl_4
  1239                              <1> 
  1240                              <1> %ifn _P & 16
  1241                              <1> .switch_default:
  1242 000001A2 BA88FF              <1> 	mov dx, ?offsets3
  1243                              <1> d0	mov byte [bp + ?errordata], 3Ch
  1244                              <1> %else
  1245                              <1> .switch_case3:
  1246                              <1> 	mov dx, ?offsets3
  1247                              <1> d0	mov byte [bp + ?errordata], 4Ah
  1248                              <1> 	jmp .switch_common_cl_4
  1249                              <1> 
  1250                              <1> .switch_default:
  1251                              <1> 	mov dx, ?offsets4
  1252                              <1> d0	mov byte [bp + ?errordata], 4Bh
  1253                              <1> %endif
  1254                              <1> 	; jmp .switch_common_cl_4
  1255                              <1> 
  1256                              <1> .switch_common_cl_4:
  1257 000001A5 B104                <1> 	mov cl, 4		; cx = 4
  1258                              <1> 
  1259                              <1> .switch_common:
  1260 000001A7 E89100              <1> 	call read_bits
  1261 000001AA 725E                <1> 	jc .error
  1262                              <1> 				; ax = next index, dx -> next table
  1263 000001AC 89C7                <1> 	mov di, ax
  1264 000001AE 01C0                <1> 	add ax, ax
  1265 000001B0 01C7                <1> 	add di, ax		; di = offset into table
  1266 000001B2 01D7                <1> 	add di, dx		; -> table entry
  1267                              <1> 	; xor cx, cx		; cx already = 0 after read_bits NC
  1268 000001B4 8A0B                <1> 	mov cl, byte [bp + di + eteBits]
  1269 000001B6 E88200              <1> 	call read_bits		; leaves cx = 0 if NC
  1270                              <1> d0	mov byte [bp + ?errordata], 3Dh
  1271 000001B9 724F                <1> 	jc .error
  1272 000001BB 87CB                <1> 	xchg cx, bx		; cx = length that we remembered in bx
  1273                              <1> 				; bx = 0
  1274 000001BD 92                  <1> 	xchg dx, ax		; bx:dx = read bits
  1275                              <1> 
  1276 000001BE 035301              <1> 	add dx, word [bp + di + eteBase]
  1277 000001C1 83D300              <1> 	adc bx, 0		; bx:dx = offset
  1278                              <1> 
  1279                              <1> 	; test bx, bx		; offset 0 ?
  1280 000001C4 7504                <1> 	jnz @F			; no -->
  1281 000001C6 85D2                <1> 	test dx, dx		; offset 0 ?
  1282                              <1> d0	mov byte [bp + ?errordata], 3Eh
  1283 000001C8 7440                <1> 	jz .error		; yes, invalid -->
  1284                              <1> @@:
  1285 000001CA 51                  <1> 	push cx
  1286 000001CB 89D1                <1> 	mov cx, dx
  1287 000001CD F7DB                <1>         neg bx
  1288 000001CF F7D9                <1>         neg cx
  1289 000001D1 83DB00              <1>         sbb bx, byte 0          ; neg bx:cx
  1290 000001D4 FF76F2              <1> 	 push word [bp + ?dst + 2]
  1291 000001D7 FF76F0              <1> 	 push word [bp + ?dst]
  1292 000001DA E83A01              <1> 	call normalise_pointer_with_displacement_bxcx
  1293 000001DD 5E                  <1> 	 pop si
  1294 000001DE 5B                  <1> 	 pop bx			; bx:si = pointer into decompressed data
  1295 000001DF 59                  <1> 	pop cx			; restore match length
  1296                              <1> d0	mov byte [bp + ?errordata], 47h
  1297 000001E0 7328                <1> 	jnc .error
  1298                              <1> 
  1299 000001E2 395EF6              <1> 	cmp word [bp + ?original_dst + 2], bx
  1300                              <1> 				; is source of matching within ?dst ?
  1301                              <1> d0	mov byte [bp + ?errordata], 16h
  1302 000001E5 7723                <1> 	ja .error
  1303 000001E7 7205                <1> 	jb @F
  1304 000001E9 3976F4              <1> 	cmp word [bp + ?original_dst], si
  1305                              <1> d0	mov byte [bp + ?errordata], 17h
  1306 000001EC 771C                <1> 	ja .error		; no, ?original_dst is above it -->
  1307                              <1> @@:
  1308 000001EE 8EDB                <1> 	mov ds, bx		; -> match source data
  1309 000001F0 E8AF00              <1> 	call copy_data
  1310                              <1> d0	mov byte [bp + ?errordata], 3Fh
  1311 000001F3 7215                <1> 	jc .error
  1312                              <1> 
  1313                              <1> %if _ALLOW_OVERLAPPING
  1314 000001F5 E8D600              <1> 	call check_pointers_not_overlapping
  1315                              <1> d0	mov byte [bp + ?errordata], 1Ch
  1316 000001F8 7210                <1> 	jc .error
  1317                              <1> %endif
  1318 000001FA E92AFF              <1> 	jmp .STATE_NEXT_BYTE
  1319                              <1> 
  1320                              <1> .end_check:
  1321                              <1> d0	mov byte [bp + ?errordata], 40h
  1322 000001FD 837EEE00            <1> 	cmp word [bp + ?src_remaining + 2], 0
  1323 00000201 7507                <1> 	jne .error
  1324 00000203 837EEC0F            <1> 	cmp word [bp + ?src_remaining], 15
  1325 00000207 7701                <1> 	ja .error
  1326                              <1> .end:
  1327 00000209 A8                  <1> 	db __TEST_IMM8			; (NC)
  1328                              <1> .error:
  1329 0000020A F9                  <1> 	stc
  1330                              <1> 
  1331                              <1> %if _COUNTER
  1332                              <1> 	lahf
  1333                              <1> 	mov al, 13
  1334                              <1> 	call disp_al
  1335                              <1> 	mov al, 10
  1336                              <1> 	call disp_al
  1337                              <1> 	sahf
  1338                              <1> %endif
  1339                              <1> d0	mov bx, word [bp + ?errordata]
  1340 0000020B 89EC5D              <1> 	lleave code
  1341 0000020E C3                  <1> 	lret
  1342                              <1> 
  1343                              <1> 
  1344                              <1> 		; INP:	?src
  1345                              <1> 		;	?src_remaining
  1346                              <1> 		; OUT:	CY if error (source exhausted)
  1347                              <1> 		;	NC if success,
  1348                              <1> 		;	 al = byte read from source
  1349                              <1> 		;	 ?src
  1350                              <1> 		;	 ?src_remaining
  1351                              <1> 		; CHG:	ds, si
  1352                              <1> 		; STT:	bp -> depack stack frame
  1353                              <1> 		;	UP
  1354                              <1> read_byte:
  1355 0000020F C576F8              <1> 	lds si, [bp + ?src]
  1356 00000212 AC                  <1> 	lodsb
  1357 00000213 1E                  <1> 	 push ds
  1358 00000214 56                  <1> 	 push si
  1359 00000215 E8E300              <1> 	call normalise_pointer
  1360 00000218 8F46F8              <1> 	 pop word [bp + ?src]
  1361 0000021B 8F46FA              <1> 	 pop word [bp + ?src + 2]
  1362 0000021E 836EEC01            <1> 	sub word [bp + ?src_remaining], 1
  1363 00000222 835EEE00            <1> 	sbb word [bp + ?src_remaining + 2], 0
  1364 00000226 C3                  <1> 	retn
  1365                              <1> 
  1366                              <1> 
  1367                              <1> 		; as for read_byte
  1368                              <1> 		; OUT:	CY if error
  1369                              <1> 		;	NC if success,
  1370                              <1> 		;	 ?bit_buffer
  1371                              <1> 		; CHG:	al, ds, si
  1372                              <1> read_byte_to_bit_buffer:
  1373 00000227 E8E5FF              <1> 	call read_byte
  1374 0000022A 8846FC              <1> 	mov byte [bp + ?bit_buffer], al
  1375 0000022D C3                  <1> 	retn
  1376                              <1> 
  1377                              <1> 
  1378                              <1> 		; INP:	CF = carry in
  1379                              <1> 		;	?bit_buffer
  1380                              <1> 		; OUT:	CF = carry out
  1381                              <1> 		;	ZF = whether ?bit_buffer is now zero
  1382                              <1> 		;	?bit_buffer
  1383                              <1> 		; CHG:	-
  1384                              <1> 		; STT:	bp -> depack stack frame
  1385                              <1> bitbuffer_rotate:
  1386                              <1> %if _P & 1
  1387 0000022E D056FC              <1> 	rcl byte [bp + ?bit_buffer], 1
  1388                              <1> %else
  1389                              <1> 	rcr byte [bp + ?bit_buffer], 1
  1390                              <1> %endif
  1391 00000231 FE4EFC              <1> 	dec byte [bp + ?bit_buffer]
  1392 00000234 FE46FC              <1> 	inc byte [bp + ?bit_buffer]	; this is to set ZF and preserve CF
  1393 00000237 C3                  <1> 	retn
  1394                              <1> 
  1395                              <1> 
  1396                              <1> read_bits_1:
  1397 00000238 B90100              <1> 	mov cx, 1
  1398                              <1> 
  1399                              <1> 		; INP:	cl = cx = number of bits to read (0..15)
  1400                              <1> 		; OUT:	CY if error (cx too high or source exhausted)
  1401                              <1> 		;	NC if success,
  1402                              <1> 		;	 ax = read data
  1403                              <1> 		;	 cx = 0
  1404                              <1> 		; CHG:	ds, si
  1405                              <1> 		; STT:	bp -> depack stack frame
  1406                              <1> 		;	UP
  1407                              <1> read_bits:
  1408                              <1> %if _P & 2
  1409 0000023B 83F910              <1> 	cmp cx, 16		; CY if valid
  1410                              <1> %else
  1411                              <1> 	cmp cx, 17		; CY if valid
  1412                              <1> %endif
  1413 0000023E F5                  <1> 	cmc			; NC if valid
  1414 0000023F 722B                <1> 	jc .ret			; if error --> (CY)
  1415                              <1> %if _P & 2
  1416 00000241 88C8                <1> 	mov al, cl
  1417 00000243 88CC                <1> 	mov ah, cl
  1418 00000245 250708              <1> 	and ax, (8 << 8) | 7	; al = bit_count, ah = byte_copy
  1419 00000248 88C1                <1> 	mov cl, al		; cl = cx = bit_count
  1420 0000024A B000                <1> 	mov al, 0		; al = bits
  1421                              <1> %else
  1422                              <1> 	xor ax, ax		; ax = bits
  1423                              <1> %endif
  1424 0000024C E315                <1> 	jcxz .end
  1425                              <1> .loop:
  1426 0000024E F8                  <1> 	clc
  1427 0000024F E8DCFF              <1> 	call bitbuffer_rotate
  1428 00000252 750B                <1> 	jnz .notzero
  1429 00000254 50                  <1> 	push ax
  1430 00000255 E8CFFF              <1> 	call read_byte_to_bit_buffer
  1431 00000258 58                  <1> 	pop ax
  1432 00000259 7211                <1> 	jc .ret			; if error --> (CY)
  1433 0000025B F9                  <1> 	stc
  1434 0000025C E8CFFF              <1> 	call bitbuffer_rotate
  1435                              <1> .notzero:
  1436                              <1> %if _P & 2
  1437 0000025F D0D0                <1> 	rcl al, 1		; bits <<= 1; bits |= carry;
  1438                              <1> %else
  1439                              <1> 	rcl ax, 1
  1440                              <1> %endif
  1441 00000261 E2EB                <1> 	loop .loop
  1442                              <1> .end:
  1443                              <1> %if _P & 2
  1444 00000263 84E4                <1> 	test ah, ah		; NC
  1445 00000265 7405                <1> 	jz .byte_copy_zero	; (NC)
  1446 00000267 88C4                <1> 	mov ah, al		; bits <<= 8;
  1447 00000269 E8A3FF              <1> 	call read_byte		; bits |= read_byte()
  1448                              <1> 				; pass CF to caller
  1449                              <1> .byte_copy_zero:		; ax = bits
  1450                              <1> %endif
  1451                              <1> .ret:
  1452 0000026C C3                  <1> 	retn
  1453                              <1> 
  1454                              <1> 
  1455                              <1> generate_table_16:
  1456 0000026D B91000              <1> 	mov cx, 16
  1457                              <1> 		; INP:	cx = amount of table entries
  1458                              <1> 		;	bp + di -> start of table
  1459                              <1> 		; OUT:	CY if error
  1460                              <1> 		;	NC if success,
  1461                              <1> 		;	 cx = 0
  1462                              <1> 		; CHG:	ax, bx, di, ds, si
  1463                              <1> 		; STT:	bp -> depack stack frame
  1464                              <1> 		;	UP
  1465                              <1> generate_table_cx:
  1466 00000270 BB0100              <1> 	mov bx, 1
  1467                              <1> .loop:
  1468 00000273 895B01              <1> 	mov word [bp + di + eteBase], bx
  1469 00000276 51                  <1> 	push cx
  1470                              <1> %if _P & 2
  1471 00000277 B90300              <1> 	mov cx, 3
  1472 0000027A E8BEFF              <1> 	call read_bits
  1473 0000027D 7221                <1> 	jc .ret_pop
  1474 0000027F 8803                <1> 	mov byte [bp + di + eteBits], al
  1475 00000281 B101                <1> 	mov cl, 1
  1476 00000283 E8B5FF              <1> 	call read_bits
  1477 00000286 7218                <1> 	jc .ret_pop
  1478 00000288 D0E0                <1> 	shl al, 1
  1479 0000028A D0E0                <1> 	shl al, 1
  1480 0000028C D0E0                <1> 	shl al, 1
  1481 0000028E 0803                <1> 	or byte [bp + di + eteBits], al
  1482 00000290 B80100              <1> 	mov ax, 1
  1483 00000293 8A0B                <1> 	mov cl, byte [bp + di + eteBits]
  1484                              <1> %else
  1485                              <1> 	mov cx, 4
  1486                              <1> 	call read_bits
  1487                              <1> 	jc .ret_pop
  1488                              <1> 	mov byte [bp + di + eteBits], al
  1489                              <1> 	mov cl, al
  1490                              <1> 	mov ax, 1
  1491                              <1> %endif
  1492 00000295 D3E0                <1> 	shl ax, cl
  1493 00000297 01C3                <1> 	add bx, ax
  1494 00000299 59                  <1> 	pop cx
  1495 0000029A 83C703              <1> 	add di, exo_table_entry_size
  1496 0000029D E2D4                <1> 	loop .loop
  1497 0000029F A8                  <1> 	db __TEST_IMM8		; (skip pop, NC)
  1498                              <1> .ret_pop:
  1499 000002A0 59                  <1> 	pop cx
  1500 000002A1 C3                  <1> 	retn
  1501                              <1> 
  1502                              <1> 
  1503                              <1> 		; INP:	ds:si -> data (normalised and in bounds)
  1504                              <1> 		;	?dst (normalised), ?dst_remaining
  1505                              <1> 		;	cx = number of bytes (entire range valid)
  1506                              <1> 		; OUT:	CY if error (destination exhausted)
  1507                              <1> 		;	NC if success,
  1508                              <1> 		;	 ds:si -> behind copied source (normalised)
  1509                              <1> 		;	 ?dst -> behind copied destination (normalised)
  1510                              <1> 		;	 ?dst_remaining decremented
  1511                              <1> 		;	 ax = cx = 0
  1512                              <1> 		;	Instead of returning, this may jump to depack.end
  1513                              <1> 		;	 if the destination segment grows up to the value
  1514                              <1> 		;	 stored in the ?dst_max_segment variable. It is
  1515                              <1> 		;	 assumed that this will use the stack frame to leave
  1516                              <1> 		;	 the function, therefore discarding any of the stack
  1517                              <1> 		;	 contents between the frame and the stack top.
  1518                              <1> 		; CHG:	es, di
  1519                              <1> 		; STT:	bp -> depack stack frame
  1520                              <1> 		;	UP
  1521                              <1> copy_data:
  1522                              <1> d0	inc byte [bp + ?errordata + 1]
  1523                              <1> 
  1524 000002A2 294EE8              <1> 	sub word [bp + ?dst_remaining], cx
  1525 000002A5 835EEA00            <1> 	sbb word [bp + ?dst_remaining + 2], 0
  1526 000002A9 7222                <1> 	jc .ret
  1527 000002AB C47EF0              <1> 	les di, [bp + ?dst]
  1528                              <1> 
  1529 000002AE 31C0                <1> 	xor ax, ax			; initialise second step length
  1530 000002B0 83F9F0              <1> 	cmp cx, 0FFF0h			; can copy in one step ?
  1531 000002B3 760C                <1> 	jbe @F				; yes -->
  1532 000002B5 88C8                <1> 	mov al, cl
  1533 000002B7 240F                <1> 	and al, 15			; second step length
  1534 000002B9 B1F0                <1> 	mov cl, 0F0h			; maximum first step = 0FFF0h
  1535 000002BB F3A4                <1> 	rep movsb			; move first step of two steps
  1536 000002BD E82C00              <1> 	call normalise_both_pointers	; normalise pointers after
  1537 000002C0 91                  <1> 	xchg ax, cx			; cx = second step length
  1538                              <1> @@:
  1539 000002C1 F3A4                <1> 	rep movsb			; move last step
  1540 000002C3 E82600              <1> 	call normalise_both_pointers	; normalise (again)
  1541 000002C6 897EF0              <1> 	mov word [bp + ?dst], di
  1542 000002C9 8C46F2              <1> 	mov word [bp + ?dst + 2], es	; store to ?dst
  1543                              <1> %if _PAYLOAD_KERNEL_MAX_PARAS
  1544                              <1> 	mov di, es			; ! this is the *segment*
  1545                              <1> 	cmp di, word [bp + ?dst_max_segment]
  1546                              <1> 	jae depack.end
  1547                              <1> %endif
  1548 000002CC F8                  <1> 	clc
  1549                              <1> .ret:
  1550 000002CD C3                  <1> 	retn
   909                                  %endif
   910                                  
   911                                  
   912                                  %if _X
   913                                  	%include "x.asm"
   914                                  %endif
   915                                  
   916                                  
   917                                  %if _HEATSHRINK
   918                                  	%include "heatshr.asm"
   919                                  %endif
   920                                  
   921                                  
   922                                  %if _LZD
   923                                  	%include "lzd.asm"
   924                                  %endif
   925                                  
   926                                  
   927                                  %if _LZO
   928                                  	%include "lzo.asm"
   929                                  %endif
   930                                  
   931                                  
   932                                  %if _LZSA2
   933                                  	%include "lzsa2.asm"
   934                                  %endif
   935                                  
   936                                  
   937                                  %if _APL
   938                                  	%include "apl.asm"
   939                                  %endif
   940                                  
   941                                  
   942                                  %if _BZP
   943                                  	%include "bzp.asm"
   944                                  %endif
   945                                  
   946                                  
   947                                  %if _ALLOW_OVERLAPPING
   948                                  		; INP:	?src, ?dst
   949                                  		; OUT:	CY if error (?src < ?dst)
   950                                  		;	NC if success
   951                                  		; CHG:	ax, bx, cx, dx
   952                                  check_pointers_not_overlapping:
   953                                  %if CHECK_POINTERS_VARIABLE_DST
   954 000002CE FF76F2                  	 push word [bp + ?dst + 2]
   955 000002D1 FF76F0                  	 push word [bp + ?dst]
   956                                  %else
   957                                  	 push es
   958                                  	 push di
   959                                  %endif
   960 000002D4 E86F00                  	call pointer_to_linear
   961                                  
   962 000002D7 91                      	xchg cx, ax
   963 000002D8 87DA                    	xchg bx, dx			; bx:cx = linear ?dst after write
   964                                  
   965                                  %if CHECK_POINTERS_VARIABLE_SRC
   966 000002DA FF76FA                  	 push word [bp + ?src + 2]
   967 000002DD FF76F8                  	 push word [bp + ?src]
   968                                  %else
   969                                  	 push ds
   970                                  	 push si
   971                                  %endif
   972 000002E0 E86300                  	call pointer_to_linear		; dx:ax = linear ?src before next read
   973                                  
   974 000002E3 39DA                    	cmp dx, bx			; ?src >= ?dst ?
   975 000002E5 7704                    	ja @F
   976 000002E7 7202                    	jb .ret				; (CY)
   977 000002E9 39C8                    	cmp ax, cx
   978                                  	; jb .ret			; (CY)
   979                                  					; (NC) yes, no error
   980                                  @@:
   981                                  .ret:
   982 000002EB C3                      	retn
   983                                  %endif
   984                                  
   985                                  	; This leaves the lframe context created within the
   986                                  	;  specific depacker's file. The above function
   987                                  	;  check_pointers_not_overlapping uses the frame.
   988                                  	lleave ctx
   989                                  
   990                                  
   991                                  		; INP:	ds:si = pointer
   992                                  		;	es:di = pointer
   993                                  		; OUT:	ds:si normalised
   994                                  		;	es:di normalised
   995                                  normalise_both_pointers:
   996 000002EC 06                      	 push es
   997 000002ED 57                      	 push di
   998 000002EE E80A00                  	call normalise_pointer
   999 000002F1 5F                      	 pop di
  1000 000002F2 07                      	 pop es
  1001                                  
  1002                                  normalise_dssi_pointer:
  1003 000002F3 1E                      	 push ds
  1004 000002F4 56                      	 push si
  1005 000002F5 E80300                  	call normalise_pointer
  1006 000002F8 5E                      	 pop si
  1007 000002F9 1F                      	 pop ds
  1008 000002FA C3                      	retn
  1009                                  
  1010                                  
  1011                                  		; INP:	word [ss:sp + 2] = segment
  1012                                  		;	word [ss:sp] = offset
  1013                                  		;
  1014                                  		; Note:	Does not work correctly with pointers that point to
  1015                                  		;	 a HMA location. Do not use then!
  1016                                  normalise_pointer:
  1017                                  %if NEED_NORMALISE_POINTER_WITH_DISPLACEMENT
  1018                                  	lframe near
  1019                                  	lpar word,	segment
  1020                                  	lpar word,	offset
  1021                                  	lpar_return
  1022 000002FB 5589E5                  	lenter
  1023 000002FE 53                      	push bx
  1024 000002FF 51                      	push cx
  1025                                  
  1026 00000300 31DB                    	xor bx, bx
  1027 00000302 31C9                    	xor cx, cx
  1028 00000304 FF7606                  	 push word [bp + ?segment]
  1029 00000307 FF7604                  	 push word [bp + ?offset]
  1030 0000030A E80A00                  	call normalise_pointer_with_displacement_bxcx
  1031 0000030D 8F4604                  	 pop word [bp + ?offset]
  1032 00000310 8F4606                  	 pop word [bp + ?segment]
  1033                                  
  1034 00000313 59                      	pop cx
  1035 00000314 5B                      	pop bx
  1036 00000315 5D                      	lleave
  1037 00000316 C3                      	lret
  1038                                  
  1039                                  
  1040                                  		; INP:	word [ss:sp + 2] = segment
  1041                                  		;	word [ss:sp] = offset
  1042                                  		;	bx:cx = add/sub displacement
  1043                                  		; OUT:	CY if the displacement carries
  1044                                  		;	NC if not
  1045                                  normalise_pointer_with_displacement_bxcx:
  1046                                  %endif
  1047                                  	lframe near
  1048                                  	lpar word,	segment
  1049                                  	lpar word,	offset
  1050                                  	lpar_return
  1051 00000317 5589E5                  	lenter
  1052 0000031A 50                      	push ax
  1053 0000031B 51                      	push cx
  1054 0000031C 52                      	push dx
  1055                                  
  1056 0000031D FF7606                  	 push word [bp + ?segment]
  1057 00000320 FF7604                  	 push word [bp + ?offset]
  1058 00000323 E82000                  	call pointer_to_linear
  1059                                  
  1060                                  %if NEED_NORMALISE_POINTER_WITH_DISPLACEMENT
  1061                                  	; push bx
  1062                                  	; 				; sign-extend cx into bx:cx
  1063                                  	; cmp cx, 8000h			; CY if < 8000h (NC if negative)
  1064                                  	; cmc				; NC if positive
  1065                                  	; sbb bx, bx			; 0 if was NC, -1 if was CY
  1066                                  
  1067 00000326 01C1                    	add cx, ax
  1068 00000328 11DA                    	adc dx, bx			; dx:cx = dx:ax + bx:cx
  1069                                  	; pop bx
  1070 0000032A 9F                      	lahf				; ah = flags
  1071                                  %else
  1072                                  	xchg ax, cx
  1073                                  %endif
  1074                                  
  1075                                  %if 0
  1076                                  		; Adds in HMA support for this function. Not currently used.
  1077                                  	cmp dx, 10h			; dx:ax >= 10_0000h ?
  1078                                  	jb @F				; no, linear-to-pointer normally -->
  1079                                  	; ja .error
  1080                                  
  1081                                  	add cx, 10h
  1082                                  	; jc .error
  1083                                  	mov word [bp + ?offset], cx
  1084                                  	or word [bp + ?segment], -1
  1085                                  	jmp .return
  1086                                  @@:
  1087                                  %endif
  1088                                  
  1089 0000032B 53                      	push bx
  1090 0000032C 89CB                    	mov bx, cx
  1091 0000032E 83E10F                  	and cx, 15
  1092 00000331 894E04                  	mov word [bp + ?offset], cx
  1093                                  
  1094 00000334 B104                    	mov cl, 4
  1095                                  @@:
  1096 00000336 D1EA                    	shr dx, 1
  1097 00000338 D1DB                    	rcr bx, 1
  1098 0000033A E2FA                    	loop @B
  1099                                  
  1100 0000033C 895E06                  	mov word [bp + ?segment], bx
  1101 0000033F 5B                      	pop bx
  1102                                  
  1103                                  	; test dx, dx
  1104                                  	; jnz .error
  1105                                  
  1106                                  .return:
  1107                                  
  1108                                  %if NEED_NORMALISE_POINTER_WITH_DISPLACEMENT
  1109 00000340 9E                      	sahf				; restore flags from ah
  1110                                  %endif
  1111 00000341 5A                      	pop dx
  1112 00000342 59                      	pop cx
  1113 00000343 58                      	pop ax
  1114 00000344 5D                      	lleave
  1115 00000345 C3                      	lret
  1116                                  
  1117                                  
  1118                                  		; INP:	word [ss:sp + 2] = segment
  1119                                  		;	word [ss:sp] = offset
  1120                                  		; OUT:	dx:ax = linear address
  1121                                  pointer_to_linear:
  1122                                  	lframe near
  1123                                  	lpar word,	segment
  1124                                  	lpar word,	offset
  1125 00000346 5589E5                  	lenter
  1126                                  
  1127 00000349 8B4606                  	mov ax, word [bp + ?segment]
  1128 0000034C 31D2                    	xor dx, dx
  1129 0000034E 51                      	push cx
  1130 0000034F B90400                  	mov cx, 4
  1131                                  @@:
  1132 00000352 D1E0                    	shl ax, 1
  1133 00000354 D1D2                    	rcl dx, 1
  1134 00000356 E2FA                    	loop @B
  1135                                  
  1136 00000358 034604                  	add ax, word [bp + ?offset]
  1137 0000035B 11CA                    	adc dx, cx			; cx = 0 here
  1138 0000035D 59                      	pop cx
  1139                                  
  1140 0000035E 5D                      	lleave
  1141 0000035F C20400                  	lret
  1142                                  
  1143                                  
  1144 00000362 90<rep Eh>              	align 16
  1145                                  init1_end:
  1146                                  
  1147                                  
  1148                                  	section INIT0
  1149                                  %if _TEST_PROGRAM
  1150                                  init0_msg:
  1151                                  .error_stderr:	db "Error: Not enough memory allocated.",13,10
  1152                                  .error_stderr.length: equ $ - .error_stderr
  1153                                  .error_stdout:	_autodigits paras(_TEST_PROGRAM_DECOMPRESSED_SIZE 				+ (payload_end - payload) 				+ (init1_end - init1_start) 				+ ADDITIONAL_MEMORY 				)
  1158                                  		db 13,10
  1159                                  .error_stdout.length: equ $ - .error_stdout
  1160                                  
  1161                                  	align 512
  1162                                  %if ($ - $$) != 512
  1163                                   %error Wrong INIT0 size
  1164                                  %endif
  1165                                  %endif
  1166                                  
  1167 000000E7 90<rep 9h>              	align 16
  1168                                  init0_end:
  1169                                  
  1170                                  
  1171                                  %assign num (init1_end - init1_start) + (init0_end - init0_start)
  1172                                  %if _BRIEFLZ
  1173                                  %define which iniblz
  1174                                  %elif _LZ4
  1175                                  %define which inilz4
  1176                                  %elif _SNAPPY
  1177                                  %define which inisz
  1178                                  %elif _EXODECR
  1179                                  %define which iniexo
  1180                                  %elif _X
  1181                                  %define which inix
  1182                                  %elif _HEATSHRINK
  1183                                  %define which inihs
  1184                                  %elif _LZD
  1185                                  %define which inilz
  1186                                  %elif _LZO
  1187                                  %define which inilzo
  1188                                  %elif _LZSA2
  1189                                  %define which inilzsa2
  1190                                  %elif _APL
  1191                                  %define which iniapl
  1192                                  %elif _BZP
  1193                                  %define which inibzp
  1194                                  %endif
  1195                                  %warning which: num bytes used for depacker
  1195          ******************       warning: iniexo: 1120 bytes used for depacker [-w+user]
  1196                                  
  1197                                  
  1198                                  %if _TEST_PROGRAM
  1199                                  	section INIT2 align=16 follows=INIT1 vstart=0
  1200                                  init2_start:
  1201                                  		; si => after PSP
  1202                                  		; cs => INIT2
  1203                                  		; psp, free, payload, init1, init2, payload space, stack
  1204                                  		;
  1205                                  		; The correct allocation for the test program
  1206                                  		;  is image size (init0, payload, init1, init2)
  1207                                  		;  minus init0 plus compressed payload size
  1208                                  		;  plus decompressed size plus stack. For
  1209                                  		;  simplicity, init0 subtraction may be skipped.
  1210                                  	mov dx, cs
  1211                                  	add dx, (init2_end - init2_start) >> 4
  1212                                  				; => payload saving area
  1213                                  	mov ax, cs
  1214                                  	sub ax, ( (init1_end - init1_start) 		+ (payload_end - payload) 		) >> 4		; => payload source for first run
  1217                                  	mov cx, (payload_end - payload) >> 4
  1218                                  	call init2_movp		; copy payload to payload saving area
  1219                                  		; We save away the payload here because a failure
  1220                                  		;  to decompress generally overwrites part of that
  1221                                  		;  payload which was used as source.
  1222                                  
  1223                                  	mov dx, ax		; dx => payload source to use
  1224                                  	mov ax, cs
  1225                                  	sub ax, (init1_end - init1_start) >> 4
  1226                                  				; ax => INIT1
  1227                                  	mov bx, 1		; say we're in EXE mode
  1228                                  	push dx
  1229                                  	push ax
  1230                                  	push si			; si => target
  1231                                  	push cs
  1232                                  	call .transfer		; call decompression
  1233                                  	pop si
  1234                                  	pop ax
  1235                                  	pop dx
  1236                                  		; Returns here after decompression.
  1237                                  		; CY if error.
  1238                                  	jnc @F
  1239                                  
  1240                                  	mov dx, init2_msg.initial_error
  1241                                  	mov cx, init2_msg.initial_error.length
  1242                                  	jmp init2_error
  1243                                  
  1244                                  @@:
  1245                                  	numdef INCLUDE_UNCOMPRESSED
  1246                                  	numdef WRITE_WRONG_FILE
  1247                                  %if _INCLUDE_UNCOMPRESSED
  1248                                  payload_uncompressed_size equ payload_uncompressed.end - payload_uncompressed
  1249                                  
  1250                                  	call checkdecompressed
  1251                                  	je @F
  1252                                  
  1253                                  %if _WRITE_WRONG_FILE
  1254                                  	call writefiles
  1255                                  %endif
  1256                                  
  1257                                  %if _DEBUG0
  1258                                  	mov bx, -1
  1259                                  %endif
  1260                                  	mov dx, init2_msg.initial_error_2
  1261                                  	mov cx, init2_msg.initial_error_2.length
  1262                                  	jmp init2_error
  1263                                  
  1264                                  @@:
  1265                                  %endif
  1266                                  
  1267                                  	lframe
  1268                                  	lenter
  1269                                  	lvar word,	upperbound
  1270                                  	 push dx
  1271                                  	lvar word,	lowerbound
  1272                                  	 push si
  1273                                  	lvar word,	current_init1
  1274                                  	 push ax
  1275                                  
  1276                                  %if _TEST_PROGRESS
  1277                                  	mov dx, init2_msg.progress.1
  1278                                  	mov cx, init2_msg.progress.1.length
  1279                                  .loop:
  1280                                  	push cs
  1281                                  	pop ds
  1282                                  	mov bx, 2
  1283                                  	mov ah, 40h
  1284                                  	int 21h
  1285                                  %else
  1286                                  .loop:
  1287                                  %endif
  1288                                  
  1289                                  	mov dx, [bp + ?upperbound]
  1290                                  	sub dx, [bp + ?lowerbound]
  1291                                  	jz .found
  1292                                  	shr dx, 1
  1293                                  		; Rounding down, so that we never retry upper bound.
  1294                                  		;  The upper bound is known to be working.
  1295                                  	add dx, [bp + ?lowerbound]
  1296                                  	push dx
  1297                                  	add dx, (payload_end - payload) >> 4
  1298                                  	mov ax, [bp + ?current_init1]
  1299                                  	mov cx, (init1_end - init1_start) >> 4
  1300                                  	call init2_movp
  1301                                  	mov [bp + ?current_init1], dx
  1302                                  	pop dx
  1303                                  
  1304                                  	mov ax, cs
  1305                                  	add ax, (init2_end - init2_start) >> 4
  1306                                  				; => payload in saving area
  1307                                  	mov cx, (payload_end - payload) >> 4
  1308                                  	call init2_movp		; copy payload from payload saving area
  1309                                  
  1310                                  		; dx => source
  1311                                  	mov ax, [bp + ?current_init1]
  1312                                  	mov bx, 1
  1313                                  	push dx
  1314                                  	push si
  1315                                  	push cs
  1316                                  	call .transfer
  1317                                  	pop si
  1318                                  	pop dx
  1319                                  		; Returns here after decompression.
  1320                                  		; CY if error.
  1321                                  	jnc @F
  1322                                  		; error: this attempt is one below the new lower bound
  1323                                  	inc dx
  1324                                  	mov word [bp + ?lowerbound], dx
  1325                                  %if _TEST_PROGRESS
  1326                                  	mov dx, init2_msg.progress.fail
  1327                                  	mov cx, init2_msg.progress.fail.length
  1328                                  %endif
  1329                                  	jmp .loop
  1330                                  
  1331                                  @@:
  1332                                  %if _INCLUDE_UNCOMPRESSED
  1333                                  	call checkdecompressed
  1334                                  	je @F
  1335                                  
  1336                                  %if _WRITE_WRONG_FILE
  1337                                  	call writefiles
  1338                                  %endif
  1339                                  
  1340                                  %if _TEST_PROGRESS
  1341                                  	push cs
  1342                                  	pop ds
  1343                                  	mov dx, init2_msg.progress.linebreak
  1344                                  	mov cx, init2_msg.progress.linebreak.length
  1345                                  	mov bx, 2
  1346                                  	mov ah, 40h
  1347                                  	int 21h
  1348                                  %endif
  1349                                  %if _DEBUG0
  1350                                  	mov bx, -2
  1351                                  %endif
  1352                                  	mov dx, init2_msg.subsequent_error_2
  1353                                  	mov cx, init2_msg.subsequent_error_2.length
  1354                                  	jmp init2_error
  1355                                  
  1356                                  @@:
  1357                                  %endif
  1358                                  		; success: this attempt is the new upper bound
  1359                                  	mov word [bp + ?upperbound], dx
  1360                                  %if _TEST_PROGRESS
  1361                                  	mov dx, init2_msg.progress.success
  1362                                  	mov cx, init2_msg.progress.success.length
  1363                                  %endif
  1364                                  	jmp .loop
  1365                                  
  1366                                  .found:
  1367                                  %if _TEST_PROGRESS
  1368                                  	push cs
  1369                                  	pop ds
  1370                                  	mov dx, init2_msg.progress.linebreak
  1371                                  	mov cx, init2_msg.progress.linebreak.length
  1372                                  	mov bx, 2
  1373                                  	mov ah, 40h
  1374                                  	int 21h
  1375                                  %endif
  1376                                  	mov ax, word [bp + ?upperbound]
  1377                                  	sub ax, si		; = how many paragraphs in buffer before source
  1378                                  	add ax, paras( (init1_end - init1_start) 			+ (payload_end - payload) )
  1380                                  				; = how many paragraphs needed for process
  1381                                  	call init2_disp_ax_dec
  1382                                  	mov al, 13
  1383                                  	call init2_disp_al
  1384                                  	mov al, 10
  1385                                  	call init2_disp_al
  1386                                  	mov ax, 4C00h
  1387                                  	int 21h
  1388                                  
  1389                                  	lleave ctx
  1390                                  
  1391                                  
  1392                                  .transfer:
  1393                                  	xor di, di
  1394                                  	push di			; dummy ax value on stack
  1395                                  	push ax			; INIT1 segment
  1396                                  	push di			; zero = init1_start
  1397                                  	retf
  1398                                  
  1399                                  
  1400                                  
  1401                                  %if _INCLUDE_UNCOMPRESSED
  1402                                  
  1403                                  
  1404                                  %if _WRITE_WRONG_FILE
  1405                                  writefiles:
  1406                                  	push cs
  1407                                  	pop ds
  1408                                  	mov dx, init2_msg.wrong_file_name
  1409                                  	xor cx, cx
  1410                                  	mov ah, 3Ch
  1411                                  	int 21h
  1412                                  	jc .notfile
  1413                                  
  1414                                  	mov bx, ax
  1415                                  	mov cx, payload_uncompressed_size >> 4
  1416                                  	xor dx, dx
  1417                                  .loopfile:
  1418                                  	mov ds, si
  1419                                  	mov ah, 40h
  1420                                  	push cx
  1421                                  	mov cx, 16
  1422                                  	int 21h
  1423                                  	pop cx
  1424                                  	inc si
  1425                                  	loop .loopfile
  1426                                  
  1427                                  	mov ds, si
  1428                                  	mov cx, payload_uncompressed_size & 15
  1429                                  	mov ah, 40h
  1430                                  	int 21h
  1431                                  
  1432                                  	mov ah, 3Eh
  1433                                  	int 21h
  1434                                  
  1435                                  .notfile:
  1436                                  
  1437                                  	push cs
  1438                                  	pop ds
  1439                                  	mov dx, init2_msg.wrong_file_name2
  1440                                  	xor cx, cx
  1441                                  	mov ah, 3Ch
  1442                                  	int 21h
  1443                                  	jc .notfile2
  1444                                  
  1445                                  	mov bx, ax
  1446                                  	mov cx, payload_uncompressed_size >> 4
  1447                                  	mov si, cs
  1448                                  	add si, (payload_uncompressed - init2_start) >> 4
  1449                                  	xor dx, dx
  1450                                  .loopfile2:
  1451                                  	mov ds, si
  1452                                  	mov ah, 40h
  1453                                  	push cx
  1454                                  	mov cx, 16
  1455                                  	int 21h
  1456                                  	pop cx
  1457                                  	inc si
  1458                                  	loop .loopfile2
  1459                                  
  1460                                  	mov ds, si
  1461                                  	mov cx, payload_uncompressed_size & 15
  1462                                  	mov ah, 40h
  1463                                  	int 21h
  1464                                  
  1465                                  	mov ah, 3Eh
  1466                                  	int 21h
  1467                                  
  1468                                  .notfile2:
  1469                                  	retn
  1470                                  %endif
  1471                                  
  1472                                  		; INP:	si => decompressed image
  1473                                  		; OUT:	ZR if matching
  1474                                  		;	NZ if mismatching
  1475                                  		; CHG:	es, ds, di, bx, cx
  1476                                  		; STT:	UP
  1477                                  checkdecompressed:
  1478                                  	push ax
  1479                                  	push dx
  1480                                  	push si
  1481                                  %if _PAYLOAD_KERNEL_MAX_PARAS
  1482                                  	mov cx, _PAYLOAD_KERNEL_MAX_PARAS
  1483                                  	mov bx, 0
  1484                                  %else
  1485                                  	mov cx, payload_uncompressed_size >> 4
  1486                                  	mov bx, payload_uncompressed_size & 15
  1487                                  %endif
  1488                                  	mov di, cs
  1489                                  	add di, (payload_uncompressed - init2_start) >> 4
  1490                                  	jcxz .end
  1491                                  .loop:
  1492                                  	push cx
  1493                                  	mov cx, 8
  1494                                  	mov ds, si
  1495                                  	mov es, di
  1496                                  	inc si
  1497                                  	inc di
  1498                                  	push si
  1499                                  	push di
  1500                                  	xor si, si
  1501                                  	xor di, di
  1502                                  	repe cmpsw
  1503                                  	pop di
  1504                                  	pop si
  1505                                  	pop cx
  1506                                  	jne .ret
  1507                                  	loop .loop
  1508                                  .end:
  1509                                  	mov ds, si
  1510                                  	mov es, di
  1511                                  	xor si, si
  1512                                  	xor di, di		; (ZR)
  1513                                  	mov cx, bx
  1514                                  	repe cmpsb
  1515                                  .ret:
  1516                                  	pop si
  1517                                  	pop dx
  1518                                  	pop ax
  1519                                  	retn
  1520                                  %endif
  1521                                  
  1522                                  
  1523                                  init2_error:
  1524                                  %if _DEBUG0
  1525                                  	push bx
  1526                                  %endif
  1527                                  	push cs
  1528                                  	pop ds
  1529                                  	mov bx, 2
  1530                                  	mov ah, 40h
  1531                                  	int 21h
  1532                                  
  1533                                  %if _DEBUG0
  1534                                  	mov dx, init2_msg.rc
  1535                                  	mov cx, init2_msg.rc.length
  1536                                  	mov bx, 2
  1537                                  	mov ah, 40h
  1538                                  	int 21h
  1539                                  	pop ax
  1540                                  	call init2_error_disp_ax_hex
  1541                                  	mov dx, init2_msg.linebreak
  1542                                  	mov cx, init2_msg.linebreak.length
  1543                                  	mov bx, 2
  1544                                  	mov ah, 40h
  1545                                  	int 21h
  1546                                  %endif
  1547                                  
  1548                                  	mov dx, init2_msg.error_stdout
  1549                                  	mov cx, init2_msg.error_stdout.length
  1550                                  	mov bx, 1
  1551                                  	mov ah, 40h
  1552                                  	int 21h
  1553                                  
  1554                                  	mov ax, 4CFFh
  1555                                  	int 21h
  1556                                  
  1557                                  
  1558                                  %if _DEBUG0
  1559                                  init2_error_disp_ax_hex:	; ax
  1560                                  		xchg al,ah
  1561                                  		call init2_error_disp_al_hex	; display former ah
  1562                                  		xchg al,ah			;  and fall trough for al
  1563                                  init2_error_disp_al_hex:	; al
  1564                                  		push cx
  1565                                  		mov cl,4
  1566                                  		ror al,cl
  1567                                  		call init2_error_disp_al_lownibble_hex
  1568                                  						; display former high-nibble
  1569                                  		rol al,cl
  1570                                  		pop cx
  1571                                  						;  and fall trough for low-nibble
  1572                                  init2_error_disp_al_lownibble_hex:
  1573                                  		push ax			 ; save ax for call return
  1574                                  		and al,00001111b		; high nibble must be zero
  1575                                  		add al,'0'			; if number is 0-9, now it's the correct character
  1576                                  		cmp al,'9'
  1577                                  		jna .decimalnum		 ; if we get decimal number with this, ok -->
  1578                                  		add al,7			;  otherwise, add 7 and we are inside our alphabet
  1579                                   .decimalnum:
  1580                                  		call init2_error_disp_al
  1581                                  		pop ax
  1582                                  		retn
  1583                                  
  1584                                  
  1585                                  init2_error_disp_al:
  1586                                  	push dx
  1587                                  	push cx
  1588                                  	push bx
  1589                                  	push ax
  1590                                  	mov dx, sp
  1591                                  	push ds
  1592                                  	 push ss
  1593                                  	 pop ds
  1594                                  	mov cx, 1
  1595                                  	mov bx, 2
  1596                                  	mov ah, 40h
  1597                                  	int 21h
  1598                                  	pop ds
  1599                                  	pop ax
  1600                                  	pop bx
  1601                                  	pop cx
  1602                                  	pop dx
  1603                                  	retn
  1604                                  %endif
  1605                                  
  1606                                  
  1607                                  init2_disp_al:
  1608                                  	push dx
  1609                                  	push ax
  1610                                  	mov dl, al
  1611                                  	mov ah, 2
  1612                                  	int 21h
  1613                                  	pop ax
  1614                                  	pop dx
  1615                                  	retn
  1616                                  
  1617                                  
  1618                                  		; Display number in ax decimal
  1619                                  		;
  1620                                  		; INP:	ax = number
  1621                                  		; OUT:	displayed using Int21.02
  1622                                  		; CHG:	none
  1623                                  init2_disp_ax_dec:			; ax (no leading zeros)
  1624                                  		push bx
  1625                                  		xor bx, bx
  1626                                  .pushax:
  1627                                  		push dx
  1628                                  		push ax
  1629                                  		or bl, bl
  1630                                  		jz .nobl
  1631                                  		sub bl, 5
  1632                                  		neg bl
  1633                                  .nobl:
  1634                                  		push cx
  1635                                  		mov cx, 10000
  1636                                  		call .divide_out
  1637                                  		mov cx, 1000
  1638                                  		call .divide_out
  1639                                  		mov cx, 100
  1640                                  		call .divide_out
  1641                                  		mov cl, 10
  1642                                  		call .divide_out
  1643                                  							; (Divisor 1 is useless)
  1644                                  		add al, '0'
  1645                                  		call init2_disp_al
  1646                                  		pop cx
  1647                                  		pop ax
  1648                                  		pop dx
  1649                                  		pop bx					; Caller's register
  1650                                  		retn
  1651                                  
  1652                                  
  1653                                  		; INP:	ax = number
  1654                                  		;	cx = divisor
  1655                                  		; OUT:	ax = remainder of operation
  1656                                  		;	result displayed
  1657                                  .divide_out:
  1658                                  		push dx
  1659                                  		xor dx, dx
  1660                                  		div cx				; 0:ax / cx
  1661                                  		push dx				; remainder
  1662                                  		dec bl
  1663                                  		jnz .nobl2
  1664                                  		or bh, 1
  1665                                  .nobl2:
  1666                                  		or bh, al
  1667                                  		jz .leadingzero
  1668                                  		add al, '0'
  1669                                  		call init2_disp_al		; display result
  1670                                   .leadingzero:
  1671                                  		pop ax				; remainder
  1672                                  		pop dx
  1673                                  		retn
  1674                                  
  1675                                  
  1676                                  init2_msg:
  1677                                  %if _TEST_PROGRESS
  1678                                  .progress.1:		db "Info: 1"
  1679                                  .progress.1.length: equ $ - .progress.1
  1680                                  .progress.fail:		db "F"
  1681                                  .progress.fail.length: equ $ - .progress.fail
  1682                                  .progress.success:	db "S"
  1683                                  .progress.success.length: equ $ - .progress.success
  1684                                  .progress.linebreak:	db 13,10
  1685                                  .progress.linebreak.length: equ $ - .progress.linebreak
  1686                                  %endif
  1687                                  %if _WRITE_WRONG_FILE
  1688                                  .wrong_file_name:	asciz "WRONG.BIN"
  1689                                  .wrong_file_name2:	asciz "WRONG2.BIN"
  1690                                  %endif
  1691                                  .initial_error:	db "Error: Test program failed to decompress with full buffer."
  1692                                  .linebreak:	db 13,10
  1693                                  .initial_error.length: equ $ - .initial_error
  1694                                  .linebreak.length: equ $ - .linebreak
  1695                                  %if _DEBUG0
  1696                                  .rc:	db "Error: Failure code="
  1697                                  .rc.length: equ $ - .rc
  1698                                  %endif
  1699                                  %if _INCLUDE_UNCOMPRESSED
  1700                                  .initial_error_2:	db "Error: Test program decompressed wrongly with full buffer.",13,10
  1701                                  .initial_error_2.length: equ $ - .initial_error_2
  1702                                  .subsequent_error_2:	db "Error: Test program decompressed wrongly during test.",13,10
  1703                                  .subsequent_error_2.length: equ $ - .subsequent_error_2
  1704                                  %endif
  1705                                  .error_stdout:	_autodigits paras(_TEST_PROGRAM_DECOMPRESSED_SIZE 				+ (payload_end - payload) 				+ (init1_end - init1_start) 				+ ADDITIONAL_MEMORY 				)
  1710                                  		db 13,10
  1711                                  .error_stdout.length: equ $ - .error_stdout
  1712                                  
  1713                                  
  1714                                  		; Move paragraphs
  1715                                  		;
  1716                                  		; INP:	ax => source
  1717                                  		;	dx => destination
  1718                                  		;	cx = number of paragraphs
  1719                                  		; CHG:	-
  1720                                  		; OUT:	ax and dx unchanged
  1721                                  		; Note:	Doesn't work correctly on HMA; doesn't always wrap to LMA either.
  1722                                  		;	Do not provide a wrapped/HMA source or destination!
  1723                                  init2_movp:
  1724                                  	push cx
  1725                                  	push ds
  1726                                  	push si
  1727                                  	push es
  1728                                  	push di
  1729                                  
  1730                                  	cmp ax, dx		; source above destination ?
  1731                                  	ja .up			; yes, move up (forwards) -->
  1732                                  	je .return		; same, no need to move -->
  1733                                  	push ax
  1734                                  	add ax, cx		; (expected not to carry)
  1735                                  	cmp ax, dx		; end of source is above destination ?
  1736                                  	pop ax
  1737                                  	ja .down		; yes, move from top down -->
  1738                                  	; Here, the end of source is below-or-equal the destination,
  1739                                  	;  so they do not overlap. In this case we prefer moving up.
  1740                                  
  1741                                  .up:
  1742                                  	push ax
  1743                                  	push dx
  1744                                  .uploop:
  1745                                  	mov ds, ax
  1746                                  	mov es, dx
  1747                                  	xor di, di
  1748                                  	xor si, si		; -> start of segment
  1749                                  	sub cx, 1000h		; 64 KiB left ?
  1750                                  	jbe .uplast		; no -->
  1751                                  	push cx
  1752                                  	mov cx, 10000h /2
  1753                                  	rep movsw		; move 64 KiB
  1754                                  	pop cx
  1755                                  	add ax, 1000h
  1756                                  	add dx, 1000h		; -> next segment
  1757                                  	jmp short .uploop	; proceed for more -->
  1758                                  .uplast:
  1759                                  	add cx, 1000h		; restore counter
  1760                                  	shl cx, 1
  1761                                  	shl cx, 1
  1762                                  	shl cx, 1		; *8, paragraphs to words
  1763                                  	rep movsw		; move last part
  1764                                  	pop dx
  1765                                  	pop ax
  1766                                  	jmp short .return
  1767                                  
  1768                                  .down:
  1769                                  	std			; _AMD_ERRATUM_109_WORKAROUND as below
  1770                                  .dnloop:
  1771                                  	sub cx, 1000h		; 64 KiB left ?
  1772                                  	jbe .dnlast		; no -->
  1773                                  	push ax
  1774                                  	push dx
  1775                                  	add ax, cx
  1776                                  	add dx, cx
  1777                                  	mov ds, ax		; -> 64 KiB not yet moved
  1778                                  	mov es, dx
  1779                                  	pop dx
  1780                                  	pop ax
  1781                                  	mov di, -2
  1782                                  	mov si, di		; moved from last word down
  1783                                  	push cx
  1784                                  	mov cx, 10000h /2
  1785                                  	rep movsw		; move 64 KiB
  1786                                  	pop cx
  1787                                  	jmp short .dnloop	; proceed for more -->
  1788                                  .dnlast:
  1789                                  	add cx, 1000h		; restore counter
  1790                                  	shl cx, 1
  1791                                  	shl cx, 1
  1792                                  	shl cx, 1		; *8, paragraphs to words
  1793                                  	mov di, cx
  1794                                  	dec di
  1795                                  	shl di, 1		; words to offset, -> last word
  1796                                  	mov si, di
  1797                                  	mov ds, ax
  1798                                  	mov es, dx		; first segment correct
  1799                                  
  1800                                  		; Refer to comment in init0_movp.
  1801                                  %if _AMD_ERRATUM_109_WORKAROUND
  1802                                  	jcxz @FF
  1803                                  	cmp cx, 20
  1804                                  	ja @FF
  1805                                  @@:
  1806                                  	movsw
  1807                                  	loop @B
  1808                                  @@:
  1809                                  %endif
  1810                                  	rep movsw		; move first part
  1811                                  	cld
  1812                                  .return:
  1813                                  	pop di
  1814                                  	pop es
  1815                                  	pop si
  1816                                  	pop ds
  1817                                  	pop cx
  1818                                  	retn
  1819                                  
  1820                                  
  1821                                  	align 16
  1822                                  
  1823                                  	strdef UNCOMPRESSED_FILE, "lDOSLOAD.BIN"
  1824                                  %if _INCLUDE_UNCOMPRESSED
  1825                                  payload_uncompressed:
  1826                                  	incbin _UNCOMPRESSED_FILE
  1827                                  .end:
  1828                                  	db 38
  1829                                  	align 16, db 38
  1830                                  %endif
  1831                                  init2_end:
  1832                                  %endif
  1833                                  
