;
; Copyright 2020 Electronic Arts Inc.
;
; TiberianDawn.DLL and RedAlert.dll and corresponding source code is free 
; software: you can redistribute it and/or modify it under the terms of 
; the GNU General Public License as published by the Free Software Foundation, 
; either version 3 of the License, or (at your option) any later version.

; TiberianDawn.DLL and RedAlert.dll and corresponding source code is distributed 
; in the hope that it will be useful, but with permitted additional restrictions 
; under Section 7 of the GPL. See the GNU General Public License in LICENSE.TXT 
; distributed with this program. You should have received a copy of the 
; GNU General Public License along with permitted additional restrictions 
; with this program. If not, see [https://github.com/electronicarts/CnC_Remastered_Collection]>.


;***************************************************************************
;**   C O N F I D E N T I A L --- W E S T W O O D   S T U D I O S  I N C  **
;***************************************************************************
;*                                                                         *
;*                 Project Name : Command & Conquer                        *
;*                                                                         *
;*                    File Name : MMX.ASM                                  *
;*                                                                         *
;*                   Programmer : Steve Tall                               *
;*                                                                         *
;*                   Start Date : May 19th, 1996                           *
;*                                                                         *
;*                  Last Update : May 19th 1996 [ST]                       *
;*                                                                         *
;*-------------------------------------------------------------------------*
;* Functions:                                                              *
;* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - *


 ;		include	<mmx.inc>


		.model	flat
		;.686


		externdef	C Detect_MMX_Availability:near
		externdef	C Single_Line_Trans_Entry:near
		externdef	C Next_Line:near
		externdef	C Init_MMX:near
		externdef	C MMX_Done:near

		externdef	EndNewShapeJumpTable:byte
		externdef	NewShapeJumpTable:dword
		externdef	C Single_Line_Trans:near
		externdef	MMX_Single_Line_Trans:near


		.code

externdef	C CPUType:byte



;*********************************************************************************************
;* Detect_MMX_Availability -- Detect the presence of MMX technology.                         *
;*                                                                                           *
;*                                                                                           *
;* INPUT:	Nothing                                                                      *
;*                                                                                           *
;* OUTPUT:      True if MMX technology is available.                                         *
;*                                                                                           *
;* Warnings:                                                                                 *
;*                                                                                           *
;* Note: Based in part on CPUID32.ASM by Intel                                               *
;*                                                                                           *
;* HISTORY:                                                                                  *
;*   05/19/96 ST : Created.                                                                  *
;*===========================================================================================*

Detect_MMX_Availability proc C

		local	idflag:byte
		local	local_cputype:byte

		; MMX always available now. ST - 1/3/2019 1:31PM
		mov	[CPUType], 5
		mov	eax, 1
		ret


;assume processor is at least 386
;
;check whether AC bit in eflags can be toggled.
;If not then processor is 386

		mov	[idflag],0

		pushfd			;get Eflags in EAX
		pop	eax
		mov	ecx,eax		;save eflags
		xor	eax,40000h	;toggle AC bit in eflags
		push	eax		;new eflags on stack
		popfd			;move new value into eflags
		pushfd			;get new eflags back into eax
		pop	eax
		xor	eax,ecx		;if AC bit not toggled then CPU=386
		mov	[local_cputype],3
		jz	@@end_get_cpu	;cpu is 386

		push	ecx
		popfd			;restore AC bit in eflags


;processor is at least 486
;
;Check for ability to set/clear ID flag in EFLAGS
;ID flag indicates ability of processor to execute the CPUID instruction.
;486 not guaranteed to have CPUID inst?
;
		mov	[local_cputype],4
		mov	eax,ecx		;original EFLAGS
		xor	eax,200000h	;toggle ID bit
		push	eax
		popfd
		pushfd
		pop	eax
		xor	eax,ecx		;check if still toggled
		jz	@@end_get_cpu


;       Execute CPUID instruction to determine vendor, family,
;       model and stepping.
;

		mov	[idflag],1	;flag ID is available

		xor	eax,eax
		cpuid

		mov	dword ptr [VendorID],ebx
		mov	dword ptr [VendorID+4],edx
		mov	dword ptr [VendorID+8],ecx
		mov	dword ptr [VendorID+12]," "

		cmp	eax,1		;check if 1 is valid
		jl	@@end_get_cpu	;inp for cpuid inst.

		xor	eax,eax
		inc	eax

		cpuid		;get stepping, model and family

		and     ax,0f00H
		shr     ax,08H

		mov	[local_cputype],al

@@end_get_cpu:	mov	al,[local_cputype]
		mov	[CPUType],al


;
; We have the CPU type in al now.
; If we arent on at least a pentium then we can assume there is no MMX
;
		cmp	al,5
		jl	@@no_mmx

		mov	eax,1
		cpuid
		test	edx,00800000h
		jz	@@no_mmx

;
; MMX detected - return true
;
		mov	eax,1
		ret


@@no_mmx:	xor	eax,eax
		ret


Detect_MMX_Availability endp



;*********************************************************************************************
;* Init_MMX -- Do any special inits required for MMX support                                 *
;*                                                                                           *
;*                                                                                           *
;* INPUT:	Nothing                                                                      *
;*                                                                                           *
;* OUTPUT:      None                                                                         *
;*                                                                                           *
;* Warnings:                                                                                 *
;*                                                                                           *
;* HISTORY:                                                                                  *
;*   05/19/96 ST : Created.                                                                  *
;*===========================================================================================*

Init_MMX	proc C

		mov	edi,offset NewShapeJumpTable
		mov	ecx,offset EndNewShapeJumpTable
		sub	ecx,edi
		shr	ecx,2
		mov	eax,offset Single_Line_Trans
		mov	ebx,offset MMX_Single_Line_Trans
		cld


@@patch_loop:   repnz	scasd
		jnz	@@done
		mov	[edi-4],ebx
		test	ecx,ecx
		jnz	@@patch_loop

@@done:		ret

Init_MMX	endp






;*********************************************************************************************
;* MMX_Done -- Restores floating point capability after MMX usage                            *
;*                                                                                           *
;*                                                                                           *
;* INPUT:	Nothing                                                                      *
;*                                                                                           *
;* OUTPUT:      None                                                                         *
;*                                                                                           *
;* Warnings:                                                                                 *
;*                                                                                           *
;* HISTORY:                                                                                  *
;*   05/19/96 ST : Created.                                                                  *
;*===========================================================================================*

MMX_Done	proc C

		emms
		ret

MMX_Done	endp







		code segment page public use32 'code'	; Need stricter segment alignment
							; for pentium optimisations


;*********************************************************************************************
;* MMX_Single_Line_Trans -- draw a single line of transparent pixels using MMX technology    *
;*                                                                                           *
;*                                                                                           *
;* INPUT:	Esi - ptr to source data                                                     *
;*              Edi - ptr to destination data                                                *
;*              Ecx - width to draw in bytes                                                 *
;*                                                                                           *
;* OUTPUT:      None                                                                         *
;*                                                                                           *
;* Warnings:                                                                                 *
;*                                                                                           *
;* HISTORY:                                                                                  *
;*   05/19/96 ST : Created.                                                                  *
;*===========================================================================================*

		align	16

MMX_Single_Line_Trans proc near

;
; If we are doing less than 8 bytes then dont use MMX
;
		cmp	ecx,8
		jge	@@mmx_loop
		push	offset Single_Line_Trans_Entry
		ret

;
; Use MMX instructions to mask 8 bytes at once
;
; Creates a bitmask based on the source bytes equality with zero and then uses this to mask
; out the source bytes in the destination data. The advatage that MMX gives us is that there is
; no 'test for zero then jump' required to mask.
;
		align	64		;MMX instructions like 64 byte alignment!

@@mmx_loop:
		movq	mm0,[esi]	; move 8 bytes of source into mm0
		pxor	mm1,mm1		; zero out mm1
		pcmpeqb mm1,mm0		; compare mm0 with 0. Bits get set in mm1
		lea	esi,[esi+8]     ; adjust the source data pointer
		pand	mm1,[edi]	; and in the destination data to throw away the bytes which arent zero in the source
		sub	ecx,8		; adjust the byte counter
		por	mm1,mm0         ; or in the source with the destination data
		movq	[edi],mm1       ; write back the destination data
		lea	edi,[edi+8]	; adjust the destination pointer

		cmp	ecx,8
		jg	@@mmx_loop

;
; Jump to the approprite code for drawing the end of this line or going to the next one
;
		push	offset Next_Line
		jcxz   	@@next_line
		push	offset Single_Line_Trans_Entry
@@next_line:	ret


MMX_Single_Line_Trans endp


code ends

		.data

CPUType		db	0
VendorID	db	"Not available",0,0,0,0,0,0


end