;;
;; 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 defining data structures

; Usage example

;START_FIELDS	; JOB_AES
;;;	name		size	align
;FIELD	_plaintext,	8,	8	; pointer to plaintext
;FIELD	_ciphertext,	8,	8	; pointer to ciphertext
;FIELD	_IV,		16,	8	; IV
;FIELD	_keys,		8,	8	; pointer to keys
;FIELD	_len,		4,	4	; length in bytes
;FIELD	_status,	4,	4	; status enumeration
;FIELD	_user_data,	8,	8	; pointer to user data
;UNION  _union,         size1,  align1, \
;	                size2,  align2, \
;	                size3,  align3, \
;	                ...
;END_FIELDS
;%assign _JOB_AES_size	_FIELD_OFFSET
;%assign _JOB_AES_align	_STRUCT_ALIGN

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

; Alternate "struc-like" syntax:
;	STRUCT job_aes2
;	RES_Q	.plaintext,	1
;	RES_Q	.ciphertext, 	1
;	RES_DQ	.IV,		1
;	RES_B	.nested,	_JOB_AES_SIZE, _JOB_AES_ALIGN
;	RES_U	.union,		size1, align1, \
;				size2, align2, \
;				...
;	ENDSTRUCT
;	; Following only needed if nesting
;	%assign job_aes2_size	_FIELD_OFFSET
;	%assign job_aes2_align	_STRUCT_ALIGN
;
; RES_* macros take a name, a count and an optional alignment.
; The count in in terms of the base size of the macro, and the
; default alignment is the base size.
; The macros are:
; Macro    Base size
; RES_B	    1
; RES_W	    2
; RES_D     4
; RES_Q     8
; RES_DQ   16
; RES_Y    32
; RES_Z    64
;
; RES_U defines a union. It's arguments are a name and two or more
; pairs of "size, alignment"
;
; The two assigns are only needed if this structure is being nested
; within another. Even if the assigns are not done, one can still use
; STRUCT_NAME_size as the size of the structure.
;
; Note that for nesting, you still need to assign to STRUCT_NAME_size.
;
; The differences between this and using "struc" directly are that each
; type is implicitly aligned to its natural length (although this can be
; over-ridden with an explicit third parameter), and that the structure
; is padded at the end to its overall alignment.
;

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

%ifndef _DATASTRUCT_ASM_
%define _DATASTRUCT_ASM_

;; START_FIELDS
%macro START_FIELDS 0
%assign _FIELD_OFFSET 0
%assign _STRUCT_ALIGN 0
%endm

;; FIELD name size align
%macro FIELD 3
%define %%name  %1
%define %%size  %2
%define %%align %3

%assign _FIELD_OFFSET (_FIELD_OFFSET + (%%align) - 1) & (~ ((%%align)-1))
%%name	equ	_FIELD_OFFSET
%assign _FIELD_OFFSET _FIELD_OFFSET + (%%size)
%if (%%align > _STRUCT_ALIGN)
%assign _STRUCT_ALIGN %%align
%endif
%endm

;; END_FIELDS
%macro END_FIELDS 0
%assign _FIELD_OFFSET (_FIELD_OFFSET + _STRUCT_ALIGN-1) & (~ (_STRUCT_ALIGN-1))
%endm

%macro UNION 5-*
%if (0 == (%0 & 1))
	%error EVEN number of parameters to UNION Macro
	%err
%endif
%rotate 1
	%assign _UNION_SIZE %1
	%assign _UNION_ALIGN %2
%rep (%0 - 3)/2
	%rotate 2
	%if (%1 > _UNION_SIZE)
		%assign _UNION_SIZE %1
	%endif
	%if (%2 > _UNION_ALIGN)
		%assign _UNION_ALIGN %2
	%endif
%endrep
%rotate 2
FIELD	%1, _UNION_SIZE, _UNION_ALIGN
%endm

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

%macro STRUCT 1
START_FIELDS
struc %1
%endm

%macro ENDSTRUCT 0
%assign %%tmp _FIELD_OFFSET
END_FIELDS
%assign %%tmp (_FIELD_OFFSET - %%tmp)
%if (%%tmp > 0)
	resb	%%tmp
%endif
endstruc
%endm

;; RES_int name size align
%macro RES_int 3
%define %%name  %1
%define %%size  %2
%define %%align %3

%assign _FIELD_OFFSET (_FIELD_OFFSET + (%%align) - 1) & (~ ((%%align)-1))
align %%align
%%name	resb	%%size
%assign _FIELD_OFFSET _FIELD_OFFSET + (%%size)
%if (%%align > _STRUCT_ALIGN)
%assign _STRUCT_ALIGN %%align
%endif
%endm



; macro RES_B name, size [, align]
%macro RES_B 2-3 1
RES_int %1, %2, %3
%endm

; macro RES_W name, size [, align]
%macro RES_W 2-3 2
RES_int %1, 2*(%2), %3
%endm

; macro RES_D name, size [, align]
%macro RES_D 2-3 4
RES_int %1, 4*(%2), %3
%endm

; macro RES_Q name, size [, align]
%macro RES_Q 2-3 8
RES_int %1, 8*(%2), %3
%endm

; macro RES_DQ name, size [, align]
%macro RES_DQ 2-3 16
RES_int %1, 16*(%2), %3
%endm

; macro RES_Y name, size [, align]
%macro RES_Y 2-3 32
RES_int %1, 32*(%2), %3
%endm

; macro RES_Z name, size [, align]
%macro RES_Z 2-3 64
RES_int %1, 64*(%2), %3
%endm


%macro RES_U 5-*
%if (0 == (%0 & 1))
	%error EVEN number of parameters to RES_U Macro
	%err
%endif
%rotate 1
	%assign _UNION_SIZE %1
	%assign _UNION_ALIGN %2
%rep (%0 - 3)/2
	%rotate 2
	%if (%1 > _UNION_SIZE)
		%assign _UNION_SIZE %1
	%endif
	%if (%2 > _UNION_ALIGN)
		%assign _UNION_ALIGN %2
	%endif
%endrep
%rotate 2
RES_int	%1, _UNION_SIZE, _UNION_ALIGN
%endm

%endif ; end ifdef _DATASTRUCT_ASM_
