[list -]
%if 0

lDebug general set up and macros

Copyright (C) 1995-2003 Paul Vojta
Copyright (C) 2008-2012 C. Masloch

Usage of the works is permitted provided that this
instrument is retained with the works, so that any entity
that uses the works is notified of this instrument.

DISCLAIMER: THE WORKS ARE WITHOUT WARRANTY.

%endif

TOLOWER		equ 32
TOUPPER		equ ~32
TOUPPER_W	equ ~(32<<8|32)
MNEMONOFS	equ 28		; offset in disassembler output line
				;  where mnemonics start
MNEMONOFS_40	equ 20
MNEMONOFS_MS	equ 24

%include "lmacros3.mac"
[list -]
%include "AMIS.MAC"
[list -]

	defaulting 1			; enable defaulting
	numdef SYMBOLIC, 0

%if _SYMBOLIC
	defaulting 0			; disable defaulting
%include "symbols.mac"
[list -]
		; symbolic branch defines *without* defaulting!
	numdef ZZ_INSERT_TEMP, 1
	numdef XMS_SYMBOL_TABLE, 1
	numdef BUFFER_86MM_SLICE, 0
	numdef SECOND_SLICE, 0

	defaulting 1			; re-enable defaulting

		; symbolic branch defines
	numdef 86MM_SYMBOL_TABLE_MAX, 256, 256
%endif

		; serialp defines
	numdef USE_TX_FIFO, 1		; fill 16-byte UART TX FIFO when THRE
	numdef ECHO_RX_TO_TX, 0		; echo received text to the other side
	numdef RX_TO_TX_ADD_LF, 1

	numdef UART_PORT, 2
%if _UART_PORT == 1
	numdef INTNUM, 0Ch
	numdef OFFMASK, 0001_0000b
_ONMASK      equ ~ _OFFMASK
	numdef UART_BASE, 3F8h
%elif _UART_PORT == 2
	numdef INTNUM, 0Bh
	numdef OFFMASK, 0000_1000b
_ONMASK      equ ~ _OFFMASK
	numdef UART_BASE, 2F8h
%else
 %fatal Invalid UART_PORT value: _UART_PORT
%endif
	numdef UART_RATE, 12		; 9600 bps, see table in this file
	numdef UART_PARAMS, 0000_0011b	; 8n1, see tables
	numdef UART_FIFO, 0
		; 20h = (sometimes) use 64-byte FIFOs
		; 30h = (sometimes) mask of tx FIFO trigger level
		; C0h = mask of rx FIFO trigger level:
		;	00h = 1 byte
		;	40h = 4 bytes
		;	80h = 8 bytes
		;	C0h = 14 bytes
		; (may differ for some chips)
		; refer to https://github.com/spotify/linux/blob/6eb782fc88d11b9f40f3d1d714531f22c57b39f9/include/linux/serial_reg.h#L48
	numdef RXFIFOSIZE, 128	; set this to your needs
	numdef TXFIFOSIZE, 128	; dito.
		; the fifos must be large on slow computers
		; and can be small on fast ones
		; These have nothing to do with the 16550A's
		; built-in FIFOs!
	numdef BI_TX_FIFO_SIZE, 16
		; This refers to the 16550A's built-in TX FIFO.
		;  Set to 15 (instead of 16) here or in variable DSF if
		;  using dosemu before revision gc7f5a828 2019-01-22,
		;  see https://github.com/stsp/dosemu2/issues/748

%macro rx_checkwrap 0
  cmp  si, rxfifo+_RXFIFOSIZE
  jb  %%rx_nowrap
  mov  si, rxfifo
%%rx_nowrap:
%endmacro

%macro tx_checkwrap 0
  cmp  si, txfifo+_TXFIFOSIZE
  jb  %%tx_nowrap
  mov  si, txfifo
%%tx_nowrap:
%endmacro


			; Options. The defaults can be configured here.
			; All options can be set on NASM's command line too.
strdef FILENAME,	"DEBUG"	; max 6 characters!
strdef BOOTSCRIPTPREFIX,""
strdef BOOTSCRIPTNAME,	"LDEBUG.SLD"
strdef BOOTSCRIPTLABEL,	"bootstartup"
strdef DEVSCRIPTPREFIX,""
strdef DEVSCRIPTNAME,	"LDEBUG.SLD"
strdef DEVSCRIPTLABEL,	"devicestartup"
strdef APPSCRIPTPREFIX,""
strdef APPSCRIPTNAME,	"LDEBUG.SLD"
strdef APPSCRIPTLABEL,	"applicationstartup"
strdef PROGNAME,	"lDebug"
strdef VERSION,		{" (",__DATE__,")"}	; immediately follows _PROGNAME
numdef HELP_EXTERNAL,	0	; use externally-built help page files
numdef HELP_COMPRESSED,	0	; compress externally-built help pages
 excdef !_HELP_EXTERNAL, HELP_COMPRESSED
numdef TEST_HELP_FILE,	0	; include TESTHELP command
 excdef !_HELP_COMPRESSED, TEST_HELP_FILE
strdef REVISIONID,	""
strdef REVISIONID_LMACROS,	""
strdef REVISIONID_SYMSNIP,	""
strdef REVISIONID_SCANPTAB,	""
strdef REVISIONID_INICOMP,	""
strdef REVISIONID_INICHECK,	""
strdef REVISIONID_LDOSBOOT,	""
numdef XTNAME,		0
numdef PM,		0	; create DEBUGX
numdef PM_ENTRY_SECTION,1	; leave DPMI entry code in entry section
 excdef !_PM, PM_ENTRY_SECTION
numdef RUN_ENTRY_SECTION,1	; put some run.asm entrypoint code to entry sectiom
numdef RUN2_ENTRY_SECTION,1	; put some run.asm run code to entry section
numdef DEBUG,		0	; debug lDebug with itself, support BU command
numdef DEBUG_COND,	0	; add debug mode (conditionally debuggable)
numdef DEBUG_COND_DEFAULT_ON,1	; enable debug mode by default
numdef DEBUG0
numdef DEBUG1
numdef DEBUG2
numdef DEBUG3
numdef DEBUG4
numdef DEBUG5
%idefine d5 _d 5,
numdef TTEST,		1
numdef SLEEP_NEW,	1
numdef DOUBLEDOLLAR,	0	; accept double dollar for setting a high limit
				;  for dollar-prefixed segments in PM
numdef IMMASM,		0
numdef IMMASM_AUXBUFF,	0
numdef REGSHIGHLIGHT,	1
numdef GETLINEHIGHLIGHT,1
numdef DHIGHLIGHT,	0	; this defaults to off, not yet ready
numdef REGSLINEBREAK,	1	; allow opt6_r_linebreak to prepend linebreak to R
numdef REGSREADABLEFLAGS,1	; allow different flags state display styles
numdef MS_N_COMPAT,	1	; include N command mode compatible to MS Debug
numdef MS_0RANGE_COMPAT,1	; include compatibility mode for explicit 0 length
numdef MS_PROMPT_COMPAT,1	; include compatibility mode for R prompts
numdef MS_MNEMON_COMPAT,1	; include option for MS Debug style mnemonofs
numdef PASSTF,		0	; do not clear TF early in intr1 unconditionally
numdef VXCHG,		1	; support video swap so outputs remain separated
numdef VXCHG_DEFAULT_ON,0	; enable video swap by default
numdef VXCHGBIOS,	0	; use ROM-BIOS page swap to do video swap
numdef FORCETEXT,	0	; force setting text mode upon run return
numdef ALTVID,		1	; support alternate video adapter
numdef MCLOPT,		0	; accept /M command line option
numdef MCLOPT_DEFAULT,	8	; default for /M (8 = /M-, 20h = /M+)
numdef INDOS_PROMPT,	1	; prepend '!' to prompt while InDOS
numdef INDOS_PROMPT_NOBOOT, 1	; -... except while booted
numdef INDOS_PROMPT_NOFLAG, 1	; -... except while only DCO flag set
numdef EMS,		1	; support X commands
numdef INT,		1	; support DI command
numdef MCB,		1	; support DM command
numdef RN,		1	; support RN command
numdef DT,		1	; support DT command (ASCII table)
numdef DSTRINGS,	1	; support DZ, D$, D#, DW# commands
numdef DNUM,		1	; support DB, DW, DD commands
numdef DTOP,		1	; support TOP keyword for D, DB, DW, DD, DX
numdef RH,		1	; support RH commands
numdef SWHILEBUFFER,	1	; allow S command to use the WHILE buffer
numdef RECMDWHILEBUFFER,1	; allow RE commands to use the WHILE buffer
numdef STRNUM,		1	; support AS SIZE keywords for strings (E, F, S)
numdef COUNT,		1	; support COUNT command and variable
numdef SCOUNT,		1	; set COUNT variable for S pattern
numdef CLEAR,		1	; support CLEAR command (clear screen)
numdef HHDIVREMAIN,	1	; display remainder if H runs a division
numdef RSEPARATE,	1	; support R variable dword/3byte separator
numdef SDUMP,		1	; dump 16 bytes at found location for S command
numdef SDUMPDISPLACEMENT, 1	; in S dump list search pattern length displacement
numdef ESTRINGS,	1	; support EZ, E$, E#, EW# commands
; numdef ENUM,		1	; support EB, EW, ED, EP, ES, EO commands
numdef USESDA,		1	; use SDA to get/set PSP in RM
numdef SYSREQINT,	09h	; if _CATCHSYSREQ, defines the method (int 09h or 15h)
numdef SYSREQ_DISABLE_INT2F_HOOK,	0
				; if _CATCHSYSREQ and _PM disable int 2Fh hook
%if _SYSREQINT != 09h && _SYSREQINT != 15h
 %error Invalid SysReq interrupt number
%endif
numdef VDD,		1	; try to load DEBXXVDD.DLL to use it for L and W sector commands
numdef EXPRESSIONS,	1	; support expression evaluator for any numeric value
				; disabling this also uses the simple H command
numdef EXPRESSION_PRECEDENCE_STACK_CHECK,	128	; see usage
numdef EXPRESSION_PARENS_STACK_CHECK,		128	; see usage
numdef EXPRESSION_INDIRECTION_STACK_CHECK,	128	; see usage
numdef EXPRESSION_VALUE_IN_STACK_CHECK,		128	; see usage
numdef EXPRESSION_LINEAR_STACK_CHECK,		128	; see usage
numdef EXPRESSION_DESCTYPE_STACK_CHECK,		128	; see usage
numdef EXPRESSION_COND_STACK_CHECK,		128	; see usage
numdef EXPRESSION_DEBUG,0	; output debugging trace of expression

numdef INDIRECTION,	1	; support memory access inside expressions
numdef VARIABLES,	1	; support V0 to VF calculation variables
numdef OPTIONS,		1	; support DCO, DCS, DIF, DAO, DAS option variables
numdef MESSAGESEGMENT,	1	; separate message segment

numdef COND,		1	; disassemble short conditional jumps with notice on the condition
numdef COND_RDUMP_ONLY,	1	;  but only in the register dump single-line disassembler (R)
 excdef !_COND,COND_RDUMP_ONLY
numdef EXTHELP,		1

numdef APPLICATION,	1	; support loading as an application
numdef DEVICE,		1	; support loading as device driver
numdef DEVICE_SET_2324,	1	; set up debugger's own int 23h/24h for device mode
numdef TSR,		1	; support resident operation from application load
numdef ATTACH,		1	; support attaching from TSR/device mode
 excdef !(_APPLICATION && _TSR || _DEVICE), ATTACH
numdef CONFIG,		1	; detect and store configuration directory
 excdef !(_APPLICATION || _DEVICE), CONFIG
numdef BOOTLDR,		1	; support loading instead of DOS
numdef BOOTLDR_DISCARD,	1	; discard boot.asm code if unused
 excdef !_BOOTLDR, BOOTLDR_DISCARD
 excdef !(_APPLICATION || _DEVICE), BOOTLDR_DISCARD
numdef BOOTLDR_DISCARD_HELP, 1	; discard boot help if unused
 excdef !_BOOTLDR, BOOTLDR_DISCARD_HELP
 excdef !(_APPLICATION || _DEVICE), BOOTLDR_DISCARD_HELP
 excdef !_MESSAGESEGMENT, BOOTLDR_DISCARD_HELP
 excdef !_EXTHELP, BOOTLDR_DISCARD_HELP
numdef CHECKSUM,	0	; include inicheck revision ID if true
numdef INPUT_FILE_BOOT,	4	; number of boot input file levels to allow
 excdef !_BOOTLDR, INPUT_FILE_BOOT
				; (if no bootldr, force number to zero)

numdef INPUT_FILE_HANDLES, 16	; number of input file levels to allow
numdef RE_BUFFER_SIZE, 2048, -	; size of RE commands buffer
numdef RC_BUFFER_SIZE, 256, -	; size of RC commands buffer
numdef ACCESS_VARIABLES_AMOUNT, 4, 4
numdef MEMREF_AMOUNT, 4, 4
 excdef !_MEMREF_AMOUNT, ACCESS_VARIABLES_AMOUNT

numdef BREAKPOINTS,	1	; support B commands
numdef NUM_B_BP,	16,-	; number of breakpoints for B
numdef NUM_SYM_BP,	16,-	; number of symbol breakpoints
numdef NUM_G_BP,	16,-	; number of breakpoints for G
 excdef !_SYMBOLIC,NUM_SYM_BP	; no symbol breakpoints if not symbolic
 excdef !_BREAKPOINTS,NUM_B_BP,NUM_SYM_BP
				; (if no support, force number to zero)
 excdef !(_NUM_B_BP + _NUM_SYM_BP),BREAKPOINTS
				; (if number zero, no support)
numdef BREAKPOINTS_STICKY, 0	; support sticky breakpoints for B
numdef NUM_B_ID_BYTES, 384, -	; size of shared bb ID buffer space
numdef NUM_B_WHEN_BYTES, 1024, -; size of shared bb condition buffer space

%if _NUM_G_BP > 128
 %errror Number of G breakpoints must not be higher than 128
				; more don't fit on the command line anyway.
				; also insures our byte count is large enough.
%endif

%if (_NUM_B_BP + _NUM_SYM_BP) > 255
 %error Number of B breakpoints must not be higher than 255
				; insure that they work with a byte count
%endif

%if _NUM_B_ID_BYTES > 1024
 %error Size of bb ID buffer must not be higher than 1024 bytes
				; we use 10 bits for our offsets into this buffer
%endif

numdef DETECT,		0	; (not yet) detect DPMI mode changes
numdef MMXSUPP,		1	; support MMX specific commands
numdef MMX_REDETECT,	1	; redetect MMX support (86 Mode / PM)
numdef GUARD_86M_INT2F,	1	; check before calling 86 Mode int 2Fh
				; (it is assumed to be valid if we entered PM)
numdef DELAY_BEFORE_BP,	1	; allow option to delay before writing breakpoints
numdef HISTORY,		1	; command history for rawinput
numdef HISTORY_SIZE,	1024	; size of history buffer
numdef HISTORY_SEPARATE_FIXED, 1; use fixed-size separate history segment
%if _HISTORY
 %if _HISTORY_SEPARATE_FIXED
numdef HISTORY_SIZE,	8192	; different default size
 historysegment_size equ (_HISTORY_SIZE + 15) & ~15
 %imacro gethistorysegment 1
	mov %1, word [ss:history.segorsel]
 %endmacro
 %imacro gethistoryoffset 1
	mov %1, 0
 %endmacro
 %else
 historysegment_size equ 0
 %imacro gethistorysegment 1
	push ss
	pop %1
 %endmacro
 %imacro gethistoryoffset 1
	mov %1, historybuffer
 %endmacro
 %endif
%else
 historysegment_size equ 0
%endif
numdef NEWFULLHANDLING, 1	; fillbuf related hackery (ee/getline)
numdef DEFAULTSHOWSIZE,	0	; show size of various parts by default
numdef 40COLUMNS,	1

numdef CATCHINT00,	1	; catch Int00 (divide error)
numdef CATCHINT01,	1	; catch Int01 (single-step)
numdef CATCHINT03,	1	; catch Int03 (breakpoint)
	; The debugger only works properly with Int01 and Int03 hooked.
	;  However, the same as FreeDOS Debug we offer the option to
	;  not hook them. This is intended as an alternative to using
	;  the _DEBUG option (DDebug); if the inner debugger does not
	;  hook the breakpoint interrupts then it can be debugged.
numdef CATCHINT06,	1	; catch Int06 (invalid opcode)
numdef CATCHINT07,	0	; catch Int07 (no x87 present on 286+)
numdef CATCHINTFAULT,	1
numdef CATCHINT0C,	_CATCHINTFAULT
				; catch Int0C (stack fault in R86M, or IRQ)
numdef CATCHINT0D,	_CATCHINTFAULT
				; catch Int0D (general protection fault in R86M, or IRQ)
numdef CATCHINTFAULTCOND,1
numdef DETECT95LX,	1	; do not catch Int06 on HP 95LX
numdef CATCHINT18,	1	; catch Int18 (diskless boot hook)
numdef CATCHINT19,	1	; catch Int19 (boot load)
numdef CATCHSYSREQ,	0	; catch Int15 or Int09 (sysreq)
%assign CATCHINTAMOUNT (!!_CATCHINT00 \
			 + !!_CATCHINT01 \
			 + !!_CATCHINT03 \
			 + !!_CATCHINT06 \
			 + !!_CATCHINT07 \
			 + !!_CATCHINT0C \
			 + !!_CATCHINT0D \
			 + !!_CATCHINT18 \
			 + !!_CATCHINT19 \
			 + !!_CATCHSYSREQ \
			 )
numdef CATCHINT08,	1	; catch Int08 (timer IRQ, special)
numdef CATCHINT2D,	1	; catch Int2D (AMIS, special)
numdef DEBUGUPDATESAVE,	1
%assign _DEBUGUPDATESAVE 1	; (must be on now that unused downlinks equal -1)
numdef STACKSIZE,	512
%if _STACKSIZE < 128
 %error Too low stack size set
%endif
numdef AUXBUFFSIZE,	8192 + 16
numdef AUXBUFFMAXSIZE,	24 * 1024
%ifn _APPLICATION || _DEVICE
 %assign _AUXBUFFMAXSIZE _AUXBUFFSIZE
%endif
numdef WHILEBUFFSIZE,	264
numdef PSPVARIABLES,	1	; support PSP, PPI, PPR variables
numdef DOSEMU,		1	; detect dosemu (eg to avoid DPMI entry hook)
numdef DOSEMU_PRESTROKES_HELP,1	; call DOS_HELPER_PRESTROKES_START on dosemu2

numdef DISASM_32BIT,	1
		; these options ain't working yet:
numdef INSTSET,		6	; set general instruction set (0..6 for 8086..686)
numdef MMXINSTSET,	0	; (not yet) MMX instruction set
numdef FPUINSTSET,	1	; FPU instruction set
;numdef 386REGS,	1	; support 32-bit registers, as well as the FS and GS segment registers
numdef ONLYNON386,	0	; only support non-386 operation. no
				; 386-related patching is used.
				; additionally, 386 registers ain't
				; managed by lDebug. displays a warning.
numdef ONLY386,		0	; only 386+ operation. no 386-related
				; patching is used, and loading is
				; aborted on non-386 CPUs.
%if _ONLY386 && _ONLYNON386
 %error Cannot set both only 386 and only non-386
%endif
%if _DEBUG && _DEBUG_COND
%strcat _PROGNAME "Condtnl. Debuggable ",_PROGNAME
%strcat _FILENAME "C",_FILENAME
strdef BOOTSCRIPTNAME,	"LCDEBUG.SLD"
strdef DEVSCRIPTNAME,	"LCDEBUG.SLD"
strdef APPSCRIPTNAME,	"LCDEBUG.SLD"
%elif _DEBUG
%strcat _PROGNAME "Debuggable ",_PROGNAME
%strcat _FILENAME "D",_FILENAME
strdef BOOTSCRIPTNAME,	"LDDEBUG.SLD"
strdef DEVSCRIPTNAME,	"LDDEBUG.SLD"
strdef APPSCRIPTNAME,	"LDDEBUG.SLD"
%endif


			; Option sets. Selecting one of these
			; special options sets the default values
			; for other options. Because of defaulting,
			; the option sets have to be defined after
			; all the defaults for these options. (The
			; default that occurs last is used.)
numdef XT,		0
%if _XT
numdef INSTSET,		1	; restrict instruction set to 8086/88, 80186/88 (NEC V30/V20)
numdef PM,		0	; disable DPMI support
numdef VDD,		0	; disable VDD support
numdef MMXINSTSET,	0	; disable MMX instructions
numdef MMXSUPP,		0	; disable RM command
numdef ONLYNON386,	1	; disable 386-specific code
numdef ONLY386,		0	; disable 386-specific code
numdef XTNAME,		1
%endif


%if _XTNAME
%strcat _PROGNAME _PROGNAME,"XT"; lDebugXT
%strcat _FILENAME _FILENAME,"XT"; DEBUGXT
%endif

		; Following only take effect if _PM is true
numdef NOEXTENDER,	1	; don't assume DPMI host includes a DOS extender
numdef WIN9XSUPP,	1	; avoid to hook DPMI entry when running in Win9x
numdef CATCHEXC00,	1
numdef CATCHEXC01,	1
numdef CATCHEXC03,	1
	; As for the interrupts (refer to CATCHINT defines above), we
	;  allow building without the hooks for breakpoint exceptions.
numdef CATCHEXC06,	1	; catch exception 06h in PM
numdef CATCHEXC0C,	1	; catch exception 0Ch in PM
numdef CATCHEXC0D,	1
numdef CATCHEXC0E,	1
%assign CATCHEXCAMOUNT (!!_CATCHEXC00 \
			 + !!_CATCHEXC01 \
			 + !!_CATCHEXC03 \
			 + !!_CATCHEXC06 \
			 + !!_CATCHEXC0C \
			 + !!_CATCHEXC0D \
			 + !!_CATCHEXC0E \
			 )
numdef CATCHPMINT214C,	1	; catch interrupt 21h function 4Ch in PM
numdef CATCHPMINT41,	0	; catch interrupt 41h (function 004Fh handled)
%assign CATCHPMINTAMOUNT (!!_CATCHPMINT214C \
			   + !!_CATCHPMINT41)
numdef BREAK_INSTALLDPMI, 1	; allow to break on entering PM
numdef DISPHOOK,	1	; display "DPMI entry hooked..."
 excdef !_PM,NOEXTENDER,WIN9XSUPP,CATCHEXC06,CATCHEXC0C,DISPHOOK
 excdef !(_PM || _CATCHINT07 || _CATCHINT0C || _CATCHINT0D),EXCCSIP
%if _PM
%strcat _PROGNAME _PROGNAME,"X"
%strcat _FILENAME _FILENAME,"X"
%endif

	numdef BP_OFFSET, 1	; store preferred offsets in breakpoints
				;  (only displayed by BL and G LIST)
%if _BP_OFFSET
 %if _PM
  %assign BPSIZE	9	; 4 byte for 32-bit address,
				;  4 byte for 32-bit offset,
				;  1 byte storing original data
 %else
  %assign BPSIZE	6	; 3 byte for 21-bit address,
				;  2 byte for 16-bit offset,
				;  1 byte storing original data
 %endif
%else
 %if _PM
  %assign BPSIZE	5	; 4 byte for 32-bit address,
				;  1 byte storing original data
 %else
  %assign BPSIZE	4	; 3 byte for 21-bit address,
				;  1 byte storing original data
 %endif
%endif

numdef EXCCSIP,		1	; display CS:IP where exception occured
numdef AREAS_HOOK_CLIENT, _PM && _DEBUG
				; allow to install our areas into another debugger
				;  (this indicates to *use* AMIS function 33h)
numdef AREAS_HOOK_SERVER, _PM	; allow others to install areas into us
				;  (this indicates to *provide* AMIS function 33h)
numdef AREAS, \
	_AREAS_HOOK_CLIENT || _PM || \
	_CATCHINT07 || _CATCHINT0C || _CATCHINT0D
				; display message indicating area of fault


LINE_IN_LEN equ	257		; length of line_in (including header stuff)

		; PSP offsets
ALASAP	equ 02h			; Address of LAst Segment Allocated to Program
				;  => behind process's allocation
CPMCALL	equ 05h			; CP/M CALL 5 compatibility entrypoint
TPIV	equ 0Ah			; Terminate Program Interrupt Vector (Int22)
CCIV	equ 0Eh			; Control-C Interrupt Vector (Int23)
CEIV	equ 12h			; Critical Error Interrupt Vector (Int24)
SPSAV	equ 2Eh			; Save the stack pointer here
DTA	equ 80h			; Program arguments; also used to store file name (N cmd)


	struc INSTALLFLAG
ifKeyword:	resw 1
ifDescription:	resw 1
ifOptions:	resw 1
ifValue:	resw 1
ifTrying:	resw 1
ifReserved:	resw 1
	endstruc

	struc SEGADR
saOffset:	resd 1
saSegSel:	resw 1
%if _PM
saSegment:	resw 1
saSelector:	resw 1
%endif
	endstruc

	%macro segmentedaddress 0.nolist
	istruc SEGADR
	iend
	%endmacro

	struc SEGOFS16ADR
so16aOffset:	resw 1
so16aSegSel:	resw 1
%if _PM
so16aSegment:	resw 1
so16aSelector:	resw 1
%endif
	endstruc

	%macro segofs16address 0-1.nolist zero
	istruc SEGOFS16ADR
%ifidni %1,zero
%elifidni %1,minusone
at so16aOffset,		dw -1
at so16aSegSel,		dw -1
 %if _PM
at so16aSegment,	dw -1
at so16aSelector,	dw -1
 %endif
%else
 %error Unexpected initialiser keyword
%endif
	iend
	%endmacro

	struc SEGONLYADR
soaSegSel:	resw 1
%if _PM
soaSegment:	resw 1
soaSelector:	resw 1
%endif
	endstruc

	%macro segonlyaddress 0.nolist
	istruc SEGONLYADR
	iend
	%endmacro


%if _BOOTLDR
	struc BS
bsJump:	resb 3
bsOEM:	resb 8
bsBPB:
	endstruc

	struc EBPB		;        BPB sec
bpbBytesPerSector:	resw 1	; offset 00h 0Bh
bpbSectorsPerCluster:	resb 1	; offset 02h 0Dh
bpbReservedSectors:	resw 1	; offset 03h 0Eh
bpbNumFATs:		resb 1	; offset 05h 10h
bpbNumRootDirEnts:	resw 1	; offset 06h 11h -- 0 for FAT32
bpbTotalSectors:	resw 1	; offset 08h 13h
bpbMediaID:		resb 1	; offset 0Ah 15h
bpbSectorsPerFAT:	resw 1	; offset 0Bh 16h -- 0 for FAT32
bpbCHSSectors:		resw 1	; offset 0Dh 18h
bpbCHSHeads:		resw 1	; offset 0Fh 1Ah
bpbHiddenSectors:	resd 1	; offset 11h 1Ch
bpbTotalSectorsLarge:	resd 1	; offset 15h 20h
bpbNew:				; offset 19h 24h

ebpbSectorsPerFATLarge:	resd 1	; offset 19h 24h
ebpbFSFlags:		resw 1	; offset 1Dh 28h
ebpbFSVersion:		resw 1	; offset 1Fh 2Ah
ebpbRootCluster:	resd 1	; offset 21h 2Ch
ebpbFSINFOSector:	resw 1	; offset 25h 30h
ebpbBackupSector:	resw 1	; offset 27h 32h
ebpbReserved:		resb 12	; offset 29h 34h
ebpbNew:			; offset 35h 40h
	endstruc

	struc BPBN		; ofs B16 S16 B32 S32
bpbnBootUnit:		resb 1	; 00h 19h 24h 35h 40h
			resb 1	; 01h 1Ah 25h 36h 41h
bpbnExtBPBSignature:	resb 1	; 02h 1Bh 26h 37h 42h -- 29h for valid BPBN
bpbnSerialNumber:	resd 1	; 03h 1Ch 27h 38h 43h
bpbnVolumeLabel:	resb 11	; 07h 20h 2Bh 3Ch 47h
bpbnFilesystemID:	resb 8	; 12h 2Bh 36h 47h 52h
	endstruc		; 1Ah 33h 3Eh 4Fh 5Ah

	struc DIRENTRY
deName:		resb 8
deExt:		resb 3
deAttrib:	resb 1
dePlusSize:	resb 1
		resb 7
deClusterHigh:	resw 1
deTime:		resw 1
deDate:		resw 1
deClusterLow:	resw 1
deSize:		resd 1
	endstruc

ATTR_READONLY	equ 1
ATTR_HIDDEN	equ 2
ATTR_SYSTEM	equ 4
ATTR_VOLLABEL	equ 8
ATTR_DIRECTORY	equ 10h
ATTR_ARCHIVE	equ 20h

lsvclSignature		equ "CL"
lsvclBufferLength	equ 256

	struc LOADSTACKVARS, -10h
lsvFirstCluster:	resd 1
lsvFATSector:		resd 1
lsvFATSeg:		resw 1
lsvLoadSeg:		resw 1
lsvDataStart:		resd 1
	endstruc

	struc LOADDATA, LOADSTACKVARS - 10h
ldMemoryTop:	resw 1
ldLoadTop:	resw 1
ldSectorSeg:	resw 1
ldFATType:	resb 1
ldFlags:
ldHasLBA:	resb 1
ldClusterSize:	resw 1
ldParaPerSector:resw 1
ldDirCluster:			; dword
ldLoadingSeg:		; word
ldQueryPatchValue:	; word
lsvCommandLine:		; word
.start:		equ $ - lsvclBufferLength
.signature:	resw 1
ldLoadUntilSeg:		; word
lsvExtra:		; word
.partition:	resb 1	; byte
.flags:		resb 1	; byte
	endstruc

lsvefNoDataStart	equ 1
lsvefPartitionNumber	equ 2

	struc LOADCMDLINE, LOADDATA - lsvclBufferLength
ldCommandLine:
.start:		resb lsvclBufferLength
	endstruc

ldfHasLBA:	equ 1
ldfFATInvalid:	equ 2

	struc LOADDATA2, LOADDATA - 10h
ldRootSector:		resd 1
ldEntriesPerSector:	resw 1
ldLastAvailableSector:	resw 1
ldParasLeft:		resw 1
ldParasDone:		resw 1
	endstruc

	struc LOADDATA3, LOADDATA2 - 10h
ldMaxCluster:		resd 1
ldFileSize:		resd 1
ldCurrentCluster:	resd 1
ldCurrentSeek:		resd 1
	endstruc

	struc LOADSETTINGS
lsKernelName:	resw 1	; -> kernel file default name
lsAddName:	resw 1	; -> additional file default name, may be empty string
lsMinPara:	resw 1	; how much to load at least, fail if file smaller
lsMaxPara:	resw 1	; how much to load at most
lsOptions:	resw 1	; option flags
lsSegment:	resw 1	; => where to load file
lsEntry:	resd 1	; relative segment for CS, value for IP
lsBPB:		resd 1	; segment for BPB (-1 auto-BPB), offset for BPB
lsCheckOffset:	resw 1	; offset in file segment of word to check
lsCheckValue:	resw 1	; value to check for word, 0 if unused
lsName:		resq 1	; ASCIZ load protocol name
	endstruc

	struc DIRENTRY
deName:		resb 8
deExt:		resb 3
deAttrib:	resb 1
		resb 8
deClusterHigh:	resw 1
deTime:		resw 1
deDate:		resw 1
deClusterLow:	resw 1
deSize:		resd 1
	endstruc

ATTR_READONLY	equ 1
ATTR_HIDDEN	equ 2
ATTR_SYSTEM	equ 4
ATTR_VOLLABEL	equ 8
ATTR_DIRECTORY	equ 10h
ATTR_ARCHIVE	equ 20h

	struc LBAPACKET
lpSize:		resw 1
lpCount:	resw 1
lpBuffer:	resd 1
lpSector:	resq 1
	endstruc

	struc PARTINFO
piBoot:		resb 1
piStartCHS:	resb 3
piType:		resb 1
piEndCHS:	resb 3
piStart:	resd 1
piLength:	resd 1
	endstruc

ptEmpty:		equ 0
ptFAT12:		equ 1
ptFAT16_16BIT_CHS:	equ 4
ptExtendedCHS:		equ 5
ptFAT16_CHS:		equ 6
ptFAT32_CHS:		equ 0Bh
ptFAT32:		equ 0Ch
ptFAT16:		equ 0Eh
ptExtended:		equ 0Fh
ptLinux:		equ 83h
ptExtendedLinux:	equ 85h

		; Flags of load_unit_flags
lufForceCHS:		equ 1
lufForceLBA:		equ 2
lufForceGeometry:	equ 4
luf_mask_writable equ lufForceCHS | lufForceLBA | lufForceGeometry

		numdef LUF_DEFAULT_DISKETTE, 0
		numdef LUF_DEFAULT_HARDDISK, 0
%endif

	struc EXEHEADER
exact_struc_at 00h, exeSignature:	resw 1
exact_struc_at 02h, exeExtraBytes:	resw 1	; bytes in last page
exact_struc_at 04h, exePages:		resw 1	; number of 512-byte pages. includes the header!
exact_struc_at 06h, exeRelocItems:	resw 1	; number of relocation items
exact_struc_at 08h, exeHeaderSize:	resw 1	; header size in 16-byte paragraphs
exact_struc_at 0Ah, exeMinAlloc:	resw 1	; minimum (bss) allocation in paragraphs
exact_struc_at 0Ch, exeMaxAlloc:	resw 1	; maximum (bss) allocation in paragraphs
exact_struc_at 0Eh, exeInitSS:		resw 1	; init ss (is relocated)
exact_struc_at 10h, exeInitSP:		resw 1	; init sp
exact_struc_at 12h, exeChecksum:	resw 1
exact_struc_at 14h, exeInitCSIP:
exact_struc_at 14h, exeInitIP:		resw 1	; init ip
exact_struc_at 16h, exeInitCS:		resw 1	; init cs (is relocated)
exact_struc_at 18h, exeRelocTable:	resw 1	; byte offset of relocation table
		; Each relocation item is a word offset and a word segment.
		;  The segment of the item itself is relocated as well.
exact_struc_at 1Ah, exeOverlayNum:	resw 1
exact_struc_at 1Ch
	endstruc


	struc INPUTFILEHANDLE
ifhHandle:	resw 1
ifhFlags:	resw 1
ifhParentSeek:	resd 1
	endstruc

ifhfIsDup:		equ  100h	; before closing, seek it back
	; same value as LBA flag for boot load input files
ifhfTestReserved1:	equ 1000h
ifhfTestReserved2:	equ 2000h
ifhfQuietInput:		equ 4000h	; do not display prompt and input
ifhfQuietOutput:	equ 8000h	; do not display normal output
	; these four are valid for both input file handles and
	;  boot load input files.


	struc AREASTRUC
areastrucEntry:		resb 24
areastrucNext:		resd 1
areastrucPrev:		resd 1
areastrucSubAmount:	resw 1
areastrucSubOffset:	resw 1
areastrucFunAmount:	resw 1
areastrucFunOffset:	resw 1
	endstruc

	struc AREASTRUCSUB
areastrucsubLinear:	resd 1
areastrucsubLinearEnd:	resd 1
areastrucsubListOffset:	resw 1
areastrucsubListAmount:	resw 1
	endstruc

	struc AREASTRUCFUN
areastrucfunLinear:	resd 1
areastrucfunLinearEnd:	resd 1
areastrucfunListOffset:	resw 1
areastrucfunListAmount:	resw 1
	endstruc

	struc AREA
areastart:		resw 1
areaend:		resw 1
areamessage:		resw 1
			resw 1
	endstruc


	struc ISVARIABLESTRUC
ivName:		resw 1		; -> name (up to 13 bytes, but actually only 11)
				;  (search for ivfNameLengthLimit for limit)
				;  (length given by ivFlags & ivfNameLengthMask)
	; The ivName pointer is only used for more-byte names. It actually
	;  contains the trailer of the name, excluding the prefix formed by
	;  the first two bytes. This suffix can be the empty string if the
	;  variable in question has a two-byte name.
	; (For one-byte names this field is unused and contains zero.)
ivFlags:	resw 1
ivAddress:	resw 1		; -> variable, or -> special set up code
ivArrayLast:	resb 1		; 0 if no array, FFh = 256 entries
ivArrayBetween: resb 1		; how many bytes to skip for each index
	endstruc

ivfNameLengthMask:	equ 15
ivfNameLengthLimit:	equ 13
ivfVarLengthShift:	equ 4
ivfVarLengthMask:	equ 3 << ivfVarLengthShift
ivfSpecialSetUp:	equ 40h
ivfReadOnly:		equ 80h
ivfArrayOneBased:	equ 100h
ivfArrayOptional:	equ 200h
ivfSeparatorSpecial:	equ 400h

%define ISVARIABLESTRINGS db "",db ""
%define IVS_ONEBYTE_NAMES ""
%define IVS_MOREBYTE_NAMEHEADERS ""
%assign IVS_HAVE_ONEBYTE 0
%assign IVS_SINGLE_ONEBYTE 1

	%macro isvariablestruc 4-6.nolist 0, 0
%push
%strlen %$namelength %1
%if %$namelength > ivfNameLengthLimit
 %error Expected at most 13-byte name (or adjust isvariable? code)
%endif
%if IVS_ONEBYTE && %$namelength != 1
 %error Expected a one-byte name
%elif ! IVS_ONEBYTE && %$namelength < 2
 %error Expected at least a two-byte name
%endif
%if IVS_ONEBYTE
 %define IVS_SINGLE_ONEBYTE_NAME %1
 %if IVS_HAVE_ONEBYTE
  %assign IVS_SINGLE_ONEBYTE 0
 %endif
 %assign IVS_HAVE_ONEBYTE 1
 %assign %$namelength 0
 %xdefine IVS_ONEBYTE_NAMES IVS_ONEBYTE_NAMES, %1
 %%name equ 0
%else
 %assign %$namelength %$namelength - 2
 %substr %$nametrailer %1 3,-1
 %substr %$nameheader %1 1,2
 %xdefine IVS_MOREBYTE_NAMEHEADERS IVS_MOREBYTE_NAMEHEADERS, %$nameheader
 %xdefine ISVARIABLESTRINGS ISVARIABLESTRINGS, %%name:, {db %$nametrailer}
%endif

%assign %$varlength %2 - 1	; 0 means one byte, 1 means two bytes,
				;  2 means three bytes, 3 means four bytes
	istruc ISVARIABLESTRUC
at ivName,		dw %%name
at ivFlags,		dw %$$namelength | (%$$varlength << ivfVarLengthShift) | %3
at ivAddress,		dw %4
at ivArrayLast,		db %5
at ivArrayBetween,	db %6
	iend
%pop
	%endmacro

	%macro isvariablestrings 2-*.nolist
%rep %0
 %1
 %rotate 1
%endrep
	%endmacro


	numdef WPT_LABELS, 0
		; This used to be required, because CODESECTIONFIXUP used
		;  ldebug_data_entry_size, which is not yet defined during
		;  assembling of (most) lDEBUG_CODE fragments.
		; However, assembling DebugX with this option selected
		;  took more than 2 minutes, so the non-label variant
		;  is clearly to be preferred when available.
		; Now that lDEBUG_CODE has vstart=0 we can use the
		;  CODESECTIONFIXUP again and thus disable this option.

%define PATCH_NO386_TABLE ""
%define PATCH_386_TABLE ""
%define PATCH_NO386_TABLE2 ""
%define PATCH_386_TABLE2 ""
%define PATCH_NO386_TABLEENTRY ""
%define PATCH_386_TABLEENTRY ""

%if _ONLY386
		; Default patch macros if only running on 386+.
%define _386_o32 o32
%define _386_a32 a32
%define _386_jmps jmp short
%define _386_jmpn jmp near
%define _no386_jmps comment
%define _no386_jmpn comment
	%macro _386 0-1+.nolist
[cpu 386]			; change CPU type
		%1		; write instruction
__CPU__				; reset CPU type
	%endmacro
%define _no386 comment
%elif _ONLYNON386
		; Default patch macros if only running on non-386.
%define _386_o32
%define _386_a32
%define _386_jmps comment
%define _386_jmpn comment
%define _no386_jmps jmp short
%define _no386_jmpn jmp near
%define _386 comment
%define _no386
%else

; These macros are to make DEBUG's 386 support as small as
; possible. To achieve this, two patch tables are created
; in the initialisation code. One of the tables is used if
; the CPU is a 386+, the other one if it isn't. The bytes
; pointed to in the used table are over-written with NOP
; instructions. (The patched bytes are usually address or
; operand size prefixes or jumps that branch to 386/non-386
; code.)

; There are a few special patches that require the
; initialisation code to write specific bytes other than
; NOP instructions for lower resident memory usage.
; Two are in the run: code, three in pmentry.asm.

	%macro patch386 2+.nolist
%ifidn _CURRENT_SECTION, lDEBUG_CODE
 %define PATCH_%{1}386_TABLE %[PATCH_%{1}386_TABLE], %2
%elifidn _CURRENT_SECTION, lDEBUG_CODE2
 %define PATCH_%{1}386_TABLE2 %[PATCH_%{1}386_TABLE2], %2
%elifidn _CURRENT_SECTION, lDEBUG_DATA_ENTRY
 %define PATCH_%{1}386_TABLEENTRY %[PATCH_%{1}386_TABLEENTRY], %2
%else
 %error Wrong section
%endif
	%endmacro

%if _WPT_LABELS
	; These forms provide verbose info by defining a
	; meaningful label for each patch. That fills up
	; the map file and might take longer though.
		; Operand size 32-bit prefix if 386+ CPU
	%macro _386_o32 0-1+.nolist
%%386_o32:	o32
patch386 NO, %%386_o32
		%1
	%endmacro

		; Address size 32-bit prefix if 386+ CPU
	%macro _386_a32 0-1+.nolist
%%386_a32:	a32
patch386 NO, %%386_a32
		%1
	%endmacro

		; Short jump if 386+ CPU
	%macro _386_jmps 1.nolist
%%386_jmps:	jmp short %1
patch386 NO, %%386_jmps,%%386_jmps+1
	%endmacro

		; Near jump if 386+ CPU
	%macro _386_jmpn 1.nolist
%%386_jmpn:	jmp near %1
patch386 NO, %%386_jmpn,%%386_jmpn+1,%%386_jmpn+2
	%endmacro

		; Short jump if no 386+ CPU
	%macro _no386_jmps 1.nolist
%%no386_jmps:	jmp short %1
patch386 , %%no386_jmps,%%no386_jmps+1
	%endmacro

		; Near jump if no 386+ CPU
	%macro _no386_jmpn 1.nolist
%%no386_jmpn:	jmp near %1
patch386 , %%no386_jmpn,%%no386_jmpn+1,%%no386_jmpn+2
	%endmacro

		; Instruction if 386+ CPU
	%macro _386 0-1+.nolist
[cpu 386]			; change CPU type
%%386_instr:	%1		; write instruction
__CPU__				; reset CPU type

%assign %%INSTRCOUNT 0
%rep $-%%386_instr		; count size of instruction
 patch386 NO, %%386_instr+%[%%INSTRCOUNT]
				; write a patch for each byte
 %assign %%INSTRCOUNT %%INSTRCOUNT+1
%endrep
%undef %%INSTRCOUNT
	%endmacro

		; Instruction if no 386+ CPU
	%macro _no386 0-1+.nolist
%%no386_instr:	%1		; write instruction

%assign %%INSTRCOUNT 0
%rep $-%%no386_instr		; count size of instruction
 patch386 , %%no386_instr+%[%%INSTRCOUNT]
				; write a patch for each byte
 %assign %%INSTRCOUNT %%INSTRCOUNT+1
%endrep
%undef %%INSTRCOUNT
	%endmacro
%else	; 0
		; Operand size 32-bit prefix if 386+ CPU
	%macro _386_o32 0-1+.nolist
_386		o32
		%1
	%endmacro

		; Address size 32-bit prefix if 386+ CPU
	%macro _386_a32 0-1+.nolist
_386		a32
		%1
	%endmacro

		; Short jump if 386+ CPU
	%macro _386_jmps 1.nolist
_386		jmp short %1
	%endmacro

		; Near jump if 386+ CPU
	%macro _386_jmpn 1.nolist
_386		jmp near %1
	%endmacro

		; Short jump if no 386+ CPU
	%macro _no386_jmps 1.nolist
_no386		jmp short %1
	%endmacro

		; Near jump if no 386+ CPU
	%macro _no386_jmpn 1.nolist
_no386		jmp near %1
	%endmacro

		; Instruction if 386+ CPU
	%macro _386 0-1+.nolist
%push
[cpu 386]			; change CPU type
%assign %$entry $ + _CURRENT_SECTION %+ FIXUP
		%1		; write instruction
__CPU__				; reset CPU type

%rep ($ + _CURRENT_SECTION %+ FIXUP) - %$entry
				; count size of instruction
 patch386 NO, %[%$entry]	; write a patch for each byte
 %assign %$entry %$entry+1
%endrep
%pop
	%endmacro

		; Instruction if no 386+ CPU
	%macro _no386 0-1+.nolist
%push
%assign %$entry $ + _CURRENT_SECTION %+ FIXUP
		%1		; write instruction

%rep ($ + _CURRENT_SECTION %+ FIXUP) - %$entry
				; count size of instruction
 patch386 , %[%$entry]		; write a patch for each byte
 %assign %$entry %$entry+1
%endrep
%pop
	%endmacro
%endif	; 1


%endif

		; Patch macros but for cases where the 386+
		; instructions should only be generated for
		; DEBUGX (i.e. for 32-bit DPMI addressing code).
%if _PM
%define _386_PM_o32	_386_o32
%define _386_PM_a32	_386_a32
%define _386_PM_jmps	_386_jmps
%define _386_PM_jmpn	_386_jmpn
%define _386_PM		_386
%else
%define _386_PM_o32
%define _386_PM_a32
%define _386_PM_jmps	comment
%define _386_PM_jmpn	comment
%define _386_PM		comment
%endif

%if _VDD
; standard BOPs for communication with DEBXXVDD on NT platforms
%macro RegisterModule 0.nolist
	db 0C4h, 0C4h, 58h, 0
	nop
%endmacro
%macro UnRegisterModule 0.nolist
	db 0C4h, 0C4h, 58h, 1
	nop
%endmacro
%macro DispatchCall 0.nolist
	db 0C4h, 0C4h, 58h, 2
	nop
%endmacro
%endif

%assign CODE_INSURE_COUNT 0

		; The entry_to_code_seg/_sel dispatcher in lDEBUG_DATA_ENTRY
		;  detects mistaken debugger breakpoints in its
		;  in-code-parameter by checking for a low-byte
		;  value equal to 0CCh (one-byte int3 opcode).
		; Therefore, we insure that all destinations jumped to
		;  via that dispatcher do not happen to be located
		;  on an offset that gives 0CCh in the low byte.
	%imacro code_insure_low_byte_not_0CCh 0.nolist
 %if (($ - _CURRENT_SECTION %+ _start) & 0FFh) == 0CCh
	nop
  %assign CODE_INSURE_COUNT 1 + CODE_INSURE_COUNT
 %endif
	%endmacro


		; dual code segments
	numdef DUALCODE, _SYMBOLIC && _PM
	numdef DUALCODENEARDUAL, 1
	numdef EXPRDUALCODE, 0
	numdef SYMBOLICDUALCODE, 1
	numdef SYMBOLASMDUALCODE, 0
%if _DUALCODE && _PM

%if _DEBUG
%idefine dualfunction comment
%else
%idefine dualfunction code_insure_low_byte_not_0CCh
%endif

%idefine dualreturn call _CURRENT_SECTION %+ _dualret_helper
%idefine dualdistance far
	%imacro dualcall 1.nolist
%ifndef SECTION_OF_%1
 %error Unknown target section for symbol %1
%endif
	call _CURRENT_SECTION %+ _to_ %+ %[SECTION_OF_%1] %+ _dualcall_helper
 %if _DEBUG
	jmp strict short %%skipdata
 %endif
	dw %1
%%skipdata:
	%endmacro
	%imacro nearcall 1.nolist
%ifndef SECTION_OF_%1
 %error Unknown target section for symbol %1
%endif
%ifidni %[SECTION_OF_%1], _CURRENT_SECTION
	call %1
%else
	call _CURRENT_SECTION %+ _to_ %+ %[SECTION_OF_%1] %+ _nearcall_helper
 %if _DEBUG
	jmp strict short %%skipdata
 %endif
	dw %1
%%skipdata:
%endif
	%endmacro

%elif _DUALCODE && ! _PM

%idefine dualfunction comment
%idefine dualreturn
%idefine dualdistance far
%define PATCH_RELOCATE_FROM_lDEBUG_CODE ""
%define PATCH_RELOCATE_FROM_lDEBUG_CODE2 ""
	%imacro dualcall 1.nolist
%ifndef SECTION_OF_%1
 %error Unknown target section for symbol %1
%endif
%ifidni %[SECTION_OF_%1], _CURRENT_SECTION
	push cs
	call %1
%else
	call relocatedzero:%1
%push
%assign %$entry ($ + _CURRENT_SECTION %+ FIXUP) - 2
	relocatelist _CURRENT_SECTION, %$entry
%pop
%endif
	%endmacro
	%imacro relocatelist 2.nolist
 %define PATCH_RELOCATE_FROM_%1 %[PATCH_RELOCATE_FROM_%1],%2
	%endmacro
 %if _DUALCODENEARDUAL
	%imacro nearcall 1
%ifndef SECTION_OF_%1
 %error Unknown target section for symbol %1
%endif
%ifidni %[SECTION_OF_%1], _CURRENT_SECTION
	call %1
%else
 %push
 %xdefine %$originalsection _CURRENT_SECTION
 %xdefine %$targetsection SECTION_OF_%1
  %ifndef NEARCALL_THUNK_TO_%1
	usesection %$targetsection
%define NEARCALL_THUNK_TO_%1 %%nearcall_thunk_to_%1
section_of %%nearcall_thunk_to_%1
dualfunction
%%nearcall_thunk_to_%1:
	call %1
	dualreturn
	retf

	usesection %$originalsection
  %endif
 %pop
	dualcall NEARCALL_THUNK_TO_%1
%endif
	%endmacro
 %else
	%imacro nearcall 1.nolist
%ifndef SECTION_OF_%1
 %error Unknown target section for symbol %1
%endif
%ifidni %[SECTION_OF_%1], _CURRENT_SECTION
	call %1
%else
	call _CURRENT_SECTION %+ _to_ %+ %[SECTION_OF_%1] %+ _nearcall_helper
 %if _DEBUG
	jmp strict short %%skipdata
 %endif
	dw %1
%%skipdata:
%endif
	%endmacro
 %endif
%elif ! _DUALCODE

%idefine dualfunction comment
%idefine dualreturn
%idefine dualdistance near
	%imacro dualcall 1.nolist
	call %1
	%endmacro
	%imacro nearcall 1.nolist
	call %1
	%endmacro
%assign _SYMBOLICDUALCODE 0
%assign _SYMBOLASMDUALCODE 0

%else
 %error Unexpected defines
%endif

%ifn _SYMBOLICDUALCODE
 %assign _SYMBOLASMDUALCODE 0
%endif

 %if _SYMBOLIC && _DUALCODE && _SYMBOLASMDUALCODE
%idefine dual2function	dualfunction
%idefine dual2return	dualreturn
%idefine dual2distance	dualdistance
%idefine dual2call	dualcall
 %else
%idefine dual2function comment
%idefine dual2return
%idefine dual2distance near
	%imacro dual2call 1.nolist
	call %1
	%endmacro
 %endif

	%imacro section_of 1-*.nolist
%rep %0
%xdefine SECTION_OF_%1 _CURRENT_SECTION
%rotate 1
%endrep
	%endmacro

	%imacro check_section_of 1.nolist
%ifndef SECTION_OF_%1
 %error No section specified for symbol %1
%elifnidni SECTION_OF_%1, _CURRENT_SECTION
 %error Wrong section for symbol %1: section_of=SECTION_OF_%1, current=_CURRENT_SECTION
%endif
	%endmacro

	%imacro section_of_function 0-1.nolist
check_section_of %1%00
%00:
	%endmacro


	numdef CHECKSECTION, 0
	numdef CHECKCALLSECTION, _CHECKSECTION
	numdef CHECKJMPSECTION, _CHECKSECTION
	numdef CHECKJCCSECTION, _CHECKSECTION

%if _CHECKCALLSECTION
	%imacro call 1.nolist
	%? %1
checksection %1, %?, call
	%endmacro
%endif
%if _CHECKJMPSECTION
	%imacro jmp 1.nolist
	%? %1
checksection %1, %?, jmp
	%endmacro
%endif
%if _CHECKJCCSECTION
	%imacro je 1.nolist
	%? %1
checksection %1, %?, jcc
	%endmacro
	%imacro jne 1.nolist
	%? %1
checksection %1, %?, jcc
	%endmacro
	%imacro jz 1.nolist
	%? %1
checksection %1, %?, jcc
	%endmacro
	%imacro jnz 1.nolist
	%? %1
checksection %1, %?, jcc
	%endmacro

	%imacro jb 1.nolist
	%? %1
checksection %1, %?, jcc
	%endmacro
	%imacro jnb 1.nolist
	%? %1
checksection %1, %?, jcc
	%endmacro
	%imacro jbe 1.nolist
	%? %1
checksection %1, %?, jcc
	%endmacro
	%imacro jnbe 1.nolist
	%? %1
checksection %1, %?, jcc
	%endmacro
	%imacro jc 1.nolist
	%? %1
checksection %1, %?, jcc
	%endmacro
	%imacro jnc 1.nolist
	%? %1
checksection %1, %?, jcc
	%endmacro
	%imacro ja 1.nolist
	%? %1
checksection %1, %?, jcc
	%endmacro
	%imacro jna 1.nolist
	%? %1
checksection %1, %?, jcc
	%endmacro
	%imacro jae 1.nolist
	%? %1
checksection %1, %?, jcc
	%endmacro
	%imacro jnae 1.nolist
	%? %1
checksection %1, %?, jcc
	%endmacro

	%imacro jl 1.nolist
	%? %1
checksection %1, %?, jcc
	%endmacro
	%imacro jnl 1.nolist
	%? %1
checksection %1, %?, jcc
	%endmacro
	%imacro jle 1.nolist
	%? %1
checksection %1, %?, jcc
	%endmacro
	%imacro jnle 1.nolist
	%? %1
checksection %1, %?, jcc
	%endmacro
	%imacro jg 1.nolist
	%? %1
checksection %1, %?, jcc
	%endmacro
	%imacro jng 1.nolist
	%? %1
checksection %1, %?, jcc
	%endmacro
	%imacro jge 1.nolist
	%? %1
checksection %1, %?, jcc
	%endmacro
	%imacro jnge 1.nolist
	%? %1
checksection %1, %?, jcc
	%endmacro

	%imacro jo 1.nolist
	%? %1
checksection %1, %?, jcc
	%endmacro
	%imacro jno 1.nolist
	%? %1
checksection %1, %?, jcc
	%endmacro
	%imacro jp 1.nolist
	%? %1
checksection %1, %?, jcc
	%endmacro
	%imacro jnp 1.nolist
	%? %1
checksection %1, %?, jcc
	%endmacro
	%imacro jpe 1.nolist
	%? %1
checksection %1, %?, jcc
	%endmacro
	%imacro jnpe 1.nolist
	%? %1
checksection %1, %?, jcc
	%endmacro
	%imacro jpo 1.nolist
	%? %1
checksection %1, %?, jcc
	%endmacro
	%imacro jnpo 1.nolist
	%? %1
checksection %1, %?, jcc
	%endmacro
	%imacro js 1.nolist
	%? %1
checksection %1, %?, jcc
	%endmacro
	%imacro jns 1.nolist
	%? %1
checksection %1, %?, jcc
	%endmacro

	%imacro jcxz 1.nolist
	%? %1
checksection %1, %?, jcc
	%endmacro
	%imacro jecxz 1.nolist
	%? %1
checksection %1, %?, jcc
	%endmacro
	%imacro loop 1.nolist
	%? %1
checksection %1, %?, jcc
	%endmacro
	%imacro loopz 1.nolist
	%? %1
checksection %1, %?, jcc
	%endmacro
	%imacro loopnz 1.nolist
	%? %1
checksection %1, %?, jcc
	%endmacro
	%imacro loope 1.nolist
	%? %1
checksection %1, %?, jcc
	%endmacro
	%imacro loopne 1.nolist
	%? %1
checksection %1, %?, jcc
	%endmacro
%endif

	%imacro checksection 3.nolist
%push
 %defstr %$string %1
 %substr %$shortword %$string 1, 5
 %substr %$shortsep %$string 6, 1
 %substr %$nearword %$string 1, 4
 %substr %$nearsep %$string 5, 1
 %substr %$farword %$string 1, 3
 %substr %$farsep %$string 4, 1
 %assign %$isshort 0
 %ifidni %$shortword, "short"
  %if %$shortsep == 32 || %$shortsep == 9
   %assign %$isshort 1
   %substr %$string %$string 7, -1
  %elif %$shortsep == '['
   %assign %$isshort 1
   %substr %$string %$string 6, -1
  %endif
 %endif
 %assign %$isnear 0
 %ifidni %$nearword, "near"
  %if %$nearsep == 32 || %$nearsep == 9
   %assign %$isnear 1
   %substr %$string %$string 6, -1
  %elif %$nearsep == '['
   %assign %$isnear 1
   %substr %$string %$string 5, -1
  %endif
 %endif
 %assign %$isfar 0
 %ifidni %$farword, "far"
  %if %$farsep == 32 || %$farsep == 9
   %assign %$isfar 1
   %substr %$string %$string 5, -1
  %elif %$farsep == '['
   %assign %$isfar 1
   %substr %$string %$string 4, -1
  %endif
 %endif

 %deftok %$token %$string

 %assign %$size 2
 %assign %$isreg 0
 %assign %$exit 0
 %rep 2
  %ifn %$exit
   %if %$size == 2
    %define %$regnames "ax  cx  dx  bx  sp  bp  si  di  "
   %elif %$size == 4
    %define %$regnames "eax ecx edx ebx esp ebp esi edi "
   %endif
   %assign %$index 0
   %rep 8
    %ifn %$exit
     %substr %$reg %$regnames %$index * 4 + 1, 4
     %deftok %$reg %$reg
     %ifnempty %$reg
      %ifidni %$reg, %$token
       %assign %$isreg %$size
       %assign %$exit 1
       %exitrep
      %endif
     %endif
    %endif
    %assign %$index %$index + 1
   %endrep
   %if %$exit
    %exitrep
   %endif
   %assign %$size %$size * 2
  %endif
 %endrep

 %assign %$ismulti 0
 %assign %$ismem 0
 %strlen %$length %$string
 %assign %$ii 0
 %rep %$length
  %substr %$point %$string %$ii + 1, 1
  %if %$point == 32 || %$point == 9
   %assign %$ismulti 1
  %endif
  %ifidn %$point, '['
   %assign %$ismem 1
  %endif
  %assign %$ii %$ii + 1
 %endrep

 %assign %$islocal 0
 %substr %$point %$string 1, 1
 %substr %$prefix %$string 1, 3
 %ifidn %$point, '.'
  %ifnidn %$prefix, '..@'
   %assign %$islocal 1
  %endif
 %endif

 %if %$isreg
  %if %$isreg == 4
   %warning 32-bit reg %3: %2 %1
  %else
   %warning 16-bit reg %3: %2 %1
  %endif
 %elif %$ismulti || %$ismem
  %warning not single %3: %2 %1
 %elif %$islocal
  %ifidni %3, call
   %warning local %3: %2 %1
  %endif
 %elifdef SECTION_OF_%[%$token]
  %ifnidni SECTION_OF_%[%$token], _CURRENT_SECTION
   %error Symbol %$token called wrongly: section_of=SECTION_OF_%[%$token], current=_CURRENT_SECTION
  %endif
 %endif
%pop
	%endmacro


	struc MEMREF
mrLinear:		resd 1
mrOffset:		resd 1
mrSegmentSelector:	resw 1
mrFlags:		resw 1
mrLength:		resd 1
	endstruc

		; Currently only direct branches are allowed when
		;  disassembling from the U command. (That is,
		;  [disflags] & DIS_F_SHOW is clear.) All other
		;  types of references depend on segment registers
		;  and sometimes base and index registers, which are
		;  not known ahead of time. They are only known for
		;  the R command's disassembly. (DIS_F_SHOW set.)
		; (When a mov ss or pop to ss will change ss, a
		;  subsequent instruction using ss will not be
		;  disassembled with the correct ss value.
		;  This should be rare though. We may at a later
		;  point detect this condition and not display
		;  references with ss then.)
mrfBranchDirect:	equ    1
mrfMem:			equ    2
mrfMemSource:		equ    4
mrfMemDest:		equ    8
mrfA32:			equ   10h
mrfString:		equ   20h
mrfStringSource:	equ   40h
mrfStringDest:		equ   80h
mrfUsesSS:		equ  100h
mrfBranchIndirect:	equ  200h


%if _VXCHG && ! _VXCHGBIOS
	struc XMSM
.size_:		resd 1
.srchdl:	resw 1
.srcadr:	resd 1
.dsthdl:	resw 1
.dstadr:	resd 1
	endstruc
%endif


[list +]
