[list -]
%if 0

Extensions to NASM macro collection
Public Domain by E. C. Masloch, 2019--2024
Intended for Real/Virtual 86 Mode programs.

%endif

%ifndef __lMACROS3_MAC__
%assign __lMACROS3_MAC__ 1

%include "lmacros2.mac"
[list -]


	; This macro is used to generate byte or word access to specific
	; bits of a dword variable.
	; %1 = token: if "~", bit value will be negated after checking
	; %2 = instruction
	; %3 = variable, in the form "[address]" without size specification
	; %4 = bit value(s) to access, must not be 0
	; %5 = bool: disable word access warning, defaults to 0
	; If the value in %4 has bits set in different bytes so that
	; a single 8- or 16-bit instruction cannot access all the bits,
	; an error is displayed. This insures that the macro only has
	; to generate one instruction, as a 32-bit access on 16-bit
	; CPUs requires multiple instructions. This workaround code
	; needs to be written specifically then, or the flags have to
	; be re-ordered to allow the access.
%macro _opt 4-5.nolist 0
%push
%defstr %$adr %3
%strlen %$len %$adr
%substr %$tf %$adr 1
%substr %$tb %$adr %$len
%substr %$adr %$adr 2,-2
%deftok %$adr %$adr
%%num: equ %4
%assign %$num %%num
%ifnidn %$tf,"["
 %error Invalid memory access syntax
%elifnidn %$tb,"]"
 %error Invalid memory access syntax
%elifn %$num
 %error Bit value is zero! Check code.
%elifn (%$num) & ~0FFh
	%2 byte [%$adr], %1(%$num)
%elifn (%$num) & ~0FF00h
	%2 byte [%$adr+1], %1((%$num)>>8)
%elifn (%$num) & ~0FF0000h
	%2 byte [%$adr+2], %1((%$num)>>16)
%elifn (%$num) & ~0FF000000h
	%2 byte [%$adr+3], %1((%$num)>>24)
%elifn (%$num) & ~0FFFFh
 %ifn %5
  %warning Macro generated word access
 %endif
	%2 word [%$adr], %1(%$num)
%elifn (%$num) & ~0FFFF00h
 %ifn %5
  %warning Macro generated word access
 %endif
	%2 word [%$adr+1], %1((%$num)>>8)
%elifn (%$num) & ~0FFFF0000h
 %ifn %5
  %warning Macro generated word access
 %endif
	%2 word [%$adr+2], %1((%$num)>>16)
%else
 %error Unsupported macro usage, requires dword:
 %ifempty %1
  %error %2 dword [%$adr], %$num
 %else
  %error %2 dword [%$adr], %1(%$num)
 %endif
%endif
%pop
%endmacro

	; User forms for above macro.
	; %1 = variable, in the form "[address]" without size specification
	; %2 = bit value(s) to access
	; %3 = bool: disable word access warning, defaults to 0
	; testopt tests the specified bits (using a "test" instruction) and
	; leaves a meaningful result in ZF, as well as NC.
	; clropt clears the specified bits (using an "and" instruction with
	; the negated value) and leaves NC, but a random ZF.
	; setopt sets the specified bits (using an "or" instruction) and
	; leaves NC, NZ (_opt checks that the specified bits are nonzero).
	; xoropt toggles the specified bits (using a "xor" instruction) and
	; leaves NC, but a random ZF.
%idefine testopt _opt ,test,
%idefine clropt _opt ~,and,
%idefine setopt _opt ,or,
%idefine xoropt _opt ,xor,


	%imacro addsection 1-3.nolist
%ifdef _SECTION_ADDED_%1
 %error Section %1 already added
%endif
	section %1 %2
%define _SECTION_ADDED_%1 1
%xdefine SECTION_TYPE_%1 %1
%ifnempty %3
 %xdefine SECTION_TYPE_%1 %3
%endif
	usesection %1
	%endmacro

	%imacro usesection 1-2.nolist 0
%ifndef _SECTION_ADDED_%1
 %error Section %1 not yet added
%endif
%if %2
%define _CURRENT_SECTION
%define _CURRENT_SECTION_TYPE
	[section %1]
%else
%xdefine _CURRENT_SECTION %1
%xdefine _CURRENT_SECTION_TYPE SECTION_TYPE_%1
	section %1
%endif
	%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


%endif
[list +]
