%include "util.mac"
%include "icedump.inc"
%include "wiat.inc"
%include "fpu.inc"


global Parse_FPU


extern sdata
extern Parser.errorMsg
extern ParseExpression


bits 32


;-------------------------------------------------------------------------------
; FPU <FPU register number> <floating point value>
;-------------------------------------------------------------------------------
segment _LTEXT
Parse_FPU:
	mov	edx,cr0			; save CR0.TS

; for now we don't handle the case where the current thread hasn't used
; the FPU yet (i.e. CR0.TS=1), we'd have to use VMCPD_Set_Thread_State
	mov	edi,.Error_TS
	test	dl,0x08			; TS, our thread doesn't own the FPU
	jnz	near Parser.errorMsg

	mov	edi,.Error_EM
	test	dl,0x04			; EM, we don't deal with emulation
	jnz	near Parser.errorMsg

	mov	edi,+.Error_ET
	test	dl,0x10			; ET, oldies are not supported
	jz	near Parser.errorMsg

	mov	ecx,esi			; parse <FPU number> later

	mov	edi,.Error_NoValue
	call    [pSkipWord]		; skip over <FPU number>
	jb	near Parser.errorMsg

	mov	byte [esi-1],','	; terminate the commandline here
	xchg	esi,ecx			; save and restore ESI

	mov	edi,.Error_NoSTx
	call	ParseExpression		; parse <FPU number>
	jb	near Parser.errorMsg

	mov	edi,.Error_BadSTx
	cmp	eax,7			; accept ST0...ST7 only
	ja	near Parser.errorMsg

	lea	ebx,[8*eax+eax]		; EBX: index of STx in the state map
	add	ebx,eax

	mov	esi,ecx			; ESI will point to <value> now

	mov	edi,.Error_BadValue
	call	[pStr2LongReal]
	jb	near Parser.errorMsg

;	clts				; avoid triggering an exception
	fnsave	[FPUState]

	mov	esi,[tLongReal]
	lea	edi,[ebx+FPUState.STx]
	movsd
	movsd
	movsw

; because winice is fucked up, it cannot display the FPU registers when
; there're pending exceptions, so we shouldn't make such a big deal out
; of saving even this part of the state, but should simply return with
; an error message much like winice does... but we always do better ;-)
; of course introducing inconsistencies into the FPU state is not our
; problem but that of the user...

; now restore FPU state, first clear possible pending exceptions
	xor	al,al
	xchg	al,[FPUState.Status+FPU_Status_PM32.StatusLo]
	frstor	[FPUState]

; now restore status with possible pending exceptions
	xchg	al,[FPUState.Status+FPU_Status_PM32.StatusLo]
	fldenv	[FPUState.Status]

;	mov	cr0,edx			; restore CR0.TS

	call	[pUpdateSomeWindows]	; we wanna see it, don't we ;-)

	popad
	retn


segment _LDATA
.Error_TS	db 'CR0.TS=1, FPU was last used by another thread.',0
.Error_EM	db 'CR0.EM=1, FPU is emulated.',0
.Error_ET	db 'CR0.ET=0, oldies are not supported.',0
.Error_NoSTx	db 'specify an STx register.',0
.Error_BadSTx	db 'STx is invalid.',0
.Error_NoValue	db 'specify a value.',0
.Error_BadValue	db 'value is invalid.',0

	align 4
FPUState:
.Status:
istruc FPU_Status_PM32
iend

.STx:
istruc FPU_STx
iend
