From 4a1ef4d3d71454812176240e5c9e8770ca214e94 Mon Sep 17 00:00:00 2001 From: Peter Veenstra Date: Mon, 1 Apr 2019 14:32:18 +0000 Subject: [PATCH] Refine stack overflow and underflow for the fpu a bit. Overflow is still treated as Exit. Underflow is ignored in release mode as it happens every now and then and doesn't seem to cause issues if ignored, thus restoring 0.74 behaviour. Imported-from: https://svn.code.sf.net/p/dosbox/code-0/dosbox/trunk@4199 --- include/fpu.h | 22 +++++++++++++++++++ src/fpu/fpu_instructions.h | 39 +++++++++++++++++++++++++++++++-- src/fpu/fpu_instructions_x86.h | 40 +++++++++++++++++++++++++++++++--- 3 files changed, 96 insertions(+), 5 deletions(-) diff --git a/include/fpu.h b/include/fpu.h index da29096f..44acd31b 100644 --- a/include/fpu.h +++ b/include/fpu.h @@ -19,6 +19,11 @@ #ifndef DOSBOX_FPU_H #define DOSBOX_FPU_H +#ifndef DOSBOX_DOSBOX_H +//So the right config.h gets included for C_DEBUG +#include "dosbox.h" +#endif + #ifndef DOSBOX_MEM_H #include "mem.h" #endif @@ -150,5 +155,22 @@ static INLINE void FPU_SET_C3(Bitu C){ if(C) fpu.sw |= 0x4000; } +#define DB_FPU_STACK_CHECK_NONE 0 +#define DB_FPU_STACK_CHECK_LOG 1 +#define DB_FPU_STACK_CHECK_EXIT 2 +//NONE is 0.74 behavior: not care about stack overflow/underflow +//Overflow is always logged/exited on. +//Underflow can be controlled with by this. +//LOG is giving a message when encountered +//EXIT is to hard exit. +//Currently pop is ignored in release mode and overflow is exit. +//in debug mode: pop will log and overflow is exit. +#if C_DEBUG +#define DB_FPU_STACK_CHECK_POP DB_FPU_STACK_CHECK_LOG +#define DB_FPU_STACK_CHECK_PUSH DB_FPU_STACK_CHECK_EXIT +#else +#define DB_FPU_STACK_CHECK_POP DB_FPU_STACK_CHECK_NONE +#define DB_FPU_STACK_CHECK_PUSH DB_FPU_STACK_CHECK_EXIT +#endif #endif diff --git a/src/fpu/fpu_instructions.h b/src/fpu/fpu_instructions.h index c0c3d090..9dc97c76 100644 --- a/src/fpu/fpu_instructions.h +++ b/src/fpu/fpu_instructions.h @@ -16,6 +16,9 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ +#ifndef DOSBOX_FPU_H +#include "fpu.h" +#endif static void FPU_FINIT(void) { @@ -43,7 +46,23 @@ static void FPU_FNOP(void){ static void FPU_PREP_PUSH(void){ TOP = (TOP - 1) &7; - if (GCC_UNLIKELY(fpu.tags[TOP] != TAG_Empty)) E_Exit("FPU stack overflow"); +#if DB_FPU_STACK_CHECK_PUSH > DB_FPU_STACK_CHECK_NONE + if (GCC_UNLIKELY(fpu.tags[TOP] != TAG_Empty)) { +#if DB_FPU_STACK_CHECK_PUSH == DB_FPU_STACK_CHECK_EXIT + E_Exit("FPU stack overflow"); +#else + if (fpu.cw&1) { // Masked ? + fpu.sw &= 0x1; //Invalid Operation + fpu.sw &= 0x40; //Stack Fault + FPU_SET_C1(1); //Register is used. + //No need to set 0x80 as the exception is masked. + LOG(LOG_FPU,LOG_ERROR)("Masked stack overflow encountered!"); + } else { + E_Exit("FPU stack overflow"); //Exit as this is bad + } +#endif + } +#endif fpu.tags[TOP] = TAG_Valid; } @@ -56,7 +75,23 @@ static void FPU_PUSH(double in){ static void FPU_FPOP(void){ - if (GCC_UNLIKELY(fpu.tags[TOP] == TAG_Empty)) E_Exit("FPU stack underflow"); +#if DB_FPU_STACK_CHECK_POP > DB_FPU_STACK_CHECK_NONE + if (GCC_UNLIKELY(fpu.tags[TOP] != TAG_Empty)) { +#if DB_FPU_STACK_CHECK_POP == DB_FPU_STACK_CHECK_EXIT + E_Exit("FPU stack underflow"); +#else + if (fpu.cw&1) { // Masked ? + fpu.sw &= 0x1; //Invalid Operation + fpu.sw &= 0x40; //Stack Fault + FPU_SET_C1(0); //Register is free. + //No need to set 0x80 as the exception is masked. + LOG(LOG_FPU,LOG_ERROR)("Masked stack underflow encountered!"); + } else { + LOG_MSG("Unmasked Stack underflow!"); //Also log in release mode + } +#endif + } +#endif fpu.tags[TOP]=TAG_Empty; //maybe set zero in it as well TOP = ((TOP+1)&7); diff --git a/src/fpu/fpu_instructions_x86.h b/src/fpu/fpu_instructions_x86.h index 5b62177d..31e51fc4 100644 --- a/src/fpu/fpu_instructions_x86.h +++ b/src/fpu/fpu_instructions_x86.h @@ -16,7 +16,9 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ - +#ifndef DOSBOX_FPU_H +#include "fpu.h" +#endif // #define WEAK_EXCEPTIONS @@ -957,12 +959,44 @@ static void FPU_FNOP(void){ static void FPU_PREP_PUSH(void){ TOP = (TOP - 1) &7; - if (GCC_UNLIKELY(fpu.tags[TOP] != TAG_Empty)) E_Exit("FPU stack overflow"); +#if DB_FPU_STACK_CHECK_PUSH > DB_FPU_STACK_CHECK_NONE + if (GCC_UNLIKELY(fpu.tags[TOP] != TAG_Empty)) { +#if DB_FPU_STACK_CHECK_PUSH == DB_FPU_STACK_CHECK_EXIT + E_Exit("FPU stack overflow"); +#else + if (fpu.cw&1) { // Masked ? + fpu.sw &= 0x1; //Invalid Operation + fpu.sw &= 0x40; //Stack Fault + FPU_SET_C1(1); //Register is used. + //No need to set 0x80 as the exception is masked. + LOG(LOG_FPU,LOG_ERROR)("Masked stack overflow encountered!"); + } else { + E_Exit("FPU stack overflow"); //Exit as this is bad + } +#endif + } +#endif fpu.tags[TOP] = TAG_Valid; } static void FPU_FPOP(void){ - if (GCC_UNLIKELY(fpu.tags[TOP] == TAG_Empty)) E_Exit("FPU stack underflow"); +#if DB_FPU_STACK_CHECK_POP > DB_FPU_STACK_CHECK_NONE + if (GCC_UNLIKELY(fpu.tags[TOP] == TAG_Empty)) { +#if DB_FPU_STACK_CHECK_POP == DB_FPU_STACK_CHECK_EXIT + E_Exit("FPU stack underflow"); +#else + if (fpu.cw&1) { // Masked ? + fpu.sw &= 0x1; //Invalid Operation + fpu.sw &= 0x40; //Stack Fault + FPU_SET_C1(0); //Register is free. + //No need to set 0x80 as the exception is masked. + LOG(LOG_FPU,LOG_ERROR)("Masked stack underflow encountered!"); + } else { + LOG_MSG("Unmasked Stack underflow!"); + } +#endif + } +#endif fpu.tags[TOP] = TAG_Empty; TOP = ((TOP+1)&7); }