;;
;; Copyright (c) 2012-2018, Intel Corporation
;;
;; Redistribution and use in source and binary forms, with or without
;; modification, are permitted provided that the following conditions are met:
;;
;;     * Redistributions of source code must retain the above copyright notice,
;;       this list of conditions and the following disclaimer.
;;     * Redistributions in binary form must reproduce the above copyright
;;       notice, this list of conditions and the following disclaimer in the
;;       documentation and/or other materials provided with the distribution.
;;     * Neither the name of Intel Corporation nor the names of its contributors
;;       may be used to endorse or promote products derived from this software
;;       without specific prior written permission.
;;
;; THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
;; AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
;; IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
;; DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
;; FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
;; DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
;; SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
;; CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
;; OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
;; OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
;;

; Macros for "printing" for debug purposes from within asm code
;
; The basic macros are:
;   DBGPRINT16, DBGPRINT32, DBGPRINT64, DBGPRINT_XMM, DBGPRINT_YMM, DBGPRINT_ZMM
; These are called with 1 or more arguments, all of which are of the
; size/type as specified in the name. E.g.
;   DBGPRINT64 reg1, reg2, reg3, ...
;
; There is also a macro DEBUGPRINTL that takes one argument, a string. E.g.
;   DBGPRINTL "hit this point in the code"
;
; There are also variations on these with the "DBGPRINT" suffixed with "L", e.g.
; DBGPRINTL64. These take two or more arguments, where the first is a string,
; and the rest are of the specified type, e.g.
;   DBGPRINTL64 "Rindex", Rindex
; Essentially, this is the same as a DBGPRINTL followed by DBGPRINT64.
;
; If DO_DBGPRINT is defined, then the macros write the debug information into
; a buffer. If DO_DBGPRINT is *not* defined, then the macros expand to nothing.
;
; CAVEAT: The macros need a GPR. Currently, it uses R15. If the first register
; argument is R15, then it will use R14. This means that if you try
;   DBGPRINTL64 "text", rax, r15
; you will not get the proper value of r15.
; One way to avoid this issue is to not use multiple registers on the same line
; if the register types are GPR (i.e. this is not an issue for printing XMM
; registers). E.g the above could be done with:
;   DBGPRINTL64 "test", rax
;   DBGPRINT64 r15
;
; Note also that the macros only check for r15. Thus is you tried something
; like (after token expansion):
;   DBGPRINT32 r15d
; you won't get the right results. If you want to display r15d, you should
; print it as the 64-bit r15.
;
; To actually print the data, from your C code include the file
; "dbgprint.h". The default buffer size is 16kB. If you want to change
; that, #define DBG_BUFFER_SIZE before including "dbgprint.h".
;
; Then, (after your asm routine(s) have returned, call
;   print_debug()    or    print_debug(file pointer)
; If you do not specify a file pointer, it defaults to stdout.
;
; Printing the debug data also resets the write pointer to the beginning,
; effectively "deleting" the previous messages.
;

;%define DO_DBGPRINT
%ifdef DO_DBGPRINT
extern pDebugBuffer
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; DBGPRINT_INT size, param, ...
%macro DBGPRINT_INT 2-*
%ifidni %2,r15
%xdefine %%reg r14
%else
%xdefine %%reg r15
%endif
%xdefine %%size %1
%rotate 1
	push	%%reg
	mov	%%reg, [pDebugBuffer]
%rep %0 - 1
	mov	byte [%%reg], %%size
	%if (%%size == 2)
	mov	word [%%reg+1], %1
	%elif (%%size == 4)
	mov	dword [%%reg+1], %1
	%elif (%%size == 8)
	mov	qword [%%reg+1], %1
	%elif (%%size == 16)
	movdqu	oword [%%reg+1], %1
	%elif (%%size == 32)
	vmovdqu	[%%reg+1], %1
	%elif (%%size == 64)
	vmovdqu32 [%%reg+1], %1
	%else
	%error invalid size %%size
	%endif
	add	%%reg, %%size+1
%rotate 1
%endrep
	mov	[pDebugBuffer], %%reg
	pop	%%reg
%endmacro
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; DBGPRINTL_INT size, label, param, ...
%macro DBGPRINTL_INT 3-*
%ifidni %3,r15
%xdefine %%reg r14
%else
%xdefine %%reg r15
%endif
%xdefine %%size %1
%rotate 1
	push	%%reg
	mov	%%reg, [pDebugBuffer]

	mov	byte [%%reg], 0x57
section .data
%%lab: db %1, 0
section .text
	mov	qword [%%reg+1], %%lab
	add	%%reg, 8+1
%rotate 1

%rep %0 - 2
	mov	byte [%%reg], %%size
%if (%%size == 2)
	mov	word [%%reg+1], %1
%elif (%%size == 4)
	mov	dword [%%reg+1], %1
%elif (%%size == 8)
	mov	qword [%%reg+1], %1
%elif (%%size == 16)
	movdqu	oword [%%reg+1], %1
%elif (%%size == 32)
	vmovdqu	[%%reg+1], %1
%elif (%%size == 64)
	vmovdqu32 [%%reg+1], %1
%else
%error invalid size %%size
%endif
	add	%%reg, %%size+1
%rotate 1
%endrep
	mov	[pDebugBuffer], %%reg
	pop	%%reg
%endmacro
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; DBGPRINTL* data, ...
%macro DBGPRINT16 1+
	DBGPRINT_INT 2, %1
%endmacro
%macro DBGPRINT32 1+
	DBGPRINT_INT 4, %1
%endmacro
%macro DBGPRINT64 1+
	DBGPRINT_INT 8, %1
%endmacro
%macro DBGPRINT_XMM 1+
	DBGPRINT_INT 16, %1
%endmacro
%macro DBGPRINT_YMM 1+
	DBGPRINT_INT 32, %1
%endmacro
%macro DBGPRINT_ZMM 1+
	DBGPRINT_INT 64, %1
%endmacro
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; DBGPRINTL* label, data, ...
%macro DBGPRINTL16 2+
	DBGPRINTL_INT 2, %1, %2
%endmacro
%macro DBGPRINTL32 2+
	DBGPRINTL_INT 4, %1, %2
%endmacro
%macro DBGPRINTL64 2+
	DBGPRINTL_INT 8, %1, %2
%endmacro
%macro DBGPRINTL_XMM 2+
	DBGPRINTL_INT 16, %1, %2
%endmacro
%macro DBGPRINTL_YMM 2+
	DBGPRINTL_INT 32, %1, %2
%endmacro
%macro DBGPRINTL_ZMM 2+
	DBGPRINTL_INT 64, %1, %2
%endmacro
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
%macro DBGPRINTL 1
	push	r15
	mov	r15, [pDebugBuffer]

	mov	byte [r15], 0x57
section .data
%%lab: db %1, 0
section .text
	mov	qword [r15+1], %%lab
	add	r15, 8+1

	mov	[pDebugBuffer], r15
	pop	r15
%endmacro
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
%else
%macro DBGPRINT16 1+
%endmacro
%macro DBGPRINT32 1+
%endmacro
%macro DBGPRINT64 1+
%endmacro
%macro DBGPRINT_XMM 1+
%endmacro
%macro DBGPRINT_YMM 1+
%endmacro
%macro DBGPRINT_ZMM 1+
%endmacro
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
%macro DBGPRINTL16 2+
%endmacro
%macro DBGPRINTL32 2+
%endmacro
%macro DBGPRINTL64 2+
%endmacro
%macro DBGPRINTL_XMM 2+
%endmacro
%macro DBGPRINTL_YMM 2+
%endmacro
%macro DBGPRINTL_ZMM 2+
%endmacro
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
%macro DBGPRINTL 1
%endmacro
%endif



%if 0 ; OLD
%macro DBGPRINTL_ZMM 2-*
	push	rax
	mov	rax, [pDebugBuffer]

	mov	byte [rax], 0x57
section .data
%%lab: db %1, 0
section .text
	mov	qword [rax+1], %%lab
	add	rax, 8+1
%rotate 1

%rep %0 - 1
	mov	byte [rax], 64
	vmovdqu32 [rax+1], %1
%rotate 1
	add	rax, 64+1
%endrep
	mov	[pDebugBuffer], rax
	pop	rax
%endmacro
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
%macro DBGPRINT_ZMM 1-*
	push	rax
	mov	rax, [pDebugBuffer]
%rep %0
	mov	byte [rax], 64
	vmovdqu32 [rax+1], %1
%rotate 1
	add	rax, 64+1
%endrep
	mov	[pDebugBuffer], rax
	pop	rax
%endmacro
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
%macro DBGPRINT_YMM 1-*
	push	rax
	mov	rax, [pDebugBuffer]
%rep %0
	mov	byte [rax], 32
	vmovdqu	[rax+1], %1
%rotate 1
	add	rax, 32+1
%endrep
	mov	[pDebugBuffer], rax
	pop	rax
%endmacro
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
%macro DBGPRINT_XMM 1-*
	push	rax
	mov	rax, [pDebugBuffer]
%rep %0
	mov	byte [rax], 16
	vmovdqu	oword [rax+1], %1
%rotate 1
	add	rax, 16+1
%endrep
	mov	[pDebugBuffer], rax
	pop	rax
%endmacro
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
%macro DBGPRINTL64 2-*
	push	rax
	mov	rax, [pDebugBuffer]

	mov	byte [rax], 0x57
section .data
%%lab: db %1, 0
section .text
	mov	qword [rax+1], %%lab
	add	rax, 8+1
%rotate 1

%rep %0 - 1
	mov	byte [rax], 8
	mov	qword [rax+1], %1
%rotate 1
	add	rax, 8+1
%endrep
	mov	[pDebugBuffer], rax
	pop	rax
%endmacro
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
%macro DBGPRINT64 1-*
	push	rax
	mov	rax, [pDebugBuffer]
%rep %0
	mov	byte [rax], 8
	mov	qword [rax+1], %1
%rotate 1
	add	rax, 8+1
%endrep
	mov	[pDebugBuffer], rax
	pop	rax
%endmacro
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
%macro DBGPRINT32 1-*
	push	rax
	mov	rax, [pDebugBuffer]
%rep %0
	mov	byte [rax], 4
	mov	dword [rax+1], %1
%rotate 1
	add	rax, 4+1
%endrep
	mov	[pDebugBuffer], rax
	pop	rax
%endmacro
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
%macro DBGPRINT16 1-*
	push	rax
	mov	rax, [pDebugBuffer]
%rep %0
	mov	byte [rax], 2
	mov	word [rax+1], %1
%rotate 1
	add	rax, 2+1
%endrep
	mov	[pDebugBuffer], rax
	pop	rax
%endmacro
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
%macro DBGPRINT_LAB 1
	push	rax
	mov	rax, [pDebugBuffer]

	mov	byte [rax], 0x57
section .data
%%lab: db %1, 0
section .text
	mov	qword [rax+1], %%lab
	add	rax, 8+1

	mov	[pDebugBuffer], rax
	pop	rax
%endmacro
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
%macro DBGHIST 2
	inc	dword [%1 + 4 * %2]
%endmacro
%macro DBGPRINT_ZMM 1-*
%endmacro
%macro DBGPRINT_YMM 1-*
%endmacro
%macro DBGPRINT_XMM 1-*
%endmacro
%macro DBGPRINT64 1-*
%endmacro
%macro DBGPRINT32 1-*
%endmacro
%macro DBGPRINT16 1-*
%endmacro
%macro DBGHIST 2
%endmacro
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
%endif ; ifdef 0 ; OLD
