
; Public Domain. Based on:
;
;/* AMITSRS.C	List TSRs using the alternate multiplex interrupt	*/
;/* Public Domain 1992 Ralf Brown					*/
;/* Version 0.90 							*/
;/* Last Edit: 9/12/92							*/

; test install command: install; amitsrs; amitsrs uninstall
; test run command: ; .; .

%include "lmacros3.mac"
%include "eld.mac"
%include "eldcall.mac"
%include "elddata.mac"


;/* hotkey type bits returned by Get Hotkeys (function 05h) */
%define HK_INT09ENTRY	1    ;/* TSR checks keys before calling INT 09h */
%define HK_INT09EXIT	2    ;/* TSR checks keys after calling INT 09h */
%define HK_INT15ENTRY	4    ;/* TSR checks keys before chaining INT 15h/AH=4Fh */
%define HK_INT15EXIT	8    ;/* TSR checks keys after chaining INT 15h/AH=4Fh */
%define HK_INT16OLD	0x10 ;/* TSR checks on INT 16/AH=00h-02h */
%define HK_INT16NEW	0x20 ;/* TSR checks on INT 16/AH=10h-12h */

;/* hotkey shift bits returned by Get Hotkeys (function 05h) */
%define HK_NONE 	0x0000	;/* no shift keys */
%define HK_RSHIFT	0x0001
%define HK_LSHIFT	0x0002
%define HK_BOTHSHIFT	0x0003	;/* both Shift keys must be pressed */
%define HK_ANYCTRL	0x0004	;/* either Control key must be pressed */
%define HK_ANYALT	0x0008	;/* either Alt key must be pressed */
%define HK_SCRLLOCK_ON	0x0010	;/* ScrollLock must be on when hotkey pressed */
%define HK_NUMLOCK_ON	0x0020	;/* NumLock must be on when hotkey pressed */
%define HK_CAPSLOCK_ON	0x0040	;/* CapsLock must be on when hotkey pressed */
%define HK_ANYSHIFT	0x0080	;/* either Shift key must be pressed */
%define HK_LCTRL	0x0100
%define HK_LALT 	0x0200
%define HK_RCTRL	0x0400
%define HK_RALT 	0x0800
%define HK_BOTHCTRL	0x0500	;/* both Control keys must be pressed */
%define HK_BOTHALT	0x0A00	;/* both Alt keys must be pressed */
%define HK_SCROLLOCK	0x1000	;/* ScrollLock must be pressed with hotkey */
%define HK_NUMLOCK	0x2000	;/* NumLock must be pressed with hotkey */
%define HK_CAPSLOCK	0x4000	;/* CapsLock must be pressed with hotkey */
%define HK_SYSREQ	0x8000	;/* SysRq must be pressed with hotkey */

;/* hotkey flag bist returned by Get Hotkeys (function 05h) */
%define HK_CHAINBEFORE	1	;/* TSR chains hotkey before processing it */
%define HK_CHAINAFTER	2	;/* TSR chains hotkey after processing it */
%define HK_MONITOR	4	;/* TSR monitors hotkey, it should be passed thru */
%define HK_NOPRESSRELEASE 8	;/* hotkey won't activate if other keys pressed */
			        ;/* and released before hotkey combo completed */
%define HK_REMAPPED	0x10	;/* this key is remapped into some other key */

%define HK_NOCHAIN	0	;/* TSR swallows hotkey */

;/* hotkey scan codes returned by Get Hotkeys (function 05h) */
%define SCAN_NONE	0
%define SCAN_ESC	1
%define SCAN_1		2
%define SCAN_2		3
%define SCAN_3		4
%define SCAN_4		5
%define SCAN_5		6
%define SCAN_6		7
%define SCAN_7		8
%define SCAN_8		9
%define SCAN_9		10
%define SCAN_0		11
%define SCAN_HYPHEN	12
%define SCAN_EQUAL	13
%define SCAN_BACKSP	14
%define SCAN_TAB	15
%define SCAN_Q		16
%define SCAN_W		17
%define SCAN_E		18
%define SCAN_R		19
%define	SCAN_T		20
%define SCAN_Y		21
%define SCAN_U		22
%define SCAN_I		23
%define SCAN_O		24
%define SCAN_P		25
%define SCAN_LBRACKET	26
%define SCAN_RBRACKET	27
%define SCAN_ENTER	28
%define	SCAN_CTRL	29
%define SCAN_A		30
%define SCAN_S		31
%define SCAN_D		32
%define SCAN_F		33
%define SCAN_G		34
%define SCAN_H		35
%define SCAN_J		36
%define SCAN_K		37
%define SCAN_L		38
%define SCAN_SEMICOLON	39
%define SCAN_SQUOTE	40
%define SCAN_BACKQUOTE	41
%define SCAN_LSHIFT	42
%define SCAN_BACKSLASH	43
%define SCAN_Z		44
%define SCAN_X		45
%define SCAN_C		46
%define SCAN_V		47
%define SCAN_B		48
%define SCAN_N		49
%define SCAN_M		50
%define SCAN_COMMA	51
%define SCAN_PERIOD	52
%define SCAN_SLASH	53
%define SCAN_RSHIFT	54
%define SCAN_GREYSTAR	55
%define SCAN_ALT	56
%define SCAN_SPACE	57
%define SCAN_CAPSLK	58
%define SCAN_F1		59
%define SCAN_F2		60
%define SCAN_F3		61
%define SCAN_F4		62
%define SCAN_F5		63
%define SCAN_F6		64
%define SCAN_F7		65
%define SCAN_F8		66
%define SCAN_F9		67
%define SCAN_F10	68
%define SCAN_NUMLK	69
%define SCAN_SCRLLK	70
%define SCAN_HOME	71
%define SCAN_UP		72
%define SCAN_PGUP	73
%define SCAN_GREYMINUS	74
%define SCAN_LEFT	75
%define SCAN_KP5	76
%define SCAN_RIGHT	77
%define SCAN_GREYPLUS	78
%define SCAN_END	79
%define SCAN_DOWN	80
%define SCAN_PGDN	81
%define SCAN_INS	82
%define SCAN_DEL	83
%define SCAN_SYSRQ	84
%define SCAN_F11	87
%define SCAN_F12	88
%define HK_ONRELEASE	0x80  ;/* hotkey activates on key release (add to scan code) */


	cpu 8086

	addsection RELOCATEDDATA, nobits vstart=_ELD_RELOC_VSTART
relocateddata:

	addsection HEADER, start=0

	istruc ELD_HEADERX
at eldhxHeader
		; ELD executable header
	istruc ELD_HEADER
at eldhSignature,	db "ELD1"
			db 0,0,0
			db 26
at eldhCodeOffset,	dd CODEOFFSET
at eldhCodeImageLength,	dw code_size
at eldhCodeAllocLength,	dw 0
at eldhDataOffset,	dd DATAOFFSET
at eldhDataImageLength,	dw data_size
at eldhDataAllocLength,	dw total_data_size - data_size
at eldhCodeEntrypoint,	dw linker - code
at eldhReserved
at eldhExtensionSize,	dw header_extension_end - $$
	iend
at eldhxDescriptionOffset,	dd description
PUT_ELDHX_DATETIME_OFFSET
header_extension_end:
	iend

description:		asciz "List TSRs using the alternate multiplex interrupt."


	align 16, db 0

	eldstrict on

CODEOFFSET equ $ - $$
	addsection CODE, follows=HEADER vstart=_ELD_CODE_VSTART
%define CODEFIXUP - code + 0
code:
		; ELD instance header
	istruc ELD_INSTANCE
at eldiStartCode
at eldiEndCode
at eldiStartData
at eldiEndData
at eldiIdentifier,	fill 8, 32, db "AMITSRS"
at eldiListing,		asciz _ELD_LISTING
	iend


command:
	jmp strict short .entry
.chain:
	extcall cmd3_not_ext, required	; must NOT be extcallcall
	times 10 - ($ - command) nop
.entry:
	push si
	cmp al, '-'
	jne @F
	extcallcall skipcomma
@@:
	dec si

reloc	mov dx, msg.amitsrs
internaldatarelocation
	extcallcall isstring?
	je .ours
	pop si
	dec si
	lodsb
	jmp .chain

.ours:
	pop ax
	extcallcall skipcomma
	dec si
reloc2	mov word [relocateddata], relocateddata
linkdatarelocation lastcmd, -4
linkdatarelocation dmycmd
reloc	mov dx, relocateddata
linkdatarelocation msg.uninstall
	extcallcall isstring?
	je uninstall

	call run
	extcallcall cmd3

uninstall:
	lodsb
	extcallcall chkeol

	call get_es_ext

	push es
	pop ds
	xor bx, bx		; = 0 (no prior, modify ext_command_handler)
reloc	mov di, command		; di -> us
internalcoderelocation
reloc	mov si, word [ss:relocateddata]
linkdatarelocation ext_command_handler
				; si -> first
	test si, si		; none installed ?
	jz .error		; error -->

.loop:
	cmp di, si		; found ?
	je .bx			; yes, use bx -->
	mov bx, si		; bx -> prior handler
	lodsw			; skip entrypoint jmp strict short
	lodsb			; get first byte of chainer
	cmp al, 0E9h		; expecting jmp near ?
	jne .error		; no, error -->
	lodsw			; get rel16 displacement
	add si, ax		; -> next handler
	jmp .loop

.bx:
	test bx, bx		; any prior ?
	jnz .bxnz		; yes -->
	scasw			; skip entrypoint jmp strict short
	cmp byte [di], 0E8h	; is it a call to cmd3_not_ext ?
	jne @F			; no -->
				; yes, reset ext_command_handler to zero
.setbx:
reloc	mov word [ss:relocateddata], bx
linkdatarelocation ext_command_handler
	jmp .done

@@:
	cmp byte [di], 0E9h	; validate
	jne .error		; failure -->
	inc di			; -> rel16 displacement
	mov bx, word [di]	; get displacement
	scasw			; -> after jmp near
	add bx, di		; -> next handler
	jmp .setbx		; set ext_command_handler to next

.bxnz:
	mov si, bx		; -> prior handler with us as downlink
	xchg di, si		; si -> ours, di -> prior
	cmpsw			; skip entrypoint jmp strict short
	movsb			; copy 0E8h/0E9h
	lodsw			; ax = near rel16 displacement
	add ax, si		; add in our base (= absolute offset)
	sub ax, di
	dec ax
	dec ax			; subtract new base (= relative displacement)
	stosw			; store new rel16 displacement
	movsw			; jmp strict short
	movsw			; linkcall target
	movsb			; trailer
.done:
reloc	clropt [code + eldiFlags], eldifResident
internalcoderelocation -3	; mark block as free
reloc	mov dx, msg.uninstall_done
internaldatarelocation
@@:
	push ss
	pop ds
	extcallcall putsz
	extcallcall cmd3	; return

.error:
	mov ax, 0E01h
	extcallcall setrc
reloc	mov dx, msg.uninstall_error
internaldatarelocation
	jmp @B


get_es_ext:
reloc	mov es, word [relocateddata]
linkdatarelocation extdssel
	extcallcall ispm
	jz @F
reloc	mov es, word [relocateddata]
linkdatarelocation extseg
@@:
	retn


run:
	push ss
	pop es

	xor ax, ax
reloc	mov word [did_banner], ax
internaldatarelocation		; {1} also writes verbose_mpx
reloc	mov word [verbose_hotkeys], ax
internaldatarelocation		; {2} also writes verbose_int
reloc	mov word [verbose_block], ax
internaldatarelocation		; also writes verbose_char
reloc	mov word [verbose_device], ax
internaldatarelocation		; also writes verbose_dpb
reloc	mov word [mpx_from], 0FF00h
				; (also writes mpx_to)
internaldatarelocation -4
.verbose_loop:
	extcallcall skipcomma
	extcallcall iseol?
	je .verbose_done
	dec si

reloc	mov dx, msg.verbose
internaldatarelocation
	extcallcall isstring?
	jne @F
	mov ax, -1
reloc	mov byte [verbose_mpx], al
internaldatarelocation
reloc	mov word [verbose_device], ax
internaldatarelocation
reloc	mov word [verbose_hotkeys], ax
internaldatarelocation
	jmp .verbose_loop

@@:
reloc	mov dx, msg.only
internaldatarelocation
	extcallcall isstring?
	jne @F
	extcallcall skipcomma
	dec si
	extcallcall skipequals
	extcallcall skipcomm0
	dec si
	extcallcall get_value_range
	jc .error
	test bx, bx
	jnz .error
	test dh, dh
	jnz .error
reloc	mov word [mpx_from], di		; (also writes mpx_to)
internaldatarelocation
reloc	mov byte [mpx_to], dl
internaldatarelocation
	dec si
	jmp .verbose_loop

@@:
reloc	mov bx, keywordtable
internaldatarelocation
@@:
	mov dx, word [bx]
	test dx, dx
	jz .error
	extcallcall isstring?
	je @F
	add bx, 4
	jmp @B

@@:
	mov bx, word [bx + 2]
	mov byte [bx], 0FFh
	jmp .verbose_loop

.error:
	extcallcall error

.verbose_done:
	mov al, 2Dh
	extcallcall intchk	; ZR if offset = -1 or segment = 0
				; CHG: ax, dx, bx
	jnz @F
	mov ax, 0E16h
	extcallcall setrc
reloc	mov dx, msg.no2D
internaldatarelocation
	extcallcall putsz
	retn

@@:

%if 0
int main(int argc,char **argv)
{
   int mpx ;
   int did_banner = 0, verbose = 0 ;
   union REGS regs ;
   char far *sig ;
   char signaturebuffer[8 + 8 + 64];
   
   /* prevent 'unused parameters' warnings */
   (void)argv ;
   /**/
   /* if any commandline arguments, turn on verbose mode */
   /**/
   if (argc > 1)
      verbose = 1 ;
%endif

	mov ah, 0
.loop:
	push ax
reloc	cmp ah, byte [mpx_from]
internaldatarelocation
	jb .next
reloc	cmp ah, byte [mpx_to]
internaldatarelocation
	ja .next
	mov al, 00h
	extcallcall call_int2D		; installation check
	cmp al, 0FFh
	je .found

.next:
next equ $
	pop ax
	inc ah
	jnz .loop

reloc	rol byte [did_banner], 1
internaldatarelocation
	jc .ret

	mov ax, 0E17h
	extcallcall setrc
reloc	mov dx, msg.notsrs
internaldatarelocation
	extcallcall putsz
.ret:
	retn

%if 0
      }
   if (!did_banner)
      printf("No TSRs are using the alternate multiplex interrupt\n") ;
   return 0 ;
}
%endif

.found:
reloc	mov byte [mpx], ah
internaldatarelocation

reloc	rol byte [did_banner], 1
internaldatarelocation
	jc @F

	push dx
reloc	mov dx, msg.banner
internaldatarelocation
	extcallcall putsz
	pop dx
reloc	not byte [did_banner]
internaldatarelocation
@@:

%if 0
   /**/
   /* loop through all 256 multiplex numbers, listing each signature we find */
   /**/
   for (mpx = 0 ; mpx <= 255 ; mpx++)
      {
      regs.h.ah = mpx ;
      regs.h.al = AMIS_INSTCHECK ;  /* installation check */
      int86(0x2D,&regs,&regs) ;
      if (regs.h.al == AMIS_SUCCESSFUL) /* installed? */
	 {
	 if (!did_banner)
	    {
	    printf("Manufact  Product\t\tDescription\n") ;
	    printf("-------- -------- ----------------------------------------------\n") ;
	    did_banner = 1 ;
	    }
%endif

	push cx

reloc	mov si, relocateddata
linkdatarelocation line_out

	extcallcall setes2dx
	mov bx, di		; es:bx -> vendor
	mov cx, 8
	call get_esbx_pad_length_maximum_cx

	mov di, bx		; es:di -> vendor
	call swap_es_ds
	xchg di, si		; ds:si -> vendor, es:di -> buffer
	push cx
	mov al, 32
	rep stosb		; pad with pad length
	pop cx

	neg cx			; -8 if 0, -7 if 1, 0 if 8
	add cx, 8		; = length of string
	rep movsb		; write text data

	mov al, 32
	stosb			; write a blank

	xchg di, si		; si -> buffer
	call swap_es_ds		; es:bx -> signatures
	lea bx, [bx + 8]	; es:bx -> product
	mov cx, 8
	call get_esbx_pad_length_maximum_cx

	mov di, bx		; es:di -> product
	call swap_es_ds
	xchg di, si		; ds:si -> product, es:di -> buffer
	push cx
	mov al, 32
	rep stosb		; pad with pad length
	pop cx

	neg cx			; -8 if 0, -7 if 1, 0 if 8
	add cx, 8		; = length
	rep movsb		; write text data

	mov al, 32
	stosb			; write a blank

	xchg di, si
	call swap_es_ds		; es => signatures, ds:si -> buffer
	lea bx, [bx + 8]	; es:bx -> description
	mov cx, 61
	call get_esbx_pad_length_maximum_cx

	mov di, bx		; es:di -> description
	call swap_es_ds
	xchg di, si		; ds:si -> description, es:di -> buffer
	neg cx			; -61 if 0, -60 if 1, 0 if 61
	add cx, 61		; = length
	rep movsb		; write text

	push ss
	pop ds
	extcallcall trimputs

	pop bx

%if 0
	 sig = MK_FP(regs.x.dx,regs.x.di) ;
	 _fmemcpy(signaturebuffer, sig, 8 + 8 + 63);
	 signaturebuffer[8 + 8 + 63] = 0;
	 printf("%8.8s %8.8s %.61s\n",signaturebuffer,signaturebuffer+8,signaturebuffer+16) ;
	 /**/
	 /* if we were asked for a verbose display, also display TSR version */
	 /* and private API entry point (if present) on a second line	     */
	 /**/
%endif

display_second_line:
reloc	rol byte [verbose_mpx], 1
internaldatarelocation
	jnc .done

reloc	mov al, byte [mpx]
internaldatarelocation

reloc	mov di, relocateddata
linkdatarelocation line_out
reloc	mov si, msg.mpx.1
internaldatarelocation
	extcallcall copy_single_counted_string

	extcallcall hexbyte

reloc	mov si, msg.mpx.2
internaldatarelocation
	extcallcall copy_single_counted_string
					; ch = 0

	xor ax, ax
	mov al, bh
	extcallcall decword

	mov al, '.'
	stosb

	mov al, bl
	xor dx, dx
	mov cl, 2			; cx = 2
	extcallcall dec_dword_minwidth

reloc	mov ah, byte [mpx]
internaldatarelocation
	mov al, 01h
	extcallcall call_int2D		; get private entrypoint

	cmp al, 0FFh
	jne .no_private_entry_point

reloc	mov si, msg.mpx.3.yes
internaldatarelocation
	extcallcall copy_single_counted_string

	xchg ax, dx
	extcallcall hexword

	mov al, ':'
	stosb

	xchg ax, bx
	extcallcall hexword

	jmp .put_second_line

.no_private_entry_point:
reloc	mov si, msg.mpx.3.no
internaldatarelocation
	extcallcall copy_single_counted_string

.put_second_line:
	extcallcall putsline_crlf
.done:

%if 0
	 if (verbose)
	    {
	    printf(" multiplex %02Xh    version %d.%02d",mpx,regs.h.ch,regs.h.cl) ;
	    regs.h.ah = mpx ;
	    regs.h.al = AMIS_ENTRYPOINT ;  /* get private entry point */
	    int86(0x2D,&regs,&regs) ;
	    if (regs.h.al == AMIS_SUCCESSFUL)
	       printf("   entry point %04.4X:%04.4X ",regs.x.dx,regs.x.bx) ;
	    else
	       printf("   no private entry point") ;
	    printf("\n") ;
	    display_hotkeys(mpx) ;
	    display_interrupts(mpx);
	    }
	 }
%endif


display_hotkeys:
reloc	rol byte [verbose_hotkeys], 1
internaldatarelocation
	jnc .done

	houdini
reloc	mov ah, byte [mpx]
internaldatarelocation
	mov al, 05h
	extcallcall call_int2D		; get hotkeys

	cmp al, 0FFh
	je @F

%if 0
void display_hotkeys(int mpx_number)
{
   union REGS regs ;
   char far *hotkeys ;
   int num_hotkeys, hotkey_type ;
   int shifts ;
   
   regs.h.ah = mpx_number ;
   regs.h.al = AMIS_HOTKEYS ;	/* get hotkeys */
   int86(0x2D,&regs,&regs) ;
   if (regs.h.al == AMIS_SUCCESSFUL) /* supported? */
      {
%endif

reloc	mov dx, msg.no_hotkeys
internaldatarelocation
	extcallcall putsz
	jmp .done

%if 0
   else
      printf("%18sno hotkeys\n","") ;
   return ;
}
%endif

@@:
reloc	mov word [saved], dx
internaldatarelocation

reloc	mov di, relocateddata
linkdatarelocation line_out
reloc	mov si, msg.no_hotkeys
internaldatarelocation
	mov cx, 18
	rep movsb

	call get_saved_es
	xchg ax, cx			; ah = 0
	mov dx, word [es:bx]		; dl = hotkey type
	mov al, dh			; ax = number of hotkeys
	push ss
	pop es
	extcallcall decword

reloc	mov si, msg.hotkeys.singular
internaldatarelocation
	cmp al, 1
	je @F
reloc	mov si, msg.hotkeys.plural
internaldatarelocation
@@:
	extcallcall copy_single_counted_string

%if 0
      hotkeys = MK_FP(regs.x.dx,regs.x.bx) ;
      hotkey_type = hotkeys[0] ;
      num_hotkeys = hotkeys[1] ;
      printf("%18s%d hotkey%s on ","",num_hotkeys,(num_hotkeys == 1)?"":"s") ;
%endif


	test dl, HK_INT09ENTRY | HK_INT09EXIT
	jz @F
reloc	mov si, msg.hotkeys.int09
internaldatarelocation
	extcallcall copy_single_counted_string
@@:

	test dl, HK_INT15ENTRY | HK_INT15EXIT
	jz @F
reloc	mov si, msg.hotkeys.int15
internaldatarelocation
	extcallcall copy_single_counted_string
@@:

	push dx
	push bx
	extcallcall trimputs

%if 0
      if ((hotkey_type & HK_INT09ENTRY) || (hotkey_type & HK_INT09EXIT))
	 printf("INT 09h  ") ;
      if ((hotkey_type & HK_INT15ENTRY) || (hotkey_type & HK_INT15EXIT))
	 printf("INT 15h") ;
      printf("\n") ;
%endif

	pop bx
	inc bx
	inc bx

	pop cx
	mov cl, ch
	mov ch, 0
	jcxz .done

.loop:
	push cx

reloc	mov dx, msg.22blanks
internaldatarelocation
	extcallcall putsz

	call get_saved_es
	mov ax, word [es:bx + 1]
	push ss
	pop es

	push bx
reloc	mov bx, shifttable1
internaldatarelocation
	call handleshift
	pop bx

	push ax
	push bx
	call get_saved_es
	mov bl, byte [es:bx]
	push ss
	pop es

	mov bh, 0
	mov ax, bx
	add bx, bx
	cmp al, scancodes.amount
	jae .unknown
reloc	mov dx, word [word scancodes + bx]
internaldatarelocation
	test dx, dx
	jnz .known

.unknown:
reloc	mov di, relocateddata
linkdatarelocation line_out
reloc	mov si, msg.unknownkey
internaldatarelocation
	extcallcall copy_single_counted_string
	extcallcall hexbyte
	mov al, 'h'
	stosb
	extcallcall putsline
	jmp @F

.known:
	extcallcall putsz
@@:

	pop bx
	pop ax

%if 0
	 if (*hotkeys) {
	   if (*hotkeys < (sizeof(scancodes) / sizeof(scancodes[0]))
	     && scancodes[*hotkeys]) {
	     printf("%s",scancodes[*hotkeys]);
	   } else {
	     printf("unknownkey=%02Xh", *hotkeys);
	   }
	 } else {
	   printf("nokey") ;
	 }
%endif

	push bx
reloc	mov bx, shifttable2
internaldatarelocation
	call handleshift
	pop bx

reloc	mov dx, msg.linebreak
internaldatarelocation
	extcallcall putsz

	add bx, 6

	pop cx
	loop .loop
.done:

display_devices:
reloc	cmp word [verbose_block], strict byte 0
internaldatarelocation -3		; also checks verbose_char
	jne @F
reloc	rol byte [verbose_dpb], 1
internaldatarelocation
	jc @F

reloc	rol byte [verbose_device], 1
internaldatarelocation
	jnc .done
@@:

reloc	mov ah, byte [mpx]
internaldatarelocation
	mov al, 06h
	extcallcall call_int2D		; get device driver headers

	cmp al, 0
	je .no_device_driver

reloc	mov di, relocateddata
linkdatarelocation line_out
reloc	mov si, msg.dev.1
internaldatarelocation
	extcallcall copy_single_counted_string

	push ax
	mov ah, 0
reloc	mov word [devicesamount], ax
internaldatarelocation
	extcallcall decword
reloc	mov si, msg.dev.2.singular
internaldatarelocation
	cmp al, 1
	je @F
reloc	mov si, msg.dev.2.plural
internaldatarelocation
@@:
	extcallcall copy_single_counted_string

	pop ax
	xchg al, ah
	extcallcall hexbyte

reloc	mov si, msg.dev.3
internaldatarelocation
@@:
	extcallcall copy_single_counted_string

	push dx
	push bx
	xchg ax, dx
	extcallcall hexword

	mov ax, "h:"
	stosw

	xchg ax, bx
	extcallcall hexword

	mov al, "h"
	stosb

	extcallcall putsline_crlf

	pop bx
	pop dx

.loop:
	cmp bx, -1
	jne @F
reloc	mov dx, msg.invaliddevice
internaldatarelocation
	extcallcall putsz
	jmp .done

@@:
reloc	mov di, relocateddata
linkdatarelocation line_out

	mov ax, 2020h
	stosw

	mov ax, dx
	extcallcall hexword

	mov ax, "h:"
	stosw

	mov ax, bx
	extcallcall hexword

	call setds2dx
	mov ax, [bx + 4]
	push ss
	pop ds

	test ax, 8000h
	jz .blockearly
.charearly:
reloc	mov si, msg.eachdev.1.char
internaldatarelocation
reloc	rol byte [verbose_device], 1
internaldatarelocation
	jc @F
reloc	rol byte [verbose_char], 1
internaldatarelocation
	jnc .next
	jmp @F

.blockearly:
reloc	mov si, msg.eachdev.1.block
internaldatarelocation
reloc	rol byte [verbose_device], 1
internaldatarelocation
	jc @F
reloc	rol byte [verbose_dpb], 1
internaldatarelocation
	jc @F
reloc	rol byte [verbose_block], 1
internaldatarelocation
	jnc .next
@@:
	extcallcall copy_single_counted_string

	extcallcall hexword

reloc	mov si, msg.eachdev.2
internaldatarelocation
	extcallcall copy_single_counted_string

	call setds2dx
	push word [bx + 4]
	mov ax, [bx + 6]
	 push word [bx + 8]
	push ss
	pop ds

	extcallcall hexword

reloc	mov si, msg.eachdev.3
internaldatarelocation
	extcallcall copy_single_counted_string

	 pop ax
	extcallcall hexword

	pop ax
reloc	mov si, msg.eachdev.4.block
internaldatarelocation
	test ax, 8000h
	jz @F
reloc	mov si, msg.eachdev.4.char
internaldatarelocation
@@:
	extcallcall copy_single_counted_string

	call setds2dx
	lea si, [bx + 10]
	test ax, 8000h
	jz .block
.char:
	mov cl, 4
	rep movsw
	push ss
	pop ds
	mov cl, 8
@@:
	dec di
	cmp byte [di], 32
	loope @B
	je @F
	inc di
@@:
	mov al, '"'
	stosb
	push dx
	push bx
	extcallcall putsline_crlf
	jmp .common

.block:
	xor ax, ax
	lodsb
	push ss
	pop ds
reloc	mov word [unitsamount], ax
internaldatarelocation
	call decword

reloc	mov si, msg.eachdev.5.block.singular
internaldatarelocation
	cmp al, 1
	je @F
reloc	mov si, msg.eachdev.5.block.plural
internaldatarelocation
@@:
	extcallcall copy_single_counted_string
	push dx
	push bx
	extcallcall putsline_crlf

reloc	rol byte [verbose_dpb], 1
internaldatarelocation
	jnc .common

	extcallcall InDOS
	jnz error

	mov ax, 3000h
	int 21h
	mov di, 12h
	cmp al, 4
	jb @F
	inc di			; = 13h
@@:
	xor dx, dx
	mov ah, 52h
	call doscall_dx_for_es	; es:bx -> list of lists
	call setds2dx
	call ldsbxbx_dx
reloc	mov word [ss:firstdpb], bx
internaldatarelocation
reloc	mov word [ss:firstdpb + 2], dx
internaldatarelocation
	xor ax, ax
.finddpb:
reloc	mov cx, word [ss:unitsamount]
internaldatarelocation
	jcxz .common_j

.loopdpb:
reloc	mov word [ss:dpbsegment], dx
internaldatarelocation
	pop si
	pop dx
	push dx
	push si
	cmp bx, -1
	je .nodpb
	cmp byte [bx + 1], al		; device unit number
	jne .nextdpb
	cmp word [bx + di], si		; 12h v3, 13h v4+
	jne .nextdpb
	cmp word [bx + di + 2], dx	; device header
	jne .nextdpb

.founddpb:
	push di
	push ax				; low byte = unit
	push word [bx]			; low byte = drive, A: = 0
	push bx

	push ss
	pop es
	push ss
	pop ds

reloc	mov di, relocateddata
linkdatarelocation line_out

reloc	mov si, msg.dpb.1
internaldatarelocation
	extcallcall copy_single_counted_string

	extcallcall hexbyte		; unit

reloc	mov si, msg.dpb.2
internaldatarelocation
	extcallcall copy_single_counted_string

reloc	mov ax, word [dpbsegment]
internaldatarelocation
	extcallcall hexword		; segment

	mov ax, "h:"
	stosw

	pop ax
	extcallcall hexword		; offset

reloc	mov si, msg.dpb.3
internaldatarelocation
	extcallcall copy_single_counted_string

	pop ax				; drive
	add al, 'A'
	mov ah, ':'
	stosw

	extcallcall putsline_crlf
	pop ax
	pop di
	jmp .nextunit

.common_j:
	jmp .common

.nextunit:
	push ss
	pop ds
reloc	dec word [unitsamount]
internaldatarelocation
	inc ax
reloc	mov bx, firstdpb
internaldatarelocation
	call ldsbxbx_dx
	jmp .finddpb

.nextdpb:
	lea bx, [bx + di - 12h + 18h]	; 18h v3, 19h v4+
	call ldsbxbx_dx
	jmp .loopdpb

.nodpb:
	push di
	push ss
	pop es
	push ss
	pop ds

reloc	mov di, relocateddata
linkdatarelocation line_out

reloc	mov si, msg.nodpb.1
internaldatarelocation
	extcallcall copy_single_counted_string

	extcallcall hexbyte

reloc	mov si, msg.nodpb.2
internaldatarelocation
	extcallcall copy_single_counted_string

	push ax
	extcallcall putsline_crlf
	pop ax
	pop di
	jmp .nextunit


.next:
	push dx
	push bx
.common:
	 push ss
	 pop ds
reloc	dec word [devicesamount]
internaldatarelocation
	pop bx
	pop dx
	jz .done
	call setds2dx
	call ldsbxbx_dx
	push ss
	pop ds
	jmp .loop

.no_device_driver:
.done:
	push ss
	pop ds

display_interrupts:
reloc	rol byte [verbose_int], 1
internaldatarelocation
	jnc .done

reloc	mov ah, byte [mpx]
internaldatarelocation
	mov al, 04h
	mov bl, 2Dh
	extcallcall call_int2D		; determine chained interrupts

%if 0
void display_interrupts(int mpx_number)
{
  union REGS regs;
  uint8_t far * list;
  int interrupt = 0, ii = 0;
  uint16_t offset;
  const char * separator = "";

  regs.h.ah = mpx_number;
  regs.h.al = AMIS_VECTORS;
  regs.h.bl = 0x2D;
  int86(0x2D,&regs,&regs);
%endif

	cmp al, 04h
	je @F

%if 0
  if (regs.h.al == AMIS_CHAIN_HOOKLIST)
  {
%endif

reloc	mov dx, msg.no_int_list
internaldatarelocation
	extcallcall putsz
	jmp .display_interrupts_done

%if 0
  }
  printf(" chained interrupts cannot be determined\n");
  return;
}
%endif

@@:
reloc	mov word [saved], dx
internaldatarelocation

reloc	mov dx, msg.int_list
internaldatarelocation
	extcallcall putsz

%if 0
    printf(" chained interrupts: ");
    list = MK_FP(regs.x.dx,regs.x.bx);
%endif

reloc2	mov word [message_separator], msg.empty
internaldatarelocation -4
internaldatarelocation
	xor dx, dx
reloc	mov di, relocateddata
linkdatarelocation line_out

.int_loop:

reloc	mov si, word [message_separator]
internaldatarelocation
	extcallcall copy_single_counted_string

	call get_saved_es
	mov dh, byte [es:bx]
	mov al, dh
	push ss
	pop es
	extcallcall hexbyte

reloc	mov si, msg.int.1
internaldatarelocation
	extcallcall copy_single_counted_string

reloc	mov ax, word [saved]
internaldatarelocation
	extcallcall hexword

	mov ax, "h:"
	stosw

	call get_saved_es
	inc bx
	mov ax, word [es:bx]
	inc bx
	inc bx
	push ss
	pop es
	extcallcall hexword

	mov al, 'h'
	stosb

%if 0
      interrupt = *list++;
      offset = *list++;
      offset |= *list++ * 0x100;
      printf("%s%02Xh at %04Xh:%04Xh",
              separator, interrupt, regs.x.dx, offset);
%endif

reloc	mov ax, msg.separator_comma
internaldatarelocation
	inc dx

%if 0
      ++ ii;
%endif

	cmp dl, 3
	jb @F
	push bx
	push dx
	extcallcall putsline_crlf
	pop dx
	pop bx
reloc	mov di, relocateddata
linkdatarelocation line_out

	mov dl, 0
reloc	mov ax, msg.separator_nextline
internaldatarelocation
@@:
reloc	mov word [message_separator], ax
internaldatarelocation

%if 0
      if (ii % 3) {
        separator = ", ";
      } else {
        separator = "\n                     ";
                   /* " chained interrupts: " */
      }
%endif

	cmp dh, 2Dh
	jne .int_loop

%if 0
    while (interrupt != 0x2D) {
%endif

	test dl, dl
	jz @F
	extcallcall putsline_crlf
@@:

%if 0
    }
    printf("\n");
    return;
%endif

.done:
.display_interrupts_done:
	jmp next


handleshift:
	push cx
.outerloop:
	mov cx, word [bx]
	jcxz .outerdone
	inc bx
	inc bx
.loop:
	mov dx, ax
	and dx, word [bx]
	cmp dx, word [bx]
	jne .next
	mov dx, word [bx + 2]
	extcallcall putsz
	add cx, cx
	add cx, cx
	add bx, cx
	jmp .outerloop

.next:
	lea bx, [bx + 4]
	loop .loop
	jmp .outerloop

.outerdone:
	pop cx
	retn


get_saved_es:
	push dx
reloc	mov dx, word [saved]
internaldatarelocation
	extcallcall setes2dx
	pop dx
	retn


swap_es_ds:
	push es
	push ds
	pop es
	pop ds
	retn


doscall_dx_for_es:
	extcallcall ispm
	jnz .rm

subcpu 286
	push dx
	push word 21h
	extcall intcall_ext_return_es, PM required	; must NOT be extcallcall
	pop dx				; discard interrupt number
	pop dx				; get es
subcpureset
	jmp @F
.rm:
	mov es, dx
	int 21h
	mov dx, es
@@:
	push ss
	pop es
	retn


ldsbxbx_dx:
	mov dx, [bx + 2]
	mov bx, [bx]
	call setds2dx
	retn


setds2dx:
	push es
	extcallcall setes2dx
	 push es
	 pop ds
	pop es
	retn


		; INP:	es:bx -> text data, maximum length cx
		;	cx = maximum length
		; OUT:	cx = pad length
		;	calculate maximum length - OUT:cx to get string length
		; CHG:	di, al
get_esbx_pad_length_maximum_cx:
	mov di, bx
	mov al, 0
	repne scasb		; cx = 7 if 0 text bytes, = 6 if 1 text byte
	jne @F			; if NZ, then jump and leave cx = 0 -->
	inc cx			; 8 if 0, 7 if 1, 0 if 8
@@:
	retn


	eldcall_dump_callcall ELDCALL_CALLCALL_LIST

endinstalled equ ($ + CODEFIXUP + 15) & ~15


start:
	mov bx, es
	 push ss
	 pop es
	call skipcomma
	dec si
reloc	mov dx, relocateddata
linkdatarelocation msg.install
	call isstring?
	je install
	call run
	call uninstall_oneshot
	xor ax, ax
	retf


uninstall_oneshot:
reloc	testopt [ss:relocateddata], 1
linkdatarelocation options7, -3
	jnz @F

reloc	mov ax, word [cs:code + eldiEndCode]
internalcoderelocation
reloc	sub ax, word [cs:code + eldiStartCode]
internalcoderelocation
reloc	sub word [relocateddata], ax
linkdatarelocation extseg_used

reloc	mov ax, word [cs:code + eldiEndData]
internalcoderelocation
reloc	sub ax, word [cs:code + eldiStartData]
internalcoderelocation
reloc	sub word [relocateddata], ax
linkdatarelocation extdata_used
@@:
	retn


install:
	lodsb
	extcall chkeol

	houdini
	mov es, bx		; => ext seg (writable)
	mov ax, endresident - endinstalled
reloc	sub word [es:code + eldiEndCode], ax
internalcoderelocation		; adjust size
reloc	sub word [relocateddata], ax
linkdatarelocation extseg_used	; adjust size
reloc	mov bx, word [relocateddata]
linkdatarelocation ext_command_handler
				; -> prior
reloc	mov di, command		; -> our handler
internalcoderelocation
	test bx, bx		; installing as first ?
	jz .only_first		; yes, simple --> (leave as extcall cmd3_not_ext)
	scasw			; skip entrypoint jmp strict short
	mov al, 0E9h		; = jmp near opcode
	stosb			; store
	xchg ax, bx		; ax -> next handler
	sub ax, di
	dec ax
	dec ax			; ax = ax - (di + 2)
	stosw			; store our downlink as rel16 displacement

.only_first:
reloc	setopt [es:code + eldiFlags], eldifResident
internalcoderelocation -3	; mark block as resident
reloc2	mov word [relocateddata], command
linkdatarelocation ext_command_handler, -4
internalcoderelocation		; -> our entrypoint

reloc	testopt [relocateddata], 4
linkdatarelocation options7, -3
	jnz @F
reloc	mov dx, msg.installed
internaldatarelocation
	call putsz
@@:
	xor ax, ax
	retf


DATAOFFSET equ CODEOFFSET + code_size
	addsection DATA, follows=CODE vstart=_ELD_DATA_VSTART
%define DATAFIXUP - datastart + 0
datastart:
PUT_ELD_DATETIME

	align 4, db 0
keywordtable:
reloc	dw msg.mpx
internaldatarelocation
reloc	dw verbose_mpx
internaldatarelocation

reloc	dw msg.version
internaldatarelocation
reloc	dw verbose_mpx
internaldatarelocation

reloc	dw msg.entry
internaldatarelocation
reloc	dw verbose_mpx
internaldatarelocation

reloc	dw msg.hotkeys
internaldatarelocation
reloc	dw verbose_hotkeys
internaldatarelocation

reloc	dw msg.keys
internaldatarelocation
reloc	dw verbose_hotkeys
internaldatarelocation

reloc	dw msg.int
internaldatarelocation
reloc	dw verbose_int
internaldatarelocation

reloc	dw msg.intlist
internaldatarelocation
reloc	dw verbose_int
internaldatarelocation

reloc	dw msg.interrupts
internaldatarelocation
reloc	dw verbose_int
internaldatarelocation

reloc	dw msg.dev
internaldatarelocation
reloc	dw verbose_device
internaldatarelocation

reloc	dw msg.device
internaldatarelocation
reloc	dw verbose_device
internaldatarelocation

reloc	dw msg.block
internaldatarelocation
reloc	dw verbose_block
internaldatarelocation

reloc	dw msg.char
internaldatarelocation
reloc	dw verbose_char
internaldatarelocation

reloc	dw msg.dpb
internaldatarelocation
reloc	dw verbose_dpb
internaldatarelocation

	dw 0


%define MESSAGES db ""

%imacro shiftentry 2.nolist
	dw %1
reloc	dw %%message
internaldatarelocation

%xdefine MESSAGES MESSAGES, %%message:, {asciz %2}
%endmacro

%imacro dumpmessages 1-*.nolist
 %rep %0
	%1
  %rotate 1
 %endrep
%endmacro


	align 2, db 0
shifttable1:
	dw 4
	shiftentry HK_ANYCTRL, "Ctrl-"
	shiftentry HK_BOTHCTRL, "Ctrl-Ctrl-"
	shiftentry HK_LCTRL, "LCtrl-"
	shiftentry HK_RCTRL, "RCtrl-"

	dw 4
	shiftentry HK_ANYSHIFT, "Shift-"
	shiftentry HK_BOTHSHIFT, "Shift-Shift-"
	shiftentry HK_LSHIFT, "LShift-"
	shiftentry HK_RSHIFT, "RShift-"

	dw 4
	shiftentry HK_ANYALT, "Alt-"
	shiftentry HK_BOTHALT, "Alt-Alt-"
	shiftentry HK_LALT, "LAlt-"
	shiftentry HK_RALT, "RAlt-"

	dw 1
	shiftentry HK_SCROLLOCK, "ScrlLk-"
	dw 1
	shiftentry HK_NUMLOCK, "NumLk-"
	dw 1
	shiftentry HK_CAPSLOCK, "CapsLk-"
	dw 1
	shiftentry HK_SYSREQ, "SysRq-"

	dw 0

	align 2, db 0
shifttable2:
	dw 1
	shiftentry HK_SCRLLOCK_ON, " (ScrlLk on)"
	dw 1
	shiftentry HK_NUMLOCK_ON, " (NumLk on)"
	dw 1
	shiftentry HK_CAPSLOCK_ON, " (CapsLk on)"

	dw 0


%imacro scancodeentry 1.nolist
%ifidni %1, 0
	dw 0
%else
reloc	dw %%message
internaldatarelocation

%xdefine MESSAGES MESSAGES, %%message:, {asciz %1}
%endif
%endmacro

	align 2, db 0
scancodes:
.:
    scancodeentry "nokey"	;/* scan code 0 is "no key" */
    scancodeentry "Esc"
    scancodeentry "1"		;/* scan code 2 */
    scancodeentry "2"
    scancodeentry "3"		;/* scan code 4 */
    scancodeentry "4"
    scancodeentry "5"		;/* scan code 6 */
    scancodeentry "6"
    scancodeentry "7"		;/* scan code 8 */
    scancodeentry "8"
    scancodeentry "9"		;/* scan code 10 */
    scancodeentry "0"
    scancodeentry "-"		;/* scan code 12 */
    scancodeentry "="
    scancodeentry "Backsp"	;/* scan code 14 */
    scancodeentry "Tab"
    scancodeentry "Q"
    scancodeentry "W"
    scancodeentry "E"
    scancodeentry "R"
    scancodeentry "T"
    scancodeentry "Y"
    scancodeentry "U"
    scancodeentry "I"
    scancodeentry "O"
    scancodeentry "P"		;/* scan code 25 */
    scancodeentry "["
    scancodeentry "]"
    scancodeentry "Enter"
    scancodeentry "Ctrl"
    scancodeentry "A"
    scancodeentry "S"
    scancodeentry "D"
    scancodeentry "F"
    scancodeentry "G"
    scancodeentry "H"
    scancodeentry "J"
    scancodeentry "K"
    scancodeentry "L"
    scancodeentry ";"
    scancodeentry "'"		;/* scan code 40 */
    scancodeentry "`"
    scancodeentry "LShift"
    scancodeentry "\"
    scancodeentry "Z"
    scancodeentry "X"
    scancodeentry "C"
    scancodeentry "V"
    scancodeentry "B"
    scancodeentry "N"
    scancodeentry "M"
    scancodeentry ","
    scancodeentry "."
    scancodeentry "/"		;/* scan code 53 */
    scancodeentry "RShift"
    scancodeentry "*"
    scancodeentry "Alt"
    scancodeentry "Space"
    scancodeentry "CapsLk"
    scancodeentry "F1"
    scancodeentry "F2"
    scancodeentry "F3"
    scancodeentry "F4"
    scancodeentry "F5"
    scancodeentry "F6"		;/* scan code 64 */
    scancodeentry "F7"
    scancodeentry "F8"
    scancodeentry "F9"
    scancodeentry "F10"
    scancodeentry "NumLk"
    scancodeentry "ScrlLk"
    scancodeentry "Home"
    scancodeentry "Up"
    scancodeentry "PgUp"	;/* scan code 73 */
    scancodeentry "Grey-"
    scancodeentry "Left"
    scancodeentry "KP5"
    scancodeentry "Right"
    scancodeentry "Grey+"
    scancodeentry "End"
    scancodeentry "Down"
    scancodeentry "PgDn"	;/* scan code 81 */
    scancodeentry "Ins"
    scancodeentry "Del"
    scancodeentry "SysRq"
    scancodeentry 0
    scancodeentry 0
    scancodeentry "F11"		;/* scan code 87 */
    scancodeentry "F12"
.end:
.amount equ (.end - .) / 2


dumpmessages MESSAGES


msg:
.amitsrs:		asciz "AMITSRS"
.uninstall_done:	db "AMITSRS uninstalled."
%if _ELD_RECLAIM_HINT
			db " (Don't forget to use reclaim.eld)"
%endif
			asciz 13,10
.uninstall_error:	asciz "AMITSRS unable to uninstall!",13,10
.only:			asciz "ONLY"
.verbose:		asciz "VERBOSE"
.mpx:			asciz "MPX"
.hotkeys:		asciz "HOTKEYS"
.int:			asciz "INT"
.version:		asciz "VERSION"
.entry:			asciz "ENTRY"
.keys:			asciz "KEYS"
.intlist:		asciz "INTLIST"
.interrupts:		asciz "INTERRUPTS"
.dev:			asciz "DEV"
.device:		asciz "DEVICE"
.block:			asciz "BLOCK"
.char:			asciz "CHAR"
.dpb:			asciz "DPB"
.no2D:			asciz "No valid interrupt 2Dh handler!",13,10
.banner:
	db "Manufact  Product",9,9,"Description",13,10
	db "-------- -------- ----------------------------------------------",13,10
	asciz
.notsrs:	asciz "Matched no TSRs using the alternate multiplex interrupt",13,10
.mpx.1:		counted " multiplex "
.mpx.2:		counted "h    version "
.mpx.3.yes:	counted "   entry point "
.mpx.3.no:	counted "   no private entry point"
.dev.1:		counted " provides "
.dev.2.singular:counted " device header, flags="
.dev.2.plural:	counted " device headers, flags="
.dev.3:		counted "h, first at "
.no_hotkeys:		times 18 db 32
			asciz "no hotkeys",13,10
.hotkeys.plural:	counted " hotkeys on "
.hotkeys.singular:	counted " hotkey on "
.hotkeys.int09:		counted "INT 09H  "
.hotkeys.int15:		counted "INT 15H  "
.unknownkey:		counted "unknownkey="
.int_list:	asciz " chained interrupts: "
.no_int_list:	asciz " chained interrupts cannot be determined",13,10
.int.1:			counted "h at "
.separator_comma:	counted ", "
.separator_nextline:	counted "                     "
.empty:			db 0
.eachdev.1.block:	counted "h -> block dev, attr="
.eachdev.1.char:	counted "h -> char dev, attr="
.eachdev.2:		counted "h, strat="
.eachdev.3:		counted "h, int="
.eachdev.4.block:	counted "h, "
.eachdev.4.char:	counted "h, ",'"'
.eachdev.5.block.singular:
			counted " unit"
.eachdev.5.block.plural:
			counted " units"
.invaliddevice:		asciz "  Invalid device driver header address!",13,10
.nodpb.1:
.dpb.1:			counted "   DPB for unit "
.dpb.2:			counted "h at "
.dpb.3:			counted "h -> drive "
.nodpb.2:		counted "h not found!"
.22blanks:		times 22 db 32
			asciz
.linebreak:		asciz 13,10

uinit_data: equ $
.installed:		asciz "AMITSRS installed.",13,10

	align 16, db 0
transient_data_size equ $ - datastart
data_size equ $ - datastart

	absolute uinit_data

	alignb 2
firstdpb:		resd 1
dpbsegment:		resw 1
unitsamount:		resw 1
saved:			resw 1
message_separator:	resw 1
devicesamount:		resw 1
mpx_from:		resb 1
mpx_to:			resb 1	; must be directly after mpx_from
did_banner:		resb 1
verbose_mpx:		resb 1	; must be directly after did_banner {1}
verbose_hotkeys:	resb 1
verbose_int:		resb 1	; must be directly after verbose_hotkeys {2}
verbose_block:		resb 1
verbose_char:		resb 1	; must be directly after verbose_block
verbose_device:		resb 1
verbose_dpb:		resb 1	; must be directly after verbose_device
mpx:			resb 1

	alignb 16
uinit_data_end:
resident_data_end:

uinit_data_size equ uinit_data_end - datastart


%if uinit_data_size >= transient_data_size
 total_data_size equ uinit_data_size
%else
 total_data_size equ transient_data_size
%endif
%assign _DATA_SIZE total_data_size

	usesection CODE

%include "eldlink.asm"

	align 16
code_size equ $ - code
