/*
 * File      : mips_vfp32_asm.S
 * This file is part of RT-Thread RTOS
 * COPYRIGHT (C) 2008 - 2012, RT-Thread Development Team
 *
 *  This program 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 2 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License along
 *  with this program; if not, write to the Free Software Foundation, Inc.,
 *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Change Logs:
 * Date           Author       Notes
 * 2016年9月9日     Urey         the first version
 */

#ifndef __ASSEMBLY__
#	define __ASSEMBLY__
#endif

#ifdef __mips_hard_float

.module hardfloat
.module doublefloat
.set nomips16

#include "../common/mips.h"
#undef fp

	.global mips_vfp32_init
LEAF(mips_vfp32_init)
    mfc0 	t0, CP0_STATUS
    or      t0 , M_StatusCU1
    mtc0 	t0, CP0_STATUS
    jr      ra
    nop
END(mips_vfp32_init)

#
# FUNCTION:	_fpctx_save
#
# DESCRIPTION:	save floating point registers to memory starting at a0
#
# RETURNS:	int
#			0:	No context saved
#			CTX_*:	Type of context stored
#
	.global _fpctx_save
LEAF(_fpctx_save)
	sw 		zero, LINKCTX_NEXT(a0)
	mfc0	t0, CP0_STATUS
	li		t1, M_StatusCU1
	and		t1, t0, t1
	bnez	t1, 1f
	# FP not enabled, bail out
	move	v0, zero
	jr		ra

1:	# Save FP32 base
	li		t1, ST0_FR
	and		t0, t0, t1
	cfc1	t2, $31
	sw		t2, FP32CTX_CSR(a0)
	sdc1	$f0, FP32CTX_0(a0)
	sdc1	$f2, FP32CTX_2(a0)
	sdc1	$f4, FP32CTX_4(a0)
	sdc1	$f6, FP32CTX_6(a0)
	sdc1	$f8, FP32CTX_8(a0)
	sdc1	$f10, FP32CTX_10(a0)
	sdc1	$f12, FP32CTX_12(a0)
	sdc1	$f14, FP32CTX_14(a0)
	sdc1	$f16, FP32CTX_16(a0)
	sdc1	$f18, FP32CTX_18(a0)
	sdc1	$f20, FP32CTX_20(a0)
	sdc1	$f22, FP32CTX_22(a0)
	sdc1	$f24, FP32CTX_24(a0)
	sdc1	$f26, FP32CTX_26(a0)
	sdc1	$f28, FP32CTX_28(a0)
	sdc1	$f30, FP32CTX_30(a0)
	bnez	t0, 2f
	li		v0, LINKCTX_TYPE_FP32
	sw		v0, LINKCTX_ID(a0)
	jr		ra

2:	# Save FP64 extra
.set	push
.set	fp=64
	sdc1	$f1, FP64CTX_1(a0)
	sdc1	$f3, FP64CTX_3(a0)
	sdc1	$f5, FP64CTX_5(a0)
	sdc1	$f7, FP64CTX_7(a0)
	sdc1	$f9, FP64CTX_9(a0)
	sdc1	$f11, FP64CTX_11(a0)
	sdc1	$f13, FP64CTX_13(a0)
	sdc1	$f15, FP64CTX_15(a0)
	sdc1	$f17, FP64CTX_17(a0)
	sdc1	$f19, FP64CTX_19(a0)
	sdc1	$f21, FP64CTX_21(a0)
	sdc1	$f23, FP64CTX_23(a0)
	sdc1	$f25, FP64CTX_25(a0)
	sdc1	$f27, FP64CTX_27(a0)
	sdc1	$f29, FP64CTX_29(a0)
	sdc1	$f31, FP64CTX_31(a0)
.set	pop
	li	v0, LINKCTX_TYPE_FP64
	sw	v0, LINKCTX_ID(a0)
	jr	ra
END(_fpctx_save)

#
# FUNCTION:	_fpctx_load
#
# DESCRIPTION:	load floating point registers from context chain starting at a0
#
# RETURNS:	int
#			0:	Unrecognised context
#			CTX_*:	Type of context restored
#
	.global _fpctx_load
LEAF(_fpctx_load)
	lw	v0, LINKCTX_ID(a0)
	# Detect type
	li	t0, LINKCTX_TYPE_FP64
	li	t1, LINKCTX_TYPE_FP32
	li	t2, M_StatusCU1
	beq	v0, t0, 0f
	beq	v0, t1, 1f
	# Don't recognise this context, fail
	move	v0, zero
	jr	ra

0: 	# FP64 context
	# Enable CU1
	di	t3
	ehb
	or	t3, t3, t2
	mtc0	t3, CP0_STATUS
	ehb
	# Load FP64 extra
.set	push
.set	fp=64
	ldc1	$f1, FP64CTX_1(a0)
	ldc1	$f3, FP64CTX_3(a0)
	ldc1	$f5, FP64CTX_5(a0)
	ldc1	$f7, FP64CTX_7(a0)
	ldc1	$f9, FP64CTX_9(a0)
	ldc1	$f11, FP64CTX_11(a0)
	ldc1	$f13, FP64CTX_13(a0)
	ldc1	$f15, FP64CTX_15(a0)
	ldc1	$f17, FP64CTX_17(a0)
	ldc1	$f19, FP64CTX_19(a0)
	ldc1	$f21, FP64CTX_21(a0)
	ldc1	$f23, FP64CTX_23(a0)
	ldc1	$f25, FP64CTX_25(a0)
	ldc1	$f27, FP64CTX_27(a0)
	ldc1	$f29, FP64CTX_29(a0)
	ldc1	$f31, FP64CTX_31(a0)
.set	pop
1: 	# FP32 context
	# Enable CU1
	di	t3
	ehb
	or	t3, t3, t2
	mtc0	t3, CP0_STATUS
	ehb
	# Load FP32 base
	lw	t1, FP32CTX_CSR(a0)
	ctc1	t1, $31
	ldc1	$f0, FP32CTX_0(a0)
	ldc1	$f2, FP32CTX_2(a0)
	ldc1	$f4, FP32CTX_4(a0)
	ldc1	$f6, FP32CTX_6(a0)
	ldc1	$f8, FP32CTX_8(a0)
	ldc1	$f10, FP32CTX_10(a0)
	ldc1	$f12, FP32CTX_12(a0)
	ldc1	$f14, FP32CTX_14(a0)
	ldc1	$f16, FP32CTX_16(a0)
	ldc1	$f18, FP32CTX_18(a0)
	ldc1	$f20, FP32CTX_20(a0)
	ldc1	$f22, FP32CTX_22(a0)
	ldc1	$f24, FP32CTX_24(a0)
	ldc1	$f26, FP32CTX_26(a0)
	ldc1	$f28, FP32CTX_28(a0)
	ldc1	$f30, FP32CTX_30(a0)
	# Return CTX_FP32/64
	jr	ra
END(_fpctx_load)

#endif
