
%if 0

lDebug 386 patch macros

Copyright (C) 2008-2023 E. 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

	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


%macro __writepatchtable2 0-*.nolist
%if %0 & 1
 %fatal Expected even number of arguments
%endif
%rep %0 >> 1
	%1 %2
%rotate 2
%endrep
%endmacro

%macro __patchtable2_entry 0.nolist
  ; only if this isn't the first (pseudo-)entry
  %if %$lastcount != 0
    %assign %$runscount %[%$runscount]+1
   ; if the offset from %$previous is less than 255
   %if (%$last-%$previous) < 255
    %assign %$$method2tablesize %$$method2tablesize+1
    ; then write a single byte (number of bytes not to patch between)
    %xdefine %$$method2list %$$method2list,db,%$last-%$previous
   %else
    ; otherwise write a 255 ("reposition") and write the 16-bit address afterwards
    %assign %$$method2tablesize %$$method2tablesize+3
    %xdefine %$$method2list %$$method2list,db,255,dw,%$last
    %assign %$reposcount %[%$reposcount]+1
   %endif
   %if %$lastcount == 1
    %assign %$onecount %[%$onecount]+1
   %endif
   %assign %$$method2tablesize %$$method2tablesize+1
   ; and write the number of bytes to be patched
   %xdefine %$$method2list %$$method2list,db,%$lastcount
   ; define %$previous for the next entry: it points to the next non-patched byte
   %define %$previous (%[%$last]+%[%$lastcount])
  %endif
%endmacro

%macro writepatchtable 2-*.nolist

	numdef %{1}_FORCE_METHOD, 0
%push
		; Determine length of simple table:
%assign %$method1tablesize (%0 - 2)*2

%if !_%{1}_FORCE_METHOD || _%{1}_FORCE_METHOD == 2
		; Determine length of complicated table:
%assign %$method2tablesize 0
%define %$method2list db,""
%push
%if _WPT_LABELS
 %define %$previous code_start	; if list contains labels
%else
 %define %$previous 0
%endif
%define %$last %[%$previous]
%assign %$lastcount 0
%assign %$onecount 0
%assign %$reposcount 0
%assign %$bytescount %0 - 2
%assign %$runscount 0
%rotate 1
%rep %0 - 2
 %rotate 1
 ;if  it continues the previous patch   and not too long   and this isn't the first
 %if ((%$last+%$lastcount) == %1) && (%$lastcount < 255) && (%$lastcount != 0)
  ; then do not write an entry, just increase the patch's size
  %assign %$lastcount %[%$lastcount]+1
 %else
  ; otherwise write the last entry
  __patchtable2_entry
  ; define new %$last to this parameter, %$lastcount to one
  %define %$last %1
  %assign %$lastcount 1
 %endif
%endrep
__patchtable2_entry

; at the end, there's a patch with offset 0, size 0
%assign %$$method2tablesize %$$method2tablesize+2
%xdefine %$$method2list %$$method2list,db,0,db,0

%assign %$$onecount %$onecount
%assign %$$reposcount %$reposcount
%assign %$$bytescount %$bytescount
%assign %$$runscount %$runscount
%pop
%rotate 1
%endif

%if _%{1}_FORCE_METHOD == 2
 %define __%{1}_method 2
%elif _%{1}_FORCE_METHOD == 1
 %define __%{1}_method 1
%else
 %if _%{1}_FORCE_METHOD
  %fatal Invalid forced method selected: _%{1}_FORCE_METHOD
 %endif
 %if %$method1tablesize > (%$method2tablesize+20)
  %define __%{1}_method 2
 %else
  %define __%{1}_method 1
 %endif
%endif


%1:
%if __%{1}_method == 2
	__writepatchtable2 %$method2list
	endarea %1
%assign %$size %1_size
%warning %1: %$size bytes (Method 2)
%warning 1B=%$onecount repo=%$reposcount run=%$runscount byte=%$bytescount
%else
%rotate 1
%rep %0 - 2
%rotate 1
	dw %1
%endrep
%rotate 1
	endarea %1
%assign %$size %1_size
%warning %1: %$size bytes (Method 1)
%endif
%pop
%endmacro
