     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                                  %if (!!_BRIEFLZ + !!_LZ4 + !!_SNAPPY + !!_EXODECR + !!_X + !!_HEATSHRINK 	+ !!_LZD + !!_LZO) != 1
   100                                   %fatal Exactly one compression method must be selected.
   101                                  %endif
   102                                  %assign ADDITIONAL_MEMORY 0
   103                                  %if _BRIEFLZ
   104                                  	strdef PAYLOAD_FILE,	"lDOSLOAD.BLZ"
   105                                  %elif _LZ4
   106                                  	strdef PAYLOAD_FILE,	"lDOSLOAD.LZ4"
   107                                  %elif _SNAPPY
   108                                  	strdef PAYLOAD_FILE,	"lDOSLOAD.SZ"
   109                                  %elif _EXODECR
   110                                  	strdef PAYLOAD_FILE,	"lDOSLOAD.EXO"
   111                                  %elif _X
   112                                  	strdef PAYLOAD_FILE,	"lDOSLOAD.X"
   113                                  %elif _HEATSHRINK
   114                                  	strdef PAYLOAD_FILE,	"lDOSLOAD.HS"
   115                                  %elif _LZD
   116                                  	strdef PAYLOAD_FILE,	"lDOSLOAD.LZ"
   117                                  %elif _LZO
   118                                  	strdef PAYLOAD_FILE,	"lDOSLOAD.LZO"
   119                                  %endif
   120                                  	numdef PAYLOAD_KERNEL_MAX_PARAS,	0, 0
   121                                  %if _PAYLOAD_KERNEL_MAX_PARAS && ! _IMAGE_EXE
   122                                   %error Kernel mode max paras requires building dual-mode executable
   123                                  %endif
   124                                  	numdef COUNTER,		0, 32
   125                                  %if (_COUNTER - 1) & _COUNTER
   126                                   %error COUNTER must be a power of two
   127                                  %endif
   128                                  
   129                                  
   130                                  	cpu 8086
   131                                  	section INIT0 start=0 vstart=0
   132                                  init0_start:
   133                                  %if _DEVICE
   134                                  		; The device header is of a fixed format.
   135                                  		;  For our purposes, the 4-byte code for
   136                                  		;  each the strategy entry and the
   137                                  		;  interrupt entry is part of this format.
   138                                  		; (DOS may read the attributes or entrypoint
   139                                  		;  offsets before calling either, so in the inicomp
   140                                  		;  stage we need to recreate in the entrypoints part
   141                                  		;  exactly what the application has here.)
   142                                  device_header:
   143                                  .next:
   144                                   %if _DEVICE_ZERO_ENTRYPOINT
   145                                  	fill 2, -1, jmp strict short j_zero_entrypoint
   146                                  	dw -1
   147                                   %else
   148                                  	dd -1				; link to next device
   149                                   %endif
   150                                  .attributes:
   151                                  	dw _DEVICE_ATTRIBUTE		; attributes
   152                                  .strategy:
   153                                  	dw .strategy_entry		; -> strategy entry
   154                                  .interrupt:
   155                                  	dw .interrupt_entry		; -> interrupt entry
   156                                  .name:
   157                                  	fill 8, 32, db _DEVICE_NAME	; character device name,
   158                                  					;  or block device number of units
   159                                  					;  + optional name
   160                                  .strategy_entry:
   161                                  	fill 4, 90h, jmp device_entrypoint
   162                                  .interrupt_entry:
   163                                  	fill 4, 90h, retf
   164                                  %endif
   165                                  
   166                                  
   167                                  j_zero_entrypoint:
   168                                  
   169                                  %if _IMAGE_EXE || _DEVICE
   170 00000000 90                      	nop
   171 00000001 90<rep 1Fh>             	align 32, nop
   172                                  init0_kernel_entry:
   173                                  		; cs:ip = load seg : 32 here
   174                                  %if ($ - $$) != 32
   175                                   %error Wrong kernel mode entrypoint
   176                                  %endif
   177                                  %if _TEST_PROGRAM
   178                                  @@:
   179 00000020 CC                      	int3
   180 00000021 FB                      	sti
   181 00000022 F4                      	hlt
   182 00000023 EBFB                    	jmp @B
   183                                  %endif
   184 00000025 BB0000                  	mov bx, 0		; kernel mode
   185 00000028 50                      	push ax
   186 00000029 8CC8                    	mov ax, cs
   187 0000002B 83C020                  	add ax, (init0_end - init0_start) >> 4
   188 0000002E 8B56E2                  	mov dx, word [ bp + ldLoadTop ]	; => after end of available space
   189 00000031 BE6000                  	mov si, 60h		; => destination
   190 00000034 EB1A                    	jmp init0_common
   191                                  
   192                                   %if _IMAGE_EXE
   193 00000036 90<rep Ah>              	align 64, nop
   194                                  init0_exe_entry:
   195                                  		; NOTE:	This part is called with ip = 256 + 64, cs = PSP.
   196                                  %if ($ - $$) != 64
   197                                   %error Wrong EXE mode entrypoint
   198                                  %endif
   199 00000040 BB0100                  	mov bx, 1		; EXE mode
   200 00000043 50                      	push ax
   201 00000044 8CD2                    	mov dx, ss		; => after end of available space
   202 00000046 8CC8                    	mov ax, cs
   203 00000048 83C030                  	add ax, (256 + (init0_end - init0_start)) >> 4	; => source
   204 0000004B 8CCE                    	mov si, cs
   205 0000004D 83C610                  	add si, 256 >> 4	; => destination
   206                                   %endif
   207                                  
   208                                  init0_common:
   209                                  		; NOTE:	This part must be position-independent, as it is
   210                                  		;	 called either with ip = init0_common (kernel mode)
   211                                  		;	 or ip = init0_common + 256 (EXE mode).
   212 00000050 FC                      	cld
   213                                  %if _TEST_PROGRAM
   214 00000051 81EA560F                	sub dx, ( (payload_end - payload) ) >> 4
   215 00000055 721A                    	jc .error
   216 00000057 B9B324                  	mov cx, ( (payload_end - payload) 		+ (init1_end - init1_start) 		+ (init2_end - init2_start) 		) >> 4
   220 0000005A 29CA                    	sub dx, cx
   221 0000005C 7213                    	jc .error
   222 0000005E 39C2                    	cmp dx, ax
   223 00000060 720F                    	jb .error
   224                                  %else
   225                                  	mov cx, ( (payload_end - payload) 		+ (init1_end - init1_start) 		) >> 4
   228                                  	sub dx, cx
   229                                  %endif
   230 00000062 56                      	push si
   231 00000063 E82C00                  	call init0_movp
   232 00000066 5E                      	pop si
   233                                  %else
   234                                  	cld
   235                                  	mov ax, cs
   236                                  	add ax, (init0_end - init0_start) >> 4
   237                                  	mov cx, ( (payload_end - payload) 		+ (init1_end - init1_start) 		) >> 4
   240                                  	mov dx, word [ bp + ldLoadTop ]
   241                                  	sub dx, cx
   242                                  	call init0_movp
   243                                  %endif
   244                                  
   245 00000067 89D0                    	mov ax, dx
   246                                  %if _TEST_PROGRAM
   247 00000069 05940F                  	add ax, ( 		+ (payload_end - payload) 		+ (init1_end - init1_start) 		) >> 4
   251                                  %else
   252                                  	add ax, ( 		+ (payload_end - payload) 		) >> 4
   255                                  %endif
   256 0000006C 31C9                    	xor cx, cx
   257 0000006E 50                      	push ax
   258 0000006F 51                      	push cx
   259 00000070 CB                      	retf			; jump to relocated INIT1:init1_start
   260                                  
   261                                  
   262                                  %if _TEST_PROGRAM
   263                                  .error:
   264 00000071 0E                      	push cs
   265 00000072 1F                      	pop ds
   266 00000073 BA[1402]                	mov dx, init0_msg.error_stderr + 256
   267 00000076 B92500                  	mov cx, init0_msg.error_stderr.length
   268 00000079 BB0200                  	mov bx, 2
   269 0000007C B440                    	mov ah, 40h
   270 0000007E CD21                    	int 21h
   271 00000080 BA[3902]                	mov dx, init0_msg.error_stdout + 256
   272 00000083 B90600                  	mov cx, init0_msg.error_stdout.length
   273 00000086 BB0100                  	mov bx, 1
   274 00000089 B440                    	mov ah, 40h
   275 0000008B CD21                    	int 21h
   276 0000008D B8FF4C                  	mov ax, 4CFFh
   277 00000090 CD21                    	int 21h
   278                                  %endif
   279                                  
   280                                  
   281                                  %if _DEVICE
   282                                  device_entrypoint:
   283                                  %if _TEST_PROGRAM
   284                                  @@:
   285                                  	int3
   286                                  	sti
   287                                  	hlt
   288                                  	jmp @B
   289                                  %endif
   290                                  	cmp byte [es:bx + 2], 0		; command code 0 (init) ?
   291                                  	je @F
   292                                  
   293                                  	mov word [es:bx + 3], 8103h	; error, done, code: unknown command
   294                                  	retf
   295                                  
   296                                  @@:
   297                                  	or word [cs:device_header.next], -1
   298                                  	push cs
   299                                  	push word [cs:device_header.strategy]
   300                                  					; -> far return to payload's strategy
   301                                  	push bp
   302                                  	push ds
   303                                  	push si
   304                                  	push di
   305                                  	push dx
   306                                  	push cx
   307                                  	push ax
   308                                  	push bx
   309                                  	push es
   310                                  
   311                                  	mov ax, word [es:bx + 14 + 2]
   312                                  	xor dx, dx
   313                                  	mov cx, 4
   314                                  @@:
   315                                  	shl ax, 1
   316                                  	rcl dx, 1
   317                                  	loop @B
   318                                  	add ax, word [es:bx + 14]
   319                                  	adc dx, 0		; dx:ax = linear address behind end
   320                                  
   321                                  	mov cl, 4
   322                                  @@:
   323                                  	shr dx, 1
   324                                  	rcr ax, 1
   325                                  	loop @B			; ax => behind end
   326                                  
   327                                  	mov di, cs
   328                                  image_size: equ  ( (init0_end - init0_start) 		+ (payload_end - payload) 		+ (init1_end - init1_start) 		)
   332                                  	add di, image_size >> 4		; di => end of image
   333                                  
   334                                  	cmp ax, di			; enough memory to hold all of us ?
   335                                  	jae .have_some_memory		; yes -->
   336                                  
   337                                  	push cs
   338                                  	pop ds
   339                                  	mov dx, .msg_no_memory
   340                                  	mov ah, 09h
   341                                  	int 21h
   342                                  
   343                                  	mov ax, 3000h
   344                                  	int 21h
   345                                  	cmp al, 5
   346                                  	jae @F
   347                                  	mov dx, .msg_dos_below_5
   348                                  	mov ah, 09h
   349                                  	int 21h
   350                                  @@:
   351                                  
   352                                  	mov dx, .msg_linebreak
   353                                  	mov ah, 09h
   354                                  	int 21h
   355                                  
   356                                  		; tear down the stack frame and modify the request header
   357                                  	pop es
   358                                  	pop bx
   359                                  	mov word [es:bx + 3], 8103h	; set error, done, invalid command
   360                                  	mov byte [es:bx + 13], 0	; set number of units = 0
   361                                  	mov word [es:bx + 14 + 2], cs
   362                                  	and word [es:bx + 14], 0	; -> after end of memory to allocate
   363                                  	pop ax
   364                                  	pop cx
   365                                  	pop dx
   366                                  	pop di
   367                                  	pop si
   368                                  	pop ds
   369                                  	pop bp
   370                                  	add sp, 4		; discard far return to payload's strategy
   371                                  	retf			; return to DOS
   372                                  
   373                                  .msg_no_memory:		ascic "Load error: Not enough memory."
   374                                  .msg_dos_below_5:	ascic " Note: DOS must be at least version 5."
   375                                  .msg_linebreak:		ascic 13,10
   376                                  
   377                                  
   378                                  .have_some_memory:
   379                                  	mov dx, ax		; => after end of memory
   380                                  	mov bx, 2		; device mode
   381                                  	push ax
   382                                  	mov ax, cs
   383                                  	add ax, (init0_end - init0_start) >> 4
   384                                  	mov si, cs		; => destination
   385                                  	jmp init0_common
   386                                  %endif
   387                                  
   388                                  
   389                                  		; Move paragraphs
   390                                  		;
   391                                  		; INP:	ax => source
   392                                  		;	dx => destination
   393                                  		;	cx = number of paragraphs
   394                                  		; CHG:	cx, ds, si, es, di
   395                                  		; OUT:	ax and dx unchanged
   396                                  		; Note:	Doesn't work correctly on HMA; doesn't always wrap to LMA either.
   397                                  		;	Do not provide a wrapped/HMA source or destination!
   398                                  init0_movp:
   399 00000092 39D0                    	cmp ax, dx		; source above destination ?
   400 00000094 770A                    	ja .up			; yes, move up (forwards) -->
   401 00000096 747B                    	je .return		; same, no need to move -->
   402 00000098 50                      	push ax
   403 00000099 01C8                    	add ax, cx		; (expected not to carry)
   404 0000009B 39D0                    	cmp ax, dx		; end of source is above destination ?
   405 0000009D 58                      	pop ax
   406 0000009E 7730                    	ja .down		; yes, move from top down -->
   407                                  	; Here, the end of source is below-or-equal the destination,
   408                                  	;  so they do not overlap. In this case we prefer moving up.
   409                                  
   410                                  .up:
   411 000000A0 50                      	push ax
   412 000000A1 52                      	push dx
   413                                  .uploop:
   414 000000A2 8ED8                    	mov ds, ax
   415 000000A4 8EC2                    	mov es, dx
   416 000000A6 31FF                    	xor di, di
   417 000000A8 31F6                    	xor si, si		; -> start of segment
   418 000000AA 81E90010                	sub cx, 1000h		; 64 KiB left ?
   419 000000AE 7610                    	jbe .uplast		; no -->
   420 000000B0 51                      	push cx
   421 000000B1 B90080                  	mov cx, 10000h /2
   422 000000B4 F3A5                    	rep movsw		; move 64 KiB
   423 000000B6 59                      	pop cx
   424 000000B7 050010                  	add ax, 1000h
   425 000000BA 81C20010                	add dx, 1000h		; -> next segment
   426 000000BE EBE2                    	jmp short .uploop	; proceed for more -->
   427                                  .uplast:
   428 000000C0 81C10010                	add cx, 1000h		; restore counter
   429 000000C4 D1E1                    	shl cx, 1
   430 000000C6 D1E1                    	shl cx, 1
   431 000000C8 D1E1                    	shl cx, 1		; *8, paragraphs to words
   432 000000CA F3A5                    	rep movsw		; move last part
   433 000000CC 5A                      	pop dx
   434 000000CD 58                      	pop ax
   435 000000CE EB43                    	jmp short .return
   436                                  
   437                                  .down:
   438 000000D0 FD                      	std			; _AMD_ERRATUM_109_WORKAROUND as below
   439                                  .dnloop:
   440 000000D1 81E90010                	sub cx, 1000h		; 64 KiB left ?
   441 000000D5 761A                    	jbe .dnlast		; no -->
   442 000000D7 50                      	push ax
   443 000000D8 52                      	push dx
   444 000000D9 01C8                    	add ax, cx
   445 000000DB 01CA                    	add dx, cx
   446 000000DD 8ED8                    	mov ds, ax		; -> 64 KiB not yet moved
   447 000000DF 8EC2                    	mov es, dx
   448 000000E1 5A                      	pop dx
   449 000000E2 58                      	pop ax
   450 000000E3 BFFEFF                  	mov di, -2
   451 000000E6 89FE                    	mov si, di		; moved from last word down
   452 000000E8 51                      	push cx
   453 000000E9 B90080                  	mov cx, 10000h /2
   454 000000EC F3A5                    	rep movsw		; move 64 KiB
   455 000000EE 59                      	pop cx
   456 000000EF EBE0                    	jmp short .dnloop	; proceed for more -->
   457                                  .dnlast:
   458 000000F1 81C10010                	add cx, 1000h		; restore counter
   459 000000F5 D1E1                    	shl cx, 1
   460 000000F7 D1E1                    	shl cx, 1
   461 000000F9 D1E1                    	shl cx, 1		; *8, paragraphs to words
   462 000000FB 89CF                    	mov di, cx
   463 000000FD 4F                      	dec di
   464 000000FE D1E7                    	shl di, 1		; words to offset, -> last word
   465 00000100 89FE                    	mov si, di
   466 00000102 8ED8                    	mov ds, ax
   467 00000104 8EC2                    	mov es, dx		; first segment correct
   468                                  
   469                                  
   470                                  	numdef AMD_ERRATUM_109_WORKAROUND, 1
   471                                  %if 0
   472                                  
   473                                  Jack R. Ellis pointed out this erratum:
   474                                  
   475                                  Quoting from https://www.amd.com/system/files/TechDocs/25759.pdf page 69:
   476                                  
   477                                  109   Certain Reverse REP MOVS May Produce Unpredictable Behavior
   478                                  
   479                                  Description
   480                                  
   481                                  In certain situations a REP MOVS instruction may lead to
   482                                  incorrect results. An incorrect address size, data size
   483                                  or source operand segment may be used or a succeeding
   484                                  instruction may be skipped. This may occur under the
   485                                  following conditions:
   486                                  
   487                                  * EFLAGS.DF=1 (the string is being moved in the reverse direction).
   488                                  
   489                                  * The number of items being moved (RCX) is between 1 and 20.
   490                                  
   491                                  * The REP MOVS instruction is preceded by some microcoded instruction
   492                                    that has not completely retired by the time the REP MOVS begins
   493                                    execution. The set of such instructions includes BOUND, CLI, LDS,
   494                                    LES, LFS, LGS, LSS, IDIV, and most microcoded x87 instructions.
   495                                  
   496                                  Potential Effect on System
   497                                  
   498                                  Incorrect results may be produced or the system may hang.
   499                                  
   500                                  Suggested Workaround
   501                                  
   502                                  Contact your AMD representative for information on a BIOS update.
   503                                  
   504                                  %endif
   505                                  
   506                                  %if _AMD_ERRATUM_109_WORKAROUND
   507 00000106 E308                    	jcxz @FF
   508 00000108 83F914                  	cmp cx, 20
   509 0000010B 7703                    	ja @FF
   510                                  @@:
   511 0000010D A5                      	movsw
   512 0000010E E2FD                    	loop @B
   513                                  @@:
   514                                  %endif
   515 00000110 F3A5                    	rep movsw		; move first part
   516 00000112 FC                      	cld
   517                                  .return:
   518 00000113 C3                      	retn
   519                                  
   520                                  
   521                                  	section PAYLOAD align=16 follows=INIT0
   522                                  payload:
   523 00000000 <bin F55Eh>             	incbin _PAYLOAD_FILE
   524                                  .end:
   525 0000F55E 26<rep 2h>              	align 16, db 38
   526                                  payload_end:
   527                                  
   528                                  
   529                                  	section INIT1 align=16 follows=PAYLOAD vstart=0
   530                                  init1_start:
   531                                  		; INP:	ax = cs = INIT1
   532                                  		;	dx = cs - (payload_end - payload) >> 4 => source data
   533                                  		;	if kernel mode:
   534                                  		;	 ss:bp -> LOADDATA and LOADSTACKVARS
   535                                  		;	 ss:sp -> valid stack above [bp + ldLoadTop]
   536                                  		;	 60h => destination
   537                                  		;	any mode:
   538                                  		;	 word [ss:sp] = value for ax
   539                                  		;	 bx = 2 if device mode, 1 if EXE mode, 0 if kernel mode
   540                                  		;	 si => destination (60h for kernel mode,
   541                                  		;		after PSP for EXE mode,
   542                                  		;		at device header for device mode)
   543                                  		;	 if EXE mode:
   544                                  		;	  ss:sp -> valid stack above INIT1
   545                                  		;	  bp = unset
   546                                  		;	 if device mode:
   547                                  		;	  ss:sp -> device entrypoint stack
   548                                  		;	  holds: es, bx, ax, cx, dx, di, si, ds, bp,
   549                                  		;		  far address of payload strategy entrypoint,
   550                                  		;		  far return address to DOS
   551                                  		;	  bp = unset
   552                                  		; CHG:	ax, bx, cx, dx, es, ds, si, di
   553                                  %if _IMAGE_EXE || _DEVICE
   554                                  	lframe
   555 00000000 5589E5                  	lenter
   556                                  	lvar word,	exemode		; must be bp - 2!
   557 00000003 53                      	 push bx
   558                                   %if ?exemode != -2
   559                                    %error exemode variable must be directly below bp
   560                                   %endif
   561 00000004 56                      	push si
   562                                  %else
   563                                  	xor bx, bx		; always tell them it is kernel mode
   564                                  %endif
   565                                  
   566 00000005 FC                      	cld
   567                                  
   568                                  %if _IMAGE_EXE
   569 00000006 8EC6                    	mov es, si		; es => destination
   570                                  %else
   571                                  	mov ax, 60h
   572                                  	mov es, ax		; es => destination
   573                                  %endif
   574 00000008 31FF                    	xor di, di		; -> destination
   575                                  
   576 0000000A 8EDA                    	mov ds, dx
   577 0000000C 31F6                    	xor si, si		; -> source
   578                                  
   579 0000000E B95EF5                  	mov cx, (payload.end - payload) & 0FFFFh
   580                                  %if (payload.end - payload) >> 16
   581                                  	mov dx, (payload.end - payload) >> 16	; = length of source
   582                                  %else
   583 00000011 31D2                    	xor dx, dx
   584                                  %endif
   585                                  %if _PAYLOAD_KERNEL_MAX_PARAS
   586                                  	mov ax, _PAYLOAD_KERNEL_MAX_PARAS
   587                                  	test bx, bx
   588                                  	jz @F
   589                                  %endif
   590 00000013 B8FFFF                  	mov ax, -1
   591                                  @@:
   592                                  		; INP:	ds:si -> source
   593                                  		;	dx:cx = length of source
   594                                  		;	es:di -> destination (below source)
   595                                  		;	bx = EXE mode flag
   596                                  		;	 (1 if EXE mode, 0 if kernel mode)
   597                                  		;	 (always 0 if this is a build without EXE mode)
   598                                  		;	ax = maximum amount in paragraphs of destination needed
   599                                  		;	 (-1 if unused, meaning entire destination needed)
   600                                  		; Note:	The destination reaches up to below the source.
   601 00000016 E88600                  	call depack
   602                                  %ifn _TEST_PROGRAM
   603                                  	jc strict short error
   604                                  %endif
   605                                  %if _IMAGE_EXE
   606 00000019 5E                      	pop si			; si
   607                                   %if _TEST_PROGRAM
   608 0000001A 58                      	pop ax			; (discard ?exemode, leave bx as returned)
   609                                   %else
   610                                  	pop bx			; ?exemode
   611                                   %endif
   612 0000001B 5D                      	pop bp			; bp
   613 0000001C 58                      	pop ax			; ax
   614                                  	lleave ctx
   615                                  %endif
   616                                  %if _TEST_PROGRAM
   617 0000001D CB                      	retf
   618 0000001E 90                      	nop
   619                                  %endif
   620                                  
   621                                  %if _DEVICE
   622                                  	test bl, 2
   623                                  	jz .jmp_exe_or_kernel_mode
   624                                  
   625                                  .jmp_device_mode:
   626                                  	mov ds, si
   627                                  	or word [device_header.next], -1
   628                                  	pop es
   629                                  	pop bx
   630                                  	pop ax
   631                                  	pop cx
   632                                  	pop dx
   633                                  	pop di
   634                                  	pop si
   635                                  	pop ds
   636                                  	pop bp
   637                                  	retf			; transfer to payload strategy entrypoint
   638                                  				; still on stack: far return address to DOS
   639                                  
   640                                  .jmp_exe_or_kernel_mode:
   641                                  %endif
   642                                  
   643                                  %if _IMAGE_EXE
   644 0000001F F6C301                  	test bl, 1
   645 00000022 7410                    	jz .jmp_kernel_mode
   646                                  
   647                                  .jmp_exe_mode:
   648                                  %if ! _IMAGE_EXE_AUTO_STACK
   649                                  	mov cx, cs
   650                                  	lea dx, [si + _IMAGE_EXE_SS]
   651                                  	push dx			; stack = relocated ss value
   652                                  	add dx, (_IMAGE_EXE_SP + 2 + 15) >> 4
   653                                  	cmp cx, dx		; INIT1 code is above intended stack ?
   654                                  	jae @F			; yes -->
   655                                  
   656                                  	lframe
   657                                  	lenter
   658                                  	lvar	word, exemode
   659                                  	 push bx
   660                                   %if ?exemode != -2
   661                                    %error exemode variable must be directly below bp
   662                                   %endif
   663                                  	mov bx, -1		; unimplemented, return error
   664                                  	jmp error
   665                                  	lleave ctx
   666                                  @@:
   667                                  	cli
   668                                  	pop ss			; = relocated ss value
   669                                  	mov sp, (_IMAGE_EXE_SP + 2) & 0FFFFh	; change stack
   670                                  	sti
   671                                  %endif
   672                                  
   673 00000024 31C9                    	xor cx, cx
   674 00000026 51                      	push cx			; put zero on top of stack
   675                                  
   676 00000027 B94001                  	mov cx, _IMAGE_EXE_IP
   677                                  %if _IMAGE_EXE_CS == -16
   678 0000002A 83C6F0                  	add si, -16
   679 0000002D 8EDE                    	mov ds, si
   680 0000002F 8EC6                    	mov es, si
   681                                  %else
   682                                  	lea dx, [si - 10h]	; => PSP
   683                                  	mov ds, dx
   684                                  	mov es, dx		; ds = es => PSP
   685                                  	add si, _IMAGE_EXE_CS	; = relocated cs value
   686                                  %endif
   687 00000031 56                      	push si
   688 00000032 51                      	push cx
   689 00000033 CB                      	retf			; jump to EXE mode of image
   690                                  
   691                                  %endif
   692                                  .jmp_kernel_mode:
   693 00000034 EA20006000              	jmp 60h + _EXEC_SEGMENT:_EXEC_OFFSET
   694                                  
   695                                  
   696                                  error:
   697 00000039 0E                      	push cs
   698 0000003A 1F                      	pop ds
   699                                  %if _DEBUG0
   700                                  	mov si, msg.error_begin
   701                                  	call disp_error
   702                                  	mov ax, bx
   703                                  	call disp_ax_hex
   704                                  	mov si, msg.error_end
   705                                  %else
   706 0000003B BE[7A00]                	mov si, msg.error
   707                                  %endif
   708 0000003E E81100                  	call disp_error
   709                                  
   710                                  %if _DEVICE
   711                                  	test byte [bp - 2], 2
   712                                  	jz .exit_app_or_kernel
   713                                  
   714                                  	pop si				; => device segment
   715                                  	pop bx				; mode word
   716                                  	pop bp
   717                                  	pop ax
   718                                  	mov es, si
   719                                  	xor di, di			; -> device header
   720                                  	 push cs
   721                                  	 pop ds
   722                                  	mov si, device_header_copy	; -> to reset header
   723                                  	mov cx, words(device_header_copy.length)
   724                                  	rep movsw		; overwrite device header with default
   725                                  				;  (reset to a valid state after unsuccessful
   726                                  				;  decompression, which may have partially
   727                                  				;  written the header already)
   728                                  	 push es
   729                                  	 pop ds				; -> device segment
   730                                  	pop es
   731                                  	pop bx
   732                                  	mov word [es:bx + 3], 8103h	; set error, done, invalid command
   733                                  	mov byte [es:bx + 13], 0	; set number of units = 0
   734                                  	mov word [es:bx + 14 + 2], ds
   735                                  	and word [es:bx + 14], 0	; -> after end of memory to allocate
   736                                  	pop ax
   737                                  	pop cx
   738                                  	pop dx
   739                                  	pop di
   740                                  	pop si
   741                                  	pop ds
   742                                  	pop bp
   743                                  	add sp, 4		; discard far return to payload's strategy
   744                                  	retf			; return to DOS
   745                                  
   746                                  
   747                                  .exit_app_or_kernel:
   748                                  %endif
   749                                  
   750                                  %if _IMAGE_EXE
   751 00000041 F646FE01                	test byte [bp - 2], 1
   752 00000045 7405                    	jz .exit_kernel_mode
   753                                  
   754 00000047 B87F4C                  	mov ax, 4C7Fh
   755 0000004A CD21                    	int 21h
   756                                  
   757                                  .exit_kernel_mode:
   758                                  %endif
   759 0000004C 31C0                    	xor ax, ax
   760 0000004E CD16                    	int 16h
   761 00000050 CD19                    	int 19h
   762                                  
   763                                  
   764                                  %if _DEVICE
   765                                  	align 16
   766                                  device_header_copy:
   767                                  .:
   768                                  .next:
   769                                  	dd -1				; already initialised
   770                                  .attributes:
   771                                  	dw _DEVICE_ATTRIBUTE
   772                                  .strategy:
   773                                  	dw .strategy_entry - .		; -> strategy entry
   774                                  .interrupt:
   775                                  	dw .interrupt_entry - .		; -> interrupt entry
   776                                  .name:
   777                                  	fill 8, 32, db _DEVICE_NAME
   778                                  .strategy_entry:
   779                                  	fill 4, 90h, jmp .set_error	; rel8 or rel16 jump, not minus .
   780                                  .interrupt_entry:
   781                                  	fill 4, 90h, retf
   782                                  
   783                                  .set_error:
   784                                  	mov word [es:bx + 3], 8103h	; set error, done, invalid command
   785                                  	retf
   786                                  .length: equ $ - .
   787                                  %endif
   788                                  
   789                                  
   790                                  disp_error:
   791                                  .:
   792 00000052 AC                      	lodsb
   793 00000053 84C0                    	test al, al
   794 00000055 7422                    	jz .ret
   795 00000057 E80200                  	call disp_al
   796 0000005A EBF6                    	jmp short .
   797                                  
   798                                  %if _DEBUG0 || _DEBUG1 || _DEBUG2 || _DEBUG3
   799                                  disp_ax_hex:			; ax
   800                                  		xchg al,ah
   801                                  		call disp_al_hex		; display former ah
   802                                  		xchg al,ah			;  and fall trough for al
   803                                  disp_al_hex:			; al
   804                                  		push cx
   805                                  		mov cl,4
   806                                  		ror al,cl
   807                                  		call disp_al_lownibble_hex	; display former high-nibble
   808                                  		rol al,cl
   809                                  		pop cx
   810                                  						;  and fall trough for low-nibble
   811                                  disp_al_lownibble_hex:
   812                                  		push ax			 ; save ax for call return
   813                                  		and al,00001111b		; high nibble must be zero
   814                                  		add al,'0'			; if number is 0-9, now it's the correct character
   815                                  		cmp al,'9'
   816                                  		jna .decimalnum		 ; if we get decimal number with this, ok -->
   817                                  		add al,7			;  otherwise, add 7 and we are inside our alphabet
   818                                   .decimalnum:
   819                                  		call disp_al
   820                                  		pop ax
   821                                  		retn
   822                                  %endif
   823                                  
   824                                  disp_al:
   825                                  %if _TEST_PROGRAM
   826 0000005C C3                      	retn
   827                                  %else
   828                                  	push ax
   829                                  %endif
   830 0000005D 53                      	push bx
   831 0000005E 55                      	push bp
   832                                  %if _IMAGE_EXE || _DEVICE
   833 0000005F 52                      	push dx
   834                                  
   835 00000060 F646FE03                	test byte [bp - 2], 1 | 2
   836 00000064 7408                    	jz .display_kernel_mode
   837                                  
   838 00000066 88C2                    	mov dl, al
   839 00000068 B402                    	mov ah, 02h
   840 0000006A CD21                    	int 21h
   841 0000006C EB07                    	jmp .common
   842                                  
   843                                  .display_kernel_mode:
   844                                  %endif
   845 0000006E B40E                    	mov ah, 0Eh
   846 00000070 BB0700                  	mov bx, 7
   847 00000073 CD10                    	int 10h
   848                                  %if _IMAGE_EXE
   849                                  .common:
   850 00000075 5A                      	pop dx
   851                                  %endif
   852 00000076 5D                      	pop bp
   853 00000077 5B                      	pop bx
   854 00000078 58                      	pop ax
   855                                  disp_error.ret:
   856 00000079 C3                      	retn
   857                                  
   858                                  
   859                                  msg:
   860                                  %if _DEBUG0
   861                                  .error_begin:	db "Load error: Decompression failure, code ",0
   862                                  .error_end:	db "h.",13,10,0
   863                                  %else
   864 0000007A 4C6F6164206572726F-     .error:		db "Load error: Decompression failure.",13,10,0
   864 00000083 723A204465636F6D70-
   864 0000008C 72657373696F6E2066-
   864 00000095 61696C7572652E0D0A-
   864 0000009E 00                 
   865                                  %endif
   866                                  
   867                                  
   868                                  		; Specific depacker's file is included within label msg.
   869                                  		; In the file, lframe is used and lleave ctx is not used.
   870                                  
   871                                  %if _BRIEFLZ
   872                                  	%include "brieflz.asm"
   873                                  %endif
   874                                  
   875                                  
   876                                  %if _LZ4
   877                                  	%include "lz4.asm"
   878                              <1> 
   879                              <1> %if 0
   880                              <1> 
   881                              <1> 8086 Assembly lDOS iniload payload LZ4 depacker
   882                              <1>  by C. Masloch, 2018
   883                              <1> 
   884                              <1> Usage of the works is permitted provided that this
   885                              <1> instrument is retained with the works, so that any entity
   886                              <1> that uses the works is notified of this instrument.
   887                              <1> 
   888                              <1> DISCLAIMER: THE WORKS ARE WITHOUT WARRANTY.
   889                              <1> 
   890                              <1> %endif
   891                              <1> 
   892                              <1> 
   893                              <1> lz4_flg_version_mask:	equ 1100_0000b
   894                              <1> lz4_flg_version:	equ 0100_0000b
   895                              <1> lz4_flg_b_indep:	equ 0010_0000b
   896                              <1> lz4_flg_b_checksum:	equ 0001_0000b
   897                              <1> lz4_flg_c_size:		equ 0000_1000b
   898                              <1> lz4_flg_c_checksum:	equ 0000_0100b
   899                              <1> lz4_flg_reserved:	equ 0000_0010b
   900                              <1> lz4_flg_dict_id:	equ 0000_0001b
   901                              <1> 
   902                              <1> lz4_bd_reserved_mask:	equ 1000_1111b
   903                              <1> 		; BD block max size is not used by us
   904                              <1> 
   905                              <1> 
   906                              <1> 		; INP:	ds:si -> source
   907                              <1> 		;	dx:cx = length of source
   908                              <1> 		;	es:di -> destination (below source)
   909                              <1> 		;	if _IMAGE_EXE:
   910                              <1> 		;	 bx = EXE mode flag (bit 0)
   911                              <1> 		;	else:
   912                              <1> 		;	 bx = 0
   913                              <1> 		;	ax = maximum amount in paragraphs of destination needed
   914                              <1> 		;	 (-1 if full source should be decompressed)
   915                              <1> 		; OUT:	NC if success
   916                              <1> 		;	CY if error,
   917                              <1> 		;	 bx = ?errordata (if _DEBUG0)
   918                              <1> 		; CHG:	ax, (bx), cx, dx, es, ds, si, di
   919                              <1> 		; STT:	UP
   920                              <1> 		;
   921                              <1> 		; Note:	The destination reaches up to below the source.
   922                              <1> 		; Note:	The input pointers need not be normalised yet.
   923                              <1> 		;	 Normalised means that the offset part is below 16.
   924                              <1> depack:
   925                              <1> 	lframe near
   926                              <1> %if _IMAGE_EXE || _DEBUG0 || _COUNTER
   927 0000009F 5589E5              <1> 	lenter early
   928                              <1>  %if _IMAGE_EXE
   929                              <1> 	lvar word,	exemode	; must be bp - 2!
   930 000000A2 53                  <1> 	 push bx
   931                              <1>   %if ?exemode != -2
   932                              <1>    %error exemode variable must be directly below bp
   933                              <1>   %endif
   934                              <1>  %endif
   935                              <1>  %if _DEBUG0 || _COUNTER
   936                              <1> 	xor bx, bx
   937                              <1>  %endif
   938                              <1>  %if _DEBUG0
   939                              <1> 	lvar word,	errordata
   940                              <1> 	 push bx
   941                              <1>  %endif
   942                              <1> %endif
   943                              <1> 	lvar word,	token_and_counter
   944                              <1> 	lequ ?token_and_counter, token
   945                              <1> 	lequ ?token_and_counter + 1, counter
   946                              <1> %if _COUNTER
   947                              <1> 	 push bx		; initialise counter (high byte) to zero
   948                              <1> %endif
   949                              <1> 	lvar dword,	src_behind_block
   950                              <1> 	lvar word,	frame_descriptor_flg_and_bd
   951 000000A3 8D66F6              <1> 	lenter
   952                              <1> 
   953 000000A6 E8AC02              <1> 	call normalise_both_pointers
   954                              <1> 
   955                              <1> 	lvar dword,	src
   956 000000A9 1E                  <1> 	 push ds
   957 000000AA 56                  <1> 	 push si
   958                              <1> 	lvar dword,	original_dst
   959 000000AB 06                  <1> 	 push es
   960 000000AC 57                  <1> 	 push di
   961                              <1> 	lvar dword,	dst
   962 000000AD 06                  <1> 	 push es
   963 000000AE 57                  <1> 	 push di
   964                              <1> 	lvar dword,	length_of_source
   965 000000AF 52                  <1> 	 push dx
   966 000000B0 51                  <1> 	 push cx
   967                              <1> 
   968 000000B1 83F8FF              <1> 	cmp ax, -1		; no maximum specified ?
   969 000000B4 740B                <1> 	je @FF			; retain -1 in ax -->
   970 000000B6 85FF                <1> 	test di, di		; do we need an additional paragraph ?
   971 000000B8 7401                <1> 	jz @F			; no -->
   972 000000BA 40                  <1> 	inc ax			; es + ax => paragraph after necessary part
   973                              <1> @@:
   974 000000BB 8CC2                <1> 	mov dx, es
   975 000000BD 01D0                <1> 	add ax, dx		; => paragraph after necessary part
   976                              <1> 		; If the normalised destination pointer's segment grows
   977                              <1> 		;  to this segment then enough has been decompressed.
   978                              <1> d0	mov byte [bp + ?errordata], 40h
   979 000000BF 722D                <1> 	jc .error		; should not carry
   980                              <1> @@:
   981                              <1> 	lvar word,	dst_max_segment
   982 000000C1 50                  <1> 	 push ax
   983                              <1> 
   984 000000C2 1E                  <1> 	 push ds
   985 000000C3 56                  <1> 	 push si
   986 000000C4 E8EE02              <1> 	call pointer_to_linear
   987                              <1> 
   988 000000C7 89D3                <1> 	mov bx, dx
   989 000000C9 89C1                <1> 	mov cx, ax		; bx:cx = source linear
   990                              <1> 
   991 000000CB 06                  <1> 	 push es
   992 000000CC 57                  <1> 	 push di
   993 000000CD E8E502              <1> 	call pointer_to_linear
   994                              <1> 
   995                              <1> %if _ALLOW_OVERLAPPING
   996 000000D0 034EE6              <1> 	add cx, word [bp + ?length_of_source]
   997 000000D3 135EE8              <1> 	adc bx, word [bp + ?length_of_source + 2]
   998                              <1> 		; In case of allowing overlapping source and destination,
   999                              <1> 		;  the ?length_of_destination variable is set to
  1000                              <1> 		;  ?src + ?length_of_source - ?dst, allowing to write to
  1001                              <1> 		;  all of the source buffer (with the checks already in place
  1002                              <1> 		;  from the default handling). Additional checks are done by
  1003                              <1> 		;  calling check_pointers_not_overlapping. This is done after
  1004                              <1> 		;  every change of ?dst to verify that the write pointer stays
  1005                              <1> 		;  below-or-equal the read pointer.
  1006                              <1> 		; This means the remaining source data may be corrupted by a
  1007                              <1> 		;  write, but nothing after the source data is written to,
  1008                              <1> 		;  so the error handling (in INIT1 after the data) still works.
  1009                              <1> %endif
  1010                              <1> 
  1011 000000D6 29C1                <1> 	sub cx, ax
  1012 000000D8 19D3                <1> 	sbb bx, dx		; bx:cx = source linear - destination linear
  1013                              <1> 
  1014                              <1> 	lvar dword,	length_of_destination
  1015 000000DA 53                  <1> 	 push bx		; push into [bp + ?length_of_destination + 2]
  1016 000000DB 51                  <1> 	 push cx		; push into [bp + ?length_of_destination]
  1017                              <1> 
  1018                              <1> %if _ALLOW_OVERLAPPING
  1019 000000DC E85802              <1> 	call check_pointers_not_overlapping
  1020                              <1> 		; Note:	We initially check here that the write pointer is
  1021                              <1> 		;	 low enough, ie below-or-equal the read pointer.
  1022                              <1> 		;	 Doing this check here (as well as after any
  1023                              <1> 		;	 copied match) allows us to drop the check done
  1024                              <1> 		;	 after moving literal bytes.
  1025                              <1> d0	mov byte [bp + ?errordata], 1Bh
  1026 000000DF 720D                <1> 	jc .error
  1027                              <1> %endif
  1028                              <1> 
  1029                              <1> .loop_frame:
  1030 000000E1 31C9                <1> 	xor cx, cx
  1031 000000E3 394EE8              <1> 	cmp word [bp + ?length_of_source + 2], cx
  1032 000000E6 750B                <1> 	jne @F
  1033 000000E8 394EE6              <1> 	cmp word [bp + ?length_of_source], cx
  1034 000000EB 7506                <1> 	jne @F
  1035                              <1> 
  1036                              <1> .end:
  1037 000000ED A8                  <1> 	db __TEST_IMM8			; (NC)
  1038                              <1> .error:
  1039 000000EE F9                  <1> 	stc
  1040                              <1> 
  1041                              <1> %if _COUNTER
  1042                              <1> 	lahf
  1043                              <1> 	mov al, 13
  1044                              <1> 	call disp_al
  1045                              <1> 	mov al, 10
  1046                              <1> 	call disp_al
  1047                              <1> 	sahf
  1048                              <1> %endif
  1049                              <1> d0	mov bx, word [bp + ?errordata]
  1050 000000EF 89EC5D              <1> 	lleave code
  1051 000000F2 C3                  <1> 	lret
  1052                              <1> 
  1053                              <1> 
  1054                              <1> @@:
  1055 000000F3 B104                <1> 	mov cl, 4
  1056 000000F5 E81802              <1> 	call read_le_data_src
  1057                              <1> d0	mov byte [bp + ?errordata], 1
  1058 000000F8 72F4                <1> 	jc .error
  1059                              <1> 
  1060 000000FA 81FA4D18            <1> 	cmp dx, 184Dh			; signature match ?
  1061                              <1> d0	mov byte [bp + ?errordata], 2
  1062 000000FE 75EE                <1> 	jne .error			; no -->
  1063 00000100 3D0422              <1> 	cmp ax, 2204h			; usual frame ?
  1064 00000103 7427                <1> 	je @F				; yes -->
  1065                              <1> 
  1066 00000105 24F0                <1> 	and al,  ~0Fh
  1067 00000107 3D502A              <1> 	cmp ax, 2A50h			; skippable frame ?
  1068                              <1> d0	mov byte [bp + ?errordata], 3
  1069 0000010A 75E2                <1> 	jne .error			; no -->
  1070                              <1> 
  1071                              <1> 		; cx = 4 still here
  1072 0000010C E80102              <1> 	call read_le_data_src		; read length of skippable frame
  1073                              <1> d0	mov byte [bp + ?errordata], 4
  1074 0000010F 72DD                <1> 	jc .error
  1075                              <1> 
  1076 00000111 1E                  <1> 	 push ds
  1077 00000112 56                  <1> 	 push si
  1078 00000113 89C1                <1> 	mov cx, ax
  1079 00000115 89D3                <1> 	mov bx, dx			; displacement = skippable frame length
  1080 00000117 E86602              <1> 	call normalise_pointer_with_displacement_bxcx
  1081 0000011A 8F46F2              <1> 	 pop word [bp + ?src]
  1082 0000011D 8F46F4              <1> 	 pop word [bp + ?src + 2]	; ?src += length
  1083                              <1> d0	mov byte [bp + ?errordata], 1Dh
  1084 00000120 72CC                <1> 	jc .error
  1085                              <1> 
  1086 00000122 2946E6              <1> 	sub word [bp + ?length_of_source], ax
  1087 00000125 1956E8              <1> 	sbb word [bp + ?length_of_source + 2], dx
  1088                              <1> 					; ?length_of_source -= length
  1089                              <1> d0	mov byte [bp + ?errordata], 5
  1090 00000128 72C4                <1> 	jc .error
  1091 0000012A EBB5                <1> 	jmp .loop_frame
  1092                              <1> 
  1093                              <1> 
  1094                              <1> @@:
  1095 0000012C B102                <1> 	mov cl, 2
  1096 0000012E E8DF01              <1> 	call read_le_data_src		; read FLG (low byte), BD (high byte)
  1097                              <1> d0	mov byte [bp + ?errordata], 6
  1098                              <1> .error_CY_1:
  1099 00000131 72BB                <1> 	jc .error
  1100                              <1> 
  1101 00000133 8946F6              <1> 	mov word [bp + ?frame_descriptor_flg_and_bd], ax
  1102 00000136 89C3                <1> 	mov bx, ax
  1103 00000138 80E3C0              <1> 	and bl, lz4_flg_version_mask
  1104 0000013B 80FB40              <1> 	cmp bl, lz4_flg_version		; version correct ?
  1105                              <1> d0	mov byte [bp + ?errordata], 7
  1106                              <1> .error_NZ_1:
  1107 0000013E 75AE                <1> 	jne .error			; no -->
  1108                              <1> 
  1109 00000140 A9038F              <1> 	test ax, (lz4_bd_reserved_mask << 8) 		 | lz4_flg_reserved | lz4_flg_dict_id	; unsupported bits set?
  1111                              <1> d0	mov byte [bp + ?errordata], 8
  1112 00000143 75F9                <1> 	jnz .error_NZ_1			; yes -->
  1113                              <1> 
  1114                              <1> 		; not checked: lz4_flg_b_indep (linked is always supported),
  1115                              <1> 		;  lz4_flg_b_checksum, lz4_flg_c_checksum (both checked later)
  1116                              <1> 
  1117 00000145 A808                <1> 	test al, lz4_flg_c_size		; content size field present ?
  1118 00000147 7407                <1> 	jz @F				; no -->
  1119 00000149 B108                <1> 	mov cl, 8
  1120 0000014B E8C201              <1> 	call read_le_data_src		; (skip content size field)
  1121                              <1> d0	mov byte [bp + ?errordata], 9
  1122 0000014E 72E1                <1> 	jc .error_CY_1
  1123                              <1> @@:
  1124 00000150 B101                <1> 	mov cl, 1
  1125 00000152 E8BB01              <1> 	call read_le_data_src		; (skip header checksum field)
  1126                              <1> d0	mov byte [bp + ?errordata], 0Ah
  1127 00000155 72DA                <1> 	jc .error_CY_1
  1128                              <1> 
  1129                              <1> .loop_block:
  1130                              <1> %if _COUNTER
  1131                              <1> 	mov al, '#'
  1132                              <1> 	call disp_al
  1133                              <1> %endif
  1134 00000157 B90400              <1> 	mov cx, 4
  1135 0000015A E8B301              <1> 	call read_le_data_src		; read block size field
  1136                              <1> 					; leaves ds:si -> source
  1137                              <1> d0	mov byte [bp + ?errordata], 0Bh
  1138 0000015D 72D2                <1> 	jc .error_CY_1
  1139                              <1> 
  1140 0000015F 85D2                <1> 	test dx, dx			; nonzero ?
  1141 00000161 7512                <1> 	jnz @FF
  1142 00000163 85C0                <1> 	test ax, ax
  1143 00000165 750E                <1> 	jnz @FF				; yes -->
  1144                              <1> 
  1145 00000167 F646F604            <1> 	test byte [bp + ?frame_descriptor_flg_and_bd], lz4_flg_c_checksum
  1146 0000016B 7405                <1> 	jz @F
  1147                              <1> 		; cx = 4 already
  1148 0000016D E8A001              <1> 	call read_le_data_src		; (skip c checksum field)
  1149                              <1> d0	mov byte [bp + ?errordata], 0Ch
  1150                              <1> .error_CY_2:
  1151 00000170 72BF                <1> 	jc .error_CY_1
  1152                              <1> @@:
  1153 00000172 E96CFF              <1> 	jmp .loop_frame			; next frame, if any -->
  1154                              <1> 
  1155                              <1> 
  1156                              <1> @@:
  1157 00000175 1E                  <1> 	 push ds
  1158 00000176 56                  <1> 	 push si			; -> source
  1159 00000177 89D3                <1> 	mov bx, dx
  1160 00000179 80E77F              <1> 	and bh, ~80h			; clear "uncompressed" flag
  1161 0000017C 89C1                <1> 	mov cx, ax			; bx:cx = block size
  1162 0000017E E8FF01              <1> 	call normalise_pointer_with_displacement_bxcx
  1163                              <1> 					; -> source after block
  1164 00000181 8F46F8              <1> 	 pop word [bp + ?src_behind_block]
  1165 00000184 8F46FA              <1> 	 pop word [bp + ?src_behind_block + 2]
  1166                              <1> d0	mov byte [bp + ?errordata], 1Eh
  1167 00000187 7303E962FF          <1> 	jc .error
  1168 0000018C F6C680              <1> 	test dh, 80h			; is it uncompressed ?
  1169 0000018F 7448                <1> 	jz .compressed			; no -->
  1170                              <1> 
  1171                              <1> .uncompressed:
  1172 00000191 87DA                <1> 	xchg bx, dx			; get size without "uncompressed" flag
  1173 00000193 E8EB00              <1> 	call lz4_copy_literal_or_uncompressed
  1174                              <1> d0	mov byte [bp + ?errordata], 0Dh
  1175 00000196 72D8                <1> 	jc .error_CY_2
  1176                              <1> 
  1177                              <1> .end_block:
  1178 00000198 FF76FA              <1> 	 push word [bp + ?src_behind_block + 2]
  1179 0000019B FF76F8              <1> 	 push word [bp + ?src_behind_block]
  1180 0000019E E81402              <1> 	call pointer_to_linear
  1181 000001A1 89C1                <1> 	mov cx, ax
  1182 000001A3 89D3                <1> 	mov bx, dx			; bx:cx = linear ?src_behind_block
  1183                              <1> 
  1184 000001A5 FF76F4              <1> 	 push word [bp + ?src + 2]
  1185 000001A8 FF76F2              <1> 	 push word [bp + ?src]
  1186 000001AB E80702              <1> 	call pointer_to_linear		; dx:ax = linear ?src
  1187                              <1> 
  1188 000001AE 29C1                <1> 	sub cx, ax
  1189 000001B0 19D3                <1> 	sbb bx, dx			; ?src_behind_block - ?src
  1190                              <1> 					;  = amount to skip
  1191                              <1> d0	mov byte [bp + ?errordata], 0Fh
  1192 000001B2 72BC                <1> 	jc .error_CY_2
  1193                              <1> 
  1194 000001B4 294EE6              <1> 	sub word [bp + ?length_of_source], cx
  1195 000001B7 195EE8              <1> 	sbb word [bp + ?length_of_source + 2], bx
  1196                              <1> d0	mov byte [bp + ?errordata], 10h
  1197                              <1> .error_CY_3:
  1198 000001BA 72B4                <1> 	jc .error_CY_2			; not enough data to skip -->
  1199                              <1> 
  1200 000001BC FF76FA              <1> 	push word [bp + ?src_behind_block + 2]
  1201 000001BF FF76F8              <1> 	push word [bp + ?src_behind_block]
  1202 000001C2 8F46F2              <1> 	pop word [bp + ?src]
  1203 000001C5 8F46F4              <1> 	pop word [bp + ?src + 2]	; set ?src -> behind block
  1204                              <1> 
  1205 000001C8 F646F610            <1> 	test byte [bp + ?frame_descriptor_flg_and_bd], lz4_flg_b_checksum
  1206 000001CC 7408                <1> 	jz @F				; no block checksum -->
  1207 000001CE B90400              <1> 	mov cx, 4
  1208 000001D1 E83C01              <1> 	call read_le_data_src		; (skip block checksum field)
  1209                              <1> d0	mov byte [bp + ?errordata], 0Eh
  1210 000001D4 72E4                <1> 	jc .error_CY_3
  1211                              <1> @@:
  1212                              <1> 
  1213 000001D6 E97EFF              <1> 	jmp .loop_block
  1214                              <1> 
  1215                              <1> 
  1216                              <1> .compressed:
  1217                              <1> .loop_sequence:
  1218                              <1> 
  1219                              <1> %if _COUNTER
  1220                              <1> 	inc byte [bp + ?counter]
  1221                              <1> 	test byte [bp + ?counter], _COUNTER - 1
  1222                              <1> 	jnz @F
  1223                              <1> 	mov al, '.'
  1224                              <1> 	call disp_al
  1225                              <1> @@:
  1226                              <1> %endif
  1227                              <1> 
  1228 000001D9 BB[5402]            <1> 	mov bx, .lodsb
  1229 000001DC E8F500              <1> 	call lz4_func_bx_with_src	; load token
  1230                              <1> d0	mov byte [bp + ?errordata], 11h
  1231 000001DF 72D9                <1> 	jc .error_CY_3
  1232 000001E1 8846FC              <1> 	mov byte [bp + ?token], al
  1233                              <1> 
  1234 000001E4 B104                <1> 	mov cl, 4
  1235 000001E6 D2E8                <1> 	shr al, cl
  1236 000001E8 E8FE00              <1> 	call lz4_get_length		; dx:cx = length of literals
  1237                              <1> d0	mov byte [bp + ?errordata], 12h
  1238 000001EB 72CD                <1> 	jc .error_CY_3
  1239                              <1> 
  1240 000001ED 89C8                <1> 	mov ax, cx			; dx:ax = length of literals (may be 0)
  1241 000001EF E88F00              <1> 	call lz4_copy_literal_or_uncompressed
  1242                              <1> 					; copy over the literals
  1243                              <1> d0	mov byte [bp + ?errordata], 13h
  1244 000001F2 72C6                <1> 	jc .error_CY_3
  1245                              <1> 
  1246 000001F4 E87500              <1> 	call lz4_check_behind_block_higher_than_src
  1247                              <1> 					; do we have more data in this block ?
  1248 000001F7 7258                <1> 	jc .end_sequence		; no -->
  1249                              <1> 
  1250 000001F9 BB[6002]            <1> 	mov bx, .lodsw
  1251 000001FC E8D500              <1> 	call lz4_func_bx_with_src	; load match offset
  1252                              <1> d0	mov byte [bp + ?errordata], 14h
  1253                              <1> .error_CY_4:
  1254 000001FF 72B9                <1> 	jc .error_CY_3
  1255                              <1> 
  1256 00000201 85C0                <1> 	test ax, ax			; offset is 0 ?
  1257                              <1> d0	mov byte [bp + ?errordata], 15h
  1258 00000203 F9                  <1> 	stc
  1259 00000204 74F9                <1> 	jz .error_CY_4			; yes, error -->
  1260                              <1> 
  1261 00000206 89C1                <1> 	mov cx, ax
  1262 00000208 F7D9                <1> 	neg cx				; -1 .. -65535
  1263 0000020A BBFFFF              <1> 	mov bx, -1			; sign-extend (always negative sense)
  1264                              <1> 
  1265 0000020D FF76EC              <1> 	 push word [bp + ?dst + 2]
  1266 00000210 FF76EA              <1> 	 push word [bp + ?dst]
  1267 00000213 E86A01              <1> 	call normalise_pointer_with_displacement_bxcx
  1268 00000216 5E                  <1> 	 pop si
  1269 00000217 1F                  <1> 	 pop ds				; ds:si -> source of matching
  1270                              <1> d0	mov byte [bp + ?errordata], 1Fh
  1271 00000218 7203E9D1FE          <1> 	jnc .error
  1272                              <1> 
  1273 0000021D 8CD8                <1> 	mov ax, ds			; is source of matching within ?dst ?
  1274 0000021F 3946F0              <1> 	cmp word [bp + ?original_dst + 2], ax
  1275                              <1> d0	mov byte [bp + ?errordata], 16h
  1276                              <1> .error_A_1:
  1277 00000222 7603E9C7FE          <1> 	ja .error
  1278 00000227 7205                <1> 	jb @F
  1279 00000229 3976EE              <1> 	cmp word [bp + ?original_dst], si
  1280                              <1> d0	mov byte [bp + ?errordata], 17h
  1281 0000022C 77F4                <1> 	ja .error_A_1			; no, ?original_dst is above it -->
  1282                              <1> @@:
  1283                              <1> 
  1284 0000022E 8A46FC              <1> 	mov al, byte [bp + ?token]
  1285 00000231 240F                <1> 	and al, 0Fh			; get match length from token
  1286 00000233 E8B300              <1> 	call lz4_get_length		; dx:cx = length of match - 4
  1287                              <1> d0	mov byte [bp + ?errordata], 18h
  1288 00000236 72C7                <1> 	jc .error_CY_4
  1289 00000238 89C8                <1> 	mov ax, cx			; dx:ax = length of match - 4
  1290 0000023A 83C004              <1> 	add ax, 4
  1291 0000023D 83D200              <1> 	adc dx, 0			; dx:ax = length of match
  1292                              <1> d0	mov byte [bp + ?errordata], 19h
  1293 00000240 72BD                <1> 	jc .error_CY_4
  1294 00000242 E85100              <1> 	call lz4_copy_data		; give ?dst -> dest, ds:si -> source
  1295                              <1> 		; returns: ?dst incremented, ds:si -> after match source
  1296                              <1> d0	mov byte [bp + ?errordata], 1Ah
  1297 00000245 72B8                <1> 	jc .error_CY_4
  1298                              <1> 
  1299                              <1> %if _ALLOW_OVERLAPPING
  1300 00000247 E8ED00              <1> 	call check_pointers_not_overlapping
  1301                              <1> d0	mov byte [bp + ?errordata], 1Ch
  1302 0000024A 72B3                <1> 	jc .error_CY_4
  1303                              <1> %endif
  1304                              <1> 
  1305                              <1> .next_sequence:
  1306 0000024C E81D00              <1> 	call lz4_check_behind_block_higher_than_src
  1307 0000024F 7388                <1> 	jnc .loop_sequence		; process next sequence -->
  1308                              <1> 
  1309                              <1> .end_sequence:
  1310 00000251 E944FF              <1> 	jmp .end_block
  1311                              <1> 
  1312                              <1> 
  1313                              <1> 		; INP:	ds:si -> source data
  1314                              <1> 		;	?length_of_source
  1315                              <1> 		; OUT:	CY if error (source buffer too small)
  1316                              <1> 		;	NC if success,
  1317                              <1> 		;	 al = value read
  1318                              <1> 		;	 ds:si incremented (NOT normalised)
  1319                              <1> 		;	 ?length_of_source decremented
  1320                              <1> .lodsb:
  1321 00000254 836EE601            <1> 	sub word [bp + ?length_of_source], 1
  1322 00000258 835EE800            <1> 	sbb word [bp + ?length_of_source + 2], 0
  1323 0000025C 7201                <1> 	jb .retn
  1324 0000025E AC                  <1> 	lodsb
  1325                              <1> .retn:
  1326 0000025F C3                  <1> 	retn
  1327                              <1> 
  1328                              <1> 
  1329                              <1> 		; INP:	ds:si -> source data
  1330                              <1> 		;	?length_of_source
  1331                              <1> 		; OUT:	CY if error (source buffer too small)
  1332                              <1> 		;	NC if success,
  1333                              <1> 		;	 ax = value read
  1334                              <1> 		;	 ds:si incremented (NOT normalised)
  1335                              <1> 		;	 ?length_of_source decremented
  1336                              <1> .lodsw:
  1337 00000260 836EE602            <1> 	sub word [bp + ?length_of_source], 2
  1338 00000264 835EE800            <1> 	sbb word [bp + ?length_of_source + 2], 0
  1339 00000268 72F5                <1> 	jb .retn
  1340 0000026A AD                  <1> 	lodsw
  1341 0000026B C3                  <1> 	retn
  1342                              <1> 
  1343                              <1> 
  1344                              <1> 		; INP:	?src_behind_block -> block end (normalised)
  1345                              <1> 		;	?src -> current address in source buffer
  1346                              <1> 		; OUT:	CY if ?src is >= (above-or-equal) ?src_behind_block
  1347                              <1> 		;	NC else (?src is below ?src_behind_block, more data)
  1348                              <1> 		; CHG:	ax, dx
  1349                              <1> 		;
  1350                              <1> 		; Note:	Although ?src should always equal ?src_behind_block
  1351                              <1> 		;	 if CY here, we actually check for above-or-equal.
  1352                              <1> lz4_check_behind_block_higher_than_src:
  1353 0000026C 8B56FA              <1> 	mov dx, word [bp + ?src_behind_block + 2]
  1354 0000026F 8B46F8              <1> 	mov ax, word [bp + ?src_behind_block]
  1355                              <1> 					; dx:ax -> behind block
  1356                              <1> 
  1357 00000272 3956F4              <1> 	cmp word [bp + ?src + 2], dx	; compare segment
  1358 00000275 7708                <1> 	ja .error			; ?src > dx:ax -->
  1359 00000277 7205                <1> 	jb .success			; ?src < dx:ax -->
  1360 00000279 3946F2              <1> 	cmp word [bp + ?src], ax	; segment is same, compare offset
  1361 0000027C 7301                <1> 	jae .error			; ?src >= dx:ax -->
  1362                              <1> 
  1363                              <1> .success:
  1364 0000027E A8                  <1> 	db __TEST_IMM8			; (NC)
  1365                              <1> .error:
  1366 0000027F F9                  <1> 	stc
  1367 00000280 C3                  <1> 	retn
  1368                              <1> 
  1369                              <1> 
  1370                              <1> 		; INP:	?dst -> destination (normalised)
  1371                              <1> 		;	?src -> source (normalised)
  1372                              <1> 		;	dx:ax = how long the literal data is (0 is valid)
  1373                              <1> 		; OUT:	?dst incremented (normalised)
  1374                              <1> 		;	?src incremented (normalised)
  1375                              <1> 		;	?length_of_destination shortened
  1376                              <1> 		;	?length_of_source shortened
  1377                              <1> 		;	CY if error (either buffer too small)
  1378                              <1> 		;	NC if success
  1379                              <1> 		; CHG:	cx, dx, ax, es, di, ds, si
  1380                              <1> lz4_copy_literal_or_uncompressed:
  1381 00000281 C576F2              <1> 	lds si, [bp + ?src]
  1382                              <1> 
  1383 00000284 2946E6              <1> 	sub word [bp + ?length_of_source], ax
  1384 00000287 1956E8              <1> 	sbb word [bp + ?length_of_source + 2], dx
  1385                              <1> 					; enough data exists ?
  1386 0000028A 7209                <1> 	jb .return			; no --> (CY)
  1387                              <1> 
  1388 0000028C E80700              <1> 	call lz4_copy_data		; CY/NC depending on status
  1389                              <1> 
  1390 0000028F 8976F2              <1> 	mov word [bp + ?src], si
  1391 00000292 8C5EF4              <1> 	mov word [bp + ?src + 2], ds
  1392                              <1> 					; (CF preserved)
  1393                              <1> .return:
  1394 00000295 C3                  <1> 	retn
  1395                              <1> 
  1396                              <1> 
  1397                              <1> 		; INP:	?dst -> destination (normalised)
  1398                              <1> 		;	ds:si -> source (normalised)
  1399                              <1> 		;	dx:ax = how long the data is (0 is valid)
  1400                              <1> 		; OUT:	?dst incremented (normalised)
  1401                              <1> 		;	ds:si incremented (normalised)
  1402                              <1> 		;	?length_of_destination shortened
  1403                              <1> 		;	CY if error (buffer too small)
  1404                              <1> 		;	NC if success
  1405                              <1> 		;	Instead of returning, this may jump to depack.end
  1406                              <1> 		;	 if the destination segment grows up to the value
  1407                              <1> 		;	 stored in the ?dst_max_segment variable. It is
  1408                              <1> 		;	 assumed that this will use the stack frame to leave
  1409                              <1> 		;	 the function, therefore discarding any of the stack
  1410                              <1> 		;	 contents between the frame and the stack top.
  1411                              <1> 		; CHG:	cx, dx, ax, es, di, ds, si
  1412                              <1> lz4_copy_data:
  1413                              <1> d0	inc byte [bp + ?errordata + 1]
  1414 00000296 2946E0              <1> 	sub word [bp + ?length_of_destination], ax
  1415 00000299 1956E2              <1> 	sbb word [bp + ?length_of_destination + 2], dx
  1416                              <1> 					; enough space left ?
  1417 0000029C 7234                <1> 	jb .error			; no -->
  1418                              <1> 
  1419 0000029E C47EEA              <1> 	les di, [bp + ?dst]
  1420                              <1> .loop:
  1421 000002A1 B9F0FF              <1> 	mov cx, 64 * 1024 - 16		; block size
  1422                              <1> 		; If both pointers are normalised, moving 0FFF0h bytes is
  1423                              <1> 		;  valid and results in a maximum offset of 0FFFFh in either.
  1424                              <1> 
  1425 000002A4 85D2                <1> 	test dx, dx			; >= 1_0000h ?
  1426 000002A6 7508                <1> 	jnz @F				; yes, full block -->
  1427 000002A8 85C0                <1> 	test ax, ax			; == 0 ?
  1428 000002AA 7415                <1> 	jz .end				; yes, done -->
  1429 000002AC 39C8                <1> 	cmp ax, cx			; can move in one (last) block ?
  1430 000002AE 7607                <1> 	jbe .last			; yes -->
  1431                              <1> @@:
  1432                              <1> 					; no, move one block and continue
  1433 000002B0 29C8                <1> 	sub ax, cx
  1434 000002B2 83DA00              <1> 	sbb dx, 0			; left over remaining
  1435 000002B5 EB03                <1> 	jmp .copy
  1436                              <1> 
  1437                              <1> .last:
  1438 000002B7 91                  <1> 	xchg cx, ax			; cx = remaining length
  1439 000002B8 31C0                <1> 	xor ax, ax			; no more remaining
  1440                              <1> 
  1441                              <1> .copy:
  1442 000002BA F3A4                <1> 	rep movsb			; move one block (full or partial)
  1443                              <1> 
  1444 000002BC E89600              <1> 	call normalise_both_pointers
  1445 000002BF EBE0                <1> 	jmp .loop
  1446                              <1> 
  1447                              <1> .end:
  1448 000002C1 897EEA              <1> 	mov word [bp + ?dst], di
  1449 000002C4 8C46EC              <1> 	mov word [bp + ?dst + 2], es
  1450 000002C7 8CC0                <1> 	mov ax, es
  1451 000002C9 3B46E4              <1> 	cmp ax, word [bp + ?dst_max_segment]
  1452 000002CC 7203E91CFE          <1> 	jae depack.end
  1453                              <1> 
  1454 000002D1 A8                  <1> 	db __TEST_IMM8			; (NC)
  1455                              <1> .error:
  1456 000002D2 F9                  <1> 	stc
  1457 000002D3 C3                  <1> 	retn
  1458                              <1> 
  1459                              <1> 
  1460                              <1> 		; INP:	?src -> source data
  1461                              <1> 		;	bx = function to call
  1462                              <1> 		; OUT:	ds:si = ?src -> behind data (normalised)
  1463                              <1> 		;	CY if error (buffer too small)
  1464                              <1> 		;	NC if success
  1465                              <1> 		;	(CF is passed from what the function at bx returns)
  1466                              <1> 		;
  1467                              <1> 		; Protocol of function in bx called by this:
  1468                              <1> 		; INP:	ds:si -> source data
  1469                              <1> 		;	?length_of_source
  1470                              <1> 		;	(may take more inputs depending on function)
  1471                              <1> 		; OUT:	ds:si incremented (NOT normalised)
  1472                              <1> 		;	?length_of_source decremented
  1473                              <1> 		;	CY if error (buffer too small or other error)
  1474                              <1> 		;	NC if success
  1475                              <1> 		;	(may give more outputs depending on function)
  1476                              <1> lz4_func_bx_with_src:
  1477 000002D4 C576F2              <1> 	lds si, [bp + ?src]
  1478 000002D7 FFD3                <1> 	call bx
  1479 000002D9 9C                  <1> 	pushf
  1480 000002DA 1E                  <1> 	 push ds
  1481 000002DB 56                  <1> 	 push si
  1482 000002DC E88500              <1> 	call normalise_pointer
  1483 000002DF 5E                  <1> 	 pop si
  1484 000002E0 1F                  <1> 	 pop ds
  1485 000002E1 8976F2              <1> 	mov word [bp + ?src], si
  1486 000002E4 8C5EF4              <1> 	mov word [bp + ?src + 2], ds
  1487 000002E7 9D                  <1> 	popf
  1488 000002E8 C3                  <1> 	retn
  1489                              <1> 
  1490                              <1> 
  1491                              <1> 		; INP:	?src -> source data
  1492                              <1> 		;	?length_of_source
  1493                              <1> 		;	al = first field data (0 to 15)
  1494                              <1> 		; OUT:	dx:cx = length value
  1495                              <1> 		;	?src incremented
  1496                              <1> 		;	?length_of_source decremented
  1497                              <1> 		;	CY if error (too high or out of source data)
  1498                              <1> 		;	NC if success
  1499                              <1> 		; CHG:	ax, bx
  1500                              <1> lz4_get_length:
  1501 000002E9 1E                  <1> 	push ds
  1502 000002EA 56                  <1> 	push si
  1503                              <1> 
  1504 000002EB 31C9                <1> 	xor cx, cx
  1505 000002ED 31D2                <1> 	xor dx, dx			; dx:cx = length field
  1506 000002EF B40F                <1> 	mov ah, 15			; first byte maximum value
  1507                              <1> .loop:
  1508 000002F1 00C1                <1> 	add cl, al
  1509 000002F3 80D500              <1> 	adc ch, 0
  1510 000002F6 83D200              <1> 	adc dx, 0			; add in this byte
  1511 000002F9 7211                <1> 	jc .error			; if too high -->
  1512 000002FB 38E0                <1> 	cmp al, ah			; is this the maximum value ?
  1513 000002FD 750C                <1> 	jne .end			; no -->
  1514 000002FF BB[5402]            <1> 	mov bx, depack.lodsb
  1515 00000302 E8CFFF              <1> 	call lz4_func_bx_with_src	; load next byte
  1516 00000305 7205                <1> 	jc .error
  1517 00000307 B4FF                <1> 	mov ah, 255			; next maximum value is 255
  1518 00000309 EBE6                <1> 	jmp .loop			; -->
  1519                              <1> 
  1520                              <1> .end:
  1521 0000030B A8                  <1> 	db __TEST_IMM8			; (NC)
  1522                              <1> .error:
  1523 0000030C F9                  <1> 	stc
  1524                              <1> 
  1525 0000030D 5E                  <1> 	pop si
  1526 0000030E 1F                  <1> 	pop ds
  1527 0000030F C3                  <1> 	retn
  1528                              <1> 
  1529                              <1> 
  1530                              <1> 		; INP:	?src -> source data (normalised)
  1531                              <1> 		;	cx = size to read, 1 to 4 or higher (at most 0FFF0h)
  1532                              <1> 		;	?length_of_source
  1533                              <1> 		; OUT:	If cx >= 4,
  1534                              <1> 		;	 dx:ax = value read as little-endian
  1535                              <1> 		;	If cx == 3,
  1536                              <1> 		;	 dl:ax = value read
  1537                              <1> 		;	If cx == 2,
  1538                              <1> 		;	 ax = value read
  1539                              <1> 		;	If cx == 1,
  1540                              <1> 		;	 al = value read
  1541                              <1> 		;	If cx == 0,
  1542                              <1> 		;	 invalid, CY
  1543                              <1> 		;	ds:si = ?src = incremented source (normalised)
  1544                              <1> 		;	?length_of_source decremented
  1545                              <1> 		;	CY if error (source buffer too small, or cx zero)
  1546                              <1> 		;	NC if success
  1547                              <1> 		; CHG:	ds, si, dx, ax
  1548                              <1> 		;
  1549                              <1> 		; Note:	Always reads four bytes at INP:ds:si -> data.
  1550                              <1> read_le_data_src:
  1551 00000310 E323                <1> 	jcxz .error
  1552                              <1> 
  1553 00000312 294EE6              <1> 	sub word [bp + ?length_of_source], cx
  1554 00000315 835EE800            <1> 	sbb word [bp + ?length_of_source + 2], 0
  1555 00000319 721A                <1> 	jb .error
  1556                              <1> 
  1557 0000031B C576F2              <1> 	lds si, [bp + ?src]
  1558                              <1> 
  1559 0000031E AD                  <1> 	lodsw
  1560 0000031F 92                  <1> 	xchg ax, dx		; dx = low word (first)
  1561 00000320 AD                  <1> 	lodsw			; ax = high word (second)
  1562 00000321 92                  <1> 	xchg ax, dx		; fix order, dx:ax = dword
  1563                              <1> 
  1564 00000322 83EE04              <1> 	sub si, 4
  1565 00000325 01CE                <1> 	add si, cx
  1566                              <1> 
  1567 00000327 1E                  <1> 	 push ds
  1568 00000328 56                  <1> 	 push si
  1569 00000329 E83800              <1> 	call normalise_pointer
  1570 0000032C 5E                  <1> 	 pop si
  1571 0000032D 1F                  <1> 	 pop ds
  1572 0000032E 8976F2              <1> 	mov word [bp + ?src], si
  1573 00000331 8C5EF4              <1> 	mov word [bp + ?src + 2], ds
  1574                              <1> 
  1575 00000334 A8                  <1> 	db __TEST_IMM8		; (NC)
  1576                              <1> .error:
  1577 00000335 F9                  <1> 	stc
  1578 00000336 C3                  <1> 	retn
  1579                              <1> 
   878                                  %endif
   879                                  
   880                                  
   881                                  %if _SNAPPY
   882                                  	%include "snappy.asm"
   883                                  %endif
   884                                  
   885                                  
   886                                  %if _EXODECR
   887                                  	%include "exodecr.asm"
   888                                  %endif
   889                                  
   890                                  
   891                                  %if _X
   892                                  	%include "x.asm"
   893                                  %endif
   894                                  
   895                                  
   896                                  %if _HEATSHRINK
   897                                  	%include "heatshr.asm"
   898                                  %endif
   899                                  
   900                                  
   901                                  %if _LZD
   902                                  	%include "lzd.asm"
   903                                  %endif
   904                                  
   905                                  
   906                                  %if _LZO
   907                                  	%include "lzo.asm"
   908                                  %endif
   909                                  
   910                                  
   911                                  %if _ALLOW_OVERLAPPING
   912                                  		; INP:	?src, ?dst
   913                                  		; OUT:	CY if error (?src < ?dst)
   914                                  		;	NC if success
   915                                  		; CHG:	ax, bx, cx, dx
   916                                  check_pointers_not_overlapping:
   917 00000337 FF76EC                  	 push word [bp + ?dst + 2]
   918 0000033A FF76EA                  	 push word [bp + ?dst]
   919 0000033D E87500                  	call pointer_to_linear
   920                                  
   921 00000340 91                      	xchg cx, ax
   922 00000341 87DA                    	xchg bx, dx			; bx:cx = linear ?dst after write
   923                                  
   924 00000343 FF76F4                  	 push word [bp + ?src + 2]
   925 00000346 FF76F2                  	 push word [bp + ?src]
   926 00000349 E86900                  	call pointer_to_linear		; dx:ax = linear ?src before next read
   927                                  
   928 0000034C 39DA                    	cmp dx, bx			; ?src >= ?dst ?
   929 0000034E 7704                    	ja @F
   930 00000350 7202                    	jb .ret				; (CY)
   931 00000352 39C8                    	cmp ax, cx
   932                                  	; jb .ret			; (CY)
   933                                  					; (NC) yes, no error
   934                                  @@:
   935                                  .ret:
   936 00000354 C3                      	retn
   937                                  %endif
   938                                  
   939                                  	; This leaves the lframe context created within the
   940                                  	;  specific depacker's file. The above function
   941                                  	;  check_pointers_not_overlapping uses the frame.
   942                                  	lleave ctx
   943                                  
   944                                  
   945                                  		; INP:	ds:si = pointer
   946                                  		;	es:di = pointer
   947                                  		; OUT:	ds:si normalised
   948                                  		;	es:di normalised
   949                                  normalise_both_pointers:
   950 00000355 1E                      	 push ds
   951 00000356 56                      	 push si
   952 00000357 E80A00                  	call normalise_pointer
   953 0000035A 5E                      	 pop si
   954 0000035B 1F                      	 pop ds
   955                                  
   956 0000035C 06                      	 push es
   957 0000035D 57                      	 push di
   958 0000035E E80300                  	call normalise_pointer
   959 00000361 5F                      	 pop di
   960 00000362 07                      	 pop es
   961 00000363 C3                      	retn
   962                                  
   963                                  
   964                                  		; INP:	word [ss:sp + 2] = segment
   965                                  		;	word [ss:sp] = offset
   966                                  		;
   967                                  		; Note:	Does not work correctly with pointers that point to
   968                                  		;	 a HMA location. Do not use then!
   969                                  normalise_pointer:
   970                                  	lframe near
   971                                  	lpar word,	segment
   972                                  	lpar word,	offset
   973                                  	lpar_return
   974 00000364 5589E5                  	lenter
   975 00000367 53                      	push bx
   976 00000368 51                      	push cx
   977                                  
   978 00000369 31DB                    	xor bx, bx
   979 0000036B 31C9                    	xor cx, cx
   980 0000036D FF7606                  	 push word [bp + ?segment]
   981 00000370 FF7604                  	 push word [bp + ?offset]
   982 00000373 E80A00                  	call normalise_pointer_with_displacement_bxcx
   983 00000376 8F4604                  	 pop word [bp + ?offset]
   984 00000379 8F4606                  	 pop word [bp + ?segment]
   985                                  
   986 0000037C 59                      	pop cx
   987 0000037D 5B                      	pop bx
   988 0000037E 5D                      	lleave
   989 0000037F C3                      	lret
   990                                  
   991                                  
   992                                  		; INP:	word [ss:sp + 2] = segment
   993                                  		;	word [ss:sp] = offset
   994                                  		;	bx:cx = add/sub displacement
   995                                  		; OUT:	CY if the displacement carries
   996                                  		;	NC if not
   997                                  normalise_pointer_with_displacement_bxcx:
   998                                  	lframe near
   999                                  	lpar word,	segment
  1000                                  	lpar word,	offset
  1001                                  	lpar_return
  1002 00000380 5589E5                  	lenter
  1003 00000383 50                      	push ax
  1004 00000384 51                      	push cx
  1005 00000385 52                      	push dx
  1006                                  
  1007 00000386 FF7606                  	 push word [bp + ?segment]
  1008 00000389 FF7604                  	 push word [bp + ?offset]
  1009 0000038C E82600                  	call pointer_to_linear
  1010                                  
  1011                                  	; push bx
  1012                                  	; 				; sign-extend cx into bx:cx
  1013                                  	; cmp cx, 8000h			; CY if < 8000h (NC if negative)
  1014                                  	; cmc				; NC if positive
  1015                                  	; sbb bx, bx			; 0 if was NC, -1 if was CY
  1016                                  
  1017 0000038F 01C1                    	add cx, ax
  1018 00000391 11DA                    	adc dx, bx			; dx:cx = dx:ax + bx:cx
  1019                                  	; pop bx
  1020 00000393 9F                      	lahf				; ah = flags
  1021                                  
  1022                                  %if 0
  1023                                  		; Adds in HMA support for this function. Not currently used.
  1024                                  	cmp dx, 10h			; dx:ax >= 10_0000h ?
  1025                                  	jb @F				; no, linear-to-pointer normally -->
  1026                                  	; ja .error
  1027                                  
  1028                                  	add cx, 10h
  1029                                  	; jc .error
  1030                                  	mov word [bp + ?offset], cx
  1031                                  	or word [bp + ?segment], -1
  1032                                  	jmp .return
  1033                                  @@:
  1034                                  %endif
  1035                                  
  1036 00000394 51                      	push cx
  1037 00000395 83E10F                  	and cx, 15
  1038 00000398 894E04                  	mov word [bp + ?offset], cx
  1039 0000039B 59                      	pop cx
  1040                                  
  1041                                  %rep 4
  1042                                  	shr dx, 1
  1043                                  	rcr cx, 1
  1044                                  %endrep
  1042 0000039C D1EA                <1>  shr dx, 1
  1043 0000039E D1D9                <1>  rcr cx, 1
  1042 000003A0 D1EA                <1>  shr dx, 1
  1043 000003A2 D1D9                <1>  rcr cx, 1
  1042 000003A4 D1EA                <1>  shr dx, 1
  1043 000003A6 D1D9                <1>  rcr cx, 1
  1042 000003A8 D1EA                <1>  shr dx, 1
  1043 000003AA D1D9                <1>  rcr cx, 1
  1045 000003AC 894E06                  	mov word [bp + ?segment], cx
  1046                                  
  1047                                  	; test dx, dx
  1048                                  	; jnz .error
  1049                                  
  1050                                  .return:
  1051                                  
  1052 000003AF 9E                      	sahf				; restore flags from ah
  1053 000003B0 5A                      	pop dx
  1054 000003B1 59                      	pop cx
  1055 000003B2 58                      	pop ax
  1056 000003B3 5D                      	lleave
  1057 000003B4 C3                      	lret
  1058                                  
  1059                                  
  1060                                  		; INP:	word [ss:sp + 2] = segment
  1061                                  		;	word [ss:sp] = offset
  1062                                  		; OUT:	dx:ax = linear address
  1063                                  pointer_to_linear:
  1064                                  	lframe near
  1065                                  	lpar word,	segment
  1066                                  	lpar word,	offset
  1067 000003B5 5589E5                  	lenter
  1068                                  
  1069 000003B8 8B4606                  	mov ax, word [bp + ?segment]
  1070 000003BB 31D2                    	xor dx, dx
  1071                                  %rep 4
  1072                                  	shl ax, 1
  1073                                  	rcl dx, 1
  1074                                  %endrep
  1072 000003BD D1E0                <1>  shl ax, 1
  1073 000003BF D1D2                <1>  rcl dx, 1
  1072 000003C1 D1E0                <1>  shl ax, 1
  1073 000003C3 D1D2                <1>  rcl dx, 1
  1072 000003C5 D1E0                <1>  shl ax, 1
  1073 000003C7 D1D2                <1>  rcl dx, 1
  1072 000003C9 D1E0                <1>  shl ax, 1
  1073 000003CB D1D2                <1>  rcl dx, 1
  1075                                  
  1076 000003CD 034604                  	add ax, word [bp + ?offset]
  1077 000003D0 83D200                  	adc dx, 0
  1078                                  
  1079 000003D3 5D                      	lleave
  1080 000003D4 C20400                  	lret
  1081                                  
  1082                                  
  1083 000003D7 90<rep 9h>              	align 16
  1084                                  init1_end:
  1085                                  
  1086                                  
  1087                                  	section INIT0
  1088                                  %if _TEST_PROGRAM
  1089                                  init0_msg:
  1090 00000114 4572726F723A204E6F-     .error_stderr:	db "Error: Not enough memory allocated.",13,10
  1090 0000011D 7420656E6F75676820-
  1090 00000126 6D656D6F727920616C-
  1090 0000012F 6C6F63617465642E0D-
  1090 00000138 0A                 
  1091                                  .error_stderr.length: equ $ - .error_stderr
  1092 00000139 39333437                .error_stdout:	_autodigits paras(_TEST_PROGRAM_DECOMPRESSED_SIZE 				+ (payload_end - payload) 				+ (init1_end - init1_start) 				+ ADDITIONAL_MEMORY 				)
  1097 0000013D 0D0A                    		db 13,10
  1098                                  .error_stdout.length: equ $ - .error_stdout
  1099                                  
  1100 0000013F 90<rep C1h>             	align 512
  1101                                  %if ($ - $$) != 512
  1102                                   %error Wrong INIT0 size
  1103                                  %endif
  1104                                  %endif
  1105                                  
  1106                                  	align 16
  1107                                  init0_end:
  1108                                  
  1109                                  
  1110                                  %assign num (init1_end - init1_start) + (init0_end - init0_start)
  1111                                  %if _BRIEFLZ
  1112                                  %define which iniblz
  1113                                  %elif _LZ4
  1114                                  %define which inilz4
  1115                                  %elif _SNAPPY
  1116                                  %define which inisz
  1117                                  %elif _EXODECR
  1118                                  %define which iniexo
  1119                                  %elif _X
  1120                                  %define which inix
  1121                                  %elif _HEATSHRINK
  1122                                  %define which inihs
  1123                                  %elif _LZD
  1124                                  %define which inilz
  1125                                  %elif _LZO
  1126                                  %define which inilzo
  1127                                  %endif
  1128                                  %warning which: num bytes used for depacker
  1128          ******************       warning: inilz4: 1504 bytes used for depacker [-w+user]
  1129                                  
  1130                                  
  1131                                  %if _TEST_PROGRAM
  1132                                  	section INIT2 align=16 follows=INIT1 vstart=0
  1133                                  init2_start:
  1134                                  		; si => after PSP
  1135                                  		; cs => INIT2
  1136                                  		; psp, free, payload, init1, init2, payload space, stack
  1137                                  		;
  1138                                  		; The correct allocation for the test program
  1139                                  		;  is image size (init0, payload, init1, init2)
  1140                                  		;  minus init0 plus compressed payload size
  1141                                  		;  plus decompressed size plus stack. For
  1142                                  		;  simplicity, init0 subtraction may be skipped.
  1143 00000000 8CCA                    	mov dx, cs
  1144 00000002 81C21F15                	add dx, (init2_end - init2_start) >> 4
  1145                                  				; => payload saving area
  1146 00000006 8CC8                    	mov ax, cs
  1147 00000008 2D940F                  	sub ax, ( (init1_end - init1_start) 		+ (payload_end - payload) 		) >> 4		; => payload source for first run
  1150 0000000B B9560F                  	mov cx, (payload_end - payload) >> 4
  1151 0000000E E84602                  	call init2_movp		; copy payload to payload saving area
  1152                                  		; We save away the payload here because a failure
  1153                                  		;  to decompress generally overwrites part of that
  1154                                  		;  payload which was used as source.
  1155                                  
  1156 00000011 89C2                    	mov dx, ax		; dx => payload source to use
  1157 00000013 8CC8                    	mov ax, cs
  1158 00000015 83E83E                  	sub ax, (init1_end - init1_start) >> 4
  1159                                  				; ax => INIT1
  1160 00000018 BB0100                  	mov bx, 1		; say we're in EXE mode
  1161 0000001B 52                      	push dx
  1162 0000001C 50                      	push ax
  1163 0000001D 56                      	push si			; si => target
  1164 0000001E 0E                      	push cs
  1165 0000001F E8C700                  	call .transfer		; call decompression
  1166 00000022 5E                      	pop si
  1167 00000023 58                      	pop ax
  1168 00000024 5A                      	pop dx
  1169                                  		; Returns here after decompression.
  1170                                  		; CY if error.
  1171 00000025 7309                    	jnc @F
  1172                                  
  1173 00000027 BA[A201]                	mov dx, init2_msg.initial_error
  1174 0000002A B93C00                  	mov cx, init2_msg.initial_error.length
  1175 0000002D E9F800                  	jmp init2_error
  1176                                  
  1177                                  @@:
  1178                                  	numdef INCLUDE_UNCOMPRESSED
  1179                                  	numdef WRITE_WRONG_FILE
  1180                                  %if _INCLUDE_UNCOMPRESSED
  1181                                  payload_uncompressed_size equ payload_uncompressed.end - payload_uncompressed
  1182                                  
  1183 00000030 E8BC00                  	call checkdecompressed
  1184 00000033 7409                    	je @F
  1185                                  
  1186                                  %if _WRITE_WRONG_FILE
  1187                                  	call writefiles
  1188                                  %endif
  1189                                  
  1190                                  %if _DEBUG0
  1191                                  	mov bx, -1
  1192                                  %endif
  1193 00000035 BA[DE01]                	mov dx, init2_msg.initial_error_2
  1194 00000038 B93C00                  	mov cx, init2_msg.initial_error_2.length
  1195 0000003B E9EA00                  	jmp init2_error
  1196                                  
  1197                                  @@:
  1198                                  %endif
  1199                                  
  1200                                  	lframe
  1201 0000003E 5589E5                  	lenter
  1202                                  	lvar word,	upperbound
  1203 00000041 52                      	 push dx
  1204                                  	lvar word,	lowerbound
  1205 00000042 56                      	 push si
  1206                                  	lvar word,	current_init1
  1207 00000043 50                      	 push ax
  1208                                  
  1209                                  %if _TEST_PROGRESS
  1210 00000044 BA[9701]                	mov dx, init2_msg.progress.1
  1211 00000047 B90700                  	mov cx, init2_msg.progress.1.length
  1212                                  .loop:
  1213 0000004A 0E                      	push cs
  1214 0000004B 1F                      	pop ds
  1215 0000004C BB0200                  	mov bx, 2
  1216 0000004F B440                    	mov ah, 40h
  1217 00000051 CD21                    	int 21h
  1218                                  %else
  1219                                  .loop:
  1220                                  %endif
  1221                                  
  1222 00000053 8B56FE                  	mov dx, [bp + ?upperbound]
  1223 00000056 2B56FC                  	sub dx, [bp + ?lowerbound]
  1224 00000059 7465                    	jz .found
  1225 0000005B D1EA                    	shr dx, 1
  1226                                  		; Rounding down, so that we never retry upper bound.
  1227                                  		;  The upper bound is known to be working.
  1228 0000005D 0356FC                  	add dx, [bp + ?lowerbound]
  1229 00000060 52                      	push dx
  1230 00000061 81C2560F                	add dx, (payload_end - payload) >> 4
  1231 00000065 8B46FA                  	mov ax, [bp + ?current_init1]
  1232 00000068 B93E00                  	mov cx, (init1_end - init1_start) >> 4
  1233 0000006B E8E901                  	call init2_movp
  1234 0000006E 8956FA                  	mov [bp + ?current_init1], dx
  1235 00000071 5A                      	pop dx
  1236                                  
  1237 00000072 8CC8                    	mov ax, cs
  1238 00000074 051F15                  	add ax, (init2_end - init2_start) >> 4
  1239                                  				; => payload in saving area
  1240 00000077 B9560F                  	mov cx, (payload_end - payload) >> 4
  1241 0000007A E8DA01                  	call init2_movp		; copy payload from payload saving area
  1242                                  
  1243                                  		; dx => source
  1244 0000007D 8B46FA                  	mov ax, [bp + ?current_init1]
  1245 00000080 BB0100                  	mov bx, 1
  1246 00000083 52                      	push dx
  1247 00000084 56                      	push si
  1248 00000085 0E                      	push cs
  1249 00000086 E86000                  	call .transfer
  1250 00000089 5E                      	pop si
  1251 0000008A 5A                      	pop dx
  1252                                  		; Returns here after decompression.
  1253                                  		; CY if error.
  1254 0000008B 730C                    	jnc @F
  1255                                  		; error: this attempt is one below the new lower bound
  1256 0000008D 42                      	inc dx
  1257 0000008E 8956FC                  	mov word [bp + ?lowerbound], dx
  1258                                  %if _TEST_PROGRESS
  1259 00000091 BA[9E01]                	mov dx, init2_msg.progress.fail
  1260 00000094 B90100                  	mov cx, init2_msg.progress.fail.length
  1261                                  %endif
  1262 00000097 EBB1                    	jmp .loop
  1263                                  
  1264                                  @@:
  1265                                  %if _INCLUDE_UNCOMPRESSED
  1266 00000099 E85300                  	call checkdecompressed
  1267 0000009C 7417                    	je @F
  1268                                  
  1269                                  %if _WRITE_WRONG_FILE
  1270                                  	call writefiles
  1271                                  %endif
  1272                                  
  1273                                  %if _TEST_PROGRESS
  1274 0000009E 0E                      	push cs
  1275 0000009F 1F                      	pop ds
  1276 000000A0 BA[A001]                	mov dx, init2_msg.progress.linebreak
  1277 000000A3 B90200                  	mov cx, init2_msg.progress.linebreak.length
  1278 000000A6 BB0200                  	mov bx, 2
  1279 000000A9 B440                    	mov ah, 40h
  1280 000000AB CD21                    	int 21h
  1281                                  %endif
  1282                                  %if _DEBUG0
  1283                                  	mov bx, -2
  1284                                  %endif
  1285 000000AD BA[1A02]                	mov dx, init2_msg.subsequent_error_2
  1286 000000B0 B93700                  	mov cx, init2_msg.subsequent_error_2.length
  1287 000000B3 EB73                    	jmp init2_error
  1288                                  
  1289                                  @@:
  1290                                  %endif
  1291                                  		; success: this attempt is the new upper bound
  1292 000000B5 8956FE                  	mov word [bp + ?upperbound], dx
  1293                                  %if _TEST_PROGRESS
  1294 000000B8 BA[9F01]                	mov dx, init2_msg.progress.success
  1295 000000BB B90100                  	mov cx, init2_msg.progress.success.length
  1296                                  %endif
  1297 000000BE EB8A                    	jmp .loop
  1298                                  
  1299                                  .found:
  1300                                  %if _TEST_PROGRESS
  1301 000000C0 0E                      	push cs
  1302 000000C1 1F                      	pop ds
  1303 000000C2 BA[A001]                	mov dx, init2_msg.progress.linebreak
  1304 000000C5 B90200                  	mov cx, init2_msg.progress.linebreak.length
  1305 000000C8 BB0200                  	mov bx, 2
  1306 000000CB B440                    	mov ah, 40h
  1307 000000CD CD21                    	int 21h
  1308                                  %endif
  1309 000000CF 8B46FE                  	mov ax, word [bp + ?upperbound]
  1310 000000D2 29F0                    	sub ax, si		; = how many paragraphs in buffer before source
  1311 000000D4 05940F                  	add ax, paras( (init1_end - init1_start) 			+ (payload_end - payload) )
  1313                                  				; = how many paragraphs needed for process
  1314 000000D7 E87400                  	call init2_disp_ax_dec
  1315 000000DA B00D                    	mov al, 13
  1316 000000DC E86400                  	call init2_disp_al
  1317 000000DF B00A                    	mov al, 10
  1318 000000E1 E85F00                  	call init2_disp_al
  1319 000000E4 B8004C                  	mov ax, 4C00h
  1320 000000E7 CD21                    	int 21h
  1321                                  
  1322                                  	lleave ctx
  1323                                  
  1324                                  
  1325                                  .transfer:
  1326 000000E9 31FF                    	xor di, di
  1327 000000EB 57                      	push di			; dummy ax value on stack
  1328 000000EC 50                      	push ax			; INIT1 segment
  1329 000000ED 57                      	push di			; zero = init1_start
  1330 000000EE CB                      	retf
  1331                                  
  1332                                  
  1333                                  
  1334                                  %if _INCLUDE_UNCOMPRESSED
  1335                                  
  1336                                  
  1337                                  %if _WRITE_WRONG_FILE
  1338                                  writefiles:
  1339                                  	push cs
  1340                                  	pop ds
  1341                                  	mov dx, init2_msg.wrong_file_name
  1342                                  	xor cx, cx
  1343                                  	mov ah, 3Ch
  1344                                  	int 21h
  1345                                  	jc .notfile
  1346                                  
  1347                                  	mov bx, ax
  1348                                  	mov cx, payload_uncompressed_size >> 4
  1349                                  	xor dx, dx
  1350                                  .loopfile:
  1351                                  	mov ds, si
  1352                                  	mov ah, 40h
  1353                                  	push cx
  1354                                  	mov cx, 16
  1355                                  	int 21h
  1356                                  	pop cx
  1357                                  	inc si
  1358                                  	loop .loopfile
  1359                                  
  1360                                  	mov ds, si
  1361                                  	mov cx, payload_uncompressed_size & 15
  1362                                  	mov ah, 40h
  1363                                  	int 21h
  1364                                  
  1365                                  	mov ah, 3Eh
  1366                                  	int 21h
  1367                                  
  1368                                  .notfile:
  1369                                  
  1370                                  	push cs
  1371                                  	pop ds
  1372                                  	mov dx, init2_msg.wrong_file_name2
  1373                                  	xor cx, cx
  1374                                  	mov ah, 3Ch
  1375                                  	int 21h
  1376                                  	jc .notfile2
  1377                                  
  1378                                  	mov bx, ax
  1379                                  	mov cx, payload_uncompressed_size >> 4
  1380                                  	mov si, cs
  1381                                  	add si, (payload_uncompressed - init2_start) >> 4
  1382                                  	xor dx, dx
  1383                                  .loopfile2:
  1384                                  	mov ds, si
  1385                                  	mov ah, 40h
  1386                                  	push cx
  1387                                  	mov cx, 16
  1388                                  	int 21h
  1389                                  	pop cx
  1390                                  	inc si
  1391                                  	loop .loopfile2
  1392                                  
  1393                                  	mov ds, si
  1394                                  	mov cx, payload_uncompressed_size & 15
  1395                                  	mov ah, 40h
  1396                                  	int 21h
  1397                                  
  1398                                  	mov ah, 3Eh
  1399                                  	int 21h
  1400                                  
  1401                                  .notfile2:
  1402                                  	retn
  1403                                  %endif
  1404                                  
  1405                                  		; INP:	si => decompressed image
  1406                                  		; OUT:	ZR if matching
  1407                                  		;	NZ if mismatching
  1408                                  		; CHG:	es, ds, di, bx, cx
  1409                                  		; STT:	UP
  1410                                  checkdecompressed:
  1411 000000EF 50                      	push ax
  1412 000000F0 52                      	push dx
  1413 000000F1 56                      	push si
  1414                                  %if _PAYLOAD_KERNEL_MAX_PARAS
  1415                                  	mov cx, _PAYLOAD_KERNEL_MAX_PARAS
  1416                                  	mov bx, 0
  1417                                  %else
  1418 000000F2 B9EF14                  	mov cx, payload_uncompressed_size >> 4
  1419 000000F5 BB0000                  	mov bx, payload_uncompressed_size & 15
  1420                                  %endif
  1421 000000F8 8CCF                    	mov di, cs
  1422 000000FA 83C72F                  	add di, (payload_uncompressed - init2_start) >> 4
  1423 000000FD E319                    	jcxz .end
  1424                                  .loop:
  1425 000000FF 51                      	push cx
  1426 00000100 B90800                  	mov cx, 8
  1427 00000103 8EDE                    	mov ds, si
  1428 00000105 8EC7                    	mov es, di
  1429 00000107 46                      	inc si
  1430 00000108 47                      	inc di
  1431 00000109 56                      	push si
  1432 0000010A 57                      	push di
  1433 0000010B 31F6                    	xor si, si
  1434 0000010D 31FF                    	xor di, di
  1435 0000010F F3A7                    	repe cmpsw
  1436 00000111 5F                      	pop di
  1437 00000112 5E                      	pop si
  1438 00000113 59                      	pop cx
  1439 00000114 750E                    	jne .ret
  1440 00000116 E2E7                    	loop .loop
  1441                                  .end:
  1442 00000118 8EDE                    	mov ds, si
  1443 0000011A 8EC7                    	mov es, di
  1444 0000011C 31F6                    	xor si, si
  1445 0000011E 31FF                    	xor di, di		; (ZR)
  1446 00000120 89D9                    	mov cx, bx
  1447 00000122 F3A6                    	repe cmpsb
  1448                                  .ret:
  1449 00000124 5E                      	pop si
  1450 00000125 5A                      	pop dx
  1451 00000126 58                      	pop ax
  1452 00000127 C3                      	retn
  1453                                  %endif
  1454                                  
  1455                                  
  1456                                  init2_error:
  1457                                  %if _DEBUG0
  1458                                  	push bx
  1459                                  %endif
  1460 00000128 0E                      	push cs
  1461 00000129 1F                      	pop ds
  1462 0000012A BB0200                  	mov bx, 2
  1463 0000012D B440                    	mov ah, 40h
  1464 0000012F CD21                    	int 21h
  1465                                  
  1466                                  %if _DEBUG0
  1467                                  	mov dx, init2_msg.rc
  1468                                  	mov cx, init2_msg.rc.length
  1469                                  	mov bx, 2
  1470                                  	mov ah, 40h
  1471                                  	int 21h
  1472                                  	pop ax
  1473                                  	call init2_error_disp_ax_hex
  1474                                  	mov dx, init2_msg.linebreak
  1475                                  	mov cx, init2_msg.linebreak.length
  1476                                  	mov bx, 2
  1477                                  	mov ah, 40h
  1478                                  	int 21h
  1479                                  %endif
  1480                                  
  1481 00000131 BA[5102]                	mov dx, init2_msg.error_stdout
  1482 00000134 B90600                  	mov cx, init2_msg.error_stdout.length
  1483 00000137 BB0100                  	mov bx, 1
  1484 0000013A B440                    	mov ah, 40h
  1485 0000013C CD21                    	int 21h
  1486                                  
  1487 0000013E B8FF4C                  	mov ax, 4CFFh
  1488 00000141 CD21                    	int 21h
  1489                                  
  1490                                  
  1491                                  %if _DEBUG0
  1492                                  init2_error_disp_ax_hex:	; ax
  1493                                  		xchg al,ah
  1494                                  		call init2_error_disp_al_hex	; display former ah
  1495                                  		xchg al,ah			;  and fall trough for al
  1496                                  init2_error_disp_al_hex:	; al
  1497                                  		push cx
  1498                                  		mov cl,4
  1499                                  		ror al,cl
  1500                                  		call init2_error_disp_al_lownibble_hex
  1501                                  						; display former high-nibble
  1502                                  		rol al,cl
  1503                                  		pop cx
  1504                                  						;  and fall trough for low-nibble
  1505                                  init2_error_disp_al_lownibble_hex:
  1506                                  		push ax			 ; save ax for call return
  1507                                  		and al,00001111b		; high nibble must be zero
  1508                                  		add al,'0'			; if number is 0-9, now it's the correct character
  1509                                  		cmp al,'9'
  1510                                  		jna .decimalnum		 ; if we get decimal number with this, ok -->
  1511                                  		add al,7			;  otherwise, add 7 and we are inside our alphabet
  1512                                   .decimalnum:
  1513                                  		call init2_error_disp_al
  1514                                  		pop ax
  1515                                  		retn
  1516                                  
  1517                                  
  1518                                  init2_error_disp_al:
  1519                                  	push dx
  1520                                  	push cx
  1521                                  	push bx
  1522                                  	push ax
  1523                                  	mov dx, sp
  1524                                  	push ds
  1525                                  	 push ss
  1526                                  	 pop ds
  1527                                  	mov cx, 1
  1528                                  	mov bx, 2
  1529                                  	mov ah, 40h
  1530                                  	int 21h
  1531                                  	pop ds
  1532                                  	pop ax
  1533                                  	pop bx
  1534                                  	pop cx
  1535                                  	pop dx
  1536                                  	retn
  1537                                  %endif
  1538                                  
  1539                                  
  1540                                  init2_disp_al:
  1541 00000143 52                      	push dx
  1542 00000144 50                      	push ax
  1543 00000145 88C2                    	mov dl, al
  1544 00000147 B402                    	mov ah, 2
  1545 00000149 CD21                    	int 21h
  1546 0000014B 58                      	pop ax
  1547 0000014C 5A                      	pop dx
  1548 0000014D C3                      	retn
  1549                                  
  1550                                  
  1551                                  		; Display number in ax decimal
  1552                                  		;
  1553                                  		; INP:	ax = number
  1554                                  		; OUT:	displayed using Int21.02
  1555                                  		; CHG:	none
  1556                                  init2_disp_ax_dec:			; ax (no leading zeros)
  1557 0000014E 53                      		push bx
  1558 0000014F 31DB                    		xor bx, bx
  1559                                  .pushax:
  1560 00000151 52                      		push dx
  1561 00000152 50                      		push ax
  1562 00000153 08DB                    		or bl, bl
  1563 00000155 7405                    		jz .nobl
  1564 00000157 80EB05                  		sub bl, 5
  1565 0000015A F6DB                    		neg bl
  1566                                  .nobl:
  1567 0000015C 51                      		push cx
  1568 0000015D B91027                  		mov cx, 10000
  1569 00000160 E81B00                  		call .divide_out
  1570 00000163 B9E803                  		mov cx, 1000
  1571 00000166 E81500                  		call .divide_out
  1572 00000169 B96400                  		mov cx, 100
  1573 0000016C E80F00                  		call .divide_out
  1574 0000016F B10A                    		mov cl, 10
  1575 00000171 E80A00                  		call .divide_out
  1576                                  							; (Divisor 1 is useless)
  1577 00000174 0430                    		add al, '0'
  1578 00000176 E8CAFF                  		call init2_disp_al
  1579 00000179 59                      		pop cx
  1580 0000017A 58                      		pop ax
  1581 0000017B 5A                      		pop dx
  1582 0000017C 5B                      		pop bx					; Caller's register
  1583 0000017D C3                      		retn
  1584                                  
  1585                                  
  1586                                  		; INP:	ax = number
  1587                                  		;	cx = divisor
  1588                                  		; OUT:	ax = remainder of operation
  1589                                  		;	result displayed
  1590                                  .divide_out:
  1591 0000017E 52                      		push dx
  1592 0000017F 31D2                    		xor dx, dx
  1593 00000181 F7F1                    		div cx				; 0:ax / cx
  1594 00000183 52                      		push dx				; remainder
  1595 00000184 FECB                    		dec bl
  1596 00000186 7503                    		jnz .nobl2
  1597 00000188 80CF01                  		or bh, 1
  1598                                  .nobl2:
  1599 0000018B 08C7                    		or bh, al
  1600 0000018D 7405                    		jz .leadingzero
  1601 0000018F 0430                    		add al, '0'
  1602 00000191 E8AFFF                  		call init2_disp_al		; display result
  1603                                   .leadingzero:
  1604 00000194 58                      		pop ax				; remainder
  1605 00000195 5A                      		pop dx
  1606 00000196 C3                      		retn
  1607                                  
  1608                                  
  1609                                  init2_msg:
  1610                                  %if _TEST_PROGRESS
  1611 00000197 496E666F3A2031          .progress.1:		db "Info: 1"
  1612                                  .progress.1.length: equ $ - .progress.1
  1613 0000019E 46                      .progress.fail:		db "F"
  1614                                  .progress.fail.length: equ $ - .progress.fail
  1615 0000019F 53                      .progress.success:	db "S"
  1616                                  .progress.success.length: equ $ - .progress.success
  1617 000001A0 0D0A                    .progress.linebreak:	db 13,10
  1618                                  .progress.linebreak.length: equ $ - .progress.linebreak
  1619                                  %endif
  1620                                  %if _WRITE_WRONG_FILE
  1621                                  .wrong_file_name:	asciz "WRONG.BIN"
  1622                                  .wrong_file_name2:	asciz "WRONG2.BIN"
  1623                                  %endif
  1624 000001A2 4572726F723A205465-     .initial_error:	db "Error: Test program failed to decompress with full buffer."
  1624 000001AB 73742070726F677261-
  1624 000001B4 6D206661696C656420-
  1624 000001BD 746F206465636F6D70-
  1624 000001C6 726573732077697468-
  1624 000001CF 2066756C6C20627566-
  1624 000001D8 6665722E           
  1625 000001DC 0D0A                    .linebreak:	db 13,10
  1626                                  .initial_error.length: equ $ - .initial_error
  1627                                  .linebreak.length: equ $ - .linebreak
  1628                                  %if _DEBUG0
  1629                                  .rc:	db "Error: Failure code="
  1630                                  .rc.length: equ $ - .rc
  1631                                  %endif
  1632                                  %if _INCLUDE_UNCOMPRESSED
  1633 000001DE 4572726F723A205465-     .initial_error_2:	db "Error: Test program decompressed wrongly with full buffer.",13,10
  1633 000001E7 73742070726F677261-
  1633 000001F0 6D206465636F6D7072-
  1633 000001F9 65737365642077726F-
  1633 00000202 6E676C792077697468-
  1633 0000020B 2066756C6C20627566-
  1633 00000214 6665722E0D0A       
  1634                                  .initial_error_2.length: equ $ - .initial_error_2
  1635 0000021A 4572726F723A205465-     .subsequent_error_2:	db "Error: Test program decompressed wrongly during test.",13,10
  1635 00000223 73742070726F677261-
  1635 0000022C 6D206465636F6D7072-
  1635 00000235 65737365642077726F-
  1635 0000023E 6E676C792064757269-
  1635 00000247 6E6720746573742E0D-
  1635 00000250 0A                 
  1636                                  .subsequent_error_2.length: equ $ - .subsequent_error_2
  1637                                  %endif
  1638 00000251 39333437                .error_stdout:	_autodigits paras(_TEST_PROGRAM_DECOMPRESSED_SIZE 				+ (payload_end - payload) 				+ (init1_end - init1_start) 				+ ADDITIONAL_MEMORY 				)
  1643 00000255 0D0A                    		db 13,10
  1644                                  .error_stdout.length: equ $ - .error_stdout
  1645                                  
  1646                                  
  1647                                  		; Move paragraphs
  1648                                  		;
  1649                                  		; INP:	ax => source
  1650                                  		;	dx => destination
  1651                                  		;	cx = number of paragraphs
  1652                                  		; CHG:	-
  1653                                  		; OUT:	ax and dx unchanged
  1654                                  		; Note:	Doesn't work correctly on HMA; doesn't always wrap to LMA either.
  1655                                  		;	Do not provide a wrapped/HMA source or destination!
  1656                                  init2_movp:
  1657 00000257 51                      	push cx
  1658 00000258 1E                      	push ds
  1659 00000259 56                      	push si
  1660 0000025A 06                      	push es
  1661 0000025B 57                      	push di
  1662                                  
  1663 0000025C 39D0                    	cmp ax, dx		; source above destination ?
  1664 0000025E 770A                    	ja .up			; yes, move up (forwards) -->
  1665 00000260 747B                    	je .return		; same, no need to move -->
  1666 00000262 50                      	push ax
  1667 00000263 01C8                    	add ax, cx		; (expected not to carry)
  1668 00000265 39D0                    	cmp ax, dx		; end of source is above destination ?
  1669 00000267 58                      	pop ax
  1670 00000268 7730                    	ja .down		; yes, move from top down -->
  1671                                  	; Here, the end of source is below-or-equal the destination,
  1672                                  	;  so they do not overlap. In this case we prefer moving up.
  1673                                  
  1674                                  .up:
  1675 0000026A 50                      	push ax
  1676 0000026B 52                      	push dx
  1677                                  .uploop:
  1678 0000026C 8ED8                    	mov ds, ax
  1679 0000026E 8EC2                    	mov es, dx
  1680 00000270 31FF                    	xor di, di
  1681 00000272 31F6                    	xor si, si		; -> start of segment
  1682 00000274 81E90010                	sub cx, 1000h		; 64 KiB left ?
  1683 00000278 7610                    	jbe .uplast		; no -->
  1684 0000027A 51                      	push cx
  1685 0000027B B90080                  	mov cx, 10000h /2
  1686 0000027E F3A5                    	rep movsw		; move 64 KiB
  1687 00000280 59                      	pop cx
  1688 00000281 050010                  	add ax, 1000h
  1689 00000284 81C20010                	add dx, 1000h		; -> next segment
  1690 00000288 EBE2                    	jmp short .uploop	; proceed for more -->
  1691                                  .uplast:
  1692 0000028A 81C10010                	add cx, 1000h		; restore counter
  1693 0000028E D1E1                    	shl cx, 1
  1694 00000290 D1E1                    	shl cx, 1
  1695 00000292 D1E1                    	shl cx, 1		; *8, paragraphs to words
  1696 00000294 F3A5                    	rep movsw		; move last part
  1697 00000296 5A                      	pop dx
  1698 00000297 58                      	pop ax
  1699 00000298 EB43                    	jmp short .return
  1700                                  
  1701                                  .down:
  1702 0000029A FD                      	std			; _AMD_ERRATUM_109_WORKAROUND as below
  1703                                  .dnloop:
  1704 0000029B 81E90010                	sub cx, 1000h		; 64 KiB left ?
  1705 0000029F 761A                    	jbe .dnlast		; no -->
  1706 000002A1 50                      	push ax
  1707 000002A2 52                      	push dx
  1708 000002A3 01C8                    	add ax, cx
  1709 000002A5 01CA                    	add dx, cx
  1710 000002A7 8ED8                    	mov ds, ax		; -> 64 KiB not yet moved
  1711 000002A9 8EC2                    	mov es, dx
  1712 000002AB 5A                      	pop dx
  1713 000002AC 58                      	pop ax
  1714 000002AD BFFEFF                  	mov di, -2
  1715 000002B0 89FE                    	mov si, di		; moved from last word down
  1716 000002B2 51                      	push cx
  1717 000002B3 B90080                  	mov cx, 10000h /2
  1718 000002B6 F3A5                    	rep movsw		; move 64 KiB
  1719 000002B8 59                      	pop cx
  1720 000002B9 EBE0                    	jmp short .dnloop	; proceed for more -->
  1721                                  .dnlast:
  1722 000002BB 81C10010                	add cx, 1000h		; restore counter
  1723 000002BF D1E1                    	shl cx, 1
  1724 000002C1 D1E1                    	shl cx, 1
  1725 000002C3 D1E1                    	shl cx, 1		; *8, paragraphs to words
  1726 000002C5 89CF                    	mov di, cx
  1727 000002C7 4F                      	dec di
  1728 000002C8 D1E7                    	shl di, 1		; words to offset, -> last word
  1729 000002CA 89FE                    	mov si, di
  1730 000002CC 8ED8                    	mov ds, ax
  1731 000002CE 8EC2                    	mov es, dx		; first segment correct
  1732                                  
  1733                                  		; Refer to comment in init0_movp.
  1734                                  %if _AMD_ERRATUM_109_WORKAROUND
  1735 000002D0 E308                    	jcxz @FF
  1736 000002D2 83F914                  	cmp cx, 20
  1737 000002D5 7703                    	ja @FF
  1738                                  @@:
  1739 000002D7 A5                      	movsw
  1740 000002D8 E2FD                    	loop @B
  1741                                  @@:
  1742                                  %endif
  1743 000002DA F3A5                    	rep movsw		; move first part
  1744 000002DC FC                      	cld
  1745                                  .return:
  1746 000002DD 5F                      	pop di
  1747 000002DE 07                      	pop es
  1748 000002DF 5E                      	pop si
  1749 000002E0 1F                      	pop ds
  1750 000002E1 59                      	pop cx
  1751 000002E2 C3                      	retn
  1752                                  
  1753                                  
  1754 000002E3 90<rep Dh>              	align 16
  1755                                  
  1756                                  	strdef UNCOMPRESSED_FILE, "lDOSLOAD.BIN"
  1757                                  %if _INCLUDE_UNCOMPRESSED
  1758                                  payload_uncompressed:
  1759 000002F0 <bin 14EF0h>            	incbin _UNCOMPRESSED_FILE
  1760                                  .end:
  1761 000151E0 26                      	db 38
  1762 000151E1 26<rep Fh>              	align 16, db 38
  1763                                  %endif
  1764                                  init2_end:
  1765                                  %endif
  1766                                  
