+/* Project 16 Source Code~\r
+ * Copyright (C) 2012-2016 sparky4 & pngwen & andrius4669 & joncampbell123 & yakui-lover\r
+ *\r
+ * This file is part of Project 16.\r
+ *\r
+ * Project 16 is free software; you can redistribute it and/or modify\r
+ * it under the terms of the GNU General Public License as published by\r
+ * the Free Software Foundation; either version 3 of the License, or\r
+ * (at your option) any later version.\r
+ *\r
+ * Project 16 is distributed in the hope that it will be useful,\r
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
+ * GNU General Public License for more details.\r
+ *\r
+ * You should have received a copy of the GNU General Public License\r
+ * along with this program. If not, see <http://www.gnu.org/licenses/>, or\r
+ * write to the Free Software Foundation, Inc., 51 Franklin Street,\r
+ * Fifth Floor, Boston, MA 02110-1301 USA.\r
+ *\r
+ */\r
+/* tab size = 8 */\r
+\r
+#include "src/lib/wcpu/16_wcpu.h"\r
+\r
+//#define USECPUPROBE\r
+\r
+byte WCPU_detectfpu()\r
+{\r
+ byte fputype=0;\r
+ word funk=0;\r
+ boolean errflag=0;\r
+ __asm {\r
+ PUSHF ; we gonna modify flags, so back them up\r
+.8087 fninit ; Initialize FPU\r
+// mov [WORD PTR funk], 55AAh ; Set junk value\r
+// fnstsw funk ; Store status word\r
+// cmp [BYTE PTR funk], 0 ; If it's not 0, no FPU\r
+ mov funk, 55AAh ; Set junk value\r
+ fnstsw funk ; Store status word\r
+ cmp funk, 0 ; If it's not 0, no FPU\r
+// jne short _done\r
+ jne short _err\r
+ jmp _fpu\r
+ _err:\r
+ mov errflag, 1\r
+ _fpu:\r
+/* }\r
+ if(!errflag){\r
+ printf(".");\r
+ __asm {*/\r
+ fnstcw funk ; Store control word\r
+ mov ax, funk ; If the bits are not the way\r
+ and ax, 103Fh ; they should be, no FPU\r
+ cmp ax, 3Fh\r
+// jne short _done\r
+ je short __err\r
+ jmp __fpu\r
+ __err:\r
+ mov errflag, 1\r
+ __fpu:\r
+ /*}}\r
+ if(!errflag){\r
+ printf(".");\r
+ __asm {*/\r
+// and [WORD PTR funk], 0FF7Fh ; Clear interrupt bit\r
+ and funk, 0FF7Fh ; Clear interrupt bit\r
+ fldcw funk ; Load control word\r
+ fdisi ; Disable interrupts\r
+ fstcw funk ; Store control word\r
+// test [BYTE PTR funk], 80h ; If it changed, it's an 8087\r
+ test funk, 80h ; If it changed, it's an 8087\r
+ mov fputype, 1\r
+\r
+ _done:\r
+ POPF ; restore flags we backed up earlier\r
+ }//}\r
+ //printf("WCPU_detectfpu():\n fputype=%u\n funk=%u errflag=%u\n", fputype, funk, errflag);\r
+#ifdef USECPUPROBE\r
+ if (cpu_flags & CPU_FLAG_FPU) printf(" - With FPU\n");\r
+#endif\r
+ return fputype;\r
+}\r
+\r
+byte WCPU_detectcpu()\r
+{\r
+ byte cputype=0;\r
+ __asm {\r
+ PUSHF ; we gonna modify flags, so back them up\r
+ ; first check if its 8086/8088 or 80186/80188\r
+ PUSHF ; FLAGS -> STACK\r
+ POP AX ; STACK -> AX\r
+ AND AX, 00FFFh ; clear 12-15 bits (they are always 1 on 8086/8088 and 80186/80188)\r
+ PUSH AX ; AX -> STACK\r
+ POPF ; STACK -> FLAGS\r
+ ; this is where magic happen\r
+ PUSHF ; FLAGS -> STACK\r
+ POP AX ; STACK -> AX\r
+ AND AX, 0F000h ; 0-11 bits aren't important to us\r
+ CMP AX, 0F000h ; check if all 12-15 bits are set (simple comparision)\r
+ JNE _286p ; if no, 286+ CPU\r
+ MOV cputype, 0 ; if yes, we are done, set cputype to 0 and end this\r
+ JMP _done\r
+ _286p:\r
+ ; now check if its 286 or newer\r
+ PUSHF ; FLAGS -> STACK\r
+ POP AX ; STACK -> AX\r
+ OR AX, 07000h ; set 12-14 bits (they are always cleared by 286 if its real mode)\r
+ PUSH AX ; AX -> STACK\r
+ POPF ; STACK -> FLAGS\r
+ ; this is where magic happen\r
+ PUSHF ; FLAGS -> STACK\r
+ POP AX ; STACK -> AX\r
+ TEST AX, 07000h ; check if at least 1 bit in 12-14 bits range is set (15th won't be set anyway)\r
+ JNZ _386p ; not all bits clear, its 386+\r
+ MOV cputype, 1 ; all bits clear, its 286, we are done\r
+ JMP _done\r
+ _386p:\r
+ MOV cputype, 2 ; its 386 or newer, but we don't care if its newer at this point\r
+ _done:\r
+ POPF ; restore flags we backed up earlier\r
+ }\r
+ return cputype;\r
+}\r
+\r
+const char *WCPU_cpudetectmesg()\r
+{\r
+ const char *cpus;\r
+ unsigned char cput;\r
+\r
+ cput = WCPU_detectcpu();\r
+ switch(cput)\r
+ {\r
+ case 0: cpus = "8086/8088 or 186/88"; break;\r
+ case 1: cpus = "286"; break;\r
+ case 2: cpus = "386 or newer"; break;\r
+ default: cpus = "internal error"; break;\r
+ }\r
+ return cpus;\r
+}\r
+\r
+const char *WCPU_fpudetectmesg()\r
+{\r
+ const char *fpus;\r
+ unsigned char fput;\r
+\r
+ fput = WCPU_detectfpu();\r
+ switch(fput)\r
+ {\r
+ case 0: fpus = "none"; break;\r
+ case 1: fpus = "8087"; break;\r
+ default: fpus = "internal error"; break;\r
+ }\r
+ return fpus;\r
+}\r
+\r
+void WCPU_cpufpumesg()\r
+{\r
+#ifdef USECPUPROBE\r
+ cpu_probe();\r
+#endif\r
+ printf("detected CPU type: %s\n", WCPU_cpudetectmesg());\r
+ printf("detected FPU type: %s\n", WCPU_fpudetectmesg());\r
+}\r