mirror of
https://github.com/genodelabs/genode.git
synced 2024-12-19 21:57:55 +00:00
hw: enable eager FPU context switch for ARM
* Add an ieee754 FPU test * Remove simple fpu test Fix #2822
This commit is contained in:
parent
4b4247f412
commit
d7fa4cfb8b
@ -51,6 +51,11 @@ struct Genode::Vm_state : Genode::Cpu_state_modes
|
||||
Genode::uint32_t tls3;
|
||||
Genode::uint32_t cpacr;
|
||||
|
||||
/**
|
||||
* Fpu registers
|
||||
*/
|
||||
Genode::uint32_t fpscr;
|
||||
Genode::uint64_t d0_d31[32];
|
||||
|
||||
/**
|
||||
* Timer related registers
|
||||
|
@ -31,6 +31,13 @@ struct Genode::Vm_state : Genode::Cpu_state_modes
|
||||
Genode::addr_t dfar;
|
||||
Genode::addr_t ttbr[2];
|
||||
Genode::addr_t ttbrc;
|
||||
|
||||
/**
|
||||
* Fpu registers
|
||||
*/
|
||||
Genode::uint32_t fpscr;
|
||||
Genode::uint64_t d0_d31[32];
|
||||
|
||||
Genode::addr_t irq_injection;
|
||||
};
|
||||
|
||||
|
@ -16,5 +16,7 @@ SRC_CC += spec/arm/kernel/thread_update_pd.cc
|
||||
SRC_CC += kernel/vm_thread_off.cc
|
||||
SRC_CC += kernel/kernel.cc
|
||||
|
||||
SRC_S += spec/arm/vfpv2.s
|
||||
|
||||
# include less specific configuration
|
||||
include $(BASE_DIR)/../base-hw/lib/mk/spec/arm/core-hw.inc
|
||||
|
@ -11,5 +11,7 @@ INC_DIR += $(BASE_DIR)/../base-hw/src/core/spec/arm_v7
|
||||
SRC_CC += spec/arm_v7/cpu.cc
|
||||
SRC_CC += spec/arm_v7/perf_counter.cc
|
||||
|
||||
SRC_S += spec/arm/vfpv3-d32.cc
|
||||
|
||||
# include less specific configuration
|
||||
include $(BASE_DIR)/../base-hw/lib/mk/spec/arm/core-hw.inc
|
||||
|
@ -13,6 +13,6 @@ NR_OF_CPUS = 2
|
||||
# we need more specific compiler hints for some 'special' assembly code
|
||||
# override -march=armv7-a because it conflicts with -mcpu=cortex-a15
|
||||
#
|
||||
CC_MARCH = -mcpu=cortex-a15
|
||||
CC_MARCH = -mcpu=cortex-a15 -mfpu=vfpv3 -mfloat-abi=softfp
|
||||
|
||||
include $(REP_DIR)/lib/mk/bootstrap-hw.inc
|
||||
|
@ -25,7 +25,7 @@ NR_OF_CPUS = 2
|
||||
# we need more specific compiler hints for some 'special' assembly code
|
||||
# override -march=armv7-a because it conflicts with -mcpu=cortex-a15
|
||||
#
|
||||
CC_MARCH = -mcpu=cortex-a15
|
||||
CC_MARCH = -mcpu=cortex-a15 -mfpu=vfpv3 -mfloat-abi=softfp
|
||||
|
||||
# include less specific configuration
|
||||
include $(REP_DIR)/lib/mk/spec/exynos5/core-hw.inc
|
||||
|
@ -10,7 +10,6 @@ INC_DIR += $(BASE_DIR)/../base-hw/src/core/spec/arm_gic
|
||||
|
||||
# add C++ sources
|
||||
SRC_CC += spec/cortex_a9/kernel/cpu.cc
|
||||
SRC_CC += spec/cortex_a9/fpu.cc
|
||||
SRC_CC += spec/cortex_a9/board.cc
|
||||
SRC_CC += spec/cortex_a9/timer.cc
|
||||
SRC_CC += spec/arm/smp/kernel/thread_update_pd.cc
|
||||
|
@ -9,6 +9,6 @@ SRC_CC += hw/spec/arm/arm_v7_cpu.cc
|
||||
SRC_CC += hw/spec/32bit/memory_map.cc
|
||||
SRC_S += bootstrap/spec/arm/crt0.s
|
||||
|
||||
CC_MARCH = -mcpu=cortex-a9
|
||||
CC_MARCH = -mcpu=cortex-a9 -mfpu=vfpv3 -mfloat-abi=softfp
|
||||
|
||||
include $(BASE_DIR)/../base-hw/lib/mk/bootstrap-hw.inc
|
||||
|
@ -13,7 +13,7 @@ SRC_CC += platform_services.cc
|
||||
|
||||
NR_OF_CPUS += 2
|
||||
|
||||
CC_MARCH = -mcpu=cortex-a9
|
||||
CC_MARCH = -mcpu=cortex-a9 -mfpu=vfpv3 -mfloat-abi=softfp
|
||||
|
||||
# include less specific configuration
|
||||
include $(REP_DIR)/lib/mk/spec/cortex_a9/core-hw.inc
|
||||
|
@ -62,6 +62,22 @@
|
||||
add sp, r0, r1
|
||||
|
||||
|
||||
/****************
|
||||
** Enable VFP **
|
||||
****************/
|
||||
|
||||
mov r0, #0xf
|
||||
lsl r0, #20
|
||||
mcr p15, 0, r0, c1, c0, 2 /* write to CPACR to enable VFP access */
|
||||
mcr p15, 0, r0, c7, c5, 4 /* deprecated ISB instruction <= ARMv6 */
|
||||
|
||||
vmrs r0, fpexc /* enable the VFP by read/write fpexc */
|
||||
mov r1, #1 /* enable bit 30 */
|
||||
lsl r1, #30
|
||||
orr r0, r1
|
||||
vmsr fpexc, r0
|
||||
|
||||
|
||||
/************************************
|
||||
** Jump to high-level entry point **
|
||||
************************************/
|
||||
|
@ -58,7 +58,13 @@ struct Genode::Arm_cpu : public Hw::Arm_cpu
|
||||
}
|
||||
};
|
||||
|
||||
struct alignas(4) Context : Cpu_state
|
||||
struct Fpu_context
|
||||
{
|
||||
uint32_t fpscr { 1UL << 24 }; /* VFP/SIMD - status/control register */
|
||||
uint64_t d0_d31[32]; /* VFP/SIMD - general purpose registers */
|
||||
};
|
||||
|
||||
struct alignas(4) Context : Cpu_state, Fpu_context
|
||||
{
|
||||
Context(bool privileged);
|
||||
};
|
||||
@ -146,8 +152,6 @@ struct Genode::Arm_cpu : public Hw::Arm_cpu
|
||||
** Dummies **
|
||||
*************/
|
||||
|
||||
bool retry_undefined_instr(Context&) { return false; }
|
||||
|
||||
/**
|
||||
* Return kernel name of the executing CPU
|
||||
*/
|
||||
|
@ -115,6 +115,17 @@
|
||||
stmia r0!, {r1-r3} /* save pc, cpsr and exception type */
|
||||
clrex /* clear exclusive access needed for cmpxchg */
|
||||
cps #SVC_MODE
|
||||
|
||||
mov r1, #1 /* clear exception state of the VFP */
|
||||
lsl r1, #30
|
||||
vmsr fpexc, r1
|
||||
adr r1, _fpu_save
|
||||
ldr r1, [r1]
|
||||
blx r1
|
||||
|
||||
/*
|
||||
* Go to kernel entry code
|
||||
*/
|
||||
adr lr, _kernel_entry
|
||||
ldr lr, [lr]
|
||||
bx lr
|
||||
@ -122,6 +133,9 @@
|
||||
_kernel_entry:
|
||||
.long kernel
|
||||
|
||||
_fpu_save:
|
||||
.long vfp_save_fpu_context
|
||||
|
||||
|
||||
.section .text
|
||||
|
||||
@ -133,3 +147,21 @@
|
||||
idle_thread_main:
|
||||
wfi
|
||||
b idle_thread_main
|
||||
|
||||
|
||||
/*****************************
|
||||
** kernel to userland switch **
|
||||
*******************************/
|
||||
|
||||
.global kernel_to_user_context_switch
|
||||
kernel_to_user_context_switch:
|
||||
push { r0 }
|
||||
mov r0, r1
|
||||
bl vfp_load_fpu_context
|
||||
pop { r0 }
|
||||
mov sp, r0
|
||||
ldr lr, [sp, #15*4]
|
||||
ldr r1, [sp, #16*4]
|
||||
msr spsr_cxsf, r1
|
||||
ldm sp, {r0-r14}^
|
||||
subs pc, lr, #0
|
||||
|
@ -1,255 +0,0 @@
|
||||
/*
|
||||
* \brief ARM-specific FPU driver for core
|
||||
* \author Stefan Kalkowski
|
||||
* \author Martin stein
|
||||
* \date 2016-01-19
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2016-2017 Genode Labs GmbH
|
||||
*
|
||||
* This file is part of the Genode OS framework, which is distributed
|
||||
* under the terms of the GNU Affero General Public License version 3.
|
||||
*/
|
||||
|
||||
#ifndef _CORE__SPEC__ARM__FPU_H_
|
||||
#define _CORE__SPEC__ARM__FPU_H_
|
||||
|
||||
#include <util/register.h>
|
||||
|
||||
namespace Genode { class Fpu; }
|
||||
|
||||
/**
|
||||
* FPU driver for the ARM VFPv3-D16 architecture
|
||||
*/
|
||||
class Genode::Fpu
|
||||
{
|
||||
private:
|
||||
|
||||
/**
|
||||
* Floating-point Status and Control Register
|
||||
*/
|
||||
struct Fpscr : Register<32>
|
||||
{
|
||||
/**
|
||||
* Read register value
|
||||
*/
|
||||
static access_t read()
|
||||
{
|
||||
/* FIXME: See annotation 1. */
|
||||
access_t v;
|
||||
asm volatile ("mrc p10, 7, %[v], cr1, cr0, 0" : [v] "=r" (v) ::);
|
||||
return v;
|
||||
}
|
||||
|
||||
/**
|
||||
* Override register value
|
||||
*
|
||||
* \param v write value
|
||||
*/
|
||||
static void write(access_t const v)
|
||||
{
|
||||
/* FIXME: See annotation 1. */
|
||||
asm volatile ("mcr p10, 7, %[v], cr1, cr0, 0" :: [v] "r" (v) :);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Floating-Point Exception Control register
|
||||
*/
|
||||
struct Fpexc : Register<32>
|
||||
{
|
||||
struct En : Bitfield<30, 1> { };
|
||||
|
||||
/**
|
||||
* Read register value
|
||||
*/
|
||||
static access_t read()
|
||||
{
|
||||
/* FIXME: See annotation 1. */
|
||||
access_t v;
|
||||
asm volatile ("mrc p10, 7, %[v], cr8, cr0, 0" : [v] "=r" (v) ::);
|
||||
return v;
|
||||
}
|
||||
|
||||
/**
|
||||
* Override register value
|
||||
*
|
||||
* \param v write value
|
||||
*/
|
||||
static void write(access_t const v)
|
||||
{
|
||||
/* FIXME: See annotation 1. */
|
||||
asm volatile ("mcr p10, 7, %[v], cr8, cr0, 0" :: [v] "r" (v) :);
|
||||
}
|
||||
};
|
||||
|
||||
public:
|
||||
|
||||
class Context
|
||||
{
|
||||
private:
|
||||
|
||||
/*
|
||||
* Noncopyable
|
||||
*/
|
||||
Context(Context const &);
|
||||
Context &operator = (Context const &);
|
||||
|
||||
friend class Fpu;
|
||||
|
||||
struct
|
||||
{
|
||||
/* advanced FP/SIMD - system registers */
|
||||
uint32_t fpscr;
|
||||
uint32_t fpexc;
|
||||
|
||||
/* advanced FP/SIMD - general purpose registers d0-d15 */
|
||||
uint64_t d0, d1, d2, d3, d4, d5, d6, d7;
|
||||
uint64_t d8, d9, d10, d11, d12, d13, d14, d15;
|
||||
};
|
||||
|
||||
Fpu * _fpu = nullptr;
|
||||
|
||||
public:
|
||||
|
||||
Context() : fpexc(Fpexc::En::bits(1)) { }
|
||||
|
||||
~Context() { if (_fpu) _fpu->unset(*this); }
|
||||
};
|
||||
|
||||
private:
|
||||
|
||||
Context * _context = nullptr;
|
||||
|
||||
/**
|
||||
* Enable FPU
|
||||
*/
|
||||
void _enable()
|
||||
{
|
||||
Fpexc::access_t fpexc = Fpexc::read();
|
||||
Fpexc::En::set(fpexc, 1);
|
||||
Fpexc::write(fpexc);
|
||||
}
|
||||
|
||||
/**
|
||||
* Disable FPU
|
||||
*/
|
||||
void _disable()
|
||||
{
|
||||
Fpexc::access_t fpexc = Fpexc::read();
|
||||
Fpexc::En::set(fpexc, 0);
|
||||
Fpexc::write(fpexc);
|
||||
}
|
||||
|
||||
/**
|
||||
* Save FPU context
|
||||
*/
|
||||
void _save()
|
||||
{
|
||||
/* save system registers */
|
||||
_context->fpexc = Fpexc::read();
|
||||
_context->fpscr = Fpscr::read();
|
||||
|
||||
/*
|
||||
* Save D0 - D15
|
||||
*
|
||||
* FIXME: See annotation 2.
|
||||
*/
|
||||
void * const d0_d15_base = &_context->d0;
|
||||
asm volatile (
|
||||
"stc p11, cr0, [%[d0_d15_base]], #128"
|
||||
:: [d0_d15_base] "r" (d0_d15_base) : );
|
||||
}
|
||||
|
||||
/**
|
||||
* Load context to FPU
|
||||
*/
|
||||
void _load()
|
||||
{
|
||||
/* load system registers */
|
||||
Fpexc::write(_context->fpexc);
|
||||
Fpscr::write(_context->fpscr);
|
||||
|
||||
/*
|
||||
* Load D0 - D15
|
||||
*
|
||||
* FIXME: See annotation 2.
|
||||
*/
|
||||
void * const d0_d15_base = &_context->d0;
|
||||
asm volatile (
|
||||
"ldc p11, cr0, [%[d0_d15_base]], #128"
|
||||
:: [d0_d15_base] "r" (d0_d15_base) : );
|
||||
}
|
||||
|
||||
/**
|
||||
* Return wether the FPU is enabled
|
||||
*/
|
||||
bool _enabled()
|
||||
{
|
||||
Fpexc::access_t fpexc = Fpexc::read();
|
||||
return Fpexc::En::get(fpexc);
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* Initialize FPU
|
||||
*/
|
||||
void init();
|
||||
|
||||
void switch_to(Context & context)
|
||||
{
|
||||
if (_context == &context) return;
|
||||
_disable();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return wether the FPU fault can be solved
|
||||
*
|
||||
* \param state CPU state of the user
|
||||
*/
|
||||
bool fault(Context & context)
|
||||
{
|
||||
if (_enabled()) { return false; }
|
||||
_enable();
|
||||
if (_context != &context) {
|
||||
if (_context) {
|
||||
_save();
|
||||
_context->_fpu = nullptr;
|
||||
}
|
||||
_context = &context;
|
||||
_context->_fpu = this;
|
||||
_load();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Unset FPU context
|
||||
*/
|
||||
void unset(Context &context) {
|
||||
if (_context == &context) _context = nullptr; }
|
||||
};
|
||||
|
||||
/*
|
||||
* Annotation 1
|
||||
*
|
||||
* According to the ARMv7 manual this should be done via vmsr/vmrs instruction
|
||||
* but it seems that binutils 2.22 doesn't fully support this yet. Hence, we
|
||||
* use a co-processor instruction instead. The parameters to target the
|
||||
* register this way can be determined via 'sys/arm/include/vfp.h' and
|
||||
* 'sys/arm/arm/vfp.c' of the FreeBSD head branch as from 2014.04.17.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Annotation 2
|
||||
*
|
||||
* According to the ARMv7 manual this should be done via vldm/vstm instruction
|
||||
* but it seems that binutils 2.22 doesn't fully support this yet. Hence, we
|
||||
* use a co-processor instruction instead. The parameters to target the
|
||||
* register this way can be determined via 'sys/arm/arm/vfp.c' of the FreeBSD
|
||||
* head branch as from 2014.04.17.
|
||||
*/
|
||||
|
||||
#endif /* _CORE__SPEC__ARM__FPU_H_ */
|
@ -19,6 +19,9 @@
|
||||
|
||||
using namespace Kernel;
|
||||
|
||||
extern "C" void kernel_to_user_context_switch(Cpu::Context*, Cpu::Fpu_context*);
|
||||
|
||||
|
||||
void Thread::exception(Cpu & cpu)
|
||||
{
|
||||
switch (regs->cpu_exception) {
|
||||
@ -34,7 +37,6 @@ void Thread::exception(Cpu & cpu)
|
||||
_interrupt(cpu.id());
|
||||
return;
|
||||
case Cpu::Context::UNDEFINED_INSTRUCTION:
|
||||
if (_cpu->retry_undefined_instr(*regs)) { return; }
|
||||
Genode::warning(*this, ": undefined instruction at ip=",
|
||||
Genode::Hex(regs->ip));
|
||||
_die();
|
||||
@ -106,14 +108,8 @@ void Thread::proceed(Cpu & cpu)
|
||||
cpu.switch_to(*regs, pd()->mmu_regs);
|
||||
|
||||
regs->cpu_exception = cpu.stack_start();
|
||||
|
||||
asm volatile("mov sp, %0 \n"
|
||||
"msr spsr_cxsf, %1 \n"
|
||||
"mov lr, %2 \n"
|
||||
"ldm sp, {r0-r14}^ \n"
|
||||
"subs pc, lr, #0 \n"
|
||||
:: "r" (static_cast<Cpu::Context*>(&*regs)),
|
||||
"r" (regs->cpsr), "r" (regs->ip));
|
||||
kernel_to_user_context_switch((static_cast<Cpu::Context*>(&*regs)),
|
||||
(static_cast<Cpu::Fpu_context*>(&*regs)));
|
||||
}
|
||||
|
||||
|
||||
|
31
repos/base-hw/src/core/spec/arm/vfpv2.s
Normal file
31
repos/base-hw/src/core/spec/arm/vfpv2.s
Normal file
@ -0,0 +1,31 @@
|
||||
/*
|
||||
* \brief VFPv2 context load/store
|
||||
* \author Stefan Kalkowski
|
||||
* \date 2018-05-06
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2018 Genode Labs GmbH
|
||||
*
|
||||
* This file is part of the Genode OS framework, which is distributed
|
||||
* under the terms of the GNU Affero General Public License version 3.
|
||||
*/
|
||||
|
||||
.section .text
|
||||
|
||||
.global vfp_save_fpu_context
|
||||
vfp_save_fpu_context:
|
||||
vmrs r1, fpscr
|
||||
stmia r0!, {r1}
|
||||
vstm r0!, {d0-d15}
|
||||
mov pc, lr
|
||||
|
||||
|
||||
.global vfp_load_fpu_context
|
||||
vfp_load_fpu_context:
|
||||
push { r1, lr }
|
||||
ldr r1, [r0]
|
||||
vmsr fpscr, r1
|
||||
add r1, r0, #4
|
||||
vldm r1!, {d0-d15}
|
||||
pop { r1, pc }
|
34
repos/base-hw/src/core/spec/arm/vfpv3-d32.s
Normal file
34
repos/base-hw/src/core/spec/arm/vfpv3-d32.s
Normal file
@ -0,0 +1,34 @@
|
||||
/*
|
||||
* \brief VFPv3-D32 context load/store
|
||||
* \author Stefan Kalkowski
|
||||
* \date 2018-05-06
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2018 Genode Labs GmbH
|
||||
*
|
||||
* This file is part of the Genode OS framework, which is distributed
|
||||
* under the terms of the GNU Affero General Public License version 3.
|
||||
*/
|
||||
|
||||
.section .text
|
||||
|
||||
.global vfp_save_fpu_context
|
||||
vfp_save_fpu_context:
|
||||
push { r1, lr }
|
||||
vmrs r1, fpscr
|
||||
stmia r0!, {r1}
|
||||
vstm r0!, {d0-d15}
|
||||
vstm r0!, {d16-d31}
|
||||
pop { r1, pc }
|
||||
|
||||
|
||||
.global vfp_load_fpu_context
|
||||
vfp_load_fpu_context:
|
||||
push { r1, lr }
|
||||
ldr r1, [r0]
|
||||
vmsr fpscr, r1
|
||||
add r1, r0, #4
|
||||
vldm r1!, {d0-d15}
|
||||
vldm r1!, {d16-d31}
|
||||
pop { r1, pc }
|
@ -69,10 +69,14 @@ monitor_mode_exception_vector:
|
||||
_nonsecure_kernel_entry:
|
||||
ldr lr, [sp, #17*4] /* load kernel sp from vm context */
|
||||
stmia r0!, {r1-r2} /* save spsr, and exception reason */
|
||||
mov r1, #1 /* clear exception state of the VFP */
|
||||
lsl r1, #30
|
||||
vmsr fpexc, r1
|
||||
mrc p15, 0, r3, c6, c0, 0 /* move DFAR to r3 */
|
||||
mrc p15, 0, r4, c2, c0, 0 /* move TTBR0 to r4 */
|
||||
mrc p15, 0, r5, c2, c0, 1 /* move TTBR1 to r5 */
|
||||
mrc p15, 0, r6, c2, c0, 2 /* move TTBRC to r6 */
|
||||
vmrs r7, fpscr /* move FPU ctrl to r7 */
|
||||
mov r1, #0
|
||||
mcr p15, 0, r1, c1, c1, 0 /* disable non-secure bit */
|
||||
.irp mode,27,19,23,18,17 /* save mode specific registers */
|
||||
@ -81,7 +85,9 @@ monitor_mode_exception_vector:
|
||||
stmia r0!, {r1,sp,lr} /* store mode-specific sp and lr */
|
||||
.endr
|
||||
stmia r0!, {r8-r12} /* save fiq r8-r12 */
|
||||
stmia r0!, {r3-r6} /* save MMU registers */
|
||||
stmia r0!, {r3-r7} /* save MMU registers */
|
||||
vstm r0!, {d0-d15} /* save FPU registers */
|
||||
vstm r0!, {d16-d31}
|
||||
cps #22 /* switch back to monitor mode */
|
||||
mov r0, #0b111010011 /* spsr to SVC mode, irqs masked */
|
||||
msr spsr_cxsf, r0
|
||||
@ -109,6 +115,12 @@ monitor_mode_enter_normal_world:
|
||||
msr spsr_cxfs, r2 /* load mode's spsr */
|
||||
.endr
|
||||
ldmia r0!, {r8 - r12} /* load fiq r8-r12 */
|
||||
add r0, r0, #4*4
|
||||
ldr r1, [r0]
|
||||
vmsr fpscr, r1
|
||||
add r1, r0, #4
|
||||
vldm r1!, {d0-d15}
|
||||
vldm r1!, {d16-d31}
|
||||
cps #22 /* switch to monitor mode */
|
||||
ldmia sp, {r0-lr}^ /* load user r0-r12,sp,lr */
|
||||
str lr, [sp, #17*4] /* store kernel sp in vm context */
|
||||
|
@ -91,11 +91,16 @@ _host_to_vm:
|
||||
mcr p15, 0, r10, c6, c0, 0 /* write DFAR */
|
||||
mcr p15, 0, r11, c6, c0, 2 /* write IFAR */
|
||||
mcr p15, 0, r12, c13, c0, 1 /* write CIDR */
|
||||
ldm r0, {r1-r4}
|
||||
ldm r0!, {r1-r4}
|
||||
mcr p15, 0, r1, c13, c0, 2 /* write TLS1 */
|
||||
mcr p15, 0, r2, c13, c0, 3 /* write TLS2 */
|
||||
mcr p15, 0, r3, c13, c0, 4 /* write TLS3 */
|
||||
mcr p15, 0, r4, c1, c0, 2 /* write CPACR */
|
||||
ldr r1, [r0]
|
||||
vmsr fpscr, r1
|
||||
add r1, r0, #4
|
||||
vldm r1!, {d0-d15}
|
||||
vldm r1!, {d16-d31}
|
||||
ldmia sp, {r0-r12} /* load vm's r0-r12 */
|
||||
eret
|
||||
|
||||
@ -106,6 +111,8 @@ _vm_to_host:
|
||||
mcrr p15, 6, r1, r1, c2 /* write VTTBR */
|
||||
mcr p15, 4, r1, c1, c1, 0 /* write HCR register */
|
||||
mcr p15, 4, r1, c1, c1, 3 /* write HSTR register */
|
||||
mov r1, #0xf
|
||||
lsl r1, #20
|
||||
mcr p15, 0, r1, c1, c0, 2 /* write CPACR */
|
||||
mrs r1, ELR_hyp /* read ip */
|
||||
mrs r2, spsr /* read cpsr */
|
||||
@ -130,7 +137,15 @@ _vm_to_host:
|
||||
mrc p15, 0, r10, c13, c0, 2 /* read TLS1 */
|
||||
mrc p15, 0, r11, c13, c0, 3 /* read TLS2 */
|
||||
mrc p15, 0, r12, c13, c0, 4 /* read TLS3 */
|
||||
stm r0, {r3-r12}
|
||||
stm r0!, {r3-r12}
|
||||
add r0, r0, #4
|
||||
mov r3, #1 /* clear fpu exception state */
|
||||
lsl r3, #30
|
||||
vmsr fpexc, r3
|
||||
vmrs r4, fpscr
|
||||
stmia r0!, {r4}
|
||||
vstm r0!, {d0-d15}
|
||||
vstm r0!, {d16-d31}
|
||||
add r0, sp, #13*4
|
||||
ldr r3, _vt_host_context_ptr
|
||||
ldr sp, [r3]
|
||||
|
@ -135,13 +135,6 @@ class Genode::Cpu : public Arm_v7_cpu
|
||||
if (mmu_context.id() && (Ttbr0_64bit::read() != mmu_context.ttbr0))
|
||||
Ttbr0_64bit::write(mmu_context.ttbr0);
|
||||
}
|
||||
|
||||
|
||||
/*************
|
||||
** Dummies **
|
||||
*************/
|
||||
|
||||
bool retry_undefined_instr(Context&) { return false; }
|
||||
};
|
||||
|
||||
#endif /* _CORE__SPEC__CORTEX_A15__CPU_H_ */
|
||||
|
@ -16,45 +16,13 @@
|
||||
#define _CORE__SPEC__CORTEX_A9__CPU_H_
|
||||
|
||||
/* core includes */
|
||||
#include <spec/arm/fpu.h>
|
||||
#include <spec/arm_v7/cpu_support.h>
|
||||
#include <board.h>
|
||||
|
||||
namespace Genode { class Cpu; }
|
||||
namespace Genode { struct Cpu; }
|
||||
|
||||
class Genode::Cpu : public Arm_v7_cpu
|
||||
struct Genode::Cpu : Arm_v7_cpu
|
||||
{
|
||||
protected:
|
||||
|
||||
Fpu _fpu { };
|
||||
|
||||
public:
|
||||
|
||||
struct Context : Arm_cpu::Context, Fpu::Context
|
||||
{
|
||||
Context(bool privileged)
|
||||
: Arm_cpu::Context(privileged) {}
|
||||
};
|
||||
|
||||
/**
|
||||
* Next cpu context to switch to
|
||||
*
|
||||
* \param context context to switch to
|
||||
*/
|
||||
void switch_to(Context & context, Mmu_context & mmu_context)
|
||||
{
|
||||
Arm_cpu::switch_to(context, mmu_context);
|
||||
_fpu.switch_to(context);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return wether to retry an undefined user instruction after this call
|
||||
*
|
||||
* \param state CPU state of the user
|
||||
*/
|
||||
bool retry_undefined_instr(Context & context) {
|
||||
return _fpu.fault(context); }
|
||||
|
||||
/**
|
||||
* Write back dirty cache lines and invalidate whole data cache
|
||||
*/
|
||||
|
@ -1,24 +0,0 @@
|
||||
/*
|
||||
* \brief CPU driver for core
|
||||
* \author Martin stein
|
||||
* \author Stefan Kalkowski
|
||||
* \date 2016-01-19
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2016-2017 Genode Labs GmbH
|
||||
*
|
||||
* This file is part of the Genode OS framework, which is distributed
|
||||
* under the terms of the GNU Affero General Public License version 3.
|
||||
*/
|
||||
|
||||
#include <cpu.h>
|
||||
|
||||
void Genode::Fpu::init()
|
||||
{
|
||||
Cpu::Cpacr::access_t cpacr = Cpu::Cpacr::read();
|
||||
Cpu::Cpacr::Cp10::set(cpacr, 3);
|
||||
Cpu::Cpacr::Cp11::set(cpacr, 3);
|
||||
Cpu::Cpacr::write(cpacr);
|
||||
_disable();
|
||||
}
|
@ -23,8 +23,6 @@
|
||||
|
||||
void Kernel::Cpu::init(Kernel::Pic &pic)
|
||||
{
|
||||
_fpu.init();
|
||||
|
||||
{
|
||||
Lock::Guard guard(data_lock());
|
||||
|
||||
|
@ -116,11 +116,6 @@ class Genode::Cpu : public Hw::X86_64_cpu
|
||||
|
||||
Fpu & fpu() { return _fpu; }
|
||||
|
||||
/**
|
||||
* Return wether to retry an undefined user instruction after this call
|
||||
*/
|
||||
bool retry_undefined_instr(Context&) { return false; }
|
||||
|
||||
/**
|
||||
* Return kernel name of the executing CPU
|
||||
*/
|
||||
|
@ -1,6 +1,6 @@
|
||||
SPECS += arm
|
||||
REP_INC_DIR += include/spec/arm_v6
|
||||
CC_MARCH ?= -march=armv6k
|
||||
CC_MARCH ?= -march=armv6k -mfpu=vfp -mfloat-abi=softfp
|
||||
|
||||
include $(BASE_DIR)/mk/spec/arm.mk
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
SPECS += arm_v7
|
||||
CC_MARCH ?= -march=armv7-a
|
||||
CC_MARCH ?= -march=armv7-a -mfpu=vfpv3 -mfloat-abi=softfp
|
||||
|
||||
include $(BASE_DIR)/mk/spec/arm_v7.mk
|
||||
|
||||
|
@ -1 +0,0 @@
|
||||
Test pseudo-parallel use of FPU if available
|
@ -1,2 +0,0 @@
|
||||
_/src/init
|
||||
_/src/test-fpu
|
@ -1 +0,0 @@
|
||||
2018-11-01 f8565783b90caaa5724a58e6ed7be9c999211fe3
|
@ -1,43 +0,0 @@
|
||||
<runtime ram="32M" caps="1000" binary="init">
|
||||
|
||||
<events>
|
||||
<timeout meaning="failed" sec="20" />
|
||||
<log meaning="succeeded">
|
||||
[init -> test] FPU user started
|
||||
[init -> test] FPU user started
|
||||
[init -> test] FPU user started
|
||||
[init -> test] FPU user started
|
||||
[init -> test] FPU user started
|
||||
[init -> test] FPU user started
|
||||
[init -> test] FPU user started
|
||||
[init -> test] FPU user started
|
||||
[init -> test] FPU user started
|
||||
[init -> test] FPU user started
|
||||
[init -> test] test done
|
||||
</log>
|
||||
<log meaning="failed">calculation error</log>
|
||||
</events>
|
||||
|
||||
<content>
|
||||
<rom label="ld.lib.so"/>
|
||||
<rom label="test-fpu"/>
|
||||
</content>
|
||||
|
||||
<config>
|
||||
<parent-provides>
|
||||
<service name="ROM"/>
|
||||
<service name="CPU"/>
|
||||
<service name="RM"/>
|
||||
<service name="PD"/>
|
||||
<service name="LOG"/>
|
||||
</parent-provides>
|
||||
<default-route>
|
||||
<any-service> <parent/> </any-service>
|
||||
</default-route>
|
||||
<default caps="100"/>
|
||||
<start name="test">
|
||||
<binary name="test-fpu"/>
|
||||
<resource name="RAM" quantum="10M"/>
|
||||
</start>
|
||||
</config>
|
||||
</runtime>
|
@ -1,2 +0,0 @@
|
||||
SRC_DIR = src/test/fpu
|
||||
include $(GENODE_DIR)/repos/base/recipes/src/content.inc
|
@ -1 +0,0 @@
|
||||
2018-11-01 fc82355e25add8ece1cfe7a4c93b8c42e4866049
|
@ -1 +0,0 @@
|
||||
base
|
@ -1,86 +0,0 @@
|
||||
/*
|
||||
* \brief Test pseudo-parallel use of FPU if available
|
||||
* \author Martin Stein
|
||||
* \date 2014-04-29
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2012-2017 Genode Labs GmbH
|
||||
*
|
||||
* This file is part of the Genode OS framework, which is distributed
|
||||
* under the terms of the GNU Affero General Public License version 3.
|
||||
*/
|
||||
|
||||
/* Genode includes */
|
||||
#include <base/component.h>
|
||||
#include <base/heap.h>
|
||||
#include <base/log.h>
|
||||
#include <base/thread.h>
|
||||
|
||||
using namespace Genode;
|
||||
|
||||
class Fpu_user : public Thread
|
||||
{
|
||||
private:
|
||||
|
||||
float _x;
|
||||
Signal_transmitter _st;
|
||||
Semaphore & _sem;
|
||||
|
||||
void _calc(float volatile & x, float volatile & y)
|
||||
{
|
||||
for (unsigned j = 0; j < 100; j++) {
|
||||
x *= (y * 1.357);
|
||||
x /= (y * 1.246);
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
Fpu_user(Env & env, float x, Signal_context_capability c, Semaphore &s)
|
||||
: Thread(env, "fpu_user", sizeof(size_t)*2048), _x(x), _st(c), _sem(s) {
|
||||
start(); }
|
||||
|
||||
void entry()
|
||||
{
|
||||
log("FPU user started");
|
||||
|
||||
enum { TRIALS = 1000 };
|
||||
for (unsigned i = 0; i < TRIALS; i++) {
|
||||
float volatile a = _x + (float)i * ((float)1 / TRIALS);
|
||||
float volatile b = _x + (float)i * ((float)1 / TRIALS);
|
||||
float volatile c = _x;
|
||||
_calc(a, c);
|
||||
_calc(b, c);
|
||||
if (a != b) {
|
||||
error("calculation error");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
_sem.up();
|
||||
_st.submit();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
struct Main
|
||||
{
|
||||
enum { FPU_USERS = 10 };
|
||||
|
||||
Semaphore sem { };
|
||||
Env & env;
|
||||
Heap heap { env.ram(), env.rm() };
|
||||
Signal_handler<Main> handler { env.ep(), *this, &Main::handle };
|
||||
|
||||
Main(Env & env) : env(env) {
|
||||
for (unsigned i = 0; i < FPU_USERS; i++)
|
||||
new (heap) Fpu_user(env, (i + 1) * 1.234, handler, sem); }
|
||||
|
||||
void handle() {
|
||||
if (sem.cnt() >= FPU_USERS) log("test done"); }
|
||||
};
|
||||
|
||||
|
||||
void Component::construct(Genode::Env & env) {
|
||||
static Main main(env); }
|
@ -1,14 +0,0 @@
|
||||
#
|
||||
# \brief Test pseudo-parallel use of FPU if available
|
||||
# \author Martin Stein
|
||||
# \date 2012-04-25
|
||||
#
|
||||
|
||||
# Set program name
|
||||
TARGET = test-fpu
|
||||
|
||||
# Add C++ sources
|
||||
SRC_CC += main.cc
|
||||
|
||||
# Add libraries
|
||||
LIBS += base
|
@ -44,7 +44,6 @@ set avail_test_pkgs {
|
||||
test-dynamic_config_slave
|
||||
test-expat
|
||||
test-fault_detection
|
||||
test-fpu
|
||||
test-fs_log
|
||||
test-fs_packet
|
||||
test-fs_report
|
||||
|
1712
repos/libports/run/ieee754.run
Normal file
1712
repos/libports/run/ieee754.run
Normal file
File diff suppressed because it is too large
Load Diff
15
repos/libports/src/test/ieee754/component.cc
Normal file
15
repos/libports/src/test/ieee754/component.cc
Normal file
@ -0,0 +1,15 @@
|
||||
#include <base/heap.h>
|
||||
#include <libc/component.h>
|
||||
|
||||
extern int main (int argc, char* argv[]);
|
||||
|
||||
void Libc::Component::construct(Libc::Env &env)
|
||||
{
|
||||
env.exec_static_constructors();
|
||||
|
||||
Genode::Heap heap(env.ram(), env.rm());
|
||||
|
||||
int r = 0;
|
||||
Libc::with_libc([&r] () { r = main(0, 0); });
|
||||
env.parent().exit(r);
|
||||
}
|
4
repos/libports/src/test/ieee754/target.mk
Normal file
4
repos/libports/src/test/ieee754/target.mk
Normal file
@ -0,0 +1,4 @@
|
||||
TARGET = test-ieee754
|
||||
LIBS = libc libm
|
||||
SRC_C = tst-ieee754.c
|
||||
SRC_CC = component.cc
|
489
repos/libports/src/test/ieee754/tst-ieee754.c
Executable file
489
repos/libports/src/test/ieee754/tst-ieee754.c
Executable file
@ -0,0 +1,489 @@
|
||||
/* Some IEEE-754 / ISO C99+ conformance tests.
|
||||
*
|
||||
* Compile this program with:
|
||||
* gcc -Wall -O2 -std=c99 tst-ieee754.c -o tst-ieee754 -lm
|
||||
* for instance.
|
||||
*
|
||||
* Add -DFP_CONTRACT to allow contraction of FP expressions (e.g. with icc).
|
||||
*
|
||||
* Copyright 2003-2017 Vincent Lefevre <vincent@vinc17.net>.
|
||||
*
|
||||
* You may use this software under the terms of the MIT License:
|
||||
* http://opensource.org/licenses/MIT
|
||||
*
|
||||
* More information: https://en.wikipedia.org/wiki/MIT_License
|
||||
*/
|
||||
|
||||
#define SVNID "$Id: tst-ieee754.c 98609 2017-05-19 18:35:55Z vinc17/zira $"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <limits.h>
|
||||
#include <float.h>
|
||||
#include <math.h>
|
||||
|
||||
#define STRINGIFY(S) #S
|
||||
#define MAKE_STR(S) STRINGIFY(S)
|
||||
|
||||
#ifdef FP_CONTRACT
|
||||
#undef FP_CONTRACT
|
||||
#define FP_CONTRACT "ON"
|
||||
#pragma STDC FP_CONTRACT ON
|
||||
#else
|
||||
#define FP_CONTRACT "OFF"
|
||||
#pragma STDC FP_CONTRACT OFF
|
||||
#endif
|
||||
|
||||
#ifndef NO_FENV_H
|
||||
#include <fenv.h>
|
||||
#pragma STDC FENV_ACCESS ON
|
||||
#endif
|
||||
|
||||
#ifndef NAN
|
||||
#define NAN (0.0/0.0)
|
||||
#endif
|
||||
|
||||
#ifndef INFINITY
|
||||
#define INFINITY (1.0/0.0)
|
||||
#endif
|
||||
|
||||
#define DBL_NAN (NAN)
|
||||
#define DBL_POS_INF (INFINITY)
|
||||
#define DBL_NEG_INF (- DBL_POS_INF)
|
||||
|
||||
/* Note: The dynamic epsilon now gives information about
|
||||
- the possible extended precision used to evaluate expression;
|
||||
- the possible reduced precision due to the use of options like
|
||||
GCC's -mpc32 or -mpc64 to reduce the dynamic rounding precision
|
||||
with "387" arithmetic on x86 processors. */
|
||||
#define PREC_EPSILON(T,V,F) \
|
||||
do \
|
||||
{ \
|
||||
volatile T eps = 1.0; \
|
||||
printf (#V " = %" F "g = %" F "a\n", (T) (V), (T) (V)); \
|
||||
while (eps != 0) \
|
||||
{ \
|
||||
volatile T x = 1.0, e = eps / FLT_RADIX; \
|
||||
x = (x + e) - 1.0; \
|
||||
if (x != e) \
|
||||
break; \
|
||||
eps = e; \
|
||||
} \
|
||||
if (eps == 0) \
|
||||
printf (" (cannot compute the dynamic epsilon)\n"); \
|
||||
else if (eps != (V)) \
|
||||
printf (" (dynamic epsilon = %" F "g = %" F "a)\n", eps, eps); \
|
||||
} \
|
||||
while (0)
|
||||
|
||||
#define ERRSTR(X) ((X) ? " [ERROR]" : "")
|
||||
|
||||
static float flt_max = FLT_MAX;
|
||||
static double dbl_max = DBL_MAX;
|
||||
static long double ldbl_max = LDBL_MAX;
|
||||
|
||||
static float flt_epsilon = FLT_EPSILON;
|
||||
static double dbl_epsilon = DBL_EPSILON;
|
||||
static long double ldbl_epsilon = LDBL_EPSILON;
|
||||
|
||||
/* <float.h> constants */
|
||||
static void float_h (void)
|
||||
{
|
||||
printf ("FLT_RADIX = %d\n", (int) FLT_RADIX);
|
||||
printf ("FLT_MANT_DIG = %d\n", (int) FLT_MANT_DIG);
|
||||
printf ("DBL_MANT_DIG = %d\n", (int) DBL_MANT_DIG);
|
||||
printf ("LDBL_MANT_DIG = %d\n\n", (int) LDBL_MANT_DIG);
|
||||
|
||||
printf ("FLT_MIN_EXP = %d\n", (int) FLT_MIN_EXP);
|
||||
printf ("DBL_MIN_EXP = %d\n", (int) DBL_MIN_EXP);
|
||||
printf ("LDBL_MIN_EXP = %d\n\n", (int) LDBL_MIN_EXP);
|
||||
|
||||
printf ("FLT_MAX_EXP = %d\n", (int) FLT_MAX_EXP);
|
||||
printf ("DBL_MAX_EXP = %d\n", (int) DBL_MAX_EXP);
|
||||
printf ("LDBL_MAX_EXP = %d\n\n", (int) LDBL_MAX_EXP);
|
||||
|
||||
PREC_EPSILON (float, FLT_EPSILON, "");
|
||||
PREC_EPSILON (double, DBL_EPSILON, "");
|
||||
PREC_EPSILON (long double, LDBL_EPSILON, "L");
|
||||
putchar ('\n');
|
||||
|
||||
printf ("FLT_MIN = %g = %a\n", (double) FLT_MIN, (double) FLT_MIN);
|
||||
printf ("DBL_MIN = %g = %a\n", (double) DBL_MIN, (double) DBL_MIN);
|
||||
printf ("LDBL_MIN = %Lg = %La\n\n",
|
||||
(long double) LDBL_MIN, (long double) LDBL_MIN);
|
||||
|
||||
printf ("FLT_MAX = %g = %a\n", (double) FLT_MAX, (double) FLT_MAX);
|
||||
printf ("DBL_MAX = %g = %a\n", (double) DBL_MAX, (double) DBL_MAX);
|
||||
printf ("LDBL_MAX = %Lg = %La\n\n",
|
||||
(long double) LDBL_MAX, (long double) LDBL_MAX);
|
||||
}
|
||||
|
||||
#define TSIZEOF(T) printf ("sizeof(" #T ") = %d\n", (int) sizeof(T))
|
||||
|
||||
static void float_sizeof (void)
|
||||
{
|
||||
TSIZEOF (float);
|
||||
TSIZEOF (double);
|
||||
TSIZEOF (long double);
|
||||
putchar ('\n');
|
||||
}
|
||||
|
||||
static void tstcast (void)
|
||||
{
|
||||
double x;
|
||||
x = (double) 0;
|
||||
printf ("(double) 0 = %g\n", x);
|
||||
}
|
||||
|
||||
/* This mostly tests signed zero support. This test is written in
|
||||
such a way that "gcc -O -ffast-math" gives a wrong result. */
|
||||
static void signed_zero_inf (void)
|
||||
{
|
||||
double x = 0.0, y = -0.0, px, py, nx, ny;
|
||||
|
||||
printf ("Signed zero tests (x is 0.0 and y is -0.0):\n");
|
||||
|
||||
if (x == y)
|
||||
printf (" Test 1.0 / x != 1.0 / y returns %d (should be 1).\n",
|
||||
1.0 / x != 1.0 / y);
|
||||
else
|
||||
printf ("x != y; this is wrong!\n");
|
||||
|
||||
px = +x;
|
||||
if (x == px)
|
||||
printf (" Test 1.0 / x == 1.0 / +x returns %d (should be 1).\n",
|
||||
1.0 / x == 1.0 / px);
|
||||
else
|
||||
printf ("x != +x; this is wrong!\n");
|
||||
|
||||
py = +y;
|
||||
if (x == py)
|
||||
printf (" Test 1.0 / x != 1.0 / +y returns %d (should be 1).\n",
|
||||
1.0 / x != 1.0 / py);
|
||||
else
|
||||
printf ("x != +y; this is wrong!\n");
|
||||
|
||||
nx = -x;
|
||||
if (x == nx)
|
||||
printf (" Test 1.0 / x != 1.0 / -x returns %d (should be 1).\n",
|
||||
1.0 / x != 1.0 / nx);
|
||||
else
|
||||
printf ("x != -x; this is wrong!\n");
|
||||
|
||||
ny = -y;
|
||||
if (x == ny)
|
||||
printf (" Test 1.0 / x == 1.0 / -y returns %d (should be 1).\n",
|
||||
1.0 / x == 1.0 / ny);
|
||||
else
|
||||
printf ("x != -y; this is wrong!\n");
|
||||
}
|
||||
|
||||
static void tstadd (double x, double y)
|
||||
{
|
||||
double a, s;
|
||||
|
||||
a = x + y;
|
||||
s = x - y;
|
||||
printf ("%g + %g = %g\n", x, y, a);
|
||||
printf ("%g - %g = %g\n", x, y, s);
|
||||
}
|
||||
|
||||
static void tstmul (double x, double y)
|
||||
{
|
||||
double m;
|
||||
|
||||
m = x * y;
|
||||
printf ("%g * %g = %g\n", x, y, m);
|
||||
}
|
||||
|
||||
#define TSTCONST(S,OP) \
|
||||
printf ("Constant expression 1 " S " DBL_MIN = %.20g\n" \
|
||||
"Variable expression 1 " S " DBL_MIN = %.20g\n", \
|
||||
1.0 OP DBL_MIN, 1.0 OP x);
|
||||
|
||||
static void tstconst (void)
|
||||
{
|
||||
volatile double x = DBL_MIN;
|
||||
|
||||
TSTCONST ("+", +);
|
||||
TSTCONST ("-", -);
|
||||
}
|
||||
|
||||
#define TSTDIV(T,S) \
|
||||
do \
|
||||
{ \
|
||||
volatile T x = 1.0, y = 3.0; \
|
||||
x /= y; \
|
||||
printf ("1/3 in %-12s: %" S "a\n", #T, x); \
|
||||
} \
|
||||
while (0)
|
||||
|
||||
static void tstpow (void)
|
||||
{
|
||||
double val[] = { 0.0, 0.0, 0.0, +0.0, -0.0,
|
||||
+0.5, -0.5, +1.0, -1.0, +2.0, -2.0 };
|
||||
int i, j;
|
||||
|
||||
/* Not used above to avoid an error with IRIX64 cc. */
|
||||
val[0] = DBL_NAN;
|
||||
val[1] = DBL_POS_INF;
|
||||
val[2] = DBL_NEG_INF;
|
||||
|
||||
for (i = 0; i < sizeof (val) / sizeof (val[0]); i++)
|
||||
for (j = 0; j < sizeof (val) / sizeof (val[0]); j++)
|
||||
{
|
||||
double p;
|
||||
p = pow (val[i], val[j]);
|
||||
printf ("pow(%g, %g) = %g\n", val[i], val[j], p);
|
||||
}
|
||||
}
|
||||
|
||||
static void tstall (void)
|
||||
{
|
||||
float fm = FLT_MAX, fe = FLT_EPSILON;
|
||||
double dm = DBL_MAX, de = DBL_EPSILON;
|
||||
long double lm = LDBL_MAX, le = LDBL_EPSILON;
|
||||
|
||||
tstcast ();
|
||||
signed_zero_inf ();
|
||||
|
||||
tstadd (+0.0, +0.0);
|
||||
tstadd (+0.0, -0.0);
|
||||
tstadd (-0.0, +0.0);
|
||||
tstadd (-0.0, -0.0);
|
||||
tstadd (+1.0, +1.0);
|
||||
tstadd (+1.0, -1.0);
|
||||
|
||||
tstmul (+0.0, +0.0);
|
||||
tstmul (+0.0, -0.0);
|
||||
tstmul (-0.0, +0.0);
|
||||
tstmul (-0.0, -0.0);
|
||||
|
||||
tstconst ();
|
||||
TSTDIV (float, "");
|
||||
TSTDIV (double, "");
|
||||
TSTDIV (long double, "L");
|
||||
|
||||
printf ("Dec 1.1 = %a\n", (double) 1.1);
|
||||
printf ("FLT_MAX = %a%s\n", (double) fm, ERRSTR (fm != flt_max));
|
||||
printf ("DBL_MAX = %a%s\n", dm, ERRSTR (dm != dbl_max));
|
||||
printf ("LDBL_MAX = %La%s\n", lm, ERRSTR (lm != ldbl_max));
|
||||
printf ("FLT_EPSILON = %a%s\n", (double) fe, ERRSTR (fe != flt_epsilon));
|
||||
printf ("DBL_EPSILON = %a%s\n", de, ERRSTR (de != dbl_epsilon));
|
||||
printf ("LDBL_EPSILON = %La%s\n", le, ERRSTR (le != ldbl_epsilon));
|
||||
|
||||
tstpow ();
|
||||
}
|
||||
|
||||
static void tsteval_method (void)
|
||||
{
|
||||
volatile double x, y, z;
|
||||
|
||||
#if __STDC__ == 1 && __STDC_VERSION__ >= 199901 && defined(__STDC_IEC_559__)
|
||||
printf ("__STDC_IEC_559__ defined:\n"
|
||||
"The implementation shall conform to the IEEE-754 standard.\n");
|
||||
# ifdef FLT_EVAL_METHOD
|
||||
printf ("FLT_EVAL_METHOD is %d (see ISO/IEC 9899, 5.2.4.2.2#8).\n\n",
|
||||
(int) FLT_EVAL_METHOD);
|
||||
# else
|
||||
printf ("But FLT_EVAL_METHOD is not defined!\n\n");
|
||||
# endif
|
||||
#endif
|
||||
|
||||
x = 9007199254740994.0; /* 2^53 + 2 */
|
||||
y = 1.0 - 1/65536.0;
|
||||
z = x + y;
|
||||
printf ("x + y, with x = 9007199254740994.0 and y = 1.0 - 1/65536.0"
|
||||
" (type double).\n"
|
||||
"The IEEE-754 result is 9007199254740994 with double precision.\n"
|
||||
"The IEEE-754 result is 9007199254740996 with extended precision.\n"
|
||||
"The obtained result is %.17g.\n", z);
|
||||
|
||||
if (z == 9007199254740996.0) /* computations in extended precision */
|
||||
{
|
||||
volatile double a, b;
|
||||
double c;
|
||||
|
||||
a = 9007199254740992.0; /* 2^53 */
|
||||
b = a + 0.25;
|
||||
c = a + 0.25;
|
||||
if (b != c)
|
||||
printf ("\nBUG:\nThe implementation doesn't seem to convert values "
|
||||
"to the target type after\nan assignment (see ISO/IEC 9899: "
|
||||
"5.1.2.3#12, 6.3.1.5#2 and 6.3.1.8#2[52]).\n");
|
||||
}
|
||||
}
|
||||
|
||||
/* This test is useful only on implementations where the "double" type
|
||||
* corresponds to the IEEE-754 double precision and the "long double"
|
||||
* type corresponds to the traditional x86 extended precision, but let's
|
||||
* do it in any case. It shows a bug in gcc 3.4 to 4.3.3 on x86_64 and
|
||||
* ia64 platforms. See:
|
||||
* https://gcc.gnu.org/bugzilla/show_bug.cgi?id=36578
|
||||
*/
|
||||
static void ldcast_test (void)
|
||||
{
|
||||
volatile double a = 4294967219.0;
|
||||
volatile double b = 4294967429.0;
|
||||
double c, d;
|
||||
long double al, bl;
|
||||
|
||||
al = a;
|
||||
bl = b;
|
||||
c = (long double) a * (long double) b;
|
||||
d = al * bl;
|
||||
if (c != d)
|
||||
printf ("\nBUG: Casts to long double do not seem to be taken into "
|
||||
"account when\nthe result to stored to a variable of type "
|
||||
"double. If your compiler\nis gcc (version < 4.3.4), this "
|
||||
"may be the following bug:\n "
|
||||
"https://gcc.gnu.org/bugzilla/show_bug.cgi?id=36578\n");
|
||||
}
|
||||
|
||||
static void tstnan (void)
|
||||
{
|
||||
double d;
|
||||
|
||||
/* Various tests to detect a NaN without using the math library (-lm).
|
||||
* MIPSpro 7.3.1.3m (IRIX64) does too many optimisations, so that
|
||||
* both NAN != NAN and !(NAN >= 0.0 || NAN <= 0.0) give 0 instead
|
||||
* of 1. As a consequence, in MPFR, one needs to use
|
||||
* #define DOUBLE_ISNAN(x) (!(((x) >= 0.0) + ((x) <= 0.0)))
|
||||
* in this case. */
|
||||
|
||||
d = NAN;
|
||||
printf ("\n");
|
||||
printf ("NAN != NAN --> %d (should be 1)\n", d != d);
|
||||
printf ("isnan(NAN) --> %d (should be 1)\n", isnan (d));
|
||||
printf ("NAN >= 0.0 --> %d (should be 0)\n", d >= 0.0);
|
||||
printf ("NAN <= 0.0 --> %d (should be 0)\n", d <= 0.0);
|
||||
printf (" #3||#4 --> %d (should be 0)\n", d >= 0.0 || d <= 0.0);
|
||||
printf ("!(#3||#4) --> %d (should be 1)\n", !(d >= 0.0 || d <= 0.0));
|
||||
printf (" #3 + #4 --> %d (should be 0)\n", (d >= 0.0) + (d <= 0.0));
|
||||
printf ("!(#3 + #4) --> %d (should be 1)\n", !((d >= 0.0) + (d <= 0.0)));
|
||||
}
|
||||
|
||||
#define TSTINVALID(F,C) \
|
||||
do \
|
||||
{ \
|
||||
feclearexcept (FE_INVALID); \
|
||||
(void) (d C 0.0); \
|
||||
if ((F) ^ ! fetestexcept (FE_INVALID)) \
|
||||
printf ("The FE_INVALID flag is%s set for NAN " #C " 0.\n", \
|
||||
(F) ? "" : " not"); \
|
||||
} \
|
||||
while (0)
|
||||
|
||||
static void tstinvalid (void)
|
||||
{
|
||||
#ifdef NO_FENV_H
|
||||
printf ("The FE_INVALID flag could not be tested (no <fenv.h>)\n");
|
||||
#else
|
||||
double d = NAN;
|
||||
TSTINVALID(1,==);
|
||||
TSTINVALID(1,!=);
|
||||
TSTINVALID(0,>=);
|
||||
TSTINVALID(0,<=);
|
||||
TSTINVALID(0,>);
|
||||
TSTINVALID(0,<);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Note: we do not use the FP_CONTRACT pragma locally (in a block) as
|
||||
icc 10.1 seems to disable contraction when it sees FP_CONTRACT OFF
|
||||
somewhere in the source. */
|
||||
static void fused_madd_test (void)
|
||||
{
|
||||
#define TWO40 (1099511627776.0) /* 2^40 */
|
||||
#define C1U40 (1.0 + 1.0/TWO40) /* 1 + 2^(-40) */
|
||||
volatile double x = C1U40, y = C1U40, z = -1.0, d;
|
||||
|
||||
d = x * y + z;
|
||||
printf ("\nx * y + z with FP_CONTRACT " FP_CONTRACT " is %sfused.\n",
|
||||
d == 2.0 * (1 + 0.5 / TWO40) / TWO40 ? "" : "not ");
|
||||
}
|
||||
|
||||
/* FE_INVALID exception with Clang:
|
||||
* https://bugs.llvm.org//show_bug.cgi?id=17686
|
||||
*/
|
||||
static void double_to_unsigned (void)
|
||||
{
|
||||
volatile double d;
|
||||
uint64_t i = (uint64_t) 1 << 63;
|
||||
int t1, t2;
|
||||
|
||||
d = i;
|
||||
feclearexcept (FE_INVALID);
|
||||
t1 = (uint64_t) d != i;
|
||||
t2 = fetestexcept (FE_INVALID);
|
||||
if (t1 || t2)
|
||||
printf ("\nError in cast of double to unsigned: %s value%s\n",
|
||||
t1 ? "incorrect" : "correct", t2 ? ", FE_INVALID" : "");
|
||||
}
|
||||
|
||||
static void ibm_ldconv (void)
|
||||
{
|
||||
#define CAT1(X) 1 ## X
|
||||
#define CAT2(X) CAT1(X)
|
||||
#define LD0 .000000000000000000000000000000000001L
|
||||
#define LD1 CAT2(LD0)
|
||||
long double x = 1.0L + LD0, y = LD1;
|
||||
|
||||
if (x > 1.0L && y == 1.0L)
|
||||
{
|
||||
printf ("\nBad conversion of " MAKE_STR(LD1) "\n");
|
||||
printf ("Got 1 instead of about 1 + %La\n", x - 1.0L);
|
||||
}
|
||||
}
|
||||
|
||||
int main (void)
|
||||
{
|
||||
/* printf ("%s\n\n", SVNID); */
|
||||
|
||||
float_h ();
|
||||
float_sizeof ();
|
||||
tsteval_method ();
|
||||
ldcast_test ();
|
||||
tstnan ();
|
||||
tstinvalid ();
|
||||
fused_madd_test ();
|
||||
double_to_unsigned ();
|
||||
|
||||
if (LDBL_MIN_EXP == -968 && LDBL_MAX_EXP == 1024 &&
|
||||
LDBL_MANT_DIG == 106) /* IBM long double format, i.e. double-double */
|
||||
ibm_ldconv ();
|
||||
|
||||
printf ("\nRounding to nearest\n");
|
||||
#ifdef FE_TONEAREST
|
||||
if (fesetround (FE_TONEAREST))
|
||||
printf ("Error, but let's do the test since it "
|
||||
"should be the default rounding mode.\n");
|
||||
#endif
|
||||
tstall ();
|
||||
|
||||
#ifdef FE_TOWARDZERO
|
||||
printf ("\nRounding toward 0\n");
|
||||
if (fesetround (FE_TOWARDZERO))
|
||||
printf ("Error\n");
|
||||
else
|
||||
tstall ();
|
||||
#endif
|
||||
|
||||
#ifdef FE_DOWNWARD
|
||||
printf ("\nRounding to -oo\n");
|
||||
if (fesetround (FE_DOWNWARD))
|
||||
printf ("Error\n");
|
||||
else
|
||||
tstall ();
|
||||
#endif
|
||||
|
||||
#ifdef FE_UPWARD
|
||||
printf ("\nRounding to +oo\n");
|
||||
if (fesetround (FE_UPWARD))
|
||||
printf ("Error\n");
|
||||
else
|
||||
tstall ();
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
@ -12,6 +12,7 @@ fetchurl_lxip
|
||||
fetchurl_lwip
|
||||
fs_query
|
||||
gdb_monitor
|
||||
ieee754
|
||||
init_smp
|
||||
input_filter
|
||||
libc_fatfs
|
||||
|
Loading…
Reference in New Issue
Block a user