[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

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

	defaulting

		; 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 PROGNAME,	"lDebug"
strdef VERSION,		{" (",__DATE__,")"}	; immediately follows _PROGNAME
strdef REVISIONID,	""
strdef REVISIONID_LMACROS,	""
strdef REVISIONID_SCANPTAB,	""
strdef REVISIONID_INICOMP,	""
strdef REVISIONID_INICHECK,	""
strdef REVISIONID_LDOSBOOT,	""
numdef XTNAME,		0
numdef PM,		0	; create DEBUGX
numdef DEBUG,		0	; debug lDebug with itself, support BU command
numdef DEBUG0
numdef DEBUG1
numdef DEBUG2
numdef DEBUG3
numdef DEBUG4
numdef DEBUG5
%idefine d5 _d 5,
numdef TTEST,		1
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 DSTRINGS,	1	; support DZ, D$, D#, DW# commands
numdef DNUM,		1	; support DB, DW, DD, DP, DS, DO commands
numdef SDUMP,		1	; dump 16 bytes at found location for S command
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 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_COND_STACK_CHECK,		128	; see usage

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 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 BOOTLDR,		1	; support loading instead of DOS
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 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_G_BP,	16,-	; number of breakpoints for G
excdef !_BREAKPOINTS,NUM_B_BP	; (if no support, force number to zero)
excdef !_NUM_B_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 > 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

%assign _DEVICE 0
numdef DEVICE,		0	; (not yet) support loading TSR as device (requires TSR)
numdef TSR,		1	; support resident operation
excdef !_TSR,DEVICE
numdef DETECT,		0	; (not yet) detect DPMI mode changes
numdef MMXSUPP,		1	; support MMX specific commands
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 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 CATCHINT18,	1	; catch Int18 (diskless boot hook)
numdef CATCHINT19,	1	; catch Int19 (boot load)
%assign CATCHINTAMOUNT (!!_CATCHINT00 \
			 + !!_CATCHINT01 \
			 + !!_CATCHINT03 \
			 + !!_CATCHINT06 \
			 + !!_CATCHINT18 \
			 + !!_CATCHINT19 \
			 )
numdef CATCHINT08,	1	; catch Int08 (timer IRQ, special)
numdef CATCHINT2D,	1	; catch Int2D (AMIS, special)
numdef DEBUGUPDATESAVE,	1
numdef STACKSIZE,	512
%if _STACKSIZE < 128
 %error Too low stack size set
%endif
numdef AUXBUFFSIZE,	8192 + 16
numdef EXTHELP,		1
numdef PSPVARIABLES,	1	; support PSP, PPI, PPR variables
numdef DOSEMU,		1	; detect dosemu (eg to avoid DPMI entry hook)

		; 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.
excdef _ONLY386,ONLYNON386
excdef _ONLYNON386,386REGS
%if _DEBUG
%strcat _PROGNAME "Debuggable ",_PROGNAME
%strcat _FILENAME "D",_FILENAME
strdef BOOTSCRIPTNAME,	"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 EXCCSIP,		1	; display CS:IP where exception occured
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
%assign CATCHPMINTAMOUNT (!!_CATCHPMINT214C)
numdef DISPHOOK,	1	; display "DPMI entry hooked..."
excdef !_PM,NOEXTENDER,WIN9XSUPP,EXCCSIP,CATCHEXC06,CATCHEXC0C,DISPHOOK
%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


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
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 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
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
luf_mask_writable equ lufForceCHS

		numdef LUF_DEFAULT_DISKETTE, 0
		numdef LUF_DEFAULT_HARDDISK, 0
%endif

	struc EXEHEADER
exeSignature:	resw 1
exeExtraBytes:	resw 1	; bytes in last page
exePages:	resw 1	; number of 512-byte pages. includes the header!
exeRelocItems:	resw 1	; number of relocation items
exeHeaderSize:	resw 1	; header size in 16-byte paragraphs
exeMinAlloc:	resw 1	; minimum (bss) allocation in paragraphs
exeMaxAlloc:	resw 1	; maximum (bss) allocation in paragraphs
exeInitSS:	resw 1	; init ss (is relocated)
exeInitSP:	resw 1	; init sp
exeChecksum:	resw 1
exeInitCSIP:
exeInitIP:	resw 1	; init ip
exeInitCS:	resw 1	; init cs (is relocated)
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.
exeOverlayNum:	resw 1
	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 ISVARIABLESTRUC
ivName:		resw 1		; -> ASCIZ name
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
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 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


	%macro subcpu 1.nolist
%push SUBCPU
%xdefine %$CPU_PREV __CPU__
	cpu %1
	%endmacro

	%macro subcpureset 0.nolist
%ifnctx SUBCPU
 %error Wrong context
%endif
%xdefine __CPU__ %$CPU_PREV
%pop
__CPU__
	%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 ""

%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.

%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
%define PATCH_NO386_TABLE %[PATCH_NO386_TABLE],%%386_o32
		%1
	%endmacro

		; Address size 32-bit prefix if 386+ CPU
	%macro _386_a32 0-1+.nolist
%%386_a32:	a32
%define PATCH_NO386_TABLE %[PATCH_NO386_TABLE],%%386_a32
		%1
	%endmacro

		; Short jump if 386+ CPU
	%macro _386_jmps 1.nolist
%%386_jmps:	jmp short %1
%define PATCH_NO386_TABLE %[PATCH_NO386_TABLE],%%386_jmps,%%386_jmps+1
	%endmacro

		; Near jump if 386+ CPU
	%macro _386_jmpn 1.nolist
%%386_jmpn:	jmp near %1
%define PATCH_NO386_TABLE %[PATCH_NO386_TABLE],%%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
%define PATCH_386_TABLE %[PATCH_386_TABLE],%%no386_jmps,%%no386_jmps+1
	%endmacro

		; Near jump if no 386+ CPU
	%macro _no386_jmpn 1.nolist
%%no386_jmpn:	jmp near %1
%define PATCH_386_TABLE %[PATCH_386_TABLE],%%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
 %define PATCH_NO386_TABLE %[PATCH_NO386_TABLE],%%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
 %define PATCH_386_TABLE %[PATCH_386_TABLE],%%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 $+CODESECTIONFIXUP
		%1		; write instruction
__CPU__				; reset CPU type

%rep ($+CODESECTIONFIXUP) - %$entry
				; count size of instruction
 %define PATCH_NO386_TABLE %[PATCH_NO386_TABLE],%[%$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 $+CODESECTIONFIXUP
		%1		; write instruction

%rep ($+CODESECTIONFIXUP) - %$entry
				; count size of instruction
 %define PATCH_386_TABLE %[PATCH_386_TABLE],%[%$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 (($ - code_start) & 0FFh) == 0CCh
	nop
  %assign CODE_INSURE_COUNT 1 + CODE_INSURE_COUNT
 %endif
	%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


[list +]
